Syntax error during associative array expansion in Bash 4.2 - bash

all
I got two 2D-array files to read with bash
these two files contain different rows x columns such as:
file1.txt (nx6)
DIFFUSION X 0.054 0.072 Y E2
DEEP_N_WELL X 1.8 2.25 N D
PW_CORE X 0.306 0.306 Y U1
PW_IO X 0.306 0.306 Y T1
NW_CORE X 0.306 0.306 Y U1
NW_IO X 0.306 0.306 Y T1
TG X 0.306 0.306 N S1
N+_POLY_IMP X 0.162 0.162 Y T1
POLY1 X 0.036 0.09 Y F2
LV_NLDD X 0.162 0.162 Y T1
LV_PLDD X 0.162 0.162 Y T1
LPL_NLDD X 0.162 0.162 Y T1
LPL_PLDD X 0.162 0.162 Y T1
CELL_NLDD X 0.216 0.216 N U1
CELL_PLDD X 0.216 0.216 N U1
HV_NLDD X 0.162 0.162 Y T1
HV_PLDD X 0.162 0.162 Y T1
N+ X 0.162 0.162 Y T1
P+ X 0.162 0.162 Y T1
SMT X 0.162 0.162 Y T1
PESD X 0.486 0.486 N A
SAB X 0.324 0.324 N S1
CONTACT X 0.054 0.072/0.090 Y F1
METAL1 1x 0.063 0.063 Y E2
MVIA1 1x 0.063 0.063/0.081 Y E1
METAL2 1x 0.063 0.063 Y E2
MVIA2 1x 0.063 0.063/0.081 Y E1
METAL3 1x 0.063 0.063 Y E2
MVIA3 1x 0.063 0.063/0.081 Y E1
METAL4 1x 0.063 0.063 Y E2
MVIA4 1x 0.063 0.063/0.081 Y E1
METAL5 1x 0.063 0.063 Y E2
MVIA5 1x 0.063 0.063/0.081 Y E1
METAL6 1x 0.063 0.063 Y E2
MVIA6 6x 0.31 0.320/0.320 N S1
METAL7 6x 0.32 0.4 N S1
TMV_RDL X 1.8 1.8 N B
AL_RDL X 1.8 1.8 N B
PASV_RDL X 5.4 5.4 N B
N_WELL X 0.306 0.306 NULL U1
HP_CELL_NLDD X 0.216 0.216 N U1
HP_CELL_PLDD X 0.216 0.216 N U1
LVH_NLDD X 0.162 0.162 Y T1
LVH_PLDD X 0.162 0.162 Y T1
LVUL_NLDD X 0.162 0.162 Y T1
LVUL_PLDD X 0.162 0.162 Y T1
CG X 0.306 0.306 N S1
AW X 1.5 1.5 N B
file2.txt (mx3)
DIFFUSION 0.054 0.072
POLY1 0.036 0.090
SMT 0.162 0.162
VTNH 0.162 0.162
VTPH 0.162 0.162
N+_POLY_IMP 0.162 0.162
P+_POLY_IMP 0.162 0.162
LV_NLDD 0.162 0.162
LV_PLDD 0.162 0.162
HV_NLDD 0.162 0.162
HV_PLDD 0.162 0.162
LVL_NLDD 0.162 0.162
LVL_PLDD 0.162 0.162
LVH_NLDD 0.162 0.162
LVH_PLDD 0.162 0.162
LPL_NLDD 0.162 0.162
LPL_PLDD 0.162 0.162
HVL_NLDD 0.162 0.162
N+ 0.162 0.162
P+ 0.162 0.162
SG 0.162 0.162
VTP_WLDR 0.162 0.162
VTN_WLDR 0.162 0.162
HS_CELL_PLDD 0.216 0.216
HS_CELL_NLDD 0.216 0.216
NW_CORE 0.306 0.306
PW_CORE 0.306 0.306
PW_IO 0.306 0.306
NW_IO 0.306 0.306
DT 0.090 0.118
CONTACT 0.054 0.072/0.091
METAL1 0.063 0.063
MVIA1 0.063 0.063/0.081
METAL2 0.063 0.063
MVIA2 0.063 0.063/0.081
METAL3 0.063 0.063
MVIA3 0.063 0.063/0.081
METAL4 0.063 0.063
MVIA4 0.063 0.063/0.081
METAL5 0.063 0.063
MVIA5 0.063 0.063/0.081
METAL6 0.063 0.063
MVIA6 0.063 0.063/0.081
METAL7 0.063 0.063
MVIA7 0.126 0.126
METAL8 0.126 0.126
MVIA8 0.126 0.126
METAL9 0.126 0.126
what I wanna do is to extract the elements inside both files then do some comparisons as following picture:
http://imgur.com/3Zd0TKD.jpg
"DESC1==DESC2" or "DESC1!=DESC2" in green label is a obstructer for me
I really wanna do is to take one element in $DESC1 and compare with whole elements in ${DESC2[#]}, if it does/dosen't find a element in ${DESC2[#]} then feedback true/false
Here is my work:
#!/bin/bash
clear
##===================================================================##
##===================================================================##
##========== read information from file1.txt and file2.txt ==========##
##===================================================================##
##===================================================================##
idx1=0
while read -a file1array$idx1; do
let idx1++
done < file1.txt
idx2=0
while read -a file2array$idx2; do
let idx2++
done < file2.txt
##===================================================================##
##===================================================================##
##================ start to compare these two files =================##
##===================================================================##
##===================================================================##
for ((i=0; i<idx1; i++)); do
for ((j=0; j<idx2; j++)); do
DESC1="file1array$i[0]"
DM1="file1array$i[1]"
W1="file1array$i[2]"
S1="file1array$i[3]"
CRITICAL1="file1array$i[4]"
GRADE1="file1array$i[5]"
DESC2="file2array$j[0]"
W2="file2array$j[1]"
S2="file2array$j[2]"
if [[ "${!GRADE1}" == [E-GT-Z][1-9] && "${!DESC1}" == "${!DESC2}" ]]; then
W1_Judge=`expr "scale=3; ${!W1} - ${!W2}" | bc`
S1_Judge=`expr "scale=3; ${!S1} - ${!S2}" | bc`
[ $W1_Judge != 0 -o $S1_Judge != 0 ] && declare -A jgWS=( ["${!DESC1}"]="WSNG" )
elif [[ "${!GRADE1}" == [E-GT-Z][1-9] && "${!DESC1}" != "${!DESC2}" ]]; then
[ "${!CRITICAL1}" != "NULL" ] && declare -A jgLOSS=( ["${!DESC1}"]="LOSSNG" )
elif [[ "${!GRADE1}" != [E-GT-Z][1-9] && "${!DESC1}" == "${!DESC2}" ]]; then
[[ "$DM1" == [1-2]x || "$DM1" == "X" ]] && declare -A jgEXTRA=( ["${!DESC1}"]="EXTRANG" )
else
declare -A jgBYPASS=( ["${!DESC1}"]="OK" )
fi
done
if [ "${jgWS[${!DESC1}]}" == "WSNG" ]; then
echo "${!DESC1} : W or S NG"
elif [ "${jgLOSS[${!DESC1}]}" == "LOSSNG" ]; then
echo "${!DESC1} : LOSS NG"
elif [ "${jgEXTRA[${!DESC1}]}" == "EXTRANG" ]; then
echo "${!DESC1} : EXTRA NG"
else
echo "${!DESC1} : OK"
fi
done
How can I solve the part of green label or is there any easier way to achieve the goal? I feel that I'm very close but turns out I'm just stuck with for-loop and test
The error message is "N+: syntax error: operand expected (error token is "+")"
Actually I can simply define "declare -A jgEXTRA=( ["N+"]="EXTRANG" )" and "echo {jgEXTRA[N+]}"
so I don't know what's going on? Is there any way to solve it?

For the first question:
The complexity of your script is high. It would be an issue if file1 and file2 are big. You should sort them to reduce the complexity (from N^2 to log N).
Do you consider to use 'comm' command? I think this does a big part of the job and could let you simplify your script a lot
For the second question:
It seems you do not initialize jgWS in some condition. When it happens, ${jgWS[a]} return empty string, but ${jgWS[a+]} prints your error message. I am not sure to understand why, but it is what I observed.
Other remarks
You read loops, at the begining, will miss the last lines of file1 and file2 if they are not terminated by a Linux Line Feed (because read returns false when it doesn't finish on LF).

Related

CLPFD constraint: is a prime number

I'm not even sure if this is possible, but I'm trying to write a predicate prime/1 which constrains its argument to be a prime number.
The problem I have is that I haven't found any way of expressing “apply that constraint to all integers less than the variable integer”.
Here is an attempt which doesn't work:
prime(N) :-
N #> 1 #/\ % Has to be strictly greater than 1
(
N #= 2 % Can be 2
#\/ % Or
(
N #> 2 #/\ % A number strictly greater than 2
N mod 2 #= 1 #/\ % which is odd
K #< N #/\
K #> 1 #/\
(#\ (
N mod K #= 0 % A non working attempt at expressing:
“there is no 1 < K < N such that K divides N”
))
)
).
I hoped that #\ would act like \+ and check that it is false for all possible cases but this doesn't seem to be the case, since this implementation does this:
?- X #< 100, prime(X), indomain(X).
X = 2 ; % Correct
X = 3 ; % Correct
X = 5 ; % Correct
X = 7 ; % Correct
X = 9 ; % Incorrect ; multiple of 3
X = 11 ; % Correct
X = 13 ; % Correct
X = 15 % Incorrect ; multiple of 5
…
Basically this unifies with 2\/{Odd integers greater than 2}.
EDIT
Expressing that a number is not prime is very easy:
composite(N) :-
I #>= J,
J #> 1,
N #= I*J.
Basically: “N is composite if it can be written as I*J with I >= J > 1”.
I am still unable to “negate” those constraints. I have tried using things like #==> (implies) but this doesn't seem to be implification at all! N #= I*J #==> J #= 1 will work for composite numbers, even though 12 = I*J doesn't imply that necessarily J = 1!
prime/1
This took me quite a while and I'm sure it's far from being very efficient but this seems to work, so here goes nothing:
We create a custom constraint propagator (following this example) for the constraint prime/1, as such:
:- use_module(library(clpfd)).
:- multifile clpfd:run_propagator/2.
prime(N) :-
clpfd:make_propagator(prime(N), Prop),
clpfd:init_propagator(N, Prop),
clpfd:trigger_once(Prop).
clpfd:run_propagator(prime(N), MState) :-
(
nonvar(N) -> clpfd:kill(MState), prime_decomposition(N, [_])
;
clpfd:fd_get(N, ND, NL, NU, NPs),
clpfd:cis_max(NL, n(2), NNL),
clpfd:update_bounds(N, ND, NPs, NL, NU, NNL, NU)
).
If N is a variable, we constrain its lower bound to be 2, or keep its original lower bound if it is bigger than 2.
If N is ground, then we check that N is prime, using this prime_decomposition/2 predicate:
prime_decomposition(2, [2]).
prime_decomposition(N, Z) :-
N #> 0,
indomain(N),
SN is ceiling(sqrt(N)),
prime_decomposition_1(N, SN, 2, [], Z).
prime_decomposition_1(1, _, _, L, L) :- !.
prime_decomposition_1(N, SN, D, L, LF) :-
(
0 #= N mod D -> !, false
;
D1 #= D+1,
(
D1 #> SN ->
LF = [N |L]
;
prime_decomposition_2(N, SN, D1, L, LF)
)
).
prime_decomposition_2(1, _, _, L, L) :- !.
prime_decomposition_2(N, SN, D, L, LF) :-
(
0 #= N mod D -> !, false
;
D1 #= D+2,
(
D1 #> SN ->
LF = [N |L]
;
prime_decomposition_2(N, SN, D1, L, LF)
)
).
You could obviously replace this predicate with any deterministic prime checking algorithm. This one is a modification of a prime factorization algorithm which has been modified to fail as soon as one factor is found.
Some queries
?- prime(X).
X in 2..sup,
prime(X).
?- X in -100..100, prime(X).
X in 2..100,
prime(X).
?- X in -100..0, prime(X).
false.
?- X in 100..200, prime(X).
X in 100..200,
prime(X).
?- X #< 20, prime(X), indomain(X).
X = 2 ;
X = 3 ;
X = 5 ;
X = 7 ;
X = 11 ;
X = 13 ;
X = 17 ;
X = 19.
?- prime(X), prime(Y), [X, Y] ins 123456789..1234567890, Y-X #= 2, indomain(Y).
X = 123457127,
Y = 123457129 ;
X = 123457289,
Y = 123457291 ;
X = 123457967,
Y = 123457969
…
?- time((X in 123456787654321..1234567876543210, prime(X), indomain(X))).
% 113,041,584 inferences, 5.070 CPU in 5.063 seconds (100% CPU, 22296027 Lips)
X = 123456787654391 .
Some problems
This constraint does not propagate as strongly as it should. For example:
?- prime(X), X in {2,3,8,16}.
X in 2..3\/8\/16,
prime(X).
when we should know that 8 and 16 are not possible since they are even numbers.
I have tried to add other constraints in the propagator but they seem to slow it down more than anything else, so I'm not sure if I was doing something wrong or if it is slower to update constaints than check for primeness when labeling.

CLP(FD)-ying Simultaneous Recursion for Fibonacci Lukas Numbers Possible?

There are some instances where recursive predicates can be CLP(FD)-fied with the benefit that the predicate turns bidirectional. What are the limits of this method? For example can the following computation CLP(FD)-fied:
Fn: n-th Fibonacci Number
Ln: n-th Lucas Number (starting with 2)
By this doubling recursion step:
F2n = Fn*Ln
L2n = (5*Fn^2+Ln^2)//2
And this incrementing recursion step:
Fn+1 = (Fn+Ln)//2
Ln+1 = (5*Fn+Ln)//2
The traditional Prolog realization works already from n to Fn. Can this be turned into a CLP(FD) program preserving the fast recursion and at the same time making it bidirectionally, for example figuring out the index n for Fn=377? If yes how? If not why?
Bye
Yes, it can be done by constraining the values. You can also move the recursion to be tail recursion, although it's not required to get the solutions:
fibluc(0, 0, 2).
fibluc(1, 1, 1).
fibluc(N, F, L) :-
N in 2..1000, % Pick a reasonable value here for 1000
[F, L] ins 1..sup,
N rem 2 #= 1,
M #= N-1,
F #= (F1 + L1) // 2,
L #= (5*F1 + L1) // 2,
fibluc(M, F1, L1).
fibluc(N, F, L) :-
N in 2..1000, % Pick a reasonable value here for 1000
[F, L] ins 1..sup,
N rem 2 #= 0,
M #= N // 2,
F #= F1 * L1,
L #= (5*F1*F1 + L1*L1) // 2,
fibluc(M, F1, L1).
Will yield:
?- fibluc(10, X, Y).
X = 55,
Y = 123 ;
false.
?- fibluc(N, 55, Y).
N = 10,
Y = 123 ;
false.
?- fibluc(N, X, 123).
N = 10,
X = 55 ;
false.
?- fibluc(N, 55, 123).
N = 10 ;
false.
?- fibluc(N, 55, 125).
false.
?- fibluc(N, X, Y).
N = X, X = 0,
Y = 2 ;
N = X, X = Y, Y = 1 ;
N = 3,
X = 2,
Y = 4 ;
N = 7,
X = 13,
Y = 29 ;
N = 15,
X = 610,
Y = 1364 ;
N = 31,
X = 1346269,
Y = 3010349 ;
N = 63,
X = 6557470319842,
Y = 14662949395604 ;
...
This could be modified to generate results for increasing values of N when N is uninstantiated.
Here's a timed, compound query example, run in SWI Prolog 7.1.33 under Linux:
?- time((fibluc(100, X, Y), fibluc(N, X, Z))).
% 11,337,988 inferences, 3.092 CPU in 3.100 seconds (100% CPU, 3666357 Lips)
X = 354224848179261915075,
Y = Z, Z = 792070839848372253127,
N = 100 ;
% 1,593,620 inferences, 0.466 CPU in 0.468 seconds (100% CPU, 3417800 Lips)
false.
?-
Using SWI Prolog 7.2.3 with the same code above and the same compound query, the code does go off for a very long time. I waited at least 15 minutes without termination. It's still running right now... I may check on it in the morning. :)
I did, however, re-arrange the above code to move the recursive call back to where the original code had it as follows:
fibluc(0, 0, 2).
fibluc(1, 1, 1).
fibluc(N, F, L) :-
N in 2..1000, % Pick a reasonable value here for 1000
[F, L] ins 1..sup,
N rem 2 #= 1,
M #= N-1,
fibluc(M, F1, L1),
F #= (F1 + L1) // 2,
L #= (5*F1 + L1) // 2.
fibluc(N, F, L) :-
N in 2..1000, % Pick a reasonable value here for 1000
[F, L] ins 1..sup,
N rem 2 #= 0,
M #= N // 2,
fibluc(M, F1, L1),
F #= F1 * L1,
L #= (5*F1*F1 + L1*L1) // 2.
In this case, the favorable results returned:
?- time((fibluc(100, X, Y), fibluc(N, X, Z))).
% 10,070,701 inferences, 3.216 CPU in 3.222 seconds (100% CPU, 3131849 Lips)
X = 354224848179261915075,
Y = Z, Z = 792070839848372253127,
N = 100 ;
% 1,415,320 inferences, 0.493 CPU in 0.496 seconds (100% CPU, 2868423 Lips)
false.
Note that the performance of CLP(FD) can be vastly different between different Prolog interpreters. It's interesting that, with SWI Prolog, the ability to handle the tail recursive case was temporarily there with version 7.1.33.

Finding all cube roots with a number as a limit

I want to find all of the cube roots that their cubes + their remainder add up to a number to user inputs. So for example, the query:
?- smallerCube(X,20).
Would give the result:
1 remainder 19
2 remainder 12
Since 1^3 = 1 (remainder 19), 2^3 = 8(remainder 12) and 3^3 = 27 which is bigger than the initial input of 20, and hence it's not being calculated here.
So far this is my code:
cubeLess(X,B,R) :-
X =< B,
X1 is X*X*X,
R is B-X1.
smallerCube(X,B) :- int(X),
X2 is X*X*X,
X2 =< B,
cubeLess(X2,B,R),
write(X), write(' rest '), writeln(R).
int(1).
int(N) :- int(N1), N is N1+1.
I use cubeLess to get the remainder, int to generate numbers from 1 onward.
However, when I run the following query:
?- smallerCube(X,130)
I get the following weird result:
1 rest 129
X = 1
2 rest -382
X = 2
3 rest -19553
X = 3 ;
Why did it work for X=1, but gave negative results for X=2,3?
Use clpfd!
:- use_module(library(clpfd)).
No need to worry about using clpfd for the 1st time—you'll get the meaning in a moment for sure!
smallerCube_(X, Remainder, Maximum) :-
X #>= 0,
Remainder #>= 0,
Remainder + X^3 #= Maximum.
First, the most general query of smallerCube_/3:
?- smallerCube_(X, Remainder, 20).
X in 1..2, _A in 1..8, Remainder in 12..19, X^3 #= _A, Remainder+_A #= 20.
One answer—two solutions: let's see them separated!
?- smallerCube_(X, Remainder, 20), indomain(X).
X = 1, Remainder = 19 % 20 #= 1^3 + 19
; X = 2, Remainder = 12. % 20 #= 2^3 + 12
Here's the second query the OP wanted to run:
?- smallerCube_(X, Remainder, 130), indomain(X).
X = 1, Remainder = 129 % 130 #= 1^3 + 129
; X = 2, Remainder = 122 % 130 #= 2^3 + 122
; X = 3, Remainder = 103 % ...
; X = 4, Remainder = 66 % ...
; X = 5, Remainder = 5. % 130 #= 5^3 + 5
Done! So what's next? Of course, that is up to you, so:
Why not re-invest the time clpfd saved you?
Why not read
this very compact CLP(FD) primer
as a jumpstart?

Prolog Program To Check If A Number Is Prime

I wrote the following program based on the logic that a prime number is only divisible by 1 and itself. So I just go through the process of dividing it to all numbers that are greater than one and less than itself, but I seem to have a problem since I get all entered numbers as true. Here's my code...
divisible(X,Y) :-
Y < X,
X mod Y is 0,
Y1 is Y+1,
divisible(X,Y1).
isprime(X) :-
integer(X),
X > 1,
\+ divisible(X,2).
Thanks in advance :)
I'm a beginner in Prolog but managed to fix your problem.
divisible(X,Y) :- 0 is X mod Y, !.
divisible(X,Y) :- X > Y+1, divisible(X, Y+1).
isPrime(2) :- true,!.
isPrime(X) :- X < 2,!,false.
isPrime(X) :- not(divisible(X, 2)).
The main issue was the statement X mod Y is 0. Predicate is has two (left and right) arguments, but the left argument has to be a constant or a variable that is already unified at the moment that the predicate is executing. I just swapped these values. The rest of the code is for checking number 2 (which is prime) and number less than 2 (that are not primes)
I forgot to mention that the comparison Y < X is buggy, because you want to test for all numbers between 2 and X-1, that comparison includes X.
This answer is a follow-up to #lefunction's previous answer.
isPrime2/1 is as close as possible to isPrime1/1 with a few changes (highlighted below):
isPrime2(2) :-
!.
isPrime2(3) :-
!.
isPrime2(X) :-
X > 3,
X mod 2 =\= 0,
isPrime2_(X, 3).
isPrime2_(X, N) :-
( N*N > X
-> true
; X mod N =\= 0,
M is N + 2,
isPrime2_(X, M)
).
Let's query!
?- time(isPrime1(99999989)).
% 24,999,999 inferences, 3.900 CPU in 3.948 seconds (99% CPU, 6410011 Lips)
true.
?- time(isPrime2(99999989)).
% 5,003 inferences, 0.001 CPU in 0.001 seconds (89% CPU, 6447165 Lips)
true.
X mod Y is 0 always fails, because no expressions allowed on the left of is.
Change to 0 is X mod Y, or, better, to X mod Y =:= 0
agarwaen's accepted answer does not perform well on large numbers. This is because it is not tail recursive (I think). Also, you can speed everything up with a few facts about prime numbers.
1) 2 is the only even prime number
2) Any number greater than half the original does not divide evenly
isPrime1(2) :-
!.
isPrime1(3) :-
!.
isPrime1(X) :-
X > 3,
( 0 is X mod 2
-> false
; Half is X/2,
isPrime1_(X,3,Half)
).
isPrime1_(X,N,Half) :-
( N > Half
-> true
; 0 is X mod N
-> false
; M is N + 2,
isPrime1_(X,M,Half)
).
1 ?- time(isPrime1(999983)).
% 1,249,983 inferences, 0.031 CPU in 0.039 seconds (80% CPU, 39999456 Lips)
true.
EDIT1
Is it possible to take it a step further? isPrime_/3 is more efficient than isPrime2/1 because it compares only to previously known primes. However, the problem is generating this list.
allPrimes(Max,Y) :-
allPrimes(3,Max,[2],Y).
allPrimes(X,Max,L,Y) :-
Z is X+2,
N_max is ceiling(sqrt(X)),
( X >= Max
-> Y = L;
( isPrime_(X,L,N_max)
-> append(L,[X],K), %major bottleneck
allPrimes(Z,Max,K,Y)
; allPrimes(Z,Max,L,Y)
)).
isPrime_(_,[],_).
isPrime_(X,[P|Ps],N_max) :-
( P > N_max
-> true %could append here but still slow
; 0 =\= X mod P,
isPrime_(X,Ps,N_max)
).
I thing that is elegant way:
isPrime(A):-not((A1 is A-1,between(2,A1,N), 0 is mod(A,N))),not(A is 1).
1 IS NOT PRIME NUMBER, but if you don't think so just delete not(A is 1).
Was trying something else. A pseudo primality test based on Fermats little theorem:
test(P) :- 2^P mod P =:= 2.
test2(P) :- modpow(2,P,P,2).
modpow(B, 1, _, R) :- !, R = B.
modpow(B, E, M, R) :- E mod 2 =:= 1, !,
F is E//2,
modpow(B, F, M, H),
R is (H^2*B) mod M.
modpow(B, E, M, R) :- F is E//2,
modpow(B, F, M, H),
R is (H^2) mod M.
Without the predicate modpow/4 things get too slow or integer overflow:
?- time(test(99999989)).
% 3 inferences, 0.016 CPU in 0.016 seconds (100% CPU, 192 Lips)
true.
?- time(test2(99999989)).
% 107 inferences, 0.000 CPU in 0.000 seconds (?% CPU, Infinite Lips)
true.
?- time(test(99999999999900000001)).
% 4 inferences, 0.000 CPU in 0.000 seconds (81% CPU, 190476 Lips)
ERROR: Stack limit (1.0Gb) exceeded
?- time(test2(99999999999900000001)).
% 267 inferences, 0.000 CPU in 0.000 seconds (87% CPU, 1219178 Lips)
true.
Not yet sure how to extend it to a full primality test.

Prolog Cryptarithmetic Puzzle

I have been asked to solve a Cryptarithmetic Puzzle using Prolog:
GIVE
* ME
------
MONEY
The above is the puzzle, I cannot figure out where is the problem, the result always returns false. Plus I am not allowed to use any library in SWI-Prolog.
solve(Z) :-
assign(Z,[0,1,2,3,4,5,6,7,8,9]),
check(Z).
find( VAL , G,I,V,E ) :- VAL is G * 1000 + I * 100 + V * 10 + E.
find2(VALR, M,E ) :- VALR is M * 10 + E.
find3(VALA, M,O,N,E,Y) :- VALA is M * 10000 + O * 1000 + N * 100 + E * 10 + Y.
check(Z) :-
G #>= 1,
M #>= 1,
find( VAL, G,I,V,E),
find2(VALR, M,E),
find3(VALA, M,O,N,E,Y),
VAL * VALR =:= VALA.
assign(Z,L) :-
permute(L,Z).
/* permute is similar to all_different in swi-prolog */
addany(X,K,[X|K]).
addany(X,[F|K],[F|L1]) :-
addany(X,K,L1).
permute([],[]).
permute([X|K],P) :-
permute(K,L1),
addany(X,L1,P).
Sample query:
?- solve([G,I,V,E,M,O,N,Y]).
false. % fails unexpectedly
Let's get right to the heart of the matter!
Every permutation of
[0,1,2,3,4,5,6,7,8,9] is a list of length 10.
[G,I,V,E,M,O,N,Y] is a list of length 8.
No permutation of [0,1,2,3,4,5,6,7,8,9] can be unified with [G,I,V,E,M,O,N,Y].
As a quick-fix, adapt the definition of check/1 like this:
check([G,I,V,E,M,O,N,Y,_,_]) :-
find( VAL, G,I,V,E),
G >= 1,
find2(VALR, M,E),
M >= 1,
find3(VALA, M,O,N,E,Y),
VAL * VALR =:= VALA.
Then, run the following "fixed" query:
?- Expr = ([G,I,V,E]*[M,E] = [M,O,N,E,Y]),
Zs = [G,I,V,E,M,O,N,Y,_,_],
time(solve(Zs)).
% 24,641,436 inferences, 7.692 CPU in 7.709 seconds (100% CPU, 3203506 Lips)
Expr = ([1,0,7,2] * [9,2] = [9,8,6,2,4]),
Zs = [1,0,7,2,9,8,6,4,3,5] ;
% 7,355 inferences, 0.007 CPU in 0.007 seconds (100% CPU, 1058235 Lips)
Expr = ([1,0,7,2] * [9,2] = [9,8,6,2,4]), % redundant
Zs = [1,0,7,2,9,8,6,4,5,3] ;
% 6,169,314 inferences, 1.935 CPU in 1.939 seconds (100% CPU, 3188312 Lips)
Expr = ([1,0,9,2] * [7,2] = [7,8,6,2,4]),
Zs = [1,0,9,2,7,8,6,4,3,5] ;
% 7,355 inferences, 0.005 CPU in 0.005 seconds (99% CPU, 1360603 Lips)
Expr = ([1,0,9,2] * [7,2] = [7,8,6,2,4]), % redundant
Zs = [1,0,9,2,7,8,6,4,5,3] ;
% 6,234,555 inferences, 1.955 CPU in 1.959 seconds (100% CPU, 3189462 Lips)
false.
Here's another way to solve the problem:
First, use clpfd!
:- use_module(library(clpfd)).
Second, (re-)use code presented earlier in my answer
to the related question Faster implementation of verbal arithmetic in Prolog:
?- Expr = ([G,I,V,E] * [M,E] #= [M,O,N,E,Y]),
Zs = [G,I,V,E,M,O,N,Y],
crypt_arith_(Expr,Zs),
time(labeling([],Zs)).
% 397,472 inferences, 0.088 CPU in 0.088 seconds (100% CPU, 4521899 Lips)
Expr = ([1,0,7,2] * [9,2] #= [9,8,6,2,4]), Zs = [1,0,7,2,9,8,6,4] ;
% 128,982 inferences, 0.037 CPU in 0.037 seconds (100% CPU, 3502788 Lips)
Expr = ([1,0,9,2] * [7,2] #= [7,8,6,2,4]), Zs = [1,0,9,2,7,8,6,4] ;
% 77,809 inferences, 0.028 CPU in 0.028 seconds (100% CPU, 2771783 Lips)
false.
No redundant solutions. Orders of magnitude faster than "generate & test". clpfd rocks!
The following article by Eric Weisstein and Ed Pegg will be useful. It offers several solutions for a similar problem in Mathematica.
Using a very brute-force approach, there are two solutions: 1072 * 92 = 98624 and 1092 * 72 = 78624. The code that I used:
In[16]:= Cases[
Permutations[
Range[0, 9], {5}], {g_, i_, v_, e_, m_} /; g > 0 && m > 0 :>
With[{dig = IntegerDigits[(g*10^3 + i*10^2 + v*10 + e) (10 m + e)]},
Join[{g, i, v, e, m}, dig[[{2, 3, 5}]]] /;
And[Length[dig] == 5, Unequal ## dig, dig[[{1, 4}]] == {m, e},
Intersection[dig[[{2, 3, 5}]], {g, i, v, e, m}] === {} ]
]]
Out[16]= {{1, 0, 7, 2, 9, 8, 6, 4}, {1, 0, 9, 2, 7, 8, 6, 4}}

Resources