How can I do cryptarithmetics in Prolog? - prolog

Each of the 7 different letters stands for a different digit. The aim is to find a substitution of digits for the letters such that the resulting sum is arithmetically correct. The solution should then produce all of the combinations of the digits that satisfy the addition problem above. Putting in a query such as crypto(P,I,N,G,O,F,U) should return your solution.
The cryptarithmetic puzzle goes like this:
P I N G
P O N G
+ F U N
---------
I G N I P

Use clpfd! Based on my previous answer to a very similar question, we run the following query:
?- Eq = ([P,I,N,G] + [P,O,N,G] + [F,U,N] #= [I,G,N,I,P]),
crypt_arith_(Eq,Zs),
labeling([],Zs).
Eq = ([7,1,9,4] + [7,0,9,4] + [6,2,9] #= [1,4,9,1,7]), Zs = [7,1,9,4,0,6,2]
; Eq = ([8,1,4,7] + [8,3,4,7] + [9,2,4] #= [1,7,4,1,8]), Zs = [8,1,4,7,3,9,2]
; Eq = ([8,1,4,7] + [8,9,4,7] + [3,2,4] #= [1,7,4,1,8]), Zs = [8,1,4,7,9,3,2]
; false.

Assuming this is a simple substitution cipher we're talking about (and just for fun), I'll take a stab at it. One should note that this is completely untested.
I'm going to set this up in a generic way, so you can say something like:
substitution_cipher( CipherExpr , CipherResult , Expr , Result , Key ).
We'll make the rule that the enciphered stuff is represented by atoms, so you can say something like this:
substitution_cipher( ping + pong + fun , ignip , Expr , Sum , Key ) .
And get the results you'd expect.
So...
First, you need the set (discrete, unique) of characters found in the cipher text:
character_set( Expr , Charset ) :-
setof( C , A^Cs^( atoms_in_expression( Expr , A ) , atom_chars(A,Cs) , member(C,Cs) ) , Charset ) .
atom_in_expression( Expr , Value ) :- atom(Expr) .
atom_in_expression( Expr , Value ) :-
Expr =.. [ _ , Left , Right ] ,
(
values( Left , Value )
;
values( Right, Value
) .
The above walks the parse tree of an expression like a * b + c * d, finding each of the leaf nodes (atoms), deconstructing them into the characters that comprise them. setof/3 ensures that the resulting list is sorted and unique.
Once you have that, you need a way of generating all the possible keys (key == mapping between a character and a digit). We want to be able to say something like
generate_key( [a,b,c] , Key )
and get back
Key = [a:1,b:2,c:3]
etc.
So:
generate_key( Charset , Key ) :-
generate_key( Charset , [] , Key ) .
generate_key( [] , Key , Key ) . % when we've exhausted the character set, we're done.
generate_key( [C|Cs] , Acc , Key ) :- % otherwise...for each character
digit(D) , % find a digit
\+ member( _:D , Acc ) , % that hasn't yet been used
generate_key( Cs , [C:D|Acc] , Key ) % map it to the character and recurse down.
.
digit(D) :- between(0,9,X) , atom_number(D,X).
Then you need a way to decode a cipher expression like
ping + pong + fun
and [try to] turn it back into proper numbers. This isn't much different than walking the parse tree and enumerating the leaf node atoms, but here we need to get them back into numeric form.
If the expression is an atom, we
decompose it into its constituent characters,
using our key, map each character to its corresponding digit,
then we turn that list of digits back into a number
decode( Key , CipherExpr , PlainExpr ) :-
atom(CipherExpression) ,
atom_chars(CipherExpression,Cs) ,
findall( D , ( member(C,Cs), member(C:D,Key) -> true ; D=C ) , Ds ) ,
number_chars( PlainExpr , Ds )
.
The general case is easy. An infix expression like ping + pong is really the prolog term +(ping,pong). We:
Decompose a infix term like ping + pong into an operator (+) and its left and right sub-expressions.
Then we recursively decode the left and right sub-expressions
Finally, we reassemble the [decoded] expression.
decode( Key , CipherExpr , PlainExpr ) :-
CipherExpr =.. [Op,L,R] ,
decode(L,L1) ,
decode(R,R1) ,
PlainExpr =.. [Op,L1,R1]
.
Then you can put it all together:
substitition_cipher( CipherExpr , CipherResult , PlainExpr , PlainResult , Key ) :-
character_set( CipherExpr = CipherResult , Charset ) ,
generate_key( Charset, Key ) ,
decode( Key , CipherExpr , PlainExpr ) ,
decode( Key , CipherResult , PlainResult ) ,
PlainResult =:= PlainExpr
.

Related

Why would a provided prolog function not be allowed to be used twice in the program

error: Full stop in clause-body? Cannot redefine ,/2
I understand that the error is caused when our Prolog system already provides X/2, and you cannot redefine it. so you can either omit your own definition (thus, using the system-provided one instead) or rename your predicate - but im not understanding why I would be getting the error with this code
county_deaths(onedia,45).
county_deaths(essex,0).
county_deaths(franklin,0).
county_deaths(clinton,4).
county_deaths(fulton,19).
county_deaths(hamilton,1).
county_deaths(herkimer,3).
county_deaths(saratoga,14).
county_deaths(stLawrence,2).
county_deaths(warren,27).
county_deaths(washington,14).
county_deaths(lewis,5).
county_cases(clinton,95).
county_cases(essex, 36).
county_cases(franklin, 20).
county_cases(fulton, 196).
county_cases(hamilton, 5).
county_cases(herkimer, 103).
county_cases(lewis, 20).
county_cases(onedia, 917).
county_cases(saratoga, 463).
county_cases(stLawrence, 197).
county_cases(warren, 251).
county_cases(washington, 228).
start :-
findall( N , county_deaths(_,N), [N|Ns] ) ,
min_max( Ns , N , N , Min, Max ) ,
display_max(Max),
display_min(Min)
.
findall( N , county_cases(_,N), [N|Ns] ) ,
min_max( Ns , N , N , Min, Max ) ,
display_maxCase(Max),
display_minCase(Min)
.
min_max( [] , Min , Max , Min , Max ) .
min_max( [N|Ns] , X , Y , Min , Max ) :- N < X , !, min_max(Ns,N,Y,Min,Max) .
min_max( [N|Ns] , X , Y , Min , Max ) :- N > Y , !, min_max(Ns,X,N,Min,Max) .
min_max( [_|Ns] , X , Y , Min , Max ) :- min_max(Ns,X,Y,Min,Max) .
% multiple counties could have the same number of deaths, so
% we use findall/3 to enumerate all counties with the specified
% number of deaths.
display_max(N) :-
findall(C,county_deaths(C,N),Cs) ,
writeln(max_deaths:Cs:N)
.
display_min(N) :-
findall(C,county_deaths(C,N),Cs) ,
writeln(min_deaths:Cs:N)
.
display_maxCase(N) :-
findall(C,county_cases(C,N),Cs) ,
writeln(max_cases:Cs:N)
.
display_minCase(N) :-
findall(C,county_cases(C,N),Cs) ,
writeln(min_cases:Cs:N)
.
I believe the error is with the findall function - but that is something prolog provides and i need to use this method 3 times in my program. I have tried to solve this by renaming the method - but then it is no longer the provided findall function. how can i get around this error?

I'm trying to remove a single occurrence of an element in a list

I'm using prolog and I'm trying to remove 1 element from the list. My append code works fine same with the if the element I am looking for is the first element in the list but it just says false if it is the second element in the list. Where am I going wrong
deleteFirst([A|X],B,Y,R):-
A\=B,
appendL(Y,A,[],Y1),
deleteFirst(X,B,Y1,R).
deleteFirst([A|X],A,Y,R):-
appendL(Y,X,[],R).
Try something like this:
% ---------------------------------------------
% remove the first X from List, yielding Result
% ---------------------------------------------
delete_first( X , List , Result ) :-
append( Prefix, [X|Suffix], List ) ,
! ,
append( Prefix, Suffix, Result ) .
The cut is needed to eliminate the choice point: otherwise, on backtracking, it will put the removed item back and try to find another matching X.
If you were to roll your own (I imagine that that is what your instructor wants), something like this, just a traversal of the list will do you:
delete_first( _ , [] , [] ) . % Remove this to fail if no matching X is found
delete_first( X , [X|Rs] , Rs ) :- % Once we find an X, we're done.
!. % - and eliminate the choice point
delete_first( X , [Y|Ys] , [Y|Rs] ) :- % Otherwise, put Y on the result list and recurse down
delete_first( X , Ys, Rs ) .

Take a positive integer n and produce a list that prints out a list in prolog?

I am trying to write a prolog rule to take a positive integer n and gives back a list that counts down from n to 0, including negatives. So spiralDown(4,L) would return L=[4,-4,3,-3,2,-2,1,-1,0]. I got it to return the positive values but cant get it to return the negative values.
ruleOne(-1,[]).
ruleOne(X,[H|T]) :-
Y is X-1,
H=X,
ruleOne(Y,T).
This is an attempt at a solution that has deficiencies, but it would point you in the correct direction, I hope:
spiral_down(N, [N, Minus_N|Rest]) :-
succ(N0, N),
Minus_N is -N,
spiral_down(N0, Rest).
spiral_down(0, [0]).
Here's one solution:
spiral_down(Hi,Ns) :-
integer(Hi) ,
Hi >= 0 ,
Lo is -Hi ,
spiral_down(Hi,Lo,Ns)
.
spiral_down( Hi , Hi , [Hi] ) .
spiral_down( Hi , Lo , [Hi|Ns] ) :-
Hi > Lo ,
H1 is Hi-1 ,
spiral(H1,Lo,Ns)
.
And another:
spiral_down( 0 , [] ) .
spiral_down( M , [M,N|Xs]) :-
M > 0 ,
N is -M ,
M1 is M-1 ,
spiral_down( M1 , Xs )
.

convert term to variable in prolog

I have a list of terms,
[g(_G543),g(_G548),g(_G553),g(_G558),g(_G558),g(_G553),g(_G548),g(_G543)]
How can I make it to
[_G543,_G548,_G553,_G558,_G558,_G553,_G548,_G543]
only left the variables.
I was trying
replace([],[]).
replace([g(X)|T1],[X|T2]):-
replace(T1,T2).
but it just returned a false, what should I do? Thanks
If your list looks like your example
[ g(A) , g(B) , g(C) , g(A) ... ]
something like this ought to do you:
extract_vars( [] , [] ) . % if the source list is exhausted, we're done
extract_vars( [g(V)|Xs] , [V|Vs] ) :- % otherwise...
var(V) , % - ensure we've got a var
! , % - eliminate the choice point
extract_vars( Xs , Vs ) % - recurse down
. %
extract_vars( [_|Xs] , Vs ) :- % anything else, we chuck
extract_vars( Xs , Vs ) %
. % Easy!
You could probably use findall\3, too:
extract_vars( Xs , Vs ) :-
findall( V , (member(g(V),Xs),var(V)) , Vs )
.
The underscore names eg. _G553 have no real relevance, so there's no need to maintain the exact names ?
In which case, assuming all list items are all g(..), there is no need to recurse through them.. just create a new list with the same length as the input list, but without the 'g' prefix:
X=[g(_G543),g(_G548),g(_G553),g(_G558),g(_G558),g(_G553),g(_G548),g(_G543)], length(X, Len), length(Y,Len).
X = [g(_G543), g(_G548), g(_G553), g(_G558), g(_G558), g(_G553), g(_G548), g(_G543)],
Len = 8,
Y = [_G3808, _G3811, _G3814, _G3817, _G3820, _G3823, _G3826, _G3829].
Here, length/2 is used to create a list of 'Len' items.

Unifying a number to a list in Prolog

Alright, so I'm working on a homework assignment, this is supposed to be a four function calculator taking in a list of strings [three, times, two] for example, and output a number. It only considers the numbers from one to twenty in its initial list. The following code is all my own. It runs up to the point where it takes in the last item in the list (that I've been using to test it, but the problem is for any of the inputs) in numberize and then will not unify.
calculator([twenty, times, three, plus, five, divided_by, two],Total).
I know the solution must be an easy one, but I'm not experienced enough yet in Prolog to figure it out.
My question is: how do I fix my code so that it runs the way I want it to?
calculator(X,Total):-
numberize(X,L),
reverse(L,L1),
func(L1,Total).
numberize([X,Y|T],L):-
str2num(X,X1),
numberize(T,[Y,X1|L]).
numberize([X],L):-
str2num(X,X1),
%somehow add on the X1 to the front of L without any errors and it's golden
/*Whatever that line is*/L is [X1|L].
func([X1,X,Z1|T], Total):-
(X == times, times(X1,Z1,Ttl));
(X == plus, plus(X1,Z1,Ttl));
(X == divided_by, divided_by(X1,Z1,Ttl));
(X == minus, minus(X1,Z1,Ttl)),
func([Ttl|T],Total).
str2num(one, X):- X is 1.
str2num(two, X):- X is 2.
str2num(three, X):- X is 3.
str2num(four, X):- X is 4.
str2num(five, X):- X is 5.
str2num(six, X):- X is 6.
str2num(seven, X):- X is 7.
str2num(eight, X):- X is 8.
str2num(nine, X):- X is 9.
str2num(ten, X):- X is 10.
str2num(eleven, X):- X is 11.
str2num(twelve, X):- X is 12.
str2num(thirteen, X):- X is 13.
str2num(fourteen, X):- X is 14.
str2num(fifteen, X):- X is 15.
str2num(sixteen, X):- X is 16.
str2num(seventeen, X):- X is 17.
str2num(eighteen, X):- X is 18.
str2num(nineteen, X):- X is 19.
str2num(twenty, X):- X is 20.
times(X,Y,Prod):-
Prod is X*Y.
plus(X,Y,Sum):-
Sum is X+Y.
divided_by(X,Y,Quo):-
Quo is X/Y.
minus(X,Y,Dif):-
Dif is X-Y.
Small style remark: use facts for str2num/2: just str2num(one, 1). instead of str2num(one, X):- X is 1., etc. Added benefit is that now the predicate can be used both ways, like str2num(Word, 1).
As for the main question, you are almost correct.
The whole numberize predicate can be as simple as this:
numberize([X], [N]) :-
str2num(X, N).
numberize([X, Op | T], [N, Op | NewT]) :-
str2num(X, N),
numberize(T, NewT).
Let's test it:
?- numberize([one, plus, two, minus, three], L).
L = [1, plus, 2, minus, 3]
But you need to remove call to reverse from calculator:
calculator(X,Total):-
numberize(X,L),
func(L,Total).
You have almost correct func predicate. One problem: in Prolog you should have braces around disjunction:
func([X1,X,Z1|T], Total):-
(
X == times, times(X1,Z1,Ttl)
;
X == plus, plus(X1,Z1,Ttl)
;
X == divided_by, divided_by(X1,Z1,Ttl)
;
X == minus, minus(X1,Z1,Ttl)
),
func([Ttl|T],Total).
The second problem: when your list reduced to one number (think how func([1,plus,2], Total) will call func([3], Total) the predicate will fail. All you need to fix this is the rule that Total of a list with just 1 number is the number itself:
func([X], X).
Now the whole thing works:
?- calculator([one, plus, two], Total).
Total = 3
?- calculator([one, plus, two, minus, four], Total).
Total = -1
The way I'd approach this is to start by defining a grammar for arithmetic expressions. The "standard" way of defining grammars is left-recursive. Since prolog does recursive descent parsing, the grammar can't be left-recursive. Every iteration has to remove something from the token stream, lest you go in to the death spiral of infinite recursion. Here's my non-left recursive grammar for a 4-banger calculator like yours:
expression : multiplicative_expression '+' expression
| multiplicative_expression '-' expression
| multiplicative_expression
;
multiplicative_expression : factor '*' multiplicative_expression
| factor '/' multiplicative_expression
| factor '%' multiplicative_expression
| factor
;
factor : '-' value
| '(' expression ')'
| value
;
value : number
Once we have the grammar, the prolog code pretty much writes itself. First, some facts to work with. We need a list of operators and their types (along with the equivalent prolog operator:
operator( plus , additive , '+' ) .
operator( minus , additive , '-' ) .
operator( times , multiplicative , '*' ) .
operator( divided_by , multiplicative , '/' ) .
operator( modulo , multiplicative , 'mod' ) .
And a words-to-numbers-map:
number_word( zero , 0 ).
number_word( one , 1 ).
...
number_word( nineteen , 19 ) .
number_word( twenty , 20 ) .
And we need our interface predicate, calculate/2:
%--------------------------------------------------------------------
% we can calculate a result if Expr is a valid expression
% that consumes all the available tokens in the token stream
%---------------------------------------------------------------------
calculate(Expr,Result) :- expr( Expr , Result , [] ) .
That invokes the "start symbol" of the grammar, expr/3. expr/3 (and the other worker predicates) are pretty much direct restatements of the grammar, with the additional requirement that they need to hand back the unconsumed portion of the input token stream. The parse is successful, if, at the end of the day, the token stream is empty:
expr( Xs , Result , Tail ) :- % per the grammar, an expression is
mult( Xs , LHS , [Sym|X1] ) , % - a multiplicative expression, followed by
operator( Sym , additive , Op ) , % - an infix additive operator, followed by
expr( X1 , RHS , X2 ) , % - another expression
Term =.. [Op,LHS,RHS] , % * in which case, we construct the proper prolog structure
Result is Term , % * in which case, we evaluate the result in the usual way
Tail = X2 % * and unify any remaining tokens with the Tail
. %
expr( Xs , Result , Tail ) :- % alternatively, an expression is simply
mult( Xs , Result , Tail ) % - a single multiplicative expression
. %
The worker predicate for multiplicative terms, mult/3 is pretty much identical — a direct restatement of the grammar:
mult( Xs , Result, Tail ) :- % a multiplicative expression is
factor( Xs , LHS , [Sym|X1] ) , % - a factor, followed by
operator( Sym , multiplicative , Op ) , % - an infix multiplicative operator, followed by
mult( X1 , RHS , X2 ) , % - another factor
evaluate( Op , LHS , RHS , Result ) , % * in which case, we evalute the result in the usual way
Tail = X2 % * and unify any remaining tokens with the tail
. %
mult( Xs , Result , Tail ) :- % alternatively, a multiplicative expression is simply
factor( Xs , Result , Tail ) % - a single factor
. %
Finally, since we're not wrassling with higher-precedence operations like unary minus, exponentiation or parentheses that change operator precedence, a factor is simply a number word that can be converted into an integer value:
factor( [X|Xs] , Value , Xs ) :- % a factor is simply
number_word(X,Value) % - a number value (in our case, a word that we convert to an integer)
.
and a simple helper to evaluate each subexpression as needed:
evaluate( Op , LHS , RHS , Result ) :- % to evaluate an infix term,
Term =.. [Op,LHS,RHS] , % - use univ to convert to the correct prolog structure, and
Result is Term % evaluate it as the result
. %

Resources