~ubuntu-branches/ubuntu/wily/acl2/wily

« back to all changes in this revision

Viewing changes to books/ccg/ccg.lisp

  • Committer: Package Import Robot
  • Author(s): Camm Maguire
  • Date: 2015-01-16 10:35:45 UTC
  • mfrom: (3.3.26 sid)
  • Revision ID: package-import@ubuntu.com-20150116103545-prehe9thgo79o8w8
Tags: 7.0-1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#|$ACL2s-Preamble$;
2
 
 
3
 
(begin-book t :ttags ((:ccg)));$ACL2s-Preamble$|#
4
 
 
5
 
(in-package "ACL2")
6
 
 
7
 
(defttag :ccg)
8
 
 
9
 
; load in the expander book.
10
 
 
11
 
(include-book "misc/expander" :dir :system)
12
 
 
13
 
 
14
 
; load in Peter's hacker stuff.  we use at least three things from this:
15
 
; - add several keys to the acl2-defaults-table
16
 
; - make raw Lisp definitions from an acl2 book, i.e. defstruct-raw,
17
 
;   defmacro-raw, and defun-raw
18
 
; - bridge raw lisp and ACL2 so that we can access the raw Lisp code
19
 
;
20
 
(include-book "hacking/hacker" :dir :system)
21
 
(progn+all-ttags-allowed
22
 
 (include-book "hacking/all" :dir :system :ttags :all))
23
 
(subsume-ttags-since-defttag)
24
 
 
25
 
 
26
 
(defdoc CCG
27
 
  ":Doc-Section CCG
28
 
   
29
 
   a powerful automated termination prover for ACL2~/~/
30
 
 
31
 
   In order to see how the CCG analysis works, consider the following
32
 
   definition of Ackermann's function from exercise 6.15 in the ACL2 textbook:
33
 
   ~bv[]
34
 
   (defun ack (x y)
35
 
      (if (zp x) 
36
 
          1
37
 
        (if (zp y) 
38
 
            (if (equal x 1) 2 (+ x 2))
39
 
          (ack (ack (1- x) y) (1- y))))) 
40
 
    ~ev[] 
41
 
    ACL2 cannot automatically prove the termination of ~c[ack] using its
42
 
    measure-based termination proof. In order to admit the function, the user
43
 
    must supply a measure. An example measure is 
44
 
    ~c[(make-ord 1 (1+ (acl2-count y)) (acl2-count x))], which is equivalent to the ordinal 
45
 
    ~c[w * (1+ (acl2-count y)) + (acl2-count x)], where ~c[w] is the first infinite
46
 
    ordinal.
47
 
 
48
 
   The CCG analysis, on the other hand, automatically proves termination as
49
 
   follows. Note that there are two recursive calls. These calls, along with
50
 
   their rulers (i.e. the conditions under which the recursive call is reached)
51
 
   are called ~em[calling contexts], or sometimes just ~em[contexts] (for more
52
 
   on rulers, see ~il[ruler-extenders]). For
53
 
   ~c[ack], these are:
54
 
   ~bv[]
55
 
   1. (ack (1- x) y) with ruler ((not (zp x)) (not (zp y))).
56
 
   2. (ack (ack (1- x) y) (1- y)) with ruler ((not (zp x)) (not (zp y))). 
57
 
   ~ev[]
58
 
   These calling contexts are used to build a ~em[calling context graph (CCG)],
59
 
   from which our analysis derives its name. This graph has an edge from
60
 
   context ~c[c1] to context ~c[c2] when it is possible that execution can move
61
 
   from context ~c[c1] to context ~c[c2] in one ``step'' (i.e. without visiting
62
 
   any other contexts). For our example, we get the complete graph, with edges
63
 
   from each context to both contexts.
64
 
 
65
 
   The analysis next attempts to guess ~em[calling context measures (CCMs)], or
66
 
   just ~em[measures], for each function. These are similar to ACL2 measures,
67
 
   in that they are ACL2 terms that must provably be able to evaluate to an
68
 
   ordinal value (unlike ACL2 measures, CCG currently ignores the current
69
 
   well-founded relation setting). However, functions may have multiple CCMs,
70
 
   instead of one, like ACL2, and the CCG analysis has some more sophisticated
71
 
   heuristics for guessing appropriate measures. However, there is a mechanism
72
 
   for supplying measures to the CCG analysis if you need to ~pl[CCG-XARGS]. In
73
 
   our example, the CCG analysis will guess the measures ~c[(acl2-count x)],
74
 
   ~c[(acl2-count y)], and ~c[(+ (acl2-count x) (acl2-count y))]. This last one
75
 
   turns out to be unimportant for the termination proof. However, note that
76
 
   the first two of these measures are components of the ordinal measure that
77
 
   we gave ACL2 to prove termination earlier. As one might guess, these are
78
 
   important for the success of our CCG analysis.
79
 
 
80
 
   Like ACL2's measure analysis, we are concerned with what happens to these
81
 
   values when a recursive call is made. However, we are concerned not just
82
 
   with decreasing measures, but also non-increasing measures. Thus, we
83
 
   construct ~em[Calling Context Measure Functions (CCMFs)], which tell us how
84
 
   one measure compares to another across recursive calls.
85
 
 
86
 
   In our example, note that when the recursive call of the context 1 is made,
87
 
   the new value of ~c[(acl2-count x)] is less than the original value of
88
 
   ~c[(acl2-count x)]. More formally, we can prove the following:
89
 
   ~bv[]
90
 
   (implies (and (not (zp x))
91
 
                 (not (zp y)))
92
 
            (o< (acl2-count (1- x))
93
 
                (acl2-count x)))
94
 
   ~ev[]
95
 
   For those of you that are familiar with measure-based termination proofs in
96
 
   ACL2, this should look familiar, as it has the same structure as such a
97
 
   termination proof. However, we also note the following trivial observation:
98
 
   ~bv[]
99
 
   (implies (and (not (zp x))
100
 
                 (not (zp y)))
101
 
            (o<= (acl2-count y)
102
 
                 (acl2-count y)))
103
 
   ~ev[]
104
 
   That is, ~c[y] stays the same across this recursive call. For the other
105
 
   context, we similarly note that ~c[(acl2-count y)] is decreasing. However,
106
 
   we can say nothing about the value of ~c[(acl2-count x)]. The CCG algorithm
107
 
   does this analysis using queries to the theorem prover that are carefully
108
 
   restricted to limit prover time.
109
 
 
110
 
   Finally, the CCG analysis uses this local information to do a global
111
 
   analysis of what happens to values. This analysis asks the question, for
112
 
   every infinite path through our CCG, ~c[c_1], ~c[c_2], ~c[c_3], ..., is
113
 
   there a natural number ~c[N] such that there is an infinite sequence of
114
 
   measures ~c[m_N], ~c[m_(N+1)], ~c[m_(N+2)], ... such that each ~c[m_i] is a
115
 
   measure for the context ~c[c_i] (i.e. a measure for the function containing
116
 
   ~c[ci]), we have proven that the ~c[m_(i+1)] is never larger than ~c[m_i],
117
 
   and for infinitely many ~c[i], it is the case that we have proven that
118
 
   ~c[m_i] is always larger than ~c[m_(i+)]. That's a bit of a mouthful, but
119
 
   what we are essentially saying is that, for every possible infinite sequence
120
 
   of recursions it is the case that after some finite number of steps, we can
121
 
   start picking out measures such that they never increase and infinitely
122
 
   often they decrease. Since these measures return ordinal values, we then
123
 
   know that there can be no infinite recursions, and we are done.
124
 
 
125
 
   For our example, consider two kinds of infinite paths through our CCG: those
126
 
   that visit context 2 infinitely often, and those that don't. In the first
127
 
   case, we know that ~c[(acl2-count y)] is never increasing, since a visit to
128
 
   context 1 does not change the value of ~c[y], and a visit to context 2
129
 
   decreases the value of ~c[(acl2-count y)]. Furthermore, since we visit
130
 
   context 2 infinitely often, we know that ~c[(acl2-count y)] is infinitely
131
 
   decreasing along this path. Therefore, we have met the criteria for proving
132
 
   no such path is a valid computation. In the case in which we do not visit
133
 
   context 2 infinitely often, there must be a value ~c[N] such that we do not
134
 
   visit context 2 any more after the ~c[N]th context in the path. After this,
135
 
   we must only visit context 1, which always decreases the value of
136
 
   ~c[(acl2-count x)]. Therefore, no such path can be a valid
137
 
   computation. Since all infinite paths through our CCG either visit context 2
138
 
   infinitely often or not, we have proven termination. This analysis of the
139
 
   local data in the global context is done automatically by a decision
140
 
   procedure.
141
 
 
142
 
   That is a brief overview of the CCG analysis. Note that, can it prove many
143
 
   functions terminating that ACL2 cannot. It also does so using simpler
144
 
   measures. In the ~c[ack] example, we did not require any infinite ordinal
145
 
   measures to prove termination using CCG. Intuitively, CCG is in a way
146
 
   putting together the measures for you so you don't have to think about the
147
 
   ordinal structure. Thus, even when the CCG analysis to prove termination, it
148
 
   is often easier to give it multiple simple measures and allow it to put
149
 
   together the global termination argument than to give ACL2 the entire
150
 
   measure so it can prove that it decreases every single step.
151
 
 
152
 
   To find out more about interacting and controlling the CCG analysis, see the
153
 
   topics included in this section.")
154
 
 
155
 
; BEGIN public configuration interface
156
 
 
157
 
; add :termination-method key to acl2-defaults-table
158
 
;
159
 
; add-acl2-defaults-table-key is provided by my hacker stuff. -Peter
160
 
 
161
 
(add-acl2-defaults-table-key :termination-method
162
 
                             (member-eq val '(:measure :ccg)))
163
 
 
164
 
(defdoc set-termination-method
165
 
  ":Doc-Section CCG
166
 
 
167
 
  Set the default means of proving termination.~/
168
 
  ~bv[]
169
 
  Examples:
170
 
  (set-termination-method :ccg)
171
 
  (set-termination-method :measure)
172
 
  ~ev[]
173
 
 
174
 
  Introduced by the CCG analysis book, this macro sets the default
175
 
  means by which ACL2 will prove termination. Note: This is an event!
176
 
  It does not print the usual event summary but nevertheless changes
177
 
  the ACL2 logical ~il[world] and is so recorded.~/
178
 
 
179
 
  ~bv[] General Form:
180
 
  (set-termination-method tm)
181
 
  ~ev[]
182
 
 
183
 
  where ~c[tm] is ~c[:CCG] or ~c[:MEASURE]. The default is ~c[:MEASURE] (chosen
184
 
  to assure compatibility with books created without CCG). The recommended
185
 
  setting is ~c[:CCG]. This macro is equivalent to 
186
 
  ~c[(table acl2-defaults-table :termination-method 'tm)], and hence is ~ilc[local] to
187
 
  any ~il[books] and ~ilc[encapsulate] ~il[events] in which it occurs;
188
 
  ~pl[acl2-defaults-table].
189
 
 
190
 
  When the termination-method is set to ~c[:CCG], a termination proof is
191
 
  attempted using the the hierarchical CCG algorithm ~url[CCG-hierarchy].
192
 
 
193
 
  When the termination-method is set to ~c[:MEASURE], ACL2 attempts to
194
 
  prove termination using its default measure-based method. Thus, in
195
 
  this setting, ACL2's behavior is identical to that when the CCG book
196
 
  is not included at all.
197
 
 
198
 
  To see what the current termination method setting is, use
199
 
  ~ilc[get-termination-method].~/")
200
 
 
201
 
(defun get-termination-method (wrld)
202
 
  ":Doc-Section CCG
203
 
 
204
 
  Returns the current default termination method.~/
205
 
 
206
 
  ~bv[]
207
 
  Examples:
208
 
  (get-termination-method (w state))
209
 
  ~ev[]
210
 
 
211
 
  This will return the termination-method as specified by the current world. ~/
212
 
  
213
 
  ~bv[]
214
 
  General Form:
215
 
  (get-termination-method wrld)
216
 
  ~ev[]
217
 
 
218
 
  where ~c[wrld] is a ~il[world]. For information on the settings and
219
 
  their meaning, ~pl[set-termination-method].~/"
220
 
 
221
 
  (declare (xargs :guard (and (plist-worldp wrld)
222
 
                              (alistp (table-alist 'acl2-defaults-table wrld)))))
223
 
  (let ((entry (assoc :termination-method (table-alist 'acl2-defaults-table wrld))))
224
 
    (or (and entry (cdr entry)) :measure)))
225
 
 
226
 
(verify-guards get-termination-method)
227
 
 
228
 
(defmacro hlevel-proof-technique (hlevel)
229
 
  `(car ,hlevel))
230
 
 
231
 
(defmacro hlevel-ccm-comparison-scheme (hlevel)
232
 
  `(cadr ,hlevel))
233
 
 
234
 
(defmacro hlevel-ccmfs-per-nodep (hlevel)
235
 
  `(caddr ,hlevel))
236
 
 
237
 
(defmacro make-hlevel (pt ccm-cs cpn)
238
 
  `(list ,pt ,ccm-cs ,cpn))
239
 
 
240
 
(defun proof-techniquep (pt)
241
 
 
242
 
; checks whether pt is a valid "proof technique" as described in the
243
 
; documentation for the set-ccg-hierarchy. That is, this function returns true
244
 
; if pt is :built-in-clauses or of the form (:induction-depth n) for some
245
 
; natural number n.
246
 
 
247
 
  (declare (xargs :guard t))
248
 
  (or (and (keywordp pt)
249
 
           (eq pt :built-in-clauses))
250
 
      (and (consp pt)
251
 
           (keywordp (car pt))
252
 
           (eq (car pt) :induction-depth)
253
 
           (consp (cdr pt))
254
 
           (natp (cadr pt))
255
 
           (null (cddr pt)))))
256
 
 
257
 
(defun hlevelp (hlevel)
258
 
  (declare (xargs :guard t))
259
 
 
260
 
; returns non-nil if hlevel is a valid level of a CCG hierarchy. That is,
261
 
; the result is non-nil if it is of the form (:measure pt) or (pt ccm-cs cpn)
262
 
; where pt satisfies proof-techniquep, ccm-cs is one of :EQUAL, :ALL, :SOME, or
263
 
; :NONE, and cpn is a boolean.
264
 
 
265
 
  (and (consp hlevel)
266
 
       (or (and (keywordp (car hlevel))
267
 
                (eq (car hlevel) :measure)
268
 
                (consp (cdr hlevel))
269
 
                (proof-techniquep (cadr hlevel))
270
 
                (null (cddr hlevel)))
271
 
           (and (proof-techniquep (car hlevel))
272
 
                (consp (cdr hlevel))
273
 
                (member-eq (cadr hlevel) '(:EQUAL :ALL :SOME :NONE))
274
 
                (consp (cddr hlevel))
275
 
                (booleanp (caddr hlevel))
276
 
                (null (cdddr hlevel))))))
277
 
 
278
 
(defun hlevel-listp (lst)
279
 
  (declare (xargs :guard t))
280
 
 
281
 
; returns non-nil iff lst is a true-list of elements satisfying hlevelp.
282
 
 
283
 
  (if (consp lst)
284
 
      (and (hlevelp (car lst))
285
 
           (hlevel-listp (cdr lst)))
286
 
    (null lst)))
287
 
 
288
 
(defun non-empty-hlevel-listp (lst)
289
 
  (declare (xargs :guard t))
290
 
  (and (consp lst)
291
 
       (hlevel-listp lst)))
292
 
 
293
 
(defun hlevel< (hlevel0 hlevel1)
294
 
 
295
 
; a non-transitive comparison function for arguments that are non-measure
296
 
; levels of a CCG hierarchy. The definition is designed to return t if the CCG
297
 
; analysis, using the techniques described in hlevel1 could possibly further
298
 
; refine an annotated CCG that had already been refined using the techniques
299
 
; described in hlevel0. That is, hlevel< returns t if hlevel0 does *not*
300
 
; subsume hlevel1.
301
 
 
302
 
  (declare (xargs :guard (and (hlevelp hlevel0)
303
 
                              (not (equal (car hlevel0)
304
 
                                          :measure))
305
 
                              (hlevelp hlevel1)
306
 
                              (not (equal (car hlevel1)
307
 
                                          :measure)))))
308
 
  (let ((pt0 (hlevel-proof-technique hlevel0))
309
 
        (ccm-cs0 (hlevel-ccm-comparison-scheme hlevel0))
310
 
        (cpn0 (hlevel-ccmfs-per-nodep hlevel0))
311
 
        (pt1 (hlevel-proof-technique hlevel1))
312
 
        (ccm-cs1 (hlevel-ccm-comparison-scheme hlevel1))
313
 
        (cpn1 (hlevel-ccmfs-per-nodep hlevel1)))
314
 
 
315
 
; if cpn0 is t and cpn1 is nil (hlevel0 calculates CCMFs on a per-node basis,
316
 
; and hlevel1 on a per-edge basis), then we return t.
317
 
 
318
 
    (or (and cpn0 (not cpn1))
319
 
 
320
 
; if hlevel1 has a stronger proof technique than hlevel0, then return t.
321
 
 
322
 
        (and (not (equal pt1 :built-in-clauses))
323
 
             (or (equal pt0 :built-in-clauses)
324
 
                 (< (cadr pt0) (cadr pt1))))
325
 
        
326
 
; if hlevel1 has a more comprehensive CCM comparison scheme, then return t.
327
 
 
328
 
        (let ((ccm-cs-vals '((:EQUAL . 0)
329
 
                             (:ALL . 1)
330
 
                             (:SOME . 2)
331
 
                             (:NONE . 3))))
332
 
          (< (cdr (assoc ccm-cs0 ccm-cs-vals))
333
 
             (cdr (assoc ccm-cs1 ccm-cs-vals)))))))
334
 
 
335
 
(rewrite-table-guard
336
 
 acl2-defaults-table
337
 
 (:carpat %body%
338
 
  :vars %body%
339
 
  :repl (if (eq key :ccg-hierarchy)
340
 
            (non-empty-hlevel-listp val)
341
 
          %body%)))
342
 
 
343
 
 
344
 
(defun fix-ccg-hierarchy (hierarchy)
345
 
  (declare (xargs :guard (or (consp hierarchy)
346
 
                             (and (symbolp hierarchy)
347
 
                                  (member-eq hierarchy
348
 
                                             '(:CCG-ONLY
349
 
                                               :CCG-ONLY-CPN
350
 
                                               :HYBRID
351
 
                                               :HYBRID-CPN))))))
352
 
 
353
 
  
354
 
; if hierarchy is a symbol designating one of the pre-defined hierarchies,
355
 
; return the hierarchy that it represents. Otherwise, return hierarchy.
356
 
 
357
 
  (if (consp hierarchy)
358
 
      hierarchy
359
 
    (case hierarchy
360
 
      (:CCG-ONLY
361
 
       '((:built-in-clauses :equal t)
362
 
         ((:induction-depth 0) :EQUAL t)
363
 
         ((:induction-depth 1) :EQUAL t)
364
 
         ((:induction-depth 1) :ALL   t)
365
 
         ((:induction-depth 1) :SOME  t)
366
 
         ((:induction-depth 1) :NONE  t)
367
 
         ((:induction-depth 1) :EQUAL nil)
368
 
         ((:induction-depth 1) :ALL   nil)
369
 
         ((:induction-depth 1) :SOME  nil)
370
 
         ((:induction-depth 1) :NONE  nil)))
371
 
        (:CCG-ONLY-CPN
372
 
         '((:built-in-clauses :equal t)
373
 
           ((:induction-depth 0) :EQUAL t)
374
 
           ((:induction-depth 1) :EQUAL t)
375
 
           ((:induction-depth 1) :ALL   t)
376
 
           ((:induction-depth 1) :SOME  t)
377
 
           ((:induction-depth 1) :NONE  t)))
378
 
        (:HYBRID
379
 
         '((:built-in-clauses :equal t)
380
 
           (:measure (:induction-depth 1))
381
 
           ((:induction-depth 0) :EQUAL t)
382
 
           ((:induction-depth 1) :EQUAL t)
383
 
           ((:induction-depth 1) :ALL   t)
384
 
           ((:induction-depth 1) :SOME  t)
385
 
           ((:induction-depth 1) :NONE  t)
386
 
           ((:induction-depth 1) :EQUAL nil)
387
 
           ((:induction-depth 1) :ALL   nil)
388
 
           ((:induction-depth 1) :SOME  nil)
389
 
           ((:induction-depth 1) :NONE  nil)))
390
 
        (:HYBRID-CPN
391
 
         '((:built-in-clauses :equal t)
392
 
           (:measure (:induction-depth 1))
393
 
           ((:induction-depth 0) :EQUAL t)
394
 
           ((:induction-depth 1) :EQUAL t)
395
 
           ((:induction-depth 1) :ALL   t)
396
 
           ((:induction-depth 1) :SOME  t)
397
 
           ((:induction-depth 1) :NONE  t)))
398
 
        (otherwise
399
 
         nil))))
400
 
 
401
 
(defun get-ccg-hierarchy (wrld)
402
 
  (declare (xargs :guard (and (plist-worldp wrld)
403
 
                              (alistp (table-alist 'acl2-defaults-table
404
 
                                                   wrld)))))
405
 
  
406
 
; gets the default ccg hierarchy from the acl2-defaults-table. the default is
407
 
; :CCG-ONLY.
408
 
 
409
 
  (let ((entry (assoc :ccg-hierarchy (table-alist 'acl2-defaults-table wrld))))
410
 
    (if (null entry)
411
 
        (fix-ccg-hierarchy :CCG-ONLY)
412
 
      (cdr entry))))
413
 
 
414
 
(set-state-ok t)
415
 
(program)
416
 
 
417
 
(defun chk-ccg-hierarchy1 (hierarchy cpn ctx state)
418
 
 
419
 
; checks the given hierarchy to assure that it conforms to the proper form.
420
 
; if cpn is nil, all levels of the hierarchy must have a cpn of nil. Otherwise,
421
 
; this function checks that there are no levels of the hierarchy with cpn t
422
 
; that come after levels with a cpn of nil (once you switch from CCMFs per-node
423
 
; to CCMFs per-edge, you cannot go back). The ctx and state are there to enable
424
 
; error reporting. This function returns an error triple whose value is nil if
425
 
; everything checks out.
426
 
 
427
 
  (cond ((endp hierarchy)
428
 
         (value nil))
429
 
        ((not (hlevelp (car hierarchy)))
430
 
         (er soft ctx
431
 
             "Each element of a CCG-HIERARCHY must either have the form (PT ~
432
 
              CCM-CS CPN) or (:MEASURE PT), where PT is either ~
433
 
              :BUILT-IN-CLAUSES or (:INDUCTION-DEPTH N) for some natural ~
434
 
              number, N, CCM-CS is one of :EQUAL, :ALL, :SOME, :NONE, and CPN ~
435
 
              is either T or NIL. ~x0 does not match this form."
436
 
             (car hierarchy)))
437
 
        ((and (not cpn)
438
 
              (not (equal (caar hierarchy) :MEASURE))
439
 
              (hlevel-ccmfs-per-nodep (car hierarchy)))
440
 
         (er soft ctx 
441
 
             "It is not permitted that a level of a CCG-HIERARCHY have a ~
442
 
              CCCMFs-per-nodep of T when a previous level had a ~
443
 
              CCMFs-per-nodep of NIL. But this is the case with level ~x0."
444
 
             (car hierarchy)))
445
 
        (t
446
 
         (chk-ccg-hierarchy1 (cdr hierarchy) 
447
 
                             (if (equal (caar hierarchy) :measure)
448
 
                                 cpn
449
 
                               (hlevel-ccmfs-per-nodep (car hierarchy)))
450
 
                             ctx state))))
451
 
 
452
 
(defun chk-measure-hlevel<-all (hlevel0 hierarchy ctx state)
453
 
 
454
 
; ensures that none of the measure levels of hierarchy are subsumed by hlevel0.
455
 
 
456
 
  (cond ((endp hierarchy)
457
 
         (value nil))
458
 
        ((or (not (equal (caar hierarchy) :measure))
459
 
             (and (consp (cadar hierarchy))
460
 
                  (or (atom (cadr hlevel0))
461
 
                      (< (cadadr hlevel0) (cadadr (car hierarchy))))))
462
 
         (chk-measure-hlevel<-all hlevel0 (cdr hierarchy) ctx state))
463
 
        (t
464
 
         (er soft ctx
465
 
             "Each :MEASURE level of a CCG-HIERARCHY should use strictly more ~
466
 
              powerful proof techniques than all those that come before it. ~
467
 
              However, the ~x0 level is subsumed by the earlier level, ~x1."
468
 
             (car hierarchy)
469
 
             hlevel0))))
470
 
 
471
 
(defun chk-hlevel<-all (hlevel0 hierarchy ctx state)
472
 
 
473
 
; insures that none of the CCG levels of the hierarchy are subsumed by
474
 
; hlevel0.
475
 
 
476
 
  (cond ((endp hierarchy)
477
 
         (value nil))
478
 
        ((or (equal (caar hierarchy) :MEASURE)
479
 
             (hlevel< hlevel0 (car hierarchy)))
480
 
         (chk-hlevel<-all hlevel0 (cdr hierarchy) ctx state))
481
 
        (t
482
 
         (er soft ctx
483
 
             "Each level of a CCG-HIERARCHY should be strictly more powerful ~
484
 
              than all the previous levels. That is, it should always be ~
485
 
              possible to refine the CCG or CCMF information at each step in ~
486
 
              the hierarchy. However, the ~x0 level is subsumed by the ~
487
 
              earlier level, ~x1."
488
 
             (car hierarchy)
489
 
             hlevel0))))
490
 
 
491
 
(defun chk-hierarchy-strictly-increasing (hierarchy ctx state)
492
 
 
493
 
; ensures that no level of hierarchy is subsumed by a later level.
494
 
 
495
 
  (if (endp hierarchy)
496
 
      (value nil)
497
 
    (er-progn
498
 
     (cond ((equal (caar hierarchy) :MEASURE)
499
 
            (chk-measure-hlevel<-all (car hierarchy) (cdr hierarchy)
500
 
                                     ctx state))
501
 
           (t
502
 
            (chk-hlevel<-all (car hierarchy) (cdr hierarchy)
503
 
                             ctx state)))
504
 
     (chk-hierarchy-strictly-increasing (cdr hierarchy) ctx state))))
505
 
        
506
 
(defun chk-ccg-hierarchy (hierarchy ctx state)
507
 
 
508
 
; checks a proposed CCG hierarchy.
509
 
 
510
 
  (cond ((and (symbolp hierarchy)
511
 
              (member-eq hierarchy '(:CCG-ONLY
512
 
                                     :CCG-ONLY-CPN
513
 
                                     :HYBRID
514
 
                                     :HYBRID-CPN)))
515
 
         (value nil))
516
 
        ((and (consp hierarchy)
517
 
              (true-listp hierarchy))
518
 
         (er-progn
519
 
          (chk-ccg-hierarchy1 hierarchy t ctx state)
520
 
          (chk-hierarchy-strictly-increasing hierarchy ctx state)))
521
 
        (t
522
 
         (er soft ctx
523
 
             "A CCG-HIERARCHY must be :CCG-ONLY, :CCG-ONLY-CPN, :HYBRID, ~
524
 
              :HYBRID-CPN, or a non-empty true-list. ~x0 does not have ~
525
 
              this form."
526
 
             hierarchy))))
527
 
         
528
 
(defmacro set-ccg-hierarchy (v)
529
 
    ":Doc-Section CCG
530
 
   
531
 
     Set the default hierarchy of techniques for CCG-based termination
532
 
     analysis. ~/
533
 
     ~bv[]
534
 
     (set-ccg-hierarchy ((:built-in-clauses :equal t)
535
 
                         (:measure (:induction-depth 1))
536
 
                         ((:induction-depth 0) :EQUAL t)
537
 
                         ((:induction-depth 1) :EQUAL t)
538
 
                         ((:induction-depth 1) :ALL   t)
539
 
                         ((:induction-depth 1) :SOME  t)
540
 
                         ((:induction-depth 1) :NONE  t)
541
 
                         ((:induction-depth 1) :EQUAL nil)
542
 
                         ((:induction-depth 1) :ALL   nil)
543
 
                         ((:induction-depth 1) :SOME  nil)
544
 
                         ((:induction-depth 1) :NONE  nil)))
545
 
     :set-ccg-hierarchy ((:built-in-clauses :equal t)
546
 
                         ((:induction-depth 0) :EQUAL t)
547
 
                         ((:induction-depth 1) :EQUAL t)
548
 
                         ((:induction-depth 1) :ALL   t)
549
 
                         ((:induction-depth 1) :SOME  t)
550
 
                         ((:induction-depth 1) :NONE  t))~/
551
 
 
552
 
     General Form:
553
 
     (set-ccg-hierarchy v)
554
 
     ~ev[]
555
 
     where ~c[v] is ~c[:CCG-ONLY], ~c[:CCG-ONLY-CPN], ~c[:HYBRID],
556
 
     ~c[:HYBRID-CPN], or a non-empty list of hierarchy levels, which either
557
 
     have the form ~c[(pt ccm-cs cpn)] or the form ~c[(:measure pt)], where
558
 
     ~c[pt] is either ~c[:built-in-clauses] or ~c[(:induction-depth n)] for
559
 
     some natural number ~c[n], ~c[ccm-cs] is one of ~c[:EQUAL], ~c[:ALL],
560
 
     ~c[:SOME], or ~c[:NONE], and ~c[cpn] is ~c[t] or ~c[nil].
561
 
 
562
 
     Each level of the hierarchy describes techniques used to prove
563
 
     termination. Termination proofs performed after admitting this event will
564
 
     use the specified techniques in the order in which they are listed.
565
 
 
566
 
     Basically, the CCG analysis as described and illustrated at a high level
567
 
     in the documentation for ~il[CCG] can potentially be very expensive. In
568
 
     order to make the analysis as efficient as possible, we use less expensive
569
 
     (and less powerful) techniques first, and resort to more powerful and
570
 
     expensive techniques only when these fail.
571
 
 
572
 
     There are three ways of varying the CCG analysis, which are represented by
573
 
     each of the three elements in a hierarchy level (levels of the form
574
 
     ~c[(:measure pt)] will be explained later).
575
 
 
576
 
     ~c[Pt] tells the CCG analysis how to limit proof attempts. The idea behind
577
 
     this is that ACL2 is designed to prove statements that the user thinks are
578
 
     true. It therefore does everything it can to prove the conjecture. As ACL2
579
 
     useres already know, this can lead to very long, or even non-terminating
580
 
     proof attempts. The CCG analysis, on the other hand, sends multiple
581
 
     queries to the theorem prover that may or may not be true, in order to
582
 
     improve the accuracy of the analysis. It is therefore necessary to reign
583
 
     in ACL2's proof attempts to keep them from taking too long. Of course, the
584
 
     trade-off is that, the more we limit ACL2's prover, the less powerful it
585
 
     becomes.
586
 
 
587
 
     ~c[Pt] can be ~c[:built-in-clauses], which tells ACL2 to use only
588
 
     ~il[built-in-clauses] analysis. This is a very fast, and surprisingly
589
 
     powerful proof technique. For example, the definition of Ackermann's
590
 
     function given in the documentation for ~il[CCG] is solved using only this
591
 
     proof technique.
592
 
 
593
 
     ~c[Pt] can also be of the form ~c[(:induction-depth n)], where ~c[n] is a
594
 
     natural number. This uses the full theorem prover, but limits it in two
595
 
     ways. First, it stops proof attempts if ACL2 has been working on a subgoal
596
 
     with no case splitting or induction for 20 steps (that is, at a goal of
597
 
     the form 1.5'20'). It also limits the ~em[induction depth], which
598
 
     describes how many times we allow induction goals to lead to further
599
 
     induction goals. For example, ~c[(:induction-depth 0)] allows no
600
 
     induction, while ~c[(:induction-depth 1)] allows goals of the form ~c[*1]
601
 
     or ~c[*2], but stops if it creates a goal such as ~c[*1.1] or ~c[*2.1].
602
 
 
603
 
     ~c[Ccm-cs] limits which CCMs are compared using the theorem
604
 
     prover. Consider again the ~c[ack] example in the documentation for
605
 
     ~il[CCG]. All we needed was to compare the value of ~c[(acl2-count x)]
606
 
     before and after the recursive call and the value of ~c[(acl2-count y)]
607
 
     before and after the recursive call. We would learn nothing, and waste
608
 
     time with the theorem prover if we compared ~c[(acl2-count x)] to
609
 
     ~c[(acl2-count y)]. However, other times, it is important to compare CCMs
610
 
     with each other, for example, when arguments are permuted, or we are
611
 
     dealing with a mutual recursion.
612
 
 
613
 
     ~c[Ccm-cs] can be one of ~c[:EQUAL], ~c[:ALL], ~c[:SOME], or
614
 
     ~c[:NONE]. These limit which CCMs we compare based on the variables they
615
 
     mention. Let ~c[c] be a recursive call in the body of function ~c[f] that
616
 
     calls function ~c[g]. Let ~c[m1] be a CCM for ~c[f] and ~c[m2] be a CCM
617
 
     for ~c[g]. Let ~c[v1] be the formals mentioned in ~c[m1] and ~c[v2] be the
618
 
     formals mentioned in ~c[m2'] where ~c[m2'] is derived from ~c[m2] by
619
 
     substituting the formals of ~c[g] with the actuals of ~c[c]. For example,
620
 
     consider following function:
621
 
     ~bv[]
622
 
     (defun f (x)
623
 
       (if (endp x)
624
 
           0
625
 
         (1+ (f (cdr x)))))
626
 
     ~ev[]
627
 
     Now consider the case where ~c[m1] and ~c[m2] are both the measure
628
 
     ~c[(acl2-count x)]. Then if we look at the recursive call ~c[(f (cdr x))]
629
 
     in the body of ~c[f], then ~c[m2'] is the result of replacing ~c[x] with
630
 
     ~c[(cdr x)] in ~c[m2], i.e., ~c[(acl2-count (cdr x))].
631
 
 
632
 
     If ~c[ccm-cs] is ~c[:EQUAL] we will compare ~c[m1] to
633
 
     ~c[m2] if ~c[v1] and ~c[v2] are equal. If ~c[value] is ~c[:ALL] we will
634
 
     compare ~c[m1] to ~c[m2'] if ~c[v2] is a subset of ~c[v1]. If ~c[value] is
635
 
     ~c[:SOME] we will compare ~c[m1] to ~c[m2'] if ~c[v1] and ~c[v2]
636
 
     intersect. If ~c[value] is ~c[:NONE] we will compare ~c[m1] to ~c[m2] no
637
 
     matter what.
638
 
 
639
 
     There is one caveat to what was just said: if ~c[m1] and ~c[m2] are
640
 
     syntactically equal, then regardless of the value of ~c[ccm-cs] we will
641
 
     construct a CCMF that will indicate that ~c[(o>= m1 m2)].
642
 
 
643
 
     
644
 
     ~c[Cpn] tells us how much ruler information we will use to compare CCMs.
645
 
     Unlike ACL2's measure-based termination analysis, CCG has the ability to
646
 
     use the rulers from both the current recursive call the next recursive
647
 
     call when constructing the CCMFs. That is, instead of asking ``What
648
 
     happens when I make recursive call A?'', we can ask, ``What happens when
649
 
     execution moves from recursive call A to recursive call B?''. Using this
650
 
     information potentially strengthens the termination analysis. For a brief
651
 
     example, consider the following code:
652
 
     ~bv[]
653
 
     (defun half (x)
654
 
        (if (zp x)
655
 
            0
656
 
          (1+ (half (- x 2)))))
657
 
     ~ev[]
658
 
 
659
 
     Clearly this is terminating. If we choose a measure of ~c[(nfix x)] we
660
 
     know that if ~c[x] is a positive integer, ~c[(nfix (- x 2))] is less than
661
 
     ~c[(nfix x)]. But consider the measure ~c[(acl2-count x)]. The strange
662
 
     thing here is that if ~c[x] is 1, then ~c[(acl2-count (- x 2))] is
663
 
     ~c[(acl2-count -1)], which is 1, i.e. the ~c[acl2-count] of ~c[x]. So, the
664
 
     fact that we know that ~c[x] is a positive integer is not enough to show
665
 
     that this measure decreases. But notice that if ~c[x] is 1, we will recur
666
 
     just one more time. So, if we consider what happens when we move from the
667
 
     recursive call back to itself. In this case we know 
668
 
    ~c[(and (not (zp x)) (not (zp (- x 2))))]. 
669
 
     Under these conditions, it is trivial for ACL2 to prove that
670
 
     ~c[(acl2-count (- x 2))] is always less than ~c[(acl2-count x)].
671
 
 
672
 
     However, this can make the CCG analysis much more expensive, since
673
 
     information about how values change from step to step are done on a
674
 
     per-edge, rather than a per-node basis in the CCG (where the nodes are the
675
 
     recursive calls and the edges indicate that execution can move from one
676
 
     call to another in one step). Thus, calculating CCMFs (how values change
677
 
     across recursive calls) on a per-edge basis rather than a per-node basis
678
 
     can require n^2 instead of n prover queries.
679
 
 
680
 
     If ~c[cpn] is ~c[t], we will use only the ruler of the current recursive
681
 
     call to compute our CCMFs. If it is ~c[nil], we will use the much more
682
 
     expensive technique of using the rulers of the current and next call.
683
 
 
684
 
     Levels of the hierarchy of the form ~c[(:measure pt)] specify that the CCG
685
 
     analysis is to be set aside for a step, and the traditional measure-based
686
 
     termination proof is to be attempted. Here, ~c[pt] has the same meaning as
687
 
     it does in a CCG hierarchy level. That is, it limits the measure proof in
688
 
     order to avoid prohibitively long termination analyses.
689
 
 
690
 
     The user may specify their own hierarchy in the form given above. The main
691
 
     restriction is that no level may be subsumed by an earlier level. That is,
692
 
     it should be the case at each level of the hierarchy, that it is possible
693
 
     to discover new information about the CCG that could help lead to a
694
 
     termination proof.
695
 
 
696
 
     In addition to constructing his or her own CCG hierarchy, the user may use
697
 
     several preset hierarchies:
698
 
 
699
 
     ~bv[]
700
 
     :CCG-ONLY
701
 
     ((:built-in-clauses :equal t)
702
 
      ((:induction-depth 0) :EQUAL t)
703
 
      ((:induction-depth 1) :EQUAL t)
704
 
      ((:induction-depth 1) :ALL   t)
705
 
      ((:induction-depth 1) :SOME  t)
706
 
      ((:induction-depth 1) :NONE  t)
707
 
      ((:induction-depth 1) :EQUAL nil)
708
 
      ((:induction-depth 1) :ALL   nil)
709
 
      ((:induction-depth 1) :SOME  nil)
710
 
      ((:induction-depth 1) :NONE  nil))
711
 
 
712
 
     :CCG-ONLY-CPN
713
 
     ((:built-in-clauses :equal t)
714
 
      ((:induction-depth 0) :EQUAL t)
715
 
      ((:induction-depth 1) :EQUAL t)
716
 
      ((:induction-depth 1) :ALL   t)
717
 
      ((:induction-depth 1) :SOME  t)
718
 
      ((:induction-depth 1) :NONE  t))
719
 
 
720
 
     :HYBRID
721
 
     ((:built-in-clauses :equal t)
722
 
      (:measure (:induction-depth 1))
723
 
      ((:induction-depth 0) :EQUAL t)
724
 
      ((:induction-depth 1) :EQUAL t)
725
 
      ((:induction-depth 1) :ALL   t)
726
 
      ((:induction-depth 1) :SOME  t)
727
 
      ((:induction-depth 1) :NONE  t)
728
 
      ((:induction-depth 1) :EQUAL nil)
729
 
      ((:induction-depth 1) :ALL   nil)
730
 
      ((:induction-depth 1) :SOME  nil)
731
 
      ((:induction-depth 1) :NONE  nil))
732
 
 
733
 
     :HYBRID-CPN
734
 
     ((:built-in-clauses :equal t)
735
 
      (:measure (:induction-depth 1))
736
 
      ((:induction-depth 0) :EQUAL t)
737
 
      ((:induction-depth 1) :EQUAL t)
738
 
      ((:induction-depth 1) :ALL   t)
739
 
      ((:induction-depth 1) :SOME  t)
740
 
      ((:induction-depth 1) :NONE  t))
741
 
     ~ev[]
742
 
 
743
 
     The default hierarchy for CCG termination analysis is :CCG-ONLY.~/"
744
 
 
745
 
  `(er-progn
746
 
    (chk-ccg-hierarchy ',v "SET-CCG-HIERARCHY" state)
747
 
    (with-output :off summary
748
 
     (progn (table acl2-defaults-table ':ccg-hierarchy ',(fix-ccg-hierarchy v))
749
 
            (table acl2-defaults-table ':ccg-hierarchy)))))
750
 
 
751
 
;; adds :ccg-time-limit to the acl2-global-table.
752
 
 
753
 
(add-acl2-defaults-table-key :ccg-time-limit
754
 
                             (or (null val)
755
 
                                 (and (rationalp val)
756
 
                                      (< 0 val))))
757
 
 
758
 
(logic)
759
 
(set-state-ok nil)
760
 
 
761
 
(defdoc set-ccg-time-limit
762
 
  ":Doc-Section CCG
763
 
 
764
 
  Set a global time limit for CCG-based termination proofs.~/
765
 
  ~bv[]
766
 
  Examples:
767
 
  (set-ccg-time-limit 120)  ; limits termination proofs to 120 seconds.
768
 
  (set-ccg-time-limit 53/2) ; limits termination proofs to 53/2 seconds.
769
 
  (set-ccg-time-limit nil)  ; removes any time limit for termination proofs.
770
 
  ~ev[]
771
 
 
772
 
  Introduced by the CCG analysis book, this macro sets a global time limit for
773
 
  the completion of the CCG analysis. The time limit is given as a rational
774
 
  number, signifying the number of seconds to which the CCG analysis should be
775
 
  limited, or nil, signifying that there should be no such time limit. If CCG
776
 
  has not completed its attempt to prove termination in the number of seconds
777
 
  specified, it will immediately throw an error and the definition attempt will
778
 
  fail. Note: This is an event!  It does not print the usual event summary but
779
 
  nevertheless changes the ACL2 logical ~il[world] and is so recorded.~/
780
 
 
781
 
  ~bv[] General Form:
782
 
  (set-ccg-time-limit tl)
783
 
  ~ev[]
784
 
  where ~c[tl] is a positive rational number or nil. The default is nil. If the
785
 
  time limit is nil, the CCG analysis will work as long as it needs to in order
786
 
  to complete the analysis. If the ~c[tl] is a positive rational number,
787
 
  all CCG analyses will be limited to ~c[tl] seconds.
788
 
 
789
 
  To see what the current time limit is, see
790
 
  ~ilc[get-ccg-time-limit].~/")
791
 
 
792
 
(defun get-ccg-time-limit (wrld)
793
 
  ":Doc-Section CCG
794
 
 
795
 
  Returns the current default ccg-time-limit setting.~/
796
 
 
797
 
  ~bv[]
798
 
  Examples:
799
 
  (get-ccg-time-limit (w state))
800
 
  ~ev[]
801
 
 
802
 
  This will return the time-limit as specified by the current world. ~/
803
 
  
804
 
  ~bv[]
805
 
  General Form:
806
 
  (get-time-limit wrld)
807
 
  ~ev[]
808
 
 
809
 
  where ~c[wrld] is a ~il[world]. For information on the settings and
810
 
  their meaning, ~pl[set-termination-method].~/"
811
 
 
812
 
  (declare (xargs :guard (and (plist-worldp wrld)
813
 
                              (alistp (table-alist 'acl2-defaults-table wrld)))))
814
 
  (let ((entry (assoc :ccg-time-limit (table-alist 'acl2-defaults-table wrld))))
815
 
    (or (and entry (cdr entry)) nil)))
816
 
 
817
 
(verify-guards get-ccg-time-limit)
818
 
 
819
 
(defmacro set-ccg-print-proofs (v)
820
 
  ":Doc-Section CCG
821
 
 
822
 
   controls whether proof attempts are printed during CCG analysis~/
823
 
 
824
 
   ~bv[]
825
 
   Examples:
826
 
   (set-ccg-print-proofs t)
827
 
   (set-ccg-print-proofs nil)
828
 
   :set-ccg-print-proofs t~/
829
 
 
830
 
   General Form:
831
 
   (set-ccg-print-proofs v)
832
 
   ~ev[]
833
 
   If ~c[v] is ~c[nil], no proof attempts will be printed during CCG
834
 
   analysis. This is the default. If ~c[v] is anything but ~c[nil], proofs will
835
 
   be displayed. Fair warning: there is potentially a large amount of prover
836
 
   output that might be displayed. It is probably better to use
837
 
   ~l[set-ccg-inhibit-output-lst] to un-inhibit ~c['query] output to figure out
838
 
   what lemmas might be needed to get a given query to go through."
839
 
 
840
 
 `(assign ccg-print-proofs ,v))
841
 
 
842
 
(defmacro get-ccg-print-proofs ()
843
 
  ":Doc-Section CCG
844
 
  
845
 
  returns the setting that controls whether proof attempts are printed during
846
 
  CCG analysis~/
847
 
 
848
 
  ~bv[]
849
 
  Examples:
850
 
  (get-ccg-print-proofs)
851
 
  :get-ccg-print-proofs
852
 
  ~ev[]~/
853
 
 
854
 
  See ~l[set-ccg-print-proofs] for details."
855
 
 '(and (f-boundp-global 'ccg-print-proofs state)
856
 
       (f-get-global 'ccg-print-proofs state)))
857
 
 
858
 
;; The following code is used to implement a parallel to io? as defined in
859
 
;; basis.lisp. Make sure this all stays in sync with the parallel definitions
860
 
;; in that file. To find out more, see the "Essay on Inhibited Output and the
861
 
;; Illusion of Windows" in the comments of basis.lisp.
862
 
 
863
 
;; *ccg-window-descriptions* parallels *window-descriptions* as defined in
864
 
;; basis.lisp. See the comments there for details.
865
 
 
866
 
(defconst *ccg-window-descriptions*
867
 
;                    str clr top pop
868
 
  '((query           "4" nil nil nil)
869
 
    (basics          "4" nil nil nil)
870
 
    (performance     "4" nil nil nil)
871
 
    (build/refine    "4" nil nil nil)
872
 
    (size-change     "4" nil nil nil)
873
 
    (counter-example "4" nil nil nil)))
874
 
 
875
 
;; The following mirrors *valid-output-names* as defined in axioms.lisp. This
876
 
;; is the list of valid io "kinds" that can be inhibited.
877
 
 
878
 
(defconst *ccg-valid-output-names*
879
 
  '(query basics performance build/refine size-change counter-example))
880
 
 
881
 
(defmacro set-ccg-inhibit-output-lst (lst)
882
 
 ":Doc-Section CCG
883
 
 
884
 
  control output during CCG termination analysis~/
885
 
  ~bv[]
886
 
  Examples:
887
 
  (set-ccg-inhibit-output-lst '(query))
888
 
  (set-ccg-inhibit-output-lst '(build/refine size-change))
889
 
  (set-ccg-inhibit-output-lst *ccg-valid-output-names*) ; inhibit all ccg output
890
 
  :set-ccg-inhibit-output-lst (build/refine size-change)~/
891
 
 
892
 
  General Form:
893
 
  (set-ccg-inhibit-output-lst lst)
894
 
  ~ev[]
895
 
  where ~c[lst] is a form (which may mention ~ilc[state]) that evaluates
896
 
  to a list of names, each of which is the name of one of the
897
 
  following ``kinds'' of output produced by the CCG termination analysis.
898
 
  ~bv[]
899
 
    query            prints the goal, restrictions, and results of each prover
900
 
                     query (for a discussion on displaying actual proofs,
901
 
                     see ~c[set-ccg-display-proofs](yet to be documented).
902
 
    basics           the basic CCG output, enough to follow along, but concise
903
 
                     enough to keep from drowning in output
904
 
    performance      performance information for the size change analysis
905
 
    build/refine     the details of CCG construction and refinement
906
 
    size-change      the details of size change analysis
907
 
    counter-example  prints out a counter-example that can be useful for
908
 
                     debugging failed termination proof attempts.
909
 
  ~ev[]
910
 
  It is possible to inhibit each kind of output by putting the corresponding
911
 
  name into ~c[lst].  For example, if ~c['query] is included in (the value of)
912
 
  ~c[lst], then no information about individual queries is printed during CCG
913
 
  analysis.
914
 
 
915
 
  The default setting is ~c['(query performance build/refine size-change)].
916
 
  That is, by default only the basic CCG information and counter-example (in
917
 
  the case of a failed proof attempt) are printed. This should hopefully be
918
 
  adequate for most users."
919
 
  
920
 
  `(let ((lst ,lst))
921
 
     (cond ((not (true-listp lst))
922
 
            (er soft 'set-ccg-inhibit-output-lst
923
 
                "The argument to set-ccg-inhibit-output-lst must evaluate to a ~
924
 
                 true-listp, unlike ~x0."
925
 
                lst))
926
 
           ((not (subsetp-eq lst *ccg-valid-output-names*))
927
 
            (er soft 'set-ccg-inhibit-output-lst
928
 
                "The argument to set-ccg-inhibit-output-lst must evalutate to a ~
929
 
                 subset of the list ~X01, but ~x2 contains ~&3."
930
 
                *ccg-valid-output-names*
931
 
                nil
932
 
                ',lst
933
 
                (set-difference-eq lst *ccg-valid-output-names*)))
934
 
           (t (pprogn
935
 
               (f-put-global 'ccg-inhibit-output-lst lst state)
936
 
               (value lst))))))
937
 
 
938
 
(defmacro get-ccg-inhibit-output-lst ()
939
 
  ":Doc-Section CCG
940
 
 
941
 
  returns the list of ``kinds'' of output that will be inhibited during CCG
942
 
  analysis~/
943
 
 
944
 
 
945
 
  ~bv[]
946
 
  Examples:
947
 
  (get-ccg-inhibit-output-lst)
948
 
  :get-ccg-inhibit-output-lst
949
 
  ~bv[]~/
950
 
 
951
 
  See ~l[set-ccg-inhibit-output-lst]."
952
 
  '(if (f-boundp-global 'ccg-inhibit-output-lst state)
953
 
       (f-get-global 'ccg-inhibit-output-lst state)
954
 
     '(query performance build/refine size-change)))
955
 
 
956
 
(program)
957
 
(set-state-ok t)
958
 
 
959
 
(defmacro ccg-io? (token commentp shape vars body
960
 
                     &key
961
 
                     (clear 'nil clear-argp)
962
 
                     (cursor-at-top 'nil cursor-at-top-argp)
963
 
                     (pop-up 'nil pop-up-argp)
964
 
                     (default-bindings 'nil)
965
 
                     (chk-translatable 't))
966
 
 
967
 
; NOTE: Keep this in sync with io? as defined in basis.lisp. This definition is
968
 
; almost identical to that one, except we use *ccg-window-descriptions* and
969
 
; *ccg-valid-output-names* instead of *window-descriptions* and
970
 
; *valid-output-names*, and we store our inhibited-lst in the global table
971
 
; under the symbol 'ccg-inhibit-output-lst instead of 'inhibit-output-lst. The
972
 
; remaining comments in this definition are from the original io? definition:
973
 
 
974
 
; Typical use (io? error nil (mv col state) (x y) (fmt ...)), meaning execute
975
 
; the fmt statement unless 'error is on 'inhibit-output-lst.  The mv expression
976
 
; is the shape of the output produced by the fmt expression, and the list (x y)
977
 
; for vars indicates the variables other than state that occur free in that
978
 
; expression.  See the comment above, and see the Essay on Saved-output for a
979
 
; comment that gives a convenient macro for obtaining the free variables other
980
 
; than state that occur free in body.
981
 
 
982
 
; Default-bindings is a list of doublets (symbol value).  It is used in order
983
 
; to supply a non-nil return value for other than state when io is suppressed.
984
 
; For example, fmt returns col and state, as suggested by the third (shape)
985
 
; argument below.  Without the :default-bindings, this form would evaluate to
986
 
; (mv nil state) if event IO is inhibited.  But there are fixnum declarations
987
 
; that require the first return value of fmt to be an integer, and we can
988
 
; specify the result in the inhibited case to be (mv 0 state) with the
989
 
; following :default-bindings:
990
 
 
991
 
; (io? event nil (mv col state) nil (fmt ...) :default-bindings ((col 0)))
992
 
 
993
 
; The values in :default-bindings are evaluated, so it would be equivalent to
994
 
; replace 0 with (- 4 4), for example.
995
 
 
996
 
    (declare (xargs :guard (and (symbolp token)
997
 
                              (symbol-listp vars)
998
 
                              (no-duplicatesp vars)
999
 
                              (not (member-eq 'state vars))
1000
 
                              (assoc-eq token *ccg-window-descriptions*))))
1001
 
  (let* ((associated-window (assoc-eq token *ccg-window-descriptions*))
1002
 
         (expansion
1003
 
          `(let* ((io?-output-inhibitedp
1004
 
                   (member-eq ',token
1005
 
                              (get-ccg-inhibit-output-lst)))
1006
 
                  (io?-alist
1007
 
                   (and (not io?-output-inhibitedp)
1008
 
                        (list
1009
 
                         (cons #\w ,(cadr associated-window))
1010
 
                         (cons #\c ,(if clear-argp
1011
 
                                        clear
1012
 
                                      (caddr associated-window)))
1013
 
                         (cons #\t ,(if cursor-at-top-argp
1014
 
                                        cursor-at-top
1015
 
                                      (cadddr associated-window)))
1016
 
                         (cons #\p ,(if pop-up-argp
1017
 
                                        pop-up
1018
 
                                      (car (cddddr associated-window))))
1019
 
 
1020
 
; Peter Dillinger requested the following binding, so that he could specify a
1021
 
; window prelude string that distinguishes between, for example, "prove",
1022
 
; "event", and "summary" output, which with the default string would all just
1023
 
; show up as window 4.
1024
 
 
1025
 
                         (cons #\k ,(symbol-name token))))))
1026
 
             (pprogn
1027
 
              (if (or io?-output-inhibitedp
1028
 
                      (null (f-get-global 'window-interfacep state)))
1029
 
                  state
1030
 
                (mv-let (io?-col state)
1031
 
                        (fmt1! (f-get-global 'window-interface-prelude state)
1032
 
                               io?-alist 0 *standard-co* state nil)
1033
 
                        (declare (ignore io?-col))
1034
 
                        state))
1035
 
              ,(let ((body
1036
 
                      `(check-vars-not-free
1037
 
                        (io?-output-inhibitedp io?-alist)
1038
 
                        (check-exact-free-vars io? (state ,@vars) ,body)))
1039
 
                     (nil-output (if (eq shape 'state)
1040
 
                                     'state
1041
 
                                   (cons 'mv (io?-nil-output (cdr shape)
1042
 
                                                             default-bindings))))
1043
 
                     (postlude
1044
 
                      `(mv-let
1045
 
                        (io?-col state)
1046
 
                        (if (or io?-output-inhibitedp
1047
 
                                (null (f-get-global 'window-interfacep state)))
1048
 
                            (mv 0 state)
1049
 
                          (fmt1! (f-get-global 'window-interface-postlude state)
1050
 
                                 io?-alist 0 *standard-co* state nil))
1051
 
                        (declare (ignore io?-col))
1052
 
                        (check-vars-not-free
1053
 
                         (io?-output-inhibitedp io?-alist io?-col)
1054
 
                         ,shape))))
1055
 
                 (let ((body (if commentp
1056
 
                                 `(let ,(io?-wormhole-bindings 0 vars)
1057
 
                                    ,body)
1058
 
                               body)))
1059
 
                   (cond
1060
 
                    ((eq shape 'state)
1061
 
                     `(pprogn
1062
 
                       (if io?-output-inhibitedp state ,body)
1063
 
                       ,postlude))
1064
 
                    (t `(mv-let ,(cdr shape)
1065
 
                                (if io?-output-inhibitedp
1066
 
                                    ,nil-output
1067
 
                                  ,body)
1068
 
                                ,postlude)))))))))
1069
 
    (cond
1070
 
     (commentp
1071
 
      (let ((form
1072
 
             (cond
1073
 
              ((eq shape 'state)
1074
 
               `(pprogn ,expansion (value :q)))
1075
 
              (t
1076
 
               `(mv-let ,(cdr shape)
1077
 
                        ,expansion
1078
 
                        (declare
1079
 
                         (ignore ,@(remove1-eq 'state (cdr shape))))
1080
 
                        (value :q))))))
1081
 
        `(prog2$
1082
 
          ,(if chk-translatable
1083
 
               `(chk-translatable ,body ,shape)
1084
 
             nil)
1085
 
          (wormhole 'comment-window-io
1086
 
                    '(lambda (whs)
1087
 
                       (set-wormhole-entry-code whs :ENTER))
1088
 
                    (list ,@vars)
1089
 
                    ',form
1090
 
                    :ld-error-action :return!
1091
 
                    :ld-verbose nil
1092
 
                    :ld-pre-eval-print nil
1093
 
                    :ld-prompt nil))))
1094
 
     (t `(pprogn
1095
 
          (cond ((saved-output-token-p ',token state)
1096
 
                 (push-io-record nil ; io-marker
1097
 
                                 (list 'let
1098
 
                                       (list ,@(formal-bindings vars))
1099
 
                                       ',expansion)
1100
 
                                 state))
1101
 
                (t state))
1102
 
          ,expansion)))))
1103
 
 
1104
 
 
1105
 
; END public configuration interface
1106
 
 
1107
 
; BEGIN mostly raw definitions for the CCG analysis
1108
 
 
1109
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1110
 
;;; STRUCT DEFINITIONS                                            ;;;
1111
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1112
 
 
1113
 
(defstruct-raw funct
1114
 
 
1115
 
  ;; The funct defstruct represents the relevant information about the function
1116
 
  ;; definitions provided by the user. 
1117
 
  ;;
1118
 
  ;;  * fn: the function name
1119
 
 
1120
 
  (fn nil :type symbol)
1121
 
  
1122
 
  ;;  * formals: the formals of the function
1123
 
 
1124
 
  (formals nil :type list)
1125
 
 
1126
 
  ;;  * ccms: the ccms associated with the function. This will be a vector of
1127
 
  ;;    terms, whose value will always be natural numbers.
1128
 
 
1129
 
  (ccms nil :type sequence))
1130
 
 
1131
 
(defstruct-raw context
1132
 
 
1133
 
;; The context defstruct is used to represent a calling context. The
1134
 
;; individual fields are as follows:
1135
 
;;
1136
 
;; * ruler: the ruler of the context.
1137
 
 
1138
 
  (ruler nil)
1139
 
 
1140
 
;; * call: the actual recursive call of the context.
1141
 
 
1142
 
  (call nil)
1143
 
 
1144
 
;; * parent-funct: the funct representing the function containing the context.
1145
 
 
1146
 
  (parent-funct (make-funct) :type funct)
1147
 
 
1148
 
;; * call-funct: the funct representing the function called by the call of the
1149
 
;;   context. 
1150
 
 
1151
 
  (call-funct (make-funct) :type funct)
1152
 
 
1153
 
;; * num: a unique ID number assigned to each context. Also indicates
1154
 
;;   its index in the context-array.
1155
 
 
1156
 
  num)
1157
 
 
1158
 
;; The following macros make it easy to get and set the fields of the functs of
1159
 
;; a given context.
1160
 
 
1161
 
(defmacro-raw context-fn (c)
1162
 
  `(funct-fn (context-parent-funct ,c)))
1163
 
 
1164
 
(defmacro-raw context-formals (c)
1165
 
  `(funct-formals (context-parent-funct ,c)))
1166
 
 
1167
 
(defmacro-raw context-callfn (c)
1168
 
  `(funct-fn (context-call-funct ,c)))
1169
 
 
1170
 
(defmacro-raw context-callformals (c)
1171
 
  `(funct-formals (context-call-funct ,c)))
1172
 
 
1173
 
(defmacro-raw context-ccms (c)
1174
 
  `(funct-ccms (context-parent-funct ,c)))
1175
 
 
1176
 
(defstruct-raw ccmf-node
1177
 
 
1178
 
  ;; The ccmf-node struct represents nodes in the graph representation
1179
 
  ;; of a CCMF (see the comments for the struct ccmf). It contains two
1180
 
  ;; lists of edges: >-edges is a list of the indices of the CCMs that
1181
 
  ;; are always < the current one, and likewise >=-edges is a list of
1182
 
  ;; the indeces of the CCMs that are always <= the current one.
1183
 
 
1184
 
  (>-edges nil :type list)
1185
 
  (>=-edges nil :type list))
1186
 
 
1187
 
(defstruct-raw ccmf
1188
 
 
1189
 
  ;; The ccmf struct represents CCMFs as a graph with edges labeled by
1190
 
  ;; > or >=. The fields are as follows:
1191
 
  ;;
1192
 
  ;; * firstsite: the index of the "tail" context of the CCMF.
1193
 
 
1194
 
  (firstsite 0 :type fixnum)
1195
 
 
1196
 
  ;; * lastsite: the index of the "head" context of the CCMF.
1197
 
 
1198
 
  (lastsite 0 :type fixnum)
1199
 
 
1200
 
  ;; * fc-num: the original index of the "tail" context. This is needed
1201
 
  ;;   because CCGs get separated into SCCs, so the index of the head
1202
 
  ;;   and tail contexts in the current SCC (firstsite and lastsite)
1203
 
  ;;   and the context in the original context array may be
1204
 
  ;;   different. Also, this item is actually a list of indices because
1205
 
  ;;   of the possibility of context merging. The list keeps track of
1206
 
  ;;   the original indices of all the contexts that were merged to
1207
 
  ;;   make the current head or tail context. Currently, absorption and
1208
 
  ;;   merging are not used, so we tend to just refer to the first item
1209
 
  ;;   in the list.
1210
 
 
1211
 
  (fc-num (list 0) :type (cons fixnum list))
1212
 
 
1213
 
  ;; * lc-num: the original index of the "head" context (see note for
1214
 
  ;;   fc-num).
1215
 
 
1216
 
  (lc-num (list 0) :type (cons fixnum list))
1217
 
 
1218
 
  ;; * graph: the graph representing the CCMF. This is an array of
1219
 
  ;;   ccmf-nodes.
1220
 
 
1221
 
  (graph nil :type (array ccmf-node))
1222
 
 
1223
 
  ;; * in-sizes: the number of CCMFs for the "tail" context.
1224
 
 
1225
 
  (in-sizes 0 :type fixnum)
1226
 
 
1227
 
  ;; * out-sizes: the number of CCMFs for the "head" context.
1228
 
 
1229
 
  (out-sizes 0 :type fixnum)
1230
 
 
1231
 
  ;; * steps: the number of steps in the CCG represented by the
1232
 
  ;;   CCMF. This is used in the sct algorithm.
1233
 
 
1234
 
  (steps 1 :type fixnum))
1235
 
 
1236
 
 
1237
 
(defstruct-raw accg-edge
1238
 
  ;; The accg-edge struct represents edges in the annotated CCG (ACCG).
1239
 
 
1240
 
  ;; * tail: the index of the tail ACCG node of the edge.
1241
 
  
1242
 
  (tail -1 :type fixnum)
1243
 
  
1244
 
  ;; * head: the index of the head ACCG node of the edge.
1245
 
 
1246
 
  (head -1 :type fixnum)
1247
 
 
1248
 
  ;; * ccmf: the CCMF associated with the edge in the ACCG.
1249
 
 
1250
 
  (ccmf nil :type (or null ccmf)))
1251
 
 
1252
 
 
1253
 
(defstruct-raw accg-node
1254
 
;; The accg-node struct represents nodes in the ACCG. An ACCG is an
1255
 
;; array of these.
1256
 
 
1257
 
  ;; * context: the context associated with the node.
1258
 
  
1259
 
  (context (make-context) :type context)
1260
 
  
1261
 
  ;; * fwd-edges: edges for which the current node is the tail.
1262
 
 
1263
 
  (fwd-edges nil :type list)
1264
 
  
1265
 
  ;; * bwd-edges: edges for which the current node is the head.
1266
 
  
1267
 
  (bwd-edges nil :type list)
1268
 
  
1269
 
  ;; * num: the index of the node in the array of nodes of the ACCG.
1270
 
  
1271
 
  (num 0 :type fixnum))
1272
 
 
1273
 
 
1274
 
;; The following macros are self-explanitory. They allow us to refer
1275
 
;; to fields of a substruct of a given struct as if it were a field in
1276
 
;; the struct.
1277
 
 
1278
 
(defmacro-raw accg-node-ruler (accg)
1279
 
  `(context-ruler (accg-node-context ,accg)))
1280
 
 
1281
 
(defmacro-raw accg-node-call (accg)
1282
 
  `(context-call (accg-node-context ,accg)))
1283
 
 
1284
 
(defmacro-raw accg-node-parent-funct (accg)
1285
 
  `(context-parent-funct (accg-node-context ,accg)))
1286
 
 
1287
 
(defmacro-raw accg-node-call-funct (accg)
1288
 
  `(context-call-funct (accg-node-context ,accg)))
1289
 
 
1290
 
(defmacro-raw accg-node-fn (accg)
1291
 
  `(context-fn (accg-node-context ,accg)))
1292
 
 
1293
 
(defmacro-raw accg-node-formals (accg)
1294
 
  `(context-formals (accg-node-context ,accg)))
1295
 
 
1296
 
(defmacro-raw accg-node-callformals (accg)
1297
 
  `(context-callformals (accg-node-context ,accg)))
1298
 
 
1299
 
(defmacro-raw accg-node-callfn (accg)
1300
 
  `(context-callfn (accg-node-context ,accg)))
1301
 
 
1302
 
(defmacro-raw accg-node-context-num (accg)
1303
 
  `(context-num (accg-node-context ,accg)))
1304
 
 
1305
 
(defmacro-raw accg-node-ccms (accg)
1306
 
  `(context-ccms (accg-node-context ,accg)))
1307
 
 
1308
 
;;; The following two structs are used to represent an SRG. See the
1309
 
;;; paper on the polynomial approximation of SCT (a.k.a. SCP) for a
1310
 
;;; full explanation. Briefly: an SRG has CCMs for nodes and edges
1311
 
;;; labeled with > or >= between them as the corresponding CCMF
1312
 
;;; dictates. In other words, the graph connects all the CCMF graphs
1313
 
;;; into one graph.
1314
 
 
1315
 
(defstruct-raw srg-edge
1316
 
  ;; The srg-edge represents an edge in an SRG.
1317
 
 
1318
 
  ;; * tail: the tail CCM of the edge.
1319
 
  
1320
 
  (tail  0 :type fixnum)
1321
 
  
1322
 
  ;; * head: the head CCM of the edge.
1323
 
 
1324
 
  (head  0 :type fixnum)
1325
 
  
1326
 
  ;; * ccmf: the CCMF from which this edge was derived.
1327
 
 
1328
 
  (ccmf (make-ccmf) :type ccmf)
1329
 
  
1330
 
;; * label: generally > or >=, indicating the label of the CCMF edge
1331
 
;;   from which this edge is derived.
1332
 
 
1333
 
  (label 'none :type symbol))
1334
 
 
1335
 
(defstruct-raw srg-node
1336
 
  ;; The srg-node struct represents a node of the SRG
1337
 
 
1338
 
  ;; * node: the index of the ACCG node associated with this SRG node.
1339
 
 
1340
 
  (node 0 :type fixnum)
1341
 
 
1342
 
  ;; * ccm: the index of the CCM in the array of CCMs assigned to the
1343
 
  ;;   corresponding ACCG node.
1344
 
 
1345
 
  (ccm 0 :type fixnum)
1346
 
 
1347
 
  ;; * fwd-edges: the list of srg-edges of which this srg-node is the
1348
 
  ;;   tail.
1349
 
 
1350
 
  (fwd-edges nil :type list)
1351
 
 
1352
 
  ;; * bwd-edges: the list of srg-edges of which this srg-node is the
1353
 
  ;;   head.
1354
 
 
1355
 
  (bwd-edges nil :type list))
1356
 
 
1357
 
;;; the memoization struct contains the information that we use for
1358
 
;;; memoization. The fields are as follows:
1359
 
;;;
1360
 
;;; * proved: the list of proved conjectures.
1361
 
;;; * unproved0: the list of conjectures that we could not prove with 0 inductions.
1362
 
;;; * unproved1: the list of conjectures that we could not prove with 1 induction.
1363
 
 
1364
 
(defstruct-raw memoization
1365
 
  (proved nil :type list)
1366
 
  (unproved (make-array 0 :initial-element nil :element-type 'list)
1367
 
            :type (vector list)))
1368
 
 
1369
 
(defun-raw create-memoization (max-ind)
1370
 
  (make-memoization :unproved (make-array (1+ max-ind)
1371
 
                                          :initial-element nil
1372
 
                                          :element-type 'list)))
1373
 
 
1374
 
;;; ccg-simplify-hyps-no-split takes a list of expressions, hyps,
1375
 
;;; representing a conjunction of predicates and quickly simplifies
1376
 
;;; them in such a way that does not cause a case split. It returns
1377
 
;;; the list of simplified expressions.
1378
 
(defun-raw ccg-simplify-hyps-no-split (hyps ctx ens wrld state)
1379
 
  (declare (ignore ctx))
1380
 
  (mv-let (nhyps ttree)
1381
 
          (normalize-lst hyps t nil ens wrld nil)
1382
 
          (er-progn
1383
 
           (accumulate-ttree-and-step-limit-into-state ttree :skip state)
1384
 
           (value (flatten-ands-in-lit-lst nhyps)))))
1385
 
 
1386
 
(defrec query-spec-var
1387
 
  ((wrld . ens)
1388
 
   (ctx . otf-flg)
1389
 
   (stop-time . mem))
1390
 
  t)
1391
 
 
1392
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1393
 
;;; Printing Functions                                               ;;;
1394
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1395
 
 
1396
 
(defun-raw print-funct-ccms (functs wrld state)
1397
 
  (if (endp functs)
1398
 
      state
1399
 
    (pprogn
1400
 
     (fms "The CCM~#1~[~/s~] for ~x0 ~#1~[is~/are~] ~&1.~|"
1401
 
          `((#\0 . ,(funct-fn (car functs)))
1402
 
            (#\1 . ,(untranslate-lst
1403
 
                     (mapcar #'de-propagate
1404
 
                             (coerce (funct-ccms (car functs))
1405
 
                                     'list))
1406
 
                     nil
1407
 
                     wrld)))
1408
 
          *standard-co*
1409
 
          state
1410
 
          nil)
1411
 
     (print-funct-ccms (cdr functs) wrld state))))
1412
 
      
1413
 
;; The following definitions culminate in print-counter-example.
1414
 
 
1415
 
(defun-raw prettify-ccms (ccm-array vars vals wrld)
1416
 
  (let ((fn (if vars
1417
 
                #'(lambda (x)
1418
 
                    (untranslate (subcor-var vars vals 
1419
 
                                             (de-propagate x))
1420
 
                                 nil wrld))
1421
 
              #'(lambda (x)
1422
 
                  (untranslate (de-propagate x)
1423
 
                               nil wrld)))))
1424
 
    (map 'vector fn ccm-array)))             
1425
 
 
1426
 
(defmacro-raw ce-defun-fn (defun)
1427
 
  `(cadr ,defun))
1428
 
 
1429
 
(defmacro-raw ce-defun-formals (defun)
1430
 
  `(caddr ,defun))
1431
 
 
1432
 
(defmacro-raw ce-defun-body (defun)
1433
 
  `(cadddr ,defun))
1434
 
 
1435
 
(defmacro-raw ce-defun-test (defun)
1436
 
  `(let ((body (ce-defun-body ,defun)))
1437
 
     (if (eq (fn-symb body) 'if)
1438
 
         (cadr body)
1439
 
       T)))
1440
 
 
1441
 
(defmacro-raw ce-defun-call (defun)
1442
 
  `(let ((body (ce-defun-body ,defun)))
1443
 
     (if (eq (fn-symb body) 'if)
1444
 
         (caddr body)
1445
 
       body)))
1446
 
 
1447
 
(defun-raw ccmf-graph-no-edges? (ccmf-graph)
1448
 
  (loop for node across ccmf-graph
1449
 
        when (or (consp (ccmf-node->-edges node))
1450
 
                 (consp (ccmf-node->=-edges node)))
1451
 
          return nil
1452
 
        finally (return t)))
1453
 
 
1454
 
(defun-raw ccmf-graph-term (i graph ccms0 ccms1 acc)
1455
 
  (if (< i 0)
1456
 
      (cond ((endp acc) acc)
1457
 
            ((endp (cdr acc)) (car acc))
1458
 
            (t (cons 'and acc)))
1459
 
    (let* ((node (aref graph i))
1460
 
           (>=-edges (ccmf-node->=-edges node))
1461
 
           (>-edges  (ccmf-node->-edges node))
1462
 
           (ccm (de-propagate (aref ccms0 i))))
1463
 
      (ccmf-graph-term (1- i)
1464
 
                       graph
1465
 
                       ccms0
1466
 
                       ccms1
1467
 
                       (append (mapcar #'(lambda (x)
1468
 
                                           `(> ,ccm 
1469
 
                                               ,(de-propagate
1470
 
                                                 (aref ccms1 x))))
1471
 
                                       >-edges)
1472
 
                               (mapcar #'(lambda (x)
1473
 
                                           `(>= ,ccm
1474
 
                                                ,(de-propagate
1475
 
                                                  (aref ccms1 x))))
1476
 
                                       >=-edges)
1477
 
                               acc)))))
1478
 
 
1479
 
(defun-raw print-ccmfs1 (defuns defun0 defun1 ccmfs flst funct0 col wrld state)
1480
 
  (if (endp defuns)
1481
 
      state
1482
 
    (let* ((graph (ccmf-graph (car ccmfs)))
1483
 
           (ne? (ccmf-graph-no-edges? graph))
1484
 
           (f0 (car defuns))
1485
 
           (f1 (if (consp (cdr defuns))
1486
 
                   (cadr defuns)
1487
 
                 defun0))
1488
 
           (f2 (cond ((endp (cdr defuns))
1489
 
                      defun1)
1490
 
                     ((endp (cddr defuns))
1491
 
                      defun0)
1492
 
                     (t (caddr defuns))))
1493
 
           (fn0 (ce-defun-fn f0))
1494
 
           (fn1 (ce-defun-fn f1))
1495
 
           (fn2 (ce-defun-fn f2))
1496
 
           (formals (ce-defun-formals f1))
1497
 
           (actuals (fargs (ce-defun-call f0)))
1498
 
           (ccms0 (prettify-ccms (funct-ccms (car flst)) nil nil wrld))
1499
 
           (ccms0-lst (coerce ccms0 'list))
1500
 
           (ccms1 (prettify-ccms (funct-ccms (if (endp (cdr flst))
1501
 
                                                 funct0
1502
 
                                               (cadr flst)))
1503
 
                                 formals actuals wrld))
1504
 
           (ccms1-lst (coerce ccms1 'list)))
1505
 
      (pprogn
1506
 
       (fms "When execution moves from the recursive call in ~x0 of ~x1 to ~
1507
 
             ~#2~[itself~/the recursive call in ~x1 of ~x3~], we need to know ~
1508
 
             how the measures of ~x0 compare with the result of substituting ~
1509
 
             the formals of ~x1 with the actuals of the call to ~x1 in the ~
1510
 
             measures of ~x1. The measure~#4~[~/s~] for ~x0 ~
1511
 
             ~#4~[is~/are~]:~|~%~*6~%The result~#5~[~/s~] of applying the ~
1512
 
             substitution to the measures of ~x1 ~#5~[is~/are~]:~|~%~*7~%We ~
1513
 
             know ~#8~[nothing about how the values of these CCMs ~
1514
 
             relate.~/the following about these CCMs:~%~%~Y9A~]~|~%If you can ~
1515
 
             show that any of the terms in the first list is always either ~
1516
 
             strictly greater than, or greater than or equal to some term in ~
1517
 
             the second list, this could be helpful for proving termination.~|"
1518
 
            (list (cons #\0 fn0)
1519
 
                  (cons #\1 fn1)
1520
 
                  (cons #\2 (if (eq fn0 fn1) 0 1))
1521
 
                  (cons #\3 fn2)
1522
 
                  (cons #\4 ccms0-lst)
1523
 
                  (cons #\5 ccms1-lst)
1524
 
                  (cons #\6 `("" "~x*.~|" "~x*~|" "~x*~|"
1525
 
                              ,ccms0-lst))
1526
 
                  (cons #\7 `("" "~x*.~|" "~x*~|" "~x*~|"
1527
 
                              ,ccms1-lst))
1528
 
                  (cons #\8 (if ne? 0 1))
1529
 
                  (cons #\9 (ccmf-graph-term
1530
 
                              (1- (array-dimension graph 0))
1531
 
                              graph
1532
 
                              ccms0
1533
 
                              ccms1
1534
 
                              nil))
1535
 
                  (cons #\A (term-evisc-tuple nil state)))
1536
 
            *standard-co* state nil)
1537
 
       (print-ccmfs1 (cdr defuns)
1538
 
                     defun0
1539
 
                     defun1
1540
 
                     (cdr ccmfs)
1541
 
                     (cdr flst)
1542
 
                     funct0
1543
 
                     col wrld state)))))
1544
 
 
1545
 
(defun-raw print-ccmfs (defuns ccmfs flst col wrld state)
1546
 
  (if (endp defuns)
1547
 
      state
1548
 
    (print-ccmfs1 defuns
1549
 
                   (car defuns)
1550
 
                   (if (endp (cdr defuns))
1551
 
                       (car defuns)
1552
 
                     (cadr defuns))
1553
 
                   ccmfs
1554
 
                   flst
1555
 
                   (car flst)
1556
 
                   col
1557
 
                   wrld
1558
 
                   state)))
1559
 
          
1560
 
(defun-raw print-ccms (defuns functs col wrld state)
1561
 
  ;; (format t "defuns: ~A functs: ~A col: ~A state: ~A~%" defuns functs col state)
1562
 
  (if (endp defuns)
1563
 
      (mv-let (col state)
1564
 
              (fmt1 "~|" nil col *standard-co* state nil)
1565
 
              (declare (ignore col))
1566
 
              state)
1567
 
    (mv-let
1568
 
     (col state)
1569
 
     (fmt1 "The CCM~#1~[~/s~] for ~x0 ~#1~[is~/are~] ~&1. "
1570
 
           (list (cons #\0 (cadar defuns))
1571
 
                 (cons #\1 (untranslate-lst
1572
 
                            (mapcar #'de-propagate
1573
 
                                    (coerce (funct-ccms (car functs))
1574
 
                                            'list))
1575
 
                            nil
1576
 
                            wrld)))
1577
 
           col
1578
 
           *standard-co*
1579
 
           state nil)
1580
 
     (print-ccms (cdr defuns) (cdr functs) col wrld state))))
1581
 
 
1582
 
(defun-raw produce-counter-example1 (ccmfs context-array alist wrld)
1583
 
  (if (endp ccmfs)
1584
 
      (mv nil nil nil)
1585
 
    (let* ((context (aref context-array (car (ccmf-fc-num (car ccmfs)))))
1586
 
           (funct (context-parent-funct context))
1587
 
           (fn (funct-fn funct)))
1588
 
      
1589
 
      (mv-let
1590
 
       (name i)
1591
 
       (ccg-counter-example-fn-name fn (assoc-eq-value fn 0 alist) wrld)
1592
 
       (mv-let
1593
 
        (contexts functs names)
1594
 
        (produce-counter-example1 (cdr ccmfs) context-array 
1595
 
                                  (assoc-set-eq fn (1+ i) alist) wrld)
1596
 
        (mv (cons context contexts)
1597
 
            (cons funct functs)
1598
 
            (cons name names)))))))
1599
 
 
1600
 
(defun-raw produce-counter-example2 (contexts names name0 ctx ens wrld state)
1601
 
  (if (endp contexts)
1602
 
      (value nil)
1603
 
    (let* ((context (car contexts))
1604
 
           (funct (context-parent-funct context))
1605
 
           (call (cons (if (endp (cdr names))
1606
 
                           name0
1607
 
                         (cadr names))
1608
 
                       (fargs (context-call context)))))
1609
 
      (er-let*
1610
 
       ((ruler (state-global-let*
1611
 
                ((inhibit-output-lst
1612
 
                  ;; no output here.
1613
 
                  *valid-output-names*))
1614
 
                ;; remove any redundant or subsumed hyps.
1615
 
                (simp-hyps0 (context-ruler context)
1616
 
                            ctx ens wrld state nil t nil :term-order)))
1617
 
        (body (value (if (endp ruler)
1618
 
                         call
1619
 
                       `(if ,(if (endp (cdr ruler))
1620
 
                                 (car ruler)
1621
 
                               `(and ,@ruler))
1622
 
                            ,call
1623
 
                          (list ,@(funct-formals funct))))))
1624
 
        (rst (produce-counter-example2 (cdr contexts)
1625
 
                                       (cdr names)
1626
 
                                       name0
1627
 
                                       ctx ens wrld state)))
1628
 
       (value (cons `(defun ,(car names) ,(funct-formals funct) ,body)
1629
 
                    rst))))))  
1630
 
 
1631
 
(defun-raw accg-find-ccmf (accg i j)
1632
 
  (loop for edge in (accg-node-fwd-edges (aref accg i))
1633
 
        when (= j (accg-edge-head edge))
1634
 
          return (accg-edge-ccmf edge)))
1635
 
 
1636
 
(defun-raw produce-counter-example (path accg context-array ctx ens wrld state)
1637
 
  (let* ((ccmfs (loop for p on path
1638
 
                      when (and (consp p) (consp (cdr p)))
1639
 
                        collect (accg-find-ccmf accg (car p) (cadr p)))))
1640
 
    (pprogn
1641
 
     (fms "Producing counter-example, including simplifying rulers in order to ~
1642
 
           maximize the reabability of the counter-example."
1643
 
          nil
1644
 
          *standard-co*
1645
 
          state nil)
1646
 
     (mv-let
1647
 
      (contexts functs names)
1648
 
      (produce-counter-example1 ccmfs context-array nil wrld)
1649
 
      (er-let* ((defuns (produce-counter-example2 contexts names (car names)
1650
 
                                                  ctx ens wrld state)))
1651
 
               (value (list* ccmfs functs defuns)))))))
1652
 
 
1653
 
(defun-raw print-counter-example (accg ce contexts ctx ens wrld state)
1654
 
  (er-let*
1655
 
   ((triple (produce-counter-example (cdr ce)
1656
 
                                     accg
1657
 
                                     contexts
1658
 
                                     ctx ens wrld state))
1659
 
    (ccmfs (value (car triple)))
1660
 
    (functs (value (cadr triple)))
1661
 
    (defuns (value (cddr triple))))
1662
 
   (pprogn
1663
 
    (fms "The following function definitions correspond to an actual loop in ~
1664
 
          your function definitions for which the CCG analysis was unable to ~
1665
 
          prove termination in all cases: ~%~%~Y01~%"
1666
 
         (list (cons #\0 (untranslate (if (endp (cdr defuns))
1667
 
                                          (car defuns)
1668
 
                                        (cons 'mutual-recursion defuns))
1669
 
                                      nil wrld))
1670
 
               (cons #\1 (term-evisc-tuple nil state)))
1671
 
         *standard-co*
1672
 
         state nil)
1673
 
    ;; (print-ccms defuns functs 0 wrld state)
1674
 
    (print-ccmfs defuns ccmfs functs 0 wrld state)
1675
 
    (let* ((loop-graph (car ce))
1676
 
           (ne? (ccmf-graph-no-edges? loop-graph))
1677
 
           (ccms (funct-ccms (car functs))))
1678
 
      (fms "As it stands, we do not have enough information to show that this ~
1679
 
            loop terminates. ~#0~[When we put it all together, we find that ~
1680
 
            when we loop from ~x1 to itself, we know ~#2~[nothing about how ~
1681
 
            the values of the CCMs change. ~/the following about how values ~
1682
 
            change from one iteration to the loop to the next (measures are ~
1683
 
            presented without substitution):~%~%~Y34~]~/~]~|~%Note that under ~
1684
 
            this abstraction, the loop is idempotent (i.e. going through the ~
1685
 
            loop again will result in the same information about ~
1686
 
            non-increasing and decreasing values as we have just stated), and ~
1687
 
            that there is no CCM that decreases to itself across the loop. ~
1688
 
            There are therefore three possibilities: ~|~%(1) We did not guess ~
1689
 
            the CCMs needed for proving termination. If this is the case, you ~
1690
 
            could provide them for us using a :CONSIDER-CCMS or ~
1691
 
            :CONSIDER-ONLY-CCMS hint (see :DOC CCG-XARGS). If you are truly ~
1692
 
            desperate, you can resort to proving termination using ACL2's ~
1693
 
            measure-based termination method (do this globally by using ~
1694
 
            SET-TERMINATION-METHOD or just once by using the ~
1695
 
            :TERMINATION-METHOD xarg; see :DOC CCG-XARGS).~|~%(2) We guessed ~
1696
 
            the proper CCMs, but were unable to prove some necessary ~
1697
 
            theorem(s) about how these values change from step to step in the ~
1698
 
            loop. In this case, we suggest that you look at the ~
1699
 
            counter-example we generated and use it to determine what ~
1700
 
            additional lemmas are needed for CCG analysis to successfully ~
1701
 
            prove termination.~|~%(3) The loop really is non-terminating for ~
1702
 
            some inputs. In this case, you should alter the definition of the ~
1703
 
            function so that it will terminate on all inputs.~%~%"
1704
 
           (list (cons #\0 (if (consp (cdr defuns)) 0 1))
1705
 
                 (cons #\1 (cadar defuns))
1706
 
                 (cons #\2 (if ne? 0 1))
1707
 
                 (cons #\3 (untranslate
1708
 
                            (ccmf-graph-term
1709
 
                             (1- (array-dimension loop-graph 0))
1710
 
                             loop-graph
1711
 
                             ccms
1712
 
                             ccms
1713
 
                             nil)
1714
 
                            nil
1715
 
                            wrld))
1716
 
                 (cons #\4 (term-evisc-tuple nil state)))
1717
 
           *standard-co*
1718
 
           state nil)))))
1719
 
 
1720
 
(defun-raw print-ccmf-changes (col changes state)
1721
 
  (if (endp changes)
1722
 
      state
1723
 
    (let ((change (car changes)))
1724
 
      (mv-let
1725
 
       (col state)
1726
 
       (fmt1 "When execution moves ~@0, the following ~
1727
 
             always holds:~|~%~x1.~|~%"
1728
 
             `((#\0 . ,(if (consp (car change))
1729
 
                           `("from context ~x0 to context ~x1"
1730
 
                             (#\0 . ,(caar change))
1731
 
                             (#\1 . ,(cdar change)))
1732
 
                         `("across context ~x0"
1733
 
                           (#\0 . ,(car change)))))
1734
 
               (#\1 . ,(cdr change)))
1735
 
             col
1736
 
             *standard-co*
1737
 
             state
1738
 
             nil)
1739
 
       (print-ccmf-changes col (cdr changes) state)))))
1740
 
 
1741
 
(defun-raw p< (p1 p2)
1742
 
  (or (< (car p1) (car p2))
1743
 
      (and (= (car p1) (car p2))
1744
 
           (< (cdr p1) (cdr p2)))))
1745
 
 
1746
 
(defun-raw construct-accg-changes-printout (changes)
1747
 
  (if (endp changes)
1748
 
      nil
1749
 
    (cons `("the edge from context ~x0 to context ~x1"
1750
 
            (#\0 . ,(caar changes))
1751
 
            (#\1 . ,(cdar changes)))
1752
 
          (construct-accg-changes-printout (cdr changes)))))
1753
 
 
1754
 
(defun-raw print-accg-changes (changes state)
1755
 
  (if (endp changes)
1756
 
      (fms "~|" nil *standard-co* state nil)
1757
 
    (pprogn
1758
 
     (fms "~x0 -> ~x1"
1759
 
          `((#\0 . ,(caar changes))
1760
 
            (#\1 . ,(cdar changes)))
1761
 
          *standard-co*
1762
 
          state
1763
 
          nil)
1764
 
     (print-accg-changes (cdr changes) state))))
1765
 
 
1766
 
(defun-raw print-changes (col changes state)
1767
 
  (if (and (endp (car changes))
1768
 
           (endp (cdr changes)))
1769
 
      (mv-let
1770
 
       (col state)
1771
 
       (fmt1 "We discovered nothing new about the CCG.~|"
1772
 
             nil
1773
 
             col
1774
 
             *standard-co*
1775
 
             state
1776
 
             nil)
1777
 
       (declare (ignore col))
1778
 
       state)
1779
 
    (mv-let
1780
 
     (col state)
1781
 
     (fmt1 "We discovered the following about the CCG.~|~%"
1782
 
           nil
1783
 
           col
1784
 
           *standard-co*
1785
 
           state
1786
 
           nil)
1787
 
     (mv-let
1788
 
      (col state)
1789
 
      (if (endp (car changes))
1790
 
          (mv col state)
1791
 
        (mv-let
1792
 
         (col state)
1793
 
         (fmt1 "We can safely omit the following edges from the CCG:~|"
1794
 
               nil
1795
 
               col
1796
 
               *standard-co*
1797
 
               state
1798
 
               nil)
1799
 
         (declare (ignore col))
1800
 
         (mv 0 (print-accg-changes (car changes) state))))
1801
 
     (print-ccmf-changes col
1802
 
                         (sort (copy-list (cdr changes))
1803
 
                               (if (consp (caadr changes))
1804
 
                                   #'p<
1805
 
                                 #'<)
1806
 
                               :key #'car)
1807
 
                         state)))))
1808
 
 
1809
 
 
1810
 
(defun-raw print-context-array1 (i names context-array state)
1811
 
  (if (>= i (array-dimension context-array 0))
1812
 
      state
1813
 
    (pprogn
1814
 
     (let ((context (aref context-array i)))
1815
 
       (fms "CALLING CONTEXT ~x0~#1~[~/ in the body of ~x2~]:~|rulers: ~
1816
 
             ~x3~|call: ~x4~|"
1817
 
            `((#\0 . ,i)
1818
 
              (#\1 . ,names)
1819
 
              (#\2 . ,(context-fn context))
1820
 
              (#\3 . ,(context-ruler context))
1821
 
              (#\4 . ,(context-call context)))
1822
 
            *standard-co*
1823
 
            state
1824
 
            nil))
1825
 
     (print-context-array1 (1+ i) names context-array state))))
1826
 
 
1827
 
(defun-raw print-context-array (names context-array state)
1828
 
  (pprogn
1829
 
   (fms "The calling contexts for ~#0~[this definition~/these definitions~] ~
1830
 
         are:~|"
1831
 
        `((#\0 . ,names))
1832
 
        *standard-co*
1833
 
        state
1834
 
        nil)
1835
 
  (print-context-array1 0 names context-array state)))
1836
 
 
1837
 
(defun-raw print-accg-edges3 (edges accg state)
1838
 
  (if (endp edges)
1839
 
      state
1840
 
    (pprogn
1841
 
     (let ((pair (accg-edge-context-pair (car edges) accg)))
1842
 
       (fms "~x0 -> ~x1"
1843
 
            `((#\0 . ,(car pair))
1844
 
              (#\1 . ,(cdr pair)))
1845
 
            *standard-co*
1846
 
            state
1847
 
            nil))
1848
 
     (print-accg-edges3 (cdr edges) accg state))))
1849
 
 
1850
 
(defun-raw print-accg-edges2 (i n accg state)
1851
 
  (if (>= i n)
1852
 
      state
1853
 
    (pprogn
1854
 
     (print-accg-edges3 (accg-node-fwd-edges (aref accg i)) accg state)
1855
 
     (print-accg-edges2 (1+ i) n accg state))))
1856
 
 
1857
 
(defun-raw print-accg-edges1 (accgs state)
1858
 
  (if (endp accgs)
1859
 
      (fms "~|" nil *standard-co* state nil)
1860
 
    (pprogn
1861
 
     (print-accg-edges2 0
1862
 
                        (array-dimension (car accgs) 0)
1863
 
                        (car accgs)
1864
 
                        state)
1865
 
     (print-accg-edges1 (cdr accgs) state))))
1866
 
 
1867
 
(defun-raw print-accg-edges (col accgs state)
1868
 
  (if (endp accgs)
1869
 
      state
1870
 
    (mv-let
1871
 
     (col state)
1872
 
     (fmt1 "The Calling Context Graph has the following edges:~|"
1873
 
          nil col *standard-co* state nil)
1874
 
     (declare (ignore col))
1875
 
     (print-accg-edges1 accgs state))))
1876
 
 
1877
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1878
 
;;; the following code is for building a CCG
1879
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1880
 
 
1881
 
;;; limit-induction-hint-fn limits the amount of time spent on a proof
1882
 
;;; attempt by limiting the amount of induction and subgoals that may
1883
 
;;; be considered before the prover gives up. This is done with
1884
 
;;; computed hintus.
1885
 
(defun limit-induction-hint-fn (i)
1886
 
  ;; this computed hint has two pieces. the first limits induction,
1887
 
  ;; the second limits subgoals in order to avoid infinite loops.
1888
 
  `(or (and (length-exceedsp (car id) ,i) ;;if we are i inductions deep
1889
 
            (endp (cdadr id))             ;;and we are not in a subgoal of an induction
1890
 
            (eq (cddr id) 0)              ;;and we haven't done anything with the current subgoal yet,
1891
 
            '(:computed-hint-replacement t :do-not-induct :otf-flg-override));; do not induct any further.
1892
 
       (and (> (cddr id) 20) ;; if we have been working on the same subgoal for 20 steps with no induction or case splitting,
1893
 
            '(:computed-hint-replacement t
1894
 
                                         :do-not '(eliminate-destructors
1895
 
                                                   eliminate-irrelevance
1896
 
                                                   generalize fertilize) ;; turn off all proof methods
1897
 
                                         ;; Pete: put a quote in front of (eliminate ...) above since that generated an error 
1898
 
                                         :in-theory (theory 'minimal-theory))))) ;; and use minimal theory
1899
 
 
1900
 
(defun translated-limit-induction-hint (i)
1901
 
  `((eval-and-translate-hint-expression
1902
 
     "CCG Query" nil
1903
 
     (cons
1904
 
      'nil
1905
 
      (cons
1906
 
       ((lambda
1907
 
          (i id)
1908
 
          (if
1909
 
              (if
1910
 
                  (length-exceedsp (car id) i)
1911
 
                  (if
1912
 
                      (endp (cdr (car (cdr id))))
1913
 
                      (if (eq (cdr (cdr id)) '0)
1914
 
                          '(:computed-hint-replacement t
1915
 
                                                       :do-not-induct :otf-flg-override)
1916
 
                        'nil)
1917
 
                    'nil)
1918
 
                'nil)
1919
 
              (if
1920
 
                  (length-exceedsp (car id) i)
1921
 
                  (if
1922
 
                      (endp (cdr (car (cdr id))))
1923
 
                      (if (eq (cdr (cdr id)) '0)
1924
 
                          '(:computed-hint-replacement t
1925
 
                                                       :do-not-induct :otf-flg-override)
1926
 
                        'nil)
1927
 
                    'nil)
1928
 
                'nil)
1929
 
            (if (< '20 (cdr (cdr id)))
1930
 
                '(:computed-hint-replacement
1931
 
                  t
1932
 
                  :do-not '(eliminate-destructors eliminate-irrelevance
1933
 
                                                  generalize fertilize)
1934
 
                  :in-theory (theory 'minimal-theory))
1935
 
              'nil)))
1936
 
        ',i
1937
 
        id)
1938
 
       (cons state 'nil))))))
1939
 
 
1940
 
;;;ccg-simplify-contexts;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1941
 
 
1942
 
(defun-raw ccg-negate (exp)
1943
 
  ;; returns expression corresponding to the negation of expression exp.
1944
 
  (if (and (consp exp)
1945
 
           (eq (first exp) 'not))
1946
 
      (second exp)
1947
 
    `(not ,exp)))
1948
 
 
1949
 
(defun-raw ccg-addlist (lst)
1950
 
  ;; creates a macro-expanded expression corresponding to the sum of a
1951
 
  ;; list of expressions.
1952
 
  (cond ((endp lst) 0)
1953
 
        ((endp (cdr lst)) (car lst))
1954
 
        (t `(binary-+ ,(car lst) ,(ccg-addlist (cdr lst))))))
1955
 
 
1956
 
 
1957
 
(defun-raw ccg-count-contexts (tms)
1958
 
  ;; given a list of lists of items, returns the total number of items.
1959
 
  (let ((i 0))
1960
 
    (dolist (tm tms i)
1961
 
      (setf i (+ i (len tm))))))
1962
 
 
1963
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1964
 
;;; helper functions                                           ;;;
1965
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1966
 
 
1967
 
;;; The following code implements memoization. Currently this works as
1968
 
;;; follows. At the beginning of termination analysis, we create a
1969
 
;;; memoization struct with the default values for each list. At each
1970
 
;;; prover query that is not built-in-clauses only, we check the prove
1971
 
;;; list to see if any previously proved query subsumes our current
1972
 
;;; goal. If so, we know our goal is true. Otherwise, we check our
1973
 
;;; current goal against those previously unproven using 1 induction
1974
 
;;; and, if our current restrictions indicate that we should only use
1975
 
;;; 0 inductions, those previously unproven using 0 inductions. Here
1976
 
;;; we check for equality (modulo alpha renaming) rather than
1977
 
;;; subsumption, due to the fact that ACL2 is not a decision
1978
 
;;; procedure, but relies on heuristics to guide proofs. Hence, ACL2
1979
 
;;; might fail to prove a given theorem but succeed in proving a more
1980
 
;;; general version.  Therefore, unless we find the same query (modulo
1981
 
;;; alpha renaming) in our unproved lists, we try the proof anyway.
1982
 
;;;
1983
 
;;; When a ACL2 is done with a query, we add it to proved, unproved0,
1984
 
;;; or unproved1 depending on whether the proof attempt was successful
1985
 
;;; (and if it was not successful, how many inductions were tried).
1986
 
;;;
1987
 
;;; Possible improvements:
1988
 
;;;
1989
 
;;; * instead of proving queries on the fly, perhaps we could collect
1990
 
;;;   all the queries and sort them from most to least general. That
1991
 
;;;   way, if we prove a query, we get for free all the queries that
1992
 
;;;   it generalizes.
1993
 
;;;
1994
 
;;; * can we do some preprocessing on the queries before we compare
1995
 
;;;   them for subsumption? The current subsumption checks are simple
1996
 
;;;   syntactic comparisons.
1997
 
;;;
1998
 
;;; * we can use random testing to discover queries that are provably
1999
 
;;;   false. We can then have another list, false-queries that we can
2000
 
;;;   check against. When doing so, we can safely check subsumption
2001
 
;;;   rather than equality, making it much more powerful than the
2002
 
;;;   current unproved checks.
2003
 
 
2004
 
(defun-raw subsumed-by-proved-clause (cl proved)
2005
 
  (and (consp proved)
2006
 
       (or (eq t (subsumes *init-subsumes-count* (car proved) cl nil))
2007
 
           (subsumed-by-proved-clause cl (cdr proved)))))
2008
 
 
2009
 
(defun-raw eliminate-subsumed-tail (cl cl-set acc)
2010
 
  (if (endp cl-set)
2011
 
      acc
2012
 
    (eliminate-subsumed-tail cl (cdr cl-set)
2013
 
                             (if (subsumes *init-subsumes-count*
2014
 
                                           cl (car cl-set) nil)
2015
 
                                 acc
2016
 
                               (cons (car cl-set) acc)))))
2017
 
 
2018
 
(defun-raw add-proved-clause (cl proved)
2019
 
  (cons cl (eliminate-subsumed-tail cl proved nil)))
2020
 
 
2021
 
(defun-raw equals-unproved-clause1 (cl unproved)
2022
 
  ;; note, it is logically sufficient to check that cl subsumes some
2023
 
  ;; unproved clause to say that if the unproved clause is unproveable
2024
 
  ;; in the current theory, that cl will also be unproveable. However,
2025
 
  ;; we are talking about clauses that ACL2 was unable to prove under
2026
 
  ;; a set of restrictions. Given ACL2's heuristics and proving
2027
 
  ;; algorithm, it is possible that adding hypotheses might lead ACL2
2028
 
  ;; astray. Therefore, we want to attempt the proof unless we were
2029
 
  ;; unsuccessful proving the exact same query.
2030
 
  (and (consp unproved)
2031
 
       (or (let ((cl-unproved (car unproved)))
2032
 
             (and (eq t (subsumes *init-subsumes-count* cl cl-unproved nil)) 
2033
 
                  (eq t (subsumes *init-subsumes-count* cl-unproved cl nil))))
2034
 
           (equals-unproved-clause1 cl (cdr unproved)))))
2035
 
 
2036
 
(defun-raw equals-unproved-clause (cl unproved i)
2037
 
  ;; checks if we already failed to prove cl using an induction depth of i or
2038
 
  ;; higher. 
2039
 
  (and (< i (array-dimension unproved 0))
2040
 
       (or (equals-unproved-clause1 cl (aref unproved i))
2041
 
           (equals-unproved-clause cl unproved (1+ i)))))
2042
 
 
2043
 
;;; time-limit check
2044
 
(defmacro-raw time-er (ctx)
2045
 
  `(er soft ,ctx "CCG analysis has exceeded the specified time ~
2046
 
        limit. If you did not expect a time-limit, check the global ~
2047
 
         time-limit setting (see :DOC set-ccg-time-limit and the ~
2048
 
         discussion of the :time-limit flag in :DOC CCG) to find out ~
2049
 
         more. At this point you have several options:~|~% ~
2050
 
         * Set the :don't-guess-ccms flag to t. Sometimes CCG analysis ~
2051
 
           guesses too many CCMs which leads to excessive prover ~
2052
 
           queries. This will eliminate *all* CCMs other than the ~
2053
 
           acl2-count of each formal.~|~%~
2054
 
         * Do you see a variable that you don't think is relevant to the ~
2055
 
           termination proof? In that case, us the :ignore-formals flag ~
2056
 
           to tell the CCG analysis to throw out CCMs that contain that ~
2057
 
           formal. This may also cut down on CCMs and therefore prover ~
2058
 
           queries.~|~%~
2059
 
         * Finally, if you are willing to wait some more, you ~
2060
 
           could try increasing the time limit, or eliminating it by ~
2061
 
           setting it to nil."))
2062
 
 
2063
 
 
2064
 
(defun-raw time-left (stop-time ctx state)
2065
 
  (let ((now (get-internal-run-time)))
2066
 
    (if (< now stop-time)
2067
 
        (value (/ (- stop-time now)
2068
 
                  (coerce internal-time-units-per-second 'float)))
2069
 
      (time-er ctx))))
2070
 
 
2071
 
(defun-raw time-check (stop-time ctx state)
2072
 
  (if (and (posp stop-time)
2073
 
           (<= stop-time (get-internal-run-time)))
2074
 
      (time-er ctx)
2075
 
    (value nil)))
2076
 
 
2077
 
(defmacro-raw maybe-prover-before-stop-time (stop-time ctx state body)
2078
 
  `(let ((stop-time ,stop-time))
2079
 
     (if (null stop-time)
2080
 
         ,body
2081
 
       (er-let* ((time-limit (time-left stop-time ,ctx ,state)))
2082
 
                (with-prover-time-limit time-limit
2083
 
                                        ,body)))))
2084
 
 
2085
 
(defun prove-no-er (term pspv hints ens wrld ctx state)
2086
 
  ;; calls prover, catching any error that occurred. Returns the error
2087
 
  ;; triple whose value is the cons of the negation of the error value
2088
 
  ;; returned by prove (i.e. whether prove successfully proved the
2089
 
  ;; query or not) and either nil (if unsuccessful) or the resulting
2090
 
  ;; ttree (if successful).
2091
 
  (mv-let (er ttree state)
2092
 
          (prove term pspv hints ens wrld ctx state)
2093
 
          (if er
2094
 
              (value (cons nil nil))
2095
 
            (value (cons t ttree)))))
2096
 
 
2097
 
;; query is the work-horse of our algorithm. It calls the prover
2098
 
;; with the appropriate restrictions to ensure that it does not
2099
 
;; attempt to prove termination forever. This function returns an
2100
 
;; error triple whose value is the ttree generated by the proof. If
2101
 
;; the proof fails, the triple indicates an error.
2102
 
 
2103
 
(defun-raw query (hyps concl pt qspv state)
2104
 
  (let* ((stop-time (access query-spec-var qspv :stop-time))
2105
 
         (mem (access query-spec-var qspv :mem))
2106
 
         (otf-flg (access query-spec-var qspv :otf-flg))
2107
 
         (ens (access query-spec-var qspv :ens))
2108
 
         (ctx (access query-spec-var qspv :ctx))
2109
 
         (wrld (access query-spec-var qspv :wrld))
2110
 
         (clause (add-literal concl (dumb-negate-lit-lst hyps) t))
2111
 
         (bic-onlyp (equal pt :built-in-clauses))
2112
 
         (ind-limit (if bic-onlyp -1 (cadr pt)))
2113
 
         (displayed-goal (prettyify-clause-set (list clause)
2114
 
                                               (let*-abstractionp state)
2115
 
                                               wrld)))
2116
 
    (pprogn (ccg-io? query nil state
2117
 
                     (bic-onlyp ind-limit clause wrld)
2118
 
                     (fms "We now make the following query, using ~
2119
 
                           proof-technique ~x0 (see :DOC ~
2120
 
                           CCG-hierarchy)~#1~[~/ and with the otf-flg set to ~
2121
 
                           ~x2~]:~|~%GOAL~%~Y34."
2122
 
                          `((#\0 . ,pt)
2123
 
                            (#\1 . ,(if bic-onlyp 0 1))
2124
 
                            (#\2 . ,otf-flg)
2125
 
                            (#\3 . ,displayed-goal)
2126
 
                            (#\4 . ,(term-evisc-tuple nil state)))
2127
 
                          (proofs-co state)
2128
 
                          state
2129
 
                          nil))
2130
 
            (er-let*
2131
 
             ((pair
2132
 
               (cond (bic-onlyp
2133
 
                      ;; if the proof-technique tells us to only use built-in-clauses, we call built-in-clause-p
2134
 
                      (mv-let (built-in-clausep ttree)
2135
 
                              (built-in-clausep 'query clause ens (match-free-override wrld) wrld state)
2136
 
                              (value (if built-in-clausep
2137
 
                                         (cons t ttree)
2138
 
                                       (cons nil nil)))))
2139
 
                     ;; have we already proved a more general query?
2140
 
                     ((subsumed-by-proved-clause clause (memoization-proved mem))
2141
 
                      (pprogn
2142
 
                       (ccg-io? query nil state
2143
 
                                ()
2144
 
                                (fms "But we see that this query is already ~
2145
 
                                      subsumed by another query that was ~
2146
 
                                      previously proven.~%~%"
2147
 
                                     nil
2148
 
                                     (proofs-co state)
2149
 
                                     state
2150
 
                                     nil))
2151
 
                       (value (cons t nil))))
2152
 
                     ;; have we already failed to prove this query using the same proof techniques?
2153
 
                     ((equals-unproved-clause clause 
2154
 
                                              (memoization-unproved mem)
2155
 
                                              ind-limit)
2156
 
                      (pprogn
2157
 
                       (ccg-io? query nil state
2158
 
                                ()
2159
 
                                (fms "But we see that we already tried and ~
2160
 
                                      failed to prove an equivalent query ~
2161
 
                                      using the same restrictions on the ~
2162
 
                                      theorem prover.~%~%"
2163
 
                                     nil
2164
 
                                     (proofs-co state)
2165
 
                                     state
2166
 
                                     nil))
2167
 
                       (value (cons nil nil))))
2168
 
                     (t
2169
 
                      ;; otherwise, we we need to call prove.
2170
 
                      (er-let*
2171
 
                       ((pair
2172
 
                         (let ((hints (translated-limit-induction-hint ind-limit)))
2173
 
                           (maybe-prover-before-stop-time
2174
 
                            stop-time ctx state
2175
 
                            (prove-no-er (termify-clause-set (list clause))
2176
 
                                         (make-pspv ens wrld
2177
 
                                                    :displayed-goal displayed-goal
2178
 
                                                    :otf-flg otf-flg)
2179
 
                                         hints ens wrld ctx state)))))
2180
 
                       (progn
2181
 
                         ;; update the memoization
2182
 
                         (if (car pair)
2183
 
                             (setf (memoization-proved mem)
2184
 
                                   (add-proved-clause clause
2185
 
                                                      (memoization-proved mem)))
2186
 
                           (setf (aref (memoization-unproved mem)
2187
 
                                       ind-limit)
2188
 
                                 (cons clause
2189
 
                                       (aref (memoization-unproved mem)
2190
 
                                             ind-limit))))
2191
 
                         (value pair)))))))
2192
 
             (pprogn
2193
 
              (ccg-io? query nil state
2194
 
                       ()
2195
 
                       (fms "ACL2 has ~#0~[SUCCEEDED in proving this ~
2196
 
                             query~/FAILED to prove this query~].~|"
2197
 
                            (list (cons #\0 (if (car pair) 0 1)))
2198
 
                            (proofs-co state)
2199
 
                            state
2200
 
                            nil))
2201
 
              (er-progn
2202
 
               (time-check stop-time ctx state)
2203
 
               (if (car pair)
2204
 
                   (accumulate-ttree-and-step-limit-into-state 
2205
 
                    (cdr pair) 
2206
 
                    :skip;(initial-step-limit wrld state)
2207
 
                    state)
2208
 
                 (pprogn
2209
 
                  (erase-gag-state state)
2210
 
                  (value nil)))
2211
 
               (value (car pair))))))))
2212
 
 
2213
 
;; the following two functions, ccg-generic-dfs-visit and
2214
 
;; ccg-generic-dfs perform a depth-first search of a "generic"
2215
 
;; directed graph. That is, a graph that is represented as an array of
2216
 
;; nodes with some way to get a list of adjacent nodes
2217
 
;; (node-fwd-edges) and some way, given an edge to get the index of
2218
 
;; the node that it points to (edge-head). The algorithm itself is
2219
 
;; taken directly out of the CLRS algorithms book.
2220
 
 
2221
 
(defun-raw ccg-generic-dfs-visit (u graph f color time node-fwd-edges edge-head)
2222
 
  (setf (aref color u) 'grey)
2223
 
  (dolist (vn (funcall node-fwd-edges (aref graph u)))
2224
 
    (let ((v (funcall edge-head vn)))
2225
 
      (when (eq (aref color v) 'white)
2226
 
        (setf time (ccg-generic-dfs-visit v graph f color time node-fwd-edges edge-head)))))
2227
 
  (setf (aref color u) 'black)
2228
 
  (setf (aref f time) u)
2229
 
  (incf time))
2230
 
 
2231
 
(defun-raw ccg-generic-dfs (graph node-fwd-edges edge-head)
2232
 
  ;; this is the main generic DFS function. See the comment before the
2233
 
  ;; previous function for a description of the arguments. This
2234
 
  ;; function returns an array of indices indicating the order that
2235
 
  ;; the nodes of the graph were visited. That is, the ith element of
2236
 
  ;; the return value is the index of the ith node visited.
2237
 
  (let* ((size (array-total-size graph))
2238
 
         (f (make-array size :element-type 'fixnum))
2239
 
         (time 0)
2240
 
         (color (make-array size
2241
 
                            :element-type '(member white grey black)
2242
 
                            :initial-element 'white)))
2243
 
    (dotimes (i size f)
2244
 
      (when (eq (aref color i) 'white)
2245
 
        (setf time (ccg-generic-dfs-visit i graph f color time node-fwd-edges edge-head))))))
2246
 
 
2247
 
;;; The next two functions, like the previous two, operate on a
2248
 
;;; "generic" graph that is represented as an array of
2249
 
;;; nodes. Together, they implement an SCC analysis. The algorithm
2250
 
;;; used here is straight from the CLRS algorithm book.
2251
 
 
2252
 
(defun-raw ccg-generic-scc-aux (u graph scc scc-array scc-num color node-bwd-edges edge-tail)
2253
 
  ;; this is the helper function for ccg-generic-scc. u is the index
2254
 
  ;; of the current node. graph is the array of nodes in the
2255
 
  ;; graph. scc is the list of nodes in the scc that we are building.
2256
 
  (let ((scc scc))
2257
 
    (setf (aref color u) 'grey)
2258
 
    (dolist (vn (funcall node-bwd-edges (aref graph u)))
2259
 
      (let ((v (funcall edge-tail vn)))
2260
 
        (when (eq (aref color v) 'white)
2261
 
          (setf scc
2262
 
                (ccg-generic-scc-aux v graph scc scc-array scc-num color
2263
 
                                     node-bwd-edges edge-tail)))))
2264
 
    (setf (aref color u) 'black)
2265
 
    (setf (aref scc-array u) scc-num)
2266
 
    (cons u scc)))
2267
 
 
2268
 
(defun-raw ccg-generic-scc (graph node-fwd-edges node-bwd-edges edge-tail edge-head)
2269
 
  ;; this is the main scc algorithm. graph is the array of nodes
2270
 
  ;; representing the graph to be analyzed. node-fwd-edges is a
2271
 
  ;; function that takes a node from the graph and returns the list of
2272
 
  ;; the edges for which the given node is the tail. node-bwd-edges
2273
 
  ;; takes a node from the graph and returns the list of edges for
2274
 
  ;; which the given node is the head. edge-tail takes an edge and
2275
 
  ;; returns the index in graph that corresponds to the tail of the
2276
 
  ;; edge. edge-head takes an edge nad returns the index in graph that
2277
 
  ;; corresponds to the head of the edge. the function returns a list
2278
 
  ;; of lists of the nodes such that each list lists all the nodes in
2279
 
  ;; one scc, as well as an array indicating which scc each node
2280
 
  ;; belongs to.
2281
 
  (let ((scc-num -1))
2282
 
    (loop
2283
 
     with f = (ccg-generic-dfs graph node-fwd-edges edge-head)
2284
 
     with size = (array-dimension graph 0)
2285
 
     with color = (make-array size
2286
 
                              :element-type '(member black grey white)
2287
 
                              :initial-element 'white)
2288
 
     with scc-array = (make-array size
2289
 
                                  :element-type 'fixnum
2290
 
                                  :initial-element 0)
2291
 
     for i from (1- size) downto 0
2292
 
     for u = (aref f i)
2293
 
     when (eq (aref color u) 'white)
2294
 
     collect (ccg-generic-scc-aux u graph nil scc-array (incf scc-num) color
2295
 
                                  node-bwd-edges edge-tail)
2296
 
     into sccs
2297
 
     finally (return (values sccs scc-array)))))
2298
 
 
2299
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2300
 
;;; building an accg          ;;;
2301
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2302
 
 
2303
 
(defun-raw accg-can-omit-edge? (node1 node2 hlevel qspv state)
2304
 
  ;; given two ACCG nodes, node1 and node2, such that the function called by
2305
 
  ;; the call of node1 is equal to the fn of node2, as well as a
2306
 
  ;; ccg-restrict struct, and proof-related stuff (ens, wrld, ctx,
2307
 
  ;; state), this function attempts to prove that it is impossible to
2308
 
  ;; end up at node2 directly after visiting node1. We do this by
2309
 
  ;; attempting to prove that the ruler of node1 implies the negation of
2310
 
  ;; the ruler of node2 after the formals of the fn of node2 have been
2311
 
  ;; replaced by the actuals of the call of node1. if this can be
2312
 
  ;; proven, we return nil, otherwise, we return t.  
2313
 
  (if (hlevel-ccmfs-per-nodep hlevel)
2314
 
      (value nil)
2315
 
    (query (append (accg-node-ruler node1)
2316
 
                   (subcor-var-lst (accg-node-formals node2)
2317
 
                                   (fargs (accg-node-call node1))
2318
 
                                   (accg-node-ruler node2)))
2319
 
           nil
2320
 
           (hlevel-proof-technique hlevel) qspv state)))
2321
 
 
2322
 
(defun-raw accg-fill-in-edges (accg name-node-alist)
2323
 
  (loop for i from 0 below (array-dimension accg 0)
2324
 
        for node1 = (aref accg i)
2325
 
        for successors = (cdr (assoc (accg-node-callfn node1)
2326
 
                                     name-node-alist))
2327
 
        do (setf (accg-node-fwd-edges node1)
2328
 
                 (loop for node2 in successors
2329
 
                       for j = (accg-node-num node2)
2330
 
                       for edge = (make-accg-edge :tail i :head j)
2331
 
                       do (setf (accg-node-bwd-edges node2)
2332
 
                                (cons edge (accg-node-bwd-edges node2)))
2333
 
                       collect edge))))
2334
 
                       
2335
 
(defun-raw context-to-accg-node-lst (contexts total)
2336
 
  (if (endp contexts)
2337
 
      (mv nil total)
2338
 
    (mv-let
2339
 
     (nodes ntotal)
2340
 
     (context-to-accg-node-lst (cdr contexts) total)
2341
 
     (let ((node (make-accg-node :context (car contexts))))
2342
 
       (mv (cons node nodes) (cons node ntotal))))))
2343
 
 
2344
 
(defun-raw ccg-build-accg0 (names contexts)
2345
 
  (if (endp names)
2346
 
      (mv nil nil)
2347
 
    (let ((name (car names))
2348
 
          (context-list (car contexts)))
2349
 
      (mv-let
2350
 
       (alist total)
2351
 
       (ccg-build-accg0 (cdr names) (cdr contexts))
2352
 
       (mv-let
2353
 
        (nodes ntotal)
2354
 
        (context-to-accg-node-lst context-list total)
2355
 
        (mv (acons name nodes alist)
2356
 
            ntotal))))))
2357
 
 
2358
 
(defun-raw ccg-build-accg (names contexts)
2359
 
  ;; given the names of the functions being analyzed, the contexts
2360
 
  ;; organized as a list of lists of contexts such that the ith list
2361
 
  ;; in contexts corresponds to the list of contexts in the ith
2362
 
  ;; function in names, the ccg-restrict struct restrict, and the
2363
 
  ;; other proof-related stuff, we build an ACCG.
2364
 
  (mv-let
2365
 
   (name-node-alist accg-node-lst)
2366
 
   (ccg-build-accg0 names contexts)
2367
 
   (let ((accg (coerce accg-node-lst 'vector)))
2368
 
     (progn
2369
 
       (loop for i from 0 below (array-dimension accg 0)
2370
 
           do (setf (accg-node-num (aref accg i)) i))
2371
 
       (accg-fill-in-edges accg name-node-alist)
2372
 
       accg))))
2373
 
 
2374
 
(defun-raw simplify-contexts1 (context-lst ens wrld ctx state)
2375
 
  (if (endp context-lst)
2376
 
      state
2377
 
    (mv-let
2378
 
     (erp value state)
2379
 
     (ccg-simplify-hyps-no-split (context-ruler (car context-lst))
2380
 
                                 ctx ens wrld state)
2381
 
     (progn
2382
 
       (unless erp (setf (context-ruler (car context-lst)) value))
2383
 
       (simplify-contexts1 (cdr context-lst) ens wrld ctx state)))))
2384
 
 
2385
 
(defun-raw simplify-contexts (contexts ens wrld ctx state)
2386
 
  (if (endp contexts)
2387
 
      state
2388
 
    (pprogn
2389
 
     (simplify-contexts1 (car contexts) ens wrld ctx state)
2390
 
     (simplify-contexts (cdr contexts) ens wrld ctx state))))                           
2391
 
 
2392
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2393
 
;;; annotating accgs (ccmfs)                                   ;;;
2394
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2395
 
 
2396
 
 
2397
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2398
 
;;; choosing ccms (see CAV paper)        ;;;
2399
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2400
 
 
2401
 
(defun de-propagate (term)
2402
 
  (if (eq (fn-symb term) 'ccg-propagate)
2403
 
      (fargn term 2)
2404
 
    term))
2405
 
 
2406
 
(defun-raw ccg-formal-sizes (formals)
2407
 
  ;; given a list of formals, this function returns a list of
2408
 
  ;; expressions to calculate the acl2-count of each formal.
2409
 
  (loop for x in formals
2410
 
        collect `(acl2-count ,x)))
2411
 
 
2412
 
(defun-raw ccg-add-zp-ccm (r formals ccms)
2413
 
  ;; if an expression, r -- which will generally correspond to one of
2414
 
  ;; the expressions in a ruler -- is (not (zp e)) for some expression
2415
 
  ;; e that is not in the list of formals, then we add e to our list
2416
 
  ;; of ccms.
2417
 
  (cond ((atom r) ccms)
2418
 
        ((and (eq (ffn-symb r) 'not)
2419
 
              (consp (fargn r 1))
2420
 
              (eq (ffn-symb (fargn r 1)) 'zp)
2421
 
              ;; NOTE: We could remove th
2422
 
              (not (member-eq (fargn (fargn r 1) 1) formals)))
2423
 
         (cons (fargn (fargn r 1) 1) ccms))
2424
 
        (t ccms)))
2425
 
 
2426
 
 
2427
 
(defun-raw ccg-add-<-ccm (r formals ccms)
2428
 
  ;; if an expression, r -- which will generally correspond to one of
2429
 
  ;; the expressions in a ruler -- is one of the following forms, we
2430
 
  ;; add the corresponding expression to the ccms:
2431
 
  ;;
2432
 
  ;; * (< 0 e2) --> (acl2-count e2)
2433
 
  ;; * (< e1 e2) --> (acl2-count (- e2 e1))
2434
 
  ;; * (not (< e1 0)) --> (1+ (acl2-count e1))
2435
 
  ;; * (not (< e1 e2)) --> (1+ (acl2-count (- e1 e2)))
2436
 
  (declare (ignore formals))
2437
 
  (cond ((atom r) ccms)
2438
 
        ((or (eq (car r) '<)
2439
 
             (and (eq (car r) 'not)
2440
 
                  (consp (second r))
2441
 
                  (eq (car (second r)) '<)))
2442
 
         (let* ((r0 (if (eq (car r) '<) r (second r)))
2443
 
                (p (term-order (second r0) (third r0)))
2444
 
                (arg1 (if p (second r0) (third r0)))
2445
 
                (arg2 (if p (third r0) (second r0))))
2446
 
           (cond ((and (quotep arg1) (quotep arg2))
2447
 
                  ccms)
2448
 
                 ((not (or (quotep arg1) (quotep arg2)))
2449
 
                  (cons `(acl2-count (binary-+ '1
2450
 
                                               (binary-+ ,arg2
2451
 
                                                         (unary-- ,arg1))))
2452
 
                        ccms))
2453
 
                 ((and (quotep arg1) (acl2-numberp (unquote arg1)))
2454
 
                  (if (and (or (eql (unquote arg1) 0)
2455
 
                               (eql (unquote arg1) 1))
2456
 
                           (variablep arg2))
2457
 
                      ccms
2458
 
                    (cons `(acl2-count (binary-+ (quote ,(- 1 (unquote arg1))) ,arg2))
2459
 
                          ccms)))
2460
 
                 ((and (quotep arg2) (acl2-numberp (unquote arg2)))
2461
 
                  (if (and (or (eql (unquote arg2) 0) 
2462
 
                               (eql (unquote arg2) 1))
2463
 
                           (variablep arg1))
2464
 
                      ccms
2465
 
                    (cons `(acl2-count (binary-+ (quote ,(- 1 (unquote arg2))) ,arg1))
2466
 
                          ccms)))
2467
 
                 (t
2468
 
                  ccms))))
2469
 
        (t ccms)))
2470
 
 
2471
 
(defun-raw ccg-add-dec-ccm (arg ccms)
2472
 
  ;; a rule for adding a ccm that is not very helpful in general, but
2473
 
  ;; illustrates how it might be useful, in the future, to allow users
2474
 
  ;; to define their own rules for adding ccms. given an expression
2475
 
  ;; that should correspond to an argument of the call of a context,
2476
 
  ;; adds arg to the list of ccms if it is of the form (dec e).
2477
 
  (if (and (consp arg)
2478
 
           (eq (car arg) 'dec))
2479
 
      (cons arg ccms)
2480
 
    ccms))
2481
 
 
2482
 
(defun-raw accg-guess-ccms-for-node (node)
2483
 
  ;; given a node, guesses ccms beyond the basic acl2-count of the
2484
 
  ;; formals.
2485
 
  (let ((ccms nil)
2486
 
        (rulers (accg-node-ruler node))
2487
 
        (formals (accg-node-formals node)))
2488
 
    (dolist (r rulers ccms)
2489
 
      (setf ccms (ccg-add-<-ccm r formals ccms))
2490
 
      (setf ccms (ccg-add-zp-ccm r formals ccms)))
2491
 
;;     (dolist (a (fargs (accg-node-call node)) ccms)
2492
 
;;       (setf ccms (ccg-add-dec-ccm a ccms)))
2493
 
    ))
2494
 
 
2495
 
(defun-raw ccg-remove-duplicate-ccms-in-functs (functs)
2496
 
  ;; a function for removing any duplicate ccms in an array of lists of ccms.
2497
 
  (dolist (funct functs functs)
2498
 
    (setf (funct-ccms funct)
2499
 
          (remove-duplicates (funct-ccms funct)
2500
 
                             :test #'equal
2501
 
                             :key #'de-propagate))))
2502
 
 
2503
 
(defun-raw ccg-remove-duplicate-ccms (ccms)
2504
 
  ;; a function for removing any duplicate ccms in an array of lists of ccms.
2505
 
  (let ((n (array-dimension ccms 0)))
2506
 
    (dotimes (i n ccms)
2507
 
      (setf (aref ccms i) (remove-duplicates (aref ccms i)
2508
 
                                             :test #'equal
2509
 
                                             :key #'de-propagate)))))
2510
 
 
2511
 
;; when we guess ccms beyond the basic acl2-count of the formals of a
2512
 
;; function, we need to propagate the ccms throughout the accg. for
2513
 
;; example, suppose we have two functions, f and g, such that f
2514
 
;; contains the call (g x y) when (not (zp (- y x))) and g always
2515
 
;; calls (f (1+ x) y). then f will get assigned the ccm (- y x), but g
2516
 
;; will only have (acl2-count x) and (acl2-count y). in this
2517
 
;; situation, there will be no way to tell that (- y x) decreases each
2518
 
;; time through the loop. we need some sort of "place-holder" to keep
2519
 
;; track of the value of (- y x) when we are in the function g. the
2520
 
;; next few functions do this by walking backwards through the graph,
2521
 
;; visiting each node just once, and adding the ccm resulting in
2522
 
;; substituting actuals for formals in the non-trivial ccms from the
2523
 
;; next node. in our example, g would get the ccm (- y (1+ x)).
2524
 
 
2525
 
 
2526
 
 
2527
 
(defun-raw accg-propagate-ccm (ccm accg n consider-onlyp)
2528
 
  ;; propagates a single ccm through the accg. here ccm is the ccm
2529
 
  ;; expression, accg is the accg, n is the index of the node to which
2530
 
  ;; the ccm is assigned, and consider-onlyp is an array of booleans
2531
 
  ;; that tells us whether the user supplied the ccms using a
2532
 
  ;; :CONSIDER-ONLY-CCMS hint or not for each node. this is done in a
2533
 
  ;; breadth-first order to ensure the shortest propagation paths and
2534
 
  ;; therefore simpler ccms in general.
2535
 
  (let* ((size (array-dimension accg 0))
2536
 
         ;; queued tells us if node i has been added to the queue for
2537
 
         ;; each 0 <= i < size.
2538
 
         (queued (make-array size :element-type 'boolean :initial-element nil))
2539
 
         ;; successor tells us the index of the successor of node i
2540
 
         ;; from which we propagate the ccm.
2541
 
         (successor (make-array size :element-type 'integer :initial-element 0))
2542
 
         ;; ccms is an array assigning each node index, i, to the ccm
2543
 
         ;; for that node.
2544
 
         (ccms (make-array size :initial-element nil))
2545
 
         ;; queue is the queue into which we put the indices of the
2546
 
         ;; nodes we are to visit in the order in which we are to
2547
 
         ;; visit them. the initial element is -1 so we know when we
2548
 
         ;; reach the end of the queue.
2549
 
         (queue (make-array size :element-type 'integer :initial-element -1))
2550
 
         (c (accg-node-context-num (aref accg n)))
2551
 
         ;; i is the index of the queue where the next enqueue
2552
 
         ;; operation should put the next node index.
2553
 
         (i 0)
2554
 
         ;; queue-preds is a small function that puts all the unqueued
2555
 
         ;; predecessors of node m into the queue.
2556
 
         (queue-preds (lambda (m)
2557
 
                        (loop for edge in (accg-node-bwd-edges (aref accg m))
2558
 
                              for pred = (accg-edge-tail edge)
2559
 
                              unless (or (aref queued pred)
2560
 
                                         (aref consider-onlyp pred))
2561
 
                                do (setf (aref queued pred) t)
2562
 
                                and do (setf (aref queue (incf i)) pred)
2563
 
                                and do (setf (aref successor pred) m)))))
2564
 
    (let ((node (aref accg n)))
2565
 
      (setf (accg-node-ccms node)
2566
 
            (cons ccm (accg-node-ccms node)))
2567
 
      (setf (aref ccms n) ccm))
2568
 
    (setf (aref queued n) t)
2569
 
    (funcall queue-preds n)
2570
 
    (loop for j from 1 below size
2571
 
          for k = (aref queue j)
2572
 
          when (= k -1) ;; if we get a -1, we have reached the end of the queue.
2573
 
            return nil
2574
 
          do (let* ((succ (aref successor k))
2575
 
                    (node (aref accg k))
2576
 
                    ;; we substitute actuals for formals in the ccm of the
2577
 
                    ;; successor to get the new ccm.
2578
 
                    (nccm (subcor-var (accg-node-callformals node)
2579
 
                                      (fargs (accg-node-call node))
2580
 
                                      (aref ccms succ))))
2581
 
               (setf (aref ccms k) nccm))
2582
 
          do (funcall queue-preds k))
2583
 
    (loop for j from 1 below size
2584
 
          for k = (aref queue j)
2585
 
          when (= k -1)
2586
 
            return nil
2587
 
          do (let ((node (aref accg k)))
2588
 
               (setf (accg-node-ccms node)
2589
 
                     (cons `(ccg-propagate ,c ,(aref ccms k))
2590
 
                           (accg-node-ccms node)))))))
2591
 
 
2592
 
(defun-raw accg-propagate-ccms (ccms accg consider-onlyp)
2593
 
  ;; (print ccms) accg-propagate-ccms propagates all the ccms in ccms
2594
 
  ;; throughout the accg. here, ccms is an array of lists of ccms
2595
 
  ;; corresponding to the ccms assigned to each node in the
2596
 
  ;; accg. consider-onlyp is an array of booleans telling us whether
2597
 
  ;; or not the user supplied the ccms using a :CONSIDER-ONLY-CCMS
2598
 
  ;; xarg for each node. we return nccms which holds the new list of
2599
 
  ;; ccms for each node.
2600
 
  (loop with size = (array-dimension ccms 0)
2601
 
        for i from 0 below size
2602
 
        do (loop for ccm in (aref ccms i)
2603
 
                 do (accg-propagate-ccm ccm accg i consider-onlyp))))
2604
 
 
2605
 
(defun-raw accg-partition-ccms-by-function (ccms nodes)
2606
 
  ;; in order to compute ccmfs by node instead of by edge, ccms need
2607
 
  ;; to be assigned by function, not by accg node. this function takes
2608
 
  ;; the ccms assigned to the nodes of a accg and unions all the ccms
2609
 
  ;; of the contexts of each function. the result is an alist that
2610
 
  ;; maps function names to the ccms for that function.
2611
 
  (loop for i from 0 below (array-dimension ccms 0)
2612
 
        for funct = (accg-node-parent-funct (aref nodes i))
2613
 
        do (setf (funct-ccms funct)
2614
 
                 (append (aref ccms i) (funct-ccms funct)))))
2615
 
 
2616
 
(defun-raw accg-guess-ccms (accg functs ccm-hints-alist)
2617
 
  ;; accg-guess-ccms puts all the ccm-guessing together. it takes an
2618
 
  ;; accg and an alist mapping function names to ccms that is
2619
 
  ;; presumably provided by the user. the ccms are computed and then
2620
 
  ;; the accg is annotated by setting the accg-node-ccms field of each
2621
 
  ;; node in the accg to the appropriate list of ccms.
2622
 
  (let* ((size (array-dimension accg 0))
2623
 
         (ccms (make-array size :element-type 'list :initial-element nil))
2624
 
         (consider-onlyp (make-array size :element-type 'boolean :initial-element nil)))
2625
 
    ;; first we fill in the correct values for consider-onlyp for each
2626
 
    ;; node depending on whether the user provided ccms using
2627
 
    ;; :CONSIDER-ONLY-CCMs for the function containing the node. at
2628
 
    ;; the same time, we set the ccms for any node for which the user
2629
 
    ;; did supply ccms.
2630
 
    (loop for i from 0 below size
2631
 
          for entry = (assoc (accg-node-fn (aref accg i))
2632
 
                             ccm-hints-alist)
2633
 
          do (setf (aref consider-onlyp i) (cadr entry))
2634
 
          unless (eq (cddr entry) *0*) ;; no value supplied is represented as *0*.
2635
 
            do (setf (aref ccms i) (cddr entry)))
2636
 
    ;; guess the non-trivial ccms for each node.
2637
 
    (loop for i from 0 below size
2638
 
          for node = (aref accg i)
2639
 
          unless (or (aref consider-onlyp i)
2640
 
                     ;; don't guess ccms for dead-ends.
2641
 
                     (endp (accg-node-fwd-edges (aref accg i))))
2642
 
            do (setf (aref ccms i)
2643
 
                     (append (accg-guess-ccms-for-node node)
2644
 
                             (aref ccms i))))
2645
 
    ;; next, we propagate the ccms and then partition them by
2646
 
    ;; function. finally, we set the ccm list of each node to be the
2647
 
    ;; non-trivial ccms for the function plus the acl2-count of each
2648
 
    ;; formal of the parent function and the sum of all the formal
2649
 
    ;; acl2-counts (if there is more than one formal).
2650
 
     (accg-propagate-ccms
2651
 
      (ccg-remove-duplicate-ccms ccms)
2652
 
      accg
2653
 
      consider-onlyp)
2654
 
    (ccg-remove-duplicate-ccms-in-functs functs)
2655
 
    (loop for funct in functs
2656
 
          for fn-sccms in ccm-hints-alist
2657
 
          for fsizes = (ccg-formal-sizes (funct-formals funct))
2658
 
;;; I've commented out the next line to avoid a compiler warning.
2659
 
;         for ccms = (funct-ccms funct)
2660
 
          unless (cadr fn-sccms)
2661
 
            do (setf (funct-ccms funct)
2662
 
                     (append fsizes
2663
 
                             (if (length-exceedsp fsizes 1)
2664
 
                                 (cons (ccg-addlist fsizes)
2665
 
                                       (funct-ccms funct))
2666
 
                               (funct-ccms funct))))
2667
 
          finally (ccg-remove-duplicate-ccms-in-functs functs))
2668
 
    ;; finally, we coerce the ccms for each function from lists into vectors
2669
 
    (loop for funct in functs
2670
 
          do (setf (funct-ccms funct)
2671
 
                   (coerce (funct-ccms funct) 'vector)))))
2672
 
 
2673
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2674
 
;;; accg annotation (ccmfs)        ;;;
2675
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2676
 
 
2677
 
(defun-raw ccmf->-value? (ruler e1 e2 pt qspv state)
2678
 
  ;; returns true if we can prove that, under the ruler conditions, e2
2679
 
  ;; will always be o< e1.
2680
 
  (query ruler `(o< ,(de-propagate e2) ,(de-propagate e1))
2681
 
         pt qspv state))
2682
 
 
2683
 
(defun-raw ccmf->=-value? (ruler e1 e2 pt qspv state)
2684
 
  ;; returns true if we can prove that, under the ruler conditions, e1
2685
 
  ;; will never be o< e2.
2686
 
  (query ruler `(not (o< ,(de-propagate e1) ,(de-propagate e2)))
2687
 
         pt qspv state))
2688
 
 
2689
 
(defun-raw ccmf-skip-edge (f1 n1 c1 e1 f2 n2 e2 hlevel)
2690
 
  ;; returns whether, based on the restrictions indicated by the
2691
 
  ;; ccg-restrict struct, restrict, we should skip creating a ccmf
2692
 
  ;; edge for the ccms e1 and e2. this is mostly based on the
2693
 
  ;; ccg-restrict-measure-vars field.
2694
 
 
2695
 
 
2696
 
  ;; (format t "ccmf-skip-edge: ~A ~A~%~%" e1 e2)
2697
 
  (or (null hlevel)
2698
 
      (eq (fn-symb e1) 'ccg-propagated)
2699
 
      (and (eq (fn-symb e2) 'ccg-propagated)
2700
 
           (not (equal (fargn e2 1) c1)))
2701
 
      ;; NOTE: we used to think that built-in-clauses are so fast, we don't
2702
 
      ;; need to skip any. However, we came across some very expensive analyses
2703
 
      ;; (see one-way-unify1 in the foundations book in the paco directory of
2704
 
      ;; the regression suite).
2705
 
      (and ;;(not (ccg-restrict-bic-onlyp restrict))
2706
 
           (let ((v1 (all-vars e1)) ;; v1 is all the variables in e1
2707
 
                 (v2 (all-vars e2))) ;; v2 is all the variables in e2
2708
 
             (and (not (and (eq f1 f2)
2709
 
                            (= n1 n2)))
2710
 
                  (case (hlevel-ccm-comparison-scheme hlevel)
2711
 
                    ;; (:across
2712
 
                    ;;  (not (and (subsetp v1 v2)
2713
 
                    ;;            (subsetp v2 v1))))
2714
 
                    ;; ;; if :equal, we skip if the variable sets are not equal.
2715
 
                    (:equal
2716
 
                     (not (and (subsetp v1 v2)
2717
 
                               (subsetp v2 v1))))
2718
 
                    ;; if :all, we skip if v1 is not a proper subset of v2.
2719
 
                    (:all
2720
 
                     (or (subsetp v2 v1)
2721
 
                         (not (subsetp v1 v2))))
2722
 
                    ;; if :some, we skip if v1 a subset of v2 or v1 and v2 do
2723
 
                    ;; not intersect.
2724
 
                    (:some
2725
 
                     (or (subsetp v1 v2)
2726
 
                         (not (intersectp-eq v1 v2))))
2727
 
                    ;; if :none, we skip if v1 and v2 intersect.
2728
 
                    (:none
2729
 
                     (intersectp-eq v1 v2))))))))
2730
 
 
2731
 
(defun-raw accg-copy-ccmf-graph (graph &key (size nil))
2732
 
  ;; creates a copy of a ccmf graph
2733
 
  (let* ((n (array-dimension graph 0))
2734
 
         (ngraph (make-array (if size (max n size) n)
2735
 
                             :element-type 'ccmf-node
2736
 
                             :initial-element (make-ccmf-node))))
2737
 
    (loop for i from 0 below n
2738
 
          for node = (aref graph i)
2739
 
          do (setf (aref ngraph i)
2740
 
                   (make-ccmf-node :>-edges (copy-list (ccmf-node->-edges node))
2741
 
                                   :>=-edges (copy-list (ccmf-node->=-edges node)))))
2742
 
    ngraph))
2743
 
 
2744
 
(defun-raw accg-add-ccmfs (accg)
2745
 
  (loop for node1 across accg
2746
 
        for in-sizes = (array-dimension (accg-node-ccms node1) 0)
2747
 
        do (loop for edge in (accg-node-fwd-edges node1)
2748
 
                 for head = (accg-edge-head edge)
2749
 
                 for node2 = (aref accg head)
2750
 
                 for graph = (make-array in-sizes)
2751
 
                 do (loop for i from 0 below in-sizes
2752
 
                          do (setf (aref graph i)
2753
 
                                   (make-ccmf-node)))
2754
 
                 do (setf (accg-edge-ccmf edge)
2755
 
                          (make-ccmf :firstsite (accg-edge-tail edge)
2756
 
                                     :lastsite  head
2757
 
                                     :fc-num    (accg-node-context-num node1)
2758
 
                                     :lc-num    (accg-node-context-num node2)
2759
 
                                     :in-sizes  in-sizes
2760
 
                                     :out-sizes (array-dimension (accg-node-ccms
2761
 
                                                                  node2)
2762
 
                                                                 0)
2763
 
                                     :graph graph)))))
2764
 
 
2765
 
;;;;;;;;;;;;;;;;;;;;;;;;
2766
 
;;; accg sccs        ;;;
2767
 
;;;;;;;;;;;;;;;;;;;;;;;;
2768
 
 
2769
 
(defun-raw accg-scc (graph)
2770
 
  (ccg-generic-scc graph
2771
 
                   #'accg-node-fwd-edges #'accg-node-bwd-edges
2772
 
                   #'accg-edge-tail #'accg-edge-head))
2773
 
 
2774
 
(defun-raw accg-edge-context-pair (edge accg)
2775
 
  (cons (car
2776
 
         (accg-node-context-num
2777
 
          (aref accg
2778
 
                (accg-edge-tail
2779
 
                 edge))))
2780
 
        (car
2781
 
         (accg-node-context-num
2782
 
          (aref accg
2783
 
                (accg-edge-head
2784
 
                 edge))))))
2785
 
 
2786
 
(defun-raw accg-delete-non-scc-edges1 (edges accg scc scc-array)
2787
 
  (if (endp edges)
2788
 
      (mv nil nil)
2789
 
    (mv-let
2790
 
     (changes nedges)
2791
 
     (accg-delete-non-scc-edges1 (cdr edges) accg scc scc-array)
2792
 
     (if (= scc (aref scc-array (accg-edge-head (car edges))))
2793
 
         (mv changes (cons (car edges) nedges))
2794
 
       (mv (cons (accg-edge-context-pair (car edges) accg)
2795
 
                 changes)
2796
 
           nedges)))))
2797
 
 
2798
 
(defun-raw accg-delete-non-scc-edges (accg scc-array)
2799
 
  (loop with changes = nil
2800
 
        for i from 0 below (array-dimension accg 0)
2801
 
        for nodei = (aref accg i)
2802
 
        for scci = (aref scc-array i)
2803
 
        do (mv-let
2804
 
            (nchanges nedges)
2805
 
            (accg-delete-non-scc-edges1 (accg-node-fwd-edges nodei) accg scci scc-array)
2806
 
            (progn
2807
 
              (setf (accg-node-fwd-edges nodei) nedges)
2808
 
              (setf changes (append nchanges changes))))
2809
 
        do (setf (accg-node-bwd-edges nodei)
2810
 
                 (delete-if-not #'(lambda (x)
2811
 
                                    (= scci
2812
 
                                       (aref scc-array
2813
 
                                             (accg-edge-tail x))))
2814
 
                  (accg-node-bwd-edges nodei)))
2815
 
        finally (return changes)))
2816
 
 
2817
 
(defun-raw accg-separate-sccs0 (accg sccs scc-array &key (ccmfp nil))
2818
 
  (if (endp (cdr sccs))
2819
 
      (mv nil (list accg))
2820
 
    (let* ((m (array-dimension accg 0)) ;; the number of nodes in the current accg
2821
 
           (n (len sccs))               ;; the number of sccs
2822
 
           (count (make-array n ;; an array keeping track of the size of each scc.
2823
 
                              :element-type 'fixnum
2824
 
                              :initial-element 0))
2825
 
           (mapping (make-array m ;; a mapping from the old index of each node to its new index.
2826
 
                                :element-type 'fixnum
2827
 
                                :initial-element 0))
2828
 
           (changes nil))
2829
 
      ;; next, we calculate the values of count and the mapping.
2830
 
      (loop for i from 0 below m
2831
 
            for j = (aref scc-array i)
2832
 
            do (setf (aref mapping i) (aref count j))
2833
 
            do (incf (aref count j)))
2834
 
      ;; naccgs is an array of the new accgs.
2835
 
      (let ((naccgs (make-array n)))
2836
 
        ;; we set each accg in naccg to be an array of nodes.
2837
 
        (loop for i from 0 below n
2838
 
              do (setf (aref naccgs i)
2839
 
                       (make-array (aref count i))))
2840
 
        ;; we now populate naccgs with nodes, setting the
2841
 
        ;; accg-node-num and resetting the accg-node-bwd-edges
2842
 
        (loop for i from 0 below m
2843
 
              for sccn = (aref scc-array i)
2844
 
              for noden = (aref mapping i)
2845
 
              for node = (aref accg i)
2846
 
              do (setf (aref (aref naccgs sccn) noden)
2847
 
                       node)
2848
 
              do (setf (accg-node-num node) noden)
2849
 
              do (setf (accg-node-bwd-edges node) nil))
2850
 
        ;; now we fix the edges
2851
 
        (loop for i from 0 below n
2852
 
              for naccg = (aref naccgs i)
2853
 
              do (loop for j from 0 below (aref count i)
2854
 
                       for node = (aref naccg j)
2855
 
                       ;; we recalculate the accg-node-fwd-edges of node as follows
2856
 
                       do (setf (accg-node-fwd-edges node)
2857
 
                                (loop for e in (accg-node-fwd-edges node)
2858
 
                                      for head = (accg-edge-head e)
2859
 
                                      for nhead = (aref mapping head)
2860
 
                                      for ccmf = (accg-edge-ccmf e)
2861
 
                                      ;; if the edge traverses two
2862
 
                                      ;; edges in the same scc,
2863
 
                                      if (= (aref scc-array head) i)
2864
 
                                      ;; set the head and tail of the edge
2865
 
                                      do (setf (accg-edge-head e) nhead)
2866
 
                                      and do (setf (accg-edge-tail e) j)
2867
 
                                      ;; add the edge to the
2868
 
                                      ;; appropriate bwd-edges list
2869
 
                                      and do (let ((hnode (aref naccg nhead)))
2870
 
                                               (setf (accg-node-bwd-edges hnode)
2871
 
                                                     (cons e
2872
 
                                                           (accg-node-bwd-edges hnode))))
2873
 
                                      ;; collect e into our new list of fwd-edges
2874
 
                                      and collect e
2875
 
                                      ;; when we need to worry about
2876
 
                                      ;; ccmfs, fix this edge's
2877
 
                                      ;; ccmf.
2878
 
                                      and when ccmfp
2879
 
                                      do (setf (ccmf-firstsite ccmf) j)
2880
 
                                      and do (setf (ccmf-lastsite ccmf)
2881
 
                                                   nhead)
2882
 
                                      else do (setf changes
2883
 
                                                    (cons 
2884
 
                                                     (accg-edge-context-pair e accg)
2885
 
                                                     changes))))))
2886
 
        ;; finally, we collect all the non-trivial sccs into a list and return it.
2887
 
        (mv changes
2888
 
            (loop for i from 0 below n
2889
 
                  for naccg = (aref naccgs i)
2890
 
                  unless (and (= (aref count i) 1)
2891
 
                              (not (accg-node-fwd-edges (aref naccg 0))))
2892
 
                  collect naccg))))))
2893
 
 
2894
 
(defun-raw accg-separate-sccs (accg &key (ccmfp nil))
2895
 
  ;; separates an accg into its sccs. ccmfp indicates whether or not
2896
 
  ;; the accg has already been annotated with ccmfs. this function is
2897
 
  ;; destructive.
2898
 
 
2899
 
  ;; we start by doing the scc analysis:
2900
 
  (multiple-value-bind
2901
 
      (sccs scc-array)
2902
 
      (accg-scc accg)
2903
 
     (accg-separate-sccs0 accg sccs scc-array :ccmfp ccmfp)))
2904
 
 
2905
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2906
 
;;; putting it all together ;;;
2907
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2908
 
 
2909
 
(defun-raw build-and-annotate-accgs (names functs contexts ccm-hints-alist)
2910
 
  ;; build-and-annotate-accgs does exactly what it says. names is the
2911
 
  ;; names of the functions, contexts is a list of lists of contexts
2912
 
  ;; such that the ith list in contexts is the list of contexts in the
2913
 
  ;; ith function in names. restrict is the current ccg-restrict
2914
 
  ;; struct, and ccms-alist is the alist mapping function names to the
2915
 
  ;; ccms provided for the user for that function.
2916
 
  (let ((accg (ccg-build-accg names contexts)))
2917
 
    (multiple-value-bind
2918
 
        (sccs scc-array)
2919
 
        (accg-scc accg)
2920
 
      (progn
2921
 
        (accg-delete-non-scc-edges accg scc-array)
2922
 
        (accg-guess-ccms accg functs ccm-hints-alist)
2923
 
        (accg-add-ccmfs accg)
2924
 
        (mv-let
2925
 
         (changes0 naccgs)
2926
 
         (accg-separate-sccs0 accg sccs scc-array :ccmfp t)
2927
 
         (declare (ignore changes0))
2928
 
         naccgs)))))
2929
 
 
2930
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2931
 
;;; refining accgs          ;;;
2932
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2933
 
 
2934
 
 
2935
 
(defun-raw weaker-proof-techniquesp (h1 h2)
2936
 
  ;; given two levels in the hierarchy, this function tells us whether the
2937
 
  ;; proof-techniques of the first are weaker than the proof-techniques of the
2938
 
  ;; second, i.e. that it might be possible to prove something using the proof
2939
 
  ;; techniques of h2 that would not be proven using the techniques in h1.
2940
 
  
2941
 
  
2942
 
  (or ;; h1 is nil in our first round of refinement, when their is no
2943
 
      ;; previous level to the hierarchy
2944
 
   (null h1)
2945
 
   (not (null h2)) ;; this should never happen
2946
 
   (let ((pt1 (car h1))
2947
 
         (pt2 (car h2)))
2948
 
     ;; the proof techniques of h1 are weaker if it limited to built-in-clauses
2949
 
     ;; while h2 is not:
2950
 
     (if (equal pt1 :built-in-clauses)
2951
 
         (not (equal pt2 :built-in-clauses))
2952
 
       ;; the proof techniques of h1 are weaker if it is of the form
2953
 
       ;; (:induction-depth n1), h2 is of the form (:induction-depth n2) and
2954
 
       ;; (< n1 n2).
2955
 
       (and (consp pt2)
2956
 
            (< (cadr pt1)
2957
 
               (cadr pt2)))))))
2958
 
 
2959
 
(defun-raw accg-ccmf-adj-matrix (ccmf)
2960
 
  ;; given a ccmf, this function builds an adjacency matrix where
2961
 
  ;; element i,j is >, >=, or nil if there is a >-edge, >=-edge, or no
2962
 
  ;; edge from ccm i of the first context to ccm j of the second index
2963
 
  ;; in the ccmf, respectively.
2964
 
  (loop with n1 = (ccmf-in-sizes ccmf)
2965
 
        with n2 = (ccmf-out-sizes ccmf)
2966
 
        with graph = (ccmf-graph ccmf)
2967
 
        with matrix = (make-array `(,n1 ,n2)
2968
 
                                  :initial-element nil
2969
 
                                  :element-type '(member nil '>= '>))
2970
 
        for i from 0 below n1
2971
 
        for node = (aref graph i)
2972
 
        do (loop for j in (ccmf-node->-edges node)
2973
 
                 do (setf (aref matrix i j) '>))
2974
 
        do (loop for j in (ccmf-node->=-edges node)
2975
 
                 do (setf (aref matrix i j) '>=))
2976
 
        finally (return matrix)))
2977
 
           
2978
 
;; currently destructive
2979
 
 
2980
 
(defun-raw accg-refine-ccmf2 (i j matrix node e1 hyps f1 c1 f2 ccms2 cformals args redop
2981
 
                                changes old-hlevel hlevel qspv state)
2982
 
  (let ((wrld (access query-spec-var qspv :wrld)))
2983
 
    (if (< j 0)
2984
 
        (value changes)
2985
 
      (let* ((o2 (aref ccms2 j))
2986
 
             (e2 (subcor-var cformals args o2))
2987
 
             (u1 (untranslate e1 nil wrld))
2988
 
             (u2 (untranslate o2 nil wrld))
2989
 
             (skipp (or (ccmf-skip-edge f1 i c1 e1 f2 j e2 hlevel)
2990
 
                        (not (or redop ;; if circumstances tell us to redo the > proof,
2991
 
                                 (ccmf-skip-edge f1 i c1 e1 f2 j e2 old-hlevel)))))
2992
 
             (label (aref matrix i j))
2993
 
             (pt (hlevel-proof-technique hlevel)))
2994
 
        (er-let*
2995
 
         ((nlabel
2996
 
           (cond (skipp (value label))
2997
 
                 ((eq label '>) (value '>))
2998
 
                 ((equal (de-propagate e1) (de-propagate e2)) (value '>=))
2999
 
                 (t
3000
 
                  (er-let*
3001
 
                   ((result 
3002
 
                     (pprogn
3003
 
                      (increment-timer 'other-time state)
3004
 
                      (ccg-io? build/refine nil state
3005
 
                               (u1 u2)
3006
 
                               (fms "We attempt to prove that, under the given ~
3007
 
                                   conditions, it is the case that the ~
3008
 
                                   context measure ~x0 is always greater than ~
3009
 
                                   ~x1.~|"
3010
 
                                    `((#\0 . ,u1)
3011
 
                                      (#\1 . ,u2))
3012
 
                                    *standard-co*
3013
 
                                    state
3014
 
                                    nil))
3015
 
                      (increment-timer 'print-time state)
3016
 
                      (ccmf->-value? hyps e1 e2 pt qspv state))))
3017
 
                   (cond (result (value '>))
3018
 
                         ((eq label '>=) (value '>=))
3019
 
                         (t
3020
 
                          (er-let*
3021
 
                           ((result 
3022
 
                             (pprogn
3023
 
                              (increment-timer 'other-time state)
3024
 
                              (ccg-io? build/refine nil state
3025
 
                                       (u1 u2)
3026
 
                                       (fms "Since the previous query failed, ~
3027
 
                                           we attempt to prove that, under ~
3028
 
                                           the given conditions,  it is the ~
3029
 
                                           case that the context measure ~x0 ~
3030
 
                                           is never less than ~x1.~|"
3031
 
                                            `((#\0 . ,u1)
3032
 
                                              (#\1 . ,u2))
3033
 
                                            *standard-co*
3034
 
                                            state
3035
 
                                            nil))
3036
 
                              (increment-timer 'print-time state)
3037
 
                              (ccmf->=-value? hyps e1 e2 pt qspv state))))
3038
 
                           (value (if result '>= nil))))))))))
3039
 
         (progn 
3040
 
           ;;(format t "~&e1: ~A e2: ~A label: ~A~%" e1 e2 nlabel)
3041
 
           (case nlabel
3042
 
             (> (setf (ccmf-node->-edges node)
3043
 
                      (cons j (ccmf-node->-edges node))))
3044
 
             (>= (setf (ccmf-node->=-edges node)
3045
 
                       (cons j (ccmf-node->=-edges node)))))
3046
 
           (accg-refine-ccmf2 i (1- j) matrix node e1
3047
 
                              hyps f1 c1 f2 ccms2 cformals args redop
3048
 
                              (if (eq nlabel label)
3049
 
                                  changes
3050
 
                                (cons `(,nlabel ,u1 ,u2) changes))
3051
 
                              old-hlevel hlevel qspv state)))))))
3052
 
 
3053
 
(defun-raw accg-refine-ccmf1 (i matrix ccmf
3054
 
                               hyps f1 ccms1 c1 f2 ccms2 cformals args redop
3055
 
                               changes old-hlevel hlevel
3056
 
                               qspv state)
3057
 
  ;; this function destructively refines a ccmf. note that its
3058
 
  ;; signature looks just like that of accg-construct-ccmf-graph,
3059
 
  ;; except we have the added arguments redop and old-hlevel, which
3060
 
  ;; help us to know when we need to redo proofs we have already done.
3061
 
  
3062
 
  (if (< i 0)
3063
 
      (value (cond ((endp changes) changes)
3064
 
                   ((endp (cdr changes)) (car changes))
3065
 
                   (t (cons 'and changes))))
3066
 
    (er-let*
3067
 
     ((changes0 (accg-refine-ccmf2 i (1- (ccmf-out-sizes ccmf)) matrix (aref (ccmf-graph ccmf) i)
3068
 
                                   (aref ccms1 i) hyps f1 c1 f2 ccms2 cformals args redop
3069
 
                                   changes old-hlevel hlevel qspv state)))
3070
 
     (accg-refine-ccmf1 (1- i) matrix ccmf
3071
 
                        hyps f1 ccms1 c1 f2 ccms2 cformals args redop
3072
 
                        changes0 old-hlevel hlevel qspv state))))
3073
 
 
3074
 
(defun-raw accg-refine-ccmf (ccmf hyps f1 ccms1 c1 f2 ccms2 cformals args redop
3075
 
                               old-hlevel hlevel qspv state)
3076
 
  (let ((matrix (accg-ccmf-adj-matrix ccmf)))
3077
 
    (loop for node across (ccmf-graph ccmf)
3078
 
          do (setf (ccmf-node->-edges node) nil)
3079
 
          do (setf (ccmf-node->=-edges node) nil))
3080
 
    (accg-refine-ccmf1 (1- (ccmf-in-sizes ccmf)) matrix
3081
 
                       ccmf hyps f1 ccms1 c1 f2 ccms2 cformals args redop
3082
 
                       nil old-hlevel hlevel qspv state)))
3083
 
 
3084
 
(defun-raw accg-node-refine-ccmfs-per-edge
3085
 
  (edges node1 accg ccms1 c1 ruler1 cformals args
3086
 
         stronger-proofsp changes old-hlevel hlevel
3087
 
         qspv state)
3088
 
  (if (endp edges)
3089
 
      (value changes)
3090
 
    (let* ((edge (car edges))
3091
 
           (node2 (aref accg (accg-edge-head edge)))
3092
 
           (ccms2 (accg-node-ccms node2))
3093
 
           (ruler2 (subcor-var-lst cformals args (accg-node-ruler node2)))
3094
 
           (wrld (access query-spec-var qspv :wrld)))
3095
 
      (pprogn
3096
 
       (increment-timer 'other-time state)
3097
 
       (ccg-io? build/refine nil state
3098
 
                (node1 ruler1 wrld node2)
3099
 
                (fms "We use theorem prover queries to discen how the context ~
3100
 
                      measures change when execution moves from call ~x0 in ~
3101
 
                      function ~x1 under the ruler ~x2 to call ~x3 in ~
3102
 
                      function ~x4 under the ruler ~x5.~|"
3103
 
                     `((#\0 . ,(accg-node-call node1))
3104
 
                       (#\1 . ,(accg-node-fn node1))
3105
 
                       (#\2 . ,(untranslate-lst ruler1 nil wrld))
3106
 
                       (#\3 . ,(accg-node-call node2))
3107
 
                       (#\4 . ,(accg-node-fn node2))
3108
 
                       (#\5 . ,(untranslate-lst (accg-node-ruler node2) nil wrld)))
3109
 
                     *standard-co*
3110
 
                     state
3111
 
                     nil))
3112
 
       (increment-timer 'print-time state)
3113
 
       (er-let*
3114
 
        ((nchanges (accg-refine-ccmf (accg-edge-ccmf edge)
3115
 
                                     (append ruler1 ruler2)
3116
 
                                     (accg-node-fn node1)
3117
 
                                     ccms1
3118
 
                                     c1
3119
 
                                     (accg-node-fn node2)
3120
 
                                     ccms2
3121
 
                                     cformals args
3122
 
                                     stronger-proofsp
3123
 
                                     old-hlevel hlevel
3124
 
                                     qspv state)))
3125
 
        (accg-node-refine-ccmfs-per-edge
3126
 
         (cdr edges) node1 accg ccms1 c1 ruler1
3127
 
         cformals args 
3128
 
         stronger-proofsp
3129
 
         (if (null nchanges)
3130
 
             changes
3131
 
           (acons (cons (car (accg-node-context-num node1))
3132
 
                        (car (accg-node-context-num node2)))
3133
 
                  nchanges
3134
 
                  changes))
3135
 
         old-hlevel hlevel
3136
 
         qspv state))))))
3137
 
 
3138
 
(defun-raw accg-refine-ccmfs1 (i accg stronger-proofsp changes
3139
 
                                 old-hlevel hlevel qspv state)
3140
 
  ;; refines all the ccmfs in an accg.
3141
 
  (if (< i 0)
3142
 
      (value changes)
3143
 
    (let* ((node1 (aref accg i))
3144
 
           (ccms1 (accg-node-ccms node1))
3145
 
           (c1 (accg-node-context-num node1))
3146
 
           (ruler1 (accg-node-ruler node1))
3147
 
           (cformals (accg-node-callformals node1))
3148
 
           (args (fargs (accg-node-call node1)))
3149
 
           (wrld (access query-spec-var qspv :wrld)))
3150
 
      (er-let*
3151
 
       ((changes0
3152
 
         (if (hlevel-ccmfs-per-nodep hlevel)
3153
 
             ;; if we are creating/refining ccmfs on a per-node basis
3154
 
             ;; (rather than per-edge), we refine one ccmf for the node and
3155
 
             ;; propagate its graph to the ccmf of every edge.
3156
 
             (pprogn
3157
 
              (ccg-io? build/refine nil state
3158
 
                       (c1 ruler1 wrld)
3159
 
                       (fms "We use theorem prover queries to discern how our ~
3160
 
                             context mesaures change when execution moves ~
3161
 
                             across call ~x0 in function ~x1 under the ruler ~
3162
 
                             ~x2.~|"
3163
 
                            `((#\0 . ,(accg-node-call node1))
3164
 
                              (#\1 . ,(accg-node-fn node1))
3165
 
                              (#\2 . ,(untranslate-lst ruler1 nil wrld)))
3166
 
                            *standard-co*
3167
 
                            state
3168
 
                            nil))
3169
 
              (er-let*
3170
 
               ((edge1 (value (car (accg-node-fwd-edges node1))))
3171
 
                (node2 (value (aref accg (accg-edge-head edge1))))
3172
 
                (ccmf (value (accg-edge-ccmf (car (accg-node-fwd-edges node1)))))
3173
 
                (nchanges (accg-refine-ccmf ccmf
3174
 
                                            ruler1
3175
 
                                            (accg-node-fn node1)
3176
 
                                            ccms1
3177
 
                                            c1
3178
 
                                            (accg-node-fn node2)
3179
 
                                            (accg-node-ccms node2)
3180
 
                                            cformals args
3181
 
                                            stronger-proofsp
3182
 
                                            old-hlevel hlevel
3183
 
                                            qspv state))
3184
 
                (ngraph (value (ccmf-graph ccmf))))
3185
 
               (loop for edge in (cdr (accg-node-fwd-edges node1))
3186
 
                     for occmf = (accg-edge-ccmf edge)
3187
 
                     do (setf (ccmf-graph occmf)
3188
 
                              (accg-copy-ccmf-graph ngraph))
3189
 
                     finally (return (value (if (null nchanges)
3190
 
                                                changes
3191
 
                                              (acons (car (accg-node-context-num
3192
 
                                                           node1))
3193
 
                                                     nchanges
3194
 
                                                     changes)))))))
3195
 
           ;; if we are creating/refining ccmfs on a per-edge basis, we
3196
 
           ;; refine the ccmf of each edge seperately.
3197
 
           (accg-node-refine-ccmfs-per-edge (accg-node-fwd-edges node1)
3198
 
                                            node1 accg ccms1 c1 ruler1 cformals args
3199
 
                                            stronger-proofsp changes old-hlevel hlevel
3200
 
                                            qspv state))))
3201
 
       (accg-refine-ccmfs1 (1- i) accg stronger-proofsp changes0 old-hlevel hlevel
3202
 
                           qspv state)))))
3203
 
      
3204
 
(defun-raw accg-refine-ccmfs (accg stronger-proofsp old-hlevel hlevel
3205
 
                                   qspv state)
3206
 
  (accg-refine-ccmfs1 (1- (array-dimension accg 0)) accg stronger-proofsp nil
3207
 
                      old-hlevel hlevel
3208
 
                      qspv state))
3209
 
 
3210
 
(defun-raw accg-refine-ccmfs-lst1 (accgs caccgs uaccgs changes stronger-proofsp
3211
 
                                         old-hlevel hlevel qspv state)
3212
 
  (if (endp accgs)
3213
 
      (value (list* changes caccgs uaccgs))
3214
 
    (er-let*
3215
 
     ((accg (value (car accgs)))
3216
 
      (nchanges (accg-refine-ccmfs accg stronger-proofsp old-hlevel hlevel
3217
 
                                   qspv state)))
3218
 
     (accg-refine-ccmfs-lst1 (cdr accgs)
3219
 
                             (if (consp nchanges)
3220
 
                                 (cons accg caccgs)
3221
 
                               caccgs)
3222
 
                             (if (consp nchanges)
3223
 
                                 uaccgs
3224
 
                               (cons accg uaccgs))
3225
 
                             (append nchanges changes) 
3226
 
                             stronger-proofsp
3227
 
                             old-hlevel hlevel
3228
 
                             qspv state))))
3229
 
 
3230
 
(defun-raw accg-refine-ccmfs-lst (accgs stronger-proofsp old-hlevel hlevel
3231
 
                                        qspv state)
3232
 
  ;; refines the ccmfs of a list of accgs.
3233
 
  ;;
3234
 
  ;;
3235
 
  ;;
3236
 
  ;; OUTPUT: an error triple whose value is (list* d c u) where d ... c is the
3237
 
  ;; list of accgs that were changed during refinement, and u is the list of
3238
 
  ;; accgs that were unchanged during refinement.
3239
 
 
3240
 
  (accg-refine-ccmfs-lst1 accgs nil nil nil stronger-proofsp old-hlevel hlevel
3241
 
                          qspv state))
3242
 
  
3243
 
(defun-raw prune-accg-node (node1 edges accg changes hlevel qspv state)
3244
 
  (if (endp edges)
3245
 
      (value changes)
3246
 
    (let* ((edge (car edges))
3247
 
           (node2 (aref accg (accg-edge-head edge))))
3248
 
      (er-let*
3249
 
       ((result 
3250
 
         (pprogn
3251
 
          (increment-timer 'other-time state)
3252
 
          (ccg-io? build/refine nil state
3253
 
                   (node1 node2)
3254
 
                   (fms "We attempt to prove that it is not possible for ~
3255
 
                         execution to move from context ~x0 to context ~x1.~|"
3256
 
                        `((#\0 . ,(car (accg-node-context-num node1)))
3257
 
                          (#\1 . ,(car (accg-node-context-num node2))))
3258
 
                        *standard-co*
3259
 
                        state
3260
 
                        nil))
3261
 
          (increment-timer 'print-time state)
3262
 
          (accg-can-omit-edge? node1 node2 hlevel qspv state))))
3263
 
       (progn
3264
 
         (unless result
3265
 
           (setf (accg-node-fwd-edges node1)
3266
 
                 (cons edge (accg-node-fwd-edges node1)))
3267
 
           (setf (accg-node-bwd-edges node2)
3268
 
                 (cons edge (accg-node-bwd-edges node2))))
3269
 
         (prune-accg-node node1 (cdr edges) accg 
3270
 
                          (if result
3271
 
                              (acons (car (accg-node-context-num node1))
3272
 
                                     (car (accg-node-context-num node2))
3273
 
                                     changes)
3274
 
                            changes)
3275
 
                          hlevel qspv state))))))
3276
 
 
3277
 
(defun-raw prune-accg1 (i accg changes hlevel qspv state)
3278
 
  (if (< i 0)
3279
 
      (value changes)
3280
 
    (let* ((node (aref accg i))
3281
 
           (edges (accg-node-fwd-edges node)))
3282
 
      (setf (accg-node-fwd-edges node) nil)
3283
 
      (er-let* ((nchanges (prune-accg-node node edges accg changes
3284
 
                                           hlevel qspv state)))
3285
 
               (prune-accg1 (1- i) accg nchanges hlevel qspv state)))))
3286
 
 
3287
 
(defun-raw prune-accg (accg hlevel qspv state)
3288
 
  ;; reset all the bwd-edges
3289
 
  (loop for node across accg
3290
 
        do (setf (accg-node-bwd-edges node) nil))
3291
 
  (pprogn
3292
 
   (ccg-io? build/refine nil state
3293
 
            ()
3294
 
            (fms "We attempt to prune the CCG by using theorem prover queries ~
3295
 
                  to determine if the rulers of adjacent calling contexts are ~
3296
 
                  incompatible.~|"
3297
 
                 nil
3298
 
                 *standard-co*
3299
 
                 state
3300
 
                 nil))
3301
 
   ;; prune!
3302
 
   (prune-accg1 (1- (array-dimension accg 0)) accg nil hlevel qspv state)))
3303
 
               
3304
 
(defun-raw accg-refine-accg (accg stronger-proofsp old-hlevel hlevel
3305
 
                                  qspv state)
3306
 
  ;; this function refines an accg based on whether we have stronger
3307
 
  ;; proof techniques available (stronger-proofsp), or some other
3308
 
  ;; weaker set of restrictions (comparing restrict to
3309
 
  ;; old-restrict). The result is a list of new accgs that have been
3310
 
  ;; separated into sccs.
3311
 
  (er-let*
3312
 
   ((accg-changes0
3313
 
     (if (and stronger-proofsp
3314
 
              (not (hlevel-ccmfs-per-nodep hlevel)))
3315
 
         ;; if we are using stronger proof techniques
3316
 
         ;; and we are not doing ccmfs on a per-node
3317
 
         ;; basis (in which case we avoid pruning to
3318
 
         ;; allow for simpler justifications in the end)
3319
 
         (prune-accg accg hlevel qspv state)
3320
 
       (value nil))))
3321
 
   (if (consp accg-changes0)
3322
 
       (mv-let
3323
 
        (accg-changes1 naccgs)
3324
 
        (accg-separate-sccs accg :ccmfp t)
3325
 
        (er-let*
3326
 
         ((triple (accg-refine-ccmfs-lst naccgs stronger-proofsp
3327
 
                                         old-hlevel hlevel
3328
 
                                         qspv state)))
3329
 
         (value (cons (cons (append accg-changes0 accg-changes1)
3330
 
                            (car triple))
3331
 
                      naccgs))))
3332
 
     (er-let*
3333
 
      ((changes0 (accg-refine-ccmfs accg stronger-proofsp
3334
 
                                    old-hlevel hlevel
3335
 
                                    qspv state)))
3336
 
      (value (cons (cons nil changes0) (list accg)))))))
3337
 
 
3338
 
(defun-raw accg-refine-accgs1 (accgs ces changes caccgs uaccgs uces
3339
 
                                     stronger-proofsp old-hlevel new-hlevel
3340
 
                                     qspv state)
3341
 
  (if (endp accgs)
3342
 
      (value (list* changes caccgs uaccgs uces))
3343
 
    (er-let*
3344
 
     ((pair (accg-refine-accg (car accgs) stronger-proofsp
3345
 
                              old-hlevel new-hlevel qspv state)))
3346
 
     (if (or (consp (caar pair)) (consp (cdar pair)))
3347
 
         (accg-refine-accgs1 (cdr accgs)
3348
 
                             (cdr ces)
3349
 
                             (cons (append (caar pair) (car changes))
3350
 
                                   (append (cdar pair) (cdr changes)))
3351
 
                             (append (cdr pair) caccgs)
3352
 
                             uaccgs
3353
 
                             uces
3354
 
                             stronger-proofsp old-hlevel new-hlevel
3355
 
                             qspv state)
3356
 
       (accg-refine-accgs1 (cdr accgs)
3357
 
                           (cdr ces)
3358
 
                           changes
3359
 
                           caccgs
3360
 
                           ;; if there are no changes, (cdr pair) is a
3361
 
                           ;; singleton list.
3362
 
                           (append (cdr pair) uaccgs)
3363
 
                           (cons (car ces) uces)
3364
 
                           stronger-proofsp old-hlevel new-hlevel
3365
 
                           qspv state)))))
3366
 
 
3367
 
(defun-raw accg-refine-accgs (accgs ces old-hlevel new-hlevel qspv state)
3368
 
  ;; refines a list of accgs by calling accg-refine-accg repeatedly. Returns an
3369
 
  ;; error triple whose value is (cons c u) where c is a list of the accgs that were
3370
 
  ;; changed by refinement, and u is a list of the accgs that were not changed
3371
 
  ;; by refinement.
3372
 
  (pprogn
3373
 
   (ccg-io? basics nil state
3374
 
            (new-hlevel accgs)
3375
 
            (fms "We now move to the ~x0 level of the hierarchy ~
3376
 
                  (see :DOC CCG-hierarchy) in order to refine the remaining ~
3377
 
                  SCC~#1~[~/s~] of our anotated CCG.~|"
3378
 
                 `((#\0 . ,new-hlevel)
3379
 
                   (#\1 . ,accgs))
3380
 
                 *standard-co*
3381
 
                 state
3382
 
                 nil))
3383
 
   (er-let*
3384
 
    ((tuple (accg-refine-accgs1 accgs ces nil nil nil nil
3385
 
                                 (weaker-proof-techniquesp old-hlevel
3386
 
                                                           new-hlevel)
3387
 
                                 old-hlevel new-hlevel
3388
 
                                 qspv state))
3389
 
     (changes (value (car tuple)))
3390
 
     (caccgs (value (cadr tuple)))
3391
 
     (uaccgs (value (caddr tuple)))
3392
 
     (uces (value (cdddr tuple))))
3393
 
    (pprogn
3394
 
     (ccg-io? basics nil state
3395
 
              (changes state)
3396
 
              (mv-let
3397
 
               (col state)
3398
 
               (fmt "We have completed CCG refinement. "
3399
 
                    nil
3400
 
                    *standard-co*
3401
 
                    state
3402
 
                    nil)
3403
 
               (print-changes col changes state)))
3404
 
     (value (list* caccgs uaccgs uces))))))
3405
 
 
3406
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3407
 
;;; the following code is used to clean up CCGs (see the SCP
3408
 
;;; paper). the code culminates in the cln function.
3409
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3410
 
 
3411
 
(defun-raw srg-scc (graph)
3412
 
  ;; srg-scc is the instantiation of ccg-generic-scc for srgs.
3413
 
  (ccg-generic-scc graph
3414
 
                   #'srg-node-fwd-edges #'srg-node-bwd-edges
3415
 
                   #'srg-edge-tail #'srg-edge-head))
3416
 
 
3417
 
 
3418
 
(defun-raw srg-scc-has->-edgep (scc scc-array srg)
3419
 
  ;; srg-scc-has->-edgep tells us whether an scc of an srg contains an
3420
 
  ;; edge labeled with a >. here scc is a list of indices of nodes in
3421
 
  ;; the same scc, and scc-array maps srg indices to a unique scc
3422
 
  ;; identifier (as in the second value returned by srg-scc).
3423
 
  (let ((scc-num (aref scc-array (car scc)))) 
3424
 
    (dolist (p scc nil)
3425
 
      (let ((x (aref srg p)))
3426
 
        (when (dolist (e (srg-node-fwd-edges x) nil)
3427
 
                (when (and (eq (srg-edge-label e) '>)
3428
 
                           (= scc-num (aref scc-array
3429
 
                                            (srg-edge-head e))))
3430
 
                  (return t)))
3431
 
          (return t))))))
3432
 
 
3433
 
(defun-raw ccmf-remove-ccms (ccmf first-del-array last-del-array)
3434
 
  ;; virtually and destructively removes ccms from a ccmf by removing
3435
 
  ;; all edges involving those ccms. This is sufficient for our
3436
 
  ;; purposes and easier than rebuilding the ccmf without the
3437
 
  ;; ccms. here, ccmf is a ccmf struct, first-del-array and
3438
 
  ;; last-del-array are arrays of booleans for which a value of t in
3439
 
  ;; slot i indicates that the ith ccm should be removed from the ith
3440
 
  ;; source or sink ccm, respectively. returns the ccmf or nil if all
3441
 
  ;; the edges have been removed from the ccmf, in which case,
3442
 
  ;; termination cannot be proven.
3443
 
  (loop with graph = (ccmf-graph ccmf)
3444
 
        for i from 0 below (ccmf-in-sizes ccmf) ;; we loop through the graph array.
3445
 
        for node = (aref graph i)
3446
 
        for f = (lambda (x) (aref last-del-array x))
3447
 
        if (aref first-del-array i) ;; if we are supposed to delete this source node,
3448
 
          do (setf (aref graph i) (make-ccmf-node)) ;; we set the node to a blank node
3449
 
        else ;; otherwise, we remove all the > and >= edges that lead
3450
 
             ;; to a deleted sink node:
3451
 
          do (setf (aref graph i)
3452
 
                   (make-ccmf-node :>-edges (delete-if f (ccmf-node->-edges node))
3453
 
                                   :>=-edges (delete-if f (ccmf-node->=-edges node))))))
3454
 
 
3455
 
(defun-raw ccmf-remove-ccms-list (ccmfs deletep-array)
3456
 
  ;; given a list of ccmfs and an array of arrays of booleans
3457
 
  ;; indicating which ccms to delete for each context, calls
3458
 
  ;; ccmf-remove-ccms on each ccmf in ccmfs with the appropriate
3459
 
  ;; deletion arrays. this function is destructively updates each
3460
 
  ;; ccmf.
3461
 
  (dolist (ccmf ccmfs nil)
3462
 
    (ccmf-remove-ccms ccmf
3463
 
                      (aref deletep-array
3464
 
                            (ccmf-firstsite ccmf))
3465
 
                      (aref deletep-array
3466
 
                            (ccmf-lastsite ccmf)))))
3467
 
 
3468
 
(defun-raw srg-restrict (srg ccms)
3469
 
  ;; restricts the given srg to only the ccms indexed by the natural
3470
 
  ;; numbers in the list ccms. this function is *not* destructive.
3471
 
  (let* ((n (length ccms))
3472
 
         (rsrg (make-array n)) ;; the restricted srg.
3473
 
         (a (make-array (array-dimension srg 0) ;; maps the srg nodes
3474
 
                        :element-type 'fixnum   ;; to their new index
3475
 
                        :initial-element -1)))  ;; if they are in rsrg.
3476
 
    ;; create a new node for each slot in rsrg with the node and ccm
3477
 
    ;; of the appropriate node in the original srg. we also update the
3478
 
    ;; map as we go mapping old node indices to new ones.
3479
 
    (loop
3480
 
     for p in ccms
3481
 
     for i from 0
3482
 
     for node = (aref srg p)
3483
 
     do (setf (aref a p) i)
3484
 
     do (setf (aref rsrg i)
3485
 
              (make-srg-node :node (srg-node-node node)
3486
 
                             :ccm  (srg-node-ccm  node))))
3487
 
    (loop
3488
 
     for p in ccms
3489
 
     for i from 0
3490
 
     for node = (aref srg p)
3491
 
     for nnode = (aref rsrg i)
3492
 
     do (loop for e in (srg-node-fwd-edges node)
3493
 
              unless (= (aref a (srg-edge-head e)) -1)
3494
 
              do (let* ((head (aref a (srg-edge-head e)))
3495
 
                        (hnode (aref rsrg head))
3496
 
                        (ne (make-srg-edge :head head
3497
 
                                           :tail i
3498
 
                                           :ccmf (srg-edge-ccmf e)
3499
 
                                           :label (srg-edge-label e))))
3500
 
                   (setf (srg-node-fwd-edges nnode)
3501
 
                         (cons ne (srg-node-fwd-edges nnode)))
3502
 
                   (setf (srg-node-bwd-edges hnode)
3503
 
                         (cons ne (srg-node-bwd-edges hnode))))))
3504
 
    rsrg))
3505
 
 
3506
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3507
 
;;; the following code implements the SCP analysis.
3508
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3509
 
 
3510
 
(defun-raw srg-scc-for-node-aux (srg nn visited node-fwd-edges edge-head)
3511
 
  ;; this is the helper function for srg-scc-for-node
3512
 
  (setf (aref visited nn) t)
3513
 
  (loop for edge in (funcall node-fwd-edges (aref srg nn))
3514
 
        for head = (funcall edge-head edge)
3515
 
        unless (aref visited head)
3516
 
        do (srg-scc-for-node-aux srg head visited node-fwd-edges edge-head)))
3517
 
 
3518
 
(defun-raw srg-scc-for-node (srg nn)
3519
 
  ;; given an srg and the index of a node in that srg (nn), returns an
3520
 
  ;; array of booleans of the same size as srg which indicates for
3521
 
  ;; each i whether the node of the srg at index i is in the same srg
3522
 
  ;; as the node at index nn. it does so by traversing the srg from
3523
 
  ;; node nn forwards and backwards and taking the intersection of the
3524
 
  ;; nodes reached.
3525
 
  (let* ((n (array-dimension srg 0))
3526
 
         (in-scc-array (make-array n :element-type '(member t nil :ignore) :initial-element nil)))
3527
 
    (let* ((n (array-dimension in-scc-array 0)))
3528
 
      ;; traverse the graph forwards, using in-scc-array to keep track
3529
 
      ;; of the visited nodes.
3530
 
      (srg-scc-for-node-aux srg nn in-scc-array #'srg-node-fwd-edges #'srg-edge-head)
3531
 
      ;; for our backwards traversal, we only want to visit nodes that
3532
 
      ;; we already visited on our forward traversal. therefore, we
3533
 
      ;; set the index of visited nodes to nil and the index of
3534
 
      ;; unvisited nodes to the non-nil value :ignore.
3535
 
      (loop for i from 0 below n
3536
 
            if (aref in-scc-array i)
3537
 
              do (setf (aref in-scc-array i) nil)
3538
 
            else
3539
 
              do (setf (aref in-scc-array i) :ignore))
3540
 
      ;; now traverse the graph backwards.
3541
 
      (srg-scc-for-node-aux srg nn in-scc-array #'srg-node-bwd-edges #'srg-edge-tail)
3542
 
      ;; finally, reset any :ignore indices to nil, since they are not in the scc.
3543
 
      (loop for i from 0 below n
3544
 
            when (eq (aref in-scc-array i) :ignore)
3545
 
              do (setf (aref in-scc-array i) nil))
3546
 
      in-scc-array)))
3547
 
 
3548
 
(defun-raw srg-add-scc-for-node (srg nn in-scc-array)
3549
 
  ;; takes the per-index disjunction of the boolean array in-scc-array
3550
 
  ;; and the result of calling srg-scc-for-node on srg and nn. In
3551
 
  ;; other words, given an array indicating which nodes are in a
3552
 
  ;; collection of sccs, this function adds the scc containing node nn
3553
 
  ;; to the array.
3554
 
  (if (aref in-scc-array nn)
3555
 
      in-scc-array
3556
 
    (let ((new-in-scc-array (srg-scc-for-node srg nn)))
3557
 
      (loop for i from 0 below (length in-scc-array)
3558
 
            when (and (not (aref in-scc-array i))
3559
 
                      (aref new-in-scc-array i))
3560
 
            do (setf (aref in-scc-array i) t))
3561
 
      in-scc-array)))
3562
 
 
3563
 
(defun-raw mtp (srg ccmfs num-contexts fwd-edges bwd-edges edge-head edge-tail)
3564
 
  ;; generic function for finding a maximal thread presever (mtp) as
3565
 
  ;; described in the scp paper. However, our algorithm is slightly
3566
 
  ;; different than that described in the scp paper. this is because
3567
 
  ;; we have a ccmf for every edge rather than every node. because of
3568
 
  ;; this, we cannot keep one count value for each ccm in the srg,
3569
 
  ;; since the are potentially multiple edges from the context
3570
 
  ;; containing the ccm, and if the ccm is not non-increasing or
3571
 
  ;; decreasing along any one of those edges, it is not part of the
3572
 
  ;; mtp. therefore, for each ccm, we maintain several counts, one for
3573
 
  ;; each outgoing edge.
3574
 
 
3575
 
  ;; the srg is an srg, the ccmfs is a list of ccmfs that should be
3576
 
  ;; the ccmfs of the srg. num-contexts is the number of contexts
3577
 
  ;; represented by the srg. fwd-edges, bwd-edges, edge-head, and
3578
 
  ;; edge-tail are functions that tell us how to get around the
3579
 
  ;; graph. these are here to allow us to quickly find mtps in a graph
3580
 
  ;; and its inverse.
3581
 
  (let* ((n (array-dimension srg 0))
3582
 
         ;; we make the count array a matrix. for each ccm, we
3583
 
         ;; maintain num-context counts. unless the accg is not
3584
 
         ;; complete, some of these counts will always be 0. however,
3585
 
         ;; this slight inefficiency in space allows us to maintain
3586
 
         ;; simpler and more efficient code.
3587
 
         (count (make-array `(,n ,num-contexts)
3588
 
                            :element-type 'fixnum :initial-element 0))
3589
 
         ;; the accg matrix is an adjacency matrix representation of
3590
 
         ;; the accg implied by the ccmfs.
3591
 
         (accg-matrix (make-array `(,num-contexts ,num-contexts)
3592
 
                                   :element-type 'boolean
3593
 
                                   :initial-element nil))
3594
 
         ;; marked keeps track of which ccms are marked as not being
3595
 
         ;; part of the mtp.
3596
 
         (marked (make-array n :element-type 'boolean :initial-element nil))
3597
 
         ;; the worklist keeps track of the ccms to visit.
3598
 
         (worklist nil))
3599
 
    ;; first, we construct the accg-matrix
3600
 
    (dolist (ccmf ccmfs)
3601
 
      (setf (aref accg-matrix (ccmf-firstsite ccmf) (ccmf-lastsite ccmf)) t))
3602
 
    ;; next, we initiate the counts.
3603
 
    (dotimes (i n)
3604
 
      (let ((node (aref srg i)))
3605
 
        ;; for each edge from node i, we increment the counter
3606
 
        ;; corresponding to the index of the context for which the
3607
 
        ;; head of e is a ccm:
3608
 
        (dolist (e (funcall fwd-edges node)) 
3609
 
          (incf (aref count i (srg-node-node (aref srg (funcall edge-head e))))))
3610
 
        ;; for every successor of the context of node that has count 0
3611
 
        ;; gets added to the worklist and is marked.
3612
 
        (dotimes (j num-contexts)
3613
 
          (when (and (aref accg-matrix (srg-node-node node) j)
3614
 
                     (= (aref count i j) 0))
3615
 
            (setf worklist (cons i worklist))
3616
 
            (setf (aref marked i) t)))))
3617
 
    ;; finally, we enter the meat of the algorithm, working through the worklist.
3618
 
    (loop while (consp worklist)
3619
 
          for cw = (car worklist)
3620
 
          for j = (srg-node-node (aref srg cw))
3621
 
          do (setf worklist (cdr worklist))
3622
 
          ;; every node in the worklist is out of the mtp, so we
3623
 
          ;; decrement the appropriate count of all its
3624
 
          ;; predecessors. any of them whose count reaches 0 gets
3625
 
          ;; added to the worklist and is marked.
3626
 
          do (dolist (e (funcall bwd-edges (aref srg cw)))
3627
 
               (let ((i (funcall edge-tail e)))
3628
 
                 (unless (aref marked i)
3629
 
                   (decf (aref count i j))
3630
 
                   (when (= (aref count i j) 0)
3631
 
                     (setf (aref marked i) t)
3632
 
                     (setf worklist (cons i worklist))))))
3633
 
          ;; finally, we return all the unmarked ccms.
3634
 
          finally (return (loop for i from 0 below n
3635
 
                                unless (aref marked i) collect i)))))
3636
 
 
3637
 
(defun-raw mtp-fwd (srg ccmfs num-contexts)
3638
 
  ;; instantiation of mtp for analysis of the original srg/accg
3639
 
  (mtp srg ccmfs num-contexts
3640
 
       #'srg-node-fwd-edges #'srg-node-bwd-edges
3641
 
       #'srg-edge-head #'srg-edge-tail))
3642
 
 
3643
 
 
3644
 
(defun-raw mtp-bwd (srg ccmfs num-contexts)
3645
 
  ;; instantiation of mtp for analysis of the transposition of the
3646
 
  ;; srg/accg
3647
 
  (mtp srg ccmfs num-contexts
3648
 
       #'srg-node-bwd-edges #'srg-node-fwd-edges
3649
 
       #'srg-edge-tail #'srg-edge-head))
3650
 
    
3651
 
 
3652
 
(defun-raw fan-free (srg edge-list other-node num-contexts)
3653
 
  ;; generic function for determining if there is no fanning in the
3654
 
  ;; srg. edge-list is a function for retrieving the list of
3655
 
  ;; incoming/outgoing edges of a node. other-node tells us how to get
3656
 
  ;; the other node adjacent to an edge. num-contexts is the number of
3657
 
  ;; contexts that the srg represents. in our context fanning is when
3658
 
  ;; a ccm has multiple incoming/outgoing edges from ccms of the same
3659
 
  ;; context.
3660
 
  (loop
3661
 
   with n = (array-dimension srg 0)
3662
 
   ;; seen is an array keeping track of which contexts we have seen ccms from.
3663
 
   with seen = (make-array num-contexts :element-type 'boolean :initial-element nil)
3664
 
   for i from 0 below n
3665
 
   ;; loop through the edges of srg ccm i, keeping track of the
3666
 
   ;; contexts to which the adjacent ccms belong. if we see a context
3667
 
   ;; twice, we have fanning and return nil.
3668
 
   unless (loop for e in (funcall edge-list (aref srg i))
3669
 
                for j = (funcall other-node e)
3670
 
                for context = (srg-node-node (aref srg j))
3671
 
                if (aref seen context) return nil
3672
 
                else do (setf (aref seen context) t)
3673
 
                finally (return t))
3674
 
     return nil
3675
 
   ;; reset the seen array. this is cheaper than creating a new array
3676
 
   ;; for each iteration of the outer loop.
3677
 
   do (loop for i from 0 below num-contexts
3678
 
            do (setf (aref seen i) nil))
3679
 
   finally (return t)))
3680
 
 
3681
 
(defun-raw fan-in-free (srg num-contexts)
3682
 
  ;; instantiation of fan-free to check for fan-in
3683
 
  (fan-free srg #'srg-node-bwd-edges #'srg-edge-tail num-contexts))
3684
 
 
3685
 
 
3686
 
(defun-raw fan-out-free (srg num-contexts)
3687
 
  ;; instantiation of fan-free to check for fan-out
3688
 
  (fan-free srg #'srg-node-fwd-edges #'srg-edge-head num-contexts))
3689
 
 
3690
 
(defun-raw mtp-to-anchor (srg ahash)
3691
 
  ;; given an srg that has been restricted to some mtp and a set of
3692
 
  ;; ccmfs represented by a hash table, we add to ahash the anchor
3693
 
  ;; implied by srg. that is, we add all ccmfs containing a > edge in
3694
 
  ;; the restricted srg.
3695
 
  (loop for i from 0 below (array-dimension srg 0)
3696
 
        do (loop for e in (srg-node-fwd-edges (aref srg i))
3697
 
                 when (and (eq (srg-edge-label e) '>)
3698
 
                           (not (gethash (srg-edge-ccmf e) ahash)))
3699
 
                   do (setf (gethash (srg-edge-ccmf e) ahash) t))
3700
 
        finally (return ahash)))
3701
 
 
3702
 
(defun-raw simple-anchors (srg ahash ccmfs num-contexts)
3703
 
  ;; simple anchors, also called type 1 anchors in other papers by the
3704
 
  ;; scp authors, are anchors based on mtps.
3705
 
  (let ((srgp (srg-restrict srg (mtp-fwd srg ccmfs num-contexts))))
3706
 
    (if (fan-in-free srgp num-contexts)
3707
 
        (mtp-to-anchor srgp ahash)
3708
 
      (let ((srgq (srg-restrict srg (mtp-bwd srg ccmfs num-contexts))))
3709
 
        (if (fan-out-free srgq num-contexts)
3710
 
            (mtp-to-anchor srgq ahash)    
3711
 
          nil)))))
3712
 
 
3713
 
(defun-raw srg-restrict-edges (srg pred)
3714
 
  ;; this function non-destructively constructs a new srg that is
3715
 
  ;; identical to srg except it excludes edges that fail the
3716
 
  ;; predicate, pred.
3717
 
  (loop
3718
 
   with n = (array-dimension srg 0)
3719
 
   with rsrg = (make-array n)
3720
 
   for i from 0 below n
3721
 
   for node = (aref srg i)
3722
 
   do (setf (aref rsrg i)
3723
 
            (make-srg-node :node (srg-node-node node)
3724
 
                           :ccm (srg-node-ccm node)
3725
 
                           :fwd-edges (remove-if-not pred (srg-node-fwd-edges node))
3726
 
                           :bwd-edges (remove-if-not pred (srg-node-bwd-edges node))))
3727
 
   finally (return rsrg)))
3728
 
 
3729
 
(defun-raw ndg (srg)
3730
 
  ;; constructs the no-descent graph, a subgraph of the srg consisting
3731
 
  ;; of only nonstrict edges.
3732
 
  (srg-restrict-edges srg (lambda (e) (eq (srg-edge-label e) '>=))))
3733
 
 
3734
 
 
3735
 
(defun-raw srg-interior (srg)
3736
 
  ;; constructs the interior of an srg, that is, the subgraph of the
3737
 
  ;; srg consisting of the edges of the srg that are interior to an
3738
 
  ;; scc of the srg.
3739
 
  (multiple-value-bind
3740
 
      (scc scc-array)
3741
 
      (srg-scc srg)
3742
 
    (declare (ignore scc))
3743
 
    (srg-restrict-edges srg
3744
 
                        (lambda (e)
3745
 
                          (eq (aref scc-array (srg-edge-tail e))
3746
 
                              (aref scc-array (srg-edge-head e)))))))
3747
 
 
3748
 
 
3749
 
(defun-raw srg-to-matrix (srg)
3750
 
  ;; straight-forward function for making an adjacency matrix of srg.
3751
 
  (loop with n = (array-dimension srg 0)
3752
 
        with matrix = (make-array (list n n)
3753
 
                                  :element-type 'boolean
3754
 
                                  :initial-element nil)
3755
 
        for i from 0 below n
3756
 
        do (loop for e in (srg-node-fwd-edges (aref srg i))
3757
 
                 do (setf (aref matrix i (srg-edge-head e)) t))
3758
 
        finally (return matrix)))
3759
 
        
3760
 
;;   (let* ((n (array-dimension srg 0))
3761
 
;;          (matrix (make-array (list n n) :element-type 'boolean :initial-element nil)))
3762
 
;;     (dotimes (i n matrix)
3763
 
;;       (dolist (e (srg-node-fwd-edges (aref srg i)))
3764
 
;;         (setf (aref matrix i (srg-edge-head e)) t)))))
3765
 
 
3766
 
 
3767
 
(defun-raw ccmf-to-ccmfdown-in-srg (srg ccmf ndgi-matrix)
3768
 
  ;; by ccmfdown, here, we mean the original ccmf minus any arcs
3769
 
  ;; belonging to the interior of ndg of srg. for ccmf, G, this is
3770
 
  ;; represented in the scp paper as G with a small down arrow to its
3771
 
  ;; right. hence the name. we return a copy of the srg restricted to
3772
 
  ;; not include edges in ccmfdown.
3773
 
  (srg-restrict-edges srg
3774
 
                      (lambda (e)
3775
 
                        (not (and (eq (srg-node-node (aref srg (srg-edge-tail e)))
3776
 
                                      (ccmf-firstsite ccmf))
3777
 
                                  (eq (srg-node-node (aref srg (srg-edge-head e)))
3778
 
                                      (ccmf-lastsite ccmf))
3779
 
                                  (aref ndgi-matrix (srg-edge-tail e) (srg-edge-head e)))))))
3780
 
 
3781
 
(defun-raw anchor-find (srg ccmfs num-contexts)
3782
 
  ;; the anchor finding algorithm, as given in the scp paper. 
3783
 
  (let ((ahash (make-hash-table :rehash-size 2 :rehash-threshold (float 3/4))))
3784
 
    (multiple-value-bind
3785
 
        (sccs scc-array)
3786
 
        (srg-scc srg)
3787
 
      (declare (ignore scc-array))
3788
 
      ;; for every scc of the srg, look for simple anchors.
3789
 
      (dolist (scc sccs)
3790
 
        (simple-anchors (srg-restrict srg scc) ahash ccmfs num-contexts))
3791
 
      ;; convert the set of anchors to a list.
3792
 
      (let ((anchors (loop for k being the hash-keys of ahash using (hash-value v)
3793
 
                           when v collect k)))
3794
 
        ;;(format t "simple anchors: ~A~%" anchors)
3795
 
        ;; if we have found anchors, return them.
3796
 
        (if anchors
3797
 
            anchors
3798
 
          ;; otherwise, we attempt to find "type 2" anchors, as they
3799
 
          ;; are called in the scp paper.
3800
 
          (loop with ndgi-matrix = (srg-to-matrix (srg-interior (ndg srg)))
3801
 
                for ccmf in ccmfs
3802
 
                for h = (ccmf-to-ccmfdown-in-srg srg ccmf ndgi-matrix)
3803
 
                when (or (mtp-fwd h ccmfs num-contexts)
3804
 
                         (mtp-bwd h ccmfs num-contexts))
3805
 
                  return (list ccmf)))))))
3806
 
 
3807
 
(defun-raw copy-a-ccmf (ccmf)
3808
 
  (make-ccmf :firstsite (ccmf-firstsite ccmf)
3809
 
             :lastsite (ccmf-lastsite ccmf)
3810
 
             :fc-num (ccmf-fc-num ccmf)
3811
 
             :lc-num (ccmf-lc-num ccmf)
3812
 
             :graph (accg-copy-ccmf-graph (ccmf-graph ccmf))
3813
 
             :in-sizes (ccmf-in-sizes ccmf)
3814
 
             :out-sizes (ccmf-out-sizes ccmf)
3815
 
             :steps (ccmf-steps ccmf)))
3816
 
 
3817
 
(defun-raw copy-ccmfs (ccmfs)
3818
 
  ;; just like it says, this function copies a list of ccmfs.
3819
 
  (loop for ccmf in ccmfs
3820
 
    collect (copy-a-ccmf ccmf)))
3821
 
 
3822
 
(defun-raw copy-accg (accg)
3823
 
  (let* ((n (array-dimension accg 0))
3824
 
         (naccg (make-array n)))
3825
 
    (loop for i from 0 below n
3826
 
          for node = (aref accg i)
3827
 
          do (setf (aref naccg i)
3828
 
                   (make-accg-node :context (accg-node-context node)
3829
 
                                   :num i)))
3830
 
    (loop
3831
 
     for node across accg
3832
 
     for nnode across naccg
3833
 
     do (setf (accg-node-fwd-edges nnode)
3834
 
              (loop
3835
 
               for edge in (accg-node-fwd-edges node)
3836
 
               for head = (accg-edge-head edge)
3837
 
               for hnode = (aref naccg head)
3838
 
               for nedge = (make-accg-edge
3839
 
                            :tail (accg-edge-tail edge)
3840
 
                            :head head
3841
 
                            :ccmf (copy-a-ccmf (accg-edge-ccmf edge)))
3842
 
               do (setf (accg-node-bwd-edges hnode)
3843
 
                        (cons nedge (accg-node-bwd-edges hnode)))
3844
 
               collect nedge)))
3845
 
    naccg))
3846
 
 
3847
 
(defun-raw accg-ccmfs (accg)
3848
 
  ;; returns all the ccmfs used to annotate accg
3849
 
  (loop for node across accg
3850
 
        append (mapcar #'accg-edge-ccmf
3851
 
                       (accg-node-fwd-edges node))))
3852
 
;;   (let ((ccmfs nil))
3853
 
;;     (dotimes (i (array-dimension accg 0) ccmfs)
3854
 
;;       (dolist (e (accg-node-fwd-edges (aref accg i)))
3855
 
;;         (setf ccmfs (cons (accg-edge-ccmf e) ccmfs))))))
3856
 
 
3857
 
(defun-raw accg-contexts (accg)
3858
 
  ;; returns the contexts of the accg.
3859
 
  (map 'vector (lambda (x) (accg-node-context x)) accg))
3860
 
 
3861
 
(defun-raw accg-srg-add-edge (tailnode headnode tailnum headnum ccmf label)
3862
 
  ;; adds an adge to the tailnode and headnode of an srg.
3863
 
  (let ((edge (make-srg-edge :tail tailnum
3864
 
                             :head headnum
3865
 
                             :ccmf ccmf
3866
 
                             :label label)))
3867
 
    (setf (srg-node-fwd-edges tailnode)
3868
 
          (cons edge (srg-node-fwd-edges tailnode)))
3869
 
    (setf (srg-node-bwd-edges headnode)
3870
 
          (cons edge (srg-node-bwd-edges headnode)))
3871
 
    nil))
3872
 
 
3873
 
(defun-raw accg-remove-edges-corresponding-to-ccmfs (accg ccmfs)
3874
 
  ;; destructively removes edges corresponding to the list of ccmfs from the
3875
 
  ;; accg. The ccmfs must be pointer-equal (eq) to the ones you want removed
3876
 
  ;; from the accg.
3877
 
  
3878
 
  ;; first, we set the firstsite field of the ccmfs we want to remove
3879
 
  ;; to -1.
3880
 
  (loop for ccmf in ccmfs do (setf (ccmf-firstsite ccmf) -1))
3881
 
  ;; next, we loop through all the accg-nodes, deleting any
3882
 
  ;; incoming/outgoing edges whose firstsite is -1.
3883
 
  (loop with pred = (lambda (edge)
3884
 
                      (= (ccmf-firstsite (accg-edge-ccmf edge)) -1))
3885
 
        for node across accg
3886
 
        do (setf (accg-node-fwd-edges node)
3887
 
                 (delete-if pred (accg-node-fwd-edges node)))
3888
 
        do (setf (accg-node-bwd-edges node)
3889
 
                 (delete-if pred (accg-node-bwd-edges node))))
3890
 
  accg)
3891
 
 
3892
 
(defun-raw accg-construct-srg (accg)
3893
 
  ;; constructs an srg from a accg. to do this, we "flatten" out the
3894
 
  ;; ccms of each accg-node, laying all the ccms from all the
3895
 
  ;; accg-nodes next to each other and creating an srg-node for each
3896
 
  ;; ccm.
3897
 
  (let* ((n (array-dimension accg 0))
3898
 
         ;; we need an offset array to tell us what index in the srg
3899
 
         ;; corresponds to the first ccm in each accg-node.
3900
 
         (node-offset (make-array n
3901
 
                                  :element-type 'fixnum
3902
 
                                  :initial-element 0))
3903
 
         (c 0))
3904
 
    ;; compute the offsets:
3905
 
    (dotimes (i n)
3906
 
      (setf (aref node-offset i) c)
3907
 
      (incf c (array-dimension (accg-node-ccms (aref accg i)) 0)))
3908
 
    ;; at this point c = the number of nodes in the srg.
3909
 
    (let ((srg (make-array c
3910
 
                           :element-type 'srg-node
3911
 
                           :initial-element (make-srg-node))))
3912
 
      ;; make all the new nodes.
3913
 
      (loop for i from 1 below c
3914
 
            do (setf (aref srg i) (make-srg-node)))
3915
 
      ;; now we add all the edges.
3916
 
      (loop ;; we loop through the accg
3917
 
       for i from 0 below n
3918
 
       do (loop ;; we loop through the fwd-ccmfs of node i
3919
 
           for edge in (accg-node-fwd-edges (aref accg i))
3920
 
           for ccmf = (accg-edge-ccmf edge)
3921
 
           for offset1 = (aref node-offset i)
3922
 
           for offset2 = (aref node-offset (accg-edge-head edge))
3923
 
           for cg = (ccmf-graph ccmf)
3924
 
           do (loop ;; we loop through the ccmf.
3925
 
               for j from 0 below (array-dimension cg 0)
3926
 
               for a from offset1
3927
 
               for nodea = (aref srg a)
3928
 
               do (setf (srg-node-node nodea) i)
3929
 
               do (setf (srg-node-ccm nodea) j)
3930
 
               do (loop ;; we loop through the >-edges and add them to the srg.
3931
 
                   for x in (ccmf-node->-edges (aref cg j))
3932
 
                   for b = (+ offset2 x)
3933
 
                   do (accg-srg-add-edge nodea (aref srg b) a b ccmf '>))
3934
 
               do (loop ;; we loop through the >=-edges and add them to the srg.
3935
 
                   for x in (ccmf-node->=-edges (aref cg j))
3936
 
                   for b = (+ offset2 x)
3937
 
                   do (accg-srg-add-edge nodea (aref srg b) a b ccmf '>=))))
3938
 
       finally (return srg)))))
3939
 
 
3940
 
(defun-raw cln-accg (accg)
3941
 
  ;; this function cleans a accg by removing any ccmf edge that is
3942
 
  ;; not internal to an scc in the corresponding srg that contains a >
3943
 
  ;; edge.
3944
 
  (let* ((srg (accg-construct-srg accg)) ;; the srg for the accg.
3945
 
         (n (array-dimension accg 0))
3946
 
         (deletep-array (make-array n))) ;; tells us which ccms to delete.
3947
 
    ;; initiate the deletep-array
3948
 
    (dotimes (i n)
3949
 
      (setf (aref deletep-array i)
3950
 
            (make-array (array-dimension
3951
 
                         (accg-node-ccms (aref accg i))
3952
 
                         0)
3953
 
                        :element-type 'boolean
3954
 
                        :initial-element nil)))
3955
 
    ;; analyze the sccs of the srg.
3956
 
    (multiple-value-bind
3957
 
        (sccs scc-array)
3958
 
        (srg-scc srg)
3959
 
      ;; for each scc, add the nodes of the scc to the deletep array
3960
 
      ;; unless it contains a > edge.
3961
 
      (loop for scc in sccs
3962
 
            unless (srg-scc-has->-edgep scc scc-array srg)
3963
 
            do (loop for v in scc
3964
 
                     for node = (aref srg v)
3965
 
                     for context = (srg-node-node node)
3966
 
                     for ccm = (srg-node-ccm node)
3967
 
                     do (setf (aref (aref deletep-array context) ccm) t))))
3968
 
    ;; destructively remove the unwanted ccms.
3969
 
    (progn
3970
 
      (ccmf-remove-ccms-list (accg-ccmfs accg)
3971
 
                             deletep-array)
3972
 
      accg)))
3973
 
 
3974
 
(defun-raw scp (accg)
3975
 
  ;; the main scp algorithm. it takes an accg and recursively removes
3976
 
  ;; anchors and analyzes the sccs of the remainder of the graph until
3977
 
  ;; either there is no graph left, or we can't find any more
3978
 
  ;; anchors. see the scp paper.
3979
 
  (when accg
3980
 
    (let* ((n (array-dimension accg 0))
3981
 
           (anchors (anchor-find (accg-construct-srg accg)
3982
 
                                 (accg-ccmfs accg)
3983
 
                                 n)))
3984
 
      (when anchors
3985
 
        (mv-let
3986
 
         (changes sccs)
3987
 
         (accg-separate-sccs
3988
 
                     (accg-remove-edges-corresponding-to-ccmfs accg anchors))
3989
 
         (declare (ignore changes))
3990
 
         (loop for scc in sccs
3991
 
               unless (scp (cln-accg scc))
3992
 
               return nil
3993
 
               finally (return t)))))))
3994
 
 
3995
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3996
 
;;; the following code implements the SCT analysis
3997
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3998
 
 
3999
 
(defstruct-raw scg-path
4000
 
  ;; the first num in the path
4001
 
  (start 0 :type fixnum)
4002
 
  ;; the second num in the path
4003
 
  (end 0 :type fixnum)
4004
 
  ;; the total length of the path
4005
 
  (length 0 :type fixnum)
4006
 
  ;; the interior of the path (everything except the start and end). We
4007
 
  ;; represent this as a tree so that we don't have to append every time we
4008
 
  ;; compose SCGs. We do this in such a way that a depth-first car-to-cdr
4009
 
  ;; seorch of the tree returns the path.
4010
 
  (interior nil :type (or null fixnum cons)))
4011
 
 
4012
 
(defun-raw new-scg-path (start end)
4013
 
  (make-scg-path :start start
4014
 
                 :end end
4015
 
                 :length 2
4016
 
                 :interior nil))
4017
 
 
4018
 
(defun-raw compose-scg-paths (p1 p2)
4019
 
  (make-scg-path :start (scg-path-start p1)
4020
 
                 :end (scg-path-end p2)
4021
 
                 :length (1- (+ (scg-path-length p1)
4022
 
                                (scg-path-length p2)))
4023
 
                 :interior (let ((x (if (null (scg-path-interior p2))
4024
 
                                        (scg-path-start p2)
4025
 
                                      (cons (scg-path-start p2)
4026
 
                                            (scg-path-interior p2)))))
4027
 
                             (if (null (scg-path-interior p1))
4028
 
                                 x
4029
 
                               (cons (scg-path-interior p1) x)))))
4030
 
 
4031
 
(defun-raw flatten-scg-interior (interior acc)
4032
 
  (cond ((null interior)
4033
 
         acc)
4034
 
        ((atom interior)
4035
 
         (cons interior acc))
4036
 
        (t
4037
 
         (flatten-scg-interior (car interior)
4038
 
                               (flatten-scg-interior (cdr interior)
4039
 
                                                     acc)))))
4040
 
 
4041
 
(defun-raw flatten-scg-path (path)
4042
 
  (cons (scg-path-start path)
4043
 
        (flatten-scg-interior (scg-path-interior path)
4044
 
                              (list (scg-path-end path)))))
4045
 
  
4046
 
 
4047
 
;; for the purposes of this algorithm, we only need to know the starts and ends
4048
 
;; of paths. We only need the interior to construct the paths later. Therefore,
4049
 
;; we define functions for equality and ordering paths accordingly.
4050
 
(defun-raw scg-path-equal (p1 p2)
4051
 
  (and (= (scg-path-start p1)
4052
 
          (scg-path-start p2))
4053
 
       (= (scg-path-end p1)
4054
 
          (scg-path-end p2))))
4055
 
 
4056
 
(defun-raw path< (p1 p2)
4057
 
  (or (< (scg-path-start p1)
4058
 
         (scg-path-start p2))
4059
 
      (and (= (scg-path-start p1)
4060
 
              (scg-path-start p2))
4061
 
           (< (scg-path-end p1)
4062
 
              (scg-path-end p2)))))
4063
 
 
4064
 
 
4065
 
;; since we keep the interior of a path aronud for constructing
4066
 
;; counter-examples, we want to keep around the shortest path. Therefore, when
4067
 
;; given two paths with identical start and end points, we pick the one with
4068
 
;; the shortest path.
4069
 
(defun-raw shortest-scg-path (p1 p2)
4070
 
  (if (<= (scg-path-length p1)
4071
 
          (scg-path-length p2))
4072
 
      p1
4073
 
    p2))
4074
 
 
4075
 
(defstruct-raw scg
4076
 
  (paths nil :type list)
4077
 
  (newest-paths nil :type list)
4078
 
  (new-newest-paths nil :type list)
4079
 
  (num 0 :type fixnum)
4080
 
  (graph nil))
4081
 
 
4082
 
(defun-raw sorted-set-union1 (lst1 lst2 key1 key2 predicate combine key test)
4083
 
  ;; lst1 and lst2 should be sorted, non-empty lists.
4084
 
  ;; key1 should be equal to (funcall key (car lst1))
4085
 
  ;; key2 should be equal to (funcall key (car lst2))
4086
 
  ;; key should be a unary function that returns an equal-able value.
4087
 
  (cond ((funcall test key1 key2)
4088
 
         (cons (car lst1)
4089
 
               (sorted-set-union (cdr lst1) (cdr lst2)
4090
 
                                 predicate
4091
 
                                 :key key
4092
 
                                 :combine combine
4093
 
                                 :test test)))
4094
 
        ((funcall predicate key1 key2)
4095
 
         (cons (car lst1)
4096
 
               (if (endp (cdr lst1))
4097
 
                   lst2
4098
 
                 (sorted-set-union1 (cdr lst1) lst2
4099
 
                                    (funcall key (cadr lst1))
4100
 
                                    key2
4101
 
                                    predicate
4102
 
                                    combine
4103
 
                                    key
4104
 
                                    test))))
4105
 
        (t
4106
 
         (cons (car lst2)
4107
 
               (if (endp (cdr lst2))
4108
 
                   lst1
4109
 
                 (sorted-set-union1 lst1 (cdr lst2)
4110
 
                                    key1
4111
 
                                    (funcall key (cadr lst2))
4112
 
                                    predicate
4113
 
                                    combine
4114
 
                                    key
4115
 
                                    test))))))
4116
 
 
4117
 
(defun-raw sorted-set-union (lst1 lst2 predicate
4118
 
                                  &key (key #'identity)
4119
 
                                  (combine #'(lambda (x y)
4120
 
                                               (declare (ignore y))
4121
 
                                               x))
4122
 
                                  (test #'equal))
4123
 
  (cond ((endp lst1) lst2)
4124
 
        ((endp lst2) lst1)
4125
 
        (t
4126
 
         (sorted-set-union1 lst1 lst2
4127
 
                            (funcall key (car lst1))
4128
 
                            (funcall key (car lst2))
4129
 
                            predicate
4130
 
                            combine
4131
 
                            key
4132
 
                            test))))
4133
 
 
4134
 
(defun-raw sorted-set-difference1 (lst1 lst2 key1 key2 predicate key test)
4135
 
  ;; lst1 and lst2 should be sorted, non-empty lists.
4136
 
  ;; key1 should be equal to (funcall key (car lst1))
4137
 
  ;; key2 should be equal to (funcall key (car lst2))
4138
 
  ;; key should be a unary function that returns an equal-able value.
4139
 
  (cond ((funcall test key1 key2)
4140
 
         (sorted-set-difference (cdr lst1) (cdr lst2)
4141
 
                                predicate
4142
 
                                :key key
4143
 
                                :test test))
4144
 
        ((funcall predicate key1 key2)
4145
 
         (cons (car lst1)
4146
 
               (if (endp (cdr lst1))
4147
 
                   nil
4148
 
                 (sorted-set-difference1 (cdr lst1) lst2
4149
 
                                         (funcall key (cadr lst1))
4150
 
                                         key2
4151
 
                                         predicate
4152
 
                                         key
4153
 
                                         test))))
4154
 
        (t
4155
 
         (if (endp (cdr lst2))
4156
 
             lst1
4157
 
           (sorted-set-difference1 lst1 (cdr lst2)
4158
 
                                   key1
4159
 
                                   (funcall key (cadr lst2))
4160
 
                                   predicate
4161
 
                                   key
4162
 
                                   test)))))
4163
 
 
4164
 
(defun-raw sorted-set-difference (lst1 lst2 predicate
4165
 
                                       &key (key #'identity)
4166
 
                                       (test #'equal))
4167
 
  (cond ((endp lst1) nil)
4168
 
        ((endp lst2) lst1)
4169
 
        (t
4170
 
         (sorted-set-difference1 lst1 lst2
4171
 
                                (funcall key (car lst1))
4172
 
                                (funcall key (car lst2))
4173
 
                                predicate
4174
 
                                key
4175
 
                                test))))
4176
 
 
4177
 
(defun-raw sorted-union/difference1 (lst1 lst2 key1 key2 predicate combine key test)
4178
 
  ;; lst1 and lst2 should be sorted, non-empty lists.
4179
 
  ;; key1 should be equal to (funcall key (car lst1))
4180
 
  ;; key2 should be equal to (funcall key (car lst2))
4181
 
  ;; key should be a unary function that returns an equal-able value.
4182
 
  (cond ((funcall test key1 key2)
4183
 
         (mv-let (union difference)
4184
 
                 (sorted-union/difference (cdr lst1) (cdr lst2)
4185
 
                                          predicate
4186
 
                                          :combine combine
4187
 
                                          :key key
4188
 
                                          :test test)
4189
 
                 (mv (cons (funcall combine (car lst1) (car lst2))
4190
 
                           union)
4191
 
                     difference)))
4192
 
        ((funcall predicate key1 key2)
4193
 
         (mv-let (union difference)
4194
 
                 (if (endp (cdr lst1))
4195
 
                     (mv lst2 nil)
4196
 
                   (sorted-union/difference1 (cdr lst1) lst2
4197
 
                                             (funcall key (cadr lst1))
4198
 
                                             key2
4199
 
                                             predicate
4200
 
                                             combine
4201
 
                                             key
4202
 
                                             test))
4203
 
                 (mv (cons (car lst1) union)
4204
 
                     (cons (car lst1) difference))))
4205
 
        (t
4206
 
         (mv-let (union difference)
4207
 
                 (if (endp (cdr lst2))
4208
 
                     (mv lst1 lst1)
4209
 
                   (sorted-union/difference1 lst1 (cdr lst2)
4210
 
                                             key1
4211
 
                                             (funcall key (cadr lst2))
4212
 
                                             predicate
4213
 
                                             combine
4214
 
                                             key
4215
 
                                             test))
4216
 
                 (mv (cons (car lst2) union)
4217
 
                     difference)))))
4218
 
 
4219
 
(defun-raw sorted-union/difference (lst1 lst2 predicate
4220
 
                                         &key (key #'identity)
4221
 
                                         (combine #'(lambda (x y)
4222
 
                                                      (declare (ignore y))
4223
 
                                                      x))
4224
 
                                         (test #'equal))
4225
 
  (cond ((endp lst1) (mv lst2 nil))
4226
 
        ((endp lst2) (mv lst1 lst1))
4227
 
        (t
4228
 
         (sorted-union/difference1 lst1 lst2
4229
 
                                   (funcall key (car lst1))
4230
 
                                   (funcall key (car lst2))
4231
 
                                   predicate
4232
 
                                   combine
4233
 
                                   key
4234
 
                                   test))))
4235
 
 
4236
 
(defun-raw sorted-adjoin (element set predicate
4237
 
                                  &key (key #'identity)
4238
 
                                  (combine #'(lambda (x y)
4239
 
                                                      (declare (ignore y))
4240
 
                                                      x))
4241
 
                                  (test #'equal))
4242
 
  (sorted-set-union (list element) set predicate
4243
 
                    :key key :combine combine :test test))
4244
 
 
4245
 
(defun-raw sorted-remove-duplicates1 (lst carkey key combine test)
4246
 
  (if (endp (cdr lst))
4247
 
      lst
4248
 
    (let ((cadrkey (funcall key (cadr lst))))
4249
 
      (if (funcall test carkey cadrkey)
4250
 
          (let ((comb (funcall combine (car lst) (cadr lst))))
4251
 
            (sorted-remove-duplicates1  (cons comb (cddr lst))
4252
 
                                        (funcall key comb)
4253
 
                                        key
4254
 
                                        combine
4255
 
                                        test))
4256
 
        (cons (car lst)
4257
 
              (sorted-remove-duplicates1 (cdr lst)
4258
 
                                        cadrkey
4259
 
                                        key
4260
 
                                        combine
4261
 
                                        test))))))
4262
 
 
4263
 
(defun-raw sorted-remove-duplicates (lst &key (key #'identity)
4264
 
                                         (combine #'(lambda (x y)
4265
 
                                                      (declare (ignore y))
4266
 
                                                      x))
4267
 
                                         (test #'equal))
4268
 
  (cond ((endp lst) nil)
4269
 
        ((endp (cdr lst)) lst)
4270
 
        (t
4271
 
         (sorted-remove-duplicates1 lst
4272
 
                                    (funcall key (car lst))
4273
 
                                    key
4274
 
                                    combine
4275
 
                                    test))))
4276
 
         
4277
 
 
4278
 
(defun-raw list-to-sorted-set (lst predicate
4279
 
                                   &key (key #'identity)
4280
 
                                   (combine #'(lambda (x y)
4281
 
                                                      (declare (ignore y))
4282
 
                                                      x))
4283
 
                                   (test #'equal))
4284
 
  ;; WARNING: THIS FUNCTION IS DESTRUCTIVE TO LST.
4285
 
  (sorted-remove-duplicates (sort lst predicate :key key)
4286
 
                            :key key
4287
 
                            :combine combine
4288
 
                            :test test))
4289
 
 
4290
 
(defun-raw scg-graph-key (graph)
4291
 
  #-gcl
4292
 
  graph
4293
 
  #+gcl
4294
 
  (loop for node across graph
4295
 
        for >-edges = (ccmf-node->-edges node)
4296
 
        for >=-edges = (ccmf-node->=-edges node)
4297
 
        collect (cons (length >-edges) (length >=-edges)) into lens
4298
 
        collect (cons >-edges >=-edges) into lst
4299
 
        finally (list* (array-dimension graph 0) lens lst)))
4300
 
 
4301
 
(defun-raw update-scg-paths (graph paths i graph-hash)
4302
 
  ;; graph is a ccmf-graph
4303
 
  ;; paths is a sorted set of paths to be added for graph
4304
 
  ;; i is our scg counter, used for giving each scg a unique numerical id.
4305
 
  ;; graph-hash is an equalp hash-table (an equal hash-table in GCL)
4306
 
  ;;
4307
 
  ;; OUTPUT: 4 values: 
4308
 
  ;; 1. the new value of i.
4309
 
  ;; 2. whether this is the first update to the new-newest-paths of the scg.
4310
 
  ;; 3. the new paths added.
4311
 
  ;; 4. the scg that was updated.
4312
 
  ;; (format t "~&Calling: ~A~%" `(update-scg-paths ,graph ,paths ,i ,graph-hash))
4313
 
  (let* ((key (scg-graph-key graph))
4314
 
         (scg (gethash key graph-hash)))
4315
 
    (if scg
4316
 
        (let* ((new-newest-paths (scg-new-newest-paths scg))
4317
 
               (npaths (sorted-set-difference
4318
 
                        (sorted-set-difference paths
4319
 
                                               (scg-paths scg)
4320
 
                                               #'path<
4321
 
                                               :test #'scg-path-equal)
4322
 
                        (scg-newest-paths scg)
4323
 
                        #'path<
4324
 
                        :test #'scg-path-equal)))
4325
 
          (mv-let (union difference)
4326
 
                  (sorted-union/difference npaths new-newest-paths #'path<
4327
 
                                           :test #'scg-path-equal
4328
 
                                           :combine #'shortest-scg-path)
4329
 
                  (progn
4330
 
                    (setf (scg-new-newest-paths scg) union)
4331
 
                    (mv i (endp new-newest-paths) difference scg))))
4332
 
      (let ((nscg (make-scg :graph graph
4333
 
                            :num i
4334
 
                            :new-newest-paths paths)))
4335
 
        (setf (gethash key graph-hash) nscg)
4336
 
        ;; (format t "Returning: ~A~%"
4337
 
        ;;                       `(update-scg-paths ,(1+ i)
4338
 
        ;;                                          t
4339
 
        ;;                                          ,paths
4340
 
        ;;                                          ,nscg))
4341
 
        (mv (1+ i) t paths nscg)))))
4342
 
 
4343
 
(defun-raw age-scgs (lst)
4344
 
  ;; lst is a list of scgs
4345
 
  ;;
4346
 
  ;; SIDE-EFFECT: the scgs are "aged", i.e. their newest-paths are unioned with
4347
 
  ;; their paths, the new-newest-paths are moved to the newest-paths, and their
4348
 
  ;; new-newest-paths slot is set to nil.
4349
 
  ;;
4350
 
  ;; OUTPUT: lst
4351
 
  (loop for scg in lst
4352
 
        do (setf (scg-paths scg)
4353
 
                 (sorted-set-union (scg-paths scg)
4354
 
                                   (scg-newest-paths scg)
4355
 
                                   #'path<
4356
 
                                   :combine #'shortest-scg-path
4357
 
                                   :test #'scg-path-equal))
4358
 
        do (setf (scg-newest-paths scg)
4359
 
                 (scg-new-newest-paths scg))
4360
 
        do (setf (scg-new-newest-paths scg)
4361
 
                 nil)
4362
 
        finally (return lst)))
4363
 
 
4364
 
(defun-raw ccmfs-to-scgs1 (ccmfs graph-hash i acc)
4365
 
  (if (endp ccmfs)
4366
 
      (mv i (sort acc #'< :key #'scg-num))
4367
 
    (let ((ccmf (car ccmfs)))
4368
 
      (mv-let (ni new? diff scg)
4369
 
              (update-scg-paths (ccmf-graph ccmf)
4370
 
                                (list (new-scg-path (ccmf-firstsite ccmf)
4371
 
                                                    (ccmf-lastsite ccmf)))
4372
 
                                i
4373
 
                                graph-hash)
4374
 
              (ccmfs-to-scgs1 (cdr ccmfs) graph-hash ni
4375
 
                              (if (and new? (consp diff))
4376
 
                                  (cons scg acc)
4377
 
                                acc))))))
4378
 
 
4379
 
(defun-raw ccmfs-to-scgs (ccmfs graph-hash)
4380
 
  (ccmfs-to-scgs1 ccmfs graph-hash 0 nil))
4381
 
 
4382
 
(defun-raw compose-scg-graphs (g h)
4383
 
  (loop with n = (array-dimension g 0)
4384
 
        with gh = (make-array (array-dimension g 0)
4385
 
                              :element-type 'ccmf-node
4386
 
                              :initial-element (make-ccmf-node))
4387
 
        for i below n
4388
 
        for nodei = (aref g i)
4389
 
        for >-edges = nil
4390
 
        for >=-edges = nil
4391
 
        do (loop for j in (ccmf-node->-edges nodei)
4392
 
                 for nodej = (aref h j)
4393
 
                 do (loop for k in (ccmf-node->-edges nodej)
4394
 
                          do (setf >-edges (cons k >-edges)))
4395
 
                 do (loop for k in (ccmf-node->=-edges nodej)
4396
 
                          do (setf >-edges (cons k >-edges))))
4397
 
        do (loop for j in (ccmf-node->=-edges nodei)
4398
 
                 for nodej = (aref h j)
4399
 
                 do (loop for k in (ccmf-node->-edges nodej)
4400
 
                          do (setf >-edges (cons k >-edges)))
4401
 
                 do (loop for k in (ccmf-node->=-edges nodej)
4402
 
                          do (setf >=-edges (cons k >=-edges))))
4403
 
        do (let* ((sorted->-edges (list-to-sorted-set >-edges #'<)))
4404
 
             (setf (aref gh i)
4405
 
                   (make-ccmf-node
4406
 
                    :>-edges sorted->-edges
4407
 
                    :>=-edges (sorted-set-difference
4408
 
                               (list-to-sorted-set >=-edges #'<)
4409
 
                               sorted->-edges
4410
 
                               #'<))))
4411
 
        finally (return gh)))
4412
 
 
4413
 
(defun-raw compose-scg-path-lsts1 (gpath hpaths acc)
4414
 
  (if (or (endp hpaths)
4415
 
          (not (= (scg-path-start (car hpaths))
4416
 
                  (scg-path-end gpath))))
4417
 
    acc
4418
 
    (compose-scg-path-lsts1 gpath (cdr hpaths)
4419
 
                            (cons (compose-scg-paths gpath (car hpaths))
4420
 
                                  acc))))
4421
 
 
4422
 
(defun-raw compose-scg-path-lsts (gpaths hpaths acc)
4423
 
  ;; gpaths should be a list of paths sorted in increasing order by their cdrs.
4424
 
  ;; hpaths should be a list of paths sorted in increasing order by their cars.
4425
 
  ;; acc is the accumulator
4426
 
  ;; returns a sorted-set of paths (sorted by path<).
4427
 
  (cond ((or (endp gpaths) (endp hpaths))
4428
 
         (list-to-sorted-set acc #'path<
4429
 
                             :test #'scg-path-equal
4430
 
                             :combine #'shortest-scg-path))
4431
 
        ((< (scg-path-end (car gpaths))
4432
 
            (scg-path-start (car hpaths)))
4433
 
         (compose-scg-path-lsts (cdr gpaths) hpaths acc))
4434
 
        ((> (scg-path-end (car gpaths))
4435
 
            (scg-path-start (car hpaths)))
4436
 
         (compose-scg-path-lsts gpaths (cdr hpaths) acc))
4437
 
        (t
4438
 
         (compose-scg-path-lsts (cdr gpaths)
4439
 
                                hpaths
4440
 
                                (compose-scg-path-lsts1 (car gpaths)
4441
 
                                                        hpaths
4442
 
                                                        acc)))))
4443
 
 
4444
 
(defun-raw scg-counter-example? (scg diff)
4445
 
  (and ;;there is a new self loop:
4446
 
   (loop for path in diff
4447
 
         when (= (scg-path-start path)
4448
 
                 (scg-path-end path))
4449
 
           return t
4450
 
         finally (return nil))
4451
 
   ;;there is no old self loop (in which case, we have already checked it out).
4452
 
   (loop for path in (append (scg-paths scg)
4453
 
                             (scg-newest-paths scg)
4454
 
                             (sorted-set-difference (scg-new-newest-paths scg)
4455
 
                                                    diff
4456
 
                                                    #'path<
4457
 
                                                    :test #'scg-path-equal))
4458
 
         when (= (scg-path-start path)
4459
 
                 (scg-path-end path))
4460
 
           return nil
4461
 
         finally (return t))
4462
 
   ;; there is no >-edge from a CCM to itself:
4463
 
   (loop with graph = (scg-graph scg)
4464
 
         for i from 0 below (array-dimension graph 0)
4465
 
         when (member i (ccmf-node->-edges (aref graph i)))
4466
 
           return nil
4467
 
         finally (return t))
4468
 
   ;; the graph is idempotent
4469
 
   (let ((graph (scg-graph scg)))
4470
 
     (equalp (compose-scg-graphs graph graph)
4471
 
             graph))))
4472
 
 
4473
 
(defun-raw shortest-self-loop (paths path)
4474
 
  (cond ((endp paths) path)
4475
 
        ((= (scg-path-start (car paths))
4476
 
            (scg-path-end (car paths)))
4477
 
         (shortest-self-loop (cdr paths)
4478
 
                             (if (or (null path)
4479
 
                                     (< (scg-path-length (car paths))
4480
 
                                        (scg-path-length path)))
4481
 
                                 (car paths)
4482
 
                               path)))
4483
 
        (t
4484
 
         (shortest-self-loop (cdr paths) path))))
4485
 
 
4486
 
(defun-raw compose-scgs (g h i graph-hash)
4487
 
  (let ((ghgraph (compose-scg-graphs (scg-graph g) (scg-graph h)))
4488
 
        (ghpaths (compose-scg-path-lsts (sort (copy-list (scg-newest-paths g))
4489
 
                                              #'< :key #'scg-path-end)
4490
 
                                        (scg-newest-paths h)
4491
 
                                        nil)))
4492
 
    (mv-let (ni new? diff gh)
4493
 
            (update-scg-paths ghgraph ghpaths i graph-hash)
4494
 
            (if (scg-counter-example? gh diff)
4495
 
                (mv t ni (cons (scg-graph gh)
4496
 
                               (flatten-scg-path (shortest-self-loop diff nil))))
4497
 
              (mv nil ni (if (and new? (consp diff)) gh nil))))))
4498
 
 
4499
 
(defun-raw scg-predecessors (scg)
4500
 
  (sorted-remove-duplicates (mapcar #'scg-path-start (scg-newest-paths scg))))
4501
 
 
4502
 
(defun-raw scg-successors (scg)
4503
 
  (list-to-sorted-set (mapcar #'scg-path-end (scg-newest-paths scg))
4504
 
                      #'<))    
4505
 
 
4506
 
(defun-raw organize-scgs-by-preds1 (scgs array)
4507
 
  (if (endp scgs)
4508
 
      nil
4509
 
    (let ((scg (car scgs)))
4510
 
      ;; to maintain the sortedness of the slots in the array, we loop through
4511
 
      ;; and build our lists on the way back.
4512
 
      (organize-scgs-by-preds1 (cdr scgs) array)
4513
 
      (loop for i in (scg-predecessors scg)
4514
 
            do (setf (aref array i)
4515
 
                     (cons scg (aref array i)))))))
4516
 
 
4517
 
(defun-raw organize-scgs-by-preds (scgs numsites)
4518
 
  (let ((array (make-array numsites :initial-element nil :element-type 'list)))
4519
 
    (organize-scgs-by-preds1 scgs array)
4520
 
    array))
4521
 
 
4522
 
(defun-raw union-scgs (scg-array indices)
4523
 
  (loop for i in indices
4524
 
        append (aref scg-array i) into union
4525
 
        finally (return (list-to-sorted-set union #'< :key #'scg-num))))
4526
 
        
4527
 
(defun-raw copy-scgs (scgs)
4528
 
  (loop for scg in scgs
4529
 
        collect (make-scg :graph (scg-graph scg)
4530
 
                          :num (scg-num scg)
4531
 
                          :paths (scg-paths scg)
4532
 
                          :newest-paths (scg-newest-paths scg)
4533
 
                          :new-newest-paths (scg-new-newest-paths scg))))
4534
 
 
4535
 
(defun print-sct-loop-report (iteration comps state)
4536
 
  (ccg-io? performance nil state
4537
 
           (iteration comps)
4538
 
           (fms "Iteration: ~x0 Compositions: ~x1."
4539
 
                (list (cons #\0 iteration)
4540
 
                      (cons #\1 comps))
4541
 
                *standard-co*
4542
 
                state
4543
 
                nil)))
4544
 
 
4545
 
(defun-raw print-sct-total-report (success? comps graph-hash start-time state)
4546
 
  (mv-let
4547
 
   (col state)
4548
 
   (ccg-io? size-change nil (mv col state)
4549
 
            (success?)
4550
 
            (fmt "~%SCT has found ~#0~[no~/a~] counter-example to ~
4551
 
                  termination. "
4552
 
                 (list (cons #\0 (if success? 0 1)))
4553
 
                 *standard-co*
4554
 
                 state
4555
 
                 nil)
4556
 
            :default-bindings ((col 0)))
4557
 
   (mv-let
4558
 
    (col state)
4559
 
    (ccg-io? performance nil (mv col state)
4560
 
             (comps graph-hash start-time internal-time-units-per-second)
4561
 
             (fmt1 "In the process, ~x0 total ~#1~[compositions ~
4562
 
                    were~/composition was~] performed and ~x2 unique ~
4563
 
                    ~#3~[graphs were~/graph was~] created. Total time taken ~
4564
 
                    was ~x4 seconds.~|"
4565
 
                   (list (cons #\0 comps)
4566
 
                         (cons #\1 (if (= comps 1) 1 0))
4567
 
                         (cons #\2 (hash-table-count graph-hash))
4568
 
                         (cons #\3 (if (= (hash-table-count graph-hash) 1)
4569
 
                                       1 0))
4570
 
                         (cons #\4 (/ (- (get-internal-run-time) start-time)
4571
 
                                      ;;internal-time-units-per-second
4572
 
                                      (coerce internal-time-units-per-second 'float))))
4573
 
                   col
4574
 
                   *standard-co*
4575
 
                   state
4576
 
                   nil)
4577
 
             :default-bindings ((col 0)))
4578
 
    (mv-let
4579
 
     (col state)
4580
 
     (ccg-io? size-change nil (mv col state)
4581
 
              ()
4582
 
              (fmt1 "~|" nil col *standard-co* state nil))
4583
 
     (declare (ignore col))
4584
 
     state))))
4585
 
 
4586
 
(defun-raw sct (ccmfs numsites state)
4587
 
  ;; ccmfs: a list of CCMFs to be analyzed
4588
 
  ;; numsites: the number of contexts over which the CCMFs range.
4589
 
  ;; state: the state
4590
 
  ;; 
4591
 
  ;; OUTPUT: an error triple whose value is a counter-example of the form (cons
4592
 
  ;; g p) where g is a ccmf-graph and p is the shortest self-looping path
4593
 
  ;; associated with g.
4594
 
 
4595
 
  ;; the basic algorithm for sct is fairly simple:
4596
 
  ;; * let S be the set of SCGs
4597
 
  ;; * repeat the following
4598
 
  ;;   * if there is a maximal ccmf without a > edge from some ccm to
4599
 
  ;;     itself, return the counter-example associated with that ccmf.
4600
 
  ;;   * let S' be S unioned with the result of composing every pair
4601
 
  ;;     <s,s'> in SxS such that the lastsite of s is the firstsite of s'.
4602
 
  ;;   * if S' = S, return nil
4603
 
  ;;   * set S <- S'
4604
 
  ;;
4605
 
  ;; however, this is inefficient, due to duplicate SCGs and the associativity
4606
 
  ;; of composition. Therefore, we do the following.
4607
 
 
4608
 
  (let ((graph-hash (make-hash-table :test #-gcl 'equalp #+gcl 'equal))
4609
 
        (start-time (get-internal-run-time)))
4610
 
    ;; first, we create the scgs, putting them in the graph-hash
4611
 
    (mv-let
4612
 
     (i newest)
4613
 
     (ccmfs-to-scgs ccmfs graph-hash)
4614
 
     (progn
4615
 
       ;;(format t "~&i: ~A~%newest: ~A~%" i newest)
4616
 
       ;; we check if any of the new scgs are counter-examples to termination.
4617
 
       (loop
4618
 
        for scg in newest
4619
 
        for nnp = (scg-new-newest-paths scg)
4620
 
        when (scg-counter-example? scg nnp)
4621
 
        do (return-from sct (value (cons (scg-graph scg)
4622
 
                                         (flatten-scg-path
4623
 
                                          (shortest-self-loop nnp nil))))))
4624
 
       ;; we age the scgs.
4625
 
       (age-scgs newest)
4626
 
       ;; the main loop:
4627
 
       (loop
4628
 
        with total-comps = 0
4629
 
        with generators = (organize-scgs-by-preds (copy-scgs newest) numsites)
4630
 
        until (endp newest)
4631
 
        for iteration from 0
4632
 
        for new-newest = nil
4633
 
        for comps = 0
4634
 
        ;;do (print iteration)
4635
 
        ;; for every scg, g, to be processed
4636
 
        do (loop
4637
 
            for g in newest
4638
 
            ;; all the ends of the pathst associated with g:
4639
 
            for gsucc = (scg-successors g)
4640
 
            do (loop
4641
 
                ;; for each generator that starts at a context where g ends,
4642
 
                for h in (union-scgs generators gsucc)
4643
 
                ;; compose them together, checking for counter-examples along
4644
 
                ;; the way
4645
 
                do (mv-let (counter-example? ni gh)
4646
 
                           (compose-scgs g h i graph-hash)
4647
 
                           (progn
4648
 
                             (incf comps)
4649
 
                             (incf total-comps)
4650
 
                             (setf i ni)
4651
 
                             ;; if we've found it, print out the report and
4652
 
                             ;; return the counter-example.
4653
 
                             (cond (counter-example?
4654
 
                                    (pprogn
4655
 
                                     (increment-timer 'other-time state)
4656
 
                                     (print-sct-loop-report iteration comps
4657
 
                                                            state)
4658
 
                                     (print-sct-total-report nil
4659
 
                                                             total-comps
4660
 
                                                             graph-hash
4661
 
                                                             start-time
4662
 
                                                             state)
4663
 
                                     (increment-timer 'print-time state)
4664
 
                                     (return-from sct (value gh))))
4665
 
                                   ;; otherwise, if gh is new and different, we
4666
 
                                   ;; add it to our new-newest set.
4667
 
                                   (gh
4668
 
                                    (setf new-newest
4669
 
                                          (cons gh new-newest))))))))
4670
 
        ;; we age all of our SCGs.
4671
 
        do (age-scgs (list-to-sorted-set (append newest
4672
 
                                                 (copy-list new-newest))
4673
 
                                         #'< :key #'scg-num))
4674
 
        ;; new-newest is the new newest (hence the name).
4675
 
        do (setf newest new-newest)
4676
 
        ;; print the loop report.
4677
 
        do (pprogn
4678
 
            (increment-timer 'other-time state)
4679
 
            (print-sct-loop-report iteration comps state)
4680
 
            (increment-timer 'print-time state))
4681
 
        ;; if we never find a counter-example, print out the report and return
4682
 
        ;; nil.
4683
 
        finally (pprogn
4684
 
                 (increment-timer 'other-time state)
4685
 
                 (print-sct-total-report t total-comps graph-hash start-time state)
4686
 
                 (increment-timer 'print-time state)
4687
 
                 (return (value nil))))))))
4688
 
 
4689
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4690
 
;;; the rest of the code connects our termination analysis with ACL2's ;;;
4691
 
;;; function admission process.                                        ;;;
4692
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4693
 
 
4694
 
(defun-raw find-funct (fn functs)
4695
 
  (cond ((endp functs)
4696
 
         (make-funct :fn fn))
4697
 
        ((eq fn (funct-fn (car functs)))
4698
 
         (car functs))
4699
 
        (t
4700
 
         (find-funct fn (cdr functs)))))
4701
 
 
4702
 
(defun-raw t-machine-to-contexts (t-machine parent-funct functs)
4703
 
  (if (endp t-machine)
4704
 
      nil
4705
 
    (let* ((tac (car t-machine))
4706
 
           (call (access tests-and-call tac :call)))
4707
 
      (cons (make-context :ruler (access tests-and-call tac :tests)
4708
 
                          :call call
4709
 
                          :parent-funct parent-funct
4710
 
                          :call-funct (find-funct (ffn-symb call) functs))
4711
 
            (t-machine-to-contexts (cdr t-machine) parent-funct functs)))))
4712
 
 
4713
 
(defun-raw t-machines-to-contexts1 (t-machines functs all-functs)
4714
 
  (if (endp t-machines)
4715
 
      nil
4716
 
    (cons (t-machine-to-contexts (car t-machines)
4717
 
                                 (car functs)
4718
 
                                 all-functs)
4719
 
          (t-machines-to-contexts1 (cdr t-machines)
4720
 
                                   (cdr functs)
4721
 
                                   all-functs))))
4722
 
 
4723
 
(defun-raw t-machines-to-contexts (t-machines functs)
4724
 
  (t-machines-to-contexts1 t-machines functs functs))
4725
 
 
4726
 
(defun-raw make-funct-structs (names arglists)
4727
 
  (if (endp names)
4728
 
      nil
4729
 
    (cons (make-funct :fn (car names)
4730
 
                      :formals (car arglists))
4731
 
          (make-funct-structs (cdr names) (cdr arglists)))))
4732
 
 
4733
 
(defun ccg-measures-declared (measures)
4734
 
  ;;; tells us whether the user declared any measures
4735
 
  (and (consp measures)
4736
 
       (or (not (equal (car measures) *0*))
4737
 
       (ccg-measures-declared (cdr measures)))))
4738
 
 
4739
 
(defun-raw context-array (contexts)
4740
 
  ;; turns a list of lists of contexts into an array and fixes the
4741
 
  ;; context-num field of each context to be its index in the array.
4742
 
  (let ((carray (coerce (loop for cs in contexts
4743
 
                              append cs)
4744
 
                        'vector)))
4745
 
    (loop for i from 0 below (length carray)
4746
 
          do (setf (context-num (aref carray i))
4747
 
                   (list i)))
4748
 
    carray))
4749
 
 
4750
 
(defun-raw accg-scp-list (lst proved unproved)
4751
 
  ;; given a list of accgs, lst, performs scp on a cleaned version of the accg,
4752
 
  ;; putting the cleaned accg into proved if scp determines the accg is
4753
 
  ;; terminating or the original accg into unproved if it is not proven
4754
 
  ;; terminating.
4755
 
  (if (endp lst)
4756
 
      (mv proved unproved)
4757
 
    (let* ((accg (cln-accg (copy-accg (car lst)))))
4758
 
      (cond ((scp (copy-accg accg))
4759
 
             (accg-scp-list (cdr lst)
4760
 
                            (cons accg proved)
4761
 
                            unproved))
4762
 
            (t
4763
 
             (accg-scp-list (cdr lst) proved (cons (car lst) unproved)))))))
4764
 
 
4765
 
(defun-raw accg-sct-list1 (lst i n proved unproved ces state)
4766
 
  ;; given a list of accgs, lst, performs sct on a cleaned version of each
4767
 
  ;; accg, putting the cleaned into proved if sct determines the accg is
4768
 
  ;; terminating or the original accg into unproved if it is not proven
4769
 
  ;; terminating.
4770
 
  (if (endp lst)
4771
 
      (pprogn
4772
 
       (let ((plen (len proved)))
4773
 
         (ccg-io? basics nil state
4774
 
                  (plen unproved)
4775
 
                  (fms "Size-change analysis has proven ~x0 out of ~x1 SCCs of ~
4776
 
                       the CCG terminating.~|"
4777
 
                       `((#\0 . ,plen)
4778
 
                         (#\1 . ,(+ plen (len unproved))))
4779
 
                       *standard-co*
4780
 
                       state
4781
 
                       nil)))
4782
 
       (value (list* proved unproved ces)))
4783
 
    (pprogn
4784
 
     (increment-timer 'other-time state)
4785
 
     (ccg-io? size-change nil state
4786
 
              ()
4787
 
              (fms "We now begin size change analysis on the ~n0 SCC out of ~
4788
 
                    ~n1."
4789
 
                   (list (cons #\0 `(,i))
4790
 
                         (cons #\1 n))
4791
 
                   *standard-co*
4792
 
                   state
4793
 
                   nil))
4794
 
     (increment-timer 'print-time state)
4795
 
     (let* ((accg (cln-accg (copy-accg (car lst)))))
4796
 
       (if (null accg)
4797
 
           ;; this should no longer happen because cln-accg no
4798
 
           ;; longer returns nil if there are empty ccmfs.
4799
 
           (pprogn
4800
 
            (increment-timer 'other-time state)
4801
 
            (ccg-io? size-change nil state
4802
 
                     ()
4803
 
                     (fms "A trivial analysis has revealed that this SCC is ~
4804
 
                           potentially non-terminating. We will set it aside ~
4805
 
                           for further refinement.~|" 
4806
 
                          nil *standard-co* state nil))
4807
 
            (increment-timer 'print-time state)
4808
 
            (accg-sct-list1 (cdr lst) (1+ i) n proved (cons (car lst) unproved)
4809
 
                            (cons nil ces) state))
4810
 
         (er-let*
4811
 
          ((ce (sct (accg-ccmfs accg) (array-dimension accg 0) state)))
4812
 
          (if (null ce)
4813
 
              (pprogn
4814
 
               (increment-timer 'other-time state)
4815
 
               (ccg-io? size-change nil state
4816
 
                        ()
4817
 
                        (fms "We have shown this SCC to be terminating, so we ~
4818
 
                              do not need to refine it any further.~|"
4819
 
                             nil *standard-co* state nil))
4820
 
               (increment-timer 'print-time state)
4821
 
               (accg-sct-list1 (cdr lst)
4822
 
                               (1+ i)
4823
 
                               n
4824
 
                               (cons accg proved)
4825
 
                               unproved
4826
 
                               ces
4827
 
                               state))
4828
 
            (pprogn
4829
 
             (increment-timer 'other-time state)
4830
 
             (ccg-io? size-change nil state
4831
 
                      ()
4832
 
                      (fms "This SCC is potentially non-terminating. We will ~
4833
 
                            set it aside for further refinement.~|"
4834
 
                           nil *standard-co* state nil))
4835
 
             (increment-timer 'print-time state)
4836
 
             (accg-sct-list1 (cdr lst)
4837
 
                             (1+ i)
4838
 
                             n
4839
 
                             proved
4840
 
                             (cons (car lst) unproved)
4841
 
                             (cons ce ces)
4842
 
                             state)))))))))
4843
 
 
4844
 
(defun-raw accg-sct-list (lst proved unproved ces state)
4845
 
  (accg-sct-list1 lst 1 (len lst) proved unproved ces state))
4846
 
 
4847
 
(defun ccg-counter-example-fn-name1 (char-lst pkg i wrld)
4848
 
  (declare (xargs :guard (and (standard-char-listp char-lst)
4849
 
                              (stringp pkg)
4850
 
                              (natp i)
4851
 
                              (plist-worldp wrld))))
4852
 
  (let ((name (intern$ (coerce (append char-lst
4853
 
                                       `(#\_)
4854
 
                                       (explode-nonnegative-integer i 10 nil))
4855
 
                               'string)
4856
 
                       pkg)))
4857
 
    (cond ((new-namep name wrld) (mv name i))
4858
 
          (t (ccg-counter-example-fn-name1 char-lst pkg (1+ i) wrld)))))
4859
 
 
4860
 
(defun ccg-counter-example-fn-name (root i wrld)
4861
 
  (declare (xargs :guard (and (symbolp root)
4862
 
                              (plist-worldp wrld)
4863
 
                              (natp i))))
4864
 
  (ccg-counter-example-fn-name1 (coerce (symbol-name root) 'list)
4865
 
                                (symbol-package-name root)
4866
 
                                i
4867
 
                                wrld))
4868
 
 
4869
 
(defun assoc-set-eq (key value alist)
4870
 
  (declare (xargs :guard (and (symbolp key)
4871
 
                              (alistp alist))))
4872
 
  (cond ((endp alist)
4873
 
         (acons key value alist))
4874
 
        ((eq key (caar alist))
4875
 
         (acons key value (cdr alist)))
4876
 
        (t
4877
 
         (assoc-set-eq key value (cdr alist)))))
4878
 
 
4879
 
(defun assoc-eq-value (key default alist)
4880
 
  (declare (xargs :guard (and (symbolp key)
4881
 
                              (alistp alist))))
4882
 
  (let ((pair (assoc-eq key alist)))
4883
 
    (if (consp pair)
4884
 
        (cdr pair)
4885
 
      default)))
4886
 
 
4887
 
(defun-raw aref-lst (array lst)
4888
 
  (mapcar #'(lambda (x) (aref array x)) lst))
4889
 
 
4890
 
(defun-raw alist-add-eq (alist key val)
4891
 
  ;; given an alist whose values are lists, returns the alist
4892
 
  ;; resulting from adding val to the list that is the value
4893
 
  ;; corresponding to the key key.
4894
 
  (cond ((endp alist)
4895
 
         (acons key (list val) nil))
4896
 
        ((eq (caar alist) key)
4897
 
         (acons key (cons val (cdar alist)) (cdr alist)))
4898
 
        (t
4899
 
         (cons (car alist) (alist-add-eq (cdr alist) key val)))))
4900
 
 
4901
 
(defun-raw order-names-arglists (names arglists rv-alist)
4902
 
  ;; when determining the minimal set of formals necessary to prove
4903
 
  ;; termination, we do a simple search of all the subsets of
4904
 
  ;; variables. to speed this up, we create a list indicating the
4905
 
  ;; order that we add the variables. this list is ordered by number
4906
 
  ;; of formals first, formal order second, and by function last. so,
4907
 
  ;; if we have function f with formals (x y) and function g with
4908
 
  ;; formals (a b), then the order would be ((f x) (g a) (f y) (g
4909
 
  ;; b)). So, the sets we would try, in the order we try them, are as
4910
 
  ;; follows:
4911
 
  ;;
4912
 
  ;; 1. {(f x)}
4913
 
  ;; 2. {(g a)}
4914
 
  ;; 3. {(f y)}
4915
 
  ;; 4. {(g b)}
4916
 
  ;; 5. {(f x) (g a)}
4917
 
  ;; 6. {(f x) (f y)}
4918
 
  ;; 7. {(f x) (g b)}
4919
 
  ;; 8. {(g a) (f y)}
4920
 
  ;; 9. {(g a) (g b)}
4921
 
  ;; 10. {(f y) (g b)}
4922
 
  ;; 11. {(f x) (g a) (f y)}
4923
 
  ;; 12. {(f x) (g a) (g b)}
4924
 
  ;; 13. {(f x) (f y) (g b)}
4925
 
  ;; 14. {(g a) (f y) (g b)}
4926
 
  ;; 15. {(f x) (g a) (f y) (g b)}
4927
 
  ;;
4928
 
  ;; the idea is that most functions require only a small subset of
4929
 
  ;; the actuals to prove termination.
4930
 
 
4931
 
  (let* ((na-arrays (coerce (mapcar (lambda (x y) (coerce (cons x y) 'vector))
4932
 
                                    names arglists)
4933
 
                            'vector))
4934
 
         (maxsize (loop for v across na-arrays maximize (array-dimension v 0))))
4935
 
    (loop for i from 1 below maxsize
4936
 
          append (loop for array across na-arrays
4937
 
                       when (and (< i (array-dimension array 0))
4938
 
                                 (not (member-eq (aref array i)
4939
 
                                                 (cdr (assoc (aref array 0) rv-alist)))))
4940
 
                         collect (cons (aref array 0)
4941
 
                                       (aref array i))))))
4942
 
 
4943
 
(defmacro-raw ccmf-tail-fn (ccmf contexts)
4944
 
  `(context-fn (aref ,contexts
4945
 
                     (car (ccmf-fc-num ,ccmf)))))
4946
 
 
4947
 
(defmacro-raw ccmf-head-fn (ccmf contexts)
4948
 
  `(context-fn (aref ,contexts
4949
 
                     (car (ccmf-lc-num ,ccmf)))))
4950
 
 
4951
 
(defun-raw restrict-ccmf (ccmf ccmr1 ccmr2)
4952
 
  ;; the dual to ccmf-remove-ccms, in that it only retains the ccms
4953
 
  ;; indicated by ccmr1 and ccmr2, but is not destructive.
4954
 
  (let* ((graph (ccmf-graph ccmf))
4955
 
         (n (array-dimension graph 0))
4956
 
         (ngraph (make-array n
4957
 
                             :element-type 'ccmf-node
4958
 
                             :initial-element (make-ccmf-node)))
4959
 
         (nccmf (make-ccmf :firstsite (ccmf-firstsite ccmf)
4960
 
                           :lastsite (ccmf-lastsite ccmf)
4961
 
                           :fc-num (ccmf-fc-num ccmf)
4962
 
                           :lc-num (ccmf-lc-num ccmf)
4963
 
                           :in-sizes (ccmf-in-sizes ccmf)
4964
 
                           :out-sizes (ccmf-out-sizes ccmf)
4965
 
                           :graph ngraph))
4966
 
         (f (lambda (x) (aref ccmr2 x))))
4967
 
    (loop for i from 0 below n
4968
 
          for node = (aref graph i)
4969
 
          if (aref ccmr1 i)
4970
 
            do (setf (aref ngraph i)
4971
 
                     (make-ccmf-node
4972
 
                      :>-edges (remove-if-not f (ccmf-node->-edges node))
4973
 
                      :>=-edges (remove-if-not f (ccmf-node->=-edges node))))
4974
 
          else
4975
 
            do (setf (aref ngraph i) (make-ccmf-node)))
4976
 
    (loop for node across ngraph
4977
 
          when (or (consp (ccmf-node->-edges node))
4978
 
                   (consp (ccmf-node->=-edges node)))
4979
 
            return nccmf
4980
 
          finally (return nil))))
4981
 
 
4982
 
(defun-raw can-solve-restricted-accgs? (accgs ccmrs scp? state)
4983
 
  ;; this is the workhorse of our controller-alist search. given ccm
4984
 
  ;; restrictions (see create-ccm-restrictions), ccmrs, and a flag to
4985
 
  ;; indicate whether the original accg was solved using scp or sct,
4986
 
  ;; we restrict the accg and attempt to reprove termination.
4987
 
  (loop for accg in accgs
4988
 
        for n = (array-dimension accg 0)
4989
 
        for naccg = (make-array n)
4990
 
        ;; first, initiate the naccg nodes
4991
 
        do (loop for i from 0 below n
4992
 
                 for node = (aref accg i)
4993
 
                 do (setf (aref naccg i)
4994
 
                          (make-accg-node 
4995
 
                           :context (accg-node-context node)
4996
 
                           :num i)))
4997
 
        ;; next, set the ccmfs for those nodes to be the restricted
4998
 
        ;; version of the ccmfs of the original accg node.
4999
 
        do (loop
5000
 
            for i from 0 below n
5001
 
            for node = (aref accg i)
5002
 
            for nnode1 = (aref naccg i)
5003
 
            for ccmr1 = (aref ccmrs (car (accg-node-context-num node)))
5004
 
            do (loop
5005
 
                for edge in (accg-node-fwd-edges node)
5006
 
                for ccmf = (accg-edge-ccmf edge)
5007
 
                for ccmr2 = (aref ccmrs (accg-edge-head edge))
5008
 
                for nnode2 = (aref naccg (accg-edge-head edge))
5009
 
                for nccmf = (restrict-ccmf ccmf ccmr1 ccmr2)
5010
 
                if nccmf
5011
 
                  do (let ((nedge (make-accg-edge :head (accg-edge-head edge)
5012
 
                                                  :tail (accg-edge-tail edge)
5013
 
                                                  :ccmf nccmf)))
5014
 
                       (setf (accg-node-fwd-edges nnode1)
5015
 
                             (cons nedge (accg-node-fwd-edges nnode1)))
5016
 
                       (setf (accg-node-bwd-edges nnode2)
5017
 
                             (cons nedge (accg-node-bwd-edges nnode2))))
5018
 
                else do (return-from can-solve-restricted-accgs? (value nil))))
5019
 
        ;; finally, run scp or sct as indicated. if we fail, then we
5020
 
        ;; immediately return nil.
5021
 
         do (if scp?
5022
 
                (unless (scp (cln-accg naccg)) (return (value nil)))
5023
 
              (er-let*
5024
 
               ((caccg (value (cln-accg naccg)))
5025
 
                (ce (if (null caccg)
5026
 
                        (value t)
5027
 
                      (sct (accg-ccmfs caccg) n state))))
5028
 
               (unless (null ce) (return (value nil)))))
5029
 
        finally (return (value t))))
5030
 
                 
5031
 
(defun-raw create-ccm-restrictions (contexts av-alist)
5032
 
  ;; creates "ccm restrictions", which is an array of boolean arrays
5033
 
  ;; such that element i j is t iff we want to keep ccm j from context
5034
 
  ;; i. which ccms to keep is determined by av-alist, which tells us
5035
 
  ;; which variables from each function we are using for the current
5036
 
  ;; restriction. 
5037
 
  (loop with n = (array-dimension contexts 0)
5038
 
        with ccmrs = (make-array n)
5039
 
        for i from 0 below n
5040
 
        for context = (aref contexts i)
5041
 
        for ccms = (context-ccms context)
5042
 
        ;; vars are the variables we are allowed to use for this context.
5043
 
        for vars = (cdr (assoc (context-fn context) av-alist))
5044
 
        for m = (array-dimension ccms 0)
5045
 
        for ccmri = (make-array m
5046
 
                                :element-type 'boolean
5047
 
                                :initial-element nil)
5048
 
        do (setf (aref ccmrs i) ccmri)
5049
 
        do (loop for j from 0 below m
5050
 
                 do (setf (aref ccmri j)
5051
 
                          (subsetp (all-vars (aref ccms j))
5052
 
                                   vars)))
5053
 
        finally (return ccmrs)))
5054
 
 
5055
 
(defun-raw ruler-vars (names contexts)
5056
 
  ;; returns an alist mapping fucntion names to the variables used in
5057
 
  ;; the rulers of the contexts of that function.
5058
 
  (loop with rv-alist = (pairlis$ names nil)
5059
 
        for context across contexts
5060
 
        for fn = (context-fn context)
5061
 
        for vars = (all-vars1-lst (context-ruler context) nil)
5062
 
        for pair = (assoc fn rv-alist)
5063
 
        do (setf (cdr pair) (union-eq vars (cdr pair)))
5064
 
        finally (return rv-alist)))
5065
 
 
5066
 
(defun-raw cgma-aux (nalist proved-scp proved-sct contexts av-alist i state)
5067
 
  ;; helper function for ccg-generate-measure-alist. nalist is the
5068
 
  ;; list of function-formal pairs as generated by
5069
 
  ;; order-names-arglists. proved-scp is a list of accgs proved
5070
 
  ;; terminating by the scp algorithm, and proved-sct is a list of
5071
 
  ;; accgs proved terminating by the sct algorithm. contexts is the
5072
 
  ;; array of contexts. av-alist is an alist mapping each function
5073
 
  ;; name to the formals that we want enabled, and i is the number of
5074
 
  ;; formals we want to enable. returns the first av-alist
5075
 
  ;; for which we can prove termination, or nil if we cannot
5076
 
  ;; prove termination.
5077
 
  (cond ((zp i) ;; if we don't want to add any more variables, try to
5078
 
                ;; prove termination of the restricted accgs.
5079
 
         (let ((ccmrs (create-ccm-restrictions contexts av-alist)))
5080
 
           (er-let*
5081
 
            ((p1 (can-solve-restricted-accgs? proved-scp ccmrs t state))
5082
 
             (p2 (if p1
5083
 
                     (can-solve-restricted-accgs? proved-sct ccmrs nil state)
5084
 
                   (value nil))))
5085
 
            (if p2
5086
 
                (value av-alist)
5087
 
              (value nil)))))
5088
 
        ((endp nalist) ;; if we reach the end of the list before i
5089
 
                       ;; reaches 0, just return nil.
5090
 
         (value nil))
5091
 
        (t ;; otherwise, we proceed in two different ways:
5092
 
         (er-let*
5093
 
          ;; first, we enable the first formal in nalist and
5094
 
          ;; proceed to enable i-1 of the rest of the formals.
5095
 
          ((nav-alist (cgma-aux (cdr nalist) proved-scp proved-sct contexts
5096
 
                                (alist-add-eq av-alist
5097
 
                                              (caar nalist)
5098
 
                                              (cdar nalist))
5099
 
                                (1- i)
5100
 
                                state)))
5101
 
          ;; if we were successful, report our success.
5102
 
          (if nav-alist
5103
 
              (value nav-alist)
5104
 
            ;; otherwise, try leaving the current variable out
5105
 
            ;; and enable i of the remaining variables.
5106
 
            (cgma-aux (cdr nalist) proved-scp proved-sct
5107
 
                      contexts av-alist i state))))))
5108
 
 
5109
 
(defun-raw ccg-generate-measure-alist1 (i nalist proved-scp proved-sct
5110
 
                                          contexts rv-alist state)
5111
 
  (er-let* ((av-alist (cgma-aux nalist proved-scp proved-sct
5112
 
                                contexts rv-alist i state)))
5113
 
           (if av-alist
5114
 
               (value (mapcar (lambda (x) (cons (car x) (cons :? (cdr x))))
5115
 
                              av-alist))
5116
 
             (ccg-generate-measure-alist1 (1+ i) nalist
5117
 
                                          proved-scp proved-sct
5118
 
                                          contexts rv-alist state))))
5119
 
 
5120
 
(defun-raw ccg-generate-measure-alist (proved-scp proved-sct names arglists
5121
 
                                                  contexts cpn state)
5122
 
  ;; generates a measure-alist designed to minimize the resulting
5123
 
  ;; controller-alist. we return the restricted set of the ccms
5124
 
  ;; necessary for proving termination with :CCG consed onto the
5125
 
  ;; front. the result is a "pseudo-measure" from which ACL2 can
5126
 
  ;; compute a safe controller alist. proved-scp and proved-sct are
5127
 
  ;; the accgs proved terminating using the scp or sct algorithm,
5128
 
  ;; respectively. names is the list of names of the functions, and
5129
 
  ;; arglists is the list of the arglists for each function. contexts
5130
 
  ;; is the array of contexts. cpn tells us whether or not we proved
5131
 
  ;; termination constructing contexts by node rather than by
5132
 
  ;; edge. This is important because, in order to construct a sound
5133
 
  ;; controller-alist we need to include all the variables in the
5134
 
  ;; context rulers if we could not prove termination using per-node
5135
 
  ;; contexts.
5136
 
  
5137
 
  ;; first, we construct an alist of the initially enabled formals
5138
 
  ;; based on cpn, and use it to make an ordered list of name-formal
5139
 
  ;; pairs.
5140
 
 
5141
 
  (let* ((rv-alist (if cpn (pairlis$ names nil) (ruler-vars names contexts)))
5142
 
         (nalist (order-names-arglists names arglists rv-alist)))
5143
 
    (ccg-generate-measure-alist1 0 nalist proved-scp proved-sct
5144
 
                                             contexts rv-alist state)))
5145
 
 
5146
 
 
5147
 
;;;;; ALL TERMINATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5148
 
 
5149
 
(defun-raw name-var-pairs1 (name arglist rst)
5150
 
  ;; name: the name of a function
5151
 
  ;; arglist: the arglist of the function whose name is name
5152
 
  ;; rst: the list to which to append the result
5153
 
  ;;
5154
 
  ;; OUTPUT: ((name . x) | x in arglist) appended to rst.
5155
 
 
5156
 
  (if (endp arglist)
5157
 
      rst
5158
 
    (acons name (car arglist)
5159
 
           (name-var-pairs1 name (cdr arglist) rst))))
5160
 
 
5161
 
(defun-raw name-var-pairs (functs rv-alist)
5162
 
  ;; functs: a list of structs of type funct.
5163
 
  ;; rv-alist: an alist mapping the names of the functions in functs
5164
 
  ;; to subsets of their formals. The idea is that these are
5165
 
  ;; restricted variables. That is, in the measured-subset analysis,
5166
 
  ;; all subsets must be supersets of the variables specified in
5167
 
  ;; rv-alist.
5168
 
  ;;
5169
 
  ;; OUTPUT: two lists of the form ((fn . x) ...) where fn is the name
5170
 
  ;; of a function in funct and x is a formal of that function. The
5171
 
  ;; first list is of these pairs that we may consider removing from
5172
 
  ;; the measured subset, and the second is a list of these pairs that
5173
 
  ;; we may *not* consider removing from the measured subset (as
5174
 
  ;; specified by rv-alist).
5175
 
  (if (endp functs)
5176
 
      (mv nil nil)
5177
 
    (mv-let
5178
 
     (free fixed)
5179
 
     (name-var-pairs (cdr functs) rv-alist)
5180
 
     (let* ((funct (car functs))
5181
 
            (fn (funct-fn funct))
5182
 
            (rv (cdr (assoc fn rv-alist))))
5183
 
       (mv (name-var-pairs1 fn
5184
 
                            (set-difference-eq (funct-formals funct) rv)
5185
 
                            free)
5186
 
           (name-var-pairs1 fn rv fixed))))))
5187
 
 
5188
 
(defun-raw get-ccm-vars1 (i ccms ccm-vars)
5189
 
  ;; i: integer such that 0 <= i < |ccms|.
5190
 
  ;; ccms: an array of calling context measures.
5191
 
  ;; ccm-vars: accumulator array such that ccm-vars[j] contains a list
5192
 
  ;; of all the variables in the expression ccms[j].
5193
 
  ;;
5194
 
  ;; OUTPUT: completed ccm-vars.
5195
 
  (cond ((< i 0)
5196
 
         ccm-vars)
5197
 
        (t
5198
 
         (setf (aref ccm-vars i)
5199
 
               (all-vars (aref ccms i)))
5200
 
         (get-ccm-vars1 (1- i) ccms ccm-vars))))
5201
 
 
5202
 
(defun-raw get-ccm-vars (ccms)
5203
 
  ;; ccms: an array of ccms.
5204
 
  ;;
5205
 
  ;; OUTPUT: an array, ccm-vars, such that ccm-vars[i] contains the
5206
 
  ;; list of variables in expression ccms[i] for all 0 <= i < |ccms|
5207
 
  (let ((len (array-dimension ccms 0)))
5208
 
    (get-ccm-vars1 (1- len) ccms (make-array len
5209
 
                                             :element-type 'list
5210
 
                                             :initial-element nil))))
5211
 
                    
5212
 
(defun-raw fn-ccm-vars-alist (functs)
5213
 
  (if (endp functs)
5214
 
      nil
5215
 
    (let ((funct (car functs)))
5216
 
      (acons (funct-fn funct) (get-ccm-vars (funct-ccms funct))
5217
 
             (fn-ccm-vars-alist (cdr functs))))))
5218
 
   
5219
 
(defun-raw gather-relevant-ccms1 (i var ccm-vars indices)
5220
 
  ;; i: an integer such that 0 <= i < |ccm-vars|. Should initially be |ccm-vars|-1.
5221
 
  ;; ccm-vars: an array of lists of integers.
5222
 
  ;; var: a variable
5223
 
  ;; indices: the accumulator; it is { k | i < k < |ccm-vars|
5224
 
  ;;   s.t. ccm-vars[k] contains var }. Should initially be nil.
5225
 
  ;;
5226
 
  ;; OUTPUT: { k | 0 <= k < |ccm-vars| s.t. ccm-vars[k] contains var }
5227
 
  (if (< i 0)
5228
 
      indices
5229
 
    (gather-relevant-ccms1 (1- i) var ccm-vars
5230
 
                           (if (member-eq var (aref ccm-vars i))
5231
 
                               (cons i indices)
5232
 
                             indices))))
5233
 
      
5234
 
(defun-raw gather-relevant-ccms (var ccm-vars)
5235
 
  ;; ccm-vars: an array of lists of variables
5236
 
  ;; var: a variable
5237
 
  ;;
5238
 
  ;; OUTPUT: the list of the indices of the slots of ccm-vars that
5239
 
  ;; contain var.
5240
 
  (gather-relevant-ccms1 (1- (array-dimension ccm-vars 0)) var ccm-vars nil))
5241
 
 
5242
 
(defun-raw gather-all-relevant-ccms1 (avars alist)
5243
 
  ;; functs: a list of structures of type funct
5244
 
  ;;
5245
 
  ;; OUTPUT: a mapping of sorts from formals to the ccms containing
5246
 
  ;; those formals. See the note on the output of
5247
 
  ;; gather-all-relevant-ccms-for-funct.
5248
 
  (if (endp avars)
5249
 
      nil
5250
 
    (let* ((avar (car avars))
5251
 
           (fn (car avar))
5252
 
           (var (cdr avar)))
5253
 
    (cons (gather-relevant-ccms var (cdr (assoc fn alist)))
5254
 
          (gather-all-relevant-ccms1 (cdr avars) alist)))))
5255
 
 
5256
 
(defun-raw gather-all-relevant-ccms (avars functs)
5257
 
  (gather-all-relevant-ccms1 avars (fn-ccm-vars-alist functs)))
5258
 
 
5259
 
(defun set-difference-and-intersection (set1 set2)
5260
 
  (declare (xargs :guard (and (eqlable-listp set1)
5261
 
                              (eqlable-listp set2))))
5262
 
  ;; set1: an eqlable-listp.
5263
 
  ;; set2: an eqlable-listp
5264
 
  ;;
5265
 
  ;; OUTPUT: two lists. The first is the difference of set1 and set2,
5266
 
  ;; and the second is the intersection of set1 and set2.
5267
 
  (if (endp set1)
5268
 
      (mv nil nil)
5269
 
    (mv-let (difference intersection)
5270
 
            (set-difference-and-intersection (cdr set1) set2)
5271
 
            (if (member (car set1) set2)
5272
 
                (mv difference (cons (car set1) intersection))
5273
 
              (mv (cons (car set1) difference) intersection)))))
5274
 
 
5275
 
(defun-raw ccmf-remove-relevant-edges1 (i graph relevant-ccms1 relevant-ccms2
5276
 
                                          edges-alist)
5277
 
  ;; i: integer such that 0 <= i < |graph|.
5278
 
  ;; graph: a ccmf-graph.
5279
 
  ;; relevant-ccms1: an increasing list of integers, j, such that 0 <=
5280
 
  ;; j < |graph|. These are the ccms we are to virtually remove from
5281
 
  ;; the graph by removing all its outgoing edges.
5282
 
  ;; ASSUMPTION: relevant-ccms1 is in increasing order.
5283
 
  ;; relevant-ccms2: a list of natural numbers. These are the ccms we
5284
 
  ;; are to virtually remove from the target context of the graph by
5285
 
  ;; removing all of its incoming edges.
5286
 
  ;; edges-alist: the accumulator alist that maps each 0 <= j <
5287
 
  ;; |graph| to a cons of the >-edges and >=-edges removed from the
5288
 
  ;; graph, so we can put them back later.
5289
 
  ;;
5290
 
  ;; SIDE EFFECT: all edges to and from relevant ccms in the graph are
5291
 
  ;; removed.
5292
 
  ;;
5293
 
  ;; OUTPUT: the completed edges-alist.
5294
 
 
5295
 
  (cond ((<= (array-dimension graph 0) i)
5296
 
         edges-alist)
5297
 
        ((and (consp relevant-ccms1)
5298
 
              (= i (car relevant-ccms1)))
5299
 
         ;; if i is a member of relevant-ccms1, it is the first
5300
 
         ;; element because of our assumption that relevant-ccms1 is
5301
 
         ;; increasing. In this case we remove all the outgoing edges
5302
 
         ;; from graph[i].
5303
 
         (let* ((node (aref graph i))
5304
 
                (>-edges-i (ccmf-node->-edges node)) ;;get the >-edges
5305
 
                (>=-edges-i (ccmf-node->=-edges node))) ;; get the >=-edges
5306
 
           (setf (ccmf-node->-edges node) nil) ;; set the >-edges to nil
5307
 
           (setf (ccmf-node->=-edges node) nil) ;; set the >=-edges to nil
5308
 
           (ccmf-remove-relevant-edges1 (1+ i) graph
5309
 
                                        (cdr relevant-ccms1) relevant-ccms2
5310
 
                                        ;; add the removed edges (if
5311
 
                                        ;; any) to the accumulator:
5312
 
                                        (if (and (endp >-edges-i) (endp >=-edges-i))
5313
 
                                            edges-alist
5314
 
                                          (acons i (cons >-edges-i >=-edges-i) 
5315
 
                                                 edges-alist)))))
5316
 
        ((consp relevant-ccms2)
5317
 
         ;; if a non-nil relevant-ccms2 was supplied, we remove all
5318
 
         ;; the edges pointing from graph[i] to ccms specified by
5319
 
         ;; relevant-ccms2.
5320
 
         (let* ((node (aref graph i))
5321
 
                (>-edges-i (ccmf-node->-edges node))
5322
 
                (>=-edges-i (ccmf-node->=-edges node)))
5323
 
           (mv-let (>-diff >-intersect)
5324
 
                   (set-difference-and-intersection >-edges-i relevant-ccms2)
5325
 
                   (mv-let (>=-diff >=-intersect)
5326
 
                           (set-difference-and-intersection >=-edges-i relevant-ccms2)
5327
 
                           (progn
5328
 
                             ;; if we removed any edges, set the new
5329
 
                             ;; edge lists.
5330
 
                             (when (consp >-intersect)
5331
 
                               (setf (ccmf-node->-edges node) >-diff))
5332
 
                             (when (consp >=-intersect)
5333
 
                               (setf (ccmf-node->=-edges node) >=-diff))
5334
 
                             (ccmf-remove-relevant-edges1
5335
 
                              (1+ i) graph
5336
 
                              relevant-ccms1 relevant-ccms2
5337
 
                              ;; add the removed edges (if any) to the accumulator.
5338
 
                              (if (and (endp >-intersect) (endp >=-intersect))
5339
 
                                  edges-alist
5340
 
                                (acons i (cons >-intersect >=-intersect)
5341
 
                                       edges-alist))))))))
5342
 
        (t
5343
 
         ;; if the current index is not in relevant-ccms1 and
5344
 
         ;; relevant-ccms2 is empty, there is nothing to do, so we
5345
 
         ;; move on to the next index.
5346
 
         (ccmf-remove-relevant-edges1 (1+ i)
5347
 
                                      graph
5348
 
                                      relevant-ccms1
5349
 
                                      relevant-ccms2
5350
 
                                      edges-alist))))
5351
 
 
5352
 
(defun-raw ccmf-remove-relevant-edges (ccmf relevant-ccms1 relevant-ccms2)
5353
 
  ;; ccmf: a struct of type ccmf.
5354
 
  ;; relevant-ccms1: an increasing list of integers, j, such that 0 <=
5355
 
  ;; j < |graph|. These are the ccms we are to virtually remove from
5356
 
  ;; the graph by removing all its outgoing edges.
5357
 
  ;; ASSUMPTION: relevant-ccms1 is in increasing order.
5358
 
  ;; relevant-ccms2: a list of natural numbers. These are the ccms we
5359
 
  ;; are to virtually remove from the target context of the graph by
5360
 
  ;; removing all of its incoming edges.
5361
 
  ;;
5362
 
  ;; SIDE EFFECT: all edges to and from relevant ccms in the ccmf are
5363
 
  ;; removed.
5364
 
  ;;
5365
 
  ;; OUTPUT: the ccmf consed to an alist that maps each 0 <= j <
5366
 
  ;; |graph| to a cons of the >-edges and >=-edges removed from the
5367
 
  ;; graph, so we can put them back later.
5368
 
 
5369
 
  (let ((graph (ccmf-graph ccmf)))
5370
 
    (cons ccmf
5371
 
          (ccmf-remove-relevant-edges1 0
5372
 
                                       graph
5373
 
                                       relevant-ccms1 relevant-ccms2
5374
 
                                       nil))))
5375
 
 
5376
 
(defun-raw ccmf-remove-relevant-edges-lst (ccmfs contexts fn relevant-ccms acc)
5377
 
  ;; ccmfs: a list of structs of type ccmf which should be the ccmfs for fn.
5378
 
  ;; contexts: an array of contexts.
5379
 
  ;; fn: a function name
5380
 
  ;; relevant-ccms: a list of indices of the ccms of fn. Indicates
5381
 
  ;; which ccms to remove.
5382
 
  ;; acc: the accumulator. This accumulates the removed edge
5383
 
  ;; information so we can restore the ccmfs when we are done.
5384
 
  ;;
5385
 
  ;; SIDE EFFECT: all edges to and from relevant ccms in the ccmfs of
5386
 
  ;; are removed.
5387
 
  ;;
5388
 
  ;; OUTPUT: the completed accumulator. It is an alist mapping the
5389
 
  ;; ccmfs to an alist mapping the indicices of the source ccms of the
5390
 
  ;; ccmf to a cons of the >-edges and >=-edges that were removed.
5391
 
 
5392
 
  (if (endp ccmfs)
5393
 
      acc
5394
 
    (let* ((ccmf (car ccmfs))
5395
 
           (tcontext (aref contexts (car (ccmf-fc-num ccmf))))
5396
 
           (relevant-ccms1 (if (eq (context-fn tcontext) fn) relevant-ccms nil))
5397
 
           (hcontext (aref contexts (car (ccmf-lc-num ccmf))))
5398
 
           (relevant-ccms2 (if (eq (context-fn hcontext) fn) relevant-ccms nil)))
5399
 
      (ccmf-remove-relevant-edges-lst
5400
 
       (cdr ccmfs)
5401
 
       contexts
5402
 
       fn
5403
 
       relevant-ccms
5404
 
       (cons (ccmf-remove-relevant-edges ccmf relevant-ccms1 relevant-ccms2)
5405
 
             acc)))))
5406
 
 
5407
 
(defun-raw accg-remove-relevant-ccmf-edges1 (i accg contexts fn relevant-ccms acc)
5408
 
  ;; i: natural number such that 0 <= i < |accg|.
5409
 
  ;; accg: an array of structs of type accg-node.
5410
 
  ;; contexts: an array of contexts.
5411
 
  ;; fn: a function name.
5412
 
  ;; relevant-ccms: the ccms to remove from all ccmfs corresponding to fn.
5413
 
  ;; acc: the accumulator. 
5414
 
  ;; 
5415
 
  ;; SIDE EFFECT: all edges to and from relevant ccms in the ccmfs of
5416
 
  ;; the accg are removed.
5417
 
  ;;
5418
 
  ;; OUTPUT: an alist mapping the ccmfs to an alist mapping the
5419
 
  ;; indicices of the source ccms of the ccmf to a cons of the >-edges
5420
 
  ;; and >=-edges that were removed.
5421
 
  (if (< i 0)
5422
 
      acc
5423
 
    (let* ((node (aref accg i)))
5424
 
      (accg-remove-relevant-ccmf-edges1
5425
 
       (1- i)
5426
 
       accg
5427
 
       contexts
5428
 
       fn
5429
 
       relevant-ccms
5430
 
       (if (eq (accg-node-fn node) fn)
5431
 
           (let ((pred (lambda (edge)
5432
 
                         (equal (accg-node-fn (aref accg (accg-edge-tail edge)))
5433
 
                                fn))))
5434
 
             (ccmf-remove-relevant-edges-lst
5435
 
              (append (mapcar #'accg-edge-ccmf
5436
 
                              (accg-node-fwd-edges node))
5437
 
                      ;; remove all edges from contexts of fn to avoid
5438
 
                      ;; redundant work.
5439
 
                      (mapcar #'accg-edge-ccmf
5440
 
                              (remove-if pred 
5441
 
                                         (accg-node-bwd-edges node))))
5442
 
              contexts
5443
 
              fn
5444
 
              relevant-ccms
5445
 
              acc))
5446
 
         acc)))))
5447
 
 
5448
 
(defun-raw accg-remove-relevant-ccmf-edges (accg contexts fn relevant-ccms)
5449
 
  
5450
 
  ;; accg: an array of structs of type accg-node.
5451
 
  ;; contexts: an array of contexts.
5452
 
  ;; fn: a function name.
5453
 
  ;; relevant-ccms: the ccms to remove from all ccmfs corresponding to fn.
5454
 
  ;; 
5455
 
  ;; SIDE EFFECT: all edges to and from relevant ccms in the ccmfs of
5456
 
  ;; the accg are removed.
5457
 
  ;;
5458
 
  ;; OUTPUT: an alist mapping the ccmfs to an alist mapping the
5459
 
  ;; indicices of the source ccms of the ccmf to a cons of the >-edges
5460
 
  ;; and >=-edges that were removed.
5461
 
  
5462
 
  (accg-remove-relevant-ccmf-edges1 (1- (array-dimension accg 0))
5463
 
                                    accg
5464
 
                                    contexts
5465
 
                                    fn
5466
 
                                    relevant-ccms
5467
 
                                    nil))
5468
 
 
5469
 
(defun-raw accg-remove-relevant-ccmf-edges-lst-tail (accgs contexts fn relevant-ccms acc)
5470
 
  ;; tail recursive implementation of accg-remove-relevant-ccmf-edges-lst
5471
 
 
5472
 
  (if (endp accgs)
5473
 
      acc
5474
 
    (accg-remove-relevant-ccmf-edges-lst-tail
5475
 
     (cdr accgs)
5476
 
     contexts
5477
 
     fn
5478
 
     relevant-ccms
5479
 
     (accg-remove-relevant-ccmf-edges1
5480
 
      (1- (array-dimension (car accgs) 0))
5481
 
      (car accgs)
5482
 
      contexts
5483
 
      fn
5484
 
      relevant-ccms
5485
 
      acc))))
5486
 
 
5487
 
(defun-raw accg-remove-relevant-ccmf-edges-lst (accgs contexts fn relevant-ccms)
5488
 
  ;; accgs: a list of accgs.
5489
 
  ;; contexts: an array of contexts
5490
 
  ;; fn: function name
5491
 
  ;; relevant-ccms: the ccms of fn to "remove" (ccms are kept, but all
5492
 
  ;; incoming and outgoing edges are removed).
5493
 
  ;;
5494
 
  ;; SIDE-EFFECT: all the incoming and outgoing edges of the indicated
5495
 
  ;; ccms of fn in the ccmfs of the accgs are removed.
5496
 
  ;;
5497
 
  ;; OUTPUT: an alist mapping the ccmfs to an alist mapping the
5498
 
  ;; indicices of the source ccms of the ccmf to a cons of the >-edges
5499
 
  ;; and >=-edges that were removed.
5500
 
  (accg-remove-relevant-ccmf-edges-lst-tail accgs contexts fn relevant-ccms nil))
5501
 
 
5502
 
(defun-raw restore-edges1 (ccmf alist)
5503
 
  ;; ccmf: a struct of type ccmf.
5504
 
  ;; alist: maps indices of the ccmf to the cons of the >-edges and
5505
 
  ;; >=-edges that should be added back to the ccmf.
5506
 
  ;; 
5507
 
  ;; SIDE-EFFECT: the edges indicated by the alist are added back to the ccmf.
5508
 
  ;;
5509
 
  ;; OUTPUT: nil.
5510
 
  (if (endp alist)
5511
 
      nil
5512
 
    (let* ((entry (car alist))
5513
 
           (i (car entry))
5514
 
           (>-edges (cadr entry))
5515
 
           (>=-edges (cddr entry))
5516
 
           (node (aref (ccmf-graph ccmf) i)))
5517
 
      (setf (ccmf-node->-edges node)
5518
 
            (merge 'list
5519
 
                   >-edges
5520
 
                   (ccmf-node->-edges node)
5521
 
                   #'<))
5522
 
      (setf (ccmf-node->=-edges node)
5523
 
            (merge 'list
5524
 
                   >=-edges
5525
 
                   (ccmf-node->=-edges node)
5526
 
                   #'<))
5527
 
      (restore-edges1 ccmf (cdr alist)))))
5528
 
 
5529
 
(defun-raw restore-edges (alist)
5530
 
  ;; alist: maps ccmfs to alists mapping indices of the ccmf to the
5531
 
  ;; cons of the >-edges and >=-edges that should be added back to the
5532
 
  ;; ccmf.
5533
 
  ;; 
5534
 
  ;; SIDE-EFFECT: the edges indicated by the alist are added back to
5535
 
  ;; their respective ccmfs.
5536
 
  ;;
5537
 
  ;; OUTPUT: nil.
5538
 
 
5539
 
  (if (endp alist)
5540
 
      nil
5541
 
    (progn
5542
 
      (restore-edges1 (caar alist) (cdar alist))
5543
 
      (restore-edges (cdr alist)))))
5544
 
  
5545
 
(defun-raw can-scp-lstp (accgs)
5546
 
  ;; accgs: a list of accgs.
5547
 
  ;;
5548
 
  ;; OUTPUT: returns non-nil iff scp succeeds for all the accgs.
5549
 
  (or (endp accgs)
5550
 
      (and (scp (cln-accg (copy-accg (car accgs))))
5551
 
           (can-scp-lstp (cdr accgs)))))
5552
 
 
5553
 
(defun-raw can-sct-lstp (accgs state) 
5554
 
  ;; accgs: a list of accgs
5555
 
  ;; state: the state
5556
 
  ;;
5557
 
  ;; OUTPUT: returns non-nil iff sct succeeds for the ccmfs of all the accgs.
5558
 
  (if (endp accgs)
5559
 
      (value t)
5560
 
    (let ((naccg (cln-accg (copy-accg (car accgs)))))
5561
 
      (if (null naccg)
5562
 
          (value nil)
5563
 
        (er-let*
5564
 
         ((ce (sct (accg-ccmfs naccg)
5565
 
                   (array-dimension naccg 0)
5566
 
                   state)))
5567
 
         (if (null ce)
5568
 
             (can-sct-lstp (cdr accgs) state)
5569
 
           (value nil)))))))
5570
 
 
5571
 
(defun remove-covered-subsets-tail (avar subsets acc)
5572
 
  ;;tail recursive implementation of remove-covered-subsets
5573
 
  (cond ((endp subsets) acc)
5574
 
        ((equal avar (caar subsets))
5575
 
         (remove-covered-subsets-tail avar (cdr subsets) acc))
5576
 
        (t
5577
 
         (remove-covered-subsets-tail avar
5578
 
                                      (cdr subsets)
5579
 
                                      (cons (car subsets) acc)))))
5580
 
 
5581
 
(defun remove-covered-subsets (avar subsets)
5582
 
  ;; avar: an element.
5583
 
  ;; subsets: a list of lists.
5584
 
  ;;
5585
 
  ;; OUTPUT: the subset of subsets which do not have avar as its first element.
5586
 
  (remove-covered-subsets-tail avar subsets nil))
5587
 
 
5588
 
(defun remove-avar-from-subsets-tail (avar subsets acc)
5589
 
  ;; a tail-recursive implementation of remove-avar-from-subsets.
5590
 
  (if (endp subsets)
5591
 
      acc
5592
 
    (remove-avar-from-subsets-tail avar (cdr subsets)
5593
 
                                   (cons (if (equal avar (caar subsets))
5594
 
                                             (cdar subsets)
5595
 
                                           (car subsets))
5596
 
                                         acc))))
5597
 
 
5598
 
(defun remove-avar-from-subsets (avar subsets)
5599
 
  ;; avar: an element
5600
 
  ;; subsets: a list of lists
5601
 
  ;;
5602
 
  ;; OUTPUT: the result of removing avar from all the lists in subsets
5603
 
  ;; for which avar is the first element.
5604
 
  (remove-avar-from-subsets-tail avar subsets nil))
5605
 
 
5606
 
(defun add-avar-to-subsets-tail (avar subsets acc)
5607
 
  ;; a tail-recursive implementation of add-avar-to-subsets.
5608
 
  (if (endp subsets)
5609
 
      acc
5610
 
    (add-avar-to-subsets-tail avar (cdr subsets)
5611
 
                              (acons avar (car subsets) acc))))
5612
 
 
5613
 
(defun add-avar-to-subsets (avar subsets)
5614
 
  ;; avar: an element.
5615
 
  ;; subsets: a list of lists.
5616
 
  ;;
5617
 
  ;; OUTPUT: the result of consing avar to every element of subsets.
5618
 
  (add-avar-to-subsets-tail avar subsets nil))
5619
 
         
5620
 
(defun-raw all-termination1 (proved-scp proved-sct contexts avars
5621
 
                                        relevant-edges subsets state)
5622
 
  ;; proved-scp: a list of accgs for which scp succeeds.
5623
 
  ;; proved-sct: a list of accgs for which sct succeeds.
5624
 
  ;; contexts: an array of contexts.
5625
 
  ;; avars: a list of pairs of the form (fn. x) where fn is a function
5626
 
  ;; name, and x is a formal of that function.
5627
 
  ;; relevant-edges: a list of lists of indices such that the ith
5628
 
  ;; element of avars appears exactly in the ccms of the corresponding
5629
 
  ;; function indicated by the indices of the ith member of relevant-edges.
5630
 
 
5631
 
  ;; subsets: a list of lists of the elements of avars. This helps us
5632
 
  ;; avoid finding supersets of already discovered measured-subsets by
5633
 
  ;; telling us what subsets to avoid (because they would result in a
5634
 
  ;; superset of an already calculated measured-subset).
5635
 
  ;;
5636
 
  ;; OUTPUT: a list of lists of the elements of avars coresponding to
5637
 
  ;; minimal variables needed to still successfully run scp on the
5638
 
  ;; elements of proved-scp and run sct on the elements of proved-sct.
5639
 
  (cond ((member-equal '() subsets)
5640
 
         ;; if '() is in subsets, that means that we have recreated an
5641
 
         ;; already calculated measured-subset, so we stop and return
5642
 
         (value '()))
5643
 
        ((endp avars)
5644
 
         ;; since we prune as we go, we know that if we make it to the
5645
 
         ;; end of the avars, we have a solution. So, we return the
5646
 
         ;; set containing the empty set, which will be populated on
5647
 
         ;; our way back up the search tree.
5648
 
         (value '(())))
5649
 
        (t
5650
 
         (let* ((avar (car avars)) ;; take the first avar.
5651
 
                (fn (car avar))   ;; the formal name
5652
 
                
5653
 
                ;; we begin by removing all the ccm edges that are
5654
 
                ;; relevant to var from all the accgs in both
5655
 
                ;; proved-sct and proved scp.
5656
 
                
5657
 
                (re-info (accg-remove-relevant-ccmf-edges-lst-tail
5658
 
                          proved-sct
5659
 
                          contexts
5660
 
                          fn
5661
 
                          (car relevant-edges)
5662
 
                          (accg-remove-relevant-ccmf-edges-lst
5663
 
                           proved-scp
5664
 
                           contexts
5665
 
                           fn
5666
 
                           (car relevant-edges)))))
5667
 
 
5668
 
           ;; if we can still prove termination without var, we
5669
 
           ;; continue our search down the subtree in which var
5670
 
           ;; is disabled. otherwise, we set nsubsets to be the
5671
 
           ;; empty set.
5672
 
           (er-let*
5673
 
            ((p (can-sct-lstp proved-sct state))
5674
 
             (nsubsets (if (and p
5675
 
                                (can-scp-lstp proved-scp))
5676
 
                           (all-termination1 proved-scp proved-sct
5677
 
                                             contexts
5678
 
                                             (cdr avars) (cdr relevant-edges)
5679
 
                                             (remove-covered-subsets avar subsets)
5680
 
                                             state)
5681
 
                         (value '()))))
5682
 
            (progn
5683
 
              ;; next we restore the edges we removed.
5684
 
              (restore-edges re-info)
5685
 
              ;; finally, we search the branch of the search tree in
5686
 
              ;; which var is enabled.
5687
 
              (er-let*
5688
 
               ((nnsubsets (all-termination1
5689
 
                            proved-scp proved-sct
5690
 
                            contexts
5691
 
                            (cdr avars) (cdr relevant-edges)
5692
 
                            (append nsubsets
5693
 
                                    (remove-avar-from-subsets avar subsets))
5694
 
                            state)))
5695
 
               ;; our solution is all the minimal measured subsets we
5696
 
               ;; discovered with var disabled along with var added to
5697
 
               ;; all the minimal measured subsets we discovered with
5698
 
               ;; var enabled.
5699
 
               (value (append nsubsets
5700
 
                              (add-avar-to-subsets avar nnsubsets))))))))))
5701
 
                
5702
 
(defun-raw funct-fns-lst (functs)
5703
 
  ;; given a list of functs, returns a corresponding list of all their funct-fns.
5704
 
  (if (endp functs)
5705
 
      nil
5706
 
    (cons (funct-fn (car functs)) (cdr functs))))
5707
 
 
5708
 
(defun append-to-all (list list-of-lists)
5709
 
  (if (endp list-of-lists)
5710
 
      nil
5711
 
    (cons (append list (car list-of-lists))
5712
 
          (append-to-all list (cdr list-of-lists)))))
5713
 
 
5714
 
(defun-raw all-termination (proved-scp proved-sct contexts functs cpn state)
5715
 
  ;; proved-scp: a list of accgs for which scp succeeds.
5716
 
  ;; proved-sct: a list of accgs for which sct succeeds.
5717
 
  ;; contexts: an array of contexts.
5718
 
  ;; functs: a list of structures of type funct.
5719
 
  ;; cpn: a boolean telling us if we proved termination using ccmfs
5720
 
  ;; per node (as opposed to per edge).
5721
 
  ;;
5722
 
  ;; OUTPUT: the minimal measured subsets of functs using the accgs
5723
 
  ;; that were used to prove termination.
5724
 
  
5725
 
  ;; we need this strange case in the beginning.
5726
 
  (if (and (endp proved-scp)
5727
 
           (endp proved-sct))
5728
 
      (value '(()))
5729
 
 
5730
 
    (let ((names (funct-fns-lst functs)))
5731
 
      (mv-let
5732
 
       (free fixed)
5733
 
       ;; if we proved termination with ccmfs per node, then by
5734
 
       ;; Vroon's dissertation, there is a measure involving only
5735
 
       ;; those variables that are needed to show termination in
5736
 
       ;; proved-scp and proved-sct. That is, all variables are
5737
 
       ;; candidates for removal from the measured-subset. If we
5738
 
       ;; used ccmfs per edge, then the dissertation tells us
5739
 
       ;; that we need to keep all variables that appear in the
5740
 
       ;; ruler. So these are off-limits for removal from the
5741
 
       ;; measured subset.
5742
 
       (name-var-pairs functs
5743
 
                       (if cpn
5744
 
                           (pairlis$ names nil)
5745
 
                         (ruler-vars names contexts)))
5746
 
       ;; we append all the required variables to the calculated
5747
 
       ;; measured subset.
5748
 
       (let ((relevant-ccms (gather-all-relevant-ccms free functs)))
5749
 
         (er-let* ((at1 (all-termination1 proved-scp proved-sct
5750
 
                                          contexts free relevant-ccms nil state)))
5751
 
                  (value (append-to-all fixed at1))))))))
5752
 
 
5753
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5754
 
;;; ACL2 integration                       ;;;
5755
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5756
 
 
5757
 
(defun get-ccms1 (m edcls key ctx state)
5758
 
  
5759
 
  ;; this function is based on get-measures1 in the ACL2 sources.
5760
 
 
5761
 
  ;; A typical edcls is given above, in the comment for get-guards.  Note
5762
 
  ;; that the :CCMs entry is found in an XARGS declaration.  By the check
5763
 
  ;; in chk-dcl-lst we know there is at most one :CCMs entry in each XARGS
5764
 
  ;; declaration.  But there may be more than one declaration.  If more than
5765
 
  ;; one measure is specified by this edcls, we'll cause an error.  Otherwise,
5766
 
  ;; we return the measure or the term *0*, which is taken as a signal that
5767
 
  ;; no measure was specified.
5768
 
  
5769
 
  ;; Our first argument, m, is the list of ccms term found so far, or
5770
 
  ;; *0* if none has been found.  We map down edcls and ensure that
5771
 
  ;; each XARGS either says nothing about :CCMs or specifies m.
5772
 
 
5773
 
  (cond ((null edcls) (value m))
5774
 
        ((eq (caar edcls) 'xargs)
5775
 
         (let ((temp (assoc-keyword key (cdar edcls))))
5776
 
           (cond ((null temp)
5777
 
                  (get-ccms1 m (cdr edcls) key ctx state))
5778
 
                 ((equal m *0*)
5779
 
                  (get-ccms1 (cadr temp) (cdr edcls) key ctx state))
5780
 
                 ((and (subsetp-equal m (cadr temp))
5781
 
                       (subsetp-equal (cadr temp) m))
5782
 
                  (get-ccms1 m (cdr edcls) key ctx state))
5783
 
                 (t (er soft ctx
5784
 
                        "It is illegal to declare two different ~
5785
 
                         sets values for the key ~x0 for the admission ~
5786
 
                         of a single function. But you have specified ~
5787
 
                         ~x0 ~x1 and ~x1 ~x2."
5788
 
                        key m (cadr temp))))))
5789
 
        (t (get-ccms1 m (cdr edcls) key ctx state))))
5790
 
 
5791
 
(defun get-ccms2 (lst key ctx state)
5792
 
  ;; this function is based on get-measures2 in the acl2-sources
5793
 
  (cond ((null lst) (value nil))
5794
 
        (t (er-let* ((m (get-ccms1 *0* (fourth (car lst)) key ctx state))
5795
 
                     (rst (get-ccms2 (cdr lst) key ctx state)))
5796
 
                    (value (cons m rst))))))
5797
 
 
5798
 
(defun get-ccms (symbol-class lst key ctx state)
5799
 
 
5800
 
  ;; based on get-measures in the ACL2 sources
5801
 
 
5802
 
  ;; This function returns a list in 1:1 correspondence with lst containing
5803
 
  ;; the user's specified :CCMs (or *0* if no measure is specified).  We
5804
 
  ;; cause an error if more than one :CCMs is specified within the edcls of
5805
 
  ;; a given element of lst.
5806
 
 
5807
 
  ;; If symbol-class is program, we ignore the contents of lst and simply return
5808
 
  ;; all *no-measure*s.  See the comment in chk-acceptable-defuns where get-ccms is
5809
 
  ;; called.
5810
 
 
5811
 
  (cond
5812
 
   ((eq symbol-class :program)
5813
 
    (value (make-list (length lst) :initial-element *0*)))
5814
 
   (t (get-ccms2 lst key ctx state))))
5815
 
 
5816
 
(defun translate-ccms-list (ccms-list ctx wrld state)
5817
 
  ;; translates a list of ccm lists using translate measures.
5818
 
  (cond ((endp ccms-list) (value nil))
5819
 
        (t (er-let* ((tccms (if (eq (car ccms-list) *0*)
5820
 
                                (value *0*)
5821
 
                              (translate-measures (car ccms-list)
5822
 
                                                  ctx wrld state)))
5823
 
                     (rst (translate-ccms-list (cdr ccms-list)
5824
 
                                               ctx wrld state)))
5825
 
                    (value (cons tccms rst))))))
5826
 
 
5827
 
(defun chk-no-overlap (consider consider-only)
5828
 
  ;; makes sure that, for each function, there is not both a consider
5829
 
  ;; and consider-only hint.
5830
 
  (cond ((endp consider)
5831
 
         nil)
5832
 
        ((not (or (eq (car consider) *0*)
5833
 
                  (eq (car consider-only) *0*)))
5834
 
         (cons consider consider-only))
5835
 
        (t
5836
 
         (chk-no-overlap (cdr consider) (cdr consider-only)))))
5837
 
 
5838
 
(defun combine-ccm-hints (consider consider-only uc uco ctx state)
5839
 
 
5840
 
  ;; combines the :CONSIDER-CCMS and :CONSIDER-ONLY-CCMS hints into one list of
5841
 
  ;; CCMs. We do not allow both of these to be specified for the same function,
5842
 
  ;; so we check that one or the other is *0*. The value returned is a list of
5843
 
  ;; pairs. The car of each pair is nil iff the given CCM is from a
5844
 
  ;; :CONSIDER-CCMS hint and non-nil if it is from a :CONSIDER-ONLY-CCMS
5845
 
  ;; hint. The cdr of each pair is the hint itself. If neither xarg is given
5846
 
  ;; (i.e. if they are both *0*) for a given function, the car of the pair is
5847
 
  ;; nil, and the cdr is *0*.
5848
 
 
5849
 
  (cond ((endp consider)
5850
 
         (value nil))
5851
 
        ((eq (car consider-only) *0*)
5852
 
         (er-let* ((rst (combine-ccm-hints (cdr consider) (cdr consider-only)
5853
 
                                           (cdr uc) (cdr uco)
5854
 
                                           ctx state)))
5855
 
                  (value (acons nil (car consider) rst))))
5856
 
        ((eq (car consider) *0*)
5857
 
         (er-let* ((rst (combine-ccm-hints (cdr consider) (cdr consider-only)
5858
 
                                           (cdr uc) (cdr uco)
5859
 
                                           ctx state)))
5860
 
                  (value (acons t (car consider-only) rst))))
5861
 
        (t
5862
 
         (er soft ctx
5863
 
             "It is illegal to provide both a :CONSIDER and ~
5864
 
              a :CONSIDER-ONLY hint for the same function. But ~
5865
 
              you have specified :CONSIDER ~x0 and :CONSIDER-ONLY ~x1."
5866
 
             (car uc) (car uco)))))
5867
 
 
5868
 
(defconst *ccg-xargs-keywords*
5869
 
  '(:CONSIDER-CCMS :CONSIDER-ONLY-CCMS :TERMINATION-METHOD
5870
 
                   :CCG-PRINT-PROOFS :TIME-LIMIT
5871
 
                   :CCG-HIERARCHY))
5872
 
                            
5873
 
(defun get-unambiguous-xargs-val1/edcls (key v edcls ctx state)
5874
 
 
5875
 
; V is the value specified so far for key in the XARSGs of this or previous
5876
 
; edcls, or else the consp '(unspecified) if no value has been specified yet.
5877
 
; We cause an error if a value different from that specified so far is
5878
 
; specified.  We return either the consp '(unspecified) or the uniformly agreed
5879
 
; upon value.
5880
 
 
5881
 
  (cond
5882
 
   ((null edcls) (value v))
5883
 
   ((eq (caar edcls) 'xargs)
5884
 
    (let ((temp (assoc-keyword key (cdar edcls))))
5885
 
      (cond ((null temp)
5886
 
             (get-unambiguous-xargs-val1/edcls key v (cdr edcls) ctx state))
5887
 
            ((or (consp v)
5888
 
                 (equal v (cadr temp)))
5889
 
             (get-unambiguous-xargs-val1/edcls key (cadr temp) (cdr edcls)
5890
 
                                              ctx state))
5891
 
            (t
5892
 
             (er soft ctx
5893
 
                 "It is illegal to specify ~x0 ~x1 in one place and ~
5894
 
                  ~x2 in another within the same definition.  The ~
5895
 
                  functionality controlled by that flag operates on ~
5896
 
                  the entire event or not at all."
5897
 
                 key v (cadr temp))))))
5898
 
   (t (get-unambiguous-xargs-val1/edcls key v (cdr edcls) ctx state))))
5899
 
 
5900
 
(defun get-unambiguous-xargs-val1 (key lst ctx state)
5901
 
 
5902
 
; We scan the edcls of lst and either extract a single uniformly agreed
5903
 
; upon value for key among the XARGS and return that value, or else no
5904
 
; value is specified and we return the consp '(unspecified) or else two or
5905
 
; more values are specified and we cause an error.  We also cause an error
5906
 
; if any edcls specifies a non-symbol for the value of key.  Thus, if we
5907
 
; return a symbol it is the uniformly agreed upon value and if we return
5908
 
; a consp there was no value specified.
5909
 
 
5910
 
  (cond ((null lst) (value '(unspecified)))
5911
 
        (t (er-let*
5912
 
            ((v (get-unambiguous-xargs-val1 key (cdr lst) ctx state))
5913
 
             (ans (get-unambiguous-xargs-val1/edcls key v (fourth (car lst))
5914
 
                                                    ctx state)))
5915
 
            (value ans)))))
5916
 
 
5917
 
(defun get-unambiguous-xargs-val (key lst default ctx state)
5918
 
 
5919
 
; Lst is a list of mutually recursive defun tuples of the form (name args doc
5920
 
; edcls body).  We scan the edcls for the settings of the XARGS keyword key.
5921
 
; If at least one entry specifies a setting, x, and all entries that specify a
5922
 
; setting specify x, we return x.  If no entry specifies a setting, we return
5923
 
; default.  If two or more entries specify different settings, we cause an
5924
 
; error.
5925
 
 
5926
 
; We assume every legal value of key is a symbol.  If you supply a consp
5927
 
; default and the default is returned, then no value was specified for key.
5928
 
 
5929
 
; Just to be concrete, suppose key is :mode and default is :logic.  The
5930
 
; user has the opportunity to specify :mode in each element of lst, i.e., he
5931
 
; may say to make the first fn :logic and the second fn :program.  But
5932
 
; that is nonsense.  We have to process the whole clique or none at all.
5933
 
; Therefore, we have to meld all of his various :mode specs together to come
5934
 
; up with a setting for the DEFUNS event.  This function explores lst and
5935
 
; either comes up with an unambiguous :mode or else causes an error.
5936
 
 
5937
 
  (er-let* ((x (get-unambiguous-xargs-val1 key lst ctx state)))
5938
 
           (cond ((equal x '(unspecified)) (value default))
5939
 
                 (t (value x)))))
5940
 
 
5941
 
(defdoc CCG-XARGS
5942
 
  ":Doc-Section CCG
5943
 
 
5944
 
  giving hints to CCG analysis via ~l[xargs]~/
5945
 
 
5946
 
  In addition to the ~ilc[xargs] provided by ACL2 for passing ~il[hints] to
5947
 
  function definitions, the CCG analysis enables several others for guiding the
5948
 
  CCG termination analysis for a given function definition. The following
5949
 
  example is nonsensical but illustrates all of these xargs:
5950
 
  ~bv[]
5951
 
  (declare (xargs :termination-method :ccg
5952
 
                  :consider-ccms ((foo x) (bar y z))
5953
 
                  :consider-only-ccms ((foo x) (bar y z))
5954
 
                  :ccg-print-proofs nil
5955
 
                  :time-limit 120
5956
 
                  :ccg-hierarchy *ccg-hierarchy-hybrid*))~/
5957
 
 
5958
 
  General Form:
5959
 
  (xargs :key1 val1 ... :keyn valn)
5960
 
  ~ev[]
5961
 
 
5962
 
  Where the keywords and their respective values are as shown below.
5963
 
 
5964
 
  Note that the :TERMINATION-METHOD ~c[xarg] is always valid, but the other
5965
 
  ~c[xargs] listed above are only valid if the termination method being used
5966
 
  for the given function is :CCG.
5967
 
 
5968
 
  ~c[:TERMINATION-METHOD value]~nl[]
5969
 
  ~c[Value] here is either ~c[:CCG] or ~c[:MEASURE]. For details on the meaning
5970
 
  of these settings, see the documentation for ~ilc[set-termination-method]. If
5971
 
  this ~c[xarg] is given, it overrides the global setting for the current
5972
 
  definition. If the current definition is part of a ~ilc[mutual-recursion],
5973
 
  and a ~c[:termination-method] is provided, it must match that provided by all
5974
 
  other functions in the ~c[mutual-recursion].
5975
 
 
5976
 
  ~c[:CONSIDER-CCMS value] or ~c[:CONSIDER-ONLY-CCMS value]~nl[] 
5977
 
  ~c[Value] is a list of terms involving only the formals of the function being
5978
 
  defined. Both suggest measures for the current function to the CCG
5979
 
  analysis. ACL2 must be able to prove that each of these terms always evaluate
5980
 
  to an ordinal ~pl[ordinals]. ACL2 will attempt to prove this before beginning
5981
 
  the CCG analysis. The difference between ~c[:consider-ccms] and
5982
 
  ~c[:consider-only-ccms] is that if ~c[:consider-ccms] is used, the CCG
5983
 
  analysis will attempt to guess additional measures that it thinks might be
5984
 
  useful for proving termination, whereas if ~c[:consider-only-ccms] is used,
5985
 
  only the measures given will be used for the given function in the CCG
5986
 
  analysis. These two ~c[xargs] may not be used together, and attempting to do
5987
 
  so will result in an error.
5988
 
 
5989
 
  ~c[:CCG-PRINT-PROOFS value]~nl[]
5990
 
  ~c[Value] is either ~c[t] or ~c[nil]. This is a local override of the
5991
 
  ~ilc[set-ccg-print-proofs] setting. See this documentation topic for details.
5992
 
 
5993
 
  ~c[:TIME-LIMIT value]~nl[]
5994
 
  ~c[Value] is either a positive rational number or nil. This is a local
5995
 
  override of the ~ilc[set-ccg-time-limit] setting. See this documentation
5996
 
  topic for details.
5997
 
 
5998
 
  ~c[:CCG-HIERARCHY value]~nl[]
5999
 
  ~c[Value] is a CCG hierarchy. This is a local override of the
6000
 
  ~ilc[set-ccg-hierarchy] setting. See this documentation topic for details.~/")
6001
 
                
6002
 
(defun chk-acceptable-ccg-xargs (fives symbol-class ctx wrld state)
6003
 
  (er-let* ((untranslated-consider (get-ccms symbol-class
6004
 
                                             fives
6005
 
                                             :CONSIDER-CCMs
6006
 
                                             ctx state))
6007
 
            (consider (translate-ccms-list untranslated-consider ctx wrld state))
6008
 
            (untranslated-consider-only (get-ccms symbol-class
6009
 
                                                  fives
6010
 
                                                  :CONSIDER-ONLY-CCMs
6011
 
                                                  ctx state))
6012
 
            (consider-only (translate-ccms-list untranslated-consider-only
6013
 
                                                ctx wrld state))
6014
 
            (ccms (combine-ccm-hints consider consider-only 
6015
 
                                     untranslated-consider
6016
 
                                     untranslated-consider-only
6017
 
                                     ctx state))
6018
 
            (verbose (get-unambiguous-xargs-flg
6019
 
                      :CCG-PRINT-PROOFS
6020
 
                      fives
6021
 
                      (get-ccg-print-proofs) ;; default is global setting
6022
 
                      ctx state))
6023
 
            (time-limit (get-unambiguous-xargs-val
6024
 
                         :TIME-LIMIT
6025
 
                         fives
6026
 
                         ;; the default time-limit is that specified in the
6027
 
                         ;; world
6028
 
                         (get-ccg-time-limit wrld) 
6029
 
                         ctx state)))
6030
 
           (cond ((not (booleanp verbose))
6031
 
                  (er soft ctx
6032
 
                      "The :CCG-PRINT-PROOFS specified by XARGS must either ~
6033
 
                       be NIL or T. ~x0 is neither."
6034
 
                      verbose))
6035
 
                 ((not (or (null time-limit)
6036
 
                           (rationalp time-limit)))
6037
 
                  (er soft ctx
6038
 
                      "The :TIME-LIMIT specified by XARGS must either be NIL ~
6039
 
                       or a rational number. ~x0 is neither."
6040
 
                      time-limit))
6041
 
                 (t 
6042
 
                  (value (list ccms
6043
 
                               verbose
6044
 
                               time-limit))))))
6045
 
 
6046
 
(defun ?-ccm-lstp (lst)
6047
 
  (or (endp lst)
6048
 
      (let ((ccm (car lst)))
6049
 
        (and (true-listp ccm)
6050
 
             (eq (car ccm) :?)
6051
 
             (arglistp (cdr ccm))
6052
 
             (?-ccm-lstp (cdr lst))))))
6053
 
     
6054
 
(defun ccg-redundant-measure-for-defunp (def justification wrld)
6055
 
  (let ((name (car def))
6056
 
        (measure0 (if justification
6057
 
                      (access justification
6058
 
                              justification
6059
 
                              :measure)
6060
 
                    nil))
6061
 
        (measures (fetch-dcl-field :measure
6062
 
                                   (butlast (cddr def)
6063
 
                                            1))))
6064
 
    (cond ((and (consp measure0)
6065
 
                (eq (car measure0) :?))
6066
 
           (if (and (consp measures)
6067
 
                    (null (cdr measures))
6068
 
                    (eq (caar measures) :?)
6069
 
                    (set-equalp-eq (cdar measures)
6070
 
                                   (cdr measure0)))
6071
 
               'redundant
6072
 
             (msg "the existing measure for ~x0 is ~x1, possibly indicating ~
6073
 
                   it was previously proven terminating using the CCG ~
6074
 
                   analysis. The new measure must therefore be explicitly ~
6075
 
                   declared to be a call of :? on the measured subset; for ~
6076
 
                   example, ~x1 will serve as the new :measure."
6077
 
                  name
6078
 
                  measure0)))
6079
 
          (t
6080
 
           (let* ((wrld1 (decode-logical-name name wrld))
6081
 
                  (val (scan-to-cltl-command (cdr wrld1)))
6082
 
                  (old-def (assoc-eq name (cdddr val))))
6083
 
             (or (non-identical-defp-chk-measures
6084
 
                  name
6085
 
                  measures
6086
 
                  (fetch-dcl-field :measure
6087
 
                                   (butlast (cddr old-def)
6088
 
                                            1))
6089
 
                  justification)
6090
 
                 'redundant))))))
6091
 
 
6092
 
(defun ccg-redundant-subset-for-defunp (chk-measurep chk-ccmsp def wrld)
6093
 
  (let* ((name (car def))
6094
 
         (justification (getprop name
6095
 
                                 'justification
6096
 
                                 'nil
6097
 
                                 'current-acl2-world
6098
 
                                 wrld))
6099
 
         (mok (if chk-measurep
6100
 
                  (ccg-redundant-measure-for-defunp def justification wrld)
6101
 
                'redundant)))
6102
 
    (cond ((consp mok) ; a message
6103
 
           mok)
6104
 
          ((and chk-ccmsp justification)
6105
 
           (let ((subset (access justification justification :subset))
6106
 
                 (ccms-lst (fetch-dcl-field :consider-only-ccms
6107
 
                                            (butlast (cddr def) 1))))
6108
 
             (if (and (consp ccms-lst)
6109
 
                      (null (cdr ccms-lst))
6110
 
                      (?-ccm-lstp (car ccms-lst))
6111
 
                      (set-equalp-eq (all-vars1-lst (car ccms-lst) nil)
6112
 
                                     subset))
6113
 
                 'redundant
6114
 
               (msg "A redundant definition using CCG termination must use ~
6115
 
                     the xarg :consider-only-ccms to declare a list of CCMs ~
6116
 
                     of the form (:? ...) whose arguments are equal to the ~
6117
 
                     measured subset of the previous definition. The ~
6118
 
                     definition of ~x0 does not do this. The previously ~
6119
 
                     defined version of this function has measured subset ~
6120
 
                     ~x1. Thus, an appropriate list of CCMs to declare would ~
6121
 
                     be ~x2."
6122
 
                    name
6123
 
                    subset
6124
 
                    `((:? ,@subset))))))
6125
 
          (t
6126
 
           'redundant))))
6127
 
 
6128
 
(defun ccg-redundant-subset-for-defunsp1 (chk-measurep chk-ccmsp def-lst wrld ans)
6129
 
  (if (endp def-lst)
6130
 
      ans
6131
 
    (let ((ans0 (ccg-redundant-subset-for-defunp chk-measurep
6132
 
                                                 chk-ccmsp
6133
 
                                                 (car def-lst)
6134
 
                                                 wrld)))
6135
 
      (cond ((consp ans0) ans0) ; a message
6136
 
            ((eq ans ans0)
6137
 
             (ccg-redundant-subset-for-defunsp1 chk-measurep
6138
 
                                                chk-ccmsp
6139
 
                                                (cdr def-lst)
6140
 
                                                wrld
6141
 
                                                ans))
6142
 
            (t nil)))))
6143
 
         
6144
 
(defun ccg-redundant-subset-for-defunsp (chk-measurep chk-ccmsp def-lst wrld)
6145
 
  (if (null def-lst)
6146
 
      'redundant
6147
 
    (let ((ans (ccg-redundant-subset-for-defunp chk-measurep
6148
 
                                                chk-ccmsp
6149
 
                                                (car def-lst)
6150
 
                                                wrld)))
6151
 
      (if (consp ans)
6152
 
          ans ;; a message
6153
 
        (ccg-redundant-subset-for-defunsp1 chk-measurep
6154
 
                                           chk-ccmsp
6155
 
                                           (cdr def-lst)
6156
 
                                           wrld
6157
 
                                           ans)))))
6158
 
 
6159
 
; Should this be in sync with redundant-or-reclassifying-defunsp ? --harshrc
6160
 
(defun ccg-redundant-or-reclassifying-defunsp (chk-measurep
6161
 
                                               chk-ccmsp
6162
 
                                               defun-mode
6163
 
                                               symbol-class
6164
 
                                               ld-skip-proofsp
6165
 
                                               def-lst
6166
 
                                               wrld)
6167
 
  (let ((ans (redundant-or-reclassifying-defunsp0 defun-mode
6168
 
                                                  symbol-class
6169
 
                                                  ld-skip-proofsp
6170
 
                                                  nil
6171
 
                                                  def-lst
6172
 
                                                  wrld)))
6173
 
    (cond ((or (consp ans) ;; a message
6174
 
               (not (eq ans 'redundant))
6175
 
 
6176
 
; the following 2 are a negation of the conditions for checking measures in
6177
 
; redundant-or-reclassifying-defunsp. We skip the check that each old
6178
 
; definition also has defun-mode of :logic, because if
6179
 
; redundant-or-reclassifying-defunsp0 returns 'redundant, and defun-mode is
6180
 
; :logic, we know that the old definitions must also all be logic (otherwise
6181
 
; there would have been an error or the new definitions would be
6182
 
; reclassifications). Keep this in sync with the conditions for checking
6183
 
; measures in redundant-or-reclassifying-defunsp.
6184
 
 
6185
 
               (not (eq defun-mode :logic))
6186
 
               ld-skip-proofsp)
6187
 
           ans)
6188
 
          (t
6189
 
           (ccg-redundant-subset-for-defunsp chk-measurep
6190
 
                                             chk-ccmsp
6191
 
                                             def-lst
6192
 
                                             wrld)))))
6193
 
 
6194
 
(defun get-and-chk-ccg-hierarchy (fives ctx wrld state)
6195
 
  (er-let*
6196
 
   ((hierarchy (get-unambiguous-xargs-val
6197
 
                :CCG-HIERARCHY
6198
 
                fives
6199
 
                *0*
6200
 
                ctx state)))
6201
 
    (if (equal hierarchy *0*)
6202
 
        (value (get-ccg-hierarchy wrld))
6203
 
      (er-progn
6204
 
       (chk-ccg-hierarchy hierarchy ctx state)
6205
 
       (value (fix-ccg-hierarchy hierarchy))))))
6206
 
 
6207
 
(defun ccg-hierarchy-kinds-of-levels (hierarchy has-ccgp has-measurep)
6208
 
  (declare (xargs :guard (and (hlevel-listp hierarchy)
6209
 
                              (booleanp has-ccgp)
6210
 
                              (booleanp has-measurep))))
6211
 
  (cond ((and has-ccgp has-measurep)
6212
 
         (mv t t))
6213
 
        ((endp hierarchy)
6214
 
         (mv has-ccgp has-measurep))
6215
 
        (t
6216
 
         (let ((is-measurep (equal (caar hierarchy) :measure)))
6217
 
           (ccg-hierarchy-kinds-of-levels (cdr hierarchy)
6218
 
                                          (or has-ccgp (not is-measurep))
6219
 
                                          (or has-measurep is-measurep))))))
6220
 
 
6221
 
 
6222
 
; ccg version of chk-acceptable-defuns (see defuns.lisp). Should be synced? --harshrc
6223
 
; annotated portions which differ by "ccg rewrite" comment --harshrc
6224
 
(defun ccg-chk-acceptable-defuns (lst ctx wrld state #+:non-standard-analysis std-p)
6225
 
 
6226
 
; WARNING: This function installs a world, hence should only be called when
6227
 
; protected by a revert-world-on-error.
6228
 
 
6229
 
; Rockwell Addition:  We now also return the non-executable flag.
6230
 
 
6231
 
; This function does all of the syntactic checking associated with defuns.  It
6232
 
; causes an error if it doesn't like what it sees.  It returns the traditional
6233
 
; 3 values of an error-producing, output-producing function.  However, the
6234
 
; "real" value of the function is a list of items extracted from lst during the
6235
 
; checking.  These items are:
6236
 
 
6237
 
;    names     - the names of the fns in the clique
6238
 
;    arglists  - their formals
6239
 
;    docs      - their documentation strings
6240
 
;    pairs     - the (section-symbol . citations) pairs parsed from docs
6241
 
;    guards    - their translated guards
6242
 
;    measures  - their translated measure terms
6243
 
;    ruler-extenders-lst
6244
 
;              - their ruler-extenders
6245
 
;    mp        - the domain predicate (e.g., o-p) for well-foundedness
6246
 
;    rel       - the well-founded relation (e.g., o<)
6247
 
;    hints     - their translated hints, to be used during the proofs of
6248
 
;                the measure conjectures, all flattened into a single list
6249
 
;                of hints of the form ((cl-id . settings) ...).
6250
 
;    guard-hints
6251
 
;              - like hints but to be used for the guard conjectures and
6252
 
;                untranslated
6253
 
;    std-hints (always returned, but only of interest when
6254
 
;               #+:non-standard-analysis)
6255
 
;              - like hints but to be used for the std-p conjectures
6256
 
;    otf-flg   - t or nil, used as "Onward Thru the Fog" arg for prove
6257
 
;    bodies    - their translated bodies
6258
 
;    symbol-class
6259
 
;              - :program, :ideal, or :common-lisp-compliant
6260
 
;    normalizeps
6261
 
;              - list of Booleans, used to determine for each fn in the clique
6262
 
;                whether its body is to be normalized
6263
 
;    reclassifyingp
6264
 
;              - t or nil, t if this is a reclassifying from :program
6265
 
;                with identical defs.
6266
 
;    wrld      - a modified wrld in which the following properties
6267
 
;                may have been stored for each fn in names:
6268
 
;                  'formals, 'stobjs-in and 'stobjs-out
6269
 
;    non-executablep - t or nil according to whether these defuns are to
6270
 
;                  non-executable.  Non-executable defuns may violate the
6271
 
;                  translate conventions on stobjs.
6272
 
;    guard-debug
6273
 
;              - t or nil, used to add calls of EXTRA-INFO to guard conjectures
6274
 
;    split-types-terms
6275
 
;              - list of translated terms, each corresponding to type
6276
 
;                declarations made for a definition with XARGS keyword
6277
 
;                :SPLIT-TYPES T
6278
 
 
6279
 
  (er-let*
6280
 
   ((fives (chk-defuns-tuples lst nil ctx wrld state))   
6281
 
 
6282
 
; Fives is a list in 1:1 correspondence with lst.  Each element of
6283
 
; fives is a 5-tuple of the form (name args doc edcls body).  Consider the
6284
 
; element of fives that corresponds to
6285
 
 
6286
 
;   (name args (DECLARE ...) "Doc" (DECLARE ...) body)
6287
 
 
6288
 
; in lst.  Then that element of fives is (name args "Doc" (...) body),
6289
 
; where the ... is the cdrs of the DECLARE forms appended together.
6290
 
; No translation has yet been applied to them.  The newness of name
6291
 
; has not been checked yet either, though we know it is all but new,
6292
 
; i.e., is a symbol in the right package.  We do know that the args
6293
 
; are all legal.
6294
 
 
6295
 
    (tm (get-unambiguous-xargs-flg :TERMINATION-METHOD
6296
 
                                   fives
6297
 
                                   (get-termination-method wrld)
6298
 
                                   ctx state)) ;ccg rewrite
6299
 
    (term-method (if (or (eq tm :ccg)
6300
 
                         (eq tm :measure))
6301
 
                     (value tm)
6302
 
                   (er soft ctx
6303
 
                       "The :TERMINATION-METHOD flag must be :CCG or ~
6304
 
                        :MEASURE, but ~x0 is none of these."
6305
 
                       tm))) ;ccg rewrite
6306
 
 
6307
 
    (names (value (strip-cars fives))))
6308
 
   (er-progn
6309
 
    (chk-no-duplicate-defuns names ctx state)
6310
 
    (chk-xargs-keywords fives ;ccg rewrite
6311
 
                        (if (eq term-method :ccg)
6312
 
                            (append *ccg-xargs-keywords*
6313
 
                                    *xargs-keywords*)
6314
 
                          (cons :termination-method
6315
 
                                *xargs-keywords*))
6316
 
                        ctx state)
6317
 
    (er-let*
6318
 
     ((tuple (chk-acceptable-defuns0 fives ctx wrld state))
6319
 
      (hierarchy (if (eq term-method :ccg)
6320
 
                     (get-and-chk-ccg-hierarchy fives ctx wrld state)
6321
 
                   (value nil)))) ;ccg rewrite
6322
 
     (let* ((stobjs-in-lst (car tuple))
6323
 
            (defun-mode (cadr tuple))
6324
 
            (non-executablep (caddr tuple))
6325
 
            (symbol-class (cdddr tuple)))
6326
 
       (mv-let ;ccg rewrite
6327
 
        (has-ccgp has-measurep)
6328
 
        (if (eq term-method :measure)
6329
 
          (mv nil t)
6330
 
        (ccg-hierarchy-kinds-of-levels hierarchy nil nil))
6331
 
        (let ((rc (ccg-redundant-or-reclassifying-defunsp
6332
 
                   has-measurep has-ccgp
6333
 
                   defun-mode symbol-class
6334
 
                   (ld-skip-proofsp state) lst wrld))) ;ccg rewrite - CHECK - harshrc
6335
 
          (cond
6336
 
           ((eq rc 'redundant)
6337
 
            (chk-acceptable-defuns-redundancy names ctx wrld state))
6338
 
           ((eq rc 'verify-guards)
6339
 
 
6340
 
; We avoid needless complication by simply causing a polite error in this
6341
 
; case.  If that proves to be too inconvenient for users, we could look into
6342
 
; arranging for a call of verify-guards here.
6343
 
 
6344
 
            (chk-acceptable-defuns-verify-guards-er names ctx wrld state))
6345
 
 
6346
 
; Synced with latest version of chk-acceptable-defuns svn version 1020
6347
 
; Added below cond clause for hons.
6348
 
; june 16 2013 - harshrc
6349
 
           #+hons
6350
 
           ((and (eq rc 'reclassifying)
6351
 
              (conditionally-memoized-fns names
6352
 
                                          (table-alist 'memoize-table wrld)))
6353
 
 
6354
 
; We no longer recall exactly why we have this restriction.  However, after
6355
 
; discussing this with Sol Swords we think it's because we tolerate all sorts
6356
 
; of guard violations when dealing with :program mode functions, but we expect
6357
 
; guards to be handled properly with :logic mode functions, including the
6358
 
; condition function.  If we verify termination and guards for the memoized
6359
 
; function but not the condition, that could present a problem.  Quite possibly
6360
 
; we can relax this check somewhat after thinking things through -- e.g., if
6361
 
; the condition function is a guard-verified :logic mode function -- if there
6362
 
; is demand for such an enhancement.
6363
 
 
6364
 
         (er soft ctx
6365
 
             "It is illegal to verify termination (i.e., convert from ~
6366
 
              :program to :logic mode) for function~#0~[~/s~] ~&0, because ~
6367
 
              ~#0~[it is~/they are~] currently memoized with conditions; you ~
6368
 
              need to unmemoize ~#0~[it~/them~] first.  See :DOC memoize."
6369
 
             (conditionally-memoized-fns names
6370
 
                                         (table-alist 'memoize-table wrld))))
6371
 
           (t
6372
 
            (er-let*
6373
 
             ((tuple1 (chk-acceptable-defuns1 names fives
6374
 
                                              stobjs-in-lst defun-mode symbol-class rc
6375
 
                                              non-executablep ctx wrld state
6376
 
                                              #+:non-standard-analysis std-p))
6377
 
              (tuplec (if (eq term-method :measure)
6378
 
                          (value (list nil nil nil)) ;ccg rewrite
6379
 
                        (chk-acceptable-ccg-xargs fives symbol-class
6380
 
                                                  ctx wrld state))))
6381
 
             (value (append (list 'chk-acceptable-defuns term-method)
6382
 
                         (cdr tuple1)
6383
 
                         tuplec
6384
 
                         `(,hierarchy))))))))))))) ;ccg rewrite
6385
 
 
6386
 
;; (defun ccg-chk-acceptable-defuns (fives lst ctx wrld state #+:non-standard-analysis std-p)
6387
 
 
6388
 
;; ; Rockwell Addition:  We now also return the non-executable flag.
6389
 
 
6390
 
;; ; This function does all of the syntactic checking associated with defuns.  It
6391
 
;; ; causes an error if it doesn't like what it sees.  It returns the traditional
6392
 
;; ; 3 values of an error-producing, output-producing function.  However, the
6393
 
;; ; "real" value of the function is a list of items extracted from lst during the
6394
 
;; ; checking.  These items are:
6395
 
 
6396
 
;; ;    names     - the names of the fns in the clique
6397
 
;; ;    arglists  - their formals
6398
 
;; ;    docs      - their documentation strings
6399
 
;; ;    pairs     - the (section-symbol . citations) pairs parsed from docs
6400
 
;; ;    guards    - their translated guards
6401
 
;; ;    measures  - their translated measure terms
6402
 
;; ;    ruler-extenders-lst
6403
 
;; ;              - their ruler-extenders
6404
 
;; ;    mp        - the domain predicate (e.g., o-p) for well-foundedness
6405
 
;; ;    rel       - the well-founded relation (e.g., o<)
6406
 
;; ;    hints     - their translated hints, to be used during the proofs of
6407
 
;; ;                the measure conjectures, all flattened into a single list
6408
 
;; ;                of hints of the form ((cl-id . settings) ...).
6409
 
;; ;    guard-hints
6410
 
;; ;              - like hints but to be used for the guard conjectures and
6411
 
;; ;                untranslated
6412
 
;; ;    std-hints (always returned, but only of interest when
6413
 
;; ;               #+:non-standard-analysis)
6414
 
;; ;              - like hints but to be used for the std-p conjectures
6415
 
;; ;    otf-flg   - t or nil, used as "Onward Thru the Fog" arg for prove
6416
 
;; ;    bodies    - their translated bodies
6417
 
;; ;    symbol-class
6418
 
;; ;              - :program, :ideal, or :common-lisp-compliant
6419
 
;; ;    normalizeps
6420
 
;; ;              - list of Booleans, used to determine for each fn in the clique
6421
 
;; ;                whether its body is to be normalized
6422
 
;; ;    reclassifyingp
6423
 
;; ;              - t or nil, t if this is a reclassifying from :program
6424
 
;; ;                with identical defs.
6425
 
;; ;    wrld      - a modified wrld in which the following properties
6426
 
;; ;                may have been stored for each fn in names:
6427
 
;; ;                  'formals, 'stobjs-in and 'stobjs-out
6428
 
;; ;    non-executablep - t or nil according to whether these defuns are to
6429
 
;; ;                  non-executable.  Non-executable defuns may violate the
6430
 
;; ;                  translate conventions on stobjs.
6431
 
;; ;    guard-debug
6432
 
;; ;              - t or nil, used to add calls of EXTRA-INFO to guard conjectures
6433
 
 
6434
 
;;   (er-let*
6435
 
;;    ((tm (get-unambiguous-xargs-flg :TERMINATION-METHOD
6436
 
;;                                    fives
6437
 
;;                                    (get-termination-method wrld)
6438
 
;;                                    ctx state))
6439
 
;;     (term-method (if (or (eq tm :ccg)
6440
 
;;                          (eq tm :measure))
6441
 
;;                      (value tm)
6442
 
;;                    (er soft ctx
6443
 
;;                        "The :TERMINATION-METHOD flag must be :CCG or ~
6444
 
;;                         :MEASURE, but ~x0 is none of these."
6445
 
;;                        tm)))
6446
 
;;     (names (value (strip-cars fives))))
6447
 
;;    (er-progn
6448
 
;;     (chk-no-duplicate-defuns names ctx state)
6449
 
;;     (chk-xargs-keywords fives
6450
 
;;                         (if (eq term-method :ccg)
6451
 
;;                             (append *ccg-xargs-keywords*
6452
 
;;                                     *xargs-keywords*)
6453
 
;;                           (cons :termination-method
6454
 
;;                                 *xargs-keywords*))
6455
 
;;                         ctx state)
6456
 
;;     (er-let*
6457
 
;;      ((tuple0 (chk-acceptable-defuns0 fives ctx wrld state))
6458
 
;;       (stobjs-in-lst (value (car tuple0)))
6459
 
;;       (defun-mode (value (cadr tuple0)))
6460
 
;;       (verify-guards (value (caddr tuple0)))
6461
 
;;       (symbol-class (value (cdddr tuple0)))
6462
 
;;       (hierarchy (if (eq term-method :ccg)
6463
 
;;                      (get-and-chk-ccg-hierarchy fives ctx wrld state)
6464
 
;;                    (value nil))))
6465
 
;;      (mv-let
6466
 
;;       (has-ccgp has-measurep)
6467
 
;;       (if (eq term-method :measure)
6468
 
;;           (mv nil t)
6469
 
;;         (ccg-hierarchy-kinds-of-levels hierarchy nil nil))
6470
 
;;       (er-let*
6471
 
;;        ((rc (value (ccg-redundant-or-reclassifying-defunsp
6472
 
;;                     has-measurep has-ccgp
6473
 
;;                     defun-mode symbol-class
6474
 
;;                     (ld-skip-proofsp state) lst wrld))))
6475
 
;;        (cond
6476
 
;;         ((eq rc 'redundant)
6477
 
;;          (chk-acceptable-defuns-redundancy names ctx wrld state))
6478
 
;;         ((eq rc 'verify-guards)
6479
 
;;          (chk-acceptable-defuns-verify-guards names ctx wrld state))
6480
 
;;         (t
6481
 
;;          (er-let*
6482
 
;;           ((tuple1 (chk-acceptable-defuns1 names fives stobjs-in-lst
6483
 
;;                                            defun-mode symbol-class rc ctx
6484
 
;;                                            wrld state
6485
 
;;                                            #+:non-standard-analysis
6486
 
;;                                            std-p))
6487
 
;;            (tuplec (if (eq term-method :measure)
6488
 
;;                        (value (list nil nil nil))
6489
 
;;                      (chk-acceptable-ccg-xargs fives symbol-class
6490
 
;;                                                ctx wrld state))))
6491
 
;;           (value (append (list 'chk-acceptable-defuns term-method)
6492
 
;;                          (cdr tuple1)
6493
 
;;                          tuplec
6494
 
;;                          `(,hierarchy))))))))))))
6495
 
 
6496
 
(defun find-?-ccm1 (ccm-list)
6497
 
  (and (consp ccm-list)
6498
 
       (let ((ccm (car ccm-list)))
6499
 
         (or (and (consp ccm)
6500
 
                  (eq (car ccm) :?)
6501
 
                  ccm)
6502
 
             (find-?-ccm1 (cdr ccm-list))))))
6503
 
 
6504
 
(defun find-?-ccm (names ccms)
6505
 
  ;; looks for CCMS with :? as the function.
6506
 
  (if (endp ccms)
6507
 
      nil
6508
 
    (let ((bad-ccm (find-?-ccm1 (car ccms))))
6509
 
      (if bad-ccm
6510
 
          (cons (car names) bad-ccm)
6511
 
        (find-?-ccm (cdr names) (cdr ccms))))))
6512
 
 
6513
 
(defun fns-without-consider-only-ccms-hints (names ccms)
6514
 
  ;; checks if all the CCMs have been declared using :CONSIDER-ONLY-CCMS. Any
6515
 
  ;; functions for which this is not the case are collected into a list.
6516
 
  ;; Ccms should of the form returned by combine-ccm-hints.
6517
 
  (if (endp ccms)
6518
 
      nil
6519
 
    (let ((rst (fns-without-consider-only-ccms-hints (cdr names)
6520
 
                                                     (cdr ccms))))
6521
 
      (if (and (consp (car ccms))
6522
 
               (caar ccms))
6523
 
          rst
6524
 
        (cons (car names)
6525
 
              rst)))))
6526
 
 
6527
 
(defun-raw ccm-o-p-clauses2 (contexts term clauses)
6528
 
  (if (endp contexts)
6529
 
      clauses
6530
 
    (ccm-o-p-clauses2
6531
 
     (cdr contexts)
6532
 
     term
6533
 
     (conjoin-clause-to-clause-set
6534
 
      (add-literal term
6535
 
                   (dumb-negate-lit-lst (context-ruler (car contexts)))
6536
 
                   t)
6537
 
      clauses))))
6538
 
 
6539
 
(defun-raw ccm-o-p-clauses1 (contexts ccm-list clauses)
6540
 
  (if (endp ccm-list)
6541
 
      clauses
6542
 
    (ccm-o-p-clauses1 contexts (cdr ccm-list)
6543
 
                       (ccm-o-p-clauses2 contexts
6544
 
                                          (mcons-term* 'o-p (car ccm-list))
6545
 
                                          clauses))))
6546
 
        
6547
 
(defun-raw ccm-o-p-clauses0 (contexts ccm-list clauses)
6548
 
  (cond ((endp contexts)
6549
 
         clauses)
6550
 
        ((eq (car ccm-list) *0*)
6551
 
         (ccm-o-p-clauses0 (cdr contexts)
6552
 
                            (cdr ccm-list)
6553
 
                            clauses))
6554
 
        (t
6555
 
         (ccm-o-p-clauses0 (cdr contexts)
6556
 
                            (cdr ccm-list)
6557
 
                            (ccm-o-p-clauses1 (car contexts)
6558
 
                                               (car ccm-list)
6559
 
                                               clauses)))))
6560
 
 
6561
 
(defun-raw ccm-o-p-clauses (contexts ccm-list)
6562
 
  ;; builds the clauses to prove that the CCMs in ccm-list all
6563
 
  ;; evaluate to natural numbers.
6564
 
  (ccm-o-p-clauses0 contexts ccm-list nil))
6565
 
 
6566
 
(defun-raw ccg-intermediate-step (accgs ces new-hlevel old-hlevel proved qspv state)
6567
 
   (er-let*
6568
 
    ((triple (accg-refine-accgs accgs ces old-hlevel new-hlevel qspv state))
6569
 
     (caccgs (value (car triple)))
6570
 
     (uaccgs (value (cadr triple)))
6571
 
     (uces (value (cddr triple))))
6572
 
    (cond ((endp caccgs)
6573
 
           (pprogn
6574
 
            ;;(progn (print uaccgs) state)
6575
 
            (ccg-io? basics nil state
6576
 
                     ()
6577
 
                     (fms "Since we have no new information, we skip size ~
6578
 
                           change analysis and attempt to further refine the ~
6579
 
                           SCCs.~|"
6580
 
                          nil
6581
 
                          *standard-co*
6582
 
                          state
6583
 
                          nil))
6584
 
            (value (list* proved uaccgs uces))))
6585
 
           (t
6586
 
            (pprogn
6587
 
             (let ((clen (len caccgs)))
6588
 
               (ccg-io? basics nil state
6589
 
                        (uaccgs clen caccgs)
6590
 
                        (fms "~@0 of the CCG ~#\3~[was~/were~] altered. We ~
6591
 
                              analyze ~#\3~[it~/each of these~] with the size ~
6592
 
                              change termination analysis.~@4~|"
6593
 
                             `((#\0 . ,(if (consp uaccgs)
6594
 
                                           "~N1 of the ~n2 SCCs"
6595
 
                                         "~#\3~[The sole SCC~/All the SCCs~]"))
6596
 
                               (#\1 . ,clen)
6597
 
                               (#\2 . ,(+ clen (len uaccgs)))
6598
 
                               (#\3 . ,caccgs)
6599
 
                               (#\4 . ,(if (endp uaccgs)
6600
 
                                           ""
6601
 
                                         " The others will be set aside ~
6602
 
                                               for further refinement.")))
6603
 
                             *standard-co*
6604
 
                             state
6605
 
                             nil)))
6606
 
             (accg-sct-list caccgs proved uaccgs uces state))))))
6607
 
 
6608
 
(defun-raw ccg-measure-step (hlevel names t-machines measure-alist mp rel
6609
 
                                    bodies verbose qspv state)
6610
 
  (if (consp measure-alist)
6611
 
      (let ((ctx (access query-spec-var qspv :ctx))
6612
 
            (wrld (access query-spec-var qspv :wrld)) 
6613
 
            (ens (access query-spec-var qspv :ens))
6614
 
            (stop-time (access query-spec-var qspv :stop-time))
6615
 
            (otf-flg (access query-spec-var qspv :otf-flg))
6616
 
            (pt (cadr hlevel)))
6617
 
     (pprogn
6618
 
       (ccg-io? basics nil state
6619
 
                (hlevel)
6620
 
                (fms "The current level of the CCG hierarchy is ~x0. We ~
6621
 
                      therefore attempt a measure proof.~|"
6622
 
                     `((#\0 . hlevel))
6623
 
                     *standard-co*
6624
 
                     state
6625
 
                     nil))
6626
 
       (mv-let
6627
 
        (erp pair state)
6628
 
        (er-let*
6629
 
         ((hints (if (equal pt :built-in-clauses)
6630
 
                     (translate-hints
6631
 
                      "Measure Built-in-clauses Hint"
6632
 
                      '(("goal"
6633
 
                         :do-not '(eliminate-destructors
6634
 
                                   eliminate-irrelevance
6635
 
                                   generalize
6636
 
                                   fertilize)
6637
 
                         :in-theory (theory 'minimal-theory)
6638
 
                         :do-not-induct :otf-flg-override))
6639
 
                      ctx wrld state)
6640
 
                   (value (translated-limit-induction-hint (cadr pt))))))
6641
 
         (state-global-let*
6642
 
          ((inhibit-output-lst (if verbose
6643
 
                                   (@ inhibit-output-lst)
6644
 
                                 (list* 'event 'error (@ inhibit-output-lst)))))
6645
 
          (maybe-prover-before-stop-time
6646
 
           stop-time ctx state
6647
 
           (prove-termination names t-machines measure-alist mp rel
6648
 
                              hints otf-flg bodies
6649
 
                              ctx ens wrld state
6650
 
                              (f-get-global
6651
 
                               'accumulated-ttree
6652
 
                               state)))))
6653
 
        (if erp
6654
 
            (er-progn
6655
 
             (time-check stop-time ctx state)
6656
 
             (pprogn
6657
 
              (ccg-io? basics nil state
6658
 
                       ()
6659
 
                       (fms "Since ACL2 has failed to prove the measure ~
6660
 
                             conjecture, we continue with the hierarchical ~
6661
 
                             analysis.~|"
6662
 
                            nil
6663
 
                            *standard-co*
6664
 
                            state
6665
 
                            nil))
6666
 
              (value nil)))
6667
 
          (pprogn
6668
 
           (ccg-io? basics nil state
6669
 
                    ()
6670
 
                    (fms "ACL2 has succeeded in proving the measure ~
6671
 
                          conjecture, thereby proving termination."
6672
 
                         nil
6673
 
                         *standard-co*
6674
 
                         state
6675
 
                         nil))
6676
 
           (value (list* :measure
6677
 
                         (car pair)
6678
 
                         measure-alist
6679
 
                         (cdr pair))))))))
6680
 
    (pprogn
6681
 
     (ccg-io? basics nil state
6682
 
              (hlevel)
6683
 
              (fms "Skipping level ~x0 of the hierarchy due to previously ~
6684
 
                    mentioned error when guessing measures."
6685
 
                   `((#\0 . hlevel))
6686
 
                   *standard-co*
6687
 
                   state
6688
 
                   nil))
6689
 
     (value nil))))
6690
 
 
6691
 
(defun-raw ccg (accgs ces last-ccg-hlevel hierarchy proved context-array
6692
 
                      names arglists t-machines measure-alist mp rel bodies
6693
 
                      verbose qspv state)
6694
 
  (cond ((endp accgs)
6695
 
         (pprogn
6696
 
          (increment-timer 'other-time state)
6697
 
          (ccg-io? basics nil state
6698
 
                   ()
6699
 
                   (fms "We have successfully proven termination! We now weed ~
6700
 
                         out irrelevant CCMs so that we can minimize the ~
6701
 
                         measured-subset. This may require running the size ~
6702
 
                         change analysis several more times.~|"
6703
 
                        nil
6704
 
                        *standard-co*
6705
 
                        state
6706
 
                        nil))
6707
 
          (increment-timer 'print-time state)
6708
 
          (er-let*
6709
 
           ((ms (ccg-generate-measure-alist
6710
 
                 nil proved
6711
 
                 names arglists
6712
 
                 context-array
6713
 
                 ;; the following is overly-cautious. It could be the case that
6714
 
                 ;; some SCCs were proven terminating with ccmfs-per-node
6715
 
                 ;; and others with ccmfs-per-edge, in which case we would
6716
 
                 ;; be assuming here that we proved all of the SCCs terminating
6717
 
                 ;; with ccmfs-per-edge.
6718
 
                 (hlevel-ccmfs-per-nodep last-ccg-hlevel)
6719
 
                 state)))
6720
 
           (pprogn
6721
 
            (mv-let
6722
 
             (col state)
6723
 
             (io? event nil (mv col state)
6724
 
                  (names ms)
6725
 
                  (fmt "CCG analysis has succeeded in proving termination of ~
6726
 
                        ~&0 using CCMs over the following variables~#0~[~/, ~
6727
 
                        respectively~]: ~&1. Thus, we admit ~#0~[this ~
6728
 
                        function~/these ~ functions~] under the principle of ~
6729
 
                        definition."
6730
 
                       (list (cons #\0 names)
6731
 
                             (cons #\1 (strip-cddrs ms)))
6732
 
                       *standard-co*
6733
 
                       state
6734
 
                       nil)
6735
 
                  :default-bindings ((col 0)))
6736
 
             (value (list* :ccg
6737
 
                           col
6738
 
                           ms
6739
 
                           (f-get-global
6740
 
                            'accumulated-ttree
6741
 
                            state))))))))
6742
 
        ((endp hierarchy)
6743
 
         (pprogn
6744
 
          (ccg-io? basics nil state
6745
 
                   ()
6746
 
                   (fms "We have completed all levels of the hierarchy, but ~
6747
 
                         have failed to prove termination."
6748
 
                        ()
6749
 
                        *standard-co*
6750
 
                        state
6751
 
                        nil))
6752
 
          (if (null (car ces))
6753
 
              state
6754
 
            (ccg-io? counter-example nil state
6755
 
                     ()
6756
 
                     (print-counter-example
6757
 
                      (car accgs) (car ces)
6758
 
                      context-array
6759
 
                      (access query-spec-var qspv :ctx)
6760
 
                      (access query-spec-var qspv :ens)
6761
 
                      (access query-spec-var qspv :wrld)
6762
 
                      state)))
6763
 
          (mv t nil state)))
6764
 
        ((eq (caar hierarchy) :MEASURE)
6765
 
         (er-let*
6766
 
          ((tuple (ccg-measure-step (car hierarchy)
6767
 
                                    names
6768
 
                                    t-machines
6769
 
                                    measure-alist
6770
 
                                    mp
6771
 
                                    rel
6772
 
                                    bodies
6773
 
                                    verbose
6774
 
                                    qspv
6775
 
                                    state)))
6776
 
          (if tuple
6777
 
              (value tuple)
6778
 
            (ccg accgs ces last-ccg-hlevel (cdr hierarchy) proved context-array
6779
 
                 names arglists t-machines measure-alist mp rel bodies
6780
 
                 verbose qspv state))))
6781
 
        (t
6782
 
         (er-let*
6783
 
          ((tuple
6784
 
            (state-global-let*
6785
 
             ((inhibit-output-lst
6786
 
               (if verbose
6787
 
                   (@ inhibit-output-lst)
6788
 
                 (list* 'prove 'proof-tree (@ inhibit-output-lst)))))
6789
 
             (ccg-intermediate-step accgs
6790
 
                                    ces
6791
 
                                    (car hierarchy)
6792
 
                                    last-ccg-hlevel
6793
 
                                    proved
6794
 
                                    qspv
6795
 
                                    state)))
6796
 
           (nproved (value (car tuple)))
6797
 
           (naccgs (value (cadr tuple)))
6798
 
           (nces (value (cddr tuple))))
6799
 
          (ccg naccgs nces (car hierarchy) (cdr hierarchy) nproved
6800
 
               context-array
6801
 
               names arglists t-machines measure-alist mp rel bodies
6802
 
               verbose qspv state)))))
6803
 
 
6804
 
(defun-raw build-accgs (names contexts functs ccm-hints wrld state)
6805
 
  (let* ((context-array (context-array contexts))
6806
 
         ;; (num-contexts (array-dimension context-array 0))
6807
 
         (accgs (build-and-annotate-accgs names
6808
 
                                          functs
6809
 
                                          contexts
6810
 
                                          (pairlis$ names ccm-hints))))
6811
 
    ;; first we build the accgs using the first restriction
6812
 
    (pprogn
6813
 
     (increment-timer 'other-time state)
6814
 
     (ccg-io? basics nil state
6815
 
              (names context-array accgs)
6816
 
              (pprogn
6817
 
               (fms "We begin with the Calling Context Graph (CCG), ~
6818
 
                     containing the following contexts (if the output doesn't ~
6819
 
                     make sense, see :DOC CCG and also the paper referenced ~
6820
 
                     above):~|"
6821
 
                    nil
6822
 
                    *standard-co*
6823
 
                    state
6824
 
                    nil)
6825
 
               (print-context-array1 0 names context-array state)
6826
 
               (fms "and the following edges:~|"
6827
 
                    nil *standard-co* state nil)
6828
 
               (print-accg-edges1 accgs state)
6829
 
               (fms "We have annotated the CCG with the following calling ~
6830
 
                     context measures (CCMs):~|"
6831
 
                    nil *standard-co* state nil)
6832
 
               (print-funct-ccms functs wrld state)))
6833
 
     (increment-timer 'print-time state)
6834
 
     (pprogn
6835
 
      (ccg-io? basics nil state
6836
 
               ()
6837
 
               (fms "Before we begin the hierarchical analysis, we run our ~
6838
 
                     size-change analysis so we have a baseline for refinement."
6839
 
                    nil
6840
 
                    *standard-co*
6841
 
                    state
6842
 
                    nil))
6843
 
      (er-let*
6844
 
       ((tuple (accg-sct-list accgs nil nil nil state)))
6845
 
       (value (cons context-array tuple)))))))
6846
 
 
6847
 
(defun max-induction-depth1 (hierarchy max)
6848
 
  (declare (xargs :guard (and (hlevel-listp hierarchy)
6849
 
                              (integerp max)
6850
 
                              (<= -1 max))))
6851
 
  (if (endp hierarchy)
6852
 
      max
6853
 
    (max-induction-depth1
6854
 
     (cdr hierarchy)
6855
 
     (cond ((or (equal (caar hierarchy) :measure)
6856
 
                (equal (hlevel-proof-technique (car hierarchy))
6857
 
                       :built-in-clauses))
6858
 
            max)
6859
 
           (t
6860
 
            (max max (cadr (hlevel-proof-technique (car hierarchy)))))))))
6861
 
 
6862
 
(defun max-induction-depth (hierarchy)
6863
 
  (max-induction-depth1 hierarchy -1))
6864
 
 
6865
 
(defun ruler-extender-printout1 (names ruler-extenders-lst)
6866
 
  (if (endp names)
6867
 
      nil
6868
 
    (cons `("function ~x0 has ruler extenders ~x1"
6869
 
            (#\0 . ,(car names))
6870
 
            (#\1 . ,(car ruler-extenders-lst)))
6871
 
          (ruler-extender-printout1 (cdr names)
6872
 
                                    (cdr ruler-extenders-lst)))))
6873
 
 
6874
 
(defun ruler-extender-printout (names ruler-extenders-lst)
6875
 
  `("" "~@*." "~@*, and " "~@*, "
6876
 
    ,(ruler-extender-printout1 names ruler-extenders-lst)))
6877
 
 
6878
 
(defun-raw prove-termination-with-ccg (names functs contexts
6879
 
                                             ruler-extenders-lst ccm-hints
6880
 
                                             hierarchy verbose time-limit 
6881
 
                                             arglists measures t-machines mp
6882
 
                                             rel otf-flg bodies
6883
 
                                             ctx ens wrld state ttree)
6884
 
 
6885
 
  ;; based on prove-termination in the ACL2 sources, this function
6886
 
  ;; attempts to prove the termination of the given functions. names
6887
 
  ;; is the list of names of the the functions, term-method is the
6888
 
  ;; termination method to be used (:hybrid or :ccg), contexts are the
6889
 
  ;; contexts for the functions, ccm-hints is a list of pairs as defined by
6890
 
  ;; combine-ccm-hints, cpn, verbose, time-limit, and ccm-comparison-scheme are the
6891
 
  ;; user-specified CCG options, arglists is the list of lists of
6892
 
  ;; formals for the functions, measures are the user-specified
6893
 
  ;; measures, t-machines are the termination machines of the
6894
 
  ;; functions, mp and rel are the domain and relation for proving
6895
 
  ;; termination with a measure and otf-flg is the on-through-the-fog
6896
 
  ;; flag.
6897
 
 
6898
 
  ;; If we succeed, we return 4 values, consed together as "the" value
6899
 
  ;; in this error/value/state producing function. The first value is
6900
 
  ;; the proof method that ultimately proved termination (:ccg or
6901
 
  ;; :measure). The second value is the "justification" alist. For a
6902
 
  ;; measure-based proof, this is the measure-alist, and for a
6903
 
  ;; CCG-based proof, this is the result of
6904
 
  ;; ccg-generate-measure-alist. The last two values are the column
6905
 
  ;; and ttree. Currently, we simply return 0 for the column and nil
6906
 
  ;; for the ttree. I believe the column value is correct, but the
6907
 
  ;; ttree should eventually be the accumulation of all the ttrees
6908
 
  ;; associated with all the proofs done in the termination analysis.
6909
 
  
6910
 
 
6911
 
  ;; This function is specially coded so that if contexts is nil then
6912
 
  ;; it is a signal that there is only one element of names and it is
6913
 
  ;; a non-recursive function.  In that case, we short-circuit all of
6914
 
  ;; the proof machinery and simply do the associated output.  We
6915
 
  ;; coded it this way to preserve the invariant that
6916
 
  ;; prove-termination is THE place the defun output is initiated.
6917
 
 
6918
 
  ;; This function increments timers.  Upon entry, any accumulated time
6919
 
  ;; is charged to 'other-time.  The printing done herein is charged
6920
 
  ;; to 'print-time and the proving is charged to 'prove-time.
6921
 
 
6922
 
  (let* ((ccms (mapcar #'cdr ccm-hints))
6923
 
         (entry (find-?-ccm names ccms))
6924
 
         ;;(time-limit (get-ccg-time-limit wrld))
6925
 
         (stop-time (if time-limit (+ (get-internal-run-time) 
6926
 
                                      (* internal-time-units-per-second
6927
 
                                         time-limit))
6928
 
                      nil))
6929
 
         (qspv (make query-spec-var
6930
 
                            :stop-time stop-time
6931
 
                            :mem (create-memoization
6932
 
                                  (max-induction-depth hierarchy))
6933
 
                            :otf-flg otf-flg
6934
 
                            :ens ens
6935
 
                            :ctx ctx
6936
 
                            :wrld wrld)))
6937
 
    (cond
6938
 
     ((and entry
6939
 
           (not (ld-skip-proofsp state)))
6940
 
      (let ((fn (car entry))
6941
 
            (ccm (cdr entry)))
6942
 
        (er soft ctx
6943
 
            "A CCM of the form (:? v1 ... vk) is only legal when the defun is ~
6944
 
             redundant (see :DOC redundant-events) or when skipping proofs ~
6945
 
             (see :DOC ld-skip-proofsp).  The CCM ~x0 supplied for function ~
6946
 
             symbol ~x1 is thus illegal."
6947
 
            ccm fn)))
6948
 
     ((null contexts)
6949
 
      (mv-let (col state)
6950
 
              (io? event nil (mv col state)
6951
 
                   (names)
6952
 
                   (fmt "Since ~&0 is non-recursive, its admission is trivial.  "
6953
 
                        (list (cons #\0 names))
6954
 
                        (proofs-co state)
6955
 
                        state
6956
 
                        nil)
6957
 
                   :default-bindings ((col 0)))
6958
 
              (value (list* :ccg (or col 0) nil nil))))
6959
 
     ((ld-skip-proofsp state)
6960
 
      (let ((fns (fns-without-consider-only-ccms-hints names ccms)))
6961
 
        (if (consp fns)
6962
 
            (er soft ctx
6963
 
                "Proofs cannot be skipped on a CCG termination proof unless ~
6964
 
                 CCMs are defined for every function. You did not supply CCMs ~
6965
 
                 for function~#0~[~/s~] ~&0. Therefore, proofs cannot be skipped."
6966
 
                fns)
6967
 
          (value (list* :ccg
6968
 
                        0
6969
 
                        (pairlis$ names
6970
 
                                  (mapcar (lambda (x)
6971
 
                                            `(:? ,@(all-vars1-lst (cdr x) nil)))
6972
 
                                          ccms))
6973
 
                        nil
6974
 
                        nil)))))
6975
 
     (t
6976
 
      (pprogn
6977
 
       (ccg-io?
6978
 
        basics nil state
6979
 
        (names ruler-extenders-lst)
6980
 
        (fms "Attempting to prove termination using Calling Context Graph ~
6981
 
              (CCG) analysis. There are various ways in which users can ~
6982
 
              control CCG analysis. See the :DOC CCG for details. This ~
6983
 
              analysis is described in a 2006 CAV paper by Manolios and ~
6984
 
              Vroon.~|~%The ruler-extenders for each function are as follows: ~
6985
 
              ~*0~|"
6986
 
             `((#\0 .
6987
 
                ,(ruler-extender-printout names
6988
 
                                          ruler-extenders-lst)))
6989
 
             *standard-co*
6990
 
             state
6991
 
             nil))
6992
 
       (simplify-contexts contexts ens wrld ctx state)
6993
 
       (mv-let
6994
 
        (o-p-clauses ttree)
6995
 
        (clean-up-clause-set (ccm-o-p-clauses contexts ccms)
6996
 
                             ens wrld ttree state)
6997
 
        (er-let*
6998
 
            ((ttree (accumulate-ttree-and-step-limit-into-state
6999
 
                      ttree :skip state)))
7000
 
        (pprogn
7001
 
         (increment-timer 'other-time state)
7002
 
         (er-let*
7003
 
          ((displayed-goal (value
7004
 
                            (prettyify-clause-set o-p-clauses
7005
 
                                                  (let*-abstractionp state)
7006
 
                                                  wrld)))
7007
 
           (simp-phrase (value (tilde-*-simp-phrase ttree)))
7008
 
           (ttree1
7009
 
            (if o-p-clauses
7010
 
                (pprogn
7011
 
                 (io? event nil state
7012
 
                      (ttree displayed-goal simp-phrase)
7013
 
                      (fms "You have told us to consider CCMs that are not ~
7014
 
                             trivially proved to be ordinals. ~
7015
 
                             Therefore, the conjecture that we must prove ~
7016
 
                             before we can continue with the CCG ~
7017
 
                             analysis~#0~[~/, given ~*1,~] is ~
7018
 
                             ~@2~%~%Goal~%~Q34."
7019
 
                           `((#\0 . ,(if (nth 4 simp-phrase) 1 0))
7020
 
                             (#\1 . ,simp-phrase)
7021
 
                             (#\2 . ,(if (tagged-objectsp 'sr-limit ttree)
7022
 
                                         " as follows (where the ~
7023
 
                                           subsumption/replacement limit ~
7024
 
                                           affected this analysis; see :DOC ~
7025
 
                                           case-split-limitations)."
7026
 
                                       ""))
7027
 
                             (#\3 . ,displayed-goal)
7028
 
                             (#\4 . ,(term-evisc-tuple nil state)))
7029
 
                           (proofs-co state)
7030
 
                           state
7031
 
                           nil))
7032
 
                 (increment-timer 'print-time state)
7033
 
                 (prove (termify-clause-set o-p-clauses)
7034
 
                        (make-pspv
7035
 
                         ens wrld
7036
 
                         :displayed-goal displayed-goal
7037
 
                         :otf-flg otf-flg)
7038
 
                        nil ens wrld ctx state))
7039
 
              (value ttree))))
7040
 
          (mv-let
7041
 
           (has-ccgp has-measurep)
7042
 
           (ccg-hierarchy-kinds-of-levels hierarchy nil nil)
7043
 
           (er-let*
7044
 
            ((ba-tuple
7045
 
              (if has-ccgp
7046
 
                  (build-accgs names contexts functs ccm-hints wrld state)
7047
 
                (list* (make-array 0
7048
 
                                   :initial-element (make-context)
7049
 
                                   :element-type 'context)
7050
 
                       `(,(make-array 0
7051
 
                                      :initial-element (make-accg-node)
7052
 
                                      :element-type 'accg-node))
7053
 
                       `(,(make-array 0
7054
 
                                      :initial-element (make-accg-node)
7055
 
                                      :element-type 'accg-node))
7056
 
                       `(nil))))
7057
 
             (context-array (value (car ba-tuple)))
7058
 
             (proved-accgs (value (cadr ba-tuple)))
7059
 
             (accgs (value (caddr ba-tuple)))
7060
 
             (ces (value (cdddr ba-tuple)))
7061
 
             (measure-alist
7062
 
              (if (not has-measurep)
7063
 
                  (value nil)
7064
 
                (mv-let
7065
 
                 (erp ma state)
7066
 
                 (guess-measure-alist names arglists
7067
 
                                      measures
7068
 
                                      t-machines
7069
 
                                      ctx wrld state)
7070
 
                 (if (not erp)
7071
 
                     (value ma)
7072
 
                   (pprogn
7073
 
                    (ccg-io? basics nil state
7074
 
                             (names)
7075
 
                             (fms "Since there was an error guessing the ~
7076
 
                                   measure~#0~[~/s~], we will skip all levels ~
7077
 
                                   of the hierarchy of the form (:MEASURE ~
7078
 
                                   PT).~|"
7079
 
                                  `((#\0 . ,names))
7080
 
                                  *standard-co*
7081
 
                                  state
7082
 
                                  nil))
7083
 
                    (value nil)))))))
7084
 
            (er-let* ((quadruple
7085
 
                       (ccg accgs ces nil hierarchy proved-accgs context-array
7086
 
                            names arglists t-machines measure-alist mp rel bodies
7087
 
                            verbose qspv state)))
7088
 
              (let* ((term-method (car quadruple))
7089
 
                     (col (cadr quadruple))
7090
 
                     (measure-alist (caddr quadruple))
7091
 
                     (ttree-new (cdddr quadruple)))
7092
 
                (prog2$
7093
 
                 nil;dummy --harshrc
7094
 
                 ;(cw "~|**DEBUG**:: old ttree=~x0 ~ new ttree is ~x1 ~ and ttree1 is ~x2~|" ttree ttree-new ttree1)
7095
 
                 (value (list* term-method
7096
 
                               col
7097
 
                               measure-alist
7098
 
                               (cons-tag-trees ttree-new ttree1))))))
7099
 
                               
7100
 
              )))))))))))
7101
 
 
7102
 
(defun-raw ccg-prove-termination-recursive
7103
 
  (names arglists measures ccm-hints
7104
 
         ruler-extenders-lst t-machines mp rel
7105
 
         verbose time-limit hierarchy
7106
 
         otf-flg bodies ctx ens wrld state)
7107
 
  
7108
 
; Next we get the measures for each function.  That may cause an error
7109
 
; if we couldn't guess one for some function.
7110
 
  
7111
 
  (let ((functs (make-funct-structs names arglists)))
7112
 
    (prove-termination-with-ccg
7113
 
     names functs (t-machines-to-contexts t-machines functs)
7114
 
     ruler-extenders-lst
7115
 
     ccm-hints hierarchy verbose time-limit arglists measures t-machines
7116
 
     mp rel otf-flg bodies ctx ens wrld state nil)))
7117
 
 
7118
 
(defun-raw ccg-put-induction-info
7119
 
  (names arglists term-method measures ccms ruler-extenders-lst bodies
7120
 
         mp rel verbose time-limit hierarchy
7121
 
         hints otf-flg big-mutrec ctx ens wrld state)
7122
 
 
7123
 
; WARNING: This function installs a world.  That is safe at the time of this
7124
 
; writing because this function is only called by defuns-fn0, which is only
7125
 
; called by defuns-fn, where that call is protected by a revert-world-on-error.
7126
 
 
7127
 
; We are processing a clique of mutually recursive functions with the names,
7128
 
; arglists, measures, ruler-extenders-lst, and bodies given.  All of the above
7129
 
; lists are in 1:1 correspondence.  The hints is the result of appending
7130
 
; together all of the hints provided.  Mp and rel are the domain predicate and
7131
 
; well-founded relation to be used.  We attempt to prove the admissibility of
7132
 
; the recursions.  We cause an error if any proof fails.  We put a lot of
7133
 
; properties under the function symbols, namely:
7134
 
 
7135
 
;    recursivep                     all fns in names
7136
 
;    justification                  all recursive fns in names
7137
 
;    induction-machine              the singly recursive fn in name*
7138
 
;    quick-block-info               the singly recursive fn in name*
7139
 
;    symbol-class :ideal            all fns in names
7140
 
 
7141
 
; *If names consists of exactly one recursive fn, we store its
7142
 
; induction-machine and its quick-block-info, otherwise we do not.
7143
 
 
7144
 
; If no error occurs, we return a triple consisting of the column the printer
7145
 
; is in, the final value of wrld and a tag tree documenting the proofs we did.
7146
 
 
7147
 
; Note: The function could be declared to return 5 values, but we would rather
7148
 
; use the standard state and error primitives and so it returns 3 and lists
7149
 
; together the three "real" answers.
7150
 
 
7151
 
 (let ((wrld1 (putprop-recursivep-lst names bodies wrld)))
7152
 
 
7153
 
; The put above stores a note on each function symbol as to whether it is
7154
 
; recursive or not.  An important question arises: have we inadventently
7155
 
; assumed something axiomatically about inadmissible functions?  We say no.
7156
 
; None of the functions in question have bodies yet, so the simplifier doesn't
7157
 
; care about properties such as 'recursivep.  However, we make use of this
7158
 
; property below to decide if we need to prove termination.
7159
 
 
7160
 
    (cond ((and (null (cdr names))
7161
 
                (null (getprop (car names) 'recursivep nil
7162
 
                               'current-acl2-world wrld1)))
7163
 
 
7164
 
; If only one function is being defined and it is non-recursive, we can quit.
7165
 
; But we have to store the symbol-class and we have to print out the admission
7166
 
; message with prove-termination so the rest of our processing is uniform.
7167
 
           
7168
 
           (er-let*
7169
 
            ((tuple (prove-termination-non-recursive names bodies mp rel hints otf-flg big-mutrec
7170
 
                                                     ctx ens wrld1 state)))
7171
 
            (value (cons nil tuple))))
7172
 
          (t
7173
 
           (let ((t-machines (termination-machines names bodies ruler-extenders-lst)))
7174
 
             (er-let*
7175
 
              ((wrld1 (update-w
7176
 
                               
7177
 
; Sol Swords sent an example in which a clause-processor failed during a
7178
 
; termination proof.  That problem goes away if we install the world, which we
7179
 
; do by making the following binding.
7180
 
 
7181
 
                       t ; formerly big-mutrec
7182
 
                       wrld1))
7183
 
              (quadruple
7184
 
               (if (eq term-method :measure)
7185
 
                   (er-let* ((triple (prove-termination-recursive
7186
 
                                      names arglists
7187
 
                                      measures
7188
 
                                      t-machines
7189
 
                                      mp rel hints otf-flg bodies
7190
 
                                      ctx ens wrld1 state)))
7191
 
                     (value (cons :measure triple)))
7192
 
                 (ccg-prove-termination-recursive names arglists
7193
 
                                                  measures
7194
 
                                                  ccms
7195
 
                                                  ruler-extenders-lst
7196
 
                                                  t-machines
7197
 
                                                  mp rel 
7198
 
                                                  verbose
7199
 
                                                  time-limit
7200
 
                                                  hierarchy
7201
 
                                                  otf-flg bodies
7202
 
                                                  ctx ens wrld1 state))))
7203
 
                ;;(progn
7204
 
                  ;;(print quadruple)
7205
 
               (let* ((term-method (car quadruple))
7206
 
                      (col (cadr quadruple))
7207
 
                      (measure-alist (caddr quadruple))
7208
 
                      (ttree (cdddr quadruple)))
7209
 
                 (er-let*
7210
 
                     ((tuple (put-induction-info-recursive names arglists
7211
 
                                                           col ttree
7212
 
                                                           measure-alist t-machines
7213
 
                                                           ruler-extenders-lst
7214
 
                                                           bodies mp rel wrld1
7215
 
                                                           state)))
7216
 
                   (value (cons term-method tuple))))))))))
7217
 
 
7218
 
(defun defun-redundant-get-ccms (fives wrld)
7219
 
  ;; gets the CCMs installed into the world for a given set of function definitions.
7220
 
  (if (endp fives)
7221
 
      nil
7222
 
    (let ((subset (access justification
7223
 
                          (getprop (first (car fives))
7224
 
                                   'justification
7225
 
                                   (make justification :subset '())
7226
 
                                   'current-acl2-world
7227
 
                                   wrld)
7228
 
                          :subset)))
7229
 
      (cons `((:? ,@subset))
7230
 
            (defun-redundant-get-ccms (cdr fives) wrld)))))
7231
 
 
7232
 
 
7233
 
(defun defun-redundant-get-measures (fives wrld)
7234
 
  ;; gets the CCMs installed into the world for a given set of function definitions.
7235
 
  (if (endp fives)
7236
 
      nil
7237
 
    (let ((subset (access justification
7238
 
                          (getprop (first (car fives))
7239
 
                                   'justification
7240
 
                                   (make justification :subset '())
7241
 
                                   'current-acl2-world
7242
 
                                   wrld)
7243
 
                          :subset)))
7244
 
      (cons `(:? ,@subset)
7245
 
            (defun-redundant-get-measures (cdr fives) wrld)))))
7246
 
 
7247
 
(defun remove-keywords (keys lst)
7248
 
  (cond ((endp lst)
7249
 
         nil)
7250
 
        ((member-eq (car lst) keys)
7251
 
         (remove-keywords keys (cddr lst)))
7252
 
        (t
7253
 
         (list* (car lst) (cadr lst) (remove-keywords keys (cddr lst))))))
7254
 
    
7255
 
(defun remove-dcls0 (edcls keys)
7256
 
  (cond ((endp edcls) nil) ;; if we don't have any xargs, we don't need to do anything.
7257
 
        ((eq (caar edcls) 'xargs)
7258
 
         (let ((newlst (remove-keywords keys (cdar edcls))))
7259
 
           (if (endp newlst)
7260
 
               (remove-dcls0 (cdr edcls) keys)
7261
 
             (acons 'xargs 
7262
 
                    newlst
7263
 
                    (remove-dcls0 (cdr edcls) keys)))))
7264
 
        (t (cons (car edcls)
7265
 
                 (remove-dcls0 (cdr edcls) keys)))))
7266
 
 
7267
 
(defun remove-dcls (fives keys)
7268
 
  ;; we alter the definitions given in fives to remove xarg
7269
 
  ;; declarations corresponding to the given keys
7270
 
  (cond ((endp fives)
7271
 
         nil)
7272
 
        ((endp (nth 3 (car fives))) ;; if there are no declarations, there is nothing to do.
7273
 
         (cons (car fives)
7274
 
               (remove-dcls (cdr fives) keys)))
7275
 
        (t
7276
 
         (cons (update-nth 3 (remove-dcls0 (nth 3 (car fives)) keys) (car fives))
7277
 
               (remove-dcls (cdr fives) keys)))))
7278
 
 
7279
 
(defun update-keyword (key val lst)
7280
 
  (cond ((endp lst)
7281
 
         (list key val))
7282
 
        ((eq (car lst) key)
7283
 
         (cons key (cons val (remove-keywords `(,key) (cddr lst)))))
7284
 
        (t
7285
 
         (cons (car lst)
7286
 
               (cons (cadr lst) 
7287
 
                     (update-keyword key val (cddr lst)))))))
7288
 
 
7289
 
(defun unambiguously-fix-dcls0 (edcls key val)
7290
 
  (cond ((endp edcls)
7291
 
         (list (cons 'xargs (list key val))))
7292
 
        ((eq (caar edcls) 'xargs)
7293
 
         (acons 'xargs (update-keyword key val (cdar edcls))
7294
 
                (remove-dcls0 (cdr edcls) `(,key))))
7295
 
        (t
7296
 
         (cons (car edcls)
7297
 
               (unambiguously-fix-dcls0 (cdr edcls) key val)))))
7298
 
 
7299
 
(defun unambiguously-fix-dcls (fives key vals)
7300
 
  ;; we alter the definitions given in fives to declare key to be of
7301
 
  ;; vals, such that the ith definition in fives has key set to the
7302
 
  ;; ith value of vals.
7303
 
  (cond ((endp fives)
7304
 
         nil)
7305
 
        (t
7306
 
         (cons (update-nth 3 (unambiguously-fix-dcls0 (nth 3 (car fives)) key (car vals))
7307
 
                           (car fives))
7308
 
               (unambiguously-fix-dcls (cdr fives) key (cdr vals))))))
7309
 
 
7310
 
(defun app-lst (lst)
7311
 
  ;; appends all the elements of lst together.
7312
 
  (if (endp lst)
7313
 
      nil
7314
 
    (append (car lst) (app-lst (cdr lst)))))
7315
 
   
7316
 
(defun fives-to-defuns0 (fives)
7317
 
  (if (endp fives)
7318
 
      nil
7319
 
    (let* ((five (car fives))
7320
 
           (name (first five))
7321
 
           (args (second five))
7322
 
           (doc (third five))
7323
 
           (dcls (fourth five))
7324
 
           (body (fifth five))
7325
 
           (d1 (list body))
7326
 
           (d2 (if doc (cons doc d1) d1))
7327
 
           (d3 (if dcls (acons 'declare dcls d2) d2)))
7328
 
      (cons `(defun ,name ,args ,@d3)
7329
 
            (fives-to-defuns0 (cdr fives))))))
7330
 
 
7331
 
(defun fives-to-defuns (fives)
7332
 
  ;; turns a list of "fives" into defuns from which such "fives" would
7333
 
  ;; be derived.
7334
 
  `(with-output
7335
 
    :off (summary event)
7336
 
    ,(if (endp (cdr fives))
7337
 
         (car (fives-to-defuns0 fives))
7338
 
       (cons 'mutual-recursion
7339
 
             (fives-to-defuns0 fives)))))
7340
 
 
7341
 
 
7342
 
;; END raw definitions for CCG analysis
7343
 
 
7344
 
 
7345
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7346
 
;
7347
 
; These support optional make-event expansion by events other than make-event.
7348
 
; -Peter Dillinger
7349
 
 
7350
 
(defun dynamic-make-event-fn (body event-form state)
7351
 
;;  (declare (xargs :mode :program))
7352
 
  (make-event-fn `',body
7353
 
                 nil
7354
 
                 nil
7355
 
                 nil
7356
 
                 event-form
7357
 
                 state))
7358
 
 
7359
 
;
7360
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7361
 
 
7362
 
(defun defun-make-event (names fives symbol-class term-method wrld event-form state)
7363
 
  (if (or (eq symbol-class :program)
7364
 
          (and (null (cdr names))
7365
 
               (null (getprop (car names) 'recursivep nil
7366
 
                              'current-acl2-world wrld))))
7367
 
      (value (cond ((null (cdr names)) (car names))
7368
 
                   (t names)))
7369
 
    (let* ((fives0 (remove-dcls fives 
7370
 
                                (if (eq term-method :measure)
7371
 
                                    *ccg-xargs-keywords*
7372
 
                                  (list* :HINTS
7373
 
                                         :MEASURE
7374
 
                                         :WELL-FOUNDED-RELATION
7375
 
                                         *ccg-xargs-keywords*))))
7376
 
           (fives1 (unambiguously-fix-dcls fives0 :termination-method
7377
 
                                           (make-list (length fives)
7378
 
                                                      :initial-element :measure)))
7379
 
           (fives2 (if (eq term-method :measure)
7380
 
                       fives1
7381
 
                     (unambiguously-fix-dcls
7382
 
                      fives1
7383
 
                      :MEASURE
7384
 
                      (defun-redundant-get-measures fives wrld)))))
7385
 
      (er-progn
7386
 
       (state-global-let* ((accumulated-ttree nil)
7387
 
                           (inhibit-output-lst (cons 'summary (@ inhibit-output-lst))))
7388
 
                          (dynamic-make-event-fn (fives-to-defuns fives2)
7389
 
                                                 event-form
7390
 
                                                 state))
7391
 
       (value (cond ((null (cdr names)) (car names))
7392
 
                    (t names)))))))
7393
 
 
7394
 
; defines a function to bridge ACL2 and raw lisp.  if you ask ACL2 what its
7395
 
; definition is, it will say "(value nil)," but if you run it, you get the
7396
 
; behavior of the raw body.  there are no soundness issues with that because
7397
 
; the function is flagged as permanently :program-mode only.
7398
 
;
7399
 
; defun-bridge is provided by my hacker stuff. -Peter
7400
 
 
7401
 
; June 16 2013 - ccg.lisp certification breaks with ACL2 6.2
7402
 
; Keep this function and defuns-fn1 call in sync in ACL2 sources - harshrc
7403
 
 
7404
 
(defun-raw ccg-defuns-fn0
7405
 
 
7406
 
; WARNING: This function installs a world.  That is safe at the time of this
7407
 
; writing because this function is only called by defuns-fn, where that call is
7408
 
; protected by a revert-world-on-error.
7409
 
 
7410
 
  (names arglists docs pairs guards term-method measures 
7411
 
         ccms ;ccg
7412
 
         ruler-extenders-lst mp rel
7413
 
         verbose time-limit hierarchy ;ccg
7414
 
         hints guard-hints std-hints 
7415
 
         otf-flg guard-debug bodies symbol-class normalizeps 
7416
 
         split-types-terms non-executablep 
7417
 
         #+:non-standard-analysis std-p 
7418
 
         ctx wrld state)
7419
 
  (cond
7420
 
   ((eq symbol-class :program)
7421
 
    (defuns-fn-short-cut names docs pairs guards split-types-terms bodies
7422
 
      non-executablep ; not sure about this, but seems plausible
7423
 
      wrld state))
7424
 
   (t
7425
 
    (let ((ens (ens state))
7426
 
          (big-mutrec (big-mutrec names)))
7427
 
      (er-let*
7428
 
       ((tuple (ccg-put-induction-info names arglists
7429
 
                                       term-method ;ccg specific
7430
 
                                       measures
7431
 
                                       ccms ;ccg
7432
 
                                       ruler-extenders-lst
7433
 
                                       bodies
7434
 
                                       mp rel
7435
 
                                       verbose ;ccg
7436
 
                                       time-limit ;ccg
7437
 
                                       hierarchy ;ccg
7438
 
                                       hints
7439
 
                                       otf-flg
7440
 
                                       big-mutrec
7441
 
                                       ctx ens wrld state)))
7442
 
       (defuns-fn1
7443
 
         (cdr tuple) ;(car tuple) is term-method
7444
 
         ens
7445
 
         big-mutrec
7446
 
         names
7447
 
         arglists
7448
 
         docs
7449
 
         pairs
7450
 
         guards
7451
 
         guard-hints
7452
 
         std-hints
7453
 
         otf-flg
7454
 
         guard-debug
7455
 
         bodies
7456
 
         symbol-class
7457
 
         normalizeps
7458
 
         split-types-terms
7459
 
         non-executablep
7460
 
         #+:non-standard-analysis std-p
7461
 
         ctx
7462
 
         state))))))
7463
 
 
7464
 
(defun-bridge ccg-defuns-fn (def-lst state event-form #+:non-standard-analysis std-p)
7465
 
 
7466
 
; Important Note:  Don't change the formals of this function without
7467
 
; reading the *initial-event-defmacros* discussion in axioms.lisp.
7468
 
 
7469
 
; On Guards
7470
 
 
7471
 
; When a function symbol fn is defund the user supplies a guard, g, and a
7472
 
; body b.  Logically speaking, the axiom introduced for fn is
7473
 
 
7474
 
;    (fn x1...xn) = b.  
7475
 
 
7476
 
; After admitting fn, the guard-related properties are set as follows:
7477
 
 
7478
 
; prop                after defun
7479
 
 
7480
 
; body                   b*
7481
 
; guard                  g
7482
 
; unnormalized-body      b
7483
 
; type-prescription      computed from b
7484
 
; symbol-class           :ideal
7485
 
 
7486
 
; * We actually normalize the above.  During normalization we may expand some
7487
 
; boot-strap non-rec fns.
7488
 
 
7489
 
; In addition, we magically set the symbol-function of fn
7490
 
 
7491
 
; symbol-function        b
7492
 
 
7493
 
; and the symbol-function of *1*fn as a program which computes the logical
7494
 
; value of (fn x).  However, *1*fn is quite fancy because it uses the raw body
7495
 
; in the symbol-function of fn if fn is :common-lisp-compliant, and may signal
7496
 
; a guard error if 'guard-checking-on is set to other than nil or :none.  See
7497
 
; oneify-cltl-code for the details.
7498
 
 
7499
 
; Observe that the symbol-function after defun may be a form that
7500
 
; violates the guards on primitives.  Until the guards in fn are
7501
 
; checked, we cannot let raw Common Lisp evaluate fn.
7502
 
 
7503
 
; Intuitively, we think of the Common Lisp programmer intending to defun (fn
7504
 
; x1...xn) to be b, and is declaring that the raw fn can be called only on
7505
 
; arguments satisfying g.  The need for guards stems from the fact that there
7506
 
; are many Common Lisp primitives, such as car and cdr and + and *, whose
7507
 
; behavior outside of their guarded domains is unspecified.  To use these
7508
 
; functions in the body of fn one must "guard" fn so that it is never called in
7509
 
; a way that would lead to the violation of the primitive guards.  Thus, we
7510
 
; make a formal precondition on the use of the Common Lisp program fn that the
7511
 
; guard g, along with the tests along the various paths through body b, imply
7512
 
; each of the guards for every subroutine in b.  We also require that each of
7513
 
; the guards in g be satisfied.  This is what we mean when we say fn is
7514
 
; :common-lisp-compliant.
7515
 
 
7516
 
; It is, however, often impossible to check the guards at defun time.  For
7517
 
; example, if fn calls itself recursively and then gives the result to +, we
7518
 
; would have to prove that the guard on + is satisfied by fn's recursive
7519
 
; result, before we admit fn.  In general, induction may be necessary to
7520
 
; establish that the recursive calls satisfy the guards of their masters;
7521
 
; hence, it is probably also necessary for the user to formulate general lemmas
7522
 
; about fn to establish those conditions.  Furthermore, guard checking is no
7523
 
; longer logically necessary and hence automatically doing it at defun time may
7524
 
; be a waste of time.
7525
 
 
7526
 
  :program (value nil)
7527
 
  :raw
7528
 
  (with-ctx-summarized
7529
 
   (defun-ctx def-lst state event-form #+:non-standard-analysis std-p)
7530
 
   (let ((wrld (w state)) 
7531
 
         (def-lst0
7532
 
           #+:non-standard-analysis
7533
 
           (if std-p
7534
 
               (non-std-def-lst def-lst)
7535
 
             def-lst)
7536
 
           #-:non-standard-analysis
7537
 
           def-lst)
7538
 
         (event-form (or event-form (list 'defuns def-lst))))
7539
 
     (revert-world-on-error
7540
 
      (er-let*
7541
 
       ((tuple (ccg-chk-acceptable-defuns def-lst ctx wrld state
7542
 
                                          #+:non-standard-analysis std-p)))
7543
 
 
7544
 
; Chk-acceptable-defuns puts the 'formals, 'stobjs-in and 'stobjs-out
7545
 
; properties (which are necessary for the translation of the bodies).
7546
 
; All other properties are put by the defuns-fn0 call below.
7547
 
 
7548
 
       (cond
7549
 
        ((eq tuple 'redundant)
7550
 
         (stop-redundant-event ctx state))
7551
 
        (t
7552
 
         (enforce-redundancy
7553
 
          event-form ctx wrld
7554
 
          (let ((term-method (nth 1 tuple))
7555
 
                (names (nth 2 tuple))
7556
 
                (arglists (nth 3 tuple))
7557
 
                (docs (nth 4 tuple))
7558
 
                (pairs (nth 5 tuple))
7559
 
                (guards (nth 6 tuple))
7560
 
                (measures (nth 7 tuple))
7561
 
                (ruler-extenders-lst (nth 8 tuple))
7562
 
                (mp (nth 9 tuple))
7563
 
                (rel (nth 10 tuple))
7564
 
                (hints (nth 11 tuple))
7565
 
                (guard-hints (nth 12 tuple))
7566
 
                (std-hints (nth 13 tuple))
7567
 
                (otf-flg (nth 14 tuple))
7568
 
                (bodies (nth 15 tuple))
7569
 
                (symbol-class (nth 16 tuple))
7570
 
                (normalizeps (nth 17 tuple))
7571
 
                (reclassifyingp (nth 18 tuple))
7572
 
                (wrld (nth 19 tuple))
7573
 
                (non-executablep (nth 20 tuple))
7574
 
                (guard-debug (nth 21 tuple))
7575
 
                (split-types-terms (nth 22 tuple))
7576
 
                (ccms (nth 23 tuple))
7577
 
                (verbose (nth 24 tuple))
7578
 
                (time-limit (nth 25 tuple))
7579
 
                (hierarchy (nth 26 tuple)))
7580
 
            (er-let*
7581
 
             ((pair (ccg-defuns-fn0
7582
 
                     names
7583
 
                     arglists
7584
 
                     docs
7585
 
                     pairs
7586
 
                     guards
7587
 
                     term-method
7588
 
                     measures
7589
 
                     ccms
7590
 
                     ruler-extenders-lst
7591
 
                     mp
7592
 
                     rel
7593
 
                     verbose
7594
 
                     time-limit
7595
 
                     hierarchy
7596
 
                     hints
7597
 
                     guard-hints
7598
 
                     std-hints
7599
 
                     otf-flg
7600
 
                     guard-debug
7601
 
                     bodies
7602
 
                     symbol-class
7603
 
                     normalizeps
7604
 
                     split-types-terms
7605
 
                     non-executablep
7606
 
                     #+:non-standard-analysis std-p
7607
 
                     ctx
7608
 
                     wrld
7609
 
                     state)))
7610
 
 
7611
 
; Triple is of the form (term-method wrld . ttree), where term-method is the
7612
 
; actual termination method used to prove termination.
7613
 
; Pair is of the form (wrld . ttree).
7614
 
 
7615
 
             ;;--harshrc: As Daron says (where?), I changed code, to force checking a nil ttree
7616
 
             ;;but ideally we shud accumulate all successful ttrees.
7617
 
 
7618
 
             (er-progn
7619
 
              (chk-assumption-free-ttree nil;(cdr pair)
7620
 
                                         ctx state)
7621
 
 
7622
 
              (install-event-defuns names event-form def-lst0 symbol-class
7623
 
                                    reclassifyingp non-executablep pair ctx wrld
7624
 
                                    state)
7625
 
              (if (or (eq symbol-class :program)
7626
 
                      (ld-skip-proofsp state)
7627
 
                      (and (null (cdr names))
7628
 
                           (null (getprop (car names)
7629
 
                                          'recursivep
7630
 
                                          nil
7631
 
                                          'current-acl2-world
7632
 
                                          wrld))))
7633
 
                  (value (cond ((null (cdr names)) (car names))
7634
 
                               (t names)))
7635
 
                (er-let* ((fives (chk-defuns-tuples def-lst nil ctx wrld state)))
7636
 
                  (defun-make-event
7637
 
                    names fives symbol-class term-method
7638
 
                    (car pair) event-form state))))))))))))))
7639
 
 
7640
 
; redefine defuns-fn to "be" (call) ccg-defuns-fn.
7641
 
;
7642
 
; redefun is provided by my hacker stuff. -Peter
7643
 
 
7644
 
(redefun defuns-fn (def-lst state event-form #+:non-standard-analysis std-p)
7645
 
         (ccg-defuns-fn def-lst state event-form #+:non-standard-analysis std-p))
7646
 
 
7647
 
(progn+touchable
7648
 
 :all
7649
 
 (redefun+rewrite
7650
 
  defstobj-fn
7651
 
  (:carpat (process-embedded-events %1%
7652
 
                                    %2%
7653
 
                                    %3%
7654
 
                                    %4%
7655
 
                                    %5%
7656
 
                                    (append
7657
 
                                     . %app-cdr%)
7658
 
                                    . %pee-cdr%)
7659
 
           :repl (process-embedded-events %1%
7660
 
                                          %2%
7661
 
                                          %3%
7662
 
                                          %4%
7663
 
                                          %5%
7664
 
                                          (append
7665
 
                                           '((set-termination-method :measure))
7666
 
                                           . %app-cdr%)
7667
 
                                          . %pee-cdr%)
7668
 
           :vars (%1% %2% %3% %4% %5% %app-cdr% %pee-cdr%)
7669
 
           :mult 1)))
7670