Prolog Counter Problem - prolog

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).

Related

Prolog - Comparing Lists that have the same element on the same index

I've been working on Prolog for a few weeks right now. I am now trying to write a function in it called matching:
Write a predicate called matching with three parameters, all lists.
The third list must contain the index of the positions in which
the first two lists contain the same value.
If I run
matching([10,71,83,9,24,5,2],[8,71,26,9],Positions).
The results are:
?- matching([10,71,83,9,24,5,2],[8,71,26,9],Positions).
Positions = [] ;
Positions = [] ;
Positions = [_2420] ;
Positions = [_2420] ;
Positions = [_2420, _2432];...
The correct answer would be that Positions is bound to [1,3]. I have no idea what is wrong with my code. Any hint is appreciated.
A hint? Each of your matchingHelper clauses contains a mistake!
OK, a little more than a hint:
Base cases
Prolog should be giving you a warning about singleton variables here. ListofIndex is a variable, but it is only used in one place. Essentially this means that there is absolutely no constraint on this, and thus can be anything.
The correct thing would be that if either of the input lists is empty, the output is also empty.
matchingHelper([], _, , []).
matchingHelper(, [], _, []).
Equal case
This one you almost have correct, but the way you deal with ListOfIndex is backwards. You construct a NewListOfIndex based on the predicate arguments, and use that in the recursive call. The problem is that the ListOfIndex is actually the output! So you should instead construct the ListOfIndex based on the output from the recursive call.
matchingHelper([X|Xs], [X|Ys], Index, [Index|ListofIndex]) :-
Index2 is Index + 1,
matchingHelper(Xs, Ys, Index2, ListofIndex).
Unequal case
Just 2 little issues with this one. First is that this clause should only apply if X and Y are different. Just using a different variable name does not enforce this. Because there is a previous clause which handles the equal case, the first result prolog finds would be correct, but it will continue to find other, incorrect solutions because of this.
The second issue is that you don't increment the index. If you ignore the first element, the current index has to be incremented to reflect the current position.
matchingHelper([X|Xs], [Y|Ys], Index, ListofIndex) :-
X \= Y,
Index2 is Index + 1,
matchingHelper(Xs, Ys, Index2, ListofIndex).
Here's a sample run:
?- matching([10,71,83,9,24,5,2],[8,71,26,9],Positions).
Positions = [1, 3]
false

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!

Generating a list in prolog

Hello I want to make a program in Prolog, that given a list of numbers and a number, it appends all the concurences of position of the number in a second list.
For example for the list (5,10,4,5,6,5) and number =5 the new list should be
(1,4,6)
here is my code so far
positions(X, [X|_],1).
positions(X, [P|T], N) :- positions(X, T, N1), N is N1+1.
find(X, [H|T] ,Z) :-positions(X,[H|T],N) , append([],N,Z).
the positions returns the first concurrence of X in the list, but I don't know how to proceed. Can you help me?
If it's not an assignment, then you can benefit from using the built-ins findall/3 and nth1/3:
?- findall(Nth, nth1(Nth, [5,10,4,5,6,5], 5), Nths).
Nths = [1, 4, 6].
Taking just the nth1 phrase, and running that, you can see it is backtracking and finding multiple solutions, then we just use findall to collect them into a list.
?- nth1(Nth, [5,10,4,5,6,5], 5).
Nth = 1 ;
Nth = 4 ;
Nth = 6.
nth1/3, when using a variable for the first parameter, is saying 'give me a list index where where the 3rd parameter is found in the list of the second parameter.
You have some good ideas, but I would suggest a couple things:
1) In Prolog, it can be beneficial to give variables meaningful names
2) Use an accumulator and you will only need positions and append
3)Use a different base case
positions([Num|List],Num,[Index|SubResult],Index) :- Index2 is Index+1,
positions(List,Num,SubResult,Index2).
positions([NotNum|List],Num,Result,Index) :- NotNum \= Num,
Index2 is Index+1,
positions(List,Num,Result,Index2).
positions([],Num,[],Index).
In our first general case, we can see the numbers match, so we go find how many results are in our sublist, which we will call the SubResult and then push the current index on to our SubResult
The next general case, the numbers do not unify, and our Result IS the SubResult, so let's call them the same thing.
In our final case (the base case) we can see the list is empty, in this case we return an empty list as we cannot match against an empty list.
You can see that the above rules are order-independent, which is something very valuable in Prolog. This means you can arrange the rules in any order, and the semantics of your Prolog program remain unchanged. Using unification to achieve this will prevent future pain in debugging.
We can wrap our predicate in the following way
positions(Num, List, Positions) :- positions(List, Num, Positions, 1).
This will allow for queries of positions(5,[5,10,4,5,6,5],Positions).

Prolog inserting multiple elements into list

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.

Passing results in prolog

I'm trying to make a function that has a list of lists, it multiplies the sum of the inner list with the outer list.
So far i can sum a list, i've made a function sumlist([1..n],X) that will return X = (result). But i cannot get another function to usefully work with that function, i've tried both is and = to no avail.
Is this what you mean?
prodsumlist([], 1).
prodsumlist([Head | Tail], Result) :-
sumlist(Head, Sum_Of_Head),
prodsumlist(Tail, ProdSum_Of_Tail),
Result is Sum_Of_Head * ProdSum_Of_Tail.
where sumlist/2 is a SWI-Prolog built-in.
Usage example:
?- prodsumlist([[1, 2], [3], [-4]], Result).
Result = -36.
The part "it multiplies the sum of the inner list with the outer list" isn't really clear, but I believe you mean that, given a list [L1,...,Ln] of lists of numbers, you want to calculate S1*..*Sn where Si is the sum of the elements in Li (for each i).
I assume the existence of plus and mult with their obvious meaning (e.g. plus(N,M,R) holds precisely when R is equal to N+M). First we need predicate sum such that sum(L,S) holds if, and only if, S is the sum of the elements of L. If L is empty, S obviously must be 0:
sum([],0).
If L is not empty but of the form [N|L2], then we have that S must be N plus the sum S2 of the elements in L2. In other words, we must have both sum(L2,S2) (to get S2 to be the sum of the elements of L2) and plus(N,S2,S). That is:
sum([N|L2],S) :- sum(L2,S2), plus(N,S2,S).
In the same way you can figure out the predicate p you are looking for. We want that p(L,R) holds if, and only if, R is the product of S1 through Sn where L=[L1,...,Ln] and sum(Li,Si) for all i. If L is empty, R must be 1:
p([],1).
If L is not empty but of the form [LL|L2], then we have that R must be the product of 'S', the sum of the elements of LL, and 'P', the product of the sums of the lists in L2. For S we have already have sum(LL,S), so this gives us the following.
p([LL|L2],R) :- sum(LL,S), p(L2,P), mult(S,P,R).
One thing I would like to add is that it is probably not such a good idea to see these predicates as functions you might be used to from imperative or functional programming. It is not the case that sumlist([1,..,n],X) returns X = (result); (result) is a value for X such that sumlist([1,...,n],X) is true. This requires a somewhat different mindset. Instead of thinking "How can I calculate X such that p(X) holds?" you must think "When does P(X) hold?" and use the answer ("Well, if q(X) or r(X)!") to make the clauses (p(X) :- q(X) and p(X) :- r(X)).
Here is a rewrite of Kaarel's answer (that's the intention anyway!) but tail-recursive.
prodsumlist(List, Result) :-
xprodsumlist(List,1,Result).
xprodsumlist([],R,R).
xprodsumlist([Head|Rest],Sofar,Result) :-
sumlist(Head, Sum_Of_Head),
NewSofar is Sofar * Sum_Of_Head,
xprodsumlist(Rest, NewSofar, Result).

Resources