views:

503

answers:

2

How can I write a relation in prolog that determines if there are any two pairs in a list with the same sum. The relation should fail if there exist no pairs whose sums are equal. The relation should also fail if the list contains less than four elements.

  • list([1 2 3]) fails since it only has 3 elements
  • list([2 3 4 1]) succeeds since 2+3=4+1
  • list([3 1 2 4 5 6]) succeds since 5+1=2+4
  • list([1 8 20 100]) fails since there are no pairs with equal sums
+2  A: 

How about this algorithm: take any two pairs of numbers, and see if they match. Here is the code for it:

has_equal_sums(List) :-
    select(A, List, List2),
    select(B, List2, List3),
    select(C, List3, List4),
    select(D, List4, _),
    A+B =:= C+D.

If you want to make sure it works, or for debug purpose, you can display the two selected pairs as an output:

has_equal_sums(List, [[A, B], [C, D]]) :-
    select(A, List, List2),
    select(B, List2, List3),
    select(C, List3, List4),
    select(D, List4, _),
    A+B =:= C+D.

Here are a few examples of usage:

?- has_equal_sums([1, 2, 3, 6, 5], X).
X = [[1,6],[2,5]] ? ;
X = [[2,6],[3,5]] ?

?- has_equal_sums([1, 2, 3, 5], X).
no

?- has_equal_sums([1, 2, 3], X).
no
Jerome
I'm not the poster, but I'm familiar with the requirement. Part of the instructions indicate that you must be able to handle a list of variable length. So the algorithm must not only do the comparisons of four items in the list in each of the three possible combinations, but also must implement some logic to check for a) list is too short b) tail recursion to check a sublist.
AJ
Hi JeromeThanks for your post.But I want a relation in prolog if there are any two pairs in the list with the same sum and the relation fails if there exists no pairs whose sums are equal.The relation also fails if list contains less than four elements.
nan
It looks like Jerome's answer does all these things correctly (and his edit demonstrates some of the cases that are mentioned). To understand why, think about what the later calls to Select/3 will do if the original list is too short, and about how they will work with backtracking for values deeper into a long list.
Eric
@jin1: To clarify things, maybe you could provide an input case for which this implementation doesn't fit your need? Either a case where the goal fails where it should succeed, or the opposite.
Jerome
+1  A: 

So I checked with my professor and since our deadline has passed, he is OK with me posting my solution to this problem. This is probably not the most succinct way to solve the problem, and I'm leaning on my Scheme a bit, but it appears to work:

%car operations
    car([],null).
    car([X|_],X).
   cadr([_|L],R) :-
    car(L,R).
  caddr([_|L],R) :-
    cadr(L,R).

%cdr operations
   cdr([],[]).
   cdr([_|L],L).
  cddr([_|L],R) :-
    cdr(L,R).
 cdddr([_|L],R) :-
    cddr(L,R).

%two-pair operation
%  This algorithm is based on the provided example
%  solution for CSC388FA09HW4.
long-enough(L,_) :-
    length(L,X),
    X>3.
too-long(L,_) :-
    length(L,X),
    X>4.
two-pair([Head|Tail]) :-
    long-enough([Head|Tail],_),
    (
        (car(Tail,N2),cadr(Tail,N3),caddr(Tail,N4),Head+N2=:=N3+N4);
        (cadr(Tail,N2),car(Tail,N3),caddr(Tail,N4),Head+N2=:=N3+N4);
        (caddr(Tail,N2),car(Tail,N3),cadr(Tail,N4),Head+N2=:=N3+N4)
    );
    too-long([Head|Tail],_),
    (
        two-pair(Tail);
        cdr(Tail,N2),two-pair([Head|N2]);
        car(Tail,N2),cddr(Tail,N3),two-pair([Head|[N2|N3]]);
        car(Tail,N2),cadr(Tail,N3),cdddr(Tail,N4),two-pair([Head|[N2|[N3|N4]]])).
AJ
If you want this to be more useful to people it would be good to add some comments. Then if you look back at this code in 5 years time you won't have to think too hard to understand it again...
Dan J