Member of a list, sum previous members list prolog - list

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.

Related

Recursion on a list involving arithmetic operations and counting elements?

I'm struggling to really grasp the understanding of Prolog lists and recursive calls. I've been working on a program to keep track of how many items are greater than the head of the list and then recursively call this relation to check greater than the next element and so on. I've gotten my program working to the point where it can count the number of elements greater than the head but once it reaches the end and tries to recursively call the relation on the next element it fails. From the research I've done here's what I have and how I think it's supposed to work:
Input - List = [7,2,4,3,6,9,8,10,12,5].
testHead(List).
testHead([H|T]) :-
greaterThan(H,T,0),
teastHead(T).
^My understanding is this relation takes the head element from the list and calls greaterThan using the head and the rest of the list. After the greaterThan finishes, it should recursively call testHead(T) to test the next element and so on.
greaterThan(H,[X|T],C) :-
H > X ->
C2 is C+1,
greaterThan(H,T,C2);
greaterThan(H,T,C).
^My understand here is the greaterThan reads in the head element, the rest of the list, and a variable for counting. If the head is greater than the next element, increase the count and recursively call greaterThan with the Tail and new count; else recursively call greaterThan without incrementing count.
My expected output would be C2 = 12. (7 is greater than 5 elements, 2 is greater than 0 elements, 4 is greater than 1 element, and so on)
The actual output currently is 5; then false.
My program seems to be correctly evaluating and incrementing for the head element but when it finishes greaterThan for that element the program returns false. I've tried researching and understanding lists and recursive calls in prolog but I've been hitting a wall. I'm not sure if it fails because you can't recursively run the increment relation or if there's some other issue with my list relation. Any clarification on how to tackle this issue and how prolog functions here would be helpful.
Lets start with your first code snippet:
testHead(List).
testHead([H|T]) :-
greaterThan(H,T,0),
teastHead(T).
You got the idea of recursion but I see four problems.
First: there is only one attribute for testHead, which means (besides true and false) you get nothing back. So it should look more like this: testHead([H|T], L) ....
Second: you need to know when to stop. This is normally the first line of a predicate. Yours states: anything matches. But it should say something like: if there is no element left, I can "return" an empty list. testHead([],[]).
Third: You call greaterThan(H,T,0) with the fixed value 0, which means you want to test if the "output" value is zero. Which is not the case, you want to count stuff. So put a variable here: N
Fourth: If you have calculated a value N you have to forward it to the outputlist. Since you will get the list Nlist from your recursive call, you can create a new list with N as the head element and Nlist as the tail and "return" this new list.
Conclusion:
testHead([],[]).
testHead([H|T],[N|Nlist]) :-
greaterThan(H,T,N),
testHead(T,Nlist).
Sadly we can not test it yet, we have to have a look at greaterThan/3.
Your snippet is the following:
greaterThan(H,[X|T],C) :-
H > X ->
C2 is C+1,
greaterThan(H,T,C2);
greaterThan(H,T,C).
And also here are some parts odd.
First: You need to tell when to stop. Usually you stop with the empty list [] or if the list has only one element left [A]. If you are not interested in the content of A you use a "throw away variable" which starts with an underscore _. This results in: greaterThan(_,[],0). Which means: if my list is empty, there are 0 numbers greater in my list, no matter what the refence value was. Also since the order of rules matters you put this on top of your recursion rule.
Second: You got the cases right, so if H is larger than the head X of the list do something, otherwise "ignore" X by just calling the same predicate without X. The problem appears in the something part: since the value of C2 is unificated before C you need to calculate C depending on C2 and not vice versa. C is C2+1 means: I know the value C2 from the recursion call and since H>X I want to add one to its value and "return" it.
Third: You know the value of C2 just after asking greaterThan(H,T,C2), so put the C is C2+1 after it.
Ok, now we got:
greaterThan(_,[],0).
greaterThan(H,[X|T],C) :-
H > X ->
greaterThan(H,T,C2),
C is C2+1;
greaterThan(H,T,C).
testHead([],[]).
testHead([H|T],[N|Nlist]) :-
greaterThan(H,T,N),
testHead(T,Nlist).
Lets test it!
?- testHead( [7,2,4,3,6,9,8,10,12,5],L).
L = [5, 0, 1, 0, 1, 2, 1, 1, 1, 0] ;
false.
Looks good besides that you don't want a list but a total number. Ok, here you go:
testHead([],0).
testHead([H|T],New) :-
greaterThan(H,T,N),
testHead(T,NN),
New is NN+N.
?- testHead( [7,2,4,3,6,9,8,10,12,5],N).
N = 12 ;
false.
Explanation: if your input list is empty, there is nothing to be done, "return" the neutral element for addition: 0.
If your inputlist has a head element H, calculate the "greater as N remaining elements" through greaterThan(H,T,N). Assume your code works so you can call testHead(T,NN) for your tail list T and get the sum value NN. If both values N and NN are known, add them and state it as the "return".

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.

swi-prolog Combination of lists whose heads are unique

I tried to modify this combination predicate:
comb(+PairCount,+List,-Combination)/3
comb(0,_,[]).
comb(N,[X|T],[X|Comb]):-N>0,N1 is N-1,comb(N1,T,Comb).
comb(N,[_|T],Comb):-N>0,comb(N,T,Comb).
To make it include only lists with unique heads so that when I run this:
?- comb(2, [[1,2],[1,3],[2,4]], L].
I should get:
L= [[1,2],[2,4]];
L= [[1,3],[2,4]].
I tried something like this but since I can't get current CombinationList, I can't restrict it by this way:
comb(0,_,[]).
comb(N,[X|T],[X|Comb]):-
N>0, N1 is N-1,
+ X = [H|_],
+ % H is not head of any of the current CombinationList's items,
comb(N1,T,Comb).
comb(N,[_|T],Comb):-
N>0,
comb(N,T,Comb).
I may be thinking unnecessarily procedural, but here it is. It would be also fine if you propose a whole different solution instead of modifying my given predicate.

Finding Length of List in Prolog

I'm running Prolog and trying to write a small function returning the length of a list:
len([],0).
len([XS], Y) :-
len([X|XS], M),
Y is M+1.
My logic is that the recursive call should include the tail of the list (XS) and increase 1 to the previous length (Y is M+1.)
This always returns false.
Any thoughts?
Here is a general methodology for debugging and testing Prolog predicates:
Start with the most general query!
Think of it: In Prolog you do not need to make up some test data. You don't even need to understand a predicate at all: Just hand in free variables! That is always a professional move!
So in your case, that's
?- len(L,N).
L = [], N = 0
; loops.
Your definition is not that bad as you claim: At least, it is true for the empty list.
Now, maybe look at the compiler warnings you probably received:
Warning: user://1:11:
Singleton variables: [X]
Next read the recursive rule in the direction of the arrow :- that is, right-to-left:
Provided len([X|Xs], M) is true and Y is M+1 is true, provided all that is true, we can conclude that
len([XS], Y) is true as well. So you are always concluding something about a list of length 1 ([Xs]).
You need to reformulate this to len([X|Xs], M) :- len(Xs, N), Y is M+1.
And here is another strategy:
Generalize your program
By removing goals, we can generalize a program1. Here is my favorite way to do it. By adding a predicate (*)/1 like so:
:- op(950,fy, *).
*_.
Now, let's remove all goals from your program:
len([],0).
len([XS], Y) :-
* len([X|XS], M),
* Y is M+1.
What we have now is a generalization. Once again, we will look at the answers of the most general query:
?- len(L, N).
L = [], N = 0
; L = [_].
What? len/2 is only true for lists of length 0 and 1. That means, even len([1,2], N) fails! So now we know for sure: something in the visible remaining part of the program has to be fixed. In fact, [XS] just describes lists of length 1. So this has to be removed...
Fine print:
1 Certain restrictions apply. Essentially, your program has to be a pure, monotonic program.

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.