Find all natural number solutions in Prolog program - math

For example if I want to get all possible natural number pairs that sum to 10, how would I get prolog to do that?
If my code is something like this:
sumsTo10(X,Y):-
Z is X+Y,
Z == 10.
Then yes, if I ask if 5 and 5 sum to 10 I get a true as an answer, but I'd like something like this:
?-sumsTo10(A,B).
[1,9]
[2,8]
....

You can use the Constraint Logic Programming library over Finite Domains (clpfd) for that:
:- use_module(library(clpfd)).
sumsTo10(X,Y):-
[X,Y] ins 1..10,
X + Y #= 10,
label([X,Y]).
This then generates:
?- sumsTo10(X,Y).
X = 1,
Y = 9 ;
X = 2,
Y = 8 ;
X = 3,
Y = 7 ;
X = 4,
Y = 6 ;
X = Y, Y = 5 ;
X = 6,
Y = 4 ;
X = 7,
Y = 3 ;
X = 8,
Y = 2 ;
X = 9,
Y = 1.
The first line specifies that both X and Y are in the 1..10 domain (that is 10 inclusive, but that does not matter). The second line is a constraint: it restricts the fact that X + Y should be equal (#=) to 10. This only adds the constraint: it will not ground X and Y to values where this actually holds, but from the moment X and Y are (partially) grounded, and the constraint is not met, it will fail. If you for instance set X to 10, it will derive that Y can only be 0, but since Y is in the interval 1..10, that is not possible hence the system will fail.
Finally by using label([X,Y]) we will assign values in the domain to X and Y such that the constraint holds.

Your Prolog could provide between/3. Then
?- between(1,10,X), between(1,10,Y), X+Y =:= 10.
X = 1,
Y = 9 ;
X = 2,
Y = 8 ;
X = 3,
Y = 7
...

Related

Euclid in Prolog (greatest common denominator)

We've been given a pseudo-code that we are supposed to translate into Prolog:
This is the solution I've been able to come up with:
% if y = 0: return x
test(X, 0, Output) :- Output is X.
% if x = 0: return y
test(0, Y, Output) :- Output is Y.
% if if x > y: return euclid_recursive(x - y, y)
test(X,Y,Output) :-
% if x > y: return euclid_recursive(x - y, y)
( X > Y -> Temp is X - Y ,
test(Temp, Y,Output);
% return euclid_recursive(x, y - x)
Temp is Y - X,
test(X, Temp, Output)
).
I've tested it with a few examples and it seems to work. I would appreciate it if you folks could have another look at it though.
You only need to use is/2 [swi-doc] to evaluate a numerical expression. So here you can use unification:
test(X, 0, X).
test(0, X, X).
test(X, Y, Output) :-
( X > Y
-> Temp is X - Y,
test(Temp, Y,Output)
; Temp is Y - X,
test(X, Temp, Output)
).
Another major problem is that Prolog will keep making recursive calls, even if one of the elements is zero. It will thus keep proposing new solutions:
?- test(36, 63, R).
R = 9 ;
R = 9 ;
R = 9 ;
R = 9 ;
R = 9 ;
R = 9 ;
R = 9 ;
R = 9 ;
R = 9 ;
R = 9 ;
R = 9 ;
R = 9 ;
…
This may not seem like a (major) problem, but if you use test/3 as part of another program, it can get stuck in an infinite loop where test/3 keeps proposing R = 9, and the next predicate call each time rejecting this.
test(X, 0, X).
test(0, X, X) :-
X > 0.
test(X, Y, Output) :-
X > 0,
Y > 0,
( X > Y
-> Temp is X - Y,
test(Temp, Y,Output)
; Temp is Y - X,
test(X, Temp, Output)
).
This will only propose one solution:
?- test(36, 63, R).
R = 9 ;
false.

Continued fractions and Pell's equation - numerical issues

Mathematical background
Continued fractions are a way to represent numbers (rational or not), with a basic recursion formula to calculate it. Given a number r, we define r[0]=r and have:
for n in range(0..N):
a[n] = floor(r[n])
if r[n] == [an]: break
r[n+1] = 1 / (r[n]-a[n])
where a is the final representation. We can also define a series of convergents by
h[-2,-1] = [0, 1]
k[-2, -1] = [1, 0]
h[n] = a[n]*h[n-1]+h[n-2]
k[n] = a[n]*k[n-1]+k[n-2]
where h[n]/k[n] converge to r.
Pell's equation is a problem of the form x^2-D*y^2=1 where all numbers are integers and D is not a perfect square in our case. A solution for a given D that minimizes x is given by continued fractions. Basically, for the above equation, it is guaranteed that this (fundamental) solution is x=h[n] and y=k[n] for the lowest n found which solves the equation in the continued fraction expansion of sqrt(D).
Problem
I am failing to get this simple algorithm work for D=61. I first noticed it did not solve Pell's equation for 100 coefficients, so I compared it against Wolfram Alpha's convergents and continued fraction representation and noticed the 20th elements fail - the representation is 3 compared to 4 that I get, yielding different convergents - h[20]=335159612 on Wolfram compared to 425680601 for me.
I tested the code below, two languages (though to be fair, Python is C under the hood I guess), on two systems and get the same result - a diff on loop 20. I'll note that the convergents are still accurate and converge! Why am I getting different results compared to Wolfram Alpha, and is it possible to fix it?
For testing, here's a Python program to solve Pell's equation for D=61, printing first 20 convergents and the continued fraction representation cf (and some extra unneeded fluff):
from math import floor, sqrt # Can use mpmath here as well.
def continued_fraction(D, count=100, thresh=1E-12, verbose=False):
cf = []
h = (0, 1)
k = (1, 0)
r = start = sqrt(D)
initial_count = count
x = (1+thresh+start)*start
y = start
while abs(x/y - start) > thresh and count:
i = int(floor(r))
cf.append(i)
f = r - i
x, y = i*h[-1] + h[-2], i*k[-1] + k[-2]
if verbose is True or verbose == initial_count-count:
print(f'{x}\u00B2-{D}x{y}\u00B2 = {x**2-D*y**2}')
if x**2 - D*y**2 == 1:
print(f'{x}\u00B2-{D}x{y}\u00B2 = {x**2-D*y**2}')
print(cf)
return
count -= 1
r = 1/f
h = (h[1], x)
k = (k[1], y)
print(cf)
raise OverflowError(f"Converged on {x} {y} with count {count} and diff {abs(start-x/y)}!")
continued_fraction(61, count=20, verbose=True, thresh=-1) # We don't want to stop on account of thresh in this example
A c program doing the same:
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
int main() {
long D = 61;
double start = sqrt(D);
long h[] = {0, 1};
long k[] = {1, 0};
int count = 20;
float thresh = 1E-12;
double r = start;
long x = (1+thresh+start)*start;
long y = start;
while(abs(x/(double)y-start) > -1 && count) {
long i = floor(r);
double f = r - i;
x = i * h[1] + h[0];
y = i * k[1] + k[0];
printf("%ld\u00B2-%ldx%ld\u00B2 = %lf\n", x, D, y, x*x-D*y*y);
r = 1/f;
--count;
h[0] = h[1];
h[1] = x;
k[0] = k[1];
k[1] = y;
}
return 0;
}
mpmath, python's multi-precision library can be used. Just be careful that all the important numbers are in mp format.
In the code below, x, y and i are standard multi-precision integers. r and f are multi-precision real numbers. Note that the initial count is set higher than 20.
from mpmath import mp, mpf
mp.dps = 50 # precision in number of decimal digits
def continued_fraction(D, count=22, thresh=mpf(1E-12), verbose=False):
cf = []
h = (0, 1)
k = (1, 0)
r = start = mp.sqrt(D)
initial_count = count
x = 0 # some dummy starting values, they will be overwritten early in the while loop
y = 1
while abs(x/y - start) > thresh and count > 0:
i = int(mp.floor(r))
cf.append(i)
x, y = i*h[-1] + h[-2], i*k[-1] + k[-2]
if verbose or initial_count == count:
print(f'{x}\u00B2-{D}x{y}\u00B2 = {x**2-D*y**2}')
if x**2 - D*y**2 == 1:
print(f'{x}\u00B2-{D}x{y}\u00B2 = {x**2-D*y**2}')
print(cf)
return
count -= 1
f = r - i
r = 1/f
h = (h[1], x)
k = (k[1], y)
print(cf)
raise OverflowError(f"Converged on {x} {y} with count {count} and diff {abs(start-x/y)}!")
continued_fraction(61, count=22, verbose=True, thresh=mpf(1e-100))
Output is similar to wolfram's:
...
335159612²-61x42912791² = 3
1431159437²-61x183241189² = -12
1766319049²-61x226153980² = 1
[7, 1, 4, 3, 1, 2, 2, 1, 3, 4, 1, 14, 1, 4, 3, 1, 2, 2, 1, 3, 4, 1]

Prolog recursive list split

I'm new to Prolog and I'm having trouble with the first part of my programming assignment:
Create a predicate split that that takes as input three parameters. The first and third parameters are lists and the second parameter is an element. You can think of the first parameter as being the input and the last two parameters being the output. The method computes all possible way of splitting a list into an element and the rest of the list. Here is an example run.
?- split([1,2,3,4,5],X,Y).
X = 1,
Y = [2, 3, 4, 5] ;
X = 2,
Y = [1, 3, 4, 5] ;
X = 3,
Y = [1, 2, 4, 5] ;
X = 4,
Y = [1, 2, 3, 5] ;
X = 5,
Y = [1, 2, 3, 4] ;
There are two rules in defining the predicate. The first rule simply gets the first element of the list and returns it as the second parameter and the rest of the list as the third parameter. The second rule generates the list by copying the first element of the list in the result (i.e., third parameter) and then recursively applying the method to the rest of the elements.
split([H|T], H, T).
split([H|T], X, [H|Y]) :-
split(T, X, Y).
There are two ways to take an element out of a list:
Take the head (the first element)
Set the head aside and take an element out of the tail (the rest of the list)
Notice that the predicate can run both ways; if the second and the third parameters are defined, it will yield all possible ways these two can be combined to form a list.
split(List,Elem,Rest) :- select(Elem,List,Rest).
| ?- select(X,[1,2,3],Y).
X = 1,
Y = [2,3] ? ;
X = 2,
Y = [1,3] ? ;
X = 3,
Y = [1,2] ? ;
no
and with split/3 ;
| ?- split([1,2,3,4],X,Y).
X = 1,
Y = [2,3,4] ? ;
X = 2,
Y = [1,3,4] ? ;
X = 3,
Y = [1,2,4] ? ;
X = 4,
Y = [1,2,3] ? ;
no
with Sicstus-prolog u need to export select from library/lists
:- use_module(library(lists)).

Cryptarithmetic Multiplication Prolog

I have the grasp of the idea of crypt arithmetic and addition but I cannot figure out how to do a multiplication crypt arithmetic problem. It's simply TWO*SIX=TWELVE or something along those lines without the middle additional part of the multiplication problem given. I couldn't find anything online and I already found some constraints for the problem but nothing to leads me to some answers. Not sure where to ask this and thought this would be the best place.
I want to know how to solve a multiplication crypt arithmetic problem.
I already concluded:
T W O
* S I X
_________________
T W E L V E
T \= 0 which also means S \= 0
T is 1-6
E is (O*X) mod 10
O or X cannot be 0 or 1 since E has to be different and 0 or 1 gives the same value
as either O or X.
EDIT: I was using the generate and test method
solve(T,W,O,S,I,X,E,L,V) :-
X = [T,W,O,S,I,X,E,L,V],
Digits = [0,1,2,3,4,5,6,7,8,9],
assign_digits(X, Digits),
T > 0,
S > 0,
100*T + 10*W + O * 100*S + 10*I + X =:=
100000*T + 10000*W + 1000*E + 100*L + 10*V + E,
write(X).
select(X, [X|R], R).
select(X, [Y|Xs], [Y|Ys]):- select(X, Xs, Ys).
assign_digits([], _List).
assign_digits([D|Ds], List):-
select(D, List, NewList),
assign_digits(Ds, NewList).
Trivially to do with constraint logic programming. For example, in ECLiPSe Prolog:
:- lib(ic).
puzzle(Vars) :-
[T,W,O,S,I,X,E,L,V] = Vars,
Vars :: 0..9,
alldifferent(Vars),
T #> 0, S #> 0,
(100*T + 10*W + O) * (100*S + 10*I + X) #=
100000*T + 10000*W + 1000*E + 100*L + 10*V + E,
labeling(Vars).
First solution:
[eclipse]: puzzle([T,W,O,S,I,X,E,L,V]).
T = 1
W = 6
O = 5
S = 9
I = 7
X = 2
E = 0
L = 3
V = 8
Yes (0.01s cpu, solution 1, maybe more) ?
There are 3 different solutions:
[eclipse]: puzzle([T,W,O,S,I,X,E,L,V]), writeln([T,W,O,S,I,X,E,L,V]), fail.
[1, 6, 5, 9, 7, 2, 0, 3, 8]
[2, 1, 8, 9, 6, 5, 0, 3, 7]
[3, 4, 5, 9, 8, 6, 0, 1, 7]
No (0.02s cpu)
Update - translation to SWI Prolog:
:- use_module(library(clpfd)).
puzzle(Vars) :-
[T,W,O,S,I,X,E,L,V] = Vars,
Vars ins 0..9,
all_different(Vars),
T #> 0, S #> 0,
(100*T + 10*W + O) * (100*S + 10*I + X) #=
100000*T + 10000*W + 1000*E + 100*L + 10*V + E,
label(Vars).
More general and no-CLP solution:
number_to_digits(Number,List) :-
length(List,Len),
ntb(0,Len,Number,List).
ntb(N,_,N,[]).
ntb(C,E,N,[D|L]) :-
NE is E-1,
V is C + D*10^NE,
ntb(V,NE,N,L).
crypto(In1, In2, Out) :-
term_variables([In1, In2, Out], Vars),
permutation([0,1,2,3,4,5,6,7,8,9], Perm),
append(_, Vars, Perm),
number_to_digits(N1, In1),
number_to_digits(N2, In2),
number_to_digits(N3, Out),
N3 is N1 * N2.
It is quite inefficient and definetly this problem should be solved using CLP like #Sergey did, but maybe someone will be interested in possible solutions without CLP.
Input and output:
?- crypto([T,W,O], [S,I,X], [T,W,E,L,V,E]).
T = 0,
W = 5,
O = 7,
S = 9,
I = 6,
X = 2,
E = 4,
L = 8,
V = 3;
(...)
(57 * 962 = 54834).

swipl increment cursor in recursive function

I am very green with Prolog. I have a 7-by-7 grid and for each cell I store the X, the Y, and two other things, like this: cell(1, 1, 0, 0).
I want to traverse the grid and reset the values of the cells if they are not given, so I created these functions:
given(X, Y):- (cell(X, Y, start, _) ; cell(X, Y, end, _)).
reset_cell(X, Y):- not(given(X, Y)), cell(X, Y, 0, 0).
reset_grid(8, _):- write('finished resetting').
reset_grid(X, 8):- X1 is X + 1, reset_cell(X1, 1), reset_grid(X1, 1).
reset_grid(X, Y):- reset_cell(X, Y), Y1 is Y + 1, reset_grid(X, Y1).
But this results in an endless loop because in the last line apparently the parameter passed to the reset_grid function remains at value 1. What am I doing wrong?
Edit: I forgot to mention that I call the function like this: ?- reset_grid(1, 1).
Edit 2: (new version as per Sergey's instructions):
reset_grid(X, _):- X > 7, write('finished resetting').
reset_grid(X, Y):- Y > 7, X1 is X + 1, reset_cell(X1, 1), reset_grid(X1, 1).
reset_grid(X, Y):- X < 8, Y < 8, reset_cell(X, Y), Y1 is Y + 1, reset_grid(X, Y1).
The problem is that when you have a call reset_grid(1, 8), your reset_grid(X, 8) clause fires, but after that reset_grid(X, Y) also fires.
To fix this you can add cut '!' to the reset_grid(X, 8) clause or add Y < 8 to the reset_grid(X, Y), or do both (to get a so-called 'green cut').
The similar problem with call reset_grid(8, 8): reset_grid(8, _) will match, but after that reset_grid(X, Y) will match. Fix in the similar manner.
UPDATE.
Try to change you reset cell definition to just logging X and Y. With this code:
reset_cell(X, Y) :- write([X, Y]), nl.
reset_grid(X, _):- X > 7, write('finished resetting').
reset_grid(X, Y):- Y > 7, X1 is X + 1, reset_cell(X1, 1), reset_grid(X1, 1).
reset_grid(X, Y):- X < 8, Y < 8, reset_cell(X, Y), Y1 is Y + 1, reset_grid(X, Y1).
I get this result:
?- reset_grid(1, 1).
[1,1]
[1,2]
[1,3]
[1,4]
[1,5]
[1,6]
[1,7]
[2,1]
[2,1]
[2,2]
[2,3]
[2,4]
[2,5]
[2,6]
[2,7]
[3,1]
[3,1]
[3,2]
[3,3]
[3,4]
[3,5]
[3,6]
[3,7]
[4,1]
[4,1]
[4,2]
[4,3]
[4,4]
[4,5]
[4,6]
[4,7]
[5,1]
[5,1]
[5,2]
[5,3]
[5,4]
[5,5]
[5,6]
[5,7]
[6,1]
[6,1]
[6,2]
[6,3]
[6,4]
[6,5]
[6,6]
[6,7]
[7,1]
[7,1]
[7,2]
[7,3]
[7,4]
[7,5]
[7,6]
[7,7]
[8,1]
finished resetting
true ;
false.
So the loop works and terminates. Maybe the problem in the last call reset_cell(8, 1)? Otherwise it's with the reset_cell predicate itself or the predicates called from reset_cell. Show the rest of your code so it can be tested.

Resources