The task is to delete all increasing subseries from a list. For example:
deleteInc([2,4,6,5,8,12,8,3],L) should produce L=[8,3] as result
I tried to solve it, but it's not working properly and I can't figure out the correct solving. Can somebody help me out please with a correct solution? Thanks in advance :)
My Code:
deleteInc([],[]).
deleteInc([H1,H2|T],L):-
H2>=H1,
!,
deleteInc(T,L).
deleteInc([H1,H2|T],[H2|T2]):-
H2<H1,
deleteInc(T,T2).
Here's what I did, assuming it's checking three values at a time:
deleteInc([],[]).
deleteInc([H1,H2,_H3|T],L):-
H2>=H1,
!,
deleteInc(T,L).
deleteInc([H1,H2|T],[H1,H2|T2]):-
H2<H1,!,
deleteInc(T,T2).
Example:
?-deleteInc([2,4,6,5,8,12,8,3],L).
L = [8, 3]
?-deleteInc([2,4,6,5,8,12,15,21,25,7,3],L).
L = [7, 3]
?-deleteInc([2,4,6,5,8,12,15,21,25,55,77,88,65,38],L).
L = [65, 38]
Here's an approach to collect all combinations that are not increasing:
deleteInc(L,[],L).
deleteInc([H1,H2|T],L,Rest):-
H2>=H1,
!,
deleteInc(T,L,Rest).
deleteInc([H1,H2|T],[H1,H2|L],Rest):-
H2<H1,!,
deleteInc(T,L,Rest).
Example:-
?-deleteInc([2,4,6,5,8,12,15,21,25,55,77,88,65,38],L,_).
L = []
L = []
L = [6, 5]
L = [6, 5]
L = [6, 5]
L = [6, 5]
L = [6, 5]
L = [6, 5, 65, 38]
?-deleteInc([2,4,6,5,8,12,15,21,25,7,3],L,_).
L = []
L = []
L = [6, 5]
L = [6, 5]
L = [6, 5]
L = [6, 5, 25, 7]
?-deleteInc([2,4,6,5,8,12,8,3],L,_).
L = []
L = []
L = [6, 5]
L = [6, 5]
L = [6, 5, 8, 3]
I would implement it like this:
deleteInc(In, Out):-
deleteInc(In,Out,new).
deleteInc([A],[A],new).
deleteInc([_],[],incr).
deleteInc([H1,H2|T],L,_):-
H2>=H1,
!,
deleteInc([H2|T],L,incr).
deleteInc([H1,H2|T],T2,incr):-
H2<H1,
deleteInc([H2|T],T2,new).
deleteInc([H1,H2|T],[H1|T2],new):-
H2<H1,
deleteInc([H2|T],T2,new).
A third attribute indicates if your are currently in a new or increasing streak.
If the two head elements of the list are in increasing order, the third element is pretty much ignored. Please note to forward not the list T but [H2|T] since you need the element H2 for further comparison. If you are in a streak (incr) and the current two head elements are not increasing, you do the same as before: ignore. However if you just started a new streak and the current head elements are decreasing, you put the first head element in the return list. Special cases for one element. Let's check:
?- deleteInc([2,4,6,5,8,12,8,3],L).
L = [8, 3] ;
false.
Looks good.
Another approach would be to just check for 3 succeeding elements if the middle one is smaller than the first but larger than the third. If this is the case: store the element. If this is is not the case: check the list without the first head element.
Add a rule for 2 elements left. Also there needs to be a special treatment for the very first element, because this is not covered in the main rule. By using the cut you can "catch" the left over case (two increasing elements or weird input with one or no element) with the last line. Please note that the order of the rules is important for the program to work.
deleteInc([H1,H2|L], [H1|R]):-
H1 >= H2,
!,
deleteInc1([H1,H2|L], R).
deleteInc([H1,H2|L], R):-
deleteInc1([H1,H2|L], R).
deleteInc1([H1,H2,H3|L], [H2|R]):-
H1 > H2,
H2 > H3,
!,
deleteInc1([H2,H3|L], R).
deleteInc1([A,B],[B]):-
A > B,
!.
deleteInc1([_|L], R):-
!,
deleteInc1(L, R).
deleteInc1(_,[]).
Let's test it:
?- deleteInc([2,4,6,5,8,12,8,3],L).
L = [8, 3].
Works (for lists of numbers).
And yet another solution would be to count the length of the streak and to filter out all results which have more than one element. The following code starts with count 0 for the first element and uses the successor predicate s/1 for counting:
deleteInc(In, Out):-
countInc(In,0,InC),
delInc(InC,Out).
countInc([A], C, [(A,C)]).
countInc([A,B|L], C, Out):-
A =< B,
countInc([B|L], s(C), Out).
countInc([A,B|L], C, [(A,C)|Out]):-
A > B,
countInc([B|L], 0, Out).
delInc([],[]).
delInc([(E,0)|L],[E|R]):-
delInc(L,R).
delInc([(_,s(_))|L],R):-
delInc(L,R).
Output:
?- deleteInc([2,4,6,5,8,12,8,3],L)
L = [8, 3] ;
false.
As expected
The problem is as follows: Write a predicate in Prolog most_common_sublist(L1,N,L2) that will find the sublist L2 with length N such that it is the most common sublist in L1.
//Example 1:
?- most_common_sublist([1,2,2,3,2,2,4,2,2,3],1,L).
L=[2];
//Example 2:
?- most_common_sublist([1,2,2,3,2,2,4,2,2,3],2,L).
L=[2,2];
//Example 3:
?- most_common_sublist([1,2,2,3,2,2,4,2,2,3],3,L).
L=[2,2,3];
My approach was to generate all the possible sublists of size N using the generator predicate, check which of those is the most common one in the list using the check predicate, and then just put that as my result.
The reason why I'm not using the built-in predicates for length and add is because I'm supposed to write my own.
My generator predicate works, it gives out the correct output.
?- generator([1,2,2,3,2,2,4,2,2,3],3,L).
L = [[1, 2, 2], [2, 2, 3], [2, 3, 2], [3, 2, 2], [2, 2, 4], [2, 4, 2], [4, 2|...], [2|...]] [write]
L = [[1, 2, 2], [2, 2, 3], [2, 3, 2], [3, 2, 2], [2, 2, 4], [2, 4, 2], [4, 2, 2], [2, 2, 3]]
I checked all my predicates and they all seem to work (at least for the test cases I'm using), the problem occurs with the check predicate. It seems to work fine until it gets to N>=P (when this is NOT true, works fine when it is true). I expect the program to go onto the next check predicate under it (the third check predicate) so that it stores Temp value in Result instead of the H value. For some reason it does not go to the third check predicate (I checked with debugger), instead it does something weird (I can't figure out what).
most_common_sublist(L,N,Result):-generator(L,N,LOP),check(LOP,_,Temp),add(Temp,[],Result).
add([],L,L).
add([X|L1],L2,[X|L3]):-add(L1,L2,L3).
length([],0).
length([X|O],N):-length(O,M),N is M+1.
sublist([H|_],1,[H]).
sublist([H|T],N,[H|LOP]):-M is N-1,sublist(T,M,LOP).
generator(L,N,[L]):-length(L,M),N=:=M.
generator([H|T],N,LOP):-sublist([H|T],N,PN),generator(T,N,LP),add([PN],LP,LOP).
check([],Z,K):-Z is 0,add([],[],K).
check([H|T],Hits,Result):-check_how_many(H,[H|T],N),check(T,P,_),N>=P,Hits is N,add(H,[],Result).
check([H|T],Hits,Result):-check_how_many(H,[H|T],N),check(T,P,Temp),Hits is P,add(Temp,[],Result).
check_how_many(X,[X],1).
check_how_many(_,[_],0).
check_how_many(Pattern,[H|T],Hits):-same(Pattern,H),check_how_many(Pattern,T,P),Hits is P+1.
check_how_many(Pattern,[_|T],Hits):-check_how_many(Pattern,T,P),Hits is P.
same([], []).
same([H1|R1], [H2|R2]):-
H1 = H2,
same(R1, R2).
Since I'm not familiar with your code I rewrote it with similar functionality. Lines followed by %here are my improvements (2 times used). For simplicity I used the inbuild predicates length/2 and append/3 instead of add/3. sublist/3 has a complete different code but same functionality, same/2 is not necessary at all. Most uses of you add/3 were not necessary as well as some equality statements.
most_common_sublist(L,N,Temp):-
generator(L,N,LOP),
check(LOP,_,Temp).
sublist(L,N,S):-
length(S,N),
append(S,_,L).
generator(L,N,[L]):-
length(L,N).
generator([H|T],N,LOP):-
sublist([H|T],N,PN),
generator(T,N,LP),
append([PN],LP,LOP).
check([],0,[]).
check([H|T],N,H):-
check_how_many(H,[H|T],N),
check(T,P,_),
N>=P.
check([H|T],P,Temp):-
check_how_many(H,[H|T],N),
check(T,P,Temp)
%here
, N=<P
.
check_how_many(X,[X],1).
check_how_many(_,[_],0).
check_how_many(H,[H|T],Hits):-
check_how_many(H,T,P),
Hits is P+1.
check_how_many(Pattern,[H|T],P):-
%here
Pattern \== H,
check_how_many(Pattern,T,P).
After giving up on tracing I just used the following call to debug after enabling long output (
?- set_prolog_flag(answer_write_options,[max_depth(100)]).
):
?- findall(Temp,check([[1, 2, 2], [2, 2, 1]],_,Temp),Out).
Initial output was
Out = [[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[2,2,1],[2,2,1],[],[],[2,2,1],[2,2,1],[],[]].
Which contains way to much empty lists. First fix (%here) was to set the condition N=<P for the last check/3 case. Until now it was possible to choose a P lower than N, which should be covered by the 2nd check/3 case. Output changed to
Out = [[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[2,2,1],[2,2,1],[2,2,1],[]].
Better, but still empty lists possible. A similar case happens in the last check_how_many/3 case: you have to state that H and Pattern are different, otherwise it would be possible for a fitting Pattern not to be counted. Lets check the output
Out = [[1,2,2],[1,2,2],[1,2,2],[2,2,1]].
Way better. Lets check another case:
?- findall(Temp,check([[1, 2, 2], [1, 2, 2], [2, 2, 1]],_,Temp),Out).
Out = [[1,2,2],[1,2,2],[1,2,2],[1,2,2]].
?- findall(Temp,check([[1, 2, 2], [2, 2, 2], [1, 2, 2]],_,Temp),Out).
Out = [[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[2,2,2],[2,2,2],[2,2,2],[1,2,2]].
Works... Almost.
So the problem seems to be check_how_many/3: alter
check_how_many(_,[_],0).
to
check_how_many(_,[],0).
and you should be fine.
?- findall(Temp,check([[1, 2, 2], [2, 2, 2], [1, 2, 2]],_,Temp),Out).
Out = [[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2]].
Since it is way more fun to write the code yourself than to debug foreign code I'll add another answer with my attempt.
It is way more fun to code by yourself than to debug alien code. So here is my attempt. It works different than yours because I do not calculate possible subsets but work on the "leftover" list. I use the inbuild predicates length/2, append/3 and member/2 which are 3 lines each to write down.
% check how often 2.nd attribute List occurs in 1st attribute List.
countit([],_,Val,Val).
countit([H|In],Out,Past,Future):-
( append(Out,_,[H|In])
-> Present is Past+1,
countit(In,Out,Present,Future)
; countit(In,Out,Past,Future)
).
mostCommonSublist(In,N,Out):-
maxStartList(In,N,OutList,Max),
member((Max,Out),OutList).
% for every endlist calculate how often the first N elements appear within the endlist, track the max
maxStartList(In,N,[(1,In)],1):-
length(In,N),
!.
maxStartList([H|In],N,[(CntH,Curr)|MaxList],Max):-
length(Curr,N),
countit([H|In],Curr,0,CntH),
maxStartList(In,N,MaxList,CntIn),
Max is max(CntH , CntIn).
The main predicate mostCommonSublist/3 calls the predicate maxStartList/4 to get all sublists/countpairs. Afterwards it validates if the count of a sublist equals the maximum. This is neccessary to check for different answers with the same (maximum) count.
The maxStartList/4 drops elements from the inputlist and counts how often the start of the current list occurs within it. Also it keeps track of the maximum.
For the current inputlist the calculating predicate countit/4 is called. It calculated for a given inputlist (first argument) the number of occurences of a sublist (2nd argument).
My code actually uses a twist: The content of the sublist is not unified when calling countit/4 for the first time, just the sublist length is set. In the first recursion it will unify all entries with the start elements from the inputlist and count it. In the following recursion steps the sublist if fully known. Using an if-then-else (..->..;..) the two cases for remaining inputlist starts with the sublist or not, the predicate basically counts the occurences. Until the remaining inputlist has only N elements left (length(In,N)).
The calculated count/sublist pairs are stored in a list, the maximum is tracked as well.
After knowing all count/sublist pairs I finallize it all by stating that the count of an accepted sublist has to be equal to the maximum.
The nice thing is that there are no dublicate answers.
?- mostCommonSublist([1,2,2,3,2,2,4,2,2,3],3,L).
L = [2,2,3] ;
false.
?- mostCommonSublist([1,2,2,1,2,1,2,2,2,3],3,L).
L = [1,2,2] ;
L = [2,1,2] ;
false.
?- mostCommonSublist([1,2,2,1,2,1,2,2,2,1],2,L).
L = [1,2] ;
L = [2,2] ;
L = [2,1] ;
false.
I have a function that outputs names that fit a specific constraint. This function is fine.
But I need to use that function to make another function that turns the outputs of the former function into a list. Being a complete beginner with Prolog, I have no clue how to do this.
My problem is that I don't know how to iterate over the outputs to append it to an accumulator. The function which outputs names does so, then I press ";" or SPACE and it outputs the next answer until it's out of answers. I figure this means I have to make multiple calls to the function then append it. But I don't know how many times I need to call it, since I can't iterate over it like a list with [Head|Tail].
Here's what I have so far(although it's probably wrong):
%p1(L,X) determines if chemicals in List X are in any of the products and stores those products in L
p1(L,X) :- p1_helper(L,X,[]).
p1_helper(L,X,Acc) :- has_chemicals(A,X),append(Acc,[A],K),L=K, p1_helper(L,X,K).
function that outputs names with query has_chemicals(X,[List of Chemicals]).:
%has_chemicals(X,Is) determines if the chemicals in List Is are in the chemical list of X.
has_chemicals(X,Is) :- chemicals(X,Y), hc(Y,Is).
%hc(X,Y) determines if elements of Y are in elements of X.
hc(Y,[]).
hc(Y,[C|D]) :- isin(C,Y), hc(Y,D).
Any help is appreciated.
But I need to use that function to make another function that turns the outputs of the former function into a list. Being a complete beginner with Prolog, I have no clue how to do this.
findall(+Template, :Goal, -Bag):
Creates a list of the instantiations Template gets successively on backtracking over Goal and unifies the result with Bag.
For example, how to collect all odd numbers from 1 to 15:
odd( X ) :-
X rem 2 =:= 1.
We can get all that odds one-by-one.
?- between( 1, 15, X ), odd( X ).
X = 1 ;
X = 3 ;
X = 5 ;
X = 7 ;
X = 9 ;
X = 11 ;
X = 13 ;
X = 15.
And we can collect them into a list:
?- findall(X, (between( 1, 15, X ), odd( X )), List).
List = [1, 3, 5, 7, 9, 11, 13, 15].
I think you are looking for a way to capture the output of isin/2. Then you can use the builtin with_output_to/2, and combine it with findall/3, as suggested by other answers.
I encourage you to visit this page especially if you use swi-prolog.
There are 4 predicates that do what you want : findall/3, findall/4, bagof/3 and setof/3.
To summarize, here is the test predicate I'll be working with :
test(0, 3).
test(1, 3).
test(2, 5).
test(3, 4).
First, the simplest, findall/3 and findall/4 :
?- findall(C, test(X, C), Cs).
Cs = [3, 3, 5, 4].
?- findall(C, test(X, C), Cs, TailCs).
Cs = [3, 3, 5, 4|TailCs].
They just return all the alternatives, with duplicates, without sorting, without binding the other free variables, as a normal list for findall/3 and difference list for findall/4. both findalls predicates succeed when the list is empty.
Then, bagof. Basically, bagof/3 works as findall/3 but binds free variables. That means that the same query than above but with bagof/3 returns :
?- bagof(C, test(X, C), Cs).
X = 0,
Cs = [3] ;
X = 1,
Cs = [3] ;
X = 2,
Cs = [5] ;
X = 3,
Cs = [4].
By telling bagof/3 not to bind all the free variables, you obtain findall/3 :
?- bagof(C, X^test(X, C), Cs).
Cs = [3, 3, 5, 4].
Still you have to note that bagof/3 fails when the result is empty, where findall/3 doesn't.
Finally, setof/3. It's basically bagof/3 but with the results sorted and no duplicates :
?- setof(C, X^test(X, C), Cs).
Cs = [3, 4, 5].