Prolog: append number to a term - prolog

Is it possible to append a number to a term directly?
I.e., I can easily do something like this:
?- A = 1 + 2, B = 3, C = A + B.
C = 1+2+3
But is there a way (operator?) to specify something instead of '+' in the C = A + B to get "C = 1+23"?
I feel I'm asking for something strange, so here is the context. I have a list of digits, and I want to generate all expressions that can be obtained by putting '+', '-' or nothing between the digits.
Pluses and minuses are easy part:
possible([X], X) :- !.
possible([A, B | Rest], E) :-
( H = A + B ; H = A - B ),
possible([H | Rest], E).
?- possible([1, 2, 3], E).
E = 1+2+3 ?;
E = 1+2-3 ?;
E = 1-2+3 ?;
E = 1-2-3
yes
But I also want to get "E = 12+3", "E = 1+23" and "E = 123". Is there an easy way to do it?
Update: the solution should be portable or at least work in B-Prolog.

here is my bet
possible([N|Ns], D) :-
digits_number([N|Ns], D).
possible([N|Ns], X) :-
append([L|Ls], [R|Rs], [N|Ns]),
possible([L|Ls], Lx),
digits_number([R|Rs], Rx),
(Op = + ; Op = -), X =.. [Op, Lx, Rx].
digits_number(Digits, N) :-
maplist(digit_code, Digits, Codes),
number_codes(N, Codes).
digit_code(D, C) :-
C is D + 0'0.
The purpose of the verbose [N|Ns], etc is to avoid matching empty lists.
edit Here is a variation, that doesn't require maplist/3 and number_codes/2. The code it's quite similar in size...
possible(Ns, D) :-
digits_number(Ns, _, D).
possible([N|Ns], X) :-
append([L|Ls], [R|Rs], [N|Ns]),
possible([L|Ls], Lx),
digits_number([R|Rs], _, Rx),
(Op = + ; Op = -), X =.. [Op, Lx,Rx].
digits_number([Digit], 1, Digit).
digits_number([D|Ds], F, N) :-
digits_number(Ds, G, T),
F is G * 10,
N is T + D * F.
It's more efficient tough (at least on inference count), indeed here is a performance test
?- L=[1,2,3,4,5,6,7,8], time(findall(X,possible_1(L,X),L1)), time(findall(X,possible_2(L,X),L2)).
% 31,591 inferences, 0.017 CPU in 0.017 seconds (100% CPU, 1851600 Lips)
% 20,656 inferences, 0.017 CPU in 0.018 seconds (98% CPU, 1192235 Lips)
L = [1, 2, 3, 4, 5, 6, 7, 8],
L1 = L2, L2 = [12345678, 1+2345678, 1-2345678, 12+345678, 12-345678, 1+2+345678, 1+2-345678, ... - ... + 345678, ... - ...|...].
Of course, I've renamed the two versions possible_1, possible_2

How about this simple and fully portable solution:
possible([Digit], Digit).
possible([Digit| Digits], Digit + RightExpression) :-
possible(Digits, RightExpression).
possible([Digit| Digits], Digit - RightExpression) :-
possible(Digits, RightExpression).
possible([Digit1, Digit2| Digits], Expression) :-
Number0 is Digit1 * 10,
Number is Number0 + Digit2,
possible([Number| Digits], Expression).
Using B-Prolog for testing:
$ bp
B-Prolog Version 8.1, All rights reserved, (C) Afany Software 1994-2014.
| ?- [possible].
consulting::possible.pl
yes
| ?- possible([1,2,3], Exp).
Exp = 1+(2+3) ?;
Exp = 1+(2-3) ?;
Exp = 1+23 ?;
Exp = 1-(2+3) ?;
Exp = 1-(2-3) ?;
Exp = 1-23 ?;
Exp = 12+3 ?;
Exp = 12-3 ?;
Exp = 123 ?;
no
Regarding performance, using the same benchmark as in Carlo's answer, I get:
?- L=[1,2,3,4,5,6,7,8], time(findall(X,possible(L,X),L1)).
% 12,037 inferences, 0.003 CPU in 0.003 seconds (93% CPU, 4223509 Lips)
L = [1, 2, 3, 4, 5, 6, 7, 8],
L1 = [1+ (2+ (3+ (4+ (5+ (6+ (7+8)))))), 1+ (2+ (3+ (4+ (5+ (6+ (7-8)))))), 1+ (2+ (3+ (4+ (5+ (6+78))))), 1+ (2+ (3+ (4+ (5+ (... - ...))))), 1+ (2+ (3+ (4+ (... + ...)))), 1+ (2+ (3+ (... + ...))), 1+ (2+ (... + ...)), 1+ (... + ...), ... + ...|...].

This solution works without string-to-term conversions. It still depends on the SWI-Prolog predicate atom_number/2 (not sure how widely available this is). If ISO compliance is necessary, I believe it should suffice to write a custom atom_number/2 predicate using atom_codes/2 and number_codes/2. digit_appended_to_expression/3 is actually too general, since it will work with any predicate that takes a number as its second argument.
digit_appended_to_expression(Expression, C, ExpressionWithC) :-
Expression =.. [Operator, A, B],
digit_concat(B, C, BC),
ExpressionWithC =.. [Operator, A, BC].
digit_concat(A, B, AB) :-
number(A),
number(B),
atom_number(A_Atom, A),
atom_number(B_Atom, B),
atom_concat(A_Atom, B_Atom, AB_Atom),
atom_number(AB_Atom, AB).
possible([X], X) :- !.
possible([A, B | Rest], E) :-
( digit_concat(A, B, H)
; H = A + B
; H = A - B
; digit_appended_to_expression(A, B, H)
),
possible([H | Rest], E).
This still doesn't give an operator, because it needs a 3-place predicate, but one could use term expansion to achieve macro if it were really important.
Is it sufficient?

Here is a possible (pun intended) solution using accumulators:
%numberexp( D, N, XN) :- number_chars( D, DL), DL=[ DC| _], number_chars( N, NL), number_chars( XN, [ DC| NL]).
numberexp( D, N, XN) :- XN is integer( exp( log( 10)*(1+integer( log( 10, N))))*D+N).
poss( [ H], H, Z, Z).
poss( [ H| T], H, Z, E) :- poss( T, F, F, XT), E= Z+XT.
poss( [ H| T], H, Z, E) :- poss( T, F, F, XT), E= Z-XT.
poss( [ H| T], A, Z, E) :- poss( T, F, Z, E), numberexp( H, F, A).
possible( L, E) :- poss( L, F, F, E).
The number expansion part is admittedly ugly either ways, but at least it can be portably ugly.
The output is:
| ?- possible([1,2,3],E).
E = 1+(2+3) ?;
E = 1+(2-3) ?;
E = 1+23 ?;
E = 1-(2+3) ?;
E = 1-(2-3) ?;
E = 1-23 ?;
E = 12+3 ?;
E = 12-3 ?;
E = 123 ?;
no

I initially misunderstood your question and just approached it as a list processing exercise using DCGs. I only realized that you were trying to generate Prolog terms after I'd finished with the DCG. But I was able to get a workable solution by converting the list to a string and then the string to a term using SWI-Prolog's string handling predicates. I'd be interested to know of a more straightforward way of accomplishing this.
possible(Digits, AsTerm) :-
phrase(sequence(Digits), Sequence),
atomics_to_string(Sequence, AsString),
term_string(AsTerm, AsString).
sequence(Ds) -->
digits(Ds).
sequence(Ds) --> {append(First, Last, Ds)},
digits(First), sign, sequence(Last).
digits([D]) -->
digit(D).
digits([D|Ds]) -->
digit(D), digits(Ds).
digit(D) --> {integer(D)},
[D].
sign --> [+].
sign --> [-].
This version of possible/2 will generate evaluable prolog terms:
?- possible([1,2,3],X), Y is X.
X = Y, Y = 123 ;
X = 1+23,
Y = 24 ;
X = 1+2+3,
Y = 6 ;
X = 1+2-3,
Y = 0 ;
...

Related

Finding prime factors in 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].

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).

Prolog, split list into two lists

I got a problem with lists. What I need to do is to split one list [1,-2,3,-4], into two lists [1,3] and [-2,-4]. My code looks like the following:
lists([],_,_).
lists([X|Xs],Y,Z):- lists(Xs,Y,Z), X>0 -> append([X],Y,Y) ; append([X],Z,Z).
and I'm getting
Y = [1|Y],
Z = [-2|Z].
What am I doing wrong?
If your Prolog system offers clpfd you could preserve logical-purity. Want to know how? Read on!
We take the second definition of lists/3 that #CapelliC wrote in
his answer as a starting point, and replace partition/4 by tpartition/4 and (<)/2 by (#<)/3:
lists(A,B,C) :- tpartition(#<(0),A,B,C).
Let's run a sample query!
?- As = [0,1,2,-2,3,4,-4,5,6,7,0], lists(As,Bs,Cs).
As = [0,1,2,-2,3,4,-4,5,6,7,0],
Bs = [ 1,2, 3,4, 5,6,7 ],
Cs = [0, -2, -4, 0].
As we use monotone code, we get logically sound answers for more general queries:
?- As = [X,Y], lists(As,Bs,Cs).
As = [X,Y], Bs = [X,Y], Cs = [ ], X in 1..sup, Y in 1..sup ;
As = [X,Y], Bs = [X ], Cs = [ Y], X in 1..sup, Y in inf..0 ;
As = [X,Y], Bs = [ Y], Cs = [X ], X in inf..0 , Y in 1..sup ;
As = [X,Y], Bs = [ ], Cs = [X,Y], X in inf..0 , Y in inf..0 .
Here you have. It splits a list, and does not matter if have odd or even items number.
div(L, A, B) :-
append(A, B, L),
length(A, N),
length(B, N).
div(L, A, B) :-
append(A, B, L),
length(A, N),
N1 is N + 1,
length(B, N1).
div(L, A, B) :-
append(A, B, L),
length(A, N),
N1 is N - 1,
length(B, N1).
Refer this:
domains
list=integer*
predicates
split(list,list,list)
clauses
split([],[],[]).
split([X|L],[X|L1],L2):-
X>= 0,
!,
split(L,L1,L2).
split([X|L],L1,[X|L2]):-
split(L,L1,L2).
Output :
Goal: split([1,2,-3,4,-5,2],X,Y)
Solution: X=[1,2,4,2], Y=[-3,-5]
See, if that helps.
Just for variety, this can also be done with a DCG, which is easy to read for a problem like this:
split([], []) --> [].
split([X|T], N) --> [X], { X >= 0 }, split(T, N).
split(P, [X|T]) --> [X], { X < 0 }, split(P, T).
split(L, A, B) :-
phrase(split(A, B), L).
As in:
| ?- split([1,2,-4,3,-5], A, B).
A = [1,2,3]
B = [-4,-5] ? ;
no
It also provides all the possible solutions in reverse:
| ?- split(L, [1,2,3], [-4,-5]).
L = [1,2,3,-4,-5] ? ;
L = [1,2,-4,3,-5] ? ;
L = [1,2,-4,-5,3] ? ;
L = [1,-4,2,3,-5] ? ;
L = [1,-4,2,-5,3] ? ;
L = [1,-4,-5,2,3] ? ;
L = [-4,1,2,3,-5] ? ;
L = [-4,1,2,-5,3] ? ;
L = [-4,1,-5,2,3] ? ;
L = [-4,-5,1,2,3] ? ;
(2 ms) no
Gaurav's solution will also do this if the cut is removed and an explicit X < 0 check placed in the third clause of the split/3 predicate.
There are several corrections to be done in your code.
If you enjoy compact (as readable) code, a possibility is
lists([],[],[]).
lists([X|Xs],Y,Z) :-
( X>0 -> (Y,Z)=([X|Ys],Zs) ; (Y,Z)=(Ys,[X|Zs]) ), lists(Xs,Ys,Zs).
But since (SWI)Prolog offers libraries to handle common list processing tasks, could be as easy as
lists(A,B,C) :- partition(<(0),A,B,C).

Inverse factorial in Prolog

Can someone helping me to find a way to get the inverse factorial in Prolog...
For example inverse_factorial(6,X) ===> X = 3.
I have been working on it a lot of time.
I currently have the factorial, but i have to make it reversible. Please help me.
Prolog's predicates are relations, so once you have defined factorial, you have implicitly defined the inverse too. However, regular arithmetics is moded in Prolog, that is, the entire expression in (is)/2 or (>)/2 has to be known at runtime, and if it is not, an error occurs. Constraints overcome this shortcoming:
:- use_module(library(clpfd)).
n_factorial(0, 1).
n_factorial(N, F) :-
N #> 0, N1 #= N - 1, F #= N * F1,
n_factorial(N1, F1).
This definition now works in both directions.
?- n_factorial(N,6).
N = 3
; false.
?- n_factorial(3,F).
F = 6
; false.
Since SICStus 4.3.4 and SWI 7.1.25 also the following terminates:
?- n_factorial(N,N).
N = 1
; N = 2
; false.
See the manual for more.
For reference, here is the best implementation of a declarative factorial predicate IĀ could come up with.
Two main points are different from #false's answer:
It uses an accumulator argument, and recursive calls increment the factor we multiply the factorial with, instead of a standard recursive implementation where the base case is 0. This makes the predicate much faster when the factorial is known and the initial number is not.
It uses if_/3 and (=)/3 extensively, from module reif, to get rid of unnecessary choice points when possible. It also uses (#>)/3 and the reified (===)/6 which is a variation of (=)/3 for cases where we have two couples that can be used for the if -> then part of if_.
factorial/2
factorial(N, F) :-
factorial(N, 0, 1, F).
factorial(N, I, N0, F) :-
F #> 0,
N #>= 0,
I #>= 0,
I #=< N,
N0 #> 0,
N0 #=< F,
if_(I #> 2,
( F #> N,
if_(===(N, I, N0, F, T1),
if_(T1 = true,
N0 = F,
N = I
),
( J #= I + 1,
N1 #= N0*J,
factorial(N, J, N1, F)
)
)
),
if_(N = I,
N0 = F,
( J #= I + 1,
N1 #= N0*J,
factorial(N, J, N1, F)
)
)
).
(#>)/3
#>(X, Y, T) :-
zcompare(C, X, Y),
greater_true(C, T).
greater_true(>, true).
greater_true(<, false).
greater_true(=, false).
(===)/6
===(X1, Y1, X2, Y2, T1, T) :-
( T1 == true -> =(X1, Y1, T)
; T1 == false -> =(X2, Y2, T)
; X1 == Y1 -> T1 = true, T = true
; X1 \= Y1 -> T1 = true, T = false
; X2 == Y2 -> T1 = false, T = true
; X2 \= Y2 -> T1 = false, T = false
; T1 = true, T = true, X1 = Y1
; T1 = true, T = false, dif(X1, Y1)
).
Some queries
?- factorial(N, N).
N = 1 ;
N = 2 ;
false. % One could probably get rid of the choice point at the cost of readability
?- factorial(N, 1).
N = 0 ;
N = 1 ;
false. % Same
?- factorial(10, N).
N = 3628800. % No choice point
?- time(factorial(N, 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000)).
% 79,283 inferences, 0.031 CPU in 0.027 seconds (116% CPU, 2541106 Lips)
N = 100. % No choice point
?- time(factorial(N, 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518284253697920827223758251185210916864000000000000000000000000)).
% 78,907 inferences, 0.031 CPU in 0.025 seconds (125% CPU, 2529054 Lips)
false.
?- F #> 10^100, factorial(N, F).
F = 11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000,
N = 70 ;
F = 850478588567862317521167644239926010288584608120796235886430763388588680378079017697280000000000000000,
N = 71 ;
F = 61234458376886086861524070385274672740778091784697328983823014963978384987221689274204160000000000000000,
N = 72 ;
...
a simple 'low tech' way: enumerate integers until
you find the sought factorial, then 'get back' the number
the factorial being built is greater than the target. Then you can fail...
Practically, you can just add 2 arguments to your existing factorial implementation, the target and the found inverse.
Just implement factorial(X, XFact) and then swap arguments
factorial(X, XFact) :- f(X, 1, 1, XFact).
f(N, N, F, F) :- !.
f(N, N0, F0, F) :- succ(N0, N1), F1 is F0 * N1, f(N, N1, F1, F).

creating lists, searching sth which has been given and making combination on prolog

I want to make a Prolog program.
Predicate will be like this:
name(name, failedCourse, age)
Database of the program is:
name(george, math, 20).
name(steve, phys, 21).
name(jane, chem, 22).
I want to implement the predicate nameList(A, B). A means list of names, B means number of names on the list. For example:
nameList([george, steve],2). returns true
nameList([george, steve],X). returns X=2
nameList(X,2). returns X=[george, steve]; X=[george, jane]; X=[steve, jane]
nameList([martin],1). returns false (because martin is not included database.)
I wanted to make a list that includes all names on the database. For that reason I made a findall.
descend(X,Y,A) :- name(X,Y,A).
descend(X,Y,A) :- name(X,Z,A),descend(Z,Y,A).
findall(director(X),descend(Y,X),Z).
?- findall(B,descend(B,X,Y),A). returns A = [george, steve, jane].
But I could not figure it out to use list A in predicates :( I cannot search the list for A in the nameList.
If you help me, I will be very grateful.
The main thing you need is a predicate that calculates combinations of a given length and of a given list:
comb(0, _, []).
comb(N, [X | T], [X | Comb]) :-
N > 0,
N1 is N - 1,
comb(N1, T, Comb).
comb(N, [_ | T], Comb) :-
N > 0,
comb(N, T, Comb).
Usage:
?- comb(2, [a, b, a], Comb).
Comb = [a, b] ;
Comb = [a, a] ;
Comb = [b, a] ;
false.
(See more here.)
Now you can just apply this predicate on your data:
name(george, math, 20).
name(steve, phys, 21).
name(jane, chem, 22).
name_list(L, N) :-
findall(X, name(X, _, _), Xs),
length(Xs, Len),
between(0, Len, N),
comb(N, Xs, L).
Usage examples:
?- name_list(L, N).
L = [],
N = 0 ;
L = [george],
N = 1 ;
L = [steve],
N = 1 ;
L = [jane],
N = 1 ;
L = [george, steve],
N = 2 ;
L = [george, jane],
N = 2 ;
L = [steve, jane],
N = 2 ;
L = [george, steve, jane],
N = 3 ;
false.
?- name_list([george, steve], N).
N = 2 ;
false.
?- name_list(L, 2).
L = [george, steve] ;
L = [george, jane] ;
L = [steve, jane] ;
false.
name(george, math, 20).
name(steve, phys, 21).
name(jane, chem, 22).
name_list(Name_List,N) :-
integer(N),
findall(Name,name(Name,_,_),L),
combination(L,N,Name_List).
name_list(Name_List,N) :-
var(N),
findall(Name,name(Name,_,_),L),
length(L,Len),
for(1,N,Len),
combination(L,N,Name_List).
combination(X,1,[A]) :-
member(A,X).
combination([A|Y],N,[A|X]) :-
N > 1,
M is N - 1,
combination(Y,M,X).
combination([_|Y],N,A) :-
N > 1,
combination(Y,N,A).

Resources