File: install-not-normalized.lisp

package info (click to toggle)
acl2 7.2dfsg-3
  • links: PTS
  • area: main
  • in suites: stretch
  • size: 198,968 kB
  • ctags: 182,300
  • sloc: lisp: 2,415,261; ansic: 5,675; perl: 5,577; xml: 3,576; sh: 3,255; cpp: 2,835; makefile: 2,440; ruby: 2,402; python: 778; ml: 763; yacc: 709; csh: 355; php: 171; lex: 162; tcl: 44; java: 24; asm: 23; haskell: 17
file content (407 lines) | stat: -rw-r--r-- 12,726 bytes parent folder | download
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
; Copyright (C) 2015, Regents of the University of Texas
; Written by Matt Kaufmann (October, 2015)
; License: A 3-clause BSD license.  See the LICENSE file distributed with ACL2.

#||

This comment motivates the macro install-not-normalized, defined below.

;;; Eric Smith created the following example.
(defun return-nil (x) (declare (ignore x)) nil)
(defun foo (x) (return-nil x))
;Now we can't prove that foo equals its body in a theory that just includes foo:
(thm
 (equal (foo x)
        (return-nil x))
 :hints (("Goal" :in-theory '(foo))))
;; Note that the defbodies property of foo no longer mentions return-nil, but
;; the unnormalized body of course does.

;;; This also fails:
(thm
 (equal (foo x)
        (return-nil x))
 :hints (("Goal"
          :expand ((foo x))
          :in-theory (theory 'minimal-theory))))

;;; NEW (to be generated programmatically using make-event via new utility
;;; install-not-normalized, below):
(defthm foo$not-normalized
  (equal (foo x) (return-nil x))
  :rule-classes ((:definition :install-body t)))

; This succeeds.
(thm
 (equal (foo x)
        (return-nil x))
 :hints (("Goal" :in-theory '(foo$not-normalized))))

; This succeeds.
(thm
 (equal (foo x)
        (return-nil x))
 :hints (("Goal"
          :expand ((foo x))
          :in-theory (theory 'minimal-theory))))
||#

(in-package "ACL2")

(defun install-not-normalized-fn-1 (name wrld clique)
  (declare (xargs :guard (and (symbolp name)
                              (plist-worldp wrld))))
  (let* ((formals (formals name wrld))
         (body (getprop name 'unnormalized-body nil 'current-acl2-world wrld))
         (defthm-name (intern-in-package-of-symbol
                       (concatenate 'string
                                    (symbol-name name)
                                    "$NOT-NORMALIZED")
                       name))
         (controller-alist (let* ((def-bodies
                                    (getprop name 'def-bodies nil
                                             'current-acl2-world wrld))
                                  (def-body ; (def-body name wrld)
                                    (and (true-listp def-bodies)
                                         (car def-bodies))))
                             (and (weak-def-body-p def-body) ; for guard proof
                                  (access def-body def-body :controller-alist)))))
    `((defthm ,defthm-name
        (equal (,name ,@formals)
               ,body)
        :hints (("Goal" :by ,name))
        :rule-classes ((:definition :install-body t
                                    ,@(and clique
                                           (list :clique
                                                 clique))
                                    ,@(and clique
                                           controller-alist
                                           (list :controller-alist
                                                 controller-alist)))))
      (in-theory (disable ,name)))))

(defun install-not-normalized-fn-lst (fns wrld all-fns)
  (declare (xargs :guard (and fns
                              (symbol-listp fns)
                              (plist-worldp wrld))))
  (cond ((endp (cdr fns))
         (install-not-normalized-fn-1 (car fns) wrld all-fns))
        (t (append (install-not-normalized-fn-1 (car fns) wrld all-fns)
                   (install-not-normalized-fn-lst (cdr fns) wrld all-fns)))))

(defun install-not-normalized-fn (name wrld nestp)
  (declare (xargs :guard (and (symbolp name)
                              (plist-worldp wrld))))
  (let ((fns (and nestp
                  (getprop name 'recursivep nil 'current-acl2-world wrld))))
    (cond ((and (true-listp fns)
                (cdr fns))
           (cond ((symbol-listp fns)
                  (install-not-normalized-fn-lst fns wrld fns))
                 (t (er hard? 'install-not-normalized-fn
                        "Surprise!  Not a non-empty symbol-listp: ~x0"
                        fns))))
          (t (install-not-normalized-fn-1 name wrld nil)))))

(defmacro install-not-normalized (name &optional (nestp 't))

; Alessandro Coglio sent the following example, which failed until taking his
; suggestion to use encapsulate (originally we used progn) and call
; set-ignore-ok.

;   (include-book "misc/install-not-normalized" :dir :system)
;   (include-book "std/util/define" :dir :system)
;   (define f (x) x)
;   (install-not-normalized f) ; error

; The problem was that the DEFINE generated the term ((LAMBDA (__FUNCTION__ X)
; X) 'F X).

  (declare (xargs :guard (and name (symbolp name))))
  `(make-event
    (list* 'encapsulate
           ()
           '(set-ignore-ok t) ; see comment above
           '(set-irrelevant-formals-ok t) ; perhaps not necessary, but harmless
           (install-not-normalized-fn ',name (w state) ,nestp))))

(defmacro fn-is-body (name &key hints thm-name rule-classes)
  (declare (xargs :guard (and name (symbolp name))))
  `(make-event
    (let* ((name ',name)
           (wrld (w state))
           (formals (formals name wrld))
           (body (getprop name 'unnormalized-body nil 'current-acl2-world wrld)))
      (list* 'defthm
             (or ',thm-name (intern-in-package-of-symbol
                             (concatenate 'string (symbol-name name) "$IS-BODY")
                             name))
             (list 'equal
                   (cons name formals)
                   body)
             (append (and ',hints
                          (list :hints ',hints))
                     (list :rule-classes ',rule-classes))))))

(local (include-book "misc/eval" :dir :system))

(defmacro my-test (&rest forms)
  `(local (encapsulate
            ()
            (in-theory (current-theory :here)) ; avoid redundancy
            ,@forms)))

; Example (challenge supplied by Eric Smith):

(my-test

(defun return-nil (x) (declare (ignore x)) nil)

(defun foo (x) (return-nil x))

(must-fail
 (fn-is-body foo
             :hints (("Goal" :in-theory '(foo)))))

(must-fail
 (fn-is-body foo
             :hints (("Goal"
                      :expand ((foo x))
                      :in-theory (theory 'minimal-theory)))))

(install-not-normalized foo)

(must-succeed
 (fn-is-body foo
             :hints (("Goal" :in-theory '(foo$not-normalized)))))

(must-succeed
 (fn-is-body foo
             :hints (("Goal"
                      :expand ((foo x))
                      :in-theory (theory 'minimal-theory)))))
)

; Recursion example:

(my-test

(defun my-t () t)
(defun my-nil () nil)
(defun my-zero () 0)

(defun f-norm (x)
  (if (my-t)
      (if (consp x)
          (cons (car x) (f-norm (cdr x)))
        (my-zero))
    (my-nil)))

(must-fail
 (fn-is-body f-norm
             :hints (("Goal" :in-theory '(f-norm)))))

(must-fail
 (fn-is-body f-norm
             :hints (("Goal"
                      :expand ((f-norm x))
                      :in-theory (theory 'minimal-theory)))))

(install-not-normalized f-norm)

(must-succeed
 (fn-is-body f-norm
             :hints (("Goal" :in-theory '(f-norm$not-normalized)))))

(must-succeed
 (fn-is-body f-norm
             :hints (("Goal"
                      :expand ((f-norm x))
                      :in-theory (theory 'minimal-theory)))))
)

; Mutual-recursion example:

(my-test

(defun my-t () t)
(defun my-nil () nil)
(defun my-zero () 0)

(mutual-recursion

 (defun f1-norm (x)
   (if (my-t)
       (if (consp x)
           (cons (car x) (f2-norm (cdr x)))
         (my-zero))
     (my-nil)))

 (defun f2-norm (x)
   (if (my-t)
       (if (consp x)
           (cons (car x) (f1-norm (cdr x)))
         (my-zero))
     (my-nil)))
 )

(must-fail
 (fn-is-body f1-norm
             :hints (("Goal" :in-theory '(f1-norm)))))

(must-fail
 (fn-is-body f1-norm
             :hints (("Goal"
                      :expand ((f1-norm x))
                      :in-theory (theory 'minimal-theory)))))

(install-not-normalized f1-norm)

(must-succeed
 (fn-is-body f1-norm
             :hints (("Goal" :in-theory '(f1-norm$not-normalized)))))

(must-succeed
 (fn-is-body f1-norm
             :hints (("Goal"
                      :expand ((f1-norm x))
                      :in-theory (theory 'minimal-theory)))))

; f2 is handled too:

(must-succeed
 (fn-is-body f2-norm
             :hints (("Goal" :in-theory '(f2-norm$not-normalized)))))

(must-succeed
 (fn-is-body f2-norm
             :hints (("Goal"
                      :expand ((f2-norm x))
                      :in-theory (theory 'minimal-theory)))))
)

; Mutual-recursion example, but handling only one function in the nest:

(my-test

(defun my-t () t)
(defun my-nil () nil)
(defun my-zero () 0)

(mutual-recursion

 (defun f3-norm (x)
   (if (my-t)
       (if (consp x)
           (cons (car x) (f4-norm (cdr x)))
         (my-zero))
     (my-nil)))

 (defun f4-norm (x)
   (if (my-t)
       (if (consp x)
           (cons (car x) (f3-norm (cdr x)))
         (my-zero))
     (my-nil)))
 )

(must-fail
 (fn-is-body f3-norm
             :hints (("Goal" :in-theory '(f3-norm)))))

(must-fail
 (fn-is-body f3-norm
             :hints (("Goal"
                      :expand ((f3-norm x))
                      :in-theory (theory 'minimal-theory)))))

(install-not-normalized f3-norm nil) ; "nil" for "not the entire nest

(must-succeed
 (fn-is-body f3-norm
             :hints (("Goal" :in-theory '(f3-norm$not-normalized)))))

(must-succeed
 (fn-is-body f3-norm
             :hints (("Goal"
                      :expand ((f3-norm x))
                      :in-theory (theory 'minimal-theory)))))

; F4 is not handled, since we gave nestp = nil in the call above of
; install-not-normalized.

(must-fail
 (fn-is-body f4-norm
             :hints (("Goal" :in-theory '(f4-norm$not-normalized)))))

(must-fail
 (fn-is-body f4-norm
             :hints (("Goal"
                      :expand ((f4-norm x))
                      :in-theory (theory 'minimal-theory)))))
)

(include-book "xdoc/top" :dir :system)

(defxdoc install-not-normalized
  :parents (proof-automation)
  :short "Install an unnormalized definition"
  :long "<p>By default, ACL2 simplifies the definitions by ``normalizing''
 their bodies.  If you prefer that ACL2 avoid such simplification when
 expanding a function call, then you can assigning the value of @('nil') to
 @(tsee xargs) keyword @(':normalize') (see @(see defun)) instead of the
 default value of @('t').  But that might not be a reasonable option, for
 example because the definition in question occurs in an included book that you
 prefer not to edit.  An alternative is to call a macro,
 @('install-not-normalized').</p>

 @({
 General Forms:

 (install-not-normalized NAME)
 (install-not-normalized NAME t) ; equivalent to the form above
 (install-not-normalized NAME nil)

 })

 <p>In the forms above, @('NAME') should be the name of a function symbol
 introduced with @(tsee defun) (or one of its variants, including @(tsee
 defund) and @(tsee defun-nx)).  The forms above are equivalent unless
 @('NAME') was defined together with other functions in a @(tsee
 mutual-recursion) (or @(tsee defuns)) event.  In that case, the first two
 forms install a non-normalized definition for every function symbol defined in
 that event, while the third form only handles @('NAME').  By ``handle'', we
 mean that a rule of class @('(:definition :install-body t)') is installed,
 with suitable additional fields for keywords @(':clique') and
 @(':controller-alist') when more than one name is handled.  The name of the
 rule generated for function @('F') is the symbol @('F$NOT-NORMALIZED'), that
 is, the result of modifying the @(tsee symbol-name) of @('F') by adding the
 suffix @('\"$NOT-NORMALIZED\"').</p>

 <p>For a somewhat related utility, see @(see fn-is-body).</p>

 <p>For examples, see the Community Book
 @('misc/install-not-normalized.lisp').</p>")

(defxdoc fn-is-body
  :parents (proof-automation)
  :short "Prove that a function called on its formals equals its body"
  :long "@({
 General Form:

 (fn-is-body fn &key hints thm-name rule-classes)

 })

 <p>Evaluation of the form above generates a @(tsee defthm) event whose name is
 @('thm-name') &mdash; by default, the result of adding the suffix \"$IS-BODY\"
 to @('fn'), which is a function symbol.  That event is of the form
 @('(equal (fn x1 ... xn) <body>)'), where @('(x1 ... xn)') is the list of
 formal parameters of @('fn') and @('<body>') is the body of @('fn').  If
 @(':hints') or @(':rule-classes') are supplied, they will be attached to the
 generated @('defthm') form.</p>

 <p>For a somewhat related utility, see @(see install-not-normalized).</p>

 <p>For examples, see the Community Book
 @('misc/install-not-normalized.lisp').</p>")