Skip to content

Commit c17f7c3

Browse files
committed
day 77
1 parent 57b2096 commit c17f7c3

File tree

1 file changed

+371
-0
lines changed

1 file changed

+371
-0
lines changed

day 77 - unification.ipynb

Lines changed: 371 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,371 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"## algorithm"
8+
]
9+
},
10+
{
11+
"cell_type": "code",
12+
"execution_count": 1,
13+
"metadata": {
14+
"collapsed": false
15+
},
16+
"outputs": [],
17+
"source": [
18+
"class Unify:\n",
19+
" \n",
20+
" def __init__(self):\n",
21+
" self.reference = {} # variable bindings\n",
22+
" self.checkpoint = [] # unification checkpoints\n",
23+
" self.var_ctx = 0 # unique variable id\n",
24+
"\n",
25+
" def variable(self, *args):\n",
26+
" self.var_ctx += 1\n",
27+
" return ['%s_%d' % (var, self.var_ctx) for var in args]\n",
28+
"\n",
29+
" def __call__(self, var_x, var_y):\n",
30+
" # resolve variable X\n",
31+
" while isinstance(var_x, str) and var_x in self.reference:\n",
32+
" var_x = self.reference[var_x]\n",
33+
"\n",
34+
" # resolve variable Y\n",
35+
" while isinstance(var_y, str) and var_y in self.reference:\n",
36+
" var_y = self.reference[var_y]\n",
37+
"\n",
38+
" # unified to self?\n",
39+
" if isinstance(var_x, str) and isinstance(var_y, str):\n",
40+
" if var_x == var_y:\n",
41+
" return True\n",
42+
"\n",
43+
" # unify free variable X\n",
44+
" if isinstance(var_x, str):\n",
45+
" self.reference[var_x] = var_y\n",
46+
" self.checkpoint[-1].append(var_x)\n",
47+
" return True\n",
48+
"\n",
49+
" # unify free variable Y\n",
50+
" if isinstance(var_y, str):\n",
51+
" self.reference[var_y] = var_x\n",
52+
" self.checkpoint[-1].append(var_y)\n",
53+
" return True\n",
54+
"\n",
55+
" # tuple is unified element-wise\n",
56+
" if isinstance(var_x, tuple) and isinstance(var_y, tuple):\n",
57+
" if len(var_x) == len(var_y):\n",
58+
" return all(self(i, j) for i, j in zip(var_x, var_y))\n",
59+
"\n",
60+
" # atom is unified on equality\n",
61+
" if isinstance(var_x, int) and isinstance(var_y, int):\n",
62+
" if var_x == var_y:\n",
63+
" return True\n",
64+
"\n",
65+
" # not unifiable\n",
66+
" raise KeyError()\n",
67+
"\n",
68+
" def __getitem__(self, var):\n",
69+
" # resolve tuple by members\n",
70+
" if isinstance(var, tuple):\n",
71+
" return tuple(self[i] for i in var)\n",
72+
"\n",
73+
" # resolve variable recursively\n",
74+
" if isinstance(var, str):\n",
75+
" if var in self.reference:\n",
76+
" return self[self.reference[var]]\n",
77+
" return var\n",
78+
"\n",
79+
" # atomic value\n",
80+
" if isinstance(var, int):\n",
81+
" return var\n",
82+
"\n",
83+
" # invalid object\n",
84+
" raise TypeError()\n",
85+
"\n",
86+
" def __enter__(self):\n",
87+
" # store unification checkpoint\n",
88+
" self.checkpoint.append([])\n",
89+
"\n",
90+
" def __exit__(self, exc_type, *args):\n",
91+
" # remove checkpoint and unbind variables\n",
92+
" for var in self.checkpoint.pop():\n",
93+
" if var in self.reference:\n",
94+
" del self.reference[var]\n",
95+
"\n",
96+
" # suppress exception\n",
97+
" if exc_type is not GeneratorExit:\n",
98+
" return True"
99+
]
100+
},
101+
{
102+
"cell_type": "code",
103+
"execution_count": 2,
104+
"metadata": {
105+
"collapsed": true
106+
},
107+
"outputs": [],
108+
"source": [
109+
"def conc(PREFIX, SUFFIX, RESULT):\n",
110+
" HEAD, TAIL, CONC = unify.variable('HEAD', 'TAIL', 'CONC')\n",
111+
"\n",
112+
" with unify:\n",
113+
" unify(PREFIX, EMPTY) and unify(SUFFIX, RESULT)\n",
114+
" yield\n",
115+
"\n",
116+
" with unify:\n",
117+
" unify(PREFIX, (HEAD, TAIL)) and unify(RESULT, (HEAD, CONC))\n",
118+
" yield from conc(TAIL, SUFFIX, CONC)"
119+
]
120+
},
121+
{
122+
"cell_type": "markdown",
123+
"metadata": {},
124+
"source": [
125+
"## run"
126+
]
127+
},
128+
{
129+
"cell_type": "code",
130+
"execution_count": 3,
131+
"metadata": {
132+
"collapsed": false
133+
},
134+
"outputs": [],
135+
"source": [
136+
"unify = Unify()"
137+
]
138+
},
139+
{
140+
"cell_type": "code",
141+
"execution_count": 4,
142+
"metadata": {
143+
"collapsed": true
144+
},
145+
"outputs": [],
146+
"source": [
147+
"EMPTY = tuple()\n",
148+
"prefix = (1, (2, EMPTY))\n",
149+
"suffix = (3, (4, EMPTY))\n",
150+
"result = (1, (2, (3, (4, EMPTY))))"
151+
]
152+
},
153+
{
154+
"cell_type": "markdown",
155+
"metadata": {},
156+
"source": [
157+
"#### concatenate PREFIX and SUFFIX"
158+
]
159+
},
160+
{
161+
"cell_type": "code",
162+
"execution_count": 5,
163+
"metadata": {
164+
"collapsed": false
165+
},
166+
"outputs": [
167+
{
168+
"name": "stdout",
169+
"output_type": "stream",
170+
"text": [
171+
"(1, (2, (3, (4, ()))))\n"
172+
]
173+
}
174+
],
175+
"source": [
176+
"for _ in conc(prefix, suffix, 'RESULT'):\n",
177+
" print(unify['RESULT'])"
178+
]
179+
},
180+
{
181+
"cell_type": "markdown",
182+
"metadata": {},
183+
"source": [
184+
"#### what was concatenated to PREFIX if RESULT is this?"
185+
]
186+
},
187+
{
188+
"cell_type": "code",
189+
"execution_count": 6,
190+
"metadata": {
191+
"collapsed": false
192+
},
193+
"outputs": [
194+
{
195+
"name": "stdout",
196+
"output_type": "stream",
197+
"text": [
198+
"(3, (4, ()))\n"
199+
]
200+
}
201+
],
202+
"source": [
203+
"for _ in conc(prefix, 'SUFFIX', result):\n",
204+
" print(unify['SUFFIX'])"
205+
]
206+
},
207+
{
208+
"cell_type": "markdown",
209+
"metadata": {},
210+
"source": [
211+
"#### this is super cool! if RESULT is this, what was PREFIX and SUFFIX?"
212+
]
213+
},
214+
{
215+
"cell_type": "code",
216+
"execution_count": 7,
217+
"metadata": {
218+
"collapsed": false
219+
},
220+
"outputs": [
221+
{
222+
"name": "stdout",
223+
"output_type": "stream",
224+
"text": [
225+
"possible answer is () and (1, (2, (3, (4, ()))))\n",
226+
"possible answer is (1, ()) and (2, (3, (4, ())))\n",
227+
"possible answer is (1, (2, ())) and (3, (4, ()))\n",
228+
"possible answer is (1, (2, (3, ()))) and (4, ())\n",
229+
"possible answer is (1, (2, (3, (4, ())))) and ()\n"
230+
]
231+
}
232+
],
233+
"source": [
234+
"for _ in conc('PREFIX', 'SUFFIX', result):\n",
235+
" print('possible answer is', unify['PREFIX'], 'and', unify['SUFFIX'])"
236+
]
237+
},
238+
{
239+
"cell_type": "markdown",
240+
"metadata": {},
241+
"source": [
242+
"#### if PREFIX and SUFFIX are concatenated, would this be RESULT?"
243+
]
244+
},
245+
{
246+
"cell_type": "code",
247+
"execution_count": 8,
248+
"metadata": {
249+
"collapsed": false
250+
},
251+
"outputs": [
252+
{
253+
"name": "stdout",
254+
"output_type": "stream",
255+
"text": [
256+
"yes\n"
257+
]
258+
}
259+
],
260+
"source": [
261+
"for _ in conc(prefix, suffix, result):\n",
262+
" print('yes')\n",
263+
" break\n",
264+
"else:\n",
265+
" print('no')"
266+
]
267+
},
268+
{
269+
"cell_type": "code",
270+
"execution_count": 9,
271+
"metadata": {
272+
"collapsed": false
273+
},
274+
"outputs": [
275+
{
276+
"name": "stdout",
277+
"output_type": "stream",
278+
"text": [
279+
"yes\n"
280+
]
281+
}
282+
],
283+
"source": [
284+
"for _ in conc(prefix, suffix, result):\n",
285+
" print('yes')\n",
286+
" break\n",
287+
"else:\n",
288+
" print('no')"
289+
]
290+
},
291+
{
292+
"cell_type": "markdown",
293+
"metadata": {},
294+
"source": [
295+
"## most people won't solve this one"
296+
]
297+
},
298+
{
299+
"cell_type": "code",
300+
"execution_count": 10,
301+
"metadata": {
302+
"collapsed": false
303+
},
304+
"outputs": [
305+
{
306+
"name": "stdout",
307+
"output_type": "stream",
308+
"text": [
309+
"PREFIX = ()\n",
310+
"SUFFIX = RESULT\n",
311+
"RESULT = RESULT\n",
312+
"\n",
313+
"PREFIX = ('HEAD_18', ())\n",
314+
"SUFFIX = CONC_18\n",
315+
"RESULT = ('HEAD_18', 'CONC_18')\n",
316+
"\n",
317+
"PREFIX = ('HEAD_18', ('HEAD_19', ()))\n",
318+
"SUFFIX = CONC_19\n",
319+
"RESULT = ('HEAD_18', ('HEAD_19', 'CONC_19'))\n",
320+
"\n",
321+
"PREFIX = ('HEAD_18', ('HEAD_19', ('HEAD_20', ())))\n",
322+
"SUFFIX = CONC_20\n",
323+
"RESULT = ('HEAD_18', ('HEAD_19', ('HEAD_20', 'CONC_20')))\n",
324+
"\n",
325+
"PREFIX = ('HEAD_18', ('HEAD_19', ('HEAD_20', ('HEAD_21', ()))))\n",
326+
"SUFFIX = CONC_21\n",
327+
"RESULT = ('HEAD_18', ('HEAD_19', ('HEAD_20', ('HEAD_21', 'CONC_21'))))\n",
328+
"\n"
329+
]
330+
}
331+
],
332+
"source": [
333+
"for _ in zip(range(5), conc('PREFIX', 'SUFFIX', 'RESULT')):\n",
334+
" print('PREFIX =', unify['PREFIX'])\n",
335+
" print('SUFFIX =', unify['SUFFIX'])\n",
336+
" print('RESULT =', unify['RESULT'])\n",
337+
" print()"
338+
]
339+
},
340+
{
341+
"cell_type": "code",
342+
"execution_count": null,
343+
"metadata": {
344+
"collapsed": true
345+
},
346+
"outputs": [],
347+
"source": []
348+
}
349+
],
350+
"metadata": {
351+
"kernelspec": {
352+
"display_name": "Python 3",
353+
"language": "python",
354+
"name": "python3"
355+
},
356+
"language_info": {
357+
"codemirror_mode": {
358+
"name": "ipython",
359+
"version": 3
360+
},
361+
"file_extension": ".py",
362+
"mimetype": "text/x-python",
363+
"name": "python",
364+
"nbconvert_exporter": "python",
365+
"pygments_lexer": "ipython3",
366+
"version": "3.6.0"
367+
}
368+
},
369+
"nbformat": 4,
370+
"nbformat_minor": 2
371+
}

0 commit comments

Comments
 (0)