Finding all sublists of size N in Prolog - list

I'm new to Prolog and I got stuck on writing this predicate. Basically I'm given a list and I need to find the most common sublist of size N. Examples:
most_common_sublist([1,2,2,3,2,2,4,2,2,3],1,L), output should be L=[2];
most_common_sublist([1,2,2,3,2,2,4,2,2,3],2,L), output should be L=[2,2];
most_common_sublist([1,2,2,3,2,2,4,2,2,3],3,L), output should be L=[2,2,3];
My approach was to write a predicate that gets the first N elements of the list, write a second predicate that will act like a generator (calling the first predicate over and over until the list is shortened to size N), and then check for all of the generated sublists how many times there was match and get the maximum of that.
I got stuck on the generator predicate the rest I'm pretty sure I know how to write.
This is my code so far:
length([],0).
length([_|L],N) :- N is M+1, length(L,M).
// This will get the first N elements from the list.
// I tested it and it works.
sublist([H|_],1,[H]).
sublist([H|T],N,[H|LOP]) :- M is N-1, sublist(T,M,LOP).
// This is supposed to generate all the sublists,
// length is a predicate that returns the length of the list.
generator(L,N,L) :- length(L,M), N=:=M.
generator([H|T],N,[PN|LOP]) :- sublist([H|T],N,PN), generator(T,N,LOP).
This is the error I'm getting:
?- generator([1,2,3,4,5,6,7],2,X).
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [12] _6018 is _6024+1
ERROR: [11] length([1,2|...],_6052) at c:/users/ace_m/documents/prolog/bp.pl:44
ERROR: [10] generator([1,2|...],2,[1,2|...]) at c:/users/ace_m/documents/prolog/bp.pl:83
ERROR: [9] <user>
Exception: (10) generator([1, 2, 3, 4, 5, 6, 7], 2, _5204) ?
I understand that the error means that I'm not passing the correct values, but I don't understand where I'm going wrong. Any help

You can't use a variable in an arithmetic expression before it has been bound to a value.

Related

Iterate over a list and apply modulus/remainder to each element

A method that returns a new list formed by applying the second argument as a modulus operand on each list member, with two arguments: a list and a numerical value.
My current method only applies modulus operand to the first element and not all the elements.
I'm trying to use the cons operator to build the new list.
modList([Head | Tail], Num) -> [Head rem Num | Tail].
You're on the right track.
You're writing a recursive function, so what you need next are two things:
The recursive step: At some point in the body of your function, you need to apply your same function to the rest of the list (i.e. modList(Tail)).
The base case: If you apply the recursive step repeatedly, since you're removing one element from the list on each iteration, at some point, you'll have a list that doesn't match your function head pattern ([Head | Tail]). That will lead to a function_clause error that you can fix by… of course… adding a clause for that list. Since that clause will likely not need to be recursive (i.e. it will return a hardcoded value), that will close the recursion loop and your recursive function will be complete.
Extra tip: It's generally more idiomatic to use snake_case instead of camelCase for function names, module names, and atoms in general in Erlang. In other words, a more common name for your function would be mod_list/2.
You can do something like
> Num = 5.
5
> [X rem Y || X <- [1, 2, 3, 4, 5, 6, 7], Y <- [Num]].
[1,2,3,4,0,1,2]

Prolog - Arguments are not sufficiently instantiated. lists/recursion

I am trying to get the maximum number from a given list 'L' and assign it to a variable, so I used to write the following function:
max(L,X):-
[H|Q]=L,
(X<H -> X=H),
length(Q,QLEN),
(QLEN>0 -> max(Q,X)),
true.
However after compiling the code and prompting max([1,2,3],X) within SWI-Prolog, I get the following error:
ERROR: Arguments are not sufficiently instantiated ERROR: In: ERROR:
[9] _1064<1 ERROR: [8] max([1,2|...],_1092) at c:/users/kais/desktop/tp3.pl:24 ERROR: [7]
Why I'm getting such error?
As said in the comment you try to compare H with X which is not instantiated. A solution to this problem is to create a predicate maxList/3 and call it inside maxList/2 as follows:
maxList([H|T], Max) :-
maxList(T, H, Max).
maxList([], Max, Max).
maxList([H|T], Max0, Max) :-
Max1 is max(H, Max0),
maxList(T, Max1, Max).
?- maxList([1,2,3],X).
X = 3.
max/2 simply returns the max between two arguments. A possible implementation for max/2 could be:
myMax(M,A,B):-
A > B -> M = A;
M = B.
?- myMax(A,1,2).
A = 2.
BTW, there is already a built in predicate in SWI to do this, which is called max_list/2 (the code I posted before actually comes from this implementation):
?- max_list([1,2,3],X).
X = 3.
Another possible implementation, not relying on an auxiliary predicate, can be done according to the following logic:
If the list contains exactly one element, then it is the maximum.
If the list L contains more than one element, i.e. it is of the form [H|T], and the greatest element of T is M, then the greatest element of L will be H if H>=M, otherwise it will be M.
A rough encoding could be:
maxList([X],X).
maxList([H|T],H) :-
maxList(T,M),
H >= M.
maxList([H|T],M) :-
maxList(T,M),
H < M.
This leaves room for improvement, but respects the logic above stated and returns the greatest element for each non-empty integer list.

Prolog - How to get the sum of a list's elements?

I'm very new to prolog and I am trying to write a little program that, given a list, returns the sum of the list's elements. Following all the examples I've seen led me to a solution that looks like this:
addup([],0).
addup([FirstNumber | RestOfList], Total) :-
addup(RestOfList, TotalOfRest),
Total is FirstNumber + TotalOfRest.
But when I test that solution with these values:
?- addup([1,2,3,4],0).
I just get garbage values from it like _34521.
Then I tried a second solution that looks like this:
sum([], 0).
sum([H|T], N):-
X is H+N,
sum(T, X).
This one is able to add up the numbers correctly, but it is unable to pass the final value of X, which is the true answer, into N. So for the test case:
?- sum([1,2,3,4], 0).
I get an answer of 6, the final value of N, and the second-to-last value of X, instead of 10, the final value of X. Any help and/or explanations of why neither of these solutions work would be greatly appreciated. Thanks.
Firstly, the sum of an empty list is 0 - this is the base case, which you already had.
Secondly, the sum N of an element H and a list T is the sum of the list T added to H. Prolog operates on unification, so this says that N is unified with the sum of H and T, where the sum of T is unified with X using sum(T,X).
sum([], 0).
sum([H|T], N):-
sum(T, X),
N is X + H.
This gives:
?- sum([1,2,3,4],N).
N = 10.
In your original question, ?- sum([1,2,3,4], 0). actually says "this is true if the sum of the list [1,2,3,4] is 0" - you need to pass a variable as the second argument to sum to be unified with the answer.
Further information:
_34521 is a representation of an unbound variable - this says that there is a variable, but that it has not yet been unified with a value.
Secondary consideration:
For a suitably long list, the implementation above will run out of stack space, as each frame of the recursion must be stored, so that the addition can happen from the bottom up. In order to prevent a stack error, we can use a tail-recursive accumulator like so:
sum(L, N):-
sum(L, 0, N).
sum([],N,N).
sum([H|T],A,N) :-
A1 is A + H,
sum(T,A1,N).
... which retains the signature of the original method, wrapping sum/3. As there is no choice-point in the body of the rule (given that A + H is always the same for a given A and H, and the list is either empty or not), Prolog will discard each frame as it leaves scope (as there is nothing more to be done with it) and, on completion, will return to the original caller.
Simplified stack for sum([1,2,3],N) in each instance:
non-tail-recursive:
rest-of-stack
rest-of-stack,sum([1|[2,3]],_1001)
rest-of-stack,sum([1|[2,3]],_1001),sum([2|[3]],_1002)
rest-of-stack,sum([1|[2,3]],_1001),sum([2|[3]],_1002),sum([3|[]],_1003)
rest-of-stack,sum([1|[2,3]],_1001),sum([2|[3]],_1002),sum([3|[]],_1003),sum([],0)
rest-of-stack,sum([1|[2,3]],_1001),sum([2|[3]],_1002),sum([3|[]],3)
rest-of-stack,sum([1|[2,3]],_1001),sum([2|[3]],5)
rest-of-stack,sum([1|[2,3]],6)
rest-of-stack
tail-recursive:
rest-of-stack
rest-of-stack,sum([1,2,3],_1001)
rest-of-stack,sum([1|[2,3]],0,_1001)
rest-of-stack,sum([2|[3]],1,_1001)
rest-of-stack,sum([3|[]],3,_1001)
rest-of-stack,sum([],6,6)
rest-of-stack
Note that the tail-recursive stack has a limited depth for any length of list (dependent on what is calling it), where the non-tail-recursive stack goes to a depth directly proportional to the length of the list.
Thus, a call such as N is 10^7,length(L,N),maplist(=(1),L),sum(L,N). (as raised by #false) will likely fail without tail-recursion, and likely succeed with it.

Prolog List, check additions to list

I have created a predicate that will check whether all the items in a list satisfy a condition.
For this example, the predicate checks that all elements are in multiples of two Check_Multiples/1, which works quite well.
How would I check to see what item could be added to the beginning or the end of the list, and still satisfy the predicate?
I am trying to make the return a list.
For example:
[2,4,6]
should return [8] as (as the predicate does not allow 0)
[6,8,10]
should return [4,12]
The following code should do the trick, given that Check_Multiples checks if every element of the list is a multiple of two in an ascending order. I'm guessing that was a condition, otherwise if lists such as [4, 6, 4, 4, 8] were allowed you could just check if every element modulus 2 is equal to 0.
additionsToList([H|T], ResultList) :-
Check_Multiples([H|T]),
firstElement(H, First),
lastElement(T, Last),
append([First],[Last], Z),
flatten(Z, ResultList).
firstElement(2, []).
firstElement(First, X) :-
X is First-2.
lastElement([H|[]], X) :-
X is H+2.
lastElement([_|T], X) :-
lastElement(T, X).

Prolog length of a list

How can I calculate the length of a list
?- size_sub([[b,a,g], [9,3,7,4], [6]], X).
X = [3, 4, 1].
?- size_sub([[c,g,e,w], [7]], X).
X = [4, 1].
?- size_sub([], X).
X = [].
Ok you need to start with the base case which is the last answer
so size_sub([],X). is true if X=[] so first you write that as a rule.
size_sub([],[]).
Then you need to do the inductive step a list that is one longer than the previous. I am going to assume that you have a size/2 function for determining the size of a single list (if not please comment).
So the inductive step is going to operate on the length of the first parameter so N->N+1. We would represent this by striping off the head of the list syntax will be [H|T] now the second parameter (your answer) is going to be the length of H with the result of calling size_sub on T. As we cannot specify rules in the parameters in the header we will use N to represent the length of H and T2 to represent the result of size_sub on T.
So the first part of the rule becomes size_sub([H|T],[N|T2]):-
now we follow it with the predicates that will assert the values for N and T2.
size(H,N),
size_sub(T,T2).
putting that all together you get
size_sub([],[]).
size_sub([H|T],[N|T2]):-
size(H,N),
size_sub(T,T2).
size/2 is a far simpler case and following the same process of base + inductive you should be able to create the rules for it. Please comment if you need further help.
** EDIT - Request for size/2 definition **
To define size/2
Start with the base case, the empty list has a size of 0.
size([],0).
Now the inductive step. The size of list of length(N+1) is the size of a list of length(N). So lets define our list as [_|T] I've defined the list using _ to represent the head because we never use it so we can just use the anonymous variable. Lets use N to represent the length of T, and M to be N+1.
so
size([_|T],M):-
now lets define N
size(T,N),
and finally assert that M is equal to N + 1
M is N+1.
so putting everything together
size([],0).
size([_|T],N):-
size(T,M),
N is M+1.
size_sub([],[]).
size_sub([H|T],[N|T2]):-
size(H,N),
size_sub(T,T2).
To map length/2 over a list of lists, we can use the meta-predicate maplist/3 like this:
size_sub(Xss,Ls):-
maplist(length,Xss,Ls).