Finding prime factors in Prolog - prolog

prime_factors(N, [_:_]) :- prime_factors(N, [_:_], 2).
prime_factors(N, [_:_], D) :- N mod D == 0, N1 is N div D,
prime_factors(N1, [_:D], D).
prime_factors(N, [_:_], D) :- N mod D =\= 0, D1 is D+1, prime_factors(N, [_:_], D1).
This is my proposed solution to find the prime factors of an input N.
When I try to run it I am getting an error about such a predicate/2 not existing - is my syntax somehow wrong with the extended predicate/3?

Using a second parameter that only seems to unify in the second case, does not seem to make much sense. Furthermore this is not the way you construct a list in Prolog anyway, since:
the "cons" has syntax [H|T], so then it should be [_|_];
by using underscores the predicates are not interested in the values, you each time pass other parameters; and
in Prolog one typically does not construct lists with answers, typically backtracking is used. One can use findall/3 to later construct a list. This is usually better since that means that we can also query like prime_factor(1425, 3) to check if 3 is a prime factor of 1425.
We can thus construct a predicate that looks like:
prime_factor(N, D) :-
find_prime_factor(N, 2, D).
find_prime_factor(N, D, D) :-
0 is N mod D.
find_prime_factor(N, D, R) :-
D < N,
(0 is N mod D
-> (N1 is N/D, find_prime_factor(N1, D, R))
; (D1 is D + 1, find_prime_factor(N, D1, R))
).
For example:
?- prime_factor(1425, R).
R = 3 ;
R = 5 ;
R = 5 ;
R = 19 ;
false.
?- prime_factor(1724, R).
R = 2 ;
R = 2 ;
R = 431 ;
false.
If we want a list of all prime factors, we can use findall/3 for that:
prime_factors(N, L) :-
findall(D, prime_factor(N, D), L).
For example:
?- prime_factors(1425, R).
R = [3, 5, 5, 19].
?- prime_factors(1724, R).
R = [2, 2, 431].
?- prime_factors(14, R).
R = [2, 7].
?- prime_factors(13, R).
R = [13].

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.

Creating a List in prolog recursively

i would like to create a list in prolog where in each recursive step i add an element to the list.My code:
solve(N,List):-
N>5,
solve(N-1,[a|List]),
N<5,
solve(N-1,[b|List]),
N is 0.
This supposedly runs recursions adding a or b to the List depending on N.However this [a|List] does not add an element in each recursion.What is the correct way to do this?
You basically need to write three clauses. First, the clause for N = 0.
solve(0, []).
When N is less than (or equal to) 5, you want to add b to the list. You also need to check that N is not negative, otherwise your program will recurse at infinity. You also need to calculate N - 1 with the is predicate.
solve(N, [b | L]) :-
N >= 0,
N =< 5,
M is N - 1,
solve(M, L).
The third clause is for the case where N is greater than 5, where a is added to the list.
solve(N, [a | L]) :-
N > 5,
M is N - 1,
solve(M, L).
Querying for solve(2, L) and solve(7, L) yields respectively:
L = [b, b] % N = 2
L = [a, a, b, b, b, b, b] % N = 7
I assume you are trying to do this:
solve(0, []).
solve(N, [a|List]):-
N > 5,
solve(N-1,List).
solve(N, [b|List]):-
N =< 5,
solve(N-1,List).

Tail-recursive program in prolog which outputs odd numbers in a list

I've written a tail-recursive predicate in Prolog which outputs the integers between A and B in a list K. I've used "reverse" to bring the numbers into the right order:
numbers(A,B,K) :- numbers(A,B,[],K).
numbers(Y,Y,X,K) :- !, reverse([Y|X],K).
numbers(A,B,X,K) :- A<B, C is A+1, numbers(C,B,[A|X],K).
Query:
?- numbers(3,6, K).
K=[3,4,5,6]
All works fine. What I now want to do is that I only want to have odd numbers of the range between A and B in the list K. How can I do that? Thanks in advance!
Firstly, I would try to avoid using reverse/2. If you have such a solution, it's often an indicator that there's a better way to get the answer forwards more directly. Not always, but most often. reverse/2 is probably the 2nd favorite band-aid in Prolog right behind use of the cut. :)
In many problems, an auxiliary accumulator is needed. In this particular case, it is not. Also, I would tend to use CLP(FD) operations when involving integers since it's the more relational approach to reasoning over integers. But you can use the solution below with is/2, etc, if you wish. It just won't be as general.
numbers(S, E, []) :- S #> E. % null case
numbers(X, X, [X]).
numbers(S, E, [S|T]) :-
S #< E,
S1 #= S + 1,
numbers(S1, E, T).
| ?- numbers(3, 8, L).
L = [3,4,5,6,7,8] ? ;
no
| ?- numbers(A, B, [2,3,4,5]).
A = 2
B = 5 ? ;
no
| ?-
This solution avoids reverse/2 and is tail recursive.
To update it for odd integers, the first thought is that we can easily modify the above to do every other number by just adding 2 instead of 1:
every_other_number(S, E, []) :- S #> E.
every_other_number(X, X, [X]).
every_other_number(S, E, [S|T]) :-
S #< E,
S1 #= S + 2,
every_other_number(S1, E, T).
| ?- every_other_number(3, 7, L).
L = [3,5,7] ? ;
no
| ?- every_other_number(3, 8, L).
L = [3,5,7] ? ;
no
| ?- every_other_number(4, 8, L).
L = [4,6,8] ? ;
no
| ?-
Then we can do odd numbers by creating an initial predicate to ensure the condition that the first value is odd and calling every_other_number/3:
odd_numbers(S, E, L) :-
S rem 2 #= 1,
every_other_number(S, E, L).
odd_numbers(S, E, L) :-
S rem 2 #= 0,
S1 #= S + 1,
every_other_number(S1, E, L).
| ?- odd_numbers(2, 8, L).
L = [3,5,7] ? ;
no
| ?- odd_numbers(2, 9, L).
L = [3,5,7,9] ? ;
no
| ?- odd_numbers(3, 8, L).
L = [3,5,7] ? ;
no
| ?-
This could be a solution, using mod/2 operator.
numbers(A,B,K) :-
B1 is B+1,
numbers(A,B1,[],K).
numbers(Y,Y1,X,K) :-
Y = Y1,
reverse(X,K).
numbers(A,B,X,K) :-
A<B,
C is A+1,
C1 is mod(C,2),
(C1 = 0 ->
numbers(C,B,[A|X],K)
; numbers(C,B,X,K)).
Another possibility is to use DCG :
numbers(A,B,K) :-
phrase(odd(A,B), K).
odd(A,B) --> {A > B, !}, [].
odd(A,B) --> {A mod2 =:= 0, !, C is A+1}, odd(C,B).
odd(A,B) --> {C is A+2}, [A], odd(C, B).

How to sum up multiple lists in Prolog?

I am working on a prolog program, but I have no idea to finish the program. Here is the requirement.
The program allows multiple fact, however, the length of list in each fact must equals
Example 1
%fact
f(first, [1, 6, 10]).
f(second, [7, 3, 8]).
f(third, [5, 9, 5]).
Example 2
%fact
f(first, [1,6,10]).
f(second, [7,3,8]).
f(third, [5,9,5]).
f(fourth, [7,3,9]).
f(fifth, [7,7,2]).
Example 3
%fact
f(first, [1,6,10,54,11,6]).
f(second, [7,3,8,34,2,7]).
Now, I need to write a predicate sum_list(), so that users can do the following things.
Example 1
?-sum_list([first,second,third], Even, Result).
Even = 1
Result = [13,18,23]
Example 2
?-sum_list([first,second,third,fourth,fifth], Even, Result).
Even = 2
Result = [27,28,34]
Example 3
?-sum_list([first,second], Even, Result).
Even = 3
Result = [8,9,18,88,13,13]
Result is a list which contains the sum of each element in the corresponding fact lists.
Even is counting the number of even number in the Result, in Example 2, only 28 and 34 are even, so Even = 2.
Thanks.
Thanks for SimoV8's hints, and I get some ideas to solve in the way:
%fact
f(first, [1, 6, 10]).
f(second, [7, 3, 8]).
sum_list([Head|Tail], E, R) :-
f(Head, P),
sw(P, Tail, [R]),
even(E,R).
sw(H1, [Head|Tail], [X|R]) :-
f(Head,S),
sum(H1, S, X),
sw(X, Tail, R).
sw(_, [], []).
sum([H1|T1],[H2|T2],[X|L3]) :-
sum(T1,T2,L3), X is H1+H2.
sum([],[],[]).
even(E, [X|R]) :-
even(E2, R),
((X mod 2) =:= 1 -> E is E2; E is E2 + 1).
even(0, []).
However, the answer only accepts two f(), if more than two f(), it will return FALSE
Try this:
sum_list([], 0, []).
sum_list([H|T], E, [RH|RT]):- f(H, X),
sum(X, RH),
sum_list(T, E2, RT),
((RH mod 2) =:= 1 -> E is E2; E is E2 + 1).
sum([], 0).
sum([H|T], S1):- sum(T, S2), S1 is H + S2.

Resources