Prolog finding a integer complement in a list - list

Given a sorted, no duplicates list L I would like to find out if it has at least one pair of complementary integers (i.e. <-1,1>, <-2,2>, etc.)
I am puzzled how to structure this one functionally in prolog. Essentially what I want to do is iterate through each negative number one by one and check if its complement (positive number digit) exists in the list. Normally this would be a double loop in other languages but how could I do this in Prolog?
Here's what I have so far but I am curious if there is a more elegant solution without using a control statement...
findint(X,[X|_]).
findint(X,[_|Tail]) :- findint(X,Tail).
findpair([X|Tail]) :- X < 0, Y is -1*X, (findint(Y,Tail) -> true ; findpair(Tail)).

a 'trick of the trade': use member/2 instead of iteration
complement_integers(L, I1,I2) :-
member(I1,L),
member(I2,L),
I1 =:= -I2.

Related

Efficient way to find numbers that multiply to given numbers

I'm given 2 lists, a and b. Both them contain only integers. min(a) > 0, max(a) can be upto 1e10 and max(abs(b)) can be upto 1e5. I need to find the number of tuples (x, y, z), where x is in a and y, z are in b such that x = -yz. The number of elements in a and b can be upto 1e5.
My attempt:
I was able to come up with a naive n^2 algorithm. But, since the size can be upto 1e5, I need to come up with a nlogn solution (max) instead. What I did was:
Split b into bp and bn where the first one contains all the positive numbers and second one contains all the negative numbers and created their maps.
Then:
2.1 I iterate over a to get x's.
2.2 Iterate over the shorter one of bn and bp. Check if the current element divides x. If yes, use map.find() to see if z = -x/y is present or not.
What could be an efficient way to do this?
There's no O(n*logn) because: z = -x/y <=> log(z) = log(-x) - log(y)
As https://stackoverflow.com/users/12299000/kaya3 has mentioned, it is 3SUM#3_different_arrays. According to wikipedia:
Kane, Lovett, and Moran showed that the 6-linear decision tree complexity of 3SUM is O(n*log^2n)
Step 1: Sort the elements in list b (say bsorted)
Step 2: For a value x in a, go through the list bsorted for every value y in bsorted and binary search for (-x/y) on bsorted to find z
Complexity |a|=m and |b|=n complexity is O(mnlogn)
Here's an untested idea. Create a trie from the elements of b, where the "characters" are ordered prime numbers. For each element in a, walk all valid paths in the trie (DFS or BFS, where the test is being able to divide further by the current node), and for each leaf reached, check if the remaining element (after dividing at each node) exists in b. (We may need to handle duplicates by storing counts of each "word" and using simple combinatorics.)

Member of a list, sum previous members list prolog

I want to verify if a member of list, is the sum of the previous numbers.
Example: [0,1,3,4,18,19]. This is TRUE because 0+1+3 = 4
sum_([],0).
sum_([X|XS],R):- suma(XS,R1), R is X + R1.
existsSum(L,[X|C]):-append(A,[X|B],L),
append(A,B,C),
sum_(C,X).
I am stuck here. Any idea? Thanks.
Why append(A,[X|B],L),append(A,B,C),sum_(C,X)? In this way you want the sum of all elements except X to be equal to X.
It is not clear what the arguments of existsSum should be. Supposing existsSum(InputList, SubList, Element):
existsSum(L,A,X) :- append(A,[X|_B],L), sum_(A,X).
With your example produces these results:
?- existsSum([0,1,3,4,18,19], Sublist, Element).
Sublist = [],
Element = 0 ;
Sublist = [0, 1, 3],
Element = 4 ;
false.
Note: also [] and 0 is a solution because of how you defined the sum_ predicate, i.e. the sum of [] is 0.
If you change the sum_ predicate in this way:
sum_([X],X).
sum_([X|XS],R):- sum_(XS,R1),R is X + R1.
it is defined only for non-empty lists, and in this case you get only one result from your example:
?- existsSum([0,1,3,4,18,19], Sublist, Element).
Sublist = [0, 1, 3],
Element = 4 ;
false.
I think your problem is ill-stated (or your example should not start with zero) because I think you basically have two ways you can process the list: either you process the entire list every time (and your example fails because 0+1+3+4+18 != 19) or you stop as soon as your expected value matches the head of the list, in which case [0] is already successful.
In the end, there aren't that many ways to process a list. You have to make a decision when you have an element, and you have to make a decision when you are out of elements. Suppose we want to succeed as soon as we have reached a value that matches the sum-so-far. We can model that fairly simply like this:
exists_sum(List) :- exists_sum(0, List).
exists_sum(RunningTotal, [RunningTotal|_]).
exists_sum(RunningTotal, [H|T]) :-
NewRunningTotal is RunningTotal + H,
exists_sum(NewRunningTotal, T).
Note that with this formulation, [0|_] is already successful. Also note that I have no empty list case: if I make it to the end of a list without having succeeded already, there is no solution there, so there's nothing to say about it.
The other formulation would be to require that the entire list is processed, which would basically be to replace the first exists_sum/2 clause with this:
exists_sum(Total, [Total]).
This will fail to unify exists_sum(4, [4|_]) which is the case you outline in the question where [0,1,3,4...] succeeds.
There may be other formulations that are more complex than these, but I don't see them. I really think there are only a couple ways to go with this that make sense.

How to Compare two lists with values and ranges in Prolog

I'm doing a project, and i'm stuck in a situation where i need to compare two lists and return if at least one member from a list is in the another list. Pretty simple, but the lists may contain not only numbers but range of numbers. Something like: [1,3,range(5,10),25]
I think my main problem is iterating the lists, because it only returns trueif the first list member matches the atom. This is my code for the comparison:
findin(E,[H|T]) :-
E == H ;
(H == range(X,Y), E \== range(Xe,Ye), between(X,Y,E)) ;
(E == range(Xe,Ye), H \== range(X,Y), between(Xe,Ye,H)) ;
(E == range(Xe,Ye), H == range(X,Y), (between(X,Y,Xe) ; between(Xe,Ye,X))) ,
findin(E,T).
And the code to call the findin/2 function:
find([Ha|Ta],[Hb|Tb]) :-
findin(Ha,[Hb|Tb]),
find(Ta,[Hb|Tb]).
I'm missing something? Also, any ideas for iterating A and B lists from the find/2 function?
So if input don't have to be sorted here is solution
doubleRangeCheck(range(Xa,Ya),range(Xb,Yb)) :-
between(Xa,Ya,Xb) ; between(Xa,Ya,Yb),!.
Checks if one of rangeB ends is in rangeA range.
numInRange(number(A),range(Xb,Yb)) :-
between(Xb,Yb,A),!.
Checks if number is in range
findInX(A,[Hb|Tb]) :-
A = Hb ;
(doubleRangeCheck(A,Hb); doubleRangeCheck(Hb,A));
numInRange(A,Hb);
numInRange(Hb,A);
findInX(A,Tb),!.
Checking if:
1. if both elements are same,
2. if one range contains any of another ranges ends, and vice versa (you was checking badly 2 ranges case),
3/4. Checking if num is in range (and if Hb or A are ranges at all),
5. ...
findX([Ha|Ta],[Hb|Tb]) :-
findInX(Ha,[Hb|Tb]);
findX(Ta,[Hb|Tb]),!.
Part that was good, except closing bracket.
If input have to be sorted, than you can use some kind of merge sort, it would be MUCH MORE effective and interesting. Recommend to do this case by yourself.

find maximum in a list in Prolog [duplicate]

Is it possible to create a predicate max/2 without an accumulator so that max(List, Max) is true if and only if Max is the maximum value of List (a list of integers)?
Yes, you can calculate the maximum after the recursive step. Like:
max([M],M). % the maximum of a list with one element is that element.
max([H|T],M) :-
max(T,M1), % first calculate the maximum of the tail.
M is max(H,M1). % then calculate the real maximum as the max of
% head an the maximum of the tail.
This predicate will work on floating points for instance. Nevertheless it is better to use an accumulator since most Prolog interpreters use tail call optimization (TCO) and predicates with accumulators tend to work with tail calls. As a result predicates with TCO will usually not get a stack overflow exception if you want to process huge lists.
As #Lurker says, is only works in case that the list is fully grounded: it is a finite list and all elements grounded. You can however use Prolog's constraint logic programming package clp(fd):
:- use_module(library(clpfd)).
max([M],M). % the maximum of a list with one element is that element.
max([H|T],M) :-
max(T,M1), % first calculate the maximum of the tail.
M #= max(H,M1). % then calculate the real maximum as the max of
% head an the maximum of the tail.
You can then for instance call:
?- max([A,B,C],M),A=2,B=3,C=1.
A = 2,
B = M, M = 3,
C = 1 ;
false.
So after the max/2 call, by grounding A, B and C, we obtain M=3.
Neither the standard predicate is/2 nor a CLP(FD) predicate (#=)/2 can do mathematics here. So that in the end, for certain applications such as exact geometry, they might not be suitable.
To make a point lets consider an example and the alternative of a computer algebra system (CAS). I am doing the demonstration with the new Jekejeke Minlog 0.9.2 prototype which provides CAS from within Prolog.
As a preliminary we have two predicates eval_keys/2 and min_key/2, their code is found at the appendix in this post. Lets illustrate what this predicates do, first with integer. The first predicate just makes the keys of a pair list evaluated:
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.3.25-3-gc3a87c2)
Copyright (c) 1990-2016 University of Amsterdam, VU Amsterdam
?- eval_keys([(1+3)-foo,2-bar],L).
L = [4-foo,2-bar]
The second predicate picks this first value where the key is minimum:
?- min_key([4-foo,2-bar],X).
X = bar
Now lets look at other key values, we will use square roots, which belong to the domain of algebraic numbers. Algebraic numbers are irrational and thus never fit into a float. We therefore get for the new example the outcome foo:
?- eval_keys([(sqrt(98428513)+sqrt(101596577))-foo,sqrt(400025090)-bar],L).
L = [20000.62724016424-foo, 20000.627240164245-bar].
?- min_key([20000.62724016424-foo, 20000.627240164245-bar], X).
X = foo.
CLP(FD) has only integers and there is no direct way to represent algebraic numbers. On the other hand many CAS systems support radicals. Our Prototype even supports comparison of them so that we can obtain the exact result bar:
Jekejeke Prolog 2, Runtime Library 1.2.2
(c) 1985-2017, XLOG Technologies GmbH, Switzerland
?- eval_keys([(sqrt(98428513)+sqrt(101596577))-foo,sqrt(400025090)-bar],L).
L = [radical(0,[98428513-1,101596577-1])-foo,
radical(0,[400025090-1])-bar]
?- min_key([radical(0,[98428513-1,101596577-1])-foo,
radical(0,[400025090-1])-bar],X).
X = bar
That bar is the exact result can be seen for example by using a multi-precision calculator. If we double the precision we indeed see that the last square root is the smaler one and not the sum of the square roots:
?- use_module(library(decimal/multi)).
% 7 consults and 0 unloads in 319 ms.
Yes
?- X is mp(sqrt(98428513)+sqrt(101596577), 32).
X = 0d20000.627240164244658958331341095
?- X is mp(sqrt(400025090), 32).
X = 0d20000.627240164244408966171597261
But a CAS need not to proceed this way. For example our Prolog implementation uses a Swinnerton-Dyer polynomial inspired method to compare radical expressions, which works purely symbolic.
Appendix Test Code:
% :- use_module(library(groebner/generic)). /* to enable CAS */
eval_keys([X-A|L], [Y-A|R]) :- Y is X, eval_keys(L, R).
eval_keys([], []).
min_key([X-A|L], B) :- min_key(L, X, A, B).
min_key([X-A|L], Y, _, B) :- X < Y, !, min_key(L, X, A, B).
min_key([_|L], X, A, B) :- min_key(L, X, A, B).
min_key([], _, A, A).

O(log n) algorithm to find the element having rank i in union of pre-sorted lists

Given two sorted lists, each containing n real numbers, is there a O(log n) time algorithm to compute the element of rank i (where i coresponds to index in increasing order) in the union of the two lists, assuming the elements of the two lists are distinct?
EDIT:
#BEN: This i s what I have been doing , but I am still not getting it.
I have an examples ;
List A : 1, 3, 5, 7
List B : 2, 4, 6, 8
Find rank(i) = 4.
First Step : i/2 = 2;
List A now contains is A: 1, 3
List B now contains is B: 2, 4
compare A[i] to B[i] i.e
A[i] is less;
So the lists now become :
A: 3
B: 2,4
Second Step:
i/2 = 1
List A now contains A:3
List B now contains B:2
NoW I HAVE LOST THE VALUE 4 which is actually the result ...
I know I am missing some thing , but even after close to a day of thinking I cant just figure this one out...
Yes:
You know the element lies within either index [0,i] of the first list or [0,i] of the second list. Take element i/2 from each list and compare. Proceed by bisection.
I'm not including any code because this problem sounds a lot like homework.
EDIT: Bisection is the method behind binary search. It works like this:
Assume i = 10; (zero-based indexing, we're looking for the 11th element overall).
On the first step, you know the answer is either in list1(0...10) or list2(0...10). Take a = list1(5) and b = list2(5).
If a > b, then there are 5 elements in list1 which come before a, and at least 6 elements in list2 which come before a. So a is an upper bound on the result. Likewise there are 5 elements in list2 which come before b and less than 6 elements in list1 which come before b. So b is an lower bound on the result. Now we know that the result is either in list1(0..5) or list2(5..10). If a < b, then the result is either in list1(5..10) or list2(0..5). And if a == b we have our answer (but the problem said the elements were distinct, therefore a != b).
We just repeat this process, cutting the size of the search space in half at each step. Bisection refers to the fact that we choose the middle element (bisector) out of the range we know includes the result.
So the only difference between this and binary search is that in binary search we compare to a value we're looking for, but here we compare to a value from the other list.
NOTE: this is actually O(log i) which is better (at least no worse than) than O(log n). Furthermore, for small i (perhaps i < 100), it would actually be fewer operations to merge the first i elements (linear search instead of bisection) because that is so much simpler. When you add in cache behavior and data locality, the linear search may well be faster for i up to several thousand.
Also, if i > n then rely on the fact that the result has to be toward the end of either list, your initial candidate range in each list is from ((i-n)..n)
Here is how you do it.
Let the first list be ListX and the second list be ListY. We need to find the right combination of ListX[x] and ListY[y] where x + y = i. Since x, y, i are natural numbers we can immediately constrain our problem domain to x*y. And by using the equations max(x) = len(ListX) and max(y) = len(ListY) we now have a subset of x*y elements in the form [x, y] that we need to search.
What you will do is order those elements like so [i - max(y), max(y)], [i - max(y) + 1, max(y) - 1], ... , [max(x), i - max(x)]. You will then bisect this list by choosing the middle [x, y] combination. Since the lists are ordered and distinct you can test ListX[x] < ListY[y]. If true then we bisect the upper half our [x, y] combinations or if false then we bisect the lower half. You will keep bisecting until find the right combination.
There are a lot of details I left, but that is the general gist of it. It is indeed O(log(n))!
Edit: As Ben pointed out this actually O(log(i)). If we let n = len(ListX) + len(ListY) then we know that i <= n.
When merging two lists, you're going to have to touch every element in both lists. If you don't touch every element, some elements will be left behind. Thus your theoretical lower bound is O(n). So you can't do it that way.
You don't have to sort, since you have two lists that are already sorted, and you can maintain that ordering as part of the merge.
edit: oops, I misread the question. I thought given value, you want to find rank, not the other way around. If you want to find rank given value, then this is how to do it in O(log N):
Yes, you can do this in O(log N), if the list allows O(1) random access (i.e. it's an array and not a linked list).
Binary search on L1
Binary search on L2
Sum the indices
You'd have to work out the math, +1, -1, what to do if element isn't found, etc, but that's the idea.