Digital root sums of factorisations in prolog - prolog

The problem is about adding the multiples of the possible factorizations in the number that is input by the user.
I tried this code.
sum_factors(N,Fs) :-
integer(N) ,
N > 0 ,
setof(F , factor(N,F) , Fs ).
factor(N,F) :-
L is floor(sqrt(N)),
between(1,L,X),
( F = X ; F is N // X),
write(F), write('x'), write(X), write('='),
write(N), nl.
output of my code if i input 24:
1x1=24
24x1=24
2x2=24
12x2=24
3x3=24
8x3=24
4x4=24
6x4=24
Fs = [1, 2, 3, 4, 6, 8, 12, 24].
the correct output if i input 24 should be:
24 = 2x2x2x3
24 = 2x3x4
24 = 2x2x6
24 = 4x6
24 = 3x8
24 = 2x12
24 = 24
Can somebody explain this code line by line for me, and if possible, tell what's i'm missing from the code.

Try this solution, I think now is complete.
% The first ten prime numbers
% You may want include more, use this URL http://primes.utm.edu/lists/small/1000.txt
prime_numbers([2,3,5,7,11,13,17,19,23,29]).
% Find the lower number in a list of numbers that divide a number N
% We asume that the list of numbers is sorted in ascendent order
lower_splitter(N, [H|_], H):- N mod H =:= 0, !.
lower_splitter(N, [_|T], H):- lower_splitter(N, T, H).
% Find factors
factors(1, []):- !.
factors(N, [R|L]):- prime_numbers(P), lower_splitter(N, P, R), N1 is N div R, factors(N1, L).
% Verify is a list contains a subset
sub_set([], []).
sub_set([X|L1], [X|L2]):- sub_set(L1, L2).
sub_set([_|L1], L2):- sub_set(L1, L2).
% Find all subset in the list X.
combinations(X, R):- setof(L, X^sub_set(X, L), R).
% Auxilary predicates
list([]).
list([_|_]).
lt(X,Y):-var(X);var(Y).
lt(X,Y):-nonvar(X),nonvar(Y),X<Y.
difference([],_,[]).
difference(S,[],S):-S\=[].
difference([X|TX],[X|TY],TZ):-
difference(TX,TY,TZ).
difference([X|TX],[Y|TY],[X|TZ]):-
lt(X,Y),
difference(TX,[Y|TY],TZ).
difference([X|TX],[Y|TY],TZ):-
lt(Y,X),
difference([X|TX],TY,TZ).
%Multiply members of a list
multiply([X], X):-!.
multiply([H|T], X):-multiply(T, M), X is M *H.
start(N):- factors(N, L),
setof(R, L^S^T^D^M^(sub_set(L, S),
length(S, T),
T>1,difference(L, S, D),
multiply(S,M),
append(D,[M], R)), F), writeall(N,[L|F]).
writeall(_,[]).
writeall(N,[H|T]):- write(N),write('='),writelist(H),nl, writeall(N,T).
writelist([X]):- write(X).
writelist([X,Y|T]):- write(X),write(x), writelist([Y|T]).
Consult using the start predicate, like this:
?- start(24).
24=2x2x2x3
24=2x2x6
24=2x3x4
24=2x12
24=3x8
24=24

Related

How to use an fd solver to determine which elements of a list can sum to a given number?

Given a list of possible summands I want to determine which, if any, can form a given sum. For example, with [1,2,3,4,5] I can make the sum of 9 with [4,5], [5,3,1], and [4,3,2].
I am using GNU Prolog and have something like the following which does not work
numbers([1,2,3,4,5]).
all_unique(_, []).
all_unique(L, [V|T]) :-
fd_exactly(1, L, V),
all_unique(L, T).
fd_sum([], Sum).
fd_sum([H|T], Sum):-
S = Sum + H,
fd_sum(T, S).
sum_clp(N, Summands):-
numbers(Numbers),
length(Numbers, F),
between(1, F, X),
length(S, X),
fd_domain(S, Numbers),
fd_domain(Y, [N]),
all_unique(S, Numbers),
fd_sum(S, Sum),
Sum #= Y,
fd_labeling(S).
I think the main problem is that I am not representing the constraint on the sum properly? Or maybe it is something else?
Just in case you're really interested in CLP(FD), here is your corrected program.
numbers([1,2,3,4,5]).
% note: use builtins where available, both for efficiency and correctness
%all_unique(_, []).
%all_unique(L, [V|T]) :-
% fd_exactly(1, L, V),
% all_unique(L, T).
fd_sum([], 0). % sum_fd_SO.pl:8: warning: singleton variables [Sum] for fd_sum/2
fd_sum([H|T], Sum):-
% note: use CLP(FD) operators and the correct operands
Sum #= S + H,
fd_sum(T, S).
sum_clp(N, S):- % sum_fd_SO.pl:13-23: warning: singleton variables [Summands] for sum_clp/2
numbers(Numbers),
length(Numbers, F),
between(1, F, X),
length(S, X),
fd_domain(S, Numbers),
%fd_domain(Y, [N]),
%all_unique(S, Numbers),
fd_all_different(S),
fd_sum(S, N),
%Sum #= Y,
fd_labeling(S).
test
?- sum_clp(3,L).
L = [3] ? ;
L = [1,2] ? ;
L = [2,1] ? ;
no
I think mixing the code for sublist into clp code is causing some confusion. GNU-Prolog has a sublist/2 predicate, you can use that.
You seem to be building the arithmetic expression with fd_sum but it is incorrectly implemented.
sum_exp([], 0).
sum_exp([X|Xs], X+Xse) :-
sum_exp(Xs, Xse).
sum_c(X, N, Xsub) :-
sublist(Xsub, X),
sum_exp(Xsub, Xe),
N #= Xe.
| ?- sum_exp([A, B, C, D], X).
X = A+(B+(C+(D+0)))
yes
| ?- sum_c([1, 2, 3, 4, 5], 9, X).
X = [4,5] ? ;
X = [2,3,4] ? ;
X = [1,3,5] ? ;
(1 ms) no
| ?- length(X, 4), sum_c(X, 4, [A, B]), member(A, [1, 2, 3]).
A = 1
B = 3
X = [_,_,1,3] ? ;
A = 2
B = 2
X = [_,_,2,2] ? ;
A = 3
B = 1
X = [_,_,3,1] ?
yes

Prolog: decompose number into its digits

I am studying prolog and I am faced with a problem that I cannot deal with.
Given a number, I have to check if the sum of the factorial of each digit that composes it is equal to the number itself.
Example:
145
1! + 4! + 5! = 1 + 24 + 120
Now my problem is just how to decompose the number so that I can factorial and sum each digit.
EDIT1.
thank to #slago I understand how decompose the number, but now I have a problem to sum the factorial terms:
fact(N):-
fact(N, N, _ListNumber).
fact(N, 0, ListNumber):-
factorial(ListNumber, 1, Sum),
Sum == N.
fact(N, Number, [D|R]):-
D is Number mod 10,
Number1 is Number div 10,
fact(N, Number1, R).
factorial([], Counter, Counter).
factorial([D|R], Counter, Sum):-
print([D|R]),
checksum(D, Counter),
factorial(R, Counter, Sum).
checksum(D, Counter):-
Counter1 is Counter * D,
M is D - 1,
M >= 2, !,
checksum(M, Counter1).
I have tried like this, but I noticed [D|R] results empty, and I don't understand why.
Your code is organized in a very confusing way. It is best to code independent predicates (for more specific purposes) and, after that, use them together to get the answer you want.
Start by creating a predicate to decompose a natural number into digits.
decompose(N, [N]) :- N<10, !.
decompose(N, [D|R]) :- N>=10, D is N mod 10, M is N//10, decompose(M, R).
Example of decomposition:
?- decompose(145, D).
D = [5, 4, 1].
Then, create a predicate to compute the factorial of a natural number.
fact(N, F) :- fact(N, 1, F).
fact(0, A, A) :- !.
fact(N, A, F) :- N>0, M is N-1, B is N*A, fact(M, B, F).
Example of factorial:
?- fact(5, F).
F = 120.
After that, create a predicate to map each number of a list into its corresponding factorial (alternatively, you could use the predefined predicate maplist/3).
map_fact([], []).
map_fact([X|Xs], [Y|Ys]) :- fact(X,Y), map_fact(Xs, Ys).
Example of mapping:
?- decompose(145, D), map_fact(D, F).
D = [5, 4, 1],
F = [120, 24, 1].
You must also create a predicate to compute the sum of the items of a list (alternatively, you could use the predefined predicate sum_list/2).
sum(L, S) :- sum(L, 0, S).
sum([], A, A).
sum([X|Xs], A, S) :- B is A+X, sum(Xs, B, S).
Example of summation:
?- decompose(145, D), map_fact(D, F), sum(F, S).
D = [5, 4, 1],
F = [120, 24, 1],
S = 145.
Finally, create the predicate to check the desired number property.
check(N) :- decompose(N, D), map_fact(D, F), sum(F, N).
Example:
?- check(145).
true.
?- check(146).
false.

Add following numbers to difference list in Prolog

I created a program in Prolog which returns following powers of two starting from one:
twos(N, L) :- twosH(N, 1, L).
twosH(0, _, L) :- L = [], !.
twosH(N, I, [R|L]) :- R is 2*I, N1 is N-1, twosH(N1, R, L).
I would like it to use difference list instead of regular one. I know how to append an element to difference list:
appendD(A-B, B-C, A-C).
but I don't know how to incorporate it into my program.
If you use a DCG, then you are using a difference list:
powers_of_2(0, 1) --> [1].
powers_of_2(N, PT) --> [PT], { PT #= 2 * PT1, N #> 0, N #= N1 + 1 }, powers_of_2(N1, PT1).
powers_of_2(N, PT) :-
phrase(powers_of_2(N, _), PT).
| ?- powers_of_2(4, P).
P = [16,8,4,2,1] ? ;
no
| ?-
A listing of what the DCG looks like as standard predicates (obtained by entering listing. then I changed the variable names a little):
powers_of_2(0, 1, [1|T], T).
powers_of_2(N, PT, [PT|PTs], T) :-
PT #= 2 * PT1,
N #> 0,
N #= N1 + 1,
powers_of_2(N1, PT1, PTs, T).
If you called it directly, you would give it the empty list as the final tail:
| ?- powers_of_2(4, P, PT, []).
P = 16
PT = [16,8,4,2,1] ? ;
no
If you want the numbers in the reverse order, I'll leave that as an exercise. :)

How to populate a list in Prolog?

Say you have the following predicate:
random_int(X/Y):-
random(1,100,X),
random(1,100,Y),
X\=Y.
How can I populate a list of size n using the result of this predicate?
I tried the following code but it only populates the list if random_int(X) is true at the first attempt, i.e. it does not backtrack to try other combinations of X and Y.
findall(X,(between(1,N,_), random_int(X)),L).
I find this small 'application' of clpfd interesting:
?- N=10,M=12, repeat, findall(X, (between(1,N,_),random(1,M,X)), L), clpfd:all_different(L).
N = 10,
M = 12,
L = [5, 4, 6, 7, 9, 11, 2, 3, 8|...]
.
note: M must be > N
I guess a simple way to do it is to make a list of 1:100, and draw 100 times from it a sample of size 2, without replacement. Since this is Prolog and not R, you can instead do:
:- use_module(library(lists)).
:- use_module(library(random)).
random_pairs(Pairs) :-
findall(X/Y,
( between(1, 100, _),
randseq(2, 100, [X,Y])
), R).
This is available in SWI-Prolog at least, but it is free software and the source to randseq/3 is available on the web site.
And since it's better to not use findall unless strictly necessary, it would probable better to write:
random_pairs(Pairs) :-
length(Pairs, 100),
maplist(randseq(2, 100), Pairs).
or, if the X/Y is important,
random_pairs(Pairs) :-
length(Pairs, 100),
maplist(rand_couple(100), Pairs).
rand_couple(N, X/Y) :-
randseq(2, N, [X,Y]).
TL;DR Use the available libraries
You could do it with findall/3:
random_list(N, L) :-
findall(X, (between(1,N,_), random(50,100,X)), L).
Another tidy way to do this would be:
random_list(N, L) :-
length(L, N),
maplist(random(50, 100), L).
Which results in:
| ?- random_list(5, L).
L = [69,89,89,95,59]
yes
| ?-
In general, if you have a predicate, p(X1,X2,...,Xn,Y), and a list you want to fill with result Y using successive calls to p/(n+1), you can use length(List, Length) to set the length of your list, and then maplist(p(X1,...,Xn), List) to populate the list. Or, using the findall/3, you can do findall(X, (between(1,N,_), p(X1,...,Xn,X)), L)..
EDIT based upon the updated conditions of the question that the generated list be unique values...
The random predicates are not generators, so they don't create new random numbers on backtracking (either unique or otherwise). So this solution, likewise, will generate one list which meets the requirements, and then just succeed without generating more such lists on backtracking:
% Generate a random number X between A and B which is not in L
rand_not_in(A, B, L, X) :-
random(A, B, X1),
( memberchk(X1, L)
-> rand_not_in(A, B, L, X)
; X = X1
).
% Generate a list L of length N consisting of unique random numbers
% between A and B
random_list(N, L) :-
random_list(N, 50, 100, [], L).
random_list(N, A, B, Acc, L) :-
N > 0,
rand_not_in(A, B, A, X),
N1 is N - 1,
random_list(N1, A, B, [X|A], L).
random_list(0, _, _, L, L).
Yet another approach, in SWI Prolog, you can use randseq, which will give a random sequence in a range 1 to N. Just scale it:
random_list(N, A, B, L) :-
A < B,
Count is B - A + 1,
randseq(N, Count, L1),
Offset is A - 1,
maplist(offset(Offset), L1, L).
offset(X, Offset, Y) :-
Y is X + Offset.
?- random_list(5, 50, 100, L).
L = [54, 91, 90, 78, 75].
?-
random_len([],0).
random_len([Q|T],N) :-
random(1,100,Q),
random_len(T,X),
N is X+1.

Prolog Find N prime numbers

I have a problem with the recursive function of Prolog. I believe I am not implementing it right and need help.
I need to generate the first N prime numbers and return it in a list. Generating the prime number is not an issue, but rather, generating it in a list is the issue I have.
This is the part of the relevant code:
genList(_, 0, _).
genList(X, N, PrimeList, PrimeList):-
N > 0,
isprime(X),
X1 is X +1,
N1 is N -1,
genList(X1,N1,[X|PrimeList], [X|PrimeList]),!.
genList(X, N, PrimeList, PrimeList):-
N>0,
\+isprime(X),
X1 is X + 1,
genList(X1,N,PrimeList, PrimeList).
This is what I type into the Prolog interpreter:
genList(1,N, [],L).
For the 1st line, how do I make the base case such that when N=0, I stop recursing? Is this correct?
As for the next 2 clauses, I am having difficulty in thinking in terms of logic programming. I definitely feel that this is not logic programming style.
I want to say that when isPrime(X) fails, we continue to the next number without saving anything, but when isPrime(X) is true, then we recurse and continue to the next number, saving X.
How do I do that in Prolog?
First of all, you shouldn't need 4 arguments to your main predicate if you only want two. Here you want the list of the first primes up to N. So an argument for N and an argument for the list should be enough:
primeList(N, L) :-
% eventually in the body a call to a worker predicate with more arguments
Now here, your logic is explained in those terms:
primeList(N, [N|L]) :-
% If we're not at the base case yet
N > 0,
% If N is a prime
isPrime(N),
NewN is N - 1,
% Let's recurse and unifie N as the head of our result list in the head
% of the predicate
primeList(NewN, L).
primeList(N, L) :-
% Same as above but no further unification in the head this time.
N > 0,
% Because N isn't a prime
\+ isPrime(N),
NewN is N - 1,
primeList(NewN, L).
To that you'd have to add the base case
primeList(0, []).
You could rewrite that with cuts as follows:
primeList(0, []) :- !.
primeList(N, [N|L]) :-
isPrime(N),
!,
NewN is N - 1,
primeList(NewN, L).
primeList(N, L) :-
NewN is N - 1,
primeList(NewN, L).
Here's what you meant to write:
genList(N, L) :- genList(2, N, L, []).
genList(X, N, L, Z):- % L-Z is the result: primes list of length N
N > 0 ->
( isprime(X) -> L=[X|T], N1 is N-1 ; L=T, N1 is N ),
X1 is X + 1,
genList(X1,N1,T,Z)
;
L = Z.
The if-then-else construct embodies the cuts. And you're right, it's essentially a functional programming style.
We can introduce a little twist to it, disallowing requests for 0 primes (there's no point to it anyway), so that we also get back the last generated prime:
genList(1, [2], 2) :- !.
genList(N, [2|L], PN) :- N>1, L=[3|_], N2 is N-2, gen_list(N2, L, [PN]).
gen_list(N, L, Z) :- L=[P|_], X is P+2, gen_list(X, N, L, Z).
gen_list(X, N, L, Z) :- % get N more odd primes into L's tail
N > 0 ->
( isprime(X) -> L=[_|T], T=[X|_], N1 is N-1 ; L=T, N1 is N ),
X1 is X + 2,
gen_list(X1,N1,T,Z)
;
L = Z. % primes list's last node
Run it:
?- genList(8,L,P).
L = [2, 3, 5, 7, 11, 13, 17, 19]
P = 19
This also enables us to stop and continue the primes generation from the point where we stopped, instead of starting over from the beginning:
?- L = [3|_], gen_list(8, L, Z), Z=[P10|_], writeln([2|L]),
gen_list(10, Z, Z2), Z2=[P20], writeln(Z).
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29|_G1037]
[29,31,37,41,43,47,53,59,61,67,71]
P10 = 29
P20 = 71

Resources