-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathdefinitions.lisp
331 lines (306 loc) · 11.2 KB
/
definitions.lisp
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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
(in-package :trivia.benchmark)
#+sbcl
(declaim (sb-ext:muffle-conditions sb-ext:compiler-note))
(defvar *optimization* nil)
;;; Fibonacci computes several times the 18th Fibonacci number.
(defun fibonacci-form (matcher)
`(lambda (arg)
(declare (optimize ,@*optimization*)
#+sbcl
(sb-ext:muffle-conditions sb-ext:compiler-note))
(labels ((fib (x)
(,matcher x
(0 0)
(1 1)
(n (+ (fib (- n 1))
(fib (- n 2)))))))
(fib arg))))
;;; Eratosthene
;; (i.e. sieve of Eratosthenes
;; https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes) computes primes
;; numbers up to 1000, using associative list matching. The improvement
;; comes from the Inlining rules which avoids computing a substitution
;; unless the rule applies (i.e. the conditions are verified).
;;; Gomoku looks for five pawn on a go board, using list matching.
;; This example contains more than 40 patterns and illustrates the interest of test-sharing.
(defun gomoku-form (matcher)
`(lambda (v)
(declare (optimize ,@*optimization*)
#+sbcl
(sb-ext:muffle-conditions sb-ext:compiler-note))
(,matcher v
((or (simple-vector
1 _ _ _ _
_ 1 _ _ _
_ _ 1 _ _
_ _ _ 1 _
_ _ _ _ 1)
(simple-vector
_ _ _ _ 1
_ _ _ 1 _
_ _ 1 _ _
_ 1 _ _ _
1 _ _ _ _)
(simple-vector
1 _ _ _ _
1 _ _ _ _
1 _ _ _ _
1 _ _ _ _
1 _ _ _ _)
(simple-vector
_ 1 _ _ _
_ 1 _ _ _
_ 1 _ _ _
_ 1 _ _ _
_ 1 _ _ _)
(simple-vector
_ _ 1 _ _
_ _ 1 _ _
_ _ 1 _ _
_ _ 1 _ _
_ _ 1 _ _)
(simple-vector
_ _ _ 1 _
_ _ _ 1 _
_ _ _ 1 _
_ _ _ 1 _
_ _ _ 1 _)
(simple-vector
_ _ _ _ 1
_ _ _ _ 1
_ _ _ _ 1
_ _ _ _ 1
_ _ _ _ 1)
(simple-vector
1 1 1 1 1
_ _ _ _ _
_ _ _ _ _
_ _ _ _ _
_ _ _ _ _)
(simple-vector
_ _ _ _ _
1 1 1 1 1
_ _ _ _ _
_ _ _ _ _
_ _ _ _ _)
(simple-vector
_ _ _ _ _
_ _ _ _ _
1 1 1 1 1
_ _ _ _ _
_ _ _ _ _)
(simple-vector
_ _ _ _ _
_ _ _ _ _
_ _ _ _ _
1 1 1 1 1
_ _ _ _ _)
(simple-vector
_ _ _ _ _
_ _ _ _ _
_ _ _ _ _
_ _ _ _ _
1 1 1 1 1)) 1)
((or (simple-vector
0 _ _ _ _
_ 0 _ _ _
_ _ 0 _ _
_ _ _ 0 _
_ _ _ _ 0)
(simple-vector
_ _ _ _ 0
_ _ _ 0 _
_ _ 0 _ _
_ 0 _ _ _
0 _ _ _ _)
(simple-vector
0 _ _ _ _
0 _ _ _ _
0 _ _ _ _
0 _ _ _ _
0 _ _ _ _)
(simple-vector
_ 0 _ _ _
_ 0 _ _ _
_ 0 _ _ _
_ 0 _ _ _
_ 0 _ _ _)
(simple-vector
_ _ 0 _ _
_ _ 0 _ _
_ _ 0 _ _
_ _ 0 _ _
_ _ 0 _ _)
(simple-vector
_ _ _ 0 _
_ _ _ 0 _
_ _ _ 0 _
_ _ _ 0 _
_ _ _ 0 _)
(simple-vector
_ _ _ _ 0
_ _ _ _ 0
_ _ _ _ 0
_ _ _ _ 0
_ _ _ _ 0)
(simple-vector
0 0 0 0 0
_ _ _ _ _
_ _ _ _ _
_ _ _ _ _
_ _ _ _ _)
(simple-vector
_ _ _ _ _
0 0 0 0 0
_ _ _ _ _
_ _ _ _ _
_ _ _ _ _)
(simple-vector
_ _ _ _ _
_ _ _ _ _
0 0 0 0 0
_ _ _ _ _
_ _ _ _ _)
(simple-vector
_ _ _ _ _
_ _ _ _ _
_ _ _ _ _
0 0 0 0 0
_ _ _ _ _)
(simple-vector
_ _ _ _ _
_ _ _ _ _
_ _ _ _ _
_ _ _ _ _
0 0 0 0 0)) 0)
(_ 2))))
(defun gen-gomoku ()
(let ((v (make-array 25 :initial-element -1))
(total (+ 12 (random 13))))
(iter (for n below total)
(iter (for index = (random 25))
(when (minusp (aref v index))
(setf (aref v index) (random 2))
(leave))))
v))
(defparameter *gomoku-testset* (iter (repeat 2000000) (collect (gen-gomoku))))
;;; Langton is a program which computes the 1000th iteration of a cellular automaton, us-
;; ing pattern matching to implement the transition function. This example contains more
;; than 100 (ground) patterns. The optimized program is optimal in the sense that a pair
;; hmm seems difficult
;;; string-matching searches for a list of strings if a given string
;;; matches against one of them
(defun strmatch-form (matcher)
`(lambda (string)
(declare (optimize ,@*optimization*)
#+sbcl
(sb-ext:muffle-conditions sb-ext:compiler-note))
(,matcher string
((or "Lorem" "ipsum" "dolor" "sit" "amet" "consectetur" "adipisicing"
"elit" "sed" "do" "eiusmod" "tempor" "incididunt" "ut" "labore" "et"
"dolore" "magna" "aliqua" "Ut" "enim" "ad" "minim" "veniam" "quis"
"nostrud" "exercitation" "ullamco" "laboris" "nisi" "ut" "aliquip" "ex"
"ea" "commodo" "consequat" "Duis" "aute" "irure" "dolor" "in"
"reprehenderit" "in" "voluptate" "velit" "esse" "cillum" "dolore" "eu"
"fugiat" "nulla" "pariatur" "Excepteur" "sint" "occaecat" "cupidatat"
"non" "proident" "sunt" "in" "culpa" "qui" "officia" "deserunt"
"mollit" "anim" "id" "est" "laborum")
t))))
(defvar *longstr*
(list "Sed" "ut" "perspiciatis" "unde" "omnis" "iste" "natus" "error" "sit"
"voluptatem" "accusantium" "doloremque" "laudantium" "totam" "rem"
"aperiam" "eaque" "ipsa" "quae" "ab" "illo" "inventore" "veritatis"
"et" "quasi" "architecto" "beatae" "vitae" "dicta" "sunt"
"explicabo" "Nemo" "enim" "ipsam" "voluptatem" "quia" "voluptas"
"sit" "aspernatur" "aut" "odit" "aut" "fugit" "sed" "quia"
"consequuntur" "magni" "dolores" "eos" "qui" "ratione" "voluptatem"
"sequi" "nesciunt" "neque" "porro" "quisquam" "est" "qui" "dolorem"
"ipsum" "quia" "dolor" "sit" "amet" "consectetur" "adipisci"
"velit" "sed" "quia" "non" "numquam" "eius" "modi" "tempora"
"incidunt" "ut" "labore" "et" "dolore" "magnam" "aliquam" "quaerat"
"voluptatem" "Ut" "enim" "ad" "minima" "veniam" "quis" "nostrum"
"exercitationem" "ullam" "corporis" "suscipit" "laboriosam" "nisi"
"ut" "aliquid" "ex" "ea" "commodi" "consequatur""? Quis" "autem" "vel"
"eum" "iure" "reprehenderit" "qui" "in" "ea" "voluptate" "velit"
"esse" "quam" "nihil" "molestiae" "consequatur" "vel" "illum" "qui"
"dolorem" "eum" "fugiat" "quo" "voluptas" "nulla" "pariatur"
"At" "vero" "eos" "et" "accusamus" "et" "iusto" "odio" "dignissimos"
"ducimus" "qui" "blanditiis" "praesentium" "voluptatum" "deleniti"
"atque" "corrupti" "quos" "dolores" "et" "quas" "molestias"
"excepturi" "sint" "obcaecati" "cupiditate" "non" "provident" "similique" "sunt" "in"
"culpa" "qui" "officia" "deserunt" "mollitia" "animi" "id" "est" "laborum" "et" "dolorum"
"fuga" "Et" "harum" "quidem" "rerum" "facilis" "est" "et" "expedita" "distinctio" "Nam"
"libero" "tempore" "cum" "soluta" "nobis" "est" "eligendi" "optio" "cumque" "nihil"
"impedit" "quo" "minus" "id" "quod" "maxime" "placeat" "facere" "possimus" "omnis"
"voluptas" "assumenda" "est" "omnis" "dolor" "repellendus" "Temporibus" "autem"
"quibusdam" "et" "aut" "officiis" "debitis" "aut" "rerum" "necessitatibus" "saepe"
"eveniet" "ut" "et" "voluptates" "repudiandae" "sint" "et" "molestiae" "non"
"recusandae" "Itaque" "earum" "rerum" "hic" "tenetur" "a" "sapiente" "delectus" "ut" "aut"
"reiciendis" "voluptatibus" "maiores" "alias" "consequatur" "aut" "perferendis"
"doloribus" "asperiores" "repellat"))
;;; benchmark maker
(defun run-benchmark (matcher name)
(format t "~&-------------------- ~a ----------------------------------------~&" name)
(list
(block nil
(let ((fn (handler-case (compile nil (fibonacci-form matcher))
(error (c)
(print c)
(return nil)))))
(format t "~&Running Fibonacci")
(time (iter (repeat 200)
(collect (funcall fn 32))))))
(block nil
(let ((fn (handler-case (compile nil (gomoku-form matcher))
(error (c)
(print c)
(return nil)))))
(format t "~&Running Gomoku")
(time
(iter outer
(repeat 100)
(iter (for test in *gomoku-testset*)
(case (funcall fn test)
(0 (in outer (counting t into black)))
(1 (in outer (counting t into white)))))
(finally
(format t "~& Black : White : Notany = ~a : ~a : ~a "
black white
(- (* 30 (length *gomoku-testset*))
black white))
(return-from outer (list black white)))))))
#+nil
(let ((fn (compile nil (eratosthenes-form matcher)))
(input 100000))
(format t "~&Running Eratosthenes-sieve with input=~a" input)
(let ((res (time (funcall fn input))))
(format t "~&~a primes" (length res))
res))
(block nil
(let ((fn (handler-case (compile nil (strmatch-form matcher))
(error (c)
(print c)
(return nil)))))
(format t "~&Running String-match")
(time (let ((sum (iter (repeat 10000)
(summing
(iter (for word in *longstr*)
(count (funcall fn word)))))))
(format t "~& Matched ~a times" sum)
sum))))))
(defun run-benchmarks (&optional *optimization*)
(let ((balland (let ((*optimizer* :balland2006))
(run-benchmark 'trivia:match :balland)))
(optima (run-benchmark 'optima:match :optima))
(trivia (let ((*optimizer* :trivial))
(run-benchmark 'trivia:match :trivial))))
(print balland)
(print optima)
(print trivia)))
#+nil
(print
(let ((*optimizer* :balland2006))
(sb-cltl2:macroexpand-all
(gomoku-form 'trivia:match))))
;; (sb-cltl2:macroexpand-all
;; (nimoku-form 'trivia:match))