I have a Matrix like this:
[[0,0,0],[1,0,0],[0,0,1],[1,0,0],[0,1,0],[0,0,0],[0,1,0],[0,1,0],[0,0,0]]
and I need a list that saves the index when a row is not [0,0,0].
So the result in my example should be:
[2,3,4,5,7,8]
I have problems to program recursive in Prolog because i haven`t really figured out how it works.
Would it maybe help to first convert the matrix into a vector? It doesn't matter if its [1,0,0] or [0,1,0]. The only thing that is important is that it's not [0,0,0].
Since you want to describe a list, you could opt to use DCGs. They usually yield quite easily readable code:
matrix_indices(M,I) :-
phrase(indices(M,0),I). % the list I is described by the DCG indices//2
indices([],_) --> % if M is empty
[]. % I is empty too
indices([[0,0,0]|Ls],I0) --> % if the head of M is [0,0,0]
{I1 is I0+1}, % the current index is calculated but is not in I
indices(Ls,I1). % the same holds for the tail
indices([L|Ls],I0) --> % if the head of the list
{dif(L,[0,0,0])}, % differs from [0,0,0]
{I1 is I0+1}, % the current index is calculated
[I1], % and is in the list I
indices(Ls,I1). % the same holds for the tail
Note that the goals enclosed in braces are normal Prolog-goals. If you query this predicate with your given example you get the desired solution:
?- matrix_indices([[0,0,0],[1,0,0],[0,0,1],[1,0,0],[0,1,0],[0,0,0],[0,1,0],[0,1,0],[0,0,0]],I).
I = [2,3,4,5,7,8] ? ;
no
You can also use the predicate in the other direction but you have to ask for a concrete length or prefix a goal length(M,_)to prevent the predicate from looping. For example the query...
?- length(M,_), matrix_indices(M,[2,3,4,5,7,8]).
M = [[0,0,0],_A,_B,_C,_D,[0,0,0],_E,_F],
dif(_A,[0,0,0]),
dif(_B,[0,0,0]),
dif(_C,[0,0,0]),
dif(_D,[0,0,0]),
dif(_E,[0,0,0]),
dif(_F,[0,0,0]) ? ;
M = [[0,0,0],_A,_B,_C,_D,[0,0,0],_E,_F,[0,0,0]],
dif(_A,[0,0,0]),
dif(_B,[0,0,0]),
dif(_C,[0,0,0]),
dif(_D,[0,0,0]),
dif(_E,[0,0,0]),
dif(_F,[0,0,0]) ? ;
M = [[0,0,0],_A,_B,_C,_D,[0,0,0],_E,_F,[0,0,0],[0,0,0]],
dif(_A,[0,0,0]),
dif(_B,[0,0,0]),
dif(_C,[0,0,0]),
dif(_D,[0,0,0]),
dif(_E,[0,0,0]),
dif(_F,[0,0,0]) ?
.
.
.
... yields infinitely many answers as expected.
How I would solve using findall/3 and nth1/3:
?- M = [[0,0,0],[1,0,0],[0,0,1],[1,0,0],[0,1,0],[0,0,0],[0,1,0],[0,1,0],[0,0,0]],
findall(I, (nth1(I,M,E), E\=[0,0,0]), L).
L = [2, 3, 4, 5, 7, 8]
Related
New to prolog and trying to implement the following function that takes 3 lists:
True if lists are the same length
True if elements of third list is sum of the two lists
Example: fn([1,2,3],[4,5,6],[5,7,9]) returns true. Note that the sum is element-wise addition.
This is what I have so far:
fn([],[],[]).
fn([_|T1], [_|T2], [_|T3]) :-
fn(T1,T2,T3), % check they are same length
fn(T1,T2,N1), % check that T3=T1+T2
N1 is T1+T2,
N1 = T3.
From what I understand, the error is due to the base case (it has empty lists which causes error with evaluation of addition?)
Thanks for any help and explanations!
In addition to #GuyCoder's answer, I would point out that it is worthwhile to consider using one of the maplist predicates from library(apply) when modifying all elements of lists. You can use a predicate to describe the relation between three numbers...
:- use_module(library(apply)). % for maplist/4
num_num_sum(X,Y,S) :-
S is X+Y.
... and subsequently use maplist/4 to apply it to entire lists:
fn(X,Y,Z) :-
maplist(num_num_sum,X,Y,Z).
This predicate yields the desired results if the first two lists are fully instantiated:
?- fn([1,2,3],[4,5,6],X).
X = [5,7,9]
However, due to the use of is/2 you get instantiation errors if the first two lists contain variables:
?- fn([1,A,3],[4,5,6],[5,7,9]).
ERROR at clause 1 of user:num_num_sum/3 !!
INSTANTIATION ERROR- X is _+B: expected bound value
?- fn([1,2,3],[4,5,A],[5,7,9]).
ERROR at clause 1 of user:num_num_sum/3 !!
INSTANTIATION ERROR- X is A+B: expected bound value
If you only want to use the predicate for lists of integers, you can use CLP(FD) to make it more versatile:
:- use_module(library(apply)).
:- use_module(library(clpfd)). % <- use CLP(FD)
int_int_sum(X,Y,S) :-
S #= X+Y. % use CLP(FD) constraint #=/2 instead of is/2
fnCLP(X,Y,Z) :-
maplist(int_int_sum,X,Y,Z).
With this definition the previously problematic queries work as well:
?- fnCLP([1,A,3],[4,5,6],[5,7,9]).
A = 2
?- fnCLP([1,2,3],[4,5,A],[5,7,9]).
A = 6
Even the most general query yields results with this version:
?- fnCLP(X,Y,Z).
X = Y = Z = [] ? ;
X = [_A],
Y = [_B],
Z = [_C],
_A+_B#=_C ? ;
X = [_A,_B],
Y = [_C,_D],
Z = [_E,_F],
_A+_C#=_E,
_B+_D#=_F ? ;
.
.
.
Since the numbers in the above answers are not uniquely determined, you get residual goals instead of actual numbers. In order to get actual numbers in the answers, you have to restrict the range of two of the lists and label them subsequently (see documentation for details), e.g. to generate lists containing the numbers 3,4,5 in the first list and 6,7,8 in the second list, you can query:
label the lists
restrict the domain | |
v v v v
?- fnCLP(X,Y,Z), X ins 3..5, Y ins 6..8, label(X), label(Y).
X = Y = Z = [] ? ;
X = [3],
Y = [6],
Z = [9] ? ;
X = [3],
Y = [7],
Z = [10] ? ;
.
.
.
X = [3,4],
Y = [6,7],
Z = [9,11] ? ;
X = [3,4],
Y = [6,8],
Z = [9,12] ? ;
.
.
.
On an additional note: there are also clp libraries for booleans (CLP(B)), rationals and reals (CLP(Q,R)) that you might find interesting.
From what I understand, the error is due to the base case.
I don't see it that way.
The first problem I see is that you are trying to process list which leads to thinking about using DCGs, but since you are new I will avoid that route.
When processing list you typically process the head of the list then pass the tail back to the predicate using recursion.
e.g. for length of list you would have
ln([],N,N).
ln([_|T],N0,N) :-
N1 is N0+1,
ln(T,N1,N).
ln(L,N) :-
ln(L,0,N).
The predicate ln/2 is used to set up the initial count of 0 and the predicate ln/3 does the work using recursion. Notice how the head of the list is taken off the front of the list and the tail of the list is passed recursively onto the predicate again. When the list is empty the predicate ln([],N,N). unifies, in this case think copies, the intermediate count from the second position into the third position, which it what is passed back with ln/2.
Now back to your problem.
The base case is fine
fn([],[],[]).
There are three list and for each one look at the list as [H|T]
fn([H1|T1],[H2|T2],[H3|T3])
and the call to do the recursion on the tail is
fn(T1,T2,T3)
all that is left is to process the heads which is
H3 is H1 + H2
putting it all together gives us
fn([],[],[]).
fn([H1|T1], [H2|T2], [H3|T3]) :-
H3 is H1 + H2,
fn(T1,T2,T3).
and a quick few checks.
?- fn([],[],[]).
true.
?- fn([1],[1],[2]).
true.
?- fn([1,2],[3,4],[4,6]).
true.
?- fn([1,2],[3,4,5],[4,6,5]).
false.
With regards to the two conditions. When I look at exercises problems for logic programming they sometimes give a condition like True if lists are the same length or some other condition that returns true. I tend to ignore those at first and concentrate on getting the other part done first, in this case elements of third list is sum of the two lists then I check to see if the other conditions are correct. For most simple classroom exercises they are. I sometimes think teacher try to give out these extra conditions to confuse the student, but in reality the are there just to clarify how the code should work.
I am not sure the problem is correct for SO. Eventually, I will migrate it.
Please consider a list [1; 2; ..; n]. How many ways there are such that it can be expressed as a concatenation of two lists?
The answer that I gave to this is n + 1. The problem with my answer, is that it is based only on empirical observation.
I.e. given a list of length 3 such as [1; 2; 3], I think that I can represent it as:
[] # [1; 2; 3]
[1] # [2; 3;]
[1; 2] # [3]
[1; 2; 3] # []
Is my hypothesis correct? How do you suggest to test it on a stronger basis?
You can prove this by induction.
You show that your formula holds for n = 1 (or n = 0 if you want to consider the epsilon case)
then you show that your formula holds when going from n to n = n + 1.
It then follows that it is correct for all n.
You can prove this from the construction of lists:
A list is either the empty list [] or a pair (a, L) where a is an element and L is a list.
Formally
L := []
| (a, L)
Now, to define your number of concatenations:
ncat(L) := 1 if L=[]
ncat(M)+1 if L=(a, M)
Both cases are easy to see. There is no other way to concatenate two lists to an empty list except for []=cat([], []). And by construction, L = cat([a], M), hence exactly one additional way to split L compared to however many splits are inM already (i.e. after the a).
Note that the specialty of being able to concatenate the empty list either at the head or tail of another list is safely included in this proof, left to the diligent reader.
I want to find the bigger value from a list's element's pairs.
Ie. list=[5,7,4,5,6,8] the pairs are [5,7], [7,4], [4,5] etc.
Right now I have this little code snippet:
bigger([],X).
bigger([E1],[H|E1]).
bigger([E1,E2|T],[H|_]):-
(E1>E2,bigger([E2|T],[H|E1]));
(E1<E2,bigger([E2|T],[H|E2])).
The solution should look like:
?- bigger([5,7,4,5,6,8],X).
X = [7,7,5,6,8,8]
EDIT:
Deleted the remove/3 lines, since they're wrong.
I'll give MY understanding of how the code works.
Empty given list check.
One element list check, adds it to output list end ([H|E1])
More than one element in given list, output list
3.1 First two element check (E1 >/< E2)
3.2 New recursive query without E1 (first element)
3.3 Whichever is bigger is output list's last element now.
First I'll show you my solution of your problem (and the result shouldn't be X = [7,7,5,6,8]? I'll make this version.)
gtr(X,Y,Y) :-
Y>=X.
gtr(X,_,X).
bigger([],[]).
bigger([_], []).
bigger([X,Y|R], [Z|H]) :-
bigger([Y|R],H), gtr(X,Y,Z),!.
If you want to have last element appear in this list anyway than just change second bigger function.
Since the relation is describing lists you could opt to use DCGs for the task:
max_of(X,X,Y) :- X >= Y. % X is maximum if X>=Y
max_of(Y,X,Y) :- Y > X. % Y is maximum if Y>X
list_biggers(L,B) :-
phrase(biggers(L),B). % the DCG biggers//1 describes B based on L
biggers([]) --> % if the list is empty
[]. % there's no element in the biggers list
biggers([X]) --> % if the list contains just one element
[X]. % it is in the biggers list
biggers([X,Y|Xs]) --> % if the list contains at least two elements
{max_of(M,X,Y)}, % the maximum of them
[M], % is in the biggers list
biggers([Y|Xs]). % the same holds for [Y|Xs]
This definition is sticking to your reading of the task, that is, in the case of a one-element list the only element is in the list of bigger elements:
?- list_biggers([5,7,4,5,6,8],B).
B = [7, 7, 5, 6, 8, 8] ;
false.
?- list_biggers([1],B).
B = [1] ;
false.
If you prefer the reading suggested by #Armatorix, just change the second DCG-rule to
biggers([_X]) -->
[].
This way the queries above yields the following results:
?- list_biggers([5,7,4,5,6,8],B).
B = [7, 7, 5, 6, 8] ;
false.
?- list_biggers([1],B).
B = [] ;
false.
Note that the list has to be sufficiently instantiated. Otherwise you get an error:
?- list_biggers([X,Y,Z],B).
ERROR: >=/2: Arguments are not sufficiently instantiated
If the list only contains integers, you can remedy this problem by using CLP(FD). Add a line to include the library and change max_of/2 like so:
:- use_module(library(clpfd)).
max_of(X,X,Y) :- X #>= Y.
max_of(Y,X,Y) :- Y #> X.
Now the query above delivers all 4 expected solutions:
?- list_biggers([X,Y,Z],B).
B = [X, Y, Z],
X#>=Y,
Y#>=Z ;
B = [X, Z, Z],
X#>=Y,
Y#=<Z+ -1 ;
B = [Y, Y, Z],
X#=<Y+ -1,
Y#>=Z ;
B = [Y, Z, Z],
X#=<Y+ -1,
Y#=<Z+ -1 ;
false.
In order to construct logical programs, one needs to think logical. Based on the problem statement, there are three possibilities here:
we have an empty list, in that case the result is an empty list as well:
bigger([],[]).
in case we have a list with one element, the problem is underspecified. I would say that the result should be an empty list, but your example seems to suggest that we return that number, since we then have a 1-tuple, and the maximum of a 1-tuple is of course the single element in the tuple:
bigger([H],[H]).
in case the list contains two or more elements [H1,H2|T], then H1 and H2 are the first two elements. In that case we construct a vitual tuple in our head [H1,H2] and calculate the maximum, which is thus M is max(H1,H2). We prepend M to the resulting list of the recursion. That recursion is done on the list [H2|T]: the list where we popped H1 from:
bigger([H1,H2|T],[M|U]) :-
M is max(H1,H2),
bigger([H2|T],U).
Or putting this all together:
bigger([],[]).
bigger([H],[H]).
bigger([H1,H2|T],[M|U]) :-
M is max(H1,H2),
bigger(T,U).
I'm trying to develop code in prolog to capture items with frequency 0. Look at the example, the tuple:
[[1,31],[2,0],[3,21],[4,0],[5,0]]
Where each element is something else with 2 elements each, so the elements that should be captured are 2, 4 and 5, for frequency 0. The code below represents the idea:
match([],_).
match([[A,Y]|Tail],[A|Tail2]):- Y==0,match(Tail,[Tail2|A]),!.
match([[_,_]|Tail],X):- match(Tail,X).
Two parameters are passed: A tuple containing the set of target values and frequencies,
(["Target value", "frequency"], ["target value", "frequency"], ...]
And a second parameter that is a variable, it receives the target elements. However, the abstraction I had to develop the code is not correct, because the results are not as expected. I have gone round step by step to understand, modified several things and the result is always the same ... A list with only 2 elements is returned in any case (even if there is only one target with a frequency of 0).
Example with 3 frequency targets 0:
?- match([[1,31],[2,0],[3,312],[4,0],[5,0]],X).
X = [2|4].
Expected result for this case: X = [2,4,5].
Example with 1 frequency target 0:
?- match([[1,31],[2,0],[3,312],[4,312],[5,123]],X).
X = [2|_9998].
Expected result for this case: X = [2].
Someone can help me?
You could opt to describe the resulting list with DCGs like so:
match(Pairs,ZFs) :- % the items with frequency 0
phrase(zeros(Pairs),ZFs). % are described by zeros//1
zeros([]) --> % the empty list
[]. % contains no items
zeros([[I,0]|Is]) --> % if the frequency is 0
[I], % the item is in the list
zeros(Is). % the same for the remaining items
zeros([[I,F]|Is]) --> % if the frequency
{dif(F,0)}, % is not 0, the item isn't in the list
zeros(Is). % the same for the remaining items
Thus the two example queries in your post yield the desired results:
?- match([[1,31],[2,0],[3,21],[4,0],[5,0]],X).
X = [2,4,5] ? ;
no
?- match([[1,31],[2,0],[3,312],[4,312],[5,123]],X).
X = [2] ? ;
no
You're very close! Just two little issues:
Currently when an empty list is passed it, you say the result can be anything (_). I highly doubt this is what you want; the output for an empty list shoudl be an empty list as well.
The recursive call in the second clause is not correct. What you want the result to be is A followed by the result of the recursive call (Tail2). However, for some reason you wrote the recursive call with also A in it. I can't quite tell how you got to this, but you should just get Tail2 on its own.
Additionally, you can avoid writing Y==0 by directly writing it in the head of the clause. The resulting code then looks like this:
match([],[]).
match([[A,0]|Tail], [A|Tail2]) :- match(Tail, Tail2), !.
match([[_,_]|Tail], X) :- match(Tail, X).
?- match([[1,31],[2,0],[3,312],[4,0],[5,0]],X).
X = [2, 4, 5]
?- match([[1,31],[2,0],[3,312],[4,312],[5,123]],X).
X = [2]
I'm trying to write a palindrome function in Prolog. I know I could just use something like
palindrome(List) :- reverse(List, List).
But I'm trying to figure out a way without using the built in reverse. I've created my own reverse rule:
rev([], []).
rev([H|T], X) :- rev(T, Y), append(Y, [H], X).
And what I'd like is, given a list, say [a,b,c,d], I'd like to do something like "X = rev([a,b,c,d]), but I'm really not sure whether this is possible in Prolog.
If it is, the way I would write my palindrome function would be something like:
palindrome(List) :- append(L1, rev(L1), List).
Is it possible to do what I'm trying to do - i.e. X = rev([a,b,c,d])?.
Thanks.
Palindromes are lists that read the same from front to back and from back to front. So the example you have given, [a,b,c,d] and it's reversal, constitute a palindrome if the first is directly followed by the second: [a,b,c,d,d,c,b,a]. Since you are trying to describe specific kinds of lists, it is very tempting to use Prolog DCGs for the task. With them you can define palindromes like so:
palindrome(X) :-
phrase(palindrome,X).
palindrome --> % base case for even number of elements
[].
palindrome --> % base case for odd number of elements
[A].
palindrome --> % general case: a palindrome is
[A], % some element A...
palindrome, % ... followed by a palindrome ...
[A]. % ... followed by element A
The most general query is producing palindromes with variables for each position:
?- palindrome(P).
P = [] ? ;
P = [_A] ? ;
P = [_A,_A] ? ;
P = [_A,_B,_A] ? ;
P = [_A,_B,_B,_A] ? ;
P = [_A,_B,_C,_B,_A] ?
...
Or alternatively you can test if a specific list is a palindrome:
?- palindrome("rats live on no evil star").
yes
?- palindrome([1,2,3,2,1]).
yes
?- palindrome([a,b,c,d]).
no
?- palindrome([a,b,c,d,d,c,b,a]).
yes
If you insist on using list reversal you can define the relation like so:
list([]) -->
[].
list([X|Xs]) -->
[X],
list(Xs).
invlist([]) -->
[].
invlist([X|Xs]) -->
invlist(Xs),
[X].
palindrome --> % a paindrome is
list(L), % a list followed
invlist(L). % by its reversal
palindrome --> % a palindrome is
list(L), % a list followed by
[_A], % some element
invlist(L). % then by the reversed list
The first of the above queries produces the answers in a different order now, namely the solutions with an even number of elements first:
?- palindrome(P).
P = [] ? ;
P = [_A,_A] ? ;
P = [_A,_B,_B,_A] ? ;
P = [_A,_B,_C,_C,_B,_A] ?
...
The other example queries yield the same result. However, the first definition seems to be clearly preferable to me. Not only because it is shorter as there is no need for additional DCG rules but also because it is producing the results in a fair order: empty list, one element, two elements, ... With the second version you get all the lists with an even number of elements first and there are infinitely many of those. So you never get to see a solution with an odd number of elements with the most general query.