Prolog, triangular numbers, accumulators and tail recursion - prolog

I'm working on a homework assignment, consisting of 2 parts.
The first is to write a Prolog program that checks if a certain pair X, Y belongs to a http://en.wikipedia.org/wiki/Triangular_number. For example: (2, 3) = true; (4, 10) = true et cetera.
The first solution uses 'ordinary' recursion, and I've solved this like this:
triangle(0, 0).
triangle(X, Y) :- X > 0, Y > 0, A is X - 1, B is Y - X, triangle(A, B).
The second part is to solve this using tail recursion/an accumulator, using a triangle/3 predicate.
Though I have used an accumulator in another assigment, in which the use was quite obvious, so I have a general idea of how to use an accumulator, I'm quite puzzeled as to how to use it in this context.
So, I'm not looking for an algorithm, I'd much rather solve that myself, but more of a practical advise on how to apply an accumulator in this context.

The beginning is always the same, i.e. the first three lines are basically what you write for each and every tail recursive predicate (with a [] instead of a 0 for list predicates).
From there you can go on without many changes:
triangle_t(X, Y) :- triangle_t(X, 0, Y).
triangle_t(0, Y, Y).
triangle_t(X, Acc, Y) :-
X > 0,
A is X - 1,
AccX is Acc + X,
triangle_t(A, AccX, Y).
Here are some statistics for large X:
64 ?- time(triangle(1000000,500000500000)).
% 4,000,000 inferences, 0.50 CPU in 0.52 seconds (96% CPU, 8012769 Lips)
true.
65 ?- time(triangle_t(1000000,500000500000)).
% 3,000,001 inferences, 0.41 CPU in 0.44 seconds (92% CPU, 7396405 Lips)
true.
So, while your own predicate is basically already tail recursive (because the recursive call is the last thing to do) the version with an accumulator still saves some time because you do not need the check for Y > 0. If you introduce this line in the triangle_t predicate, they have exactly the same runtime characteristics again:
67 ?- time(triangle_t(1000000,500000500000)).
% 4,000,001 inferences, 0.53 CPU in 0.53 seconds (100% CPU, 7541432 Lips)
true.
Also note that you can now use the predicate to generate the n'th triangular number.

Related

How to Add all lengths of sublists In prolog . Please Help me , i'm stuck

Adding all lengths of sublists In prolog
Using
sum([],ADD,ADD).
sum([P|R], ADD, OUTPUT):- X is ADD + P,
sum(R,X,ADD).
Avoiding the slow recursion:
sublists_len(SubLists, Length) :-
sublists_len_(SubLists, 0, Length).
sublists_len_([], Len, Len).
sublists_len_([H|T], Upto, Len) :-
length(H, LenH),
Upto1 is Upto + LenH,
sublists_len_(T, Upto1, Len).
Performance comparison in swi-prolog:
?- length(SubLists, 5000000), maplist(=([1, 2]), SubLists), time(sublists_len(SubLists, Len)).
% 20,000,002 inferences, 2.730 CPU in 2.697 seconds (101% CPU, 7326281 Lips)
?- length(SubLists, 5000000), maplist(=([1, 2]), SubLists), time(list_subsum(SubLists, Len)).
% 20,000,001 inferences, 7.581 CPU in 7.500 seconds (101% CPU, 2638194 Lips)
nestedlist_length(List, Length) :-
flatten(List, Flat),
length(Flat, Length).
Your code: sum([],ADD,ADD). says that the sum of the lengths of an empty list could be anything, as long as you repeat it enough. sum([], 50, 50). works there, so does sum([], dog, dog)..
This: sum([P|R], ADD, OUTPUT):- X is ADD + P, sum(R,X,ADD). says that you never use OUTPUT again, and that you try and add the head onto nothing and then stuff that down into the sum of the tail which can never get a value because there's nowhere that you say an empty list has length sum of 0.
list_subsum([], 0).
list_subsum([H|T], Output) :-
length(H, HLen),
list_subsum(T, TLengthSum),
Output is HLen + TLengthSum.
Empty lists are length 0, lists of things get the length of the head, get the length of the tail, then output those two added together.
The tail will eventually be [] which will have a length 0 which stops the process.

Prolog returning only the max value from all iterations

I have a method that returns me a number on all iterations, but now I need to returns only the max value from all of the iterations that were done.
find_max(X, Y):-
find_number(X, Y).
So the find_number() returns only 1 number and some text alongside it. So for example if I were to ran it I would get this output:
X = 1, Y = me;
X = 5, Y = you;
X = 6, Y = he;
And the only output I need to return is the X = 6, Y = he;.
I am using SWI-Prolog.
A more portable alternative to the library(aggregate) posted by Willem, as the library is only available in a few Prolog systems, is:
find_max_alt(Xm, Ym) :-
setof(max(X, Y), find_number(X, Y), Solutions),
reverse(Solutions, [max(Xm, Ym)| _]).
This solution also appears to required a smaller number of inferences. Using the data in the question, we get:
?- time(find_max(Xm, Ym)).
% 40 inferences, 0.000 CPU in 0.000 seconds (83% CPU, 800000 Lips)
Xm = 6,
Ym = he.
Versus:
?- time(find_max_alt(Xm, Ym)).
% 25 inferences, 0.000 CPU in 0.000 seconds (76% CPU, 675676 Lips)
Xm = 6,
Ym = he.
The setof/3 predicate is a standard predicate. The reverse/2 predicate is a common list predicate (and much simpler to define than the predicates in the aggregate library.
You can use the aggregate library for that:
:- use_module(library(aggregate)).
find_max(Xm, Ym):-
aggregate(max(X, Y), find_number(X, Y), max(Xm, Ym)).

On solving project Euler #303 in with Prolog / clpfd

Here comes Project Euler Problem 303, "Multiples with small digits".
For a positive integer n, define f(n) as the least positive multiple of n that, written in base 10, uses only digits ≤ 2.
Thus f(2)=2, f(3)=12, f(7)=21, f(42)=210, f(89)=1121222.
Also, .
Find .
This is the code I have already written / that I want to improve:
:- use_module(library(clpfd)).
n_fn(N,FN) :-
F #> 0,
FN #= F*N,
length(Ds, _),
digits_number(Ds, FN),
Ds ins 0..2,
labeling([min(FN)], Ds).
That code already works for solving a small number of small problem instances:
?- n_fn(2,X).
X = 2
?- n_fn(3,X).
X = 12
?- n_fn(7,X).
X = 21
?- n_fn(42,X).
X = 210
?- n_fn(89,X).
X = 1121222
What can I do to tackle above challenge "find: sum(n=1 to 10000)(f(n)/n)"?
How can I solve more and bigger instances in reasonable time?
Please share your ideas with me! Thank you in advance!
It is slow on 9's and there is a pattern..
so..
n_fn(9,12222):-!.
n_fn(99,1122222222):-!.
n_fn(999,111222222222222):-!.
n_fn(9999,11112222222222222222):-!.
But i'm sure it would be nicer to have the prolog find this patten and adapt the search.. not sure how you would do that though!
In general it must be recalculating a lot of results..
I cannot spot a recurrence relation for this problem. So, initially I was thinking that memoizing could speed it up. Not really...
This code, clp(fd) based, is marginally faster than your...
n_fn_d(N,FN) :-
F #> 0,
FN #= F*N,
digits_number_d([D|Ds], Ts),
D in 1..2,
Ds ins 0..2,
scalar_product(Ts, [D|Ds], #=, FN),
labeling([min(FN)], [D|Ds]).
digits_number_d([_], [1]).
digits_number_d([_|Ds], [T,H|Ts]) :-
digits_number_d(Ds, [H|Ts]), T #= H*10.
When I used clp(fd) to solve problems from Euler, I stumbled in poor performance... sometime the simpler 'generate and test' paired with native arithmetic make a difference.
This simpler one, 'native' based:
n_fn_e(N,FN) :-
digits_e(FN),
0 =:= FN mod N.
digits_e(N) :-
length([X|Xs], _),
maplist(code_e, [X|Xs]), X \= 0'0,
number_codes(N, [X|Xs]).
code_e(0'0).
code_e(0'1).
code_e(0'2).
it's way faster:
test(N) :-
time(n_fn(N,A)),
time(n_fn_d(N,B)),
time(n_fn_e(N,C)),
writeln([A,B,C]).
?- test(999).
% 473,671,146 inferences, 175.006 CPU in 182.242 seconds (96% CPU, 2706593 Lips)
% 473,405,175 inferences, 173.842 CPU in 178.071 seconds (98% CPU, 2723188 Lips)
% 58,724,230 inferences, 25.749 CPU in 26.039 seconds (99% CPU, 2280636 Lips)
[111222222222222,111222222222222,111222222222222]
true

Best way to generate integer numbers in Prolog

I want to generate integer numbers and I'm looking for the best way to do this. Example:
?- number2(N).
N = 0;
N = 1;
N = 2;
...
(and so on)
Now I'm simply using length/2:
number2(N) :- length(_, N).
But I think that there should be some better way (without creating temporary list). I could probably write some code myself basing on code of length/2 but I'm looking for solution that employs already existing, built-in predicates. Is there any built-in predicate that would work better than length/2? I couldn't find anything like that.
It is hard to top your solution ; and probably it is not worth the effort. After all, there are now three suggestions that all are incorrect for one case or another:
?- time( (number2_gk(N), N == 10000) ). % your original
% 20,002 inferences, 0.007 CPU in 0.007 seconds (99% CPU, 3006132 Lips)
N = 10000
?- time( (number2_cc(N), N == 10000) ). % quadratic overhead
% 50,025,001 inferences, 28.073 CPU in 28.196 seconds (100% CPU, 1781945 Lips)
N = 10000
?- time( (next_integer(N), N == 10000) ).
% 20,002 inferences, 0.011 CPU in 0.011 seconds (100% CPU, 1822247 Lips)
N = 10000
However, number2_cc(-1) and next_integer(-1) simply loop, length/2 actually should produce a domain error, like SICStus and many other systems do.
As you can see, CC's solution is worse than your original one.
Also the suggestion by mat produces different behavior in the following situation:
goal_expansion(length(Ls,L), between(0,infinite,L)) :-
var_property(Ls, fresh(true)).
as(N) :-
length(L,N),
phrase(a, L).
a --> [a], a.
a --> [].
The goal as(N) now loops instead of enumerating all N.
If you really insist on an improvement, consider the following tail-recursive solution using library(clpfd):
nat(N) :-
nat(N, 0).
nat(N, N0) :-
N #>= N0,
( N = N0
; N1 is N0+1,
nat(N, N1)
).
?- time( (nat(N), N == 10000) ).
% 1,850,152 inferences, 0.544 CPU in 0.545 seconds (100% CPU, 3399793 Lips)
Which is only an improvement for queries like the following. Otherwise it is just a waste of resources.
?- N in 1..2, nat(N).
To keep between/3 pure, i.e. only with integer arguments,
I have started providing the following predicate above/2
in a library (for the source code see here):
/**
* above(L, X):
* The predicate succeeds for every integer X above the integer L.
*/
% above(+Integer, -Integer)
So if you really want to generate integer numbers,
and not natural numbers, you can use:
gen_int(X) :-
above(0, Y),
(X is Y; X is -Y-1).
The above will give 0, -1, 1, -2, etc.. . If you want to
generate natural numbers including zero, you can use:
gen_nat(X) :-
above(0, X).
The above will give 0, 1, 2, etc... The names gen_int/1
and gen_nat/1 are inspried by SICStus Prolog, see here.
Hope this helps.
Bye
A tail-recursive alternative to Carlo's solution is:
next_integer(I) :-
next_integer(0, I).
next_integer(I, I).
next_integer(I, J) :-
I2 is I + 1,
next_integer(I2, J).
A sample query:
?- next_integer(I).
I = 0 ;
I = 1 ;
I = 2 ;
I = 3 ;
...
You can also easily start from an integer other than zero. For example:
?- next_integer(-5, I).
I = -5 ;
I = -4 ;
I = -3 ;
I = -2 ;
I = -1 ;
I = 0 ;
I = 1 ;
I = 2 ;
I = 3 ;
...

Reversible numerical calculations in Prolog

While reading SICP I came across logic programming chapter 4.4. Then I started looking into the Prolog programming language and tried to understand some simple assignments in Prolog. I found that Prolog seems to have troubles with numerical calculations.
Here is the computation of a factorial in standard Prolog:
f(0, 1).
f(A, B) :- A > 0, C is A-1, f(C, D), B is A*D.
The issues I find is that I need to introduce two auxiliary variables (C and D), a new syntax (is) and that the problem is non-reversible (i.e., f(5,X) works as expected, but f(X,120) does not).
Naively, I expect that at the very least C is A-1, f(C, D) above may be replaced by f(A-1,D), but even that does not work.
My question is: Why do I need to do this extra "stuff" in numerical calculations but not in other queries?
I do understand (and SICP is quite clear about it) that in general information on "what to do" is insufficient to answer the question of "how to do it". So the declarative knowledge in (at least some) math problems is insufficient to actually solve these problems. But that begs the next question: How does this extra "stuff" in Prolog help me to restrict the formulation to just those problems where "what to do" is sufficient to answer "how to do it"?
is/2 is very low-level and limited. As you correctly observe, it cannot be used in all directions and is therefore not a true relation.
For reversible arithmetic, use your Prolog system's constraint solvers.
For example, SWI-Prolog's CLP(FD) manual contains the following definition of n_factorial/2:
:- use_module(library(clpfd)).
n_factorial(0, 1).
n_factorial(N, F) :- N #> 0, N1 #= N - 1, F #= N * F1, n_factorial(N1, F1).
The following example queries show that it can be used in all directions:
?- n_factorial(47, F).
F = 258623241511168180642964355153611979969197632389120000000000 ;
false.
?- n_factorial(N, 1).
N = 0 ;
N = 1 ;
false.
?- n_factorial(N, 3).
false.
Of course, this definition still relies on unification, and you can therefore not plug in arbitrary integer expressions. A term like 2-2 (which is -(2,2) in prefix notation) does not unfiy with 0. But you can easily allow this if you rewrite this to:
:- use_module(library(clpfd)).
n_factorial(N, F) :- N #= 0, F #= 1.
n_factorial(N, F) :- N #> 0, N1 #= N - 1, F #= N * F1, n_factorial(N1, F1).
Example query and its result:
?- n_factorial(2-2, -4+5).
true .
Forget about variables and think that A and B - is just a name for value which can be placed into that clause (X :- Y). to make it reachable. Think about X = (2 + (3 * 4)) in the way of data structures which represent mathematical expression. If you will ask prolog to reach goal f(A-1, B) it will try to find such atom f(A-1,B). or a rule (f(A-1,B) :- Z), Z. which will be unified to "success".
is/2 tries to unify first argument with result of interpreting second argument as an expression. Consider eval/2 as variant of is/2:
eval(0, 1-1). eval(0, 2-2). eval(1,2-1).
eval(Y, X-0):- eval(Y, X).
eval(Y, A+B):- eval(ValA, A), eval(ValB, B), eval(Y, ValA + ValB).
eval(4, 2*2).
eval(0, 0*_). eval(0, _*0).
eval(Y, X*1):- eval(Y, X).
eval(Y, 1*X):- eval(Y, X).
eval(Y, A*B):- eval(ValA, A), eval(ValB, B), eval(Y, ValA * ValB).
The reason why f(X,120) doesn't work is simple >/2 works only when its arguments is bound (i.e. you can't compare something not yet defined like X with anything else). To fix that you have to split that rule into:
f(A,B) :- nonvar(A), A > 0, C is A-1, f(C, D), B is A*D.
f(A,B) :- nonvar(B), f_rev(A, B, 1, 1).
% f_rev/4 - only first argument is unbound.
f_rev(A, B, A, B). % solution
f_rev(A, B, N, C):- C < B, NextN is (N+1), NextC is (C*NextN), f_rev(A, B, NextN, NextC).
Update: (fixed f_rev/4)
You may be interested in finite-domain solver. There was a question about using such things. By using #>/2 and #=/2 you can describe some formula and restrictions and then resolve them. But these predicates uses special abilities of some prolog systems which allows to associate name with some attributes which may help to narrow set of possible values by intersection of restriction. Some other systems (usually the same) allows you to reorder sequence of processing goals ("suspend").
Also member(X,[1,2,3,4,5,6,7]), f(X, 120) is probably doing the same thing what your "other queries" do.
If you are interested in logical languages in general you may also look at Curry language (there all non-pure functions is "suspended" until not-yed-defined value is unified).
In this answer we use clpfd, just like this previous answer did.
:- use_module(library(clpfd)).
For easy head-to-head comparison (later on), we call the predicate presented here n_fac/2:
n_fac(N_expr,F_expr) :-
N #= N_expr, % eval arith expr
F #= F_expr, % eval arith expr
n_facAux(N,F).
Like in this previous answer, n_fac/2 admits the use of arithmetic expressions.
n_facAux(0,1). % 0! = 1
n_facAux(1,1). % 1! = 1
n_facAux(2,2). % 2! = 2
n_facAux(N,F) :-
N #> 2,
F #> N, % redundant constraint
% to help `n_fac(N,N)` terminate
n0_n_fac0_fac(3,N,6,F). % general case starts with "3! = 6"
The helper predicate n_facAux/2 delegates any "real" work to n0_n_fac0_fac/4:
n0_n_fac0_fac(N ,N,F ,F).
n0_n_fac0_fac(N0,N,F0,F) :-
N0 #< N,
N1 #= N0+1, % count "up", not "down"
F1 #= F0*N1, % calc `1*2*...*N`, not `N*(N-1)*...*2*1`
F1 #=< F, % enforce redundant constraint
n0_n_fac0_fac(N1,N,F1,F).
Let's compare n_fac/2 and n_factorial/2!
?- n_factorial(47,F).
F = 258623241511168180642964355153611979969197632389120000000000
; false.
?- n_fac(47,F).
F = 258623241511168180642964355153611979969197632389120000000000
; false.
?- n_factorial(N,1).
N = 0
; N = 1
; false.
?- n_fac(N,1).
N = 0
; N = 1
; false.
?- member(F,[3,1_000_000]), ( n_factorial(N,F) ; n_fac(N,F) ).
false. % both predicates agree
OK! Identical, so far... Why not do a little brute-force testing?
?- time((F1 #\= F2,n_factorial(N,F1),n_fac(N,F2))).
% 57,739,784 inferences, 6.415 CPU in 7.112 seconds (90% CPU, 9001245 Lips)
% Execution Aborted
?- time((F1 #\= F2,n_fac(N,F2),n_factorial(N,F1))).
% 52,815,182 inferences, 5.942 CPU in 6.631 seconds (90% CPU, 8888423 Lips)
% Execution Aborted
?- time((N1 #> 1,N2 #> 1,N1 #\= N2,n_fac(N1,F),n_factorial(N2,F))).
% 99,463,654 inferences, 15.767 CPU in 16.575 seconds (95% CPU, 6308401 Lips)
% Execution Aborted
?- time((N1 #> 1,N2 #> 1,N1 #\= N2,n_factorial(N2,F),n_fac(N1,F))).
% 187,621,733 inferences, 17.192 CPU in 18.232 seconds (94% CPU, 10913552 Lips)
% Execution Aborted
No differences for the first few hundred values of N in 2..sup... Good!
Moving on: How about the following (suggested in a comment to this answer)?
?- n_factorial(N,N), false.
false.
?- n_fac(N,N), false.
false.
Doing fine! Identical termination behaviour... More?
?- N #< 5, n_factorial(N,_), false.
false.
?- N #< 5, n_fac(N,_), false.
false.
?- F in 10..100, n_factorial(_,F), false.
false.
?- F in 10..100, n_fac(_,F), false.
false.
Alright! Still identical termination properties! Let's dig a little deeper! How about the following?
?- F in inf..10, n_factorial(_,F), false.
... % Execution Aborted % does not terminate universally
?- F in inf..10, n_fac(_,F), false.
false. % terminates universally
D'oh! The first query does not terminate, the second does.
What a speedup! :)
Let's do some empirical runtime measurements!
?- member(Exp,[6,7,8,9]), F #= 10^Exp, time(n_factorial(N,F)) ; true.
% 328,700 inferences, 0.043 CPU in 0.043 seconds (100% CPU, 7660054 Lips)
% 1,027,296 inferences, 0.153 CPU in 0.153 seconds (100% CPU, 6735634 Lips)
% 5,759,864 inferences, 1.967 CPU in 1.967 seconds (100% CPU, 2927658 Lips)
% 22,795,694 inferences, 23.911 CPU in 23.908 seconds (100% CPU, 953351 Lips)
true.
?- member(Exp,[6,7,8,9]), F #= 10^Exp, time(n_fac(N,F)) ; true.
% 1,340 inferences, 0.000 CPU in 0.000 seconds ( 99% CPU, 3793262 Lips)
% 1,479 inferences, 0.000 CPU in 0.000 seconds (100% CPU, 6253673 Lips)
% 1,618 inferences, 0.000 CPU in 0.000 seconds (100% CPU, 5129994 Lips)
% 1,757 inferences, 0.000 CPU in 0.000 seconds (100% CPU, 5044792 Lips)
true.
Wow! Some more?
?- member(U,[10,100,1000]), time((N in 1..U,n_factorial(N,_),false)) ; true.
% 34,511 inferences, 0.004 CPU in 0.004 seconds (100% CPU, 9591041 Lips)
% 3,091,271 inferences, 0.322 CPU in 0.322 seconds (100% CPU, 9589264 Lips)
% 305,413,871 inferences, 90.732 CPU in 90.721 seconds (100% CPU, 3366116 Lips)
true.
?- member(U,[10,100,1000]), time((N in 1..U,n_fac(N,_),false)) ; true.
% 3,729 inferences, 0.001 CPU in 0.001 seconds (100% CPU, 2973653 Lips)
% 36,369 inferences, 0.004 CPU in 0.004 seconds (100% CPU, 10309784 Lips)
% 362,471 inferences, 0.036 CPU in 0.036 seconds (100% CPU, 9979610 Lips)
true.
The bottom line?
The code presented in this answer is as low-level as you should go: Forget is/2!
Redundant constraints can and do pay off.
The order of arithmetic operations (counting "up" vs "down") can make quite a difference, too.
If you want to calculate the factorial of some "large" N, consider using a different approach.
Use clpfd!
There are some things which you must remember when looking at Prolog:
There is no implicit return value when you call a predicate. If you want to get a value out of a call you need to add extra arguments which can be used to "return" values, the second argument in your f/2 predicate. While being more verbose it does have the benefit of being easy to return many values.
This means that automatically "evaluating" arguments in a call is really quite meaningless as there is no value to return and it is not done. So there are no nested calls, in this respect Prolog is flat. So when you call f(A-1, D) the first argument to f/2 is the structure A-1, or really -(A, 1) as - is an infix operator. So if you want to get the value from a call to foo into a call to bar you have to explicitly use a variable to do it like:
foo(..., X), bar(X, ...),
So you need a special predicate which forces arithmetic evaluation, is/2. It's second argument is a structure representing an arithmetic expression which it interprets, evaluates and unifies the result with its first argument, which can be either a variable or numerical value.
While in principle you can run things backwards with most things you can't. Usually it is only simple predicates working on structures for which it is possible, though there are some very useful cases where it is possible. is/2 doesn't work backwards, it would be exceptional if it did.
This is why you need the extra variables C and D and can't replace C is A-1, f(C, D) by f(A-1,D).
(Yes I know you don't make calls in Prolog, but evaluate goals, but we were starting from a functional viewpoint here)

Resources