Prolog sequences - prolog

Good Day,
I have a task (not homework), but test preparation question. Given a value of n where n > 0. I need to find out what 3**n value is. I do have something that works.
% expo
expo([],[]).
expo([X|T], [Y|Result]):-
number(X),
Y is 3 ^ X,
expo(T,Result).
expo([ThrowAway|Tail], [ThrowAway|Result]):-
expo(Tail,Result).
last([X]):-
write("M = "),
write(X).
last([Y|Tail]):-
last(Tail).
do_list(N) :-
findall(Num, between(0, N, Num), L),
expo(L, E),
last(E).
When I run this at the console:
do_list(4).
M = 81
true.
So it does give me what I want. But is a recursive solution necessary? I just want to generate a sequence of numbers and use those numbers as my exponent which I have done, but I had to create two lists to this.
Ideally, I'd like to do:
do_list(4, M).
M = 81
true.
Is this possible to do this without two lists? Is it possible without recursion? I'm new to Prolog, so it's taking me a little getting used to "thinking" in Prolog.
TIA,
coson

If you want to do something in all elements of a list then yes most of the times you need recursion (except from cases like when you use predicates like fundall/3 which does the recursion ...).
If you want to return your result in an argument and not just print it then you need for the above predicate two lists (one is the input and the other one is the output).
Though I don't understand why not just writing:
find_pow(Input,Output):-Output is 3^Input.
From what I understood you calculate 3^i for every i<=n and keep last element which could be done independently. So if I understood corrctly what you're trying to do, this could be done without using lists and recursion (if you use predefined pow function ^ else if you write a predicate that computes the power 3^n then you would use recursion... ).
Example:
?- find_pow(4,X).
X = 81.

Related

Tail-recursive list of divisors of an integer in prolog

I am trying to make a simple tail-recursive loop to collect the divisors of an integer, divisors(N,List) and its working when List is not instantiated, for example,
?- divisors(14,What).
What = [2, 7] ?
And I can verify that the wrong list is not the list of divisors,
?- divisors(14,[2, 8]).
no
Unless I try to verify that [] is not the list, this unfortunately succeeds:
?- divisors(14,[]).
true
can see in the debugger why it is erroneously succeeding, but I don't see how to fix this:
divisors_aux(1,_,L,L).
divisors_aux(D,N,List,Aux) :- D>1,0 is N mod D,D1 is D-1,
divisors_aux(D1,N,List,[D|Aux]).
divisors_aux(D,N,List,Aux) :- D>1,D1 is D-1,divisors_aux(D1,N,List,Aux).
divisors(N,List) :- N>1,nonvar(N),D is N-1,divisors_aux(D,N,List,[]).
I know there are looping approaches (foreach, etc.) but I am trying to make this "brute force" approach work based on what I have learned so far (roughly first 100 pages of Covington et. al.)
Thanks.
Your problem is that when the second clause of divisors_aux/3 fails (or if it succeeds and you ask for another solution) it will always backtrack to the third clause.
You may want to guard the third clause with \+(0 is N mod D) so that it fails when the current number is a divisor of N.
Or alternatively join both clauses with an if-then-else construct:
divisors_aux(1,_,L,L).
divisors_aux(D,N,List,Aux) :- D>1,
(0 is N mod D -> Aux1=[D|Aux] ; Aux1=Aux),
D1 is D-1,
divisors_aux(D1,N,List,Aux1).
divisors(N,List) :- N>1,nonvar(N),D is N-1,divisors_aux(D,N,List,[]).

Prolog: Chaining multiple rules

So I am an absolute beginner in Prolog. I am learning recursion at the moment and this is what I got until now on my task.
dance(start).
dance(forward(T)) :- dance(T).
dance(backward(T)) :- dance(T).
count(start,0,0).
count(forward(X),succ(Y),Z) :- count(X,Y,Z).
count(backward(X),Y,succ(Z)) :- count(X,Y,Z).
greater(succ(0),0).
greater(succ(Y),succ(Z)):-greater(Y,Z).`
Summary of what this is supposed to do: There can be dances starting with the "start" and then either forward or backward addition per recursion. In count, I managed to be able to count the amount of forward and backward in a given sequence and save them in the "succ" notation and in greater I want to compare two of such "succ" numbers. And greater shall be true if the first argument is larger (consists of more "succs" than the second argument.
Now my task is to write a new rule "more(X)" which is true if the sequence X (build from dance) has more forward than backward in it. I think I have all the subtasks I need for it but now I am helpless with chaining them together because until now I only had 2 rules with the same amount of parameters but in this case, I got one with one, two, and three parameters. The solution should be something like this
more(X):-greater(Y,Z)
but how do I get my "succ" umbers from "count" to "greater" and the given sequence X to "count"? I do have to change some of the rules otherwise count is never called, right?
So it should be more like more(X):-greater(count(X,Y,Z)) ?
But like this, I would have to change the greater rules to be able to "get" this type of parameter.
Example query ?- more(backward(forward(start))).
false.
?- more(forward(start)).
true.
Your dance/1 and count/3 predicates seems correct.
If you want "greater" where greater(X, Y) means that X is greater than Y, you'd write:
greater(succ(_), 0).
greater(succ(X), succ(Y)) :- greater(X, Y).
Your solution checks if X is exactly one greater than Y.
Note that nothing is greater than 0.
If you implement more/1 in terms of count/3 and greater/2, you'd write:
more(X) :-
count(X, Forward, Backward),
greater(Forward, Backward).
So it should be more like more(X):-greater(count(X,Y,Z)) ?
No, you are writing that as if it is Python and greater(count(X,Y,Z)) will call greater(...) on the return from count. Prolog predicates are not function calls, and count(...) does not return anything in that way.
The result of the count is Y and Z. (These names you are using could be clearer). Do the count, and then after, use the Y and Z for something else.
count(X,Y,Z),
greater(Y,Z)
The comma being AND; "this code works if count of X is Y and Z AND Y is greater than Z".

How can I verify if a coordinate is in a list

I'm generating random coordinates and adding on my list, but first I need verify if that coordinate already exists. I'm trying to use member but when I was debugging I saw that isn't working:
My code is basically this:
% L is a list and Q is a count that define the number of coordinate
% X and Y are the coordinate members
% check if the coordniate already exists
% if exists, R is 0 and if not, R is 1
createCoordinates(L,Q) :-
random(1,10,X),
random(1,10,Y),
convertNumber(X,Z),
checkCoordinate([Z,Y],L,R),
(R is 0 -> print('member'), createCoordinates(L,Q); print('not member'),createCoordinates(L,Q-1).
checkCoordinate(C,L,R) :-
(member(C,L) -> R is 0; R is 1).
% transforms the number N in a letter L
convertNumber(N,L) :-
N is 1, L = 'A';
N is 2, L = 'B';
...
N is 10, L = 'J'.
%call createCoordinates
createCoordinates(L,20).
When I was debugging this was the output:
In this picture I'm in the firts interation and L is empty, so R should be 1 but always is 0, the coordinate always is part of the list.
I have the impression that the member clause is adding the coordinate at my list and does'nt make sense
First off, I would recommend breaking your problem down into smaller pieces. You should have a procedure for making a random coordinate:
random_coordinate([X,Y]) :-
random(1, 10, XN), convertNumber(XN, X),
random(1, 10, Y).
Second, your checkCoordinate/3 is converting Prolog's success/failure into an integer, which is just busy work for Prolog and not really improving life for you. memberchk/2 is completely sufficient to your task (member/2 would work too but is more powerful than necessary). The real problem here is not that member/2 didn't work, it's that you are trying to build up this list parameter on the way out, but you need it to exist on the way in to examine it.
We usually solve this kind of problem in Prolog by adding a third parameter and prepending values to the list on the way through. The base case then equates that list with the outbound list and we protect the whole thing with a lower-arity procedure. In other words, we do this:
random_coordinates(N, Coordinates) :- random_coordinates(N, [], Coordinates).
random_coordinates(0, Result, Result).
random_coordinates(N, CoordinatesSoFar, FinalResult) :- ...
Now that we have two things, memberchk/2 should work the way we need it to:
random_coordinates(N, CoordinatesSoFar, FinalResult) :-
N > 0, succ(N0, N), % count down, will need for recursive call
random_coordinate(Coord),
(memberchk(Coord, CoordinatesSoFar) ->
random_coordinates(N, CoordinatesSoFar, FinalResult)
;
random_coordinates(N0, [Coord|CoordinatesSoFar], FinalResult)
).
And this seems to do what we want:
?- random_coordinates(10, L), write(L), nl.
[[G,7],[G,3],[H,9],[H,8],[A,4],[G,1],[I,9],[H,6],[E,5],[G,8]]
?- random_coordinates(10, L), write(L), nl.
[[F,1],[I,8],[H,4],[I,1],[D,3],[I,6],[E,9],[D,1],[C,5],[F,8]]
Finally, I note you continue to use this syntax: N is 1, .... I caution you that this looks like an error to me because there is no distinction between this and N = 1, and your predicate could be stated somewhat tiresomely just with this:
convertNumber(1, 'A').
convertNumber(2, 'B').
...
My inclination would be to do it computationally with char_code/2 but this construction is actually probably better.
Another hint that you are doing something wrong is that the parameter L to createCoordinates/2 gets passed along in all cases and is not examined in any of them. In Prolog, we often have variables that appear to just be passed around meaninglessly, but they usually change positions or are used multiple times, as in random_coordinates(0, Result, Result); while nothing appears to be happening there, what's actually happening is plumbing: the built-up parameter becomes the result value. Nothing interesting is happening to the variable directly there, but it is being plumbed around. But nothing is happening at all to L in your code, except it is supposedly being checked for a new coordinate. But you're never actually appending anything to it, so there's no reason to expect that anything would wind up in L.
Edit Notice that #lambda.xy.x solves the problem in their answer by prepending the new coordinate in the head of the clause and examining the list only after the recursive call in the body, obviating the need for the second list parameter.
Edit 2 Also take a look at #lambda.xy.x's other solution as it has better time complexity as N approaches 100.
Since i had already written it, here is an alternative solution: The building block is gen_coord_notin/2 which guarantees a fresh solution C with regard to an exclusion list Excl.
gen_coord_notin(C, Excl) :-
random(1,10,X),
random(1,10,Y),
( memberchk(X-Y, Excl) ->
gen_coord_notin(C, Excl)
;
C = X-Y
).
The trick is that we only unify C with the new result, if it is fresh.
Then we only have to fold the generations into N iterations:
gen_coords([], 0).
gen_coords([X|Xs], N) :-
N > 0,
M is N - 1,
gen_coords(Xs, M),
gen_coord_notin(X, Xs).
Remark 1: since coordinates are always 2-tuples, a list representation invites unwanted errors (e.g. writing [X|Y] instead of [X,Y]). Traditionally, an infix operator like - is used to seperate tuples, but it's not any different than using coord(X,Y).
Remark 2: this predicate is inherently non-logical (i.e. calling gen_coords(X, 20) twice will result in different substitutions for X). You might use the meta-level predicates var/1, nonvar/1, ground/1, integer, etc. to guard against non-sensical calls like gen_coord(1-2, [1-1]).
Remark 3: it is also important that the conditional does not have multiple solutions (compare member(X,[A,B]) and memberchk(X,[A,B])). In general, this can be achieved by calling once/1 but there is a specialized predicate memberchk/2 which I used here.
I just realized that the performance of my other solutions is very bad for N close to 100. The reason is that with diminishing possible coordinates, the generate and test approach will take longer and longer. There's an alternative solution which generates all coordinates and picks N random ones:
all_pairs(Ls) :-
findall(X-Y, (between(1,10,X), between(1,10,Y)), Ls).
remove_index(X,[X|Xs],Xs,0).
remove_index(I,[X|Xs],[X|Rest],N) :-
N > 0,
M is N - 1,
remove_index(I,Xs,Rest,M).
n_from_pool(_Pool, [], 0).
n_from_pool(Pool, [C|Cs], N) :-
N > 0,
M is N - 1,
length(Pool, L),
random(0,L,R),
remove_index(C,Pool,NPool,R),
n_from_pool(NPool, Cs, M).
gen_coords2(Xs, N) :-
all_pairs(Pool),
n_from_pool(Pool, Xs, N).
Now the query
?- gen_coords2(Xs, 100).
Xs = [4-6, 5-6, 5-8, 9-6, 3-1, 1-3, 9-4, 6-1, ... - ...|...] ;
false.
succeeds as expected. The error message
?- gen_coords2(Xs, 101).
ERROR: random/1: Domain error: not_less_than_one' expected, found0'
when we try to generate more distinct elements than possible is not nice, but better than non-termination.

Categorise List in Prolog

Alright so I am coding a parser for arithmetic equations. I get the input in a list, e.g. "10+20" = [49,48,43,50,48] and then I convert all the digits to there corresponding numbers e.g. [49,48,43,50,48] = [1,0,43,2,0] and from there I want to put integers > 10 back together.
Converting from ascii -> digits I use a maplist and number_codes to convert.
One approach I had was to just traverse the list and if it's 0-9 store it in a variable and then check the next number, 0-9 append it to the other variable and so on until I hit an operator. I can't seem to simply append digits as it were. Here's my current code.
expression(L) :-
maplist(chars, L, Ls).
chars(C, N) :-
(
C >= "0", "9" >= C -> number_codes(N, [C]);
N is C
).
Not sure if there's a simple way to add to my code (as far as I know, maplist only gives back a list of equal length to the list passed in but I could be mistaken).
Any help is appreciated :)
Yes, maplist only 'gives back' a list of equal length. Moreover, maplist applies a predicate only to one element (basically it's context-free). Therefore, it is not possible to do what you want (combine digits between operators to a single number) with maplist and you would have to write the recursion yourself.
However, you can do something way easier than all this converting back and forth:
expression(L, E):-
string_to_atom(L,A),
atom_to_term(A,E,[]).
Which works like this:
2 ?- expression("1+2",E).
E = 1+2.
3 ?- expression("1+2",E), X is E.
E = 1+2, X = 3.
4 ?- expression("1+2",E), X+Y = E.
E = 1+2, X = 1, Y = 2.
5 ?- expression("1+2+3",E), X+Y = E.
E = 1+2+3, X = 1+2, Y = 3.
Naturally, if you want a list with all the numbers involved you will have to do something recursive but this is kinda trivial imho.
If however you still want to do the converting, I suggest checking Definite Clause Grammars; it will simplify the task a lot.
I answered some time ago with an expression parser.
It will show you how to use DCG for practical tasks, and I hope you will appreciate the generality and simplicity of such approach.
Just a library predicate is required from SWI-Prolog, number//1, easily implemented in Sicstus. Let me know if you need more help on that.

Sum of a list in prolog

I'm reading 'the art of prolog' book and I found an exercise that reads 'Define the relation sum(ListOfIntegers,Sum) which holds if Sum is the sum of the ListOfIntegers, without using any auxiliary predicate' .I came up with this solution:
sum([],Sum).
sum([0|Xs], Sum):-sum(Xs, Sum).
sum([s(X)|Xs], Sum):-sum([X|Xs],s(Sum)).
Which does not work exactly as I would want it to.
?- sum([s(s(0)),s(0),s(s(s(0)))],X).
true ;
false.
I was expecting X to be
s(s(s(s(s(s(0))))))
I thought that the problem is that I have to 'initialize' Sum to 0 in the first 'iteration' but that would be very procedural and unfortunately I'm not quite apt in prolog to make that work.
Any ideas or suggestions?
Your first clause should read
sum([], 0).
With that change, the vacuous true return goes away and you're left with one problem: the third clause reverses the logic of summation. It should be
sum([s(X)|Xs], s(Sum)) :- sum([X|Xs], Sum).
because the number of s/1 terms in the left argument to sum/2 should be equal to the number of them in the right argument.
The best way to localize the problem is to first simplify your query:
?- sum([0],S).
true.
?- sum([],S).
true.
Even for those, you get as an answer that any S will do. Like
?- sum([],s(s(0))).
true.
Since [] can only be handled by your fact, an error must lie in that very fact.
You stated:
sum([], Sum).
Which means that the sum of [] is just anything. You probably meant 0.
Another error hides in the last rule... After fixing the first error, we get
?- sum([0],Sum).
Sum = 0.
?- sum([s(0)],Sum).
false.
Here, the last clause is responsible. It reads:
sum([s(X)|Xs], Sum):-sum([X|Xs],s(Sum)).
Recursive rules are relatively tricky to read in Prolog. The simplest way to understand them is to look at the :- and realize that this should be an arrow ← (thus a right-to-left arrow) meaning:
provided, that the goals on the right-hand side are truewe conclude what is found on the left-hand side
So, compared to informal writing, the arrows points into the opposite direction!
For our query, we can consider the following instantiation substituting Xs with [] and X with 0.
sum([s(0)| [] ], Sum) :- sum([0| []],s(Sum)).
So this rule now reads right-to-left: Provided, sum([0],s(Sum)) is true, ... However, we do know that only sum([0],0) holds, but not that goal. Therefore, this rule never applies! What you intended was rather the opposite:
sum([s(X)|Xs], s(Sum)):-sum([X|Xs],Sum).
I'm not really following your logic, what with all the seemingle extraneous s(X) structures floating about.
Wouldn't it be easier and simpler to do something like this?
First, define your solution in plain english, thus:
The sum of an empty list is 0.
The sum of a non-empty list is obtained by adding the head of the list to the sum of the tail of the list.
From that definition, the prolog follows directly:
sum( [] , 0 ) . % the sum of an empty list is 0.
sum( [X|Xs] , T ) :- % the sum of an non-empty list is obtained by:
sum( Xs , T1 ) , % - first computing the sum of the tail
T is X + T1 % - and then, adding that the to head of the list
. % Easy!

Resources