Prolog Cryptarithmetic program - prolog

I'm taking a programming course and the professor just lightly skimmed over Prolog due to lack of time. Anyways, he suggested we research it on our own. I came across a Cryptarithmetic program that is supposed to calculate? AM+PM = DAY. I do not know what is supposed to be added as input in the SWI interpreter and what should be received as the correct output...If this makes any sense?
I tried...
solve([AM],[PM],[DAY]).
That does nothing. Any help on what the correct input would be for AM+PM = DAY or something similar would be great! Here is the program I was playing with...
solve([A,M,P,D,Y]):-
select(A,[0,1,2,3,4,5,6,7,8,9],WA), % W means Without
not(A=0),
select(M,WA,WMA),
select(P,WMA,WMAP),
not(P=0),
select(D,WMAP,WMAPD),
not(D=0),
select(Y,WMAPD,WMAPDY),
DAY is 100*D+10*A+Y,
AM is 10*A+M,
PM is 10*P+M,
DAY is AM+PM.
Please keep in mind that we only had two classes on Prolog so I know next to nothing!
Scott

Okay, this program will give a variable assignment for the formula
DAY = AM + PM
Where each of the characters is a digit from 0 to 9 no, digit may be used twice and A,P and D mustn't be 0 (no leading zeroes allowed).
For beginners trying to understand prolog programs it might be more feasible to ask the question: "How is it (the program) true", instead of "what input generates which output". Prolog gladly supplies you with the variable settings it needed to make, to give you a true. (It also tracks on the way where it could have gone another way, so can ask again).
The program uses pattern matching, but basically wants a list of five elements which represent the variables A, M,P,D and Y (in that order).
select's arguments are:
something (you can put in a list)
a list that contains the first argument
the list without the first argument.
not tries to solve what it is given and fails if it succeeds.
, is a short cirquiting and, like && in many C-like languages.
The last four lines are simple arithmetics, while the lines above just ensure that you aren't selecting doubles and leading 0s.
so after you have loaded your program, you can query for answers:
?- solve([A, M,P,D,Y]).
A = 2,
M = 5,
P = 9,
D = 1,
Y = 0
If you want another solution, you can hit space or ;. If you want to know, if there is a solution with A = 5, you can query like this:
?- A = 5, solve([A, M,P,D,Y]).
A = 5,
M = 6,
P = 9,
D = 1,
Y = 2
If you want to "reassemble" it, this line might help:
?- solve([A, M,P,D,Y]), format('~w~w~w= ~w~w + ~w~w~n', [D,A,Y,A,M,P,M]).
format is something like printf in many other languages.

Related

Prolog "," operator not working as intended?

I'm super unfamiliar with prolog but I need it for a school project. So, if I use unclear language or incorrect terms, please be understanding. My trouble is that my code is not working how I intended it at all. Here is a bit of my code in the knowledge base:
output(mn,hp,hp,hp).
output(hn,mn,hp,lp).
output(ln,hp,mp,hp).
input(lp,mp,mp,lp):-output(hn,mn,hp,lp).
And here is my query:
?- input(X,mp,mp,lp),output(hn,mn,hp,lp).
I would expect it to return X = lp, as the if-then sentence in the knowledgebase states. However, it returns X=hp, X=mp, and X=lp, which is not what I intended.
I used "trace" to see how it reasoned, and I saw that it called for other outputs. I thought the "," operator meant "and", so it would only look for the output with the values (hn,mn,hp,lp). How can I get my code to only look for if-then sentences with the correct output values? Do I have an incorrect understanding of the "," operator or is the problem due to my knowledge base?
EDIT: Here is the link to my code in SWISH: https://swish.swi-prolog.org/p/i%20wanna%20bash%20my%20head%20in.pl#&togetherjs=AQ4zzkAQk4
EDIT 2: My aim with this project is the following: I'm trying to explain a fuzzy cognitive map with this program. I want the program to determine the values of missing input concepts given the output concepts. So, I need the program to look for the clause with the correct values in output(), and then determine the values inside the relevant input().
With the whole program (88 lines):
?- output(hn,mn,hp,lp).
true.
So this can be completely disregarded in your query - it's true no matter what (constants only) and has no further effect.
Then what counts is:
?- input(X,mp,mp,lp).
X = mp ;
X = lp ;
X = hp ;
false.
No need for Prolog. Use text search to confirm that:
$ grep "mp,mp,lp" proggy.pl
input(mp,mp,mp,lp):-output(mn,hp,hp,hp).
input(mp,mp,lp,hp):-output(hn,lp,hp,hp).
input(mp,mp,lp,mp):-output(hn,mp,hp,hp).
input(lp,mp,mp,lp):-output(hn,mn,hp,lp).%this one is a pain in my ass
input(hp,mp,mp,lp):-output(ln,hp,mp,hp).
input(mp,mp,lp,lp):-output(ln,hp,mp,hp).
of the above, these three lines
input(mp,mp,mp,lp):-output(mn,hp,hp,hp).
input(lp,mp,mp,lp):-output(hn,mn,hp,lp).%this one is a pain in my ass
input(hp,mp,mp,lp):-output(ln,hp,mp,hp).
<-><------>
X MATCH
will match the query: 3 results with X from mn,hn,ln.
Working as expected.
Here is a simpler query:
?- input(X,mp,mp,lp).
This succeeds three times:
X = mp ;
X = lp ;
X = hp ;
false.
I assume you understand why this is: There are several matching clauses for input with different values for X and with bodies that succeed.
Now, you are right that , is conjunction, and that in general a goal A, B can succeed less often than A or B individually, but never more often. A and B typically constrain each other. But, very importantly: If A and B do not share any variables, then they are independent. In this case, the sequence of answers will be the Cartesian product of the answers for A and the answers for B. If A alone succeeds N times and B alone succeeds M times, then A, B without a shared variable will succeed N * M times.
You can only expect to see fewer solutions for a query of the form ?- input(X,mp,mp,lp), OtherGoal. if OtherGoal also contains an occurrence of X. In your query this is not the case. The first conjunct succeeds three times, the second succeeds once, so overall you have 3 * 1 = 3 successes, as you observed.
So the question is: What are you trying to express with your query? You cannot express something like "give me solutions for input, but only by applying certain clauses of output".

How does = operator works in Prolog

Sorry if this is a newbie question, but recently I was trying to compare an string and I used this (not exactly :P):
some_fact('Yes').
some_fact('No').
some_rule(X):- some_fact(X), (X =:= 'Yes' -> writeln("ISS YES") ; writeln("No")).
Error: Arithmetic: `'Yes'' is not a function
After that, I Googled and saw that Strings are compared with = and \=
But if I write: X = 5 I'm assigning the value 5 to X, well I don't know if the word is assign, cause the assigment operator is is. Right?
Just in case, I don't need to fix the code, I want understand what's happening.
Thanks
I think there is a lot of confusion here and most of it would be remedied by going through a book, but let me try and clear a few things up for you right now.
'Yes' is an atom, not a string. SWI-Prolog has actual strings, but most Prolog implementations do not, they use atoms instead. The nice thing about atoms is that if they are lower case and do not contain spaces there is no need for quotes. The quotes are needed to tell Prolog "this is not a variable" and resolve the syntactic ambiguity of this and that.
Lacking strings, there is no operator for string comparison.
= is the unification operator. Unification is a big topic—not something that is easily summarized in a question, but as an approximation you can think of it as a bi-directional pattern matching. So, it will do the job for what you probably need string comparisons for, but it is the real engine of computation in Prolog and is happening behind the scenes in lots of ways.
Prolog does not have assignment. True, you can give a variable a value. But you cannot change that value later; X = X + 1 is meaningless in mathematics and it's meaningless in Prolog too. In general, you will be working recursively, so you will simply create a new variable when something like this needs to occur. It will make more sense as you get further in reading about Prolog and writing your first programs. Please check out a tutorial!
is/2 resolves arithmetic expressions. If you have X = 2+3, Prolog will reply with X = 2+3. Only X is 2+3 will cause Prolog to report X=5. Arithmetic just isn't a huge part of classic Prolog usage; these days, people will quickly suggest you check out CLPFD, which enables you to do more interesting things like 15 #= X + Y and producing bindings that add up to 15. Standard Prolog cannot "work backwards" like this. But for a complete beginner it probably suffices to say that arithmetic works differently than you expect it to, and differently than the rest of Prolog unless you use CLPFD.
=:= is an arithmetic equality operator. You use this to answer questions like 6 + 1 =:= 5 + 2. This is a really special-purpose tool that I personally have never really needed to use.

prolog dcg restriction

I would like to use DCGs as a generator. As of now, the syntax is
s-->a,b.
a-->[].
a-->a,c.
c-->[t1].
c-->[t2].
b-->[t3].
b-->[t4].
I would like to generate all s where the length of a is < someNumber.
Using ?- phrase(a,X),length(X,Y),Y<4. i can get all a with less than 4 items. However, when all combinations are exhausted, the system (SWI-Prolog 6.2.5) seems to stall.
Sometimes ago, a similar question was asked here. However, being new to Prolog i am not able to make it work with the grammar above. Any ideas?
Update: There was a comment by (canrememberthename) which got deleted, somehow. Anyway, it was suggested to use between(1,4,Y),length(X,Y),phrase(a,X). to set limits. This worked nicely, after changing my code to a-->c,a.
The first steps into Prolog are often a bit difficult. But you are on the right track:
Currently, your problem is that you get some answers/solutions as expected but then the system stalls ; in fact, it is in an infinite loop. You found that out by patiently hitting SPACE. That might work with a tiny set of solutions but it will be tedious with a larger one. Just think of looking at all sentences shorter than 20.
There is a simple keyboard and carpal tunnel friendly way to simulate hitting space: Simply add a goal false at the end like so:
?- phrase(a,X),length(X,Y),Y<4, false.
What could Prolog answer to such a question? Since there is false at the end, Prolog has not much choice: Either it answers false itself ; or it loops (or produces an error or produces some side-effect). And in this case, it loops.
Now, we can narrow down the problem, by adding further false goals into your program.
?- phrase(a,X),length(X,Y),false, Y<4, false.
loops.
To make this better readable, I will only use one false goal and strike through the remaining part of the query:
?- phrase(a,X),length(X,Y),false, Y<4.
loops.
Let's reduce that even further:
?- phrase(a,X),false,length(X,Y),Y<4.
loops.
They all loop! But we get some interesting insight: Since these false-adorned queries do not terminate, also the original program does not terminate. So when you look at a query, and the very first goal does not terminate for itself, it follows that the entire query will not terminate (see the fine print at the end for more).
Therefore: You have to address the first goal somehow!
My first attempt is to exchange length and phrase:
?- length(X,Y), phrase(a,X), Y<4.
Will this work? Just look at the first goal which loops:
?- length(X,Y), false, phrase(a,X), Y<4.
loops.
So this again will not terminate.
You have to change the program again:
?- between(1,3,Y), length(X,Y), false, phrase(a,X).
false.
So this terminates. And if there will be a termination problem, phrase(a,X) has now to take the blame:
?- between(1,3,Y), length(X,Y), phrase(a,X), false.
loops.
You might be tempted to look at actual answers:
?- between(1,3,Y), length(X,Y), phrase(a,X).
Y = 1, X = [t1]
; Y = 1, X = [t2]
; resource_error(local_stack). % ERROR: Out of local stack
And you might conclude that this behavior is worse than your original definition. After all, we have now less answers than before. But exactly that kind of reasoning does not help you to improve termination: With false both are of the same kind of incorrectness and you have to address this first. So by hiding the answers you can better concentrate on the rest.
But why is your grammar problematic? We can continue with our technique to insert goals false to narrow it down. But this time within your grammar. Your program adorned with goals false is called a failure-slice.
Just a practical remark: When I insert goals false into your program, I will save the program and type make in SWI: In this manner the program is rapidly recompiled.
After trying a bit, I got the following minimal failure-slice. Note that within a DCG, false has to be written as {false}.
?- between(1,3,Y), length(X,Y), phrase(a,X), false
s--> {false}, a,b.
a-->[], {false}.
a-->a,{false}, c.
c-->{false}, [t1].
c-->{false}, [t2].
b-->{false}, [t3].
b-->{false}, [t4].
Almost all your codebase are belong to false! So you have to address the tiny visible remaining part. It would be pointless to change something somewhere else. This a --> a, ... must be changed! And in fact changing it to a --> c, s solves the problem.
Why did you write a --> a, c. in the first place? I suspect that you wanted to enumerate all solutions in a fair manner. The new version doesn't:
?- phrase(a,X).
X = []
; X = [t1]
; X = [t1,t1]
; X = [t1,t1,t1]
; X = [t1,t1,t1,t1]
; X = [t1,t1,t1,t1,t1]
; X = [t1,t1,t1,t1,t1,t1]
; X = [t1,t1,t1,t1,t1,t1,t1]
; ... .
That looks very intimidating. In fact, it looks wrong. Doesn't it? But don't let you confuse by this: We have here an infinite set of sentences. So the only correct response by Prolog is to produce infinitely many answers. For, if they would be finite, some list would be missing! But of course, you want to see them enumerated in a fair manner. To get this, simply write:
?- length(X,N), phrase(a,X).
X = [], N = 0
; X = [t1], N = 1
; X = [t2], N = 1
; X = [t1,t1], N = 2
; X = [t1,t2], N = 2
; X = [t2,t1], N = 2
; X = [t2,t2], N = 2
; X = [t1,t1,t1], N = 3
; ... .
This is a major point in Prolog programs: Always go for the best (possible) termination property first. And do not look at the precise order how Prolog enumerates answers. For, if a program has better termination properties, it is next-to-trivial to use it to enumerate all solutions in a fair manner. But: A program that enumerates infinitely many solutions in a fair manner at the expense of termination cannot be used in more interesting cases.
Fine Print See this answer.
the nonterminal a//0 is both left recursive and 'epsilon' (generate the empty sequence), and phrase/2 will loop immediately after the empty production.
You can solve your problem bounding list' length:
?- between(1,4,Y),length(X,Y),phrase(a,X).
and, as you have already done, removing the left recursion.

printing business cards - a kind of knapsack task

I am new to Prolog and I have some probably simple issue with a piece of code. This is a real world problem that arose last Friday and believe me this is not a CS Homework.
We want to print business cards and these can only be printed in blocks of 900 cards (100 sheets with 9 cards per sheet). The cards for anybody should not be distributed over several blocks. People ordered different amount of cards, E.G:
% "braucht" is german and means "needs"
braucht(anton,400).
braucht(berta,200).
braucht(claudia,400).
braucht(dorothee,100).
braucht(edgar,200).
braucht(frank,400).
braucht(georg,100).
I put together the following definition to find an appropriate block of 900 business cards:
block(0,[]).
block(N,[H|T]) :-
braucht(H,Nh),
% \+(member(H,T)),
D is N - Nh,
D >= 0,
block(D,T).
This produces a nice list of blocks of people whose cards fit together on a 900 cards block. But it stops working if I activate the commented line "\+member...." and just gives me a "false". But I need to assure that nobody is getting more than once on that block. What am I doing wrong here?
It seems that what you want to achieve is to set a constraint that H does not appear in the tail T of the list. However, T is still unbound when you call member/2, so that member(H, T) will succeed and hence \+ member(H,T) will fail.
If you don't want to use Constraint Programming, but use pure Prolog instead, you should use the check in the other direction and check whether H is already present in the list of people that has been aggregated up to that point. Something like:
block(0, List, List).
block(N, Rest, List) :-
braucht(H, Nh),
\+(memberchk(H, Rest)), % will fail when H is already in Rest
D is N-Nh,
D >= 0,
block(D, [H|Rest], List).
The predicate block/3 can be called from a predicate block/2:
block(N, List) :-
block(N, [], List).
If the second argument in your block predicate is the "output", then your problem is that T is a free variable, so member(_,T) will always succeed. For instance:
?- member(anton,T).
T = [anton|_]
T = [_,anton|_]
T = [_,_,anton|_]
and so on...

Two strange efficiency problems in Mathematica

FIRST PROBLEM
I have timed how long it takes to compute the following statements (where V[x] is a time-intensive function call):
Alice = Table[V[i],{i,1,300},{1000}];
Bob = Table[Table[V[i],{i,1,300}],{1000}]^tr;
Chris_pre = Table[V[i],{i,1,300}];
Chris = Table[Chris_pre,{1000}]^tr;
Alice, Bob, and Chris are identical matricies computed 3 slightly different ways. I find that Chris is computed 1000 times faster than Alice and Bob.
It is not surprising that Alice is computed 1000 times slower because, naively, the function V must be called 1000 more times than when Chris is computed. But it is very surprising that Bob is so slow, since he is computed identically to Chris except that Chris stores the intermediate step Chris_pre.
Why does Bob evaluate so slowly?
SECOND PROBLEM
Suppose I want to compile a function in Mathematica of the form
f(x)=x+y
where "y" is a constant fixed at compile time (but which I prefer not to directly replace in the code with its numerical because I want to be able to easily change it). If y's actual value is y=7.3, and I define
f1=Compile[{x},x+y]
f2=Compile[{x},x+7.3]
then f1 runs 50% slower than f2. How do I make Mathematica replace "y" with "7.3" when f1 is compiled, so that f1 runs as fast as f2?
EDIT:
I found an ugly workaround for the second problem:
f1=ReleaseHold[Hold[Compile[{x},x+z]]/.{z->y}]
There must be a better way...
You probably should've posted these as separate questions, but no worries!
Problem one
The problem with Alice is of course what you expect. The problem with Bob is that the inner Table is evaluated once per iteration of the outer Table. This is clearly visible with Trace:
Trace[Table[Table[i, {i, 1, 3}], {3}]]
{
Table[Table[i,{i,1,2}],{2}],
{Table[i,{i,1,2}],{i,1},{i,2},{1,2}},{Table[i,{i,1,2}],{i,1},{i,2},{1,2}},
{{1,2},{1,2}}
}
Line breaks added for emphasis, and yeah, the output of Trace on Table is a little weird, but you can see it. Clearly Mathematica could optimize this better, knowing that the outside table has no iterator, but for whatever reason, it doesn't take that into account. Only Chris does what you want, though you could modify Bob:
Transpose[Table[Evaluate[Table[V[i],{i,1,300}]],{1000}]]
This looks like it actually outperforms Chris by a factor of two or so, because it doesn't have to store the intermediate result.
Problem two
There's a simpler solution with Evaluate, though I expect it won't work with all possible functions to be compiled (i.e. ones that really should be Held):
f1 = Compile[{x}, Evaluate[x + y]];
You could also use a With:
With[{y=7.3},
f1 = Compile[{x}, x + y];
]
Or if y is defined elsewhere, use a temporary:
y = 7.3;
With[{z = y},
f1 = Compile[{x}, x + z];
]
I'm not an expert on Mathematica's scoping and evaluation mechanisms, so there could easily be a much better way, but hopefully one of those does it for you!
Your first problem has already been explained, but I want to point out that ConstantArray was introduced in Mathematica 6 to address this issue. Prior to that time Table[expr, {50}] was used for both fixed and changing expressions.
Since the introduction of ConstantArray there is clear separation between iteration with reevaluation, and simple duplication of an expression. You can see the behavior using this:
ConstantArray[Table[Pause[1]; i, {i, 5}], {50}] ~Monitor~ i
It takes five seconds to loop through Table because of Pause[1], but after that loop is complete it is not reevaluated and the 50 copies are immediately printed.
First problem
Have you checked the output of the Chris_pre computation? You will find that it is not a large matrix at all, since you're trying to store an intermediate result in a pattern, rather than a Variable. Try ChrisPre, instead. Then all the timings are comparable.
Second problem
Compile has a number of tricky restrictions on it's use. One issue is that you cannot refer to global variables. The With construct that was already suggested is the suggested way around this. If you want to learn more about Compile, check out Ted Ersek's tricks:
http://www.verbeia.com/mathematica/tips/Tricks.html

Resources