List of integers and infinite loop in Prolog CLPFD - prolog

Suppose I want to represent integers like so: integer:Sign:[FirstDigit,SecondDigit,...]. For instance, 42 would be represented as integer:positive:[4,2].
I need a predicate that generates the value of the integer based on this representation and vice versa.
Here is what I came up with:
integer_value_('integer':Sign:[H],E) :-
H in 0..9,
(
Sign = 'positive',
E #= H
;
Sign = 'negative',
E #= -H
).
integer_value_('integer':Sign:[H,I|T],E) :-
H in 0..9,
length([I|T],L),
(
Sign = 'positive',
E #= F + H * 10^L
;
Sign = 'negative',
E #= F - H * 10^L
),
integer_value_('integer':Sign:[I|T],F).
This works as expected. However, it has the unfortunate property of accepting things like integer:positive:[0,1], that is, leading zeroes at the beginning of the list. This is especially problematic when I enumerate all possible integers using integer_value_(I,J), label([J]).: the ones with leading zeroes also show up.
I then attempted to correct this by using integer_value_ only for all but the first digit, and using integer_value for the first one (keeping in mind that we need to accomodate for 0 being represented with a list containing only 0):
integer_value('integer':Sign:[H],E) :-
abs(E) #< 10,
abs(E) #> -1,
integer_value_('integer':Sign:[H],E).
integer_value('integer':Sign:[H,I|T],E) :-
H in 1..9,
length([I|T],L),
(
Sign = 'positive',
E #= F + H * 10^L
;
Sign = 'negative',
E #= F - H * 10^L
),
integer_value_('integer':Sign:[I|T],F).
However now it does not behave properly. For example, integer_value(I,-19). returns I = integer:negative:[1, 9], but if we ask for another answer Prolog goes into an infinite loop for reasons I don't understand (it should say false, or already know there are no other answers).
This problem does not occur with the "opposite" query integer_value(integer:negative:[1,9],Z). which returns Z = 19 and then false, nor does it occur when both arguments are Variables (it enumerates numbers properly, with no leading zeroes), which is surprising to me.
Any idea what that infinite loop occurs, and if there's an easy way to fix it?

To see the problem, it is sufficient to look at a tiny fraction of your program. In fact the following failure-slice is sufficient:
integer_value('integer':Sign:[H],E) :- false,
abs(E) #< 10,
abs(E) #> -1,
integer_value_('integer':Sign:[H],E).
integer_value('integer':Sign:[H,I|T],E) :-
H in 1..9,
length([I|T],L), false,
( Sign = 'positive',
E #= F + H * 10^L
;
Sign = 'negative',
E #= F - H * 10^L
),
integer_value_('integer':Sign:[I|T],F).
L occurs here for the first time, so any length is possible.
You will have to modify the length-goal somehow.

I managed to solve my problem using this other answer pointed out by #false
One of the catch is to decide of the sign of the number as the last step, so that when iterating through possible integers we get alternating answers between positive and negative numbers: after reaching 9 (1 digit), it will unify with -9, then -8, etc. After -1, it will unify with 10, 11, etc. After 99, it will unify with -99, -98, etc. You get the point.
integer_value('integer':Sign:I,E) :-
integer_value('integer':Sign:I,0,E,E).
integer_value('integer':Sign:[H],N0,N,M) :-
H in 0..9,
N1 #= H + N0 * 10,
abs(M) #>= abs(N1),
integer_value_('integer':Sign:[],N1,N,M).
integer_value('integer':Sign:[H,I|T],N0,N,M) :-
H in 1..9,
N1 #= H + N0 * 10,
abs(M) #>= abs(N1),
integer_value_('integer':Sign:[I|T],N1,N,M).
integer_value_('integer':Sign:[],N0,N,_) :-
(
Sign = 'positive',
N #= N0
;
Sign = 'negative',
N #\= 0,
N #= - N0
).
integer_value_('integer':Sign:[H],N0,N,M) :-
H in 0..9,
N1 #= H + N0 * 10,
abs(M) #>= abs(N1),
integer_value_('integer':Sign:[],N1,N,M).
integer_value_('integer':Sign:[H,I|T],N0,N,M) :-
H in 0..9,
N1 #= H + N0 * 10,
abs(M) #>= abs(N1),
integer_value_('integer':Sign:[I|T],N1,N,M).

Related

Prolog returning H = 0+1+1 rather than H = 2

I've been learning recursion in prolog and it seems to work but the output is in a very strange format;
mins_to_hours(In, H, M):-
In < 60,
H is 0,
M is In.
mins_to_hours(In, H, M):-
In > 59,
H = H1 + 1,
In1 = In - 60,
mins_to_hours(In1, H1, M).
Is my code and given the query mins_to_hours(135, H, M).
The response is
H = 0+1+1,
M = 15
I'm just confused why the minute works but the hours doesn't.
The program is supposed to convert minutes into hours and minutes.
Thanks in advance!
When reasoning over integers, use for example the predicate (#=)/2 to express equality of arithmetic expressions.
For example, using GNU Prolog:
mins_to_hours(In, H, M):-
In #< 60,
H #= 0,
M #= In.
mins_to_hours(In, H, M):-
In #> 59,
H #= H1 + 1,
In1 #= In - 60,
mins_to_hours(In1, H1, M).
Thus, I am simply using (#=)/2 to express equality, (#<)/2 to express "less than", and (#>)/2 to express "greater than".
Example query and answer:
| ?- mins_to_hours(135, H, M).
H = 2
M = 15 ? ;
no
It also works in other directions, for example:
| ?- mins_to_hours(Mins, 2, 15).
Mins = 135 ? ;
no
The most general query works too:
| ?- mins_to_hours(Mins, H, M).
H = 0
M = _#2(0..59)
Mins = _#2(0..59) ? ;
H = 1
M = _#72(0..59)
Mins = _#2(60..119) ? ;
H = 2
M = _#136(0..59)
Mins = _#2(120..179) ?
In other Prolog systems, you may have to import a library to use such relations over integers. For example, in SICStus Prolog, YAP and SWI, use library(clpfd).
In contrast, the predicate (=)/2 you are currently using denotes syntactic unification, and does not evaluate arithmetic expressions.
#mat has the correct answer regarding reasoning over integers.
The reason why you see H = 0+1+1 is because in Prolog + is just another functor. That is, H1 + 1 is equivalent to '+'(H1, 1), and the =/2 operator is not an assignment as it is in other languages. It does unification of terms. So to say, H = H1 + 1 simply unifies H with the term '+'(H1, 1) or H1 + 1. If H1 is unified with 0, then H will be unified with the term 0 + 1. If later on H1 is unified with 0 + 1 and you execute H = H1 + 1, then H will have the value 0 + 1 + 1, and so on.
If you want to execute an arithmetic expression, you can use is/2. This is described in the Prolog documentation:
H is H1 + 1
This will actually evaluate H1 + 1 assuming it is a valid arithmetic expression (which it is in this case) and all the variables are instantiated with numeric values. There are other operators in Prolog which will perform arithmetic expression evaluation: </2, >/2, =:=/2, etc, as well as the CLP(FD) operators, #=/2, etc, as described in #mat's answer. These are aall described in the Prolog documentation.
Conversely, you are using is/2 where you should be using unification. This:
mins_to_hours(In, H, M):-
In < 60,
H is 0, % 0 is a trivial expression and doesn't need evaluating
M is In. % In is a trivial expression and doesn't need evaluating
Should be written as:
mins_to_hours(In, H, M):-
In < 60,
H = 0,
M = In.
Or more concisely as:
min_to_hours(In, 0, In) :- In < 60.

Clpfd not a square number

Is it possible to make a constraint for an integer to say it can not be a (Perfect) square number?
I have:
square(Square):- N#>0, Square #= N*N.
How do I define notsquare(Notsquare):- ...
My first thought was to have P*P =Q*Q*Notsquare and Remainder #>0, Remainder #= P rem Q.
But P and Q need to be able to be non integers so this didn't work.
What about
notSquare(S):- N #> 0, R #>0, R #< 2*N+1, S #= N*N+R.
?
Should work if S > 0; if you need to work with negative numbers too, I suppose you could modify it as
notSquare(S):- S #> 0, N #> 0, R #>0, R #< 2*N+1, S #= N*N+R.
notSquare(S):- S #< 0, SM #= -S, notSquare(SM).

How to find the biggest digit in a number in Prolog?

I have an easy task, but somehow I haven't solved it in over an hour. This recursion I am doing isn't working, I'm stuck in an infinte loop. It should compare the last digit of a number with every other and remember the biggest one. Would really like to know why is my logic faulty and how to solve this problem.
This is my try on it:
maxDigit(X,X):-
X<10.
maxDigit(X,N):-
X1 is X//10,
X2 is X mod 10,
maxDigit(X1,N1),
X2=<N1,
N is N1.
maxDigit(X,N):-
X1 is X//10,
X2 is X mod 10,
maxDigit(X1,N1),
X2>N1,
N is X2.
Using SICStus Prolog 4.3.3 we simply combine n_base_digits/3 and maximum/2 like so:
?- n_base_digits(12390238464, 10, _Digits), maximum(Max, _Digits).
Max = 9.
A comment suggested stopping as soon as the maximum digit is encountered. This is how we do:
:- use_module(library(clpfd)).
:- use_module(library(reif)).
#=(X, Y, T) :- X #= Y #<==> B, bool10_t(B, T).
bool10_t(1, true).
bool10_t(0,false).
Based on if_/3, (;)/3 and (#=)/3 we then define:
n_base_maxdigit(N, Base, D) :-
N #> 0, % positive integers only
Base #> 1, % smallest base = 2
D #>= 0,
D #< Base,
n_base_maxdigit0_maxdigit(N, Base, 0, D).
n_base_maxdigit0_maxdigit(N, Base, D0, D) :-
D1 #= N mod Base,
N0 #= N // Base,
D2 #= max(D0,D1),
if_(( D2 + 1 #= Base ; N0 #= 0 ),
D = D2,
n_base_maxdigit0_maxdigit(N0, Base, D2, D)).
Sample query using SWI-Prolog 7.3.22 with Prolog lambda:
?- use_module(library(lambda)).
true.
?- Max+\ ( N is 7^7^7 * 10+9, time(n_base_maxdigit(N,10,Max)) ).
% 663 inferences, 0.001 CPU in 0.001 seconds (100% CPU, 1022162 Lips)
Max = 9.
You have just to use if/then/else :
maxDigit(X,X):-
X<10,
!. % added after false's remark
maxDigit(X,N):-
X1 is X//10,
X2 is X mod 10,
maxDigit(X1,N1),
( X2<N1
-> N = N1
; N = X2).
in SWI-Prolog could be:
maxDigit(N,M) :- number_codes(N,L), max_list(L,T), M is T-0'0.

Prolog Break Money into Smaller Amounts

I have this predicate which returns true if S is equal to some equation say K + 2N + 3L = S. The money we have are 1, 5, and 10 respectively for K, N, L.
I don't want to use :- use_module(library(clpfd)), I want to solve this without it.
My intuition was to break this into subproblems like write a function breakMoney1(S,K) :- K is S. and create more helpers with one more parameter added however I am struggling with the problem of getting uninstantiated variables, when I compare.
breakMoney(S,K,N,L) :-
This is easier than you think, probably. A very naive solution following #Will Ness' suggestion would be:
break(Sum, K, N, L) :- integer(Sum), Sum >= 0,
% upper bounds for K, N, and L
K_Max is Sum div 1,
N_Max is Sum div 5,
L_Max is Sum div 10,
% enumerate possible values for K, N, and L
between(0, L_Max, L),
between(0, N_Max, N),
between(0, K_Max, K),
Sum =:= K + 5*N + 10*L.
This will "magically" turn into a clp(fd) solution with very little effort: for example, replace between with X in 0..Max, and the =:= with #=. Although, it should be enough to simply say that X #>= 0 for each of the denominations. It is a good exercise to see how much of the constraints you can remove and still get an answer:
break(Sum, K, N, L) :-
K #>= 0, N #>= 0, L #>= 0,
Sum #= K + 5*N + 10*L.
Depending on how you instantiate the arguments, you might immediately get a unique answer, or you might need to use label/1:
?- break(100, P, 8, 5).
P = 10.
?- break(10, K, N, L).
K in 0..10,
-1*K+ -5*N+ -10*L#= -10,
N in 0..2,
L in 0..1.
?- break(10, K, N, L), label([K, N, L]).
K = N, N = 0,
L = 1 ;
K = L, L = 0,
N = 2 ;
K = 5,
N = 1,
L = 0 ;
K = 10,
N = L, L = 0.
But as #lurker has pointed out, there is very little reason not to use constraint programming for this problem. Unless, of course, you have a very clever algorithm for solving this particular problem and you know for a fact that it will outsmart the generic clp(fd) solution. Even then, it might be possible to achieve the same effect by using the options to labelling/2.

Prolog simple generator

I'm trying to learn myself Prolog and need a little help.
Could someone solve and explain this problem:
Define a p(A, M/N, K/L), which generates all possible rational fractions M/N and K/L, where:
N>M>0, K>L>0, (M/N)*(K/L) = 2 and (M+K)<A
Your description is not that clear to me, I am rather guessing which values should be known and which are asked. So I will rather use library(clpfd) where I do not have to make such considerations myself.
N>M>0, K>L>0, (M/N)*(K/L) = 2 and (M+K)<A
p(A, M/N, K/L) :-
N #> M, M #> 0,
K #> L, L #> 0,
M+K #< A,
(M/N) * (K/L) #= 2.
?- 3/2 #= F.
F = 1.
?- (3/2)*2 #= F.
F = 2.
Oh, clpfd is on the integers so fractions are truncated. I need some algebra first, multiplying both sides with (N*L) (they are both not 0...):
p(A, M/N, K/L) :-
N #> M, M #> 0,
K #> L, L #> 0,
M+K #< A,
M*K #= 2*N*L.
?- p(A, M/N, K/L).
A in 4..sup, M+K+ -1*A#=< -1, M in 1..sup,
M#=<N+ -1, M*K#=_A, N in 2..sup, 2*N#=_B,
_B in 4..sup, _B*L#=_A, L in 1..sup, L#=<K+ -1,
K in 2..sup, _A in 4..sup.
So Prolog says: Yes! That is true provided all this very fine print is true. The first line is the most interesting A in 4..sup which means that there is no upper bound for A. To get concrete solutions, A must be known:
?- A #= 10, p(A, M/N, K/L).
A = 10, M in 1..7, M+K#=_A, M#=<N+ -1,
M*K#=_B, K in 2..8, L#=<K+ -1, L in 1..7,
_C*L#=_B, _C in 4..56, 2*N#=_C, N in 2..28,
_B in 4..56, _A in 3..9.
Not enough! But now K, L, M, N have all finite domains, so we can enumerate them using labeling([], [K,L,M,N]).
?- A = 10, p(A,M/N,K/L),labeling([],[M,N,K,L]).
A = 10, M = L, L = 1, N = 2, K = 4
; A = 10, M = 1, N = L, L = 2, K = 8
; A = 10, M = L, L = 1, N = 3, K = 6
; ... .

Resources