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".
Related
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.
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.
b = [1,2,3,4,5,6,7]
for n in b:
if n > 3:
b.remove(n)
I print b, and get the following list:
[1,2,3,5,7]
Why are 5 and 7 still present? I can make a function that pretty much does the same thing and removes all numbers from the list about 3, so why can't I do the same in Terminal?
This is a well-known issue. Iterators are not reliable when you modify the underlying collection while using the iterator.
As for the behavior you experience:
With CPython, the list iterator is represented by an index into the array. If you remove an item from the list at the iterator position or before it while still iterating over it, the iterator jumps forward. The iterator position index is still the same, but all items "under" the iterator have just moved to the left by one position. This makes the iterator skip one element. Hence you only remove every second item.
l = [1, 2, 3, 4]
^it(pos=1)
l.remove(2)
l = [1, 3, 4]
^it(pos=1)
it.next() # automatically at the end of each for loop
l = [1, 3, 4] # we just skipped over an item
^it(pos=2)
Here's a nice little treatise on the topic from #mgiuca.
Interestingly enough, removing items after the iterator position is safe with the current implementation.
In short: don't modify collections while iterating over them. Alternatives for lists: Remove items from a list while iterating in Python
Thats because you are iterating over the same list. Try this:
b = [1,2,3,4,5,6,7]
c = b[:]
for n in c:
if n > 3:
b.remove(n)
If you see the below image, now I creating two different list.
When you remove an element, the array is modified (elements shifted to the left), so the next iteration takes you to the next element bypassing the shifted element. That is to say, the array is modified and the loop advances to the next index. That is why you notice a jump every time an element is removed.
I am trying to find the index position of the minimum element in a list and print the element at the corresponding index position in another list.
For example:
?- min2(X,Y,[a,b,c],[5,3,7]).
X= b
y= 3
Code:
min2(A,B,[A|_],[B|_]).
min2(A,B,[X|T1],[Y|T2]) :- smallest(W,[Y|T2]), % using a predicate to find the min element in the list
B is W, % setting B to the result of above(i.e the min element)
min2(A,B,T1,T2). % looking up position corresponding to min element in list1
the predicate for finding the min element in the list is:
smallest(Head, [Head]).
smallest(Element, [Head|Tail]) :- smallest(E, Tail), Head =< E, Element is Head.
smallest(Element, [Head|Tail]) :- smallest(E, Tail), E < Head , Element is E.
The result I am getting is :
X = a,
Y = 5 ;
X = b,
Y = 3 ;
false.
It somehow picks the first element also. My base case could be wrong? I tried altering the base case to min2(A,B,[A|_],[B|_]). and it breaks.
Please show me where I am going wrong.
Since you first write the fact (A,B,[A|_],[B|_]). it first returns the head elements of the 2 list.
You need to trim the heads of the lists until the head of the second list is equal to B. As soon as you find that the head of list2 is equal to B, you need to return the head of list1.
Maybe you want to try this:
min2(A,B,[A],[B]). %base case
min2(A,B,[X|T1],[Y|T2]) :- smallest(W,[Y|T2]), B is W, min2(A,B,T1,T2), !.
min2(A,B,[H1|T1],[H2|T2]):- B=:=H2 -> A = H1 ; min2(A,B,T1,T2).
Couldn't try it (because im currently at work). But i think it should be smth like this.
To give you little thing more, my definition of smallest in opposite order, like min_list:
smallest([A], A).
smallest([A, B|C], D) :- A > B, smallest([B|C], D), !.
smallest([A, _|B], C) :- smallest([A|B], C).
Simpler I think (and yours was also copy, not your own code). The corresponding predicate was, like I posted in DaniWeb:
corresponding(A, B, [A|_], [B|_]).
corresponding(A, B, [_|C], [_|D]) :-
corresponding(A, B, C, D).
By combining these in self-obvious minimal rule, you get your min2 predicate. I mean that you are way overcomplicating things
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.