Cryptarithmetic Multiplication Prolog - math

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

Related

Number of ways to sit in a 2XN grid

I had this question in an interview but I was not able to solve it.
We have a grid of 2 rows and n columns. We have to find the number of ways to sit M men and W women given no men can sit adjacent or in front of each other.
I thought of solving it by Dynamic Programming but I'm not sure how to get the recurrence relation.
I know that if I am at (0,i), I can go to (1,i+1) but I don't know how to keep track of counts of men and women so far. Can anybody help me with the recurrence relation or states of dp?
Recurrence relation
Here is one recurrence relation I could thing of.
Let's call n_ways(N, W, M, k) the number of ways to seat:
W women
and M men
in the remaining N columns
knowing there was k men in the previous column. k can only take values 0 and 1.
n_ways(N, 0, 0, k) = 1
n_ways(N, W, M, k) = 0 if M > N or W+M > 2*N
n_ways(N, W, 0, k) = ((2*N) choose W)
n_ways(N, 0, M, 0) = 2 * (N choose M)
n_ways(N, 0, M, 1) = (N choose M)
n_ways(N, W, M, 0)
= n_ways(N-1, W, M, 0) // put nobody in first column
+ 2 * n_ways(N-1, W-1, M, 0) // put 1 woman in first column
+ n_ways(N-1, W-2, M, 0) // put 2 women in first column
+ 2 * n_ways(N-1, W-1, M-1, 1) // put 1 woman & 1 man in first column
+ 2 * n_ways(N-1, W, M-1, 1) // put 1 man in first column
n_ways(N, W, M, 1)
= n_ways(N-1, W, M, 0) // put nobody in first column
+ 2 * n_ways(N-1, W-1, M, 0) // put 1 woman in first column
+ n_ways(N-1, W-2, M, 0) // put 2 women in first column
+ n_ways(N-1, W-1, M-1, 1) // put 1 woman & 1 man in first column
+ n_ways(N-1, W, M-1, 1) // put 1 man in first column
Testing with python
Since I'm too lazy to implement dynamic programming myself, I instead opted for caching using python's functools.cache.
I implemented the recurrence relation above as a cached recursive function, and got the following results:
Number of ways to seat w women and m men in n columns:
n, w, m --> ways
0, 0, 0 --> 1
0, 0, 1 --> 0
0, 1, 0 --> 0
1, 2, 0 --> 1
1, 0, 2 --> 0
1, 1, 1 --> 2
2, 2, 2 --> 2
3, 3, 3 --> 2
4, 6, 2 --> 18
10, 15, 5 --> 2364
10, 10, 10 --> 2
Here is the python code:
from functools import cache
from math import comb
#cache
def n_ways(n, w, m, k):
if w == m == 0:
return 1
elif m > n or w + m > 2 * n:
return 0
elif m == 0:
return comb(2*n, w)
elif w == 0:
return (2-k) * comb(n, m)
else:
r_0, r_w, r_ww, r_wm, r_m = (
n_ways(n-1, w, m, 0),
n_ways(n-1, w-1, m, 0),
n_ways(n-1, w-2, m, 0) if w > 1 else 0,
n_ways(n-1, w-1, m-1, 1),
n_ways(n-1, w, m-1, 1)
)
return (r_0 + r_w + r_w + r_ww + r_wm + r_m) + (1-k) * (r_wm + r_m)
if __name__=='__main__':
print(f'Number of ways to seat w women and m men in n columns:')
print(f' n, w, m --> ways')
for w, m in [(0, 0), (0, 1), (1, 0), (2, 0), (0, 2),
(1, 1), (2, 2), (3, 3), (6, 2), (15, 5),
(10, 10)]:
n = (w + m) // 2
print(f'{n:2d}, {w:2d}, {m:2d} --> ', end='')
print(n_ways(n, w, m, 0))

Dependent Arrays in Constraints JuMP

I want to code this constraint.
d and a in the below code are the subsets of set S with the size of N. For example: (N=5, T=3, S=6), d=[1,2,2,3,1] (the elements of d are the first three digits of S and the size of d is N) and a=[6,4,5,6,4] (the elements of a are the three last digits of set S and the size of a is N).
In the constraint, s should start with d and end with a.
It should be like s[j=1]=1:6, s[j=2]=2:4, s[j=3]=2:5, s[j=4]=3:6, s[j=5]1:4.
I do not know how to deal with this set that depends on the other sets. Can you please help me to code my constraint correctly? The below code is not working correctly.
N = 5
T=3
S=6
Cap=15
Q=rand(1:5,N)
d=[1,2,2,3,1]
a=[6,4,5,6,4]
#variable(model, x[j=1:N,t=1:T,s=1:S], Bin)
#constraint(model, [j= 1:N,t = 1:T, s = d[j]:a[j]], sum(x[j,t,s] * Q[j] for j=1:N) <= Cap)
N, T, S = 5, 3, 6
Q = rand(1:5,N)
d = [1, 2, 2, 3, 1]
a = [6, 4, 5, 6, 4]
using JuMP
model = Model()
#variable(model, x[1:N, 1:T, 1:S], Bin)
#constraint(
model,
[t = 1:T, s = 1:S],
sum(x[j, t, s] * Q[j] for j in 1:N if d[j] <= s < a[j]) <= 15,
)
p.s. There's no need to post multiple comments and questions:
Coding arrays in constraint JuMP
You should also consider posting on the Julia discourse instead: https://discourse.julialang.org/c/domain/opt/13. It's easier to have a conversation there.

mathematica code that is not working according to wanted expression

enter image description here
I failed to do the following expression and make it give accurate results if any one can help me I will be glade. I attached my expression in a pic "want this" and my trial as "my trial". the correct answer must equal 0.119 when a=1, b=10, m=3, n=6. thanks a lot in advance.
a = 1
b = 10
m = 3
n = 6
a^1 b^n (Sum[
Sum[Sum[Sum[(-1)^(k + v - n + m + 1)
If[k == 0, 1,
SeriesCoefficient[Series[(-Log[1 - x])^k, {x, 0, 30}],
p + k]] If[n - k - 2 == 0, 1,
SeriesCoefficient[
Series[(-Log[1 - x])^(n - k - 2), {x, 0, 30}],
q + (n - k - 2)]]
Binomial[n - m - 1, k] Binomial[b - 1,
v] (-PolyGamma[0, -1 + 1/a - k + n + q] +
PolyGamma[0, 2/a + n + p + q + v])/(a (1 + k + p + v) +
1), {q, 0, 30 - (n - k - 2)}], {p, 0, 30 - k}], {v, 0,
b - 1}], {k, 0, n - m - 1}])/((m - 1)! (n - m - 1)!)
I found the solution for the problem. the problem was when the value of k was 0 the coefficient will not equal 1 but the whole expression must be found from the start for a value of k that will start from 1 and an expression when the value of k is 0. yet I failed to solve it using MATHEMATICA but by doing the above I succeed to get the correct result. thank you all for your precious time and opinions.

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]

Find all natural number solutions in Prolog program

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

Resources