Prolog inserting multiple elements into list - prolog

I want to implement a predicate (vecLine2BitLine) which does the following:
get two lists and a number the first list is the length of blocks (the elements of the blocks are '$') and the second list contains the indexes that these blocks should be placed at meaning:
vecLine2BitLine([1,2,1],[2,5,9],12,BitLine).
BitLine=[' ','$',' ',' ','$','$',' ',' ','$',' ',' ',' '].
explanation:a block of length 1 is at index 2
and a block of length 2 is at index 5 and so on..
insert_at_mul : inserts an element N times (it works perfectly,dupli and my_flatten were implemented previously so i used them)
Ive been trying to activate insert_at_mul N times when N is the length of the list X and Y
in the predicate vecLine2BitLine.
dupli(L1,N,L2) :- dupli(L1,N,L2,N).
dupli([],_,[],_).
dupli([_|Xs],N,Ys,0) :- dupli(Xs,N,Ys,N).
dupli([X|Xs],N,[X|Ys],K) :- K > 0, K1 is K - 1, dupli([X|Xs],N,Ys,K1).
my_flatten(X,[X]) :- \+ is_list(X).
my_flatten([],[]).
my_flatten([X|Xs],Zs) :- my_flatten(X,Y), my_flatten(Xs,Ys), append(Y,Ys,Zs).
insert_at_mul(L,X,K,R,N):-dupli([X],N,XX) , insert_at(L,XX,K,L1) , my_flatten(L1,R).
get_num_spaces(L,N,X):-sum(L,S), X is N-S.
generate_spaces(N,L,X):- insert_at_mul(L,'',1,X,N).
vecLine2BitLineAux([],[],_,_,_).
vecLine2BitLineAux([X|Tail1],[Y|Tail2],N,L,Lnew):- insert_at_mul(L,'*',Y,Lnew,X) ,vecLine2BitLineAux(Tail1,Tail2,N,Lnew,R). // problem here!!!
vecLine2BitLine(X,Y,N,L):- get_num_spaces(X,N,Z) , generate_spaces(Z,[],ZZ) , vecLine2BitLineAux(X,Y,N,ZZ,L).
now the problem is that in the function vecLine2BitLine i cant activate insert_at_mul N times(thats what i tried to do in this code, but failed).
how can I fix vecLine2BitLine for it to work properly as in returning the correct output by actually activating the predicate insert_at_mul N times??
THANKS!
added :
vecLine2BitLine : input parameters : (L1,L2,N,Result)
N: after activating the predicate Result will be N in length.
L1: L1 is a list of numbers each number indicates the length of a block, a block is comprised of a Sequence of '$'.
L2: L2 is a list of numbers the numbers are indices for where the blocks in L1 should be placed.
example:
vecLine2BitLine([3,2],[1,5],9,BitLine).
we can look at the input better as tuples :
vecLine2BitLine[(3,1),(2,5)],9,BitLine).
(3,1) : there is a sequence of '' 3 times at index 1
(2,5) : there is a sequence of '' 2 times at index 5
in our example 9 is the length of BitLine at the end and we have to insert into the
list BitLine 3+2 of the "special chars" '*' but we have 9-(3+2) places left in the list
so we add '' in those places and then we get:
BitLine=['$','$','$','','$','$','','','',''].

This is kind of a nice problem because you can use the arguments as loop counters. The K argument gets you to the proper index. Let's just traverse the list and find a particular index as an example. Notice the base case is that you're at the right element, and the inductive case is prior to the right element.
traverse(1, [X|_], X).
traverse(N, [_|Xs], X) :- N > 0, N0 is N-1, traverse(N0, Xs, X).
We're going to apply that pattern to insert_at/4 to get to the right location in the list. Now let's write a repeat/3 predicate that repeats X N times in a new list L. This time the base case is when we've added all the repetitions we care to, and the inductive case is that we'll add another instance.
repeat(1, X, [X]).
repeat(N, X, [X|Xs]) :- N > 0, N0 is N-1, repeat(N0, X, Xs).
You can see the similarity of structure between these two. Try to combine them into a single predicate. Since this is homework, I'll stop here. You're inches from the goal.

Related

Prolog find the element with the max number of occurrences

I would like to create a predicate that returns the element that most often appears, if there are more than one with the same number of occurrences the first:
occ([a,b,c,a,a,a,b],M).
yes M = a
occ([a,b,c,a,b],M).
yes M = a
Note that in Prolog you would generally create rules, not functions to solve this.
There are a number of ways to approach this, I'll provide two.
Recursion
One way is to recurse over the list, keeping a running count of occurrences, and with each call recording what the current max is, an example of use of an accumulator:
% find the X with the most occurrences N in a list L
occ(X,N,L) :-
occ(L,max(null,0),[],max(X,N)).
%% occ(+L, +CurrentMax, +Counts, +FinalMax) is det.
%
% recurse through L, using CurrentMax accumulator to
% store current candidate as a term `max(X,N)`
%
% Counts is a list in which we accumulate counts of
% occurrences to far, as list of element-count pairs X-N
%
% The final argument is unified with the CurrentMax
% accumulator as the base case
occ([], max(Xm, Nm), _, max(Xm, Nm)).
occ([X|L], max(Xm, Nm), Counts, FinalMax) :-
% get the current count of X
( select(X-N, Counts, CountsT)
->
N1 is N+1
;
N1 = 1,
CountsT = Counts),
% make a new list of counts with the
% original entry for X replaced by a new
% one with count of N+1
Counts2 = [X-N1 | CountsT],
% recurse, using either new current best candidate
% or same one depending on whether count is exceeded.
% in case of tie, use same one, thus prioritizing first result
( N1 > Nm
->
occ(L, max(X,N1), Counts2, FinalMax)
;
occ(L, max(Xm,Nm), Counts2, FinalMax)).
Example:
?- occ(X,N,[a,b,c,a,b]).
X = a,
N = 2.
Higher-order aggregate operations
An alternative approach is to use higher-order aggregate predicates. Arguably this leads to more declarative code, although tastes will vary. If you are using SWI-Prolog you can use the aggregate library. We can start with a rule to count occurrences in a list (note I'm going to switch from your occ/2 to more explicit predicates here):
% count number N of instances of X in a list L
element_count(X,N,L) :-
aggregate(count,member(X,L),N).
If you don't want to or can't use aggregate/3 then have a look at the answers to this question previously asked on stack overflow.
Next we can use aggregate/3 to find the maximum number for N, plus a "witness" (i.e. the value of X with the highest value):
% count number N of instances of X in a list L, for highest N
max_element_count(X,N,L) :-
aggregate(max(N1,X1),element_count(X1,N1,L),max(N,X)).
(I'll leave it to you to make an equivalent implementation of this rule if you're not using the aggregate library)
Let's try it:
?- max_element_count(X,N,[a,b,c,a,a,a,b]).
X = a,
N = 4.
With a tie it seems to satisfy your criterion of using the first occurrence in the case of tie-breakers:
?- max_element_count(X,N,[a,b,c,a,b]).
X = a,
N = 2.
But this is not in fact guaranteed - we just happen to choose a here as it is alphabetically before b. Let's try:
?- max_element_count(X,N,[b,a,c,a,b]).
X = a,
N = 2.
Oops!
This time we will find the first member of the list whose number of occurrences is equal to the max:
max_element_count2(X,N,L) :-
aggregate(max(N1),X1,element_count(X1,N1,L),N),
member(X,L),
element_count(X,N,L),
!.
This assumes that member/2 will unify with elements in order, which is the behavior I have always seen with Prologs but don't know off the top of my head if it is mandated by the standard.
To demonstrate:
?- max_element_count2(X,N,[b,a,c,a,b]).
X = b,
N = 2.

Split a list multiple time in Prolog

this my code :
div2(L,N,L1,L2) :-
length(L1,N),%n=4
append(L1,L2, L),
L=L2,L1=[],L2=[].
i want it to display each time in L1 a 4 element list but it return false.
example :
L=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
L1=[1,2,3,4]
L1=[5,6,7,8]
L1=[9,10,11,12]
L1=[13,14,15,16]
how can i make it work. and thanks for the help.
Assuming you want div(L,N,L1,L2) to be that L1 is the first N element of L, and L2 is what remains:
div2(L,N,L1,L2) :-
length(L1,N),
append(L1,L2,L).
There are no other conditions that need to be placed on L, L1 or L2.
If you want to be the first 4 elements after some multiple of 4 elements, and L2 to be the rest, you need to say so:
div2(L,N,L1,L2) :-
append(L01,L2,L), % break up L
length(L01,Nx), % make sure prefix's length is multiple of N
0 is mod(Nx,N),
append(L0,L1,L01),% set L1 to be last N elements of prefix
length(L1,N).
A slightly different solution...
div2([X|Xs], N, P) :-
( length(P1, N),
append(P1, R, [X|Xs])
-> ( P = P1
; div2(R, N, P)
)
; P = [X|Xs]
).
This solution defines a list P1 of length N, and attempts to unify it (with append as a prefix list of [X|Xs]. ([X|Xs] is used instead of L to ensure that the predicate succeeds only if the first argument is a list with at least one element.)
If the append is successful, then the solution is either P1 (P is unified with P1) or a recursive call to div2 with the remainder of the first argument list with the prefix P1 absent.
If the append fails (which will happen if the number of partition elements N is larger than the first argument list length), then P is unified with the first argument list.

Prolog Picking from a list and Summing specific Values

sumPicker([[]|_], Y, Z).
sumPicker([X|X1], Y, Z):-
downList(Y, X, Sum),
Total is Z,
Z is Total + Sum,
sumPicker(X1,Y, Z).
downList([Z|_], 1, Z).
downList([_|B],Count, Number):- Count > 1,
SendCount is Count - 1,
downList(B, SendCount, Number).
So this code is basically suppose to take in Two lists sumPicker([3,5], [1,2,3,4,5,6], X). The program then takes the first list and depending on the value of the number, so in this case 3, it will find the third number in the second list then it will find the 5th number of the second list and add them together.
ERROR: is/2: Arguments are not sufficiently instantiated is what i am getting
I'm assuming that your instructor would like you to work out the recursion yourself, rather than using built-in list operations. To that end, you could approach it something like this, using no built-ins at all.
A common prolog idiom is to have a simple "public" predicate that invokes a "helper" predicate that carries state (in this case, the current position in the list and the running sum). Often, that "helper" predicate will have the same functor (name) as the public predicate, with a higher arity (number of arguments).
So, first we have the public predicate, sum_of_desired/3:
sum_of_desired( Indices , Numbers , Sum ) :- % to sum certain list elements,
sum_of_desired( Indices , Numbers , 0 , Sum ) - % invoke the helper
. %
All it does is invoke the helper, sum_of_desired/4. This helper predicate carries an extra argument that is its state: an accumulator that contains the running sum. When it succeeds, that running sum is unified with the final total. This is because, in Prolog, you can't change the value of a variable: once you assign a value to a variable, it ceases to be variable. It become that with which it was unified (that's it's called unification). The only way to undo that assignment is via backtracking.
Typically, a recursive problem has a few special cases and a more general case. So, here, our helper predicate has 2 clauses:
The first clause is the special case: the list of desired indices is empty, in which case the finally sum is the current value of the accumulator (0 initially).
the second clause is the recursive general case: here we find the desired list item, add it to the running total and recurse down, moving on to the next item in the list of desired list items.
sum_of_desired( [] , _ , S , S ) . % the list of desired indices is empty: unify the accumulator with the result.
sum_of_desired( [I|Is] , L , T , S ) :- % otherwise...
get_nth_item(I,L,N) , % - get the nth item from the list
T1 is T+N , % - add it to the running total
sum_of_desired(Is,T1,S) % - and recurse down
. %
Finally, this predicate, get_nth_item/3, simple recursively walks the list, looking for the nth item in the list, where n is relative to 1 (e.g., the first item in the list is at index 1). When it finds it, it's returned as the 3rd argument of the predicate.
Again, here you will note that we have a single terminating special case and the more general recursive special case:
get_nth_item( 1 , [X|_] , X ) . % found it!
get_nth_item( N , [_|Xs] , R ) :- % otherwise...
N > 1 , % - if N > 1 ,
N1 is N-1 , % - decrement N
nth_item( N1 , Xs , R ) % - recurse down.
. % - easy!

Prolog Ending a Recursion

countdown(0, Y).
countdown(X, Y):-
append(Y, X, Y),
Y is Y-1,
countdown(X, Y).
So for this program i am trying to make a countdown program which will take Y a number and count down from say 3 to 0 while adding each number to a list so countdown(3, Y). should produce the result Y=[3,2,1]. I can't seem the end the recursion when i run this and i was wondering if anyone could help me?
I cant seem to get this code to work any help? I seem to be getting out of global stack so I dont understand how to end the recursion.
Your original code
countdown( 0 , Y ) .
countdown( X , Y ) :-
append(Y, X, Y),
Y is Y-1,
countdown(X, Y).
has some problems:
countdown(0,Y). doesn't unify Y with anything.
Y is Y-1 is trying to unify Y with the value of Y-1. In Prolog, variables, once bound to a value, cease to be variable: they become that with which they were unified. So if Y was a numeric value, Y is Y-1 would fail. If Y were a variable, depending on your Prolog implementation, it would either fail or throw an error.
You're never working with lists. You are expecting append(Y,X,Y) to magically produce a list.
A common Prolog idiom is to build lists as you recurse along. The tail of the list is passed along on each recursion and the list itself is incomplete. A complete list is one in which the last item is the atom [], denoting the empty list. While building a list this way, the last item is always a variable and the list won't be complete until the recursion succeeds. So, the simple solution is just to build the list as you recurse down:
countdown( 0 , [] ) . % The special case.
countdown( N , [N|Ns] ) :- % The general case: to count down from N...
N > 0 , % - N must be greater than 0.
N1 is N-1 , % - decrement N
countdown(N1,Ns) % - recurse down, with the original N prepended to the [incomplete] result list.
. % Easy!
You might note that this will succeed for countdown(0,L), producing L = []. You could fix it by changing up the rules a we bit. The special (terminating) case is a little different and the general case enforces a lower bound of N > 1 instead of N > 0.
countdown( 1 , [1] ) .
countdown( N , [N|Ns] ) :-
N > 1 ,
N1 is N-1 ,
countdown(N1,Ns)
.
If you really wanted to use append/3, you could. It introduces another common Prolog idiom: the concept of a helper predicate that carries state and does all the work. It is common for the helper predicate to have the same name as the "public" predicate, with a higher arity. Something like this:
countdown(N,L) :- % to count down from N to 1...
N > 0 , % - N must first be greater than 0,
countdown(N,[],L) % - then, we just invoke the helper with its accumulator seeded as the empty list
. % Easy!
Here, countdown/2 is our "public predicate. It calls countdown/3 to do the work. The additional argument carries the required state. That helper will look like something like this:
countdown( 0 , L , L ) . % once the countdown is complete, unify the accumulator with the result list
countdown( N , T , L ) . % otherwise...
N > 0 , % - if N is greater than 0
N1 is N-1 , % - decrement N
append(T,[N],T1) , % - append N to the accumulator (note that append/3 requires lists)
countdown(N1,T1,L) % - and recurse down.
. %
You might notice that using append/3 like this means that it iterates over the accumulator on each invocation, thus giving you O(N2) performance rather than the desired O(N) performance.
One way to avoid this is to just build the list in reverse order and reverse that at the very end. This requires just a single extra pass over the list, meaning you get O(2N) performance rather than O(N2) performance. That gives you this helper:
countdown( 0 , T , L ) :- % once the countdown is complete,
reverse(T,L) % reverse the accumulator and unify it with the result list
. %
countdown( N , T , L ) :- % otherwise...
N > 0 , % - if N is greater than 0
N1 is N-1 , % - decrement N
append(T,[N],T1) , % - append N to the accumulator (note that append/3 requires lists)
countdown(N1,T1,L) % - and recurse down.
. %
There are several errors in your code:
first clause does not unify Y.
second clause uses append with first and third argument Y, which would only succeed if X=[].
in that clause you are trying to unify Y with another value which will always fail.
Y should be a list (according to your comment) in the head but you are using it to unify an integer.
You might do it this way:
countdown(X, L):-
findall(Y, between(1, X, Y), R),
reverse(R, L).
between/3 will give you every number from 1 to X (backtracking). Therefore findall/3 can collect all the numbers. This will give you ascending order so we reverse/2 it to get the descending order.
If you want to code yourself recursively:
countdown(X, [X|Z]):-
X > 1,
Y is X-1,
countdown(Y, Z).
countdown(1, [1]).
Base case (clause 2) states that number 1 yields a list with item 1.
Recursive clause (first clause) states that if X is greater than 1 then the output list should contain X appended with the result from the recursive call.

Prolog Counter Problem

I am trying to write a procedure order(List,Result) that has a List as input and returns a list Result of ordered pairs such that:
the first element of the ordered pair is the position of the pair in the list, and
the second element of the ordered pair is the element from List n the corresponding position.
Example:
if List = [a,b,c,d], the procedure order(List,Result) outputs the list:
Result = [(1,a), (2,b),(3,c),(4,d)].
I am struggling with the counter for the position of the pair in the list. I have made attempts such as:
increment(Accum,Total):-
Total is Accum + 1.
order([],[]).
order([Head|Tail],Result):-
order(Tail, NewTail),
NewCount is Count + 1,
increment(NewCount,Count),
Result = [(Count,Head)|NewTail].
Please help anyone?
The two clauses: NewCount is Count + 1 and increment(NewCount,Count) basically have the same meaning. You didn't make clear that Count is an input variable and it has a base case of 1, so Prolog didn't know where to start unifying values for it. For example, you should use Count as an input argument as follows (it doesn't change much if compared with your version):
order([],[], _).
order([Head|Tail],[(Count,Head)|NewTail], Count):-
NewCount is Count + 1,
order(Tail, NewTail, NewCount).
order(List, Result ):- order(List, Result, 1).
If you're OK with using findall/3 then this is probably the simplest solution:
order(List, Result) :-
findall(Index-Elem, nth1(Index, List, Elem), Result).
Note that here the key-value pairs are represented using the term -/2, which is how pairs are usually represented in Prolog, e.g. this is what keysort/2 expects.
order(List,Result) :-
findall((N,E),(
append(L0,[E|_],List),
length([_|L0],N)),
Result).

Resources