-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexample.pl
More file actions
170 lines (140 loc) · 4.19 KB
/
example.pl
File metadata and controls
170 lines (140 loc) · 4.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
% Mister X
% ========
%
% Although this problem has a straightforward solution, it does
% demonstrate the value of "Prolog thinking" in understanding the problem,
% which relates to nondeterminism -- especially "don't know"
% nondeterminism, and an appropriate use of "lemmas".
%
% Problem:
% --------
%
% Problem as posted to comp.lang.prolog by Thorsten Seelend. Also known as
% Hans Freudenthal's Impossible Puzzle.
%
% Mister X thinks about two integers between 1 and 100 excluding:
%
% MISTERX: Two integers, X and Y between 2 and 99 (My formalization of the
% given information)
two_integers( X, Y ) :-
between( 2, 98, X ),
between( X, 99, Y ).
% He tells Susan the Sum of them and Peter their Product. Their task is to
% get the two original values without telling each other the numbers that
% Mister X told them.
%
% After some time Peter says: "I can't say definitively which are the
% original numbers."
%
% PETER1: There is more than one pair of factors giving Product
property( peter1, Product ) :-
\+ unique_factors( Product ).
% Then Susan responds:
%
% "Neither can I, but I knew that you couldn't know it."
%
% SUSAN1: The product of every pair of summands giving Sum has the
% property PETER1
property( susan1, Sum ) :-
forall( ordered_summands(Sum, X, Y), peter1(X * Y) ).
% Peter: "Really? So now I know the original numbers".
%
% PETER2: exactly one pair of factors giving Product gives a sum with the
% property SUSAN1
property( peter2, Product ) :-
unique_solution( (ordered_factors(Product, X, Y), susan1(X+Y)) ).
% Susan: "Now I know them too".
%
% SUSAN2: exactly one pair of summands giving Sum has a product with the
% property PETER2
property( susan2, Sum ) :-
unique_solution( (ordered_summands(Sum, X, Y), peter2(X * Y)) ).
% Question: What are the two numbers that Mister X thought of?
%
% Unique solution
solve( X, Y ) :-
unique_solution( mister_x(X, Y) ).
mister_x( X, Y ) :-
two_integers( X, Y ),
Sum is X + Y,
Product is X * Y,
peter1( Product ),
susan1( Sum ),
peter2( Product ),
susan2( Sum ).
% Macros
% ------
peter1( Product ) :-
lemma( peter1, Product ).
peter2( Product ) :-
lemma( peter2, Product ).
susan1( Sum ) :-
lemma( susan1, Sum ).
susan2( Sum ) :-
lemma( susan2, Sum ).
% Lemmas
% ------
%
% lemma( +Property, +Expression )
%
% holds wherever Property holds for Expression.
%
% Asserted facts are used to record successful (positive) or failed
% (negative) demonstrations. This saves recomputation without changing the
% meaning of the pure program.
%
% Although the use of side-effects is generally undesirable, the use of
% lemmas is justified when the alternative is to compromise performance or
% clarity.
%
% Using lemmas or tabling to cache results is three orders of magnitude
% faster than recalculating each property every time it is used.
:- dynamic positive/2, negative/2.
lemma( Name, Expression ) :-
Value is Expression,
( positive( Value, Name ) ->
true
; \+ negative( Value, Name ) ->
( property(Name, Value) ->
assert( positive(Value, Name) )
; otherwise ->
assert( negative(Value, Name) ),
fail
)
).
% Supporting Predicates
% ---------------------
%
% ordered_summands( +Sum, ?X, ?Y )
%
% when X =< Y and Sum = X+Y. NB: Since X=<Y it follows that X =< Sum/2.
ordered_summands( Z, X, Y ) :-
Half is Z//2,
between( 2, Half, X ),
Y is Z - X,
between( X, 98, Y ).
% ordered_factors( +Product, ?X, ?Y )
%
% when X =< Y and Product = X × Y. NB: Since X=<Y it follows that X =<
% SQRT Product.
ordered_factors( Z, X, Y ) :-
integer_sqrt( Z, SqrtZ ),
between( 2, SqrtZ, X ),
Y is Z // X,
between( X, 99, Y ),
Z =:= X * Y.
% unique_factors( +Product )
%
% when Product has exactly one pair of factors.
unique_factors( Product ) :-
ordered_factors( Product, X, _Y ),
\+ (ordered_factors(Product, X1, _Y1), X1 =\= X).
% integer_sqrt( +N, ?Sqrt )
%
% when Sqrt^2 =< N and (Sqrt+1)^2 >= N.
integer_sqrt( N, Sqrt ) :-
Float is N * 1.0,
sqrt( Float, FSqrt ),
Sqrt is integer(FSqrt).
% Load a small library of Puzzle Utilities.
:- ensure_loaded( misc ).