-
Notifications
You must be signed in to change notification settings - Fork 0
/
memoize-raw.lisp
4268 lines (3666 loc) · 160 KB
/
memoize-raw.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
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
; ACL2 Version 6.4 -- A Computational Logic for Applicative Common Lisp
; Copyright (C) 2014, Regents of the University of Texas
; This version of ACL2 is a descendent of ACL2 Version 1.9, Copyright
; (C) 1997 Computational Logic, Inc. See the documentation topic NOTE-2-0.
; This program is free software; you can redistribute it and/or modify
; it under the terms of the LICENSE file distributed with ACL2.
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; LICENSE for more details.
; Written by: Matt Kaufmann and J Strother Moore
; email: [email protected] and [email protected]
; Department of Computer Science
; University of Texas at Austin
; Austin, TX 78712 U.S.A.
; memoize-raw.lisp -- Raw lisp definitions for memoization functions, only to
; be included in the experimental HONS version of ACL2.
; The original version of this file was contributed by Bob Boyer and
; Warren A. Hunt, Jr. The design of this system of Hash CONS,
; function memoization, and fast association lists (applicative hash
; tables) was initially implemented by Boyer and Hunt.
(in-package "ACL2")
(eval-when
(:execute :compile-toplevel :load-toplevel)
#-hons
;; [Jared]: Is there a real reason that memoization needs hons?
(error "memoize-raw.lisp should only be included when #+hons is set.")
;; [Jared]: MEMOIZE IS NOT THREAD SAFE. I am getting rid of all of the locking
;; stuff that was here before. It was just muddying the waters and making
;; things harder to understand. We'll need to think hard and do it right,
;; later.
;; One may comment out the following PUSHNEW and rebuild to get profiling
;; times not based upon the curious and wondrous RDTSC instruction of some x86
;; processors. On a machine with several cores, the RDTSC values returned by
;; different cores may be slightly different, which could lead one into such
;; nonsense as instructions apparently executing in negative time, when timing
;; starts on one core and finishes on another. To some extent we ignore such
;; RDTSC nonsense, but we still can report mysterious results since we have no
;; clue about which core we are running on in CCL.
#+Clozure
(when (fboundp 'ccl::rdtsc) (pushnew :RDTSC *features*))
)
; MFIXNUM ---------------------------------------------------------------------
;
; We use the type mfixnum for counting things that are best counted in the
; trillions or more. Mfixnums happen to coincide with regular fixnums on
; 64-bit CCL and SBCL.
;
; [Jared]: this seems fine, probably a good idea.
(defconstant most-positive-mfixnum (1- (expt 2 60)))
(deftype mfixnum ()
`(integer ,(- -1 most-positive-mfixnum)
,most-positive-mfixnum))
; OUR-SYNTAX -----------------------------------------------------------------
;
; [Jared]: This is just some printing stuff. I don't think I need/want any of
; this in the new memoize library. But there's nothing really wrong with it.
; A big part of the complexity here was probably due to supporting the old
; compact-print/compact-read mechanism, but we just don't need that anymore
; with serialize.
(defmacro our-syntax (&rest args)
"OUR-SYNTAX is similar to Common Lisp's WITH-STANDARD-IO-SYNTAX.
The settings in OUR-SYNTAX are oriented towards reliable, standard,
vanilla, mechanical reading and printing, and less towards human
readability.
Please, before changing the following, consider existing uses of
this macro insofar as the changes might impact reliable, standard,
vanilla, mechanical printing. Especially consider
COMPACT-PRINT-FILE. Consider using OUR-SYNTAX-NICE."
; We use the *ACL2-PACKAGE* and the *ACL2-READTABLE* because we use
; them almost all the time in our code.
`(with-standard-io-syntax
; Note for GCL:
; As of late May 2013, with-standard-io-syntax seems to work properly in ANSI
; GCL. If necessary one could use our-with-standard-io-syntax here, but better
; would be to use an up-to-date ANSI GCL.
(let ((*package* *acl2-package*)
(*readtable* *acl2-readtable*))
,@args)))
(defmacro our-syntax-nice (&rest args)
;; OUR-SYNTAX-NICE offers slightly more pleasant human readabilty.
`(our-syntax
(setq *print-case* :downcase)
(setq *print-pretty* t)
(setq *print-readably* nil)
(setq *print-right-margin* 70)
(setq *print-miser-width* 100)
,@args))
(defmacro our-syntax-brief (&rest args)
;; Within OUR-SYNTAX-BRIEF printing may be greatly abbreviated.
`(our-syntax-nice
(setq *print-length* 10)
(setq *print-level* 5)
(setq *print-lines* 10)
,@args))
(defmacro ofn (&rest r) ; For forming strings.
`(our-syntax (format nil ,@r)))
(defun-one-output ofnum (n) ; For forming numbers.
(check-type n number)
(if (= n 0) (setq n 0))
(our-syntax
(cond ((typep n '(integer -99 999))
(format nil "~8d" n))
((or (< -1000 n -1/100)
(< 1/100 n 1000))
(format nil "~8,2f" n))
(t (format nil "~8,2e" n)))))
(defmacro ofni (&rest r) ; For forming symbols in package ACL2.
`(our-syntax (intern (format nil ,@r) *acl2-package*)))
(defmacro ofnm (&rest r) ; For forming uninterned symbols.
`(our-syntax (make-symbol (format nil ,@r))))
(defmacro oft (&rest r) ; For writing to *standard-output*.
`(progn (format t ,@r)
(force-output *standard-output*)))
(defmacro oftr (&rest r) ; For writing to *trace-output*.
`(progn (format *trace-output* ,@r)
(force-output *trace-output*)))
; Number of arguments ---------------------------------------------------------
;
; [Jared]: dealt with this in books/memoize/numargs
(defv *number-of-arguments-and-values-ht*
(let ((ht (make-hash-table)))
(declare (hash-table ht))
(loop for pair in
'((bad-lisp-objectp . (1 . 1))
(apropos . (nil . 0))
(aref . (nil . 1))
(array-displacement . (1 . 2))
(decode-float . (1 . 3))
(expansion-alist-pkg-names-memoize . (1 . 1))
(fchecksum-obj . (1 . 1))
(worse-than . (2 . 1))
(find-symbol . (nil . 2))
(function . (nil . 1))
(get-properties . (2 . 3))
(gethash . (nil . 2))
(integer-decode-float (1 . 3))
(intern . (nil . 2))
(lambda . (nil . 1))
(list . (nil . 1))
(list* . (nil . 1))
(macroexpand . (nil . 2))
(macroexpand-1 . (nil . 2))
(pprint-dispatch . (nil . 2))
(prog1 . (nil . 1))
(prog2 . (nil . 1))
(quote . (1 . 1))) do
(setf (gethash (car pair) ht)
(cdr pair)))
(loop for sym in
'(car cdr caar cadr cdar cddr caaar cadar cdaar
cddar caadr caddr cdadr cdddr caaaar cadaar cdaaar cddaar
caadar caddar cdadar cdddar caaadr cadadr cdaadr cddadr
caaddr cadddr cdaddr cddddr) do
(setf (gethash sym ht) '(1 . 1)))
ht)
"The hash table *NUMBER-OF-ARGUMENTS-AND-VALUES-HT* maps a symbol fn
to a cons pair (a . d), where a is the number of inputs and d is the
number of outputs of fn. NIL for a or d indicates 'don't know'.")
(declaim (hash-table *number-of-arguments-and-values-ht*))
(defun-one-output input-output-number-error (fn)
;; [Jared]: bozo this is horrible, we should provide an sane interface
;; to this instead of just exposing it...
(format t "What is the number of inputs and output of ~a, please? ~%; To ~
assert that ~a takes, say, 2 inputs and returns 1 output, do ~% ~
(setf (gethash '~a acl2::*number-of-arguments-and-values-ht*) ~
(cons 2 1))."
fn fn fn)
(error "input-output-number-error: **: ~a" fn))
(defun-one-output number-of-arguments (fn)
;; A NIL value returned by NUMBER-OF-ARGUMENTS means 'don't know'.
(let* ((state *the-live-state*)
(w (w state))
(pair (gethash fn *number-of-arguments-and-values-ht*)))
(cond
((not (symbolp fn)) nil)
((and (consp pair) (integerp (car pair))) (car pair))
((let ((formals (getprop fn 'formals t 'current-acl2-world w)))
(and (not (eq t formals))
(length formals))))
((not (fboundp fn)) nil)
((macro-function fn) nil)
((special-operator-p fn) nil)
#+Clozure
((multiple-value-bind (req opt restp keys)
(ccl::function-args (symbol-function fn))
(and (null restp)
(null keys)
(integerp req)
(eql opt 0)
req)))
(t nil))))
(defun-one-output number-of-return-values (fn)
;; A NIL value returned by NUMBER-OF-RETURN-VALUES means 'don't know'.
(let*
((pair (gethash fn *number-of-arguments-and-values-ht*))
(state *the-live-state*)
(w (w state)))
(cond
((not (symbolp fn)) nil)
((and (consp pair) (integerp (cdr pair))) (cdr pair))
((member fn '(let let* mv-let progn if return-last))
(error "It is curious to ask about 'the' number of return values of ~a ~
because the answer is that it depends."
fn))
((not (eq t (getprop fn 'formals t 'current-acl2-world w)))
(len (stobjs-out fn w))))))
; Timing Utilities ------------------------------------------------------------
;
; [Jared]: dealt with this in books/memoize/timer.lsp
(defg *float-ticks/second* 1.0)
(defg *float-internal-time-units-per-second*
(float internal-time-units-per-second))
(declaim (float *float-ticks/second*
*float-internal-time-units-per-second*))
(defabbrev internal-real-time ()
#+(and RDTSC (not 32-bit-target)) ; faster for 64
(the mfixnum (ccl::rdtsc))
#+(and RDTSC 32-bit-target) ; slower for 32
(the mfixnum (mod (ccl::rdtsc64) most-positive-mfixnum))
#-RDTSC (the mfixnum (mod (get-internal-real-time)
most-positive-fixnum)))
(defun-one-output float-ticks/second-init ()
(setq *float-ticks/second*
#+RDTSC
(let ((i1 (ccl::rdtsc64))
(i2 (progn (sleep .01) (ccl::rdtsc64))))
(if (>= i2 i1)
(* 100 (float (- i2 i1)))
(error "(float-ticks/second-init).")))
#-RDTSC
*float-internal-time-units-per-second*)
(check-type *float-ticks/second*
(and float (satisfies plusp))))
; SAFE-INCF ------------------------------------------------------------------
;
; [Jared]: this is horrible and is bombing out on us in some big scripts. we
; probably would rather wrap around for performance counting than cause an
; error, or, can we maybe even just use bignums here?
(defun-one-output safe-incf-aux-error (x inc where)
(error "~%; SAFE-INCF-AUX: ** Error: ~a."
(list :x x :inc inc :where where)))
(defmacro safe-incf-aux (x inc where)
(cond
((not (or (symbolp inc)
(and (< inc most-positive-mfixnum)
(> inc 0))))
(safe-incf-aux-error x inc where))
((and (true-listp x)
(equal (len x) 3)
(member (car x) '(aref svref))
(symbolp (nth 1 x))
(consp (nth 2 x)))
(let ((idx (make-symbol "IDX")))
`(let ((,idx (the fixnum ,(nth 2 x))))
(declare (type fixnum ,idx))
(safe-incf (,(nth 0 x)
,(nth 1 x)
,idx)
,inc
',where))))
(t (let ((v (make-symbol "V")))
`(let ((,v (the mfixnum ,x)))
(declare (type mfixnum ,v))
(cond ((<= ,v (the mfixnum
(- most-positive-mfixnum
(the mfixnum ,inc))))
(setf (the mfixnum ,x)
(the mfixnum (+ ,v (the mfixnum ,inc))))
nil)
(t (safe-incf-aux-error ',x ',inc
',where))))))))
(defmacro safe-incf (x inc &optional where)
"SAFE-INCF is a raw Lisp macro that behaves the same as INCF when
both X and INC are nonnegative MFIXNUMs and their sum is a
nonnegative MFIXNUM. In a call of (SAFE-INCF x inc), X must be a
place that holds an MFIXNUM. INC must evaluate to an MFIXNUM. Both
X and INC must evaluate without side effects, so that it is
impossible to tell which was executed first or whether only one or
both were executed. If INC is not positive, no update takes place
at all. Otherwise, if the sum of the values of X and INC is not an
MFIXNUM, which is tested without causing an error, a run-time error
will be caused. Else, if the sum is an MFIXNUM then, as with INCF,
the place X will be set to hold the sum of the old value of that
place and the value of INC. The value returned by SAFE-INCF is NIL.
Caution: INC may be evaluated first, which is why side effects are
prohibited.
An optional third parameter is merely to help with error location
identification.
In (SAFE-INCF (AREF A (FOO)) INC), (FOO) is only evaluted once.
Same for SVREF."
(cond ((integerp inc)
(if (<= inc 0)
nil
`(safe-incf-aux ,x ,inc ,where)))
((symbolp inc)
`(if (>= 0 (the mfixnum ,inc))
nil
(safe-incf-aux ,x ,inc ,where)))
(t (let ((incv (make-symbol "INCV")))
`(let ((,incv (the mfixnum ,inc)))
(declare (type mfixnum ,incv))
(if (>= 0 ,incv)
nil
(safe-incf-aux ,x ,incv ,where)))))))
; PONSING ---------------------------------------------------------------------
;
; [Jared]: dealt with this in books/memoize/pons.lsp
(defparameter *count-pons-calls* t
"If *COUNT-PONS-CALLS*, then each call of PONS increments
*PONS-CALL-COUNTER* by 1, and each call of PONS that does not find
the desired PONS to already exist increments *PONS-MISSES-COUNTER*
by 1.")
(defg *pons-call-counter* 0)
(defg *pons-misses-counter* 0)
(declaim (type mfixnum *pons-call-counter*))
(declaim (type mfixnum *pons-misses-counter*))
(defmacro maybe-count-pons-calls ()
(and *count-pons-calls*
'(safe-incf *pons-call-counter* 1 maybe-count-pons-calls)))
(defmacro maybe-count-pons-misses ()
(and *count-pons-calls*
'(safe-incf *pons-misses-counter* 1 maybe-count-pons-misses)))
(defun-one-output assoc-no-error-at-end (x l)
;; We assume that every element of L is CONSP.
(if (typep x '(or cons symbol (and array string)))
(loop (if (consp l)
(let ((al (car l)))
(if (eq x (car al))
(return al)
(setq l (cdr l))))
(return nil)))
(loop (if (consp l)
(let ((al (car l)))
(if (eql x (car al))
(return al)
(setq l (cdr l))))
(return nil)))))
(defun-one-output too-long (x n)
(declare (type fixnum n))
;; (TOO-LONG x n) == (> (LENGTH x) n) provided x a noncircular list and
;; n is a nonnegative fixnum. TOO-LONG is perhaps faster than LENGTH
;; because (a) LENGTH has to worry about its argument being a circular
;; list, (b) LENGTH may worry about the answer exceeding
;; MOST-POSITIVE-FIXNUM, and (c) LENGTH must consider the possibility
;; that its argument is a vector.
(loop (cond ((atom x) (return nil))
((eql n 0) (return t))
(t (setq x (cdr x))
(setq n (the fixnum (1- n)))))))
(defconstant atom-case-fudge (+ 129 (expt 2 25)))
(defconstant most-positive-fudge (1- (expt 2 24)))
(defconstant most-negative-fudge (- (expt 2 24)))
(defconstant -most-negative-fudge (- most-negative-fudge))
#+Clozure
(defun-one-output atom-case (s)
(cond
((symbolp s)
(cond ((eq s nil) 0)
((eq s t) 1)
(t (let ((v (get (the symbol s) 'hons-hash-key)))
(cond ((null v)
(let ((c (ccl::static-cons s nil)))
(setq v (+ atom-case-fudge
(the fixnum (ccl::%staticp c))))
(setf (get (the symbol s) 'hons-hash-key) c)
(rplacd (the cons c) v)
v))
(t (cdr (the cons v))))))))
((and (typep s 'fixnum)
(> (the fixnum s) most-negative-fudge)
(<= (the fixnum s) most-positive-fudge))
(the fixnum (+ -most-negative-fudge (the fixnum s))))))
(defmacro sqmpf ()
(isqrt most-positive-fixnum))
(defmacro hmnf ()
; Half MOST-NEGATIVE-FIXNUM.
(ceiling (/ most-negative-fixnum 2)))
(defmacro static-hons-shift ()
(ceiling (/ (integer-length most-positive-fixnum) 2)))
#+Clozure
(defun-one-output addr-for (x y)
(let ((idx (let ((n (ccl::%staticp x)))
(cond (n (+ atom-case-fudge (the fixnum n)))
(t (atom-case x)))))
(large-case nil))
(cond (idx (cond ((and (typep idx 'fixnum)
(< (the fixnum idx) (sqmpf)) nil))
(t (setq large-case t))))
(t (return-from addr-for nil)))
(let ((idy (let ((n (ccl::%staticp y)))
(cond (n (+ atom-case-fudge (the fixnum n)))
(t (atom-case y))))))
(cond (idy (cond ((and (typep idy 'fixnum)
(< (the fixnum idy) (sqmpf))) nil)
(t (setq large-case t))))
(t (return-from addr-for nil)))
; ADDR-FOR is 1-1, in a sense, for a two argument function, when not
; NIL. That is, for all ACL2 objects x1, x2, y1, and y1, if (addr-for
; x1 y1) is not NIL and is equal to (addr-for x2 y2), then x1 is equal
; to x2 and y1 is equal to y2.
; Here is a sketch of a proof that if mpf = 2^60-1 and mnf = -2^60,
; then the ranges of large-case and the non-large case of ADDR-FOR do
; not intersect. In the large case, one of idx or idy, must be >=
; 2^30, so (+ (/ (* (idx+idy+1) (idx+idy)) 2) idy) > 2^59. Adding in
; -2^59 means that the large result will be positive. In the non-large
; case, the result of the logior will be <= 2^60-1, so the result of
; adding -2^60 will make the non-large result negative.
(cond (large-case
(let* ((z (+ idx idy))
(z1 (+ 1 z)))
(if (oddp z)
(setq z1 (ash z1 -1))
(setq z (ash z -1)))
(+ idy (+ (hmnf) (* z z1)))))
(t (+ (the fixnum
(logior
(the fixnum
(ash (the fixnum idx) (static-hons-shift)))
(the fixnum idy)))
most-negative-fixnum))))))
; This code has the 'feature' that if the condition causes an error,
; so will the memoized function.
; PONS differs from HONS in that it does not honsify its arguments and
; in that it takes a hash table as a third argument. We use PONS in
; memoization.
; We use PONS instead of HONS in memoization because we could not
; afford to honsify (using hons-shrink-alist!) certain alists in
; certain biology tests. About the same time, we (gratuitously)
; decided to stop hons'ifying the output of memoized functions.
(defun-one-output pons (x y ht)
(declare (hash-table ht))
; A crucial fact is:
; (implies (equal (pons x y ht) (pons x' y' ht))
; (and (equal x x')
; (equal y y'))
; Ignore the ht for the moment. Suppose that
; (equal (pons x (pons y z)) (pons x' (pons y' z'))).
;
; It follows then that x=x', y=y', and z=z'.
(let ((xval nil)
(yval nil)
(ans nil))
; We have taken string normalization out of pons because there might
; be a chance of confusing a 'normal' string with a stobj.
; If x1, ..., xn is pointwise EQL to y1, ..., yn, then are we sure
; that (pist* x1 ... xn) is EQ to (pist* y1 ... yn)?
; If CONS exists, then return it. Does CDR exist in hash table?
#+Clozure
(let ((addr (addr-for x y)))
(when addr (return-from pons addr)))
(maybe-count-pons-calls)
(setq yval (gethash y (the hash-table ht)))
; Does CAR exist in hash table?
(cond (yval
(cond ((not (consp yval))
(setq xval (gethash x (the hash-table yval)))
(cond (xval (setq ans xval))))
((setq ans (assoc-no-error-at-end x yval))))))
(cond
; If PONS found, then return previous CONS from hash table.
(ans)
; Otherwise, maybe create new CONS and install in hash table.
(t
(setq yval (gethash y ht))
(cond
((null yval)
(setq ans (cons x y))
(setf (gethash y ht) (list ans))
ans)
((consp yval)
(let ((ans (assoc-no-error-at-end x yval)))
(cond
(ans)
(t (let ((ans (cons (cons x y) yval)))
(maybe-count-pons-misses)
(cond
;; Gary Byers recalls Lisp folklore that alists are faster
;; than hash tables up to length 18.
((too-long ans 18)
(let ((tab (hl-mht)))
(declare (hash-table tab))
(loop for pair in ans do
(setf (gethash (car pair) tab) pair))
(setf (gethash y ht) tab)
(car ans)))
(t (setf (gethash y ht) ans)
(car ans))))))))
(t (setq xval (gethash x (the hash-table yval)))
(cond ((not xval)
(maybe-count-pons-misses)
(setf (gethash x (the hash-table yval))
(setq ans (cons x y))))
(t (setq ans xval)))
ans))))))
(defmacro pist* (table &rest x)
(cond ((atom x) x)
((atom (cdr x)) (car x))
(t (list 'pons (car x)
(cons 'pist* (cons table (cdr x))) table))))
; Identifying functions that are safe to memoize --------------------------
;
; [Jared]: This is really gross and I don't think it's the right way to do it
; at all. We need to figure out something better. Maybe we should instead use
; some kind of marking scheme on the symbol to say never memoize this function.
; (Modified by Matt K. 8/26/13 to avoid a weird error in profile-all after
; (include-book "memoize/old/profile" :dir :system).)
(defvar *never-memoize-ht*
(let ((ht (make-hash-table :test 'eq)))
(loop for x in
'(bytes-used
memoize-summary
memoize-summary-after-compute-calls-and-times
#+rdtsc ccl::rdtsc
*
+
-
<
<=
=
>
>=
abort
adjoin
adjust-array
allocate-instance
append
apply
apropos
apropos-list
aref
arrayp
assoc
assoc-if
assoc-if-not
atan
atom
bit
bit-and
bit-andc1
bit-andc2
bit-eqv
bit-ior
bit-nand
bit-nor
bit-not
bit-orc1
bit-orc2
bit-xor
break
butlast
car
cdr
ceiling
cerror
change-class
char-equal
char-greaterp
char-lessp
char-not-equal
char-not-greaterp
char-not-lessp
char/=
char<
char<=
char=
char>
char>=
clear-input
clear-memoize-tables
clear-output
compile
compile-file
compile-file-pathname
compiler-macro-function
complex
compute-restarts
concatenate
continue
copy-pprint-dispatch
copy-readtable
copy-symbol
count
count-if
count-if-not
decode-universal-time
delete
delete-duplicates
delete-if
delete-if-not
describe
digit-char
digit-char-p
directory
dribble
ed
encode-universal-time
enough-namestring
ensure-directories-exist
ensure-generic-function
eq
eql
error
eval
every
export
fboundp
fceiling
ffloor
file-position
fill
find
find-class
find-if
find-if-not
find-method
find-restart
find-symbol
finish-output
fixnum-to-symbol
float
float-sign
floor
force-output
format
fresh-line
fround
ftruncate
funcall
gensym
gentemp
get
get-dispatch-macro-character
get-internal-real-time
get-internal-run-time
get-macro-character
get-properties
get-setf-expansion
getf
gethash
if
import
initialize-instance
intern
internal-real-time
intersection
invalid-method-error
invoke-restart
last
ld-fn
len
len1
length
lisp-implementation-type
list
list*
listen
load
log
macro-function
macroexpand
macroexpand-1
make-array
make-broadcast-stream
make-concatenated-stream
make-condition
make-dispatch-macro-character
make-hash-table
make-instance
make-list
make-load-form
make-load-form-saving-slots
make-package
make-pathname
make-random-state
make-sequence
make-string
make-string-input-stream
make-string-output-stream
map
map-into
mapc
mapcan
mapcar
mapcon
mapl
maplist
max
member
member-if
member-if-not
memoize-call-array-grow
memoize-eval-compile
memoize-fn
merge
merge-pathnames
method-combination-error
mf-1st-warnings
mf-2nd-warnings
mf-warnings
mismatch
muffle-warning
nbutlast
nconc
nintersection
no-applicable-method
no-next-method
not
notany
notevery
nset-difference
nset-exclusive-or
nstring-capitalize
nstring-downcase
nstring-upcase
nsublis
nsubst
nsubst-if
nsubst-if-not
nsubstitute
nsubstitute-if
nsubstitute-if-not
null
nunion
open
pairlis
parse-integer
parse-namestring
pathname-device
pathname-directory
pathname-host
pathname-name
pathname-type
peek-char
position
position-if
position-if-not
pprint
pprint-dispatch
pprint-fill
pprint-indent
pprint-linear
pprint-newline
pprint-tab
pprint-tabular
prin1
princ
princ-to-string
print
print-object
profile-fn
profile-acl2
profile-all
random
rassoc
rassoc-if
rassoc-if-not
read
read-byte
read-char
read-char-no-hang
read-delimited-list
read-from-string
read-line
read-preserving-whitespace
read-sequence
reduce
reinitialize-instance
remove
remove-duplicates
remove-if
remove-if-not
rename-file
rename-package
replace
require
reverse-strip-cars
reverse-strip-cdrs
room
round
sbit
search
set-difference
set-dispatch-macro-character
set-exclusive-or
set-macro-character
set-pprint-dispatch
set-syntax-from-char
shadow
shadowing-import
shared-initialize
signal
signum
slot-missing
some
sort
stable-sort
store-value
string-capitalize
string-downcase
string-equal
string-greaterp
string-lessp
string-not-equal
string-not-greaterp
string-not-lessp
string-upcase
string/=
string<
string<=
string=
string>
string>=
stringp
sublis
subseq
subsetp
subst
subst-if
subst-if-not
substitute
substitute-if
substitute-if-not
subtypep
svref
symbol-to-fixnum
symbol-to-fixnum-create
symbolp
sync-memoize-call-array
terpri
translate-logical-pathname
translate-pathname
tree-equal
true-listp
truncate
typep
unexport
unintern
union
unread-char
unuse-package
update-instance-for-different-class
update-instance-for-redefined-class
upgraded-array-element-type
upgraded-complex-part-type
use-package
use-value
user-homedir-pathname
values
vector-push-extend
warn
wild-pathname-p
write
write-byte
write-char
write-line
write-sequence
write-string
write-to-string
y-or-n-p
yes-or-no-p)
do (setf (gethash x ht) t))
ht))
(defun never-memoize-fn (fn)
(setf (gethash fn *never-memoize-ht*) t))
(defun never-memoize-p (fn)
(if (gethash fn *never-memoize-ht*)
t
nil))
; The following was inserted by Jared to keep his place; stuff above is "done"
; and stuff below is "todo".
; -------------------------------------------------------------------------
; -------------------------------------------------------------------------
; ZZ THE GREPPABLE LINE ZZ
; -------------------------------------------------------------------------
; -------------------------------------------------------------------------
; recording vars