Included Books
other
(in-package "ACL2")
other
(defttag :ccg)
include-book
(include-book "misc/expander" :dir :system)
include-book
(include-book "acl2s/acl2s-size" :dir :system)
include-book
(include-book "hacking/hacker" :dir :system)
other
(progn+all-ttags-allowed (include-book "hacking/all" :dir :system :ttags :all))
other
(subsume-ttags-since-defttag)
fix-intern$macro
(defmacro fix-intern$ (name pkg) `(intern$ ,NAME (fix-pkg ,PKG)))
other
(add-acl2-defaults-table-key :termination-method (member-eq val '(:measure :ccg)))
get-termination-methodfunction
(defun get-termination-method (wrld) (declare (xargs :guard (and (plist-worldp wrld) (alistp (table-alist 'acl2-defaults-table wrld))))) (let ((entry (assoc :termination-method (table-alist 'acl2-defaults-table wrld)))) (or (and entry (cdr entry)) :measure)))
other
(verify-guards get-termination-method)
hlevel-proof-techniquemacro
(defmacro hlevel-proof-technique (hlevel) `(car ,HLEVEL))
hlevel-ccm-comparison-schememacro
(defmacro hlevel-ccm-comparison-scheme (hlevel) `(cadr ,HLEVEL))
hlevel-ccmfs-per-nodepmacro
(defmacro hlevel-ccmfs-per-nodep (hlevel) `(caddr ,HLEVEL))
make-hlevelmacro
(defmacro make-hlevel (pt ccm-cs cpn) `(list ,PT ,CCM-CS ,CPN))
proof-techniquepfunction
(defun proof-techniquep (pt) (declare (xargs :guard t)) (or (and (keywordp pt) (eq pt :built-in-clauses)) (and (consp pt) (keywordp (car pt)) (eq (car pt) :induction-depth) (consp (cdr pt)) (natp (cadr pt)) (null (cddr pt)))))
hlevelpfunction
(defun hlevelp (hlevel) (declare (xargs :guard t)) (and (consp hlevel) (or (and (keywordp (car hlevel)) (eq (car hlevel) :measure) (consp (cdr hlevel)) (proof-techniquep (cadr hlevel)) (null (cddr hlevel))) (and (proof-techniquep (car hlevel)) (consp (cdr hlevel)) (member-eq (cadr hlevel) '(:equal :all :some :none)) (consp (cddr hlevel)) (booleanp (caddr hlevel)) (null (cdddr hlevel))))))
hlevel-listpfunction
(defun hlevel-listp (lst) (declare (xargs :guard t)) (if (consp lst) (and (hlevelp (car lst)) (hlevel-listp (cdr lst))) (null lst)))
non-empty-hlevel-listpfunction
(defun non-empty-hlevel-listp (lst) (declare (xargs :guard t)) (and (consp lst) (hlevel-listp lst)))
hlevel<function
(defun hlevel< (hlevel0 hlevel1) (declare (xargs :guard (and (hlevelp hlevel0) (not (equal (car hlevel0) :measure)) (hlevelp hlevel1) (not (equal (car hlevel1) :measure))))) (let ((pt0 (hlevel-proof-technique hlevel0)) (ccm-cs0 (hlevel-ccm-comparison-scheme hlevel0)) (cpn0 (hlevel-ccmfs-per-nodep hlevel0)) (pt1 (hlevel-proof-technique hlevel1)) (ccm-cs1 (hlevel-ccm-comparison-scheme hlevel1)) (cpn1 (hlevel-ccmfs-per-nodep hlevel1))) (or (and cpn0 (not cpn1)) (and (not (equal pt1 :built-in-clauses)) (or (equal pt0 :built-in-clauses) (< (cadr pt0) (cadr pt1)))) (let ((ccm-cs-vals '((:equal . 0) (:all . 1) (:some . 2) (:none . 3)))) (< (cdr (assoc ccm-cs0 ccm-cs-vals)) (cdr (assoc ccm-cs1 ccm-cs-vals)))))))
other
(rewrite-table-guard acl2-defaults-table (:carpat %body% :vars %body% :repl (if (eq key :ccg-hierarchy) (non-empty-hlevel-listp val) %body%)))
fix-ccg-hierarchyfunction
(defun fix-ccg-hierarchy (hierarchy) (declare (xargs :guard (or (consp hierarchy) (and (symbolp hierarchy) (member-eq hierarchy '(:ccg-only :ccg-only-cpn :hybrid :hybrid-cpn)))))) (if (consp hierarchy) hierarchy (case hierarchy (:ccg-only '((:built-in-clauses :equal t) ((:induction-depth 0) :equal t) ((:induction-depth 1) :equal t) ((:induction-depth 1) :all t) ((:induction-depth 1) :some t) ((:induction-depth 1) :none t) ((:induction-depth 1) :equal nil) ((:induction-depth 1) :all nil) ((:induction-depth 1) :some nil) ((:induction-depth 1) :none nil))) (:ccg-only-cpn '((:built-in-clauses :equal t) ((:induction-depth 0) :equal t) ((:induction-depth 1) :equal t) ((:induction-depth 1) :all t) ((:induction-depth 1) :some t) ((:induction-depth 1) :none t))) (:hybrid '((:built-in-clauses :equal t) (:measure (:induction-depth 1)) ((:induction-depth 0) :equal t) ((:induction-depth 1) :equal t) ((:induction-depth 1) :all t) ((:induction-depth 1) :some t) ((:induction-depth 1) :none t) ((:induction-depth 1) :equal nil) ((:induction-depth 1) :all nil) ((:induction-depth 1) :some nil) ((:induction-depth 1) :none nil))) (:hybrid-cpn '((:built-in-clauses :equal t) (:measure (:induction-depth 1)) ((:induction-depth 0) :equal t) ((:induction-depth 1) :equal t) ((:induction-depth 1) :all t) ((:induction-depth 1) :some t) ((:induction-depth 1) :none t))) (otherwise nil))))
get-ccg-hierarchyfunction
(defun get-ccg-hierarchy (wrld) (declare (xargs :guard (and (plist-worldp wrld) (alistp (table-alist 'acl2-defaults-table wrld))))) (let ((entry (assoc :ccg-hierarchy (table-alist 'acl2-defaults-table wrld)))) (if (null entry) (fix-ccg-hierarchy :ccg-only) (cdr entry))))
other
(set-state-ok t)
other
(program)
chk-ccg-hierarchy1function
(defun chk-ccg-hierarchy1 (hierarchy cpn ctx state) (cond ((endp hierarchy) (value nil)) ((not (hlevelp (car hierarchy))) (er soft ctx "Each element of a CCG-HIERARCHY must either have the form (PT ~ CCM-CS CPN) or (:MEASURE PT), where PT is either ~ :BUILT-IN-CLAUSES or (:INDUCTION-DEPTH N) for some natural ~ number, N, CCM-CS is one of :EQUAL, :ALL, :SOME, :NONE, and CPN ~ is either T or NIL. ~x0 does not match this form." (car hierarchy))) ((and (not cpn) (not (equal (caar hierarchy) :measure)) (hlevel-ccmfs-per-nodep (car hierarchy))) (er soft ctx "It is not permitted that a level of a CCG-HIERARCHY have a ~ CCCMFs-per-nodep of T when a previous level had a ~ CCMFs-per-nodep of NIL. But this is the case with level ~x0." (car hierarchy))) (t (chk-ccg-hierarchy1 (cdr hierarchy) (if (equal (caar hierarchy) :measure) cpn (hlevel-ccmfs-per-nodep (car hierarchy))) ctx state))))
chk-measure-hlevel<-allfunction
(defun chk-measure-hlevel<-all (hlevel0 hierarchy ctx state) (cond ((endp hierarchy) (value nil)) ((or (not (equal (caar hierarchy) :measure)) (and (consp (cadar hierarchy)) (or (atom (cadr hlevel0)) (< (cadadr hlevel0) (cadadr (car hierarchy)))))) (chk-measure-hlevel<-all hlevel0 (cdr hierarchy) ctx state)) (t (er soft ctx "Each :MEASURE level of a CCG-HIERARCHY should use strictly more ~ powerful proof techniques than all those that come before it. ~ However, the ~x0 level is subsumed by the earlier level, ~x1." (car hierarchy) hlevel0))))
chk-hlevel<-allfunction
(defun chk-hlevel<-all (hlevel0 hierarchy ctx state) (cond ((endp hierarchy) (value nil)) ((or (equal (caar hierarchy) :measure) (hlevel< hlevel0 (car hierarchy))) (chk-hlevel<-all hlevel0 (cdr hierarchy) ctx state)) (t (er soft ctx "Each level of a CCG-HIERARCHY should be strictly more powerful ~ than all the previous levels. That is, it should always be ~ possible to refine the CCG or CCMF information at each step in ~ the hierarchy. However, the ~x0 level is subsumed by the ~ earlier level, ~x1." (car hierarchy) hlevel0))))
chk-hierarchy-strictly-increasingfunction
(defun chk-hierarchy-strictly-increasing (hierarchy ctx state) (if (endp hierarchy) (value nil) (er-progn (cond ((equal (caar hierarchy) :measure) (chk-measure-hlevel<-all (car hierarchy) (cdr hierarchy) ctx state)) (t (chk-hlevel<-all (car hierarchy) (cdr hierarchy) ctx state))) (chk-hierarchy-strictly-increasing (cdr hierarchy) ctx state))))
chk-ccg-hierarchyfunction
(defun chk-ccg-hierarchy (hierarchy ctx state) (cond ((and (symbolp hierarchy) (member-eq hierarchy '(:ccg-only :ccg-only-cpn :hybrid :hybrid-cpn))) (value nil)) ((and (consp hierarchy) (true-listp hierarchy)) (er-progn (chk-ccg-hierarchy1 hierarchy t ctx state) (chk-hierarchy-strictly-increasing hierarchy ctx state))) (t (er soft ctx "A CCG-HIERARCHY must be :CCG-ONLY, :CCG-ONLY-CPN, :HYBRID, ~ :HYBRID-CPN, or a non-empty true-list. ~x0 does not have ~ this form." hierarchy))))
set-ccg-hierarchymacro
(defmacro set-ccg-hierarchy (v) `(er-progn (chk-ccg-hierarchy ',V "SET-CCG-HIERARCHY" state) (with-output :off summary (progn (table acl2-defaults-table ':ccg-hierarchy ',(FIX-CCG-HIERARCHY V)) (table acl2-defaults-table ':ccg-hierarchy)))))
other
(logic)
other
(set-state-ok nil)
get-ccg-time-limitfunction
(defun get-ccg-time-limit (wrld) (declare (xargs :guard (and (plist-worldp wrld) (alistp (table-alist 'acl2-defaults-table wrld))))) (let ((entry (assoc :ccg-time-limit (table-alist 'acl2-defaults-table wrld)))) (or (and entry (cdr entry)) nil)))
other
(verify-guards get-ccg-time-limit)
set-ccg-print-proofsmacro
(defmacro set-ccg-print-proofs (v) `(assign ccg-print-proofs ,V))
get-ccg-print-proofsmacro
(defmacro get-ccg-print-proofs nil '(and (f-boundp-global 'ccg-print-proofs state) (f-get-global 'ccg-print-proofs state)))
*ccg-window-descriptions*constant
(defconst *ccg-window-descriptions* '((query "4" nil nil nil) (basics "4" nil nil nil) (performance "4" nil nil nil) (build/refine "4" nil nil nil) (size-change "4" nil nil nil) (counter-example "4" nil nil nil)))
*ccg-valid-output-names*constant
(defconst *ccg-valid-output-names* '(query basics performance build/refine size-change counter-example))
set-ccg-inhibit-output-lstmacro
(defmacro set-ccg-inhibit-output-lst (lst) `(let ((lst ,LST)) (cond ((not (true-listp lst)) (er soft 'set-ccg-inhibit-output-lst "The argument to set-ccg-inhibit-output-lst must evaluate to a ~ true-listp, unlike ~x0." lst)) ((not (subsetp-eq lst *ccg-valid-output-names*)) (er soft 'set-ccg-inhibit-output-lst "The argument to set-ccg-inhibit-output-lst must evalutate to a ~ subset of the list ~X01, but ~x2 contains ~&3." *ccg-valid-output-names* nil ',LST (set-difference-eq lst *ccg-valid-output-names*))) (t (pprogn (f-put-global 'ccg-inhibit-output-lst lst state) (value lst))))))
get-ccg-inhibit-output-lstmacro
(defmacro get-ccg-inhibit-output-lst nil '(if (f-boundp-global 'ccg-inhibit-output-lst state) (f-get-global 'ccg-inhibit-output-lst state) '(query performance build/refine size-change)))
other
(program)
other
(set-state-ok t)
ccg-io?macro
(defmacro ccg-io? (token commentp shape vars body &key (clear 'nil clear-argp) (cursor-at-top 'nil cursor-at-top-argp) (pop-up 'nil pop-up-argp) (default-bindings 'nil) (chk-translatable 't)) (declare (xargs :guard (and (symbolp token) (symbol-listp vars) (no-duplicatesp vars) (not (member-eq 'state vars)) (assoc-eq token *ccg-window-descriptions*)))) (let* ((associated-window (assoc-eq token *ccg-window-descriptions*)) (expansion `(let* ((io?-output-inhibitedp (member-eq ',TOKEN (get-ccg-inhibit-output-lst))) (io?-alist (and (not io?-output-inhibitedp) (list (cons #\w ,(CADR ASSOCIATED-WINDOW)) (cons #\c ,(IF CLEAR-ARGP CLEAR (CADDR ASSOCIATED-WINDOW))) (cons #\t ,(IF CURSOR-AT-TOP-ARGP CURSOR-AT-TOP (CADDDR ASSOCIATED-WINDOW))) (cons #\p ,(IF POP-UP-ARGP POP-UP (CAR (CDDDDR ASSOCIATED-WINDOW)))) (cons #\k ,(SYMBOL-NAME TOKEN)))))) (pprogn (if (or io?-output-inhibitedp (null (f-get-global 'window-interfacep state))) state (mv-let (io?-col state) (fmt1! (f-get-global 'window-interface-prelude state) io?-alist 0 *standard-co* state nil) (declare (ignore io?-col)) state)) ,(LET ((BODY `(CHECK-VARS-NOT-FREE (IO?-OUTPUT-INHIBITEDP IO?-ALIST) (CHECK-EXACT-FREE-VARS IO? (STATE ,@VARS) ,BODY))) (NIL-OUTPUT (IF (EQ SHAPE 'STATE) 'STATE (CONS 'MV (IO?-NIL-OUTPUT (CDR SHAPE) DEFAULT-BINDINGS)))) (POSTLUDE `(MV-LET (IO?-COL STATE) (IF (OR IO?-OUTPUT-INHIBITEDP (NULL (F-GET-GLOBAL 'WINDOW-INTERFACEP STATE))) (MV 0 STATE) (FMT1! (F-GET-GLOBAL 'WINDOW-INTERFACE-POSTLUDE STATE) IO?-ALIST 0 *STANDARD-CO* STATE NIL)) (DECLARE (IGNORE IO?-COL)) (CHECK-VARS-NOT-FREE (IO?-OUTPUT-INHIBITEDP IO?-ALIST IO?-COL) ,SHAPE)))) (LET ((BODY (IF COMMENTP `(LET ,(IO?-WORMHOLE-BINDINGS 0 VARS) ,BODY) BODY))) (COND ((EQ SHAPE 'STATE) `(PPROGN (IF IO?-OUTPUT-INHIBITEDP STATE ,BODY) ,POSTLUDE)) (T `(MV-LET ,(CDR SHAPE) (IF IO?-OUTPUT-INHIBITEDP ,NIL-OUTPUT ,BODY) ,POSTLUDE))))))))) (cond (commentp (let ((form (cond ((eq shape 'state) `(pprogn ,EXPANSION (value :q))) (t `(mv-let ,(CDR SHAPE) ,EXPANSION (declare (ignore ,@(REMOVE1-EQ 'STATE (CDR SHAPE)))) (value :q)))))) `(prog2$ ,(IF CHK-TRANSLATABLE `(CHK-TRANSLATABLE ,BODY ,SHAPE) NIL) (wormhole 'comment-window-io '(lambda (whs) (set-wormhole-entry-code whs :enter)) (list ,@VARS) ',FORM :ld-error-action :return! :ld-verbose nil :ld-pre-eval-print nil :ld-prompt nil)))) (t `(pprogn (cond ((saved-output-token-p ',TOKEN state) (push-io-record nil (list 'let (list ,@(FORMAL-BINDINGS VARS)) ',EXPANSION) state)) (t state)) ,EXPANSION)))))
other
(defstruct-raw funct (fn nil :type symbol) (formals nil :type list) (ccms nil :type sequence))
other
(defstruct-raw context (ruler nil) (call nil) (parent-funct (make-funct) :type funct) (call-funct (make-funct) :type funct) num)
other
(defmacro-raw context-fn (c) `(funct-fn (context-parent-funct ,C)))
other
(defmacro-raw context-formals (c) `(funct-formals (context-parent-funct ,C)))
other
(defmacro-raw context-callfn (c) `(funct-fn (context-call-funct ,C)))
other
(defmacro-raw context-callformals (c) `(funct-formals (context-call-funct ,C)))
other
(defmacro-raw context-ccms (c) `(funct-ccms (context-parent-funct ,C)))
other
(defstruct-raw ccmf (firstsite 0 :type fixnum) (lastsite 0 :type fixnum) (fc-num (list 0) :type (cons fixnum list)) (lc-num (list 0) :type (cons fixnum list)) (graph nil :type (array ccmf-node)) (in-sizes 0 :type fixnum) (out-sizes 0 :type fixnum) (steps 1 :type fixnum))
other
(defstruct-raw accg-edge (tail -1 :type fixnum) (head -1 :type fixnum) (ccmf nil :type (or null ccmf)))
other
(defstruct-raw accg-node (context (make-context) :type context) (fwd-edges nil :type list) (bwd-edges nil :type list) (num 0 :type fixnum))
other
(defmacro-raw accg-node-ruler (accg) `(context-ruler (accg-node-context ,ACCG)))
other
(defmacro-raw accg-node-call (accg) `(context-call (accg-node-context ,ACCG)))
other
(defmacro-raw accg-node-parent-funct (accg) `(context-parent-funct (accg-node-context ,ACCG)))
other
(defmacro-raw accg-node-call-funct (accg) `(context-call-funct (accg-node-context ,ACCG)))
other
(defmacro-raw accg-node-fn (accg) `(context-fn (accg-node-context ,ACCG)))
other
(defmacro-raw accg-node-formals (accg) `(context-formals (accg-node-context ,ACCG)))
other
(defmacro-raw accg-node-callformals (accg) `(context-callformals (accg-node-context ,ACCG)))
other
(defmacro-raw accg-node-callfn (accg) `(context-callfn (accg-node-context ,ACCG)))
other
(defmacro-raw accg-node-context-num (accg) `(context-num (accg-node-context ,ACCG)))
other
(defmacro-raw accg-node-ccms (accg) `(context-ccms (accg-node-context ,ACCG)))
other
(defstruct-raw srg-edge (tail 0 :type fixnum) (head 0 :type fixnum) (ccmf (make-ccmf) :type ccmf) (label 'none :type symbol))
other
(defstruct-raw srg-node (node 0 :type fixnum) (ccm 0 :type fixnum) (fwd-edges nil :type list) (bwd-edges nil :type list))
other
(defstruct-raw memoization (proved nil :type list) (unproved (make-array 0 :initial-element nil :element-type 'list) :type (vector list)))
other
(defun-raw create-memoization (max-ind) (make-memoization :unproved (make-array (1+ max-ind) :initial-element nil :element-type 'list)))
other
(defun-raw ccg-simplify-hyps-no-split (hyps ctx ens wrld state) (declare (ignore ctx)) (mv-let (nhyps ttree) (normalize-lst hyps t nil ens wrld nil (backchain-limit wrld :ts)) (er-progn (accumulate-ttree-and-step-limit-into-state ttree :skip state) (value (flatten-ands-in-lit-lst nhyps)))))
other
(defun-raw print-funct-ccms (functs wrld state) (if (endp functs) state (pprogn (fms "The CCM~#1~[~/s~] for ~x0 ~#1~[is~/are~] ~&1.~|" `((#\0 . ,(FUNCT-FN (CAR FUNCTS))) (#\1 . ,(UNTRANSLATE-LST (MAPCAR #'DE-PROPAGATE (COERCE (FUNCT-CCMS (CAR FUNCTS)) 'LIST)) NIL WRLD))) *standard-co* state nil) (print-funct-ccms (cdr functs) wrld state))))
other
(defun-raw prettify-ccms
(ccm-array vars vals wrld)
(let ((fn (if vars
(function (lambda (x)
(untranslate (subcor-var vars vals (de-propagate x))
nil
wrld)))
(function (lambda (x) (untranslate (de-propagate x) nil wrld))))))
(map 'vector fn ccm-array)))
other
(defmacro-raw ce-defun-test (defun) `(let ((body (ce-defun-body ,DEFUN))) (if (eq (fn-symb body) 'if) (cadr body) t)))
other
(defmacro-raw ce-defun-call (defun) `(let ((body (ce-defun-body ,DEFUN))) (if (eq (fn-symb body) 'if) (caddr body) body)))
other
(defun-raw ccmf-graph-no-edges?
(ccmf-graph)
(loop for
node
across
ccmf-graph
when
(or (consp (ccmf-node->-edges node))
(consp (ccmf-node->=-edges node)))
return
nil
finally
(return t)))
other
(defun-raw ccmf-graph-term (i graph ccms0 ccms1 acc) (if (< i 0) (cond ((endp acc) acc) ((endp (cdr acc)) (car acc)) (t (cons 'and acc))) (let* ((node (aref graph i)) (>=-edges (ccmf-node->=-edges node)) (>-edges (ccmf-node->-edges node)) (ccm (de-propagate (aref ccms0 i)))) (ccmf-graph-term (1- i) graph ccms0 ccms1 (append (mapcar (function (lambda (x) `(> ,CCM ,(DE-PROPAGATE (AREF CCMS1 X))))) >-edges) (mapcar (function (lambda (x) `(>= ,CCM ,(DE-PROPAGATE (AREF CCMS1 X))))) >=-edges) acc)))))
other
(defun-raw print-ccmfs1 (defuns defun0 defun1 ccmfs flst funct0 col wrld state) (if (endp defuns) state (let* ((graph (ccmf-graph (car ccmfs))) (ne? (ccmf-graph-no-edges? graph)) (f0 (car defuns)) (f1 (if (consp (cdr defuns)) (cadr defuns) defun0)) (f2 (cond ((endp (cdr defuns)) defun1) ((endp (cddr defuns)) defun0) (t (caddr defuns)))) (fn0 (ce-defun-fn f0)) (fn1 (ce-defun-fn f1)) (fn2 (ce-defun-fn f2)) (formals (ce-defun-formals f1)) (actuals (fargs (ce-defun-call f0))) (ccms0 (prettify-ccms (funct-ccms (car flst)) nil nil wrld)) (ccms0-lst (coerce ccms0 'list)) (ccms1 (prettify-ccms (funct-ccms (if (endp (cdr flst)) funct0 (cadr flst))) formals actuals wrld)) (ccms1-lst (coerce ccms1 'list))) (pprogn (fms "When execution moves from the recursive call in ~x0 of ~x1 to ~ ~#2~[itself~/the recursive call in ~x1 of ~x3~], we need to know ~ how the measures of ~x0 compare with the result of substituting ~ the formals of ~x1 with the actuals of the call to ~x1 in the ~ measures of ~x1. The measure~#4~[~/s~] for ~x0 ~ ~#4~[is~/are~]:~|~%~*6~%The result~#5~[~/s~] of applying the ~ substitution to the measures of ~x1 ~#5~[is~/are~]:~|~%~*7~%We ~ know ~#8~[nothing about how the values of these CCMs ~ relate.~/the following about these CCMs:~%~%~Y9A~]~|~%If you can ~ show that any of the terms in the first list is always either ~ strictly greater than, or greater than or equal to some term in ~ the second list, this could be helpful for proving termination.~|" (list (cons #\0 fn0) (cons #\1 fn1) (cons #\2 (if (eq fn0 fn1) 0 1)) (cons #\3 fn2) (cons #\4 ccms0-lst) (cons #\5 ccms1-lst) (cons #\6 `("" "~x*.~|" "~x*~|" "~x*~|" ,CCMS0-LST)) (cons #\7 `("" "~x*.~|" "~x*~|" "~x*~|" ,CCMS1-LST)) (cons #\8 (if ne? 0 1)) (cons #\9 (ccmf-graph-term (1- (array-dimension graph 0)) graph ccms0 ccms1 nil)) (cons #\A (term-evisc-tuple nil state))) *standard-co* state nil) (print-ccmfs1 (cdr defuns) defun0 defun1 (cdr ccmfs) (cdr flst) funct0 col wrld state)))))
other
(defun-raw print-ccmfs (defuns ccmfs flst col wrld state) (if (endp defuns) state (print-ccmfs1 defuns (car defuns) (if (endp (cdr defuns)) (car defuns) (cadr defuns)) ccmfs flst (car flst) col wrld state)))
other
(defun-raw print-ccms (defuns functs col wrld state) (if (endp defuns) (mv-let (col state) (fmt1 "~|" nil col *standard-co* state nil) (declare (ignore col)) state) (mv-let (col state) (fmt1 "The CCM~#1~[~/s~] for ~x0 ~#1~[is~/are~] ~&1. " (list (cons #\0 (cadar defuns)) (cons #\1 (untranslate-lst (mapcar (function de-propagate) (coerce (funct-ccms (car functs)) 'list)) nil wrld))) col *standard-co* state nil) (print-ccms (cdr defuns) (cdr functs) col wrld state))))
other
(defun-raw produce-counter-example1 (ccmfs context-array alist wrld) (if (endp ccmfs) (mv nil nil nil) (let* ((context (aref context-array (car (ccmf-fc-num (car ccmfs))))) (funct (context-parent-funct context)) (fn (funct-fn funct))) (mv-let (name i) (ccg-counter-example-fn-name fn (assoc-eq-value fn 0 alist) wrld) (mv-let (contexts functs names) (produce-counter-example1 (cdr ccmfs) context-array (assoc-set-eq fn (1+ i) alist) wrld) (mv (cons context contexts) (cons funct functs) (cons name names)))))))
other
(defun-raw produce-counter-example2 (contexts names name0 ctx ens wrld state) (if (endp contexts) (value nil) (let* ((context (car contexts)) (funct (context-parent-funct context)) (call (cons (if (endp (cdr names)) name0 (cadr names)) (fargs (context-call context))))) (er-let* ((ruler (state-global-let* ((inhibit-output-lst *valid-output-names*)) (simp-hyps0 (context-ruler context) ctx ens wrld state nil t nil :term-order))) (body (value (if (endp ruler) call `(if ,(IF (ENDP (CDR RULER)) (CAR RULER) `(AND ,@RULER)) ,CALL (list ,@(FUNCT-FORMALS FUNCT)))))) (rst (produce-counter-example2 (cdr contexts) (cdr names) name0 ctx ens wrld state))) (value (cons `(defun ,(CAR NAMES) ,(FUNCT-FORMALS FUNCT) ,BODY) rst))))))
other
(defun-raw accg-find-ccmf
(accg i j)
(loop for
edge
in
(accg-node-fwd-edges (aref accg i))
when
(= j (accg-edge-head edge))
return
(accg-edge-ccmf edge)))
other
(defun-raw produce-counter-example (path accg context-array ctx ens wrld state) (let* ((ccmfs (loop for p on path when (and (consp p) (consp (cdr p))) collect (accg-find-ccmf accg (car p) (cadr p))))) (pprogn (fms "Producing counter-example, including simplifying rulers in order to ~ maximize the readability of the counter-example." nil *standard-co* state nil) (mv-let (contexts functs names) (produce-counter-example1 ccmfs context-array nil wrld) (er-let* ((defuns (produce-counter-example2 contexts names (car names) ctx ens wrld state))) (value (list* ccmfs functs defuns)))))))
other
(defun-raw print-counter-example (accg ce contexts ctx ens wrld state) (er-let* ((triple (produce-counter-example (cdr ce) accg contexts ctx ens wrld state)) (ccmfs (value (car triple))) (functs (value (cadr triple))) (defuns (value (cddr triple)))) (pprogn (fms "The following function definitions correspond to an actual loop in ~ your function definitions for which the CCG analysis was unable to ~ prove termination in all cases: ~%~%~Y01~%" (list (cons #\0 (untranslate (if (endp (cdr defuns)) (car defuns) (cons 'mutual-recursion defuns)) nil wrld)) (cons #\1 (term-evisc-tuple nil state))) *standard-co* state nil) (print-ccmfs defuns ccmfs functs 0 wrld state) (let* ((loop-graph (car ce)) (ne? (ccmf-graph-no-edges? loop-graph)) (ccms (funct-ccms (car functs)))) (fms "As it stands, we do not have enough information to show that this ~ loop terminates. ~#0~[When we put it all together, we find that ~ when we loop from ~x1 to itself, we know ~#2~[nothing about how ~ the values of the CCMs change. ~/the following about how values ~ change from one iteration to the loop to the next (measures are ~ presented without substitution):~%~%~Y34~]~/~]~|~%Note that under ~ this abstraction, the loop is idempotent (i.e. going through the ~ loop again will result in the same information about ~ non-increasing and decreasing values as we have just stated), and ~ that there is no CCM that decreases to itself across the loop. ~ There are therefore three possibilities: ~|~%(1) We did not guess ~ the CCMs needed for proving termination. If this is the case, you ~ could provide them for us using a :CONSIDER-CCMS or ~ :CONSIDER-ONLY-CCMS hint (see :DOC CCG-XARGS). If you are truly ~ desperate, you can resort to proving termination using ACL2's ~ measure-based termination method (do this globally by using ~ SET-TERMINATION-METHOD or just once by using the ~ :TERMINATION-METHOD xarg; see :DOC CCG-XARGS).~|~%(2) We guessed ~ the proper CCMs, but were unable to prove some necessary ~ theorem(s) about how these values change from step to step in the ~ loop. In this case, we suggest that you look at the ~ counter-example we generated and use it to determine what ~ additional lemmas are needed for CCG analysis to successfully ~ prove termination.~|~%(3) The loop really is non-terminating for ~ some inputs. In this case, you should alter the definition of the ~ function so that it will terminate on all inputs.~%~%" (list (cons #\0 (if (consp (cdr defuns)) 0 1)) (cons #\1 (cadar defuns)) (cons #\2 (if ne? 0 1)) (cons #\3 (untranslate (ccmf-graph-term (1- (array-dimension loop-graph 0)) loop-graph ccms ccms nil) nil wrld)) (cons #\4 (term-evisc-tuple nil state))) *standard-co* state nil)))))
other
(defun-raw print-ccmf-changes (col changes state) (if (endp changes) state (let ((change (car changes))) (mv-let (col state) (fmt1 "When execution moves ~@0, the following ~ always holds:~|~%~x1.~|~%" `((#\0 . ,(IF (CONSP (CAR CHANGE)) `("from context ~x0 to context ~x1" (#\0 . ,(CAAR CHANGE)) (#\1 . ,(CDAR CHANGE))) `("across context ~x0" (#\0 . ,(CAR CHANGE))))) (#\1 . ,(CDR CHANGE))) col *standard-co* state nil) (print-ccmf-changes col (cdr changes) state)))))
other
(defun-raw p< (p1 p2) (or (< (car p1) (car p2)) (and (= (car p1) (car p2)) (< (cdr p1) (cdr p2)))))
other
(defun-raw construct-accg-changes-printout (changes) (if (endp changes) nil (cons `("the edge from context ~x0 to context ~x1" (#\0 . ,(CAAR CHANGES)) (#\1 . ,(CDAR CHANGES))) (construct-accg-changes-printout (cdr changes)))))
other
(defun-raw print-accg-changes (changes state) (if (endp changes) (fms "~|" nil *standard-co* state nil) (pprogn (fms "~x0 -> ~x1" `((#\0 . ,(CAAR CHANGES)) (#\1 . ,(CDAR CHANGES))) *standard-co* state nil) (print-accg-changes (cdr changes) state))))
other
(defun-raw print-changes (col changes state) (if (and (endp (car changes)) (endp (cdr changes))) (mv-let (col state) (fmt1 "We discovered nothing new about the CCG.~|" nil col *standard-co* state nil) (declare (ignore col)) state) (mv-let (col state) (fmt1 "We discovered the following about the CCG.~|~%" nil col *standard-co* state nil) (mv-let (col state) (if (endp (car changes)) (mv col state) (mv-let (col state) (fmt1 "We can safely omit the following edges from the CCG:~|" nil col *standard-co* state nil) (declare (ignore col)) (mv 0 (print-accg-changes (car changes) state)))) (print-ccmf-changes col (sort (copy-list (cdr changes)) (if (consp (caadr changes)) (function p<) (function <)) :key (function car)) state)))))
other
(defun-raw print-context-array1 (i names context-array state) (if (>= i (array-dimension context-array 0)) state (pprogn (let ((context (aref context-array i))) (fms "CALLING CONTEXT ~x0~#1~[~/ in the body of ~x2~]:~|rulers: ~ ~x3~|call: ~x4~|" `((#\0 . ,I) (#\1 . ,NAMES) (#\2 . ,(CONTEXT-FN CONTEXT)) (#\3 . ,(CONTEXT-RULER CONTEXT)) (#\4 . ,(CONTEXT-CALL CONTEXT))) *standard-co* state nil)) (print-context-array1 (1+ i) names context-array state))))
other
(defun-raw print-context-array (names context-array state) (pprogn (fms "The calling contexts for ~#0~[this definition~/these definitions~] ~ are:~|" `((#\0 . ,NAMES)) *standard-co* state nil) (print-context-array1 0 names context-array state)))
other
(defun-raw print-accg-edges3 (edges accg state) (if (endp edges) state (pprogn (let ((pair (accg-edge-context-pair (car edges) accg))) (fms "~x0 -> ~x1" `((#\0 . ,(CAR PAIR)) (#\1 . ,(CDR PAIR))) *standard-co* state nil)) (print-accg-edges3 (cdr edges) accg state))))
other
(defun-raw print-accg-edges2 (i n accg state) (if (>= i n) state (pprogn (print-accg-edges3 (accg-node-fwd-edges (aref accg i)) accg state) (print-accg-edges2 (1+ i) n accg state))))
other
(defun-raw print-accg-edges1 (accgs state) (if (endp accgs) (fms "~|" nil *standard-co* state nil) (pprogn (print-accg-edges2 0 (array-dimension (car accgs) 0) (car accgs) state) (print-accg-edges1 (cdr accgs) state))))
other
(defun-raw print-accg-edges (col accgs state) (if (endp accgs) state (mv-let (col state) (fmt1 "The Calling Context Graph has the following edges:~|" nil col *standard-co* state nil) (declare (ignore col)) (print-accg-edges1 accgs state))))
limit-induction-hint-fnfunction
(defun limit-induction-hint-fn (i) `(or (and (length-exceedsp (car id) ,I) (endp (cdadr id)) (eq (cddr id) 0) '(:computed-hint-replacement t :do-not-induct :otf-flg-override)) (and (> (cddr id) 20) '(:computed-hint-replacement t :do-not '(eliminate-destructors eliminate-irrelevance generalize fertilize) :in-theory (theory 'minimal-theory)))))
translated-limit-induction-hintfunction
(defun translated-limit-induction-hint (i) `((eval-and-translate-hint-expression "CCG Query" nil (cons 'nil (cons ((lambda (i id) (if (if (length-exceedsp (car id) i) (if (endp (cdr (car (cdr id)))) (if (eq (cdr (cdr id)) '0) '(:computed-hint-replacement t :do-not-induct :otf-flg-override) 'nil) 'nil) 'nil) (if (length-exceedsp (car id) i) (if (endp (cdr (car (cdr id)))) (if (eq (cdr (cdr id)) '0) '(:computed-hint-replacement t :do-not-induct :otf-flg-override) 'nil) 'nil) 'nil) (if (< '20 (cdr (cdr id))) '(:computed-hint-replacement t :do-not '(eliminate-destructors eliminate-irrelevance generalize fertilize) :in-theory (theory 'minimal-theory)) 'nil))) ',I id) (cons state 'nil))))))
other
(defun-raw ccg-negate (exp) (if (and (consp exp) (eq (first exp) 'not)) (second exp) `(not ,EXP)))
other
(defun-raw ccg-addlist (lst) (cond ((endp lst) 0) ((endp (cdr lst)) (car lst)) (t `(binary-+ ,(CAR LST) ,(CCG-ADDLIST (CDR LST))))))
other
(defun-raw ccg-count-contexts (tms) (let ((i 0)) (dolist (tm tms i) (setf i (+ i (len tm))))))
other
(defun-raw subsumed-by-proved-clause (cl proved) (and (consp proved) (or (eq t (subsumes *init-subsumes-count* (car proved) cl nil)) (subsumed-by-proved-clause cl (cdr proved)))))
other
(defun-raw eliminate-subsumed-tail (cl cl-set acc) (if (endp cl-set) acc (eliminate-subsumed-tail cl (cdr cl-set) (if (subsumes *init-subsumes-count* cl (car cl-set) nil) acc (cons (car cl-set) acc)))))
other
(defun-raw add-proved-clause (cl proved) (cons cl (eliminate-subsumed-tail cl proved nil)))
other
(defun-raw equals-unproved-clause1 (cl unproved) (and (consp unproved) (or (let ((cl-unproved (car unproved))) (and (eq t (subsumes *init-subsumes-count* cl cl-unproved nil)) (eq t (subsumes *init-subsumes-count* cl-unproved cl nil)))) (equals-unproved-clause1 cl (cdr unproved)))))
other
(defun-raw equals-unproved-clause (cl unproved i) (and (< i (array-dimension unproved 0)) (or (equals-unproved-clause1 cl (aref unproved i)) (equals-unproved-clause cl unproved (1+ i)))))
other
(defmacro-raw time-er (ctx) `(er soft ,CTX "CCG analysis has exceeded the specified time ~ limit. If you did not expect a time-limit, check the global ~ time-limit setting (see :DOC set-ccg-time-limit and the ~ discussion of the :time-limit flag in :DOC CCG) to find out ~ more. At this point you have several options:~|~% ~ * Set the :don't-guess-ccms flag to t. Sometimes CCG analysis ~ guesses too many CCMs which leads to excessive prover ~ queries. This will eliminate *all* CCMs other than the ~ acl2s-size of each formal.~|~%~ * Do you see a variable that you don't think is relevant to the ~ termination proof? In that case, us the :ignore-formals flag ~ to tell the CCG analysis to throw out CCMs that contain that ~ formal. This may also cut down on CCMs and therefore prover ~ queries.~|~%~ * Finally, if you are willing to wait some more, you ~ could try increasing the time limit, or eliminating it by ~ setting it to nil."))
other
(defun-raw time-left
(stop-time ctx state)
(let ((now (get-internal-run-time)))
(if (< now stop-time)
(value (rationalize (/ (- stop-time now)
(coerce internal-time-units-per-second 'float))))
(time-er ctx))))
other
(defun-raw time-check (stop-time ctx state) (if (and (posp stop-time) (<= stop-time (get-internal-run-time))) (time-er ctx) (value nil)))
other
(defmacro-raw maybe-prover-before-stop-time (stop-time ctx state body) `(let ((stop-time ,STOP-TIME)) (if (null stop-time) ,BODY (er-let* ((time-limit (time-left stop-time ,CTX ,STATE))) (with-prover-time-limit time-limit ,BODY)))))
prove-no-erfunction
(defun prove-no-er (term pspv hints ens wrld ctx state) (mv-let (er ttree state) (prove term pspv hints ens wrld ctx state) (if er (value (cons nil nil)) (value (cons t ttree)))))
other
(defun-raw query (hyps concl pt qspv state) (let* ((stop-time (access query-spec-var qspv :stop-time)) (mem (access query-spec-var qspv :mem)) (otf-flg (access query-spec-var qspv :otf-flg)) (ens (access query-spec-var qspv :ens)) (ctx (access query-spec-var qspv :ctx)) (wrld (access query-spec-var qspv :wrld)) (clause (add-literal concl (dumb-negate-lit-lst hyps) t)) (bic-onlyp (equal pt :built-in-clauses)) (ind-limit (if bic-onlyp -1 (cadr pt))) (displayed-goal (prettyify-clause-set (list clause) (let*-abstractionp state) wrld))) (pprogn (ccg-io? query nil state (bic-onlyp ind-limit clause wrld) (fms "We now make the following query, using ~ proof-technique ~x0 (see :DOC ~ CCG-hierarchy)~#1~[~/ and with the otf-flg set to ~ ~x2~]:~|~%GOAL~%~Y34." `((#\0 . ,PT) (#\1 . ,(IF BIC-ONLYP 0 1)) (#\2 . ,OTF-FLG) (#\3 . ,DISPLAYED-GOAL) (#\4 . ,(TERM-EVISC-TUPLE NIL STATE))) (proofs-co state) state nil)) (er-let* ((pair (cond (bic-onlyp (mv-let (built-in-clausep ttree) (built-in-clausep 'query clause ens (match-free-override wrld) wrld state) (value (if built-in-clausep (cons t ttree) (cons nil nil))))) ((subsumed-by-proved-clause clause (memoization-proved mem)) (pprogn (ccg-io? query nil state nil (fms "But we see that this query is already ~ subsumed by another query that was ~ previously proven.~%~%" nil (proofs-co state) state nil)) (value (cons t nil)))) ((equals-unproved-clause clause (memoization-unproved mem) ind-limit) (pprogn (ccg-io? query nil state nil (fms "But we see that we already tried and ~ failed to prove an equivalent query ~ using the same restrictions on the ~ theorem prover.~%~%" nil (proofs-co state) state nil)) (value (cons nil nil)))) (t (er-let* ((pair (let ((hints (translated-limit-induction-hint ind-limit))) (maybe-prover-before-stop-time stop-time ctx state (prove-no-er (termify-clause-set (list clause)) (make-pspv ens wrld state :displayed-goal displayed-goal :otf-flg otf-flg) hints ens wrld ctx state))))) (progn (if (car pair) (setf (memoization-proved mem) (add-proved-clause clause (memoization-proved mem))) (setf (aref (memoization-unproved mem) ind-limit) (cons clause (aref (memoization-unproved mem) ind-limit)))) (value pair))))))) (pprogn (ccg-io? query nil state nil (fms "ACL2 has ~#0~[SUCCEEDED in proving this ~ query~/FAILED to prove this query~].~|" (list (cons #\0 (if (car pair) 0 1))) (proofs-co state) state nil)) (er-progn (time-check stop-time ctx state) (if (car pair) (accumulate-ttree-and-step-limit-into-state (cdr pair) :skip state) (pprogn (pprogn (f-put-global 'gag-state-saved (f-get-global 'gag-state state) state) (f-put-global 'gag-state nil state)) (value nil))) (value (car pair))))))))
other
(defun-raw ccg-generic-dfs-visit (u graph f color time node-fwd-edges edge-head) (setf (aref color u) 'grey) (dolist (vn (funcall node-fwd-edges (aref graph u))) (let ((v (funcall edge-head vn))) (when (eq (aref color v) 'white) (setf time (ccg-generic-dfs-visit v graph f color time node-fwd-edges edge-head))))) (setf (aref color u) 'black) (setf (aref f time) u) (incf time))
other
(defun-raw ccg-generic-dfs (graph node-fwd-edges edge-head) (let* ((size (array-total-size graph)) (f (make-array size :element-type 'fixnum)) (time 0) (color (make-array size :element-type '(member white grey black) :initial-element 'white))) (dotimes (i size f) (when (eq (aref color i) 'white) (setf time (ccg-generic-dfs-visit i graph f color time node-fwd-edges edge-head))))))
other
(defun-raw ccg-generic-scc-aux (u graph scc scc-array scc-num color node-bwd-edges edge-tail) (let ((scc scc)) (setf (aref color u) 'grey) (dolist (vn (funcall node-bwd-edges (aref graph u))) (let ((v (funcall edge-tail vn))) (when (eq (aref color v) 'white) (setf scc (ccg-generic-scc-aux v graph scc scc-array scc-num color node-bwd-edges edge-tail))))) (setf (aref color u) 'black) (setf (aref scc-array u) scc-num) (cons u scc)))
other
(defun-raw ccg-generic-scc (graph node-fwd-edges node-bwd-edges edge-tail edge-head) (let ((scc-num -1)) (loop with f = (ccg-generic-dfs graph node-fwd-edges edge-head) with size = (array-dimension graph 0) with color = (make-array size :element-type '(member black grey white) :initial-element 'white) with scc-array = (make-array size :element-type 'fixnum :initial-element 0) for i from (1- size) downto 0 for u = (aref f i) when (eq (aref color u) 'white) collect (ccg-generic-scc-aux u graph nil scc-array (incf scc-num) color node-bwd-edges edge-tail) into sccs finally (return (values sccs scc-array)))))
other
(defun-raw accg-can-omit-edge? (node1 node2 hlevel qspv state) (if (hlevel-ccmfs-per-nodep hlevel) (value nil) (query (append (accg-node-ruler node1) (subcor-var-lst (accg-node-formals node2) (fargs (accg-node-call node1)) (accg-node-ruler node2))) nil (hlevel-proof-technique hlevel) qspv state)))
other
(defun-raw accg-fill-in-edges
(accg name-node-alist)
(loop for
i
from
0
below
(array-dimension accg 0)
for
node1
=
(aref accg i)
for
successors
=
(cdr (assoc (accg-node-callfn node1) name-node-alist))
do
(setf (accg-node-fwd-edges node1)
(loop for
node2
in
successors
for
j
=
(accg-node-num node2)
for
edge
=
(make-accg-edge :tail i :head j)
do
(setf (accg-node-bwd-edges node2)
(cons edge (accg-node-bwd-edges node2)))
collect
edge))))
other
(defun-raw context-to-accg-node-lst (contexts total) (if (endp contexts) (mv nil total) (mv-let (nodes ntotal) (context-to-accg-node-lst (cdr contexts) total) (let ((node (make-accg-node :context (car contexts)))) (mv (cons node nodes) (cons node ntotal))))))
other
(defun-raw ccg-build-accg0 (names contexts) (if (endp names) (mv nil nil) (let ((name (car names)) (context-list (car contexts))) (mv-let (alist total) (ccg-build-accg0 (cdr names) (cdr contexts)) (mv-let (nodes ntotal) (context-to-accg-node-lst context-list total) (mv (acons name nodes alist) ntotal))))))
other
(defun-raw ccg-build-accg (names contexts) (mv-let (name-node-alist accg-node-lst) (ccg-build-accg0 names contexts) (let ((accg (coerce accg-node-lst 'vector))) (progn (loop for i from 0 below (array-dimension accg 0) do (setf (accg-node-num (aref accg i)) i)) (accg-fill-in-edges accg name-node-alist) accg))))
other
(defun-raw simplify-contexts1 (context-lst ens wrld ctx state) (if (endp context-lst) state (mv-let (erp value state) (ccg-simplify-hyps-no-split (context-ruler (car context-lst)) ctx ens wrld state) (progn (unless erp (setf (context-ruler (car context-lst)) value)) (simplify-contexts1 (cdr context-lst) ens wrld ctx state)))))
other
(defun-raw simplify-contexts (contexts ens wrld ctx state) (if (endp contexts) state (pprogn (simplify-contexts1 (car contexts) ens wrld ctx state) (simplify-contexts (cdr contexts) ens wrld ctx state))))
de-propagatefunction
(defun de-propagate (term) (if (eq (fn-symb term) 'ccg-propagate) (fargn term 2) term))
other
(defun-raw ccg-formal-sizes (formals) (loop for x in formals collect `(acl2s-size ,X)))
other
(defun-raw ccg-add-zp-ccm (r formals ccms) (cond ((atom r) ccms) ((and (eq (ffn-symb r) 'not) (consp (fargn r 1)) (eq (ffn-symb (fargn r 1)) 'zp) (not (member-eq (fargn (fargn r 1) 1) formals))) (cons (fargn (fargn r 1) 1) ccms)) (t ccms)))
other
(defun-raw ccg-add-<-ccm (r formals ccms) (declare (ignore formals)) (cond ((atom r) ccms) ((or (eq (car r) '<) (and (eq (car r) 'not) (consp (second r)) (eq (car (second r)) '<))) (let* ((not? (eq (car r) 'not)) (r0 (if (eq (car r) '<) r (second r))) (rarg1 (second r0)) (rarg2 (third r0)) (p (term-order (second r0) (third r0))) (arg1 (if p (second r0) (third r0))) (arg2 (if p (third r0) (second r0)))) (cond ((and (quotep arg1) (quotep arg2)) ccms) ((not (or (quotep arg1) (quotep arg2))) (if not? (cons `(acl2s-size (binary-+ '1 (binary-+ ,RARG1 (unary-- ,RARG2)))) ccms) (cons `(acl2s-size (binary-+ '1 (binary-+ ,RARG2 (unary-- ,RARG1)))) ccms))) ((and (quotep arg1) (acl2-numberp (unquote arg1))) (if (and (or (eql (unquote arg1) 0) (eql (unquote arg1) 1)) (variablep arg2)) ccms (cons `(acl2s-size (binary-+ ',(- 1 (UNQUOTE ARG1)) ,ARG2)) ccms))) ((and (quotep arg2) (acl2-numberp (unquote arg2))) (if (and (or (eql (unquote arg2) 0) (eql (unquote arg2) 1)) (variablep arg1)) ccms (cons `(acl2s-size (binary-+ ',(- 1 (UNQUOTE ARG2)) ,ARG1)) ccms))) (t ccms)))) (t ccms)))
other
(defun-raw ccg-add-dec-ccm (arg ccms) (if (and (consp arg) (eq (car arg) 'dec)) (cons arg ccms) ccms))
other
(defun-raw accg-guess-ccms-for-node
(node)
(let ((ccms nil) (rulers (accg-node-ruler node))
(formals (accg-node-formals node)))
(dolist (r rulers ccms)
(setf ccms (ccg-add-<-ccm r formals ccms))
(setf ccms (ccg-add-zp-ccm r formals ccms)))))
other
(defun-raw ccg-remove-duplicate-ccms-in-functs
(functs)
(dolist (funct functs functs)
(setf (funct-ccms funct)
(remove-duplicates (funct-ccms funct)
:test (function equal)
:key (function de-propagate)))))
other
(defun-raw ccg-remove-duplicate-ccms (ccms) (let ((n (array-dimension ccms 0))) (dotimes (i n ccms) (setf (aref ccms i) (remove-duplicates (aref ccms i) :test (function equal) :key (function de-propagate))))))
other
(defun-raw accg-propagate-ccm (ccm accg n consider-onlyp) (let* ((size (array-dimension accg 0)) (queued (make-array size :element-type 'boolean :initial-element nil)) (successor (make-array size :element-type 'integer :initial-element 0)) (ccms (make-array size :initial-element nil)) (queue (make-array size :element-type 'integer :initial-element -1)) (c (accg-node-context-num (aref accg n))) (i 0) (queue-preds (lambda (m) (loop for edge in (accg-node-bwd-edges (aref accg m)) for pred = (accg-edge-tail edge) unless (or (aref queued pred) (aref consider-onlyp pred)) do (setf (aref queued pred) t) and do (setf (aref queue (incf i)) pred) and do (setf (aref successor pred) m))))) (let ((node (aref accg n))) (setf (accg-node-ccms node) (cons ccm (accg-node-ccms node))) (setf (aref ccms n) ccm)) (setf (aref queued n) t) (funcall queue-preds n) (loop for j from 1 below size for k = (aref queue j) when (= k -1) return nil do (let* ((succ (aref successor k)) (node (aref accg k)) (nccm (subcor-var (accg-node-callformals node) (fargs (accg-node-call node)) (aref ccms succ)))) (setf (aref ccms k) nccm)) do (funcall queue-preds k)) (loop for j from 1 below size for k = (aref queue j) when (= k -1) return nil do (let ((node (aref accg k))) (setf (accg-node-ccms node) (cons `(ccg-propagate ,C ,(AREF CCMS K)) (accg-node-ccms node)))))))
other
(defun-raw accg-propagate-ccms
(ccms accg consider-onlyp)
(loop with
size
=
(array-dimension ccms 0)
for
i
from
0
below
size
do
(loop for
ccm
in
(aref ccms i)
do
(accg-propagate-ccm ccm accg i consider-onlyp))))
other
(defun-raw accg-partition-ccms-by-function
(ccms nodes)
(loop for
i
from
0
below
(array-dimension ccms 0)
for
funct
=
(accg-node-parent-funct (aref nodes i))
do
(setf (funct-ccms funct)
(append (aref ccms i) (funct-ccms funct)))))
other
(defun-raw accg-guess-ccms (accg functs ccm-hints-alist) (let* ((size (array-dimension accg 0)) (ccms (make-array size :element-type 'list :initial-element nil)) (consider-onlyp (make-array size :element-type 'boolean :initial-element nil))) (loop for i from 0 below size for entry = (assoc (accg-node-fn (aref accg i)) ccm-hints-alist) do (setf (aref consider-onlyp i) (cadr entry)) unless (eq (cddr entry) *0*) do (setf (aref ccms i) (cddr entry))) (loop for i from 0 below size for node = (aref accg i) unless (or (aref consider-onlyp i) (endp (accg-node-fwd-edges (aref accg i)))) do (setf (aref ccms i) (append (accg-guess-ccms-for-node node) (aref ccms i)))) (accg-propagate-ccms (ccg-remove-duplicate-ccms ccms) accg consider-onlyp) (ccg-remove-duplicate-ccms-in-functs functs) (loop for funct in functs for fn-sccms in ccm-hints-alist for fsizes = (ccg-formal-sizes (funct-formals funct)) unless (cadr fn-sccms) do (setf (funct-ccms funct) (append fsizes (if (length-exceedsp fsizes 1) (cons (ccg-addlist fsizes) (funct-ccms funct)) (funct-ccms funct)))) finally (ccg-remove-duplicate-ccms-in-functs functs)) (loop for funct in functs do (setf (funct-ccms funct) (coerce (funct-ccms funct) 'vector)))))
other
(defun-raw ccmf->-value?
(ruler e1 e2 pt qspv state)
(query ruler
`(o< ,(DE-PROPAGATE E2) ,(DE-PROPAGATE E1))
pt
qspv
state))
other
(defun-raw ccmf->=-value?
(ruler e1 e2 pt qspv state)
(query ruler
`(not (o< ,(DE-PROPAGATE E1) ,(DE-PROPAGATE E2)))
pt
qspv
state))
other
(defun-raw ccmf-skip-edge (f1 n1 c1 e1 f2 n2 e2 hlevel) (or (null hlevel) (eq (fn-symb e1) 'ccg-propagated) (and (eq (fn-symb e2) 'ccg-propagated) (not (equal (fargn e2 1) c1))) (and (let ((v1 (all-vars e1)) (v2 (all-vars e2))) (and (not (and (eq f1 f2) (= n1 n2))) (case (hlevel-ccm-comparison-scheme hlevel) (:equal (not (and (subsetp v1 v2) (subsetp v2 v1)))) (:all (or (subsetp v2 v1) (not (subsetp v1 v2)))) (:some (or (subsetp v1 v2) (not (intersectp-eq v1 v2)))) (:none (intersectp-eq v1 v2))))))))
other
(defun-raw accg-copy-ccmf-graph (graph &key (size nil)) (let* ((n (array-dimension graph 0)) (ngraph (make-array (if size (max n size) n) :element-type 'ccmf-node :initial-element (make-ccmf-node)))) (loop for i from 0 below n for node = (aref graph i) do (setf (aref ngraph i) (make-ccmf-node :>-edges (copy-list (ccmf-node->-edges node)) :>=-edges (copy-list (ccmf-node->=-edges node))))) ngraph))
other
(defun-raw accg-add-ccmfs
(accg)
(loop for
node1
across
accg
for
in-sizes
=
(array-dimension (accg-node-ccms node1) 0)
do
(loop for
edge
in
(accg-node-fwd-edges node1)
for
head
=
(accg-edge-head edge)
for
node2
=
(aref accg head)
for
graph
=
(make-array in-sizes)
do
(loop for
i
from
0
below
in-sizes
do
(setf (aref graph i) (make-ccmf-node)))
do
(setf (accg-edge-ccmf edge)
(make-ccmf :firstsite (accg-edge-tail edge)
:lastsite head
:fc-num (accg-node-context-num node1)
:lc-num (accg-node-context-num node2)
:in-sizes in-sizes
:out-sizes (array-dimension (accg-node-ccms node2) 0)
:graph graph)))))
other
(defun-raw accg-scc
(graph)
(ccg-generic-scc graph
(function accg-node-fwd-edges)
(function accg-node-bwd-edges)
(function accg-edge-tail)
(function accg-edge-head)))
other
(defun-raw accg-edge-context-pair
(edge accg)
(cons (car (accg-node-context-num (aref accg (accg-edge-tail edge))))
(car (accg-node-context-num (aref accg (accg-edge-head edge))))))
other
(defun-raw accg-delete-non-scc-edges1 (edges accg scc scc-array) (if (endp edges) (mv nil nil) (mv-let (changes nedges) (accg-delete-non-scc-edges1 (cdr edges) accg scc scc-array) (if (= scc (aref scc-array (accg-edge-head (car edges)))) (mv changes (cons (car edges) nedges)) (mv (cons (accg-edge-context-pair (car edges) accg) changes) nedges)))))
other
(defun-raw accg-delete-non-scc-edges
(accg scc-array)
(loop with
changes
=
nil
for
i
from
0
below
(array-dimension accg 0)
for
nodei
=
(aref accg i)
for
scci
=
(aref scc-array i)
do
(mv-let (nchanges nedges)
(accg-delete-non-scc-edges1 (accg-node-fwd-edges nodei)
accg
scci
scc-array)
(progn (setf (accg-node-fwd-edges nodei) nedges)
(setf changes (append nchanges changes))))
do
(setf (accg-node-bwd-edges nodei)
(delete-if-not (function (lambda (x) (= scci (aref scc-array (accg-edge-tail x)))))
(accg-node-bwd-edges nodei)))
finally
(return changes)))
other
(defun-raw accg-separate-sccs0 (accg sccs scc-array &key (ccmfp nil)) (if (endp (cdr sccs)) (mv nil (list accg)) (let* ((m (array-dimension accg 0)) (n (len sccs)) (count (make-array n :element-type 'fixnum :initial-element 0)) (mapping (make-array m :element-type 'fixnum :initial-element 0)) (changes nil)) (loop for i from 0 below m for j = (aref scc-array i) do (setf (aref mapping i) (aref count j)) do (incf (aref count j))) (let ((naccgs (make-array n))) (loop for i from 0 below n do (setf (aref naccgs i) (make-array (aref count i)))) (loop for i from 0 below m for sccn = (aref scc-array i) for noden = (aref mapping i) for node = (aref accg i) do (setf (aref (aref naccgs sccn) noden) node) do (setf (accg-node-num node) noden) do (setf (accg-node-bwd-edges node) nil)) (loop for i from 0 below n for naccg = (aref naccgs i) do (loop for j from 0 below (aref count i) for node = (aref naccg j) do (setf (accg-node-fwd-edges node) (loop for e in (accg-node-fwd-edges node) for head = (accg-edge-head e) for nhead = (aref mapping head) for ccmf = (accg-edge-ccmf e) if (= (aref scc-array head) i) do (setf (accg-edge-head e) nhead) and do (setf (accg-edge-tail e) j) and do (let ((hnode (aref naccg nhead))) (setf (accg-node-bwd-edges hnode) (cons e (accg-node-bwd-edges hnode)))) and collect e and when ccmfp do (setf (ccmf-firstsite ccmf) j) and do (setf (ccmf-lastsite ccmf) nhead) else do (setf changes (cons (accg-edge-context-pair e accg) changes)))))) (mv changes (loop for i from 0 below n for naccg = (aref naccgs i) unless (and (= (aref count i) 1) (not (accg-node-fwd-edges (aref naccg 0)))) collect naccg))))))
other
(defun-raw accg-separate-sccs
(accg &key (ccmfp nil))
(multiple-value-bind (sccs scc-array)
(accg-scc accg)
(accg-separate-sccs0 accg sccs scc-array :ccmfp ccmfp)))
other
(defun-raw build-and-annotate-accgs
(names functs contexts ccm-hints-alist)
(let ((accg (ccg-build-accg names contexts)))
(multiple-value-bind (sccs scc-array)
(accg-scc accg)
(progn (accg-delete-non-scc-edges accg scc-array)
(accg-guess-ccms accg functs ccm-hints-alist)
(accg-add-ccmfs accg)
(mv-let (changes0 naccgs)
(accg-separate-sccs0 accg sccs scc-array :ccmfp t)
(declare (ignore changes0))
naccgs)))))
other
(defun-raw weaker-proof-techniquesp (h1 h2) (or (null h1) (not (null h2)) (let ((pt1 (car h1)) (pt2 (car h2))) (if (equal pt1 :built-in-clauses) (not (equal pt2 :built-in-clauses)) (and (consp pt2) (< (cadr pt1) (cadr pt2)))))))
other
(defun-raw accg-ccmf-adj-matrix
(ccmf)
(loop with
n1
=
(ccmf-in-sizes ccmf)
with
n2
=
(ccmf-out-sizes ccmf)
with
graph
=
(ccmf-graph ccmf)
with
matrix
=
(make-array `(,N1 ,N2)
:initial-element nil
:element-type '(member nil '>= '>))
for
i
from
0
below
n1
for
node
=
(aref graph i)
do
(loop for
j
in
(ccmf-node->-edges node)
do
(setf (aref matrix i j) '>))
do
(loop for
j
in
(ccmf-node->=-edges node)
do
(setf (aref matrix i j) '>=))
finally
(return matrix)))
other
(defun-raw accg-refine-ccmf2
(i j
matrix
node
e1
hyps
f1
c1
f2
ccms2
cformals
args
redop
changes
old-hlevel
hlevel
qspv
state)
(let ((wrld (access query-spec-var qspv :wrld)))
(if (< j 0)
(value changes)
(let* ((o2 (aref ccms2 j)) (e2 (subcor-var cformals args o2))
(u1 (untranslate e1 nil wrld))
(u2 (untranslate o2 nil wrld))
(skipp (or (ccmf-skip-edge f1 i c1 e1 f2 j e2 hlevel)
(not (or redop (ccmf-skip-edge f1 i c1 e1 f2 j e2 old-hlevel)))))
(label (aref matrix i j))
(pt (hlevel-proof-technique hlevel)))
(er-let* ((nlabel (cond (skipp (value label))
((eq label '>) (value '>))
((equal (de-propagate e1) (de-propagate e2)) (value '>=))
(t (er-let* ((result (pprogn (increment-timer 'other-time state)
(ccg-io? build/refine
nil
state
(u1 u2)
(fms "We attempt to prove that, under the given ~
conditions, it is the case that the ~
context measure ~x0 is always greater than ~
~x1.~|"
`((#\0 . ,U1) (#\1 . ,U2))
*standard-co*
state
nil))
(increment-timer 'print-time state)
(ccmf->-value? hyps e1 e2 pt qspv state))))
(cond (result (value '>))
((eq label '>=) (value '>=))
(t (er-let* ((result (pprogn (increment-timer 'other-time state)
(ccg-io? build/refine
nil
state
(u1 u2)
(fms "Since the previous query failed, ~
we attempt to prove that, under ~
the given conditions, it is the ~
case that the context measure ~x0 ~
is never less than ~x1.~|"
`((#\0 . ,U1) (#\1 . ,U2))
*standard-co*
state
nil))
(increment-timer 'print-time state)
(ccmf->=-value? hyps e1 e2 pt qspv state))))
(value (if result
'>=
nil))))))))))
(progn (case nlabel
(> (setf (ccmf-node->-edges node)
(cons j (ccmf-node->-edges node))))
(>= (setf (ccmf-node->=-edges node)
(cons j (ccmf-node->=-edges node)))))
(accg-refine-ccmf2 i
(1- j)
matrix
node
e1
hyps
f1
c1
f2
ccms2
cformals
args
redop
(if (eq nlabel label)
changes
(cons `(,NLABEL ,U1 ,U2) changes))
old-hlevel
hlevel
qspv
state)))))))
other
(defun-raw accg-refine-ccmf1
(i matrix
ccmf
hyps
f1
ccms1
c1
f2
ccms2
cformals
args
redop
changes
old-hlevel
hlevel
qspv
state)
(if (< i 0)
(value (cond ((endp changes) changes)
((endp (cdr changes)) (car changes))
(t (cons 'and changes))))
(er-let* ((changes0 (accg-refine-ccmf2 i
(1- (ccmf-out-sizes ccmf))
matrix
(aref (ccmf-graph ccmf) i)
(aref ccms1 i)
hyps
f1
c1
f2
ccms2
cformals
args
redop
changes
old-hlevel
hlevel
qspv
state)))
(accg-refine-ccmf1 (1- i)
matrix
ccmf
hyps
f1
ccms1
c1
f2
ccms2
cformals
args
redop
changes0
old-hlevel
hlevel
qspv
state))))
other
(defun-raw accg-refine-ccmf
(ccmf hyps
f1
ccms1
c1
f2
ccms2
cformals
args
redop
old-hlevel
hlevel
qspv
state)
(let ((matrix (accg-ccmf-adj-matrix ccmf)))
(loop for
node
across
(ccmf-graph ccmf)
do
(setf (ccmf-node->-edges node) nil)
do
(setf (ccmf-node->=-edges node) nil))
(accg-refine-ccmf1 (1- (ccmf-in-sizes ccmf))
matrix
ccmf
hyps
f1
ccms1
c1
f2
ccms2
cformals
args
redop
nil
old-hlevel
hlevel
qspv
state)))
other
(defun-raw accg-node-refine-ccmfs-per-edge
(edges node1
accg
ccms1
c1
ruler1
cformals
args
stronger-proofsp
changes
old-hlevel
hlevel
qspv
state)
(if (endp edges)
(value changes)
(let* ((edge (car edges)) (node2 (aref accg (accg-edge-head edge)))
(ccms2 (accg-node-ccms node2))
(ruler2 (subcor-var-lst cformals args (accg-node-ruler node2)))
(wrld (access query-spec-var qspv :wrld)))
(pprogn (increment-timer 'other-time state)
(ccg-io? build/refine
nil
state
(node1 ruler1 wrld node2)
(fms "We use theorem prover queries to discen how the context ~
measures change when execution moves from call ~x0 in ~
function ~x1 under the ruler ~x2 to call ~x3 in ~
function ~x4 under the ruler ~x5.~|"
`((#\0 . ,(ACCG-NODE-CALL NODE1)) (#\1 . ,(ACCG-NODE-FN NODE1))
(#\2 . ,(UNTRANSLATE-LST RULER1 NIL WRLD))
(#\3 . ,(ACCG-NODE-CALL NODE2))
(#\4 . ,(ACCG-NODE-FN NODE2))
(#\5 . ,(UNTRANSLATE-LST (ACCG-NODE-RULER NODE2) NIL WRLD)))
*standard-co*
state
nil))
(increment-timer 'print-time state)
(er-let* ((nchanges (accg-refine-ccmf (accg-edge-ccmf edge)
(append ruler1 ruler2)
(accg-node-fn node1)
ccms1
c1
(accg-node-fn node2)
ccms2
cformals
args
stronger-proofsp
old-hlevel
hlevel
qspv
state)))
(accg-node-refine-ccmfs-per-edge (cdr edges)
node1
accg
ccms1
c1
ruler1
cformals
args
stronger-proofsp
(if (null nchanges)
changes
(acons (cons (car (accg-node-context-num node1))
(car (accg-node-context-num node2)))
nchanges
changes))
old-hlevel
hlevel
qspv
state))))))
other
(defun-raw accg-refine-ccmfs1
(i accg
stronger-proofsp
changes
old-hlevel
hlevel
qspv
state)
(if (< i 0)
(value changes)
(let* ((node1 (aref accg i)) (ccms1 (accg-node-ccms node1))
(c1 (accg-node-context-num node1))
(ruler1 (accg-node-ruler node1))
(cformals (accg-node-callformals node1))
(args (fargs (accg-node-call node1)))
(wrld (access query-spec-var qspv :wrld)))
(er-let* ((changes0 (if (hlevel-ccmfs-per-nodep hlevel)
(pprogn (ccg-io? build/refine
nil
state
(c1 ruler1 wrld)
(fms "We use theorem prover queries to discern how our ~
context mesaures change when execution moves ~
across call ~x0 in function ~x1 under the ruler ~
~x2.~|"
`((#\0 . ,(ACCG-NODE-CALL NODE1)) (#\1 . ,(ACCG-NODE-FN NODE1))
(#\2 . ,(UNTRANSLATE-LST RULER1 NIL WRLD)))
*standard-co*
state
nil))
(er-let* ((edge1 (value (car (accg-node-fwd-edges node1)))) (node2 (value (aref accg (accg-edge-head edge1))))
(ccmf (value (accg-edge-ccmf (car (accg-node-fwd-edges node1)))))
(nchanges (accg-refine-ccmf ccmf
ruler1
(accg-node-fn node1)
ccms1
c1
(accg-node-fn node2)
(accg-node-ccms node2)
cformals
args
stronger-proofsp
old-hlevel
hlevel
qspv
state))
(ngraph (value (ccmf-graph ccmf))))
(loop for
edge
in
(cdr (accg-node-fwd-edges node1))
for
occmf
=
(accg-edge-ccmf edge)
do
(setf (ccmf-graph occmf) (accg-copy-ccmf-graph ngraph))
finally
(return (value (if (null nchanges)
changes
(acons (car (accg-node-context-num node1)) nchanges changes)))))))
(accg-node-refine-ccmfs-per-edge (accg-node-fwd-edges node1)
node1
accg
ccms1
c1
ruler1
cformals
args
stronger-proofsp
changes
old-hlevel
hlevel
qspv
state))))
(accg-refine-ccmfs1 (1- i)
accg
stronger-proofsp
changes0
old-hlevel
hlevel
qspv
state)))))
other
(defun-raw accg-refine-ccmfs (accg stronger-proofsp old-hlevel hlevel qspv state) (accg-refine-ccmfs1 (1- (array-dimension accg 0)) accg stronger-proofsp nil old-hlevel hlevel qspv state))
other
(defun-raw accg-refine-ccmfs-lst1
(accgs caccgs
uaccgs
changes
stronger-proofsp
old-hlevel
hlevel
qspv
state)
(if (endp accgs)
(value (list* changes caccgs uaccgs))
(er-let* ((accg (value (car accgs))) (nchanges (accg-refine-ccmfs accg
stronger-proofsp
old-hlevel
hlevel
qspv
state)))
(accg-refine-ccmfs-lst1 (cdr accgs)
(if (consp nchanges)
(cons accg caccgs)
caccgs)
(if (consp nchanges)
uaccgs
(cons accg uaccgs))
(append nchanges changes)
stronger-proofsp
old-hlevel
hlevel
qspv
state))))
other
(defun-raw accg-refine-ccmfs-lst
(accgs stronger-proofsp old-hlevel hlevel qspv state)
(accg-refine-ccmfs-lst1 accgs
nil
nil
nil
stronger-proofsp
old-hlevel
hlevel
qspv
state))
other
(defun-raw prune-accg-node (node1 edges accg changes hlevel qspv state) (if (endp edges) (value changes) (let* ((edge (car edges)) (node2 (aref accg (accg-edge-head edge)))) (er-let* ((result (pprogn (increment-timer 'other-time state) (ccg-io? build/refine nil state (node1 node2) (fms "We attempt to prove that it is not possible for ~ execution to move from context ~x0 to context ~x1.~|" `((#\0 . ,(CAR (ACCG-NODE-CONTEXT-NUM NODE1))) (#\1 . ,(CAR (ACCG-NODE-CONTEXT-NUM NODE2)))) *standard-co* state nil)) (increment-timer 'print-time state) (accg-can-omit-edge? node1 node2 hlevel qspv state)))) (progn (unless result (setf (accg-node-fwd-edges node1) (cons edge (accg-node-fwd-edges node1))) (setf (accg-node-bwd-edges node2) (cons edge (accg-node-bwd-edges node2)))) (prune-accg-node node1 (cdr edges) accg (if result (acons (car (accg-node-context-num node1)) (car (accg-node-context-num node2)) changes) changes) hlevel qspv state))))))
other
(defun-raw prune-accg1 (i accg changes hlevel qspv state) (if (< i 0) (value changes) (let* ((node (aref accg i)) (edges (accg-node-fwd-edges node))) (setf (accg-node-fwd-edges node) nil) (er-let* ((nchanges (prune-accg-node node edges accg changes hlevel qspv state))) (prune-accg1 (1- i) accg nchanges hlevel qspv state)))))
other
(defun-raw prune-accg
(accg hlevel qspv state)
(loop for
node
across
accg
do
(setf (accg-node-bwd-edges node) nil))
(pprogn (ccg-io? build/refine
nil
state
nil
(fms "We attempt to prune the CCG by using theorem prover queries ~
to determine if the rulers of adjacent calling contexts are ~
incompatible.~|"
nil
*standard-co*
state
nil))
(prune-accg1 (1- (array-dimension accg 0))
accg
nil
hlevel
qspv
state)))
other
(defun-raw accg-refine-accg (accg stronger-proofsp old-hlevel hlevel qspv state) (er-let* ((accg-changes0 (if (and stronger-proofsp (not (hlevel-ccmfs-per-nodep hlevel))) (prune-accg accg hlevel qspv state) (value nil)))) (if (consp accg-changes0) (mv-let (accg-changes1 naccgs) (accg-separate-sccs accg :ccmfp t) (er-let* ((triple (accg-refine-ccmfs-lst naccgs stronger-proofsp old-hlevel hlevel qspv state))) (value (cons (cons (append accg-changes0 accg-changes1) (car triple)) naccgs)))) (er-let* ((changes0 (accg-refine-ccmfs accg stronger-proofsp old-hlevel hlevel qspv state))) (value (cons (cons nil changes0) (list accg)))))))
other
(defun-raw accg-refine-accgs1
(accgs ces
changes
caccgs
uaccgs
uces
stronger-proofsp
old-hlevel
new-hlevel
qspv
state)
(if (endp accgs)
(value (list* changes caccgs uaccgs uces))
(er-let* ((pair (accg-refine-accg (car accgs)
stronger-proofsp
old-hlevel
new-hlevel
qspv
state)))
(if (or (consp (caar pair)) (consp (cdar pair)))
(accg-refine-accgs1 (cdr accgs)
(cdr ces)
(cons (append (caar pair) (car changes))
(append (cdar pair) (cdr changes)))
(append (cdr pair) caccgs)
uaccgs
uces
stronger-proofsp
old-hlevel
new-hlevel
qspv
state)
(accg-refine-accgs1 (cdr accgs)
(cdr ces)
changes
caccgs
(append (cdr pair) uaccgs)
(cons (car ces) uces)
stronger-proofsp
old-hlevel
new-hlevel
qspv
state)))))
other
(defun-raw accg-refine-accgs (accgs ces old-hlevel new-hlevel qspv state) (pprogn (ccg-io? basics nil state (new-hlevel accgs) (fms "We now move to the ~x0 level of the hierarchy ~ (see :DOC CCG-hierarchy) in order to refine the remaining ~ SCC~#1~[~/s~] of our anotated CCG.~|" `((#\0 . ,NEW-HLEVEL) (#\1 . ,ACCGS)) *standard-co* state nil)) (er-let* ((tuple (accg-refine-accgs1 accgs ces nil nil nil nil (weaker-proof-techniquesp old-hlevel new-hlevel) old-hlevel new-hlevel qspv state)) (changes (value (car tuple))) (caccgs (value (cadr tuple))) (uaccgs (value (caddr tuple))) (uces (value (cdddr tuple)))) (pprogn (ccg-io? basics nil state (changes state) (mv-let (col state) (fmt "We have completed CCG refinement. " nil *standard-co* state nil) (print-changes col changes state))) (value (list* caccgs uaccgs uces))))))
other
(defun-raw srg-scc
(graph)
(ccg-generic-scc graph
(function srg-node-fwd-edges)
(function srg-node-bwd-edges)
(function srg-edge-tail)
(function srg-edge-head)))
other
(defun-raw srg-scc-has->-edgep
(scc scc-array srg)
(let ((scc-num (aref scc-array (car scc))))
(dolist (p scc nil)
(let ((x (aref srg p)))
(when (dolist (e (srg-node-fwd-edges x) nil)
(when (and (eq (srg-edge-label e) '>)
(= scc-num (aref scc-array (srg-edge-head e))))
(return t)))
(return t))))))
other
(defun-raw ccmf-remove-ccms
(ccmf first-del-array last-del-array)
(loop with
graph
=
(ccmf-graph ccmf)
for
i
from
0
below
(ccmf-in-sizes ccmf)
for
node
=
(aref graph i)
for
f
=
(lambda (x) (aref last-del-array x))
if
(aref first-del-array i)
do
(setf (aref graph i) (make-ccmf-node))
else
do
(setf (aref graph i)
(make-ccmf-node :>-edges (delete-if f (ccmf-node->-edges node))
:>=-edges (delete-if f (ccmf-node->=-edges node))))))
other
(defun-raw ccmf-remove-ccms-list
(ccmfs deletep-array)
(dolist (ccmf ccmfs nil)
(ccmf-remove-ccms ccmf
(aref deletep-array (ccmf-firstsite ccmf))
(aref deletep-array (ccmf-lastsite ccmf)))))
other
(defun-raw srg-restrict (srg ccms) (let* ((n (length ccms)) (rsrg (make-array n)) (a (make-array (array-dimension srg 0) :element-type 'fixnum :initial-element -1))) (loop for p in ccms for i from 0 for node = (aref srg p) do (setf (aref a p) i) do (setf (aref rsrg i) (make-srg-node :node (srg-node-node node) :ccm (srg-node-ccm node)))) (loop for p in ccms for i from 0 for node = (aref srg p) for nnode = (aref rsrg i) do (loop for e in (srg-node-fwd-edges node) unless (= (aref a (srg-edge-head e)) -1) do (let* ((head (aref a (srg-edge-head e))) (hnode (aref rsrg head)) (ne (make-srg-edge :head head :tail i :ccmf (srg-edge-ccmf e) :label (srg-edge-label e)))) (setf (srg-node-fwd-edges nnode) (cons ne (srg-node-fwd-edges nnode))) (setf (srg-node-bwd-edges hnode) (cons ne (srg-node-bwd-edges hnode)))))) rsrg))
other
(defun-raw srg-scc-for-node-aux (srg nn visited node-fwd-edges edge-head) (setf (aref visited nn) t) (loop for edge in (funcall node-fwd-edges (aref srg nn)) for head = (funcall edge-head edge) unless (aref visited head) do (srg-scc-for-node-aux srg head visited node-fwd-edges edge-head)))
other
(defun-raw srg-scc-for-node (srg nn) (let* ((n (array-dimension srg 0)) (in-scc-array (make-array n :element-type '(member t nil :ignore) :initial-element nil))) (let* ((n (array-dimension in-scc-array 0))) (srg-scc-for-node-aux srg nn in-scc-array (function srg-node-fwd-edges) (function srg-edge-head)) (loop for i from 0 below n if (aref in-scc-array i) do (setf (aref in-scc-array i) nil) else do (setf (aref in-scc-array i) :ignore)) (srg-scc-for-node-aux srg nn in-scc-array (function srg-node-bwd-edges) (function srg-edge-tail)) (loop for i from 0 below n when (eq (aref in-scc-array i) :ignore) do (setf (aref in-scc-array i) nil)) in-scc-array)))
other
(defun-raw srg-add-scc-for-node
(srg nn in-scc-array)
(if (aref in-scc-array nn)
in-scc-array
(let ((new-in-scc-array (srg-scc-for-node srg nn)))
(loop for
i
from
0
below
(length in-scc-array)
when
(and (not (aref in-scc-array i)) (aref new-in-scc-array i))
do
(setf (aref in-scc-array i) t))
in-scc-array)))
other
(defun-raw mtp
(srg ccmfs
num-contexts
fwd-edges
bwd-edges
edge-head
edge-tail)
(let* ((n (array-dimension srg 0)) (count (make-array `(,N ,NUM-CONTEXTS)
:element-type 'fixnum
:initial-element 0))
(accg-matrix (make-array `(,NUM-CONTEXTS ,NUM-CONTEXTS)
:element-type 'boolean
:initial-element nil))
(marked (make-array n :element-type 'boolean :initial-element nil))
(worklist nil))
(dolist (ccmf ccmfs)
(setf (aref accg-matrix
(ccmf-firstsite ccmf)
(ccmf-lastsite ccmf))
t))
(dotimes (i n)
(let ((node (aref srg i)))
(dolist (e (funcall fwd-edges node))
(incf (aref count
i
(srg-node-node (aref srg (funcall edge-head e))))))
(dotimes (j num-contexts)
(when (and (aref accg-matrix (srg-node-node node) j)
(= (aref count i j) 0))
(setf worklist (cons i worklist))
(setf (aref marked i) t)))))
(loop while
(consp worklist)
for
cw
=
(car worklist)
for
j
=
(srg-node-node (aref srg cw))
do
(setf worklist (cdr worklist))
do
(dolist (e (funcall bwd-edges (aref srg cw)))
(let ((i (funcall edge-tail e)))
(unless (aref marked i)
(decf (aref count i j))
(when (= (aref count i j) 0)
(setf (aref marked i) t)
(setf worklist (cons i worklist))))))
finally
(return (loop for
i
from
0
below
n
unless
(aref marked i)
collect
i)))))
other
(defun-raw mtp-fwd
(srg ccmfs num-contexts)
(mtp srg
ccmfs
num-contexts
(function srg-node-fwd-edges)
(function srg-node-bwd-edges)
(function srg-edge-head)
(function srg-edge-tail)))
other
(defun-raw mtp-bwd
(srg ccmfs num-contexts)
(mtp srg
ccmfs
num-contexts
(function srg-node-bwd-edges)
(function srg-node-fwd-edges)
(function srg-edge-tail)
(function srg-edge-head)))
other
(defun-raw fan-free
(srg edge-list other-node num-contexts)
(loop with
n
=
(array-dimension srg 0)
with
seen
=
(make-array num-contexts
:element-type 'boolean
:initial-element nil)
for
i
from
0
below
n
unless
(loop for
e
in
(funcall edge-list (aref srg i))
for
j
=
(funcall other-node e)
for
context
=
(srg-node-node (aref srg j))
if
(aref seen context)
return
nil
else
do
(setf (aref seen context) t)
finally
(return t))
return
nil
do
(loop for
i
from
0
below
num-contexts
do
(setf (aref seen i) nil))
finally
(return t)))
other
(defun-raw fan-in-free
(srg num-contexts)
(fan-free srg
(function srg-node-bwd-edges)
(function srg-edge-tail)
num-contexts))
other
(defun-raw fan-out-free
(srg num-contexts)
(fan-free srg
(function srg-node-fwd-edges)
(function srg-edge-head)
num-contexts))
other
(defun-raw mtp-to-anchor
(srg ahash)
(loop for
i
from
0
below
(array-dimension srg 0)
do
(loop for
e
in
(srg-node-fwd-edges (aref srg i))
when
(and (eq (srg-edge-label e) '>)
(not (gethash (srg-edge-ccmf e) ahash)))
do
(setf (gethash (srg-edge-ccmf e) ahash) t))
finally
(return ahash)))
other
(defun-raw simple-anchors
(srg ahash ccmfs num-contexts)
(let ((srgp (srg-restrict srg (mtp-fwd srg ccmfs num-contexts))))
(if (fan-in-free srgp num-contexts)
(mtp-to-anchor srgp ahash)
(let ((srgq (srg-restrict srg (mtp-bwd srg ccmfs num-contexts))))
(if (fan-out-free srgq num-contexts)
(mtp-to-anchor srgq ahash)
nil)))))
other
(defun-raw srg-restrict-edges
(srg pred)
(loop with
n
=
(array-dimension srg 0)
with
rsrg
=
(make-array n)
for
i
from
0
below
n
for
node
=
(aref srg i)
do
(setf (aref rsrg i)
(make-srg-node :node (srg-node-node node)
:ccm (srg-node-ccm node)
:fwd-edges (remove-if-not pred (srg-node-fwd-edges node))
:bwd-edges (remove-if-not pred (srg-node-bwd-edges node))))
finally
(return rsrg)))
other
(defun-raw srg-interior
(srg)
(multiple-value-bind (scc scc-array)
(srg-scc srg)
(declare (ignore scc))
(srg-restrict-edges srg
(lambda (e)
(eq (aref scc-array (srg-edge-tail e))
(aref scc-array (srg-edge-head e)))))))
other
(defun-raw srg-to-matrix
(srg)
(loop with
n
=
(array-dimension srg 0)
with
matrix
=
(make-array (list n n)
:element-type 'boolean
:initial-element nil)
for
i
from
0
below
n
do
(loop for
e
in
(srg-node-fwd-edges (aref srg i))
do
(setf (aref matrix i (srg-edge-head e)) t))
finally
(return matrix)))
other
(defun-raw ccmf-to-ccmfdown-in-srg
(srg ccmf ndgi-matrix)
(srg-restrict-edges srg
(lambda (e)
(not (and (eq (srg-node-node (aref srg (srg-edge-tail e)))
(ccmf-firstsite ccmf))
(eq (srg-node-node (aref srg (srg-edge-head e)))
(ccmf-lastsite ccmf))
(aref ndgi-matrix (srg-edge-tail e) (srg-edge-head e)))))))
other
(defun-raw anchor-find (srg ccmfs num-contexts) (let ((ahash (make-hash-table :rehash-size 2 :rehash-threshold (float 3/4)))) (multiple-value-bind (sccs scc-array) (srg-scc srg) (declare (ignore scc-array)) (dolist (scc sccs) (simple-anchors (srg-restrict srg scc) ahash ccmfs num-contexts)) (let ((anchors (loop for k being the hash-keys of ahash using (hash-value v) when v collect k))) (if anchors anchors (loop with ndgi-matrix = (srg-to-matrix (srg-interior (ndg srg))) for ccmf in ccmfs for h = (ccmf-to-ccmfdown-in-srg srg ccmf ndgi-matrix) when (or (mtp-fwd h ccmfs num-contexts) (mtp-bwd h ccmfs num-contexts)) return (list ccmf)))))))
other
(defun-raw copy-a-ccmf (ccmf) (make-ccmf :firstsite (ccmf-firstsite ccmf) :lastsite (ccmf-lastsite ccmf) :fc-num (ccmf-fc-num ccmf) :lc-num (ccmf-lc-num ccmf) :graph (accg-copy-ccmf-graph (ccmf-graph ccmf)) :in-sizes (ccmf-in-sizes ccmf) :out-sizes (ccmf-out-sizes ccmf) :steps (ccmf-steps ccmf)))
other
(defun-raw copy-ccmfs
(ccmfs)
(loop for
ccmf
in
ccmfs
collect
(copy-a-ccmf ccmf)))
other
(defun-raw copy-accg (accg) (let* ((n (array-dimension accg 0)) (naccg (make-array n))) (loop for i from 0 below n for node = (aref accg i) do (setf (aref naccg i) (make-accg-node :context (accg-node-context node) :num i))) (loop for node across accg for nnode across naccg do (setf (accg-node-fwd-edges nnode) (loop for edge in (accg-node-fwd-edges node) for head = (accg-edge-head edge) for hnode = (aref naccg head) for nedge = (make-accg-edge :tail (accg-edge-tail edge) :head head :ccmf (copy-a-ccmf (accg-edge-ccmf edge))) do (setf (accg-node-bwd-edges hnode) (cons nedge (accg-node-bwd-edges hnode))) collect nedge))) naccg))
other
(defun-raw accg-ccmfs
(accg)
(loop for
node
across
accg
append
(mapcar (function accg-edge-ccmf) (accg-node-fwd-edges node))))
other
(defun-raw accg-contexts (accg) (map 'vector (lambda (x) (accg-node-context x)) accg))
other
(defun-raw accg-srg-add-edge (tailnode headnode tailnum headnum ccmf label) (let ((edge (make-srg-edge :tail tailnum :head headnum :ccmf ccmf :label label))) (setf (srg-node-fwd-edges tailnode) (cons edge (srg-node-fwd-edges tailnode))) (setf (srg-node-bwd-edges headnode) (cons edge (srg-node-bwd-edges headnode))) nil))
other
(defun-raw accg-remove-edges-corresponding-to-ccmfs
(accg ccmfs)
(loop for
ccmf
in
ccmfs
do
(setf (ccmf-firstsite ccmf) -1))
(loop with
pred
=
(lambda (edge)
(= (ccmf-firstsite (accg-edge-ccmf edge)) -1))
for
node
across
accg
do
(setf (accg-node-fwd-edges node)
(delete-if pred (accg-node-fwd-edges node)))
do
(setf (accg-node-bwd-edges node)
(delete-if pred (accg-node-bwd-edges node))))
accg)
other
(defun-raw accg-construct-srg (accg) (let* ((n (array-dimension accg 0)) (node-offset (make-array n :element-type 'fixnum :initial-element 0)) (c 0)) (dotimes (i n) (setf (aref node-offset i) c) (incf c (array-dimension (accg-node-ccms (aref accg i)) 0))) (let ((srg (make-array c :element-type 'srg-node :initial-element (make-srg-node)))) (loop for i from 1 below c do (setf (aref srg i) (make-srg-node))) (loop for i from 0 below n do (loop for edge in (accg-node-fwd-edges (aref accg i)) for ccmf = (accg-edge-ccmf edge) for offset1 = (aref node-offset i) for offset2 = (aref node-offset (accg-edge-head edge)) for cg = (ccmf-graph ccmf) do (loop for j from 0 below (array-dimension cg 0) for a from offset1 for nodea = (aref srg a) do (setf (srg-node-node nodea) i) do (setf (srg-node-ccm nodea) j) do (loop for x in (ccmf-node->-edges (aref cg j)) for b = (+ offset2 x) do (accg-srg-add-edge nodea (aref srg b) a b ccmf '>)) do (loop for x in (ccmf-node->=-edges (aref cg j)) for b = (+ offset2 x) do (accg-srg-add-edge nodea (aref srg b) a b ccmf '>=)))) finally (return srg)))))
other
(defun-raw cln-accg (accg) (let* ((srg (accg-construct-srg accg)) (n (array-dimension accg 0)) (deletep-array (make-array n))) (dotimes (i n) (setf (aref deletep-array i) (make-array (array-dimension (accg-node-ccms (aref accg i)) 0) :element-type 'boolean :initial-element nil))) (multiple-value-bind (sccs scc-array) (srg-scc srg) (loop for scc in sccs unless (srg-scc-has->-edgep scc scc-array srg) do (loop for v in scc for node = (aref srg v) for context = (srg-node-node node) for ccm = (srg-node-ccm node) do (setf (aref (aref deletep-array context) ccm) t)))) (progn (ccmf-remove-ccms-list (accg-ccmfs accg) deletep-array) accg)))
other
(defun-raw scp
(accg)
(when accg
(let* ((n (array-dimension accg 0)) (anchors (anchor-find (accg-construct-srg accg) (accg-ccmfs accg) n)))
(when anchors
(mv-let (changes sccs)
(accg-separate-sccs (accg-remove-edges-corresponding-to-ccmfs accg anchors))
(declare (ignore changes))
(loop for
scc
in
sccs
unless
(scp (cln-accg scc))
return
nil
finally
(return t)))))))
other
(defstruct-raw scg-path (start 0 :type fixnum) (end 0 :type fixnum) (length 0 :type fixnum) (interior nil :type (or null fixnum cons)))
other
(defun-raw new-scg-path (start end) (make-scg-path :start start :end end :length 2 :interior nil))
other
(defun-raw compose-scg-paths (p1 p2) (make-scg-path :start (scg-path-start p1) :end (scg-path-end p2) :length (1- (+ (scg-path-length p1) (scg-path-length p2))) :interior (let ((x (if (null (scg-path-interior p2)) (scg-path-start p2) (cons (scg-path-start p2) (scg-path-interior p2))))) (if (null (scg-path-interior p1)) x (cons (scg-path-interior p1) x)))))
other
(defun-raw flatten-scg-interior (interior acc) (cond ((null interior) acc) ((atom interior) (cons interior acc)) (t (flatten-scg-interior (car interior) (flatten-scg-interior (cdr interior) acc)))))
other
(defun-raw flatten-scg-path
(path)
(cons (scg-path-start path)
(flatten-scg-interior (scg-path-interior path)
(list (scg-path-end path)))))
other
(defun-raw scg-path-equal (p1 p2) (and (= (scg-path-start p1) (scg-path-start p2)) (= (scg-path-end p1) (scg-path-end p2))))
other
(defun-raw path< (p1 p2) (or (< (scg-path-start p1) (scg-path-start p2)) (and (= (scg-path-start p1) (scg-path-start p2)) (< (scg-path-end p1) (scg-path-end p2)))))
other
(defun-raw shortest-scg-path (p1 p2) (if (<= (scg-path-length p1) (scg-path-length p2)) p1 p2))
other
(defstruct-raw scg (paths nil :type list) (newest-paths nil :type list) (new-newest-paths nil :type list) (num 0 :type fixnum) (graph nil))
other
(defun-raw sorted-set-union1 (lst1 lst2 key1 key2 predicate combine key test) (cond ((funcall test key1 key2) (cons (car lst1) (sorted-set-union (cdr lst1) (cdr lst2) predicate :key key :combine combine :test test))) ((funcall predicate key1 key2) (cons (car lst1) (if (endp (cdr lst1)) lst2 (sorted-set-union1 (cdr lst1) lst2 (funcall key (cadr lst1)) key2 predicate combine key test)))) (t (cons (car lst2) (if (endp (cdr lst2)) lst1 (sorted-set-union1 lst1 (cdr lst2) key1 (funcall key (cadr lst2)) predicate combine key test))))))
other
(defun-raw sorted-set-union
(lst1 lst2
predicate
&key
(key (function identity))
(combine (function (lambda (x y) (declare (ignore y)) x)))
(test (function equal)))
(cond ((endp lst1) lst2)
((endp lst2) lst1)
(t (sorted-set-union1 lst1
lst2
(funcall key (car lst1))
(funcall key (car lst2))
predicate
combine
key
test))))
other
(defun-raw sorted-set-difference1 (lst1 lst2 key1 key2 predicate key test) (cond ((funcall test key1 key2) (sorted-set-difference (cdr lst1) (cdr lst2) predicate :key key :test test)) ((funcall predicate key1 key2) (cons (car lst1) (if (endp (cdr lst1)) nil (sorted-set-difference1 (cdr lst1) lst2 (funcall key (cadr lst1)) key2 predicate key test)))) (t (if (endp (cdr lst2)) lst1 (sorted-set-difference1 lst1 (cdr lst2) key1 (funcall key (cadr lst2)) predicate key test)))))
other
(defun-raw sorted-set-difference (lst1 lst2 predicate &key (key (function identity)) (test (function equal))) (cond ((endp lst1) nil) ((endp lst2) lst1) (t (sorted-set-difference1 lst1 lst2 (funcall key (car lst1)) (funcall key (car lst2)) predicate key test))))
other
(defun-raw sorted-union/difference1 (lst1 lst2 key1 key2 predicate combine key test) (cond ((funcall test key1 key2) (mv-let (union difference) (sorted-union/difference (cdr lst1) (cdr lst2) predicate :combine combine :key key :test test) (mv (cons (funcall combine (car lst1) (car lst2)) union) difference))) ((funcall predicate key1 key2) (mv-let (union difference) (if (endp (cdr lst1)) (mv lst2 nil) (sorted-union/difference1 (cdr lst1) lst2 (funcall key (cadr lst1)) key2 predicate combine key test)) (mv (cons (car lst1) union) (cons (car lst1) difference)))) (t (mv-let (union difference) (if (endp (cdr lst2)) (mv lst1 lst1) (sorted-union/difference1 lst1 (cdr lst2) key1 (funcall key (cadr lst2)) predicate combine key test)) (mv (cons (car lst2) union) difference)))))
other
(defun-raw sorted-union/difference
(lst1 lst2
predicate
&key
(key (function identity))
(combine (function (lambda (x y) (declare (ignore y)) x)))
(test (function equal)))
(cond ((endp lst1) (mv lst2 nil))
((endp lst2) (mv lst1 lst1))
(t (sorted-union/difference1 lst1
lst2
(funcall key (car lst1))
(funcall key (car lst2))
predicate
combine
key
test))))
other
(defun-raw sorted-adjoin
(element set
predicate
&key
(key (function identity))
(combine (function (lambda (x y) (declare (ignore y)) x)))
(test (function equal)))
(sorted-set-union (list element)
set
predicate
:key key
:combine combine
:test test))
other
(defun-raw sorted-remove-duplicates1 (lst carkey key combine test) (if (endp (cdr lst)) lst (let ((cadrkey (funcall key (cadr lst)))) (if (funcall test carkey cadrkey) (let ((comb (funcall combine (car lst) (cadr lst)))) (sorted-remove-duplicates1 (cons comb (cddr lst)) (funcall key comb) key combine test)) (cons (car lst) (sorted-remove-duplicates1 (cdr lst) cadrkey key combine test))))))
other
(defun-raw sorted-remove-duplicates
(lst &key
(key (function identity))
(combine (function (lambda (x y) (declare (ignore y)) x)))
(test (function equal)))
(cond ((endp lst) nil)
((endp (cdr lst)) lst)
(t (sorted-remove-duplicates1 lst
(funcall key (car lst))
key
combine
test))))
other
(defun-raw list-to-sorted-set
(lst predicate
&key
(key (function identity))
(combine (function (lambda (x y) (declare (ignore y)) x)))
(test (function equal)))
(sorted-remove-duplicates (sort lst predicate :key key)
:key key
:combine combine
:test test))
other
(defun-raw scg-graph-key (graph) graph)
other
(defun-raw update-scg-paths (graph paths i graph-hash) (let* ((key (scg-graph-key graph)) (scg (gethash key graph-hash))) (if scg (let* ((new-newest-paths (scg-new-newest-paths scg)) (npaths (sorted-set-difference (sorted-set-difference paths (scg-paths scg) (function path<) :test (function scg-path-equal)) (scg-newest-paths scg) (function path<) :test (function scg-path-equal)))) (mv-let (union difference) (sorted-union/difference npaths new-newest-paths (function path<) :test (function scg-path-equal) :combine (function shortest-scg-path)) (progn (setf (scg-new-newest-paths scg) union) (mv i (endp new-newest-paths) difference scg)))) (let ((nscg (make-scg :graph graph :num i :new-newest-paths paths))) (setf (gethash key graph-hash) nscg) (mv (1+ i) t paths nscg)))))
other
(defun-raw age-scgs
(lst)
(loop for
scg
in
lst
do
(setf (scg-paths scg)
(sorted-set-union (scg-paths scg)
(scg-newest-paths scg)
(function path<)
:combine (function shortest-scg-path)
:test (function scg-path-equal)))
do
(setf (scg-newest-paths scg) (scg-new-newest-paths scg))
do
(setf (scg-new-newest-paths scg) nil)
finally
(return lst)))
other
(defun-raw ccmfs-to-scgs1 (ccmfs graph-hash i acc) (if (endp ccmfs) (mv i (sort acc (function <) :key (function scg-num))) (let ((ccmf (car ccmfs))) (mv-let (ni new? diff scg) (update-scg-paths (ccmf-graph ccmf) (list (new-scg-path (ccmf-firstsite ccmf) (ccmf-lastsite ccmf))) i graph-hash) (ccmfs-to-scgs1 (cdr ccmfs) graph-hash ni (if (and new? (consp diff)) (cons scg acc) acc))))))
other
(defun-raw ccmfs-to-scgs
(ccmfs graph-hash)
(ccmfs-to-scgs1 ccmfs graph-hash 0 nil))
other
(defun-raw compose-scg-graphs
(g h)
(loop with
n
=
(array-dimension g 0)
with
gh
=
(make-array (array-dimension g 0)
:element-type 'ccmf-node
:initial-element (make-ccmf-node))
for
i
below
n
for
nodei
=
(aref g i)
for
>-edges
=
nil
for
>=-edges
=
nil
do
(loop for
j
in
(ccmf-node->-edges nodei)
for
nodej
=
(aref h j)
do
(loop for
k
in
(ccmf-node->-edges nodej)
do
(setf >-edges (cons k >-edges)))
do
(loop for
k
in
(ccmf-node->=-edges nodej)
do
(setf >-edges (cons k >-edges))))
do
(loop for
j
in
(ccmf-node->=-edges nodei)
for
nodej
=
(aref h j)
do
(loop for
k
in
(ccmf-node->-edges nodej)
do
(setf >-edges (cons k >-edges)))
do
(loop for
k
in
(ccmf-node->=-edges nodej)
do
(setf >=-edges (cons k >=-edges))))
do
(let* ((sorted->-edges (list-to-sorted-set >-edges (function <))))
(setf (aref gh i)
(make-ccmf-node :>-edges sorted->-edges
:>=-edges (sorted-set-difference (list-to-sorted-set >=-edges (function <))
sorted->-edges
(function <)))))
finally
(return gh)))
other
(defun-raw compose-scg-path-lsts1 (gpath hpaths acc) (if (or (endp hpaths) (not (= (scg-path-start (car hpaths)) (scg-path-end gpath)))) acc (compose-scg-path-lsts1 gpath (cdr hpaths) (cons (compose-scg-paths gpath (car hpaths)) acc))))
other
(defun-raw compose-scg-path-lsts (gpaths hpaths acc) (cond ((or (endp gpaths) (endp hpaths)) (list-to-sorted-set acc (function path<) :test (function scg-path-equal) :combine (function shortest-scg-path))) ((< (scg-path-end (car gpaths)) (scg-path-start (car hpaths))) (compose-scg-path-lsts (cdr gpaths) hpaths acc)) ((> (scg-path-end (car gpaths)) (scg-path-start (car hpaths))) (compose-scg-path-lsts gpaths (cdr hpaths) acc)) (t (compose-scg-path-lsts (cdr gpaths) hpaths (compose-scg-path-lsts1 (car gpaths) hpaths acc)))))
other
(defun-raw scg-counter-example? (scg diff) (and (loop for path in diff when (= (scg-path-start path) (scg-path-end path)) return t finally (return nil)) (loop for path in (append (scg-paths scg) (scg-newest-paths scg) (sorted-set-difference (scg-new-newest-paths scg) diff (function path<) :test (function scg-path-equal))) when (= (scg-path-start path) (scg-path-end path)) return nil finally (return t)) (loop with graph = (scg-graph scg) for i from 0 below (array-dimension graph 0) when (member i (ccmf-node->-edges (aref graph i))) return nil finally (return t)) (let ((graph (scg-graph scg))) (equalp (compose-scg-graphs graph graph) graph))))
other
(defun-raw shortest-self-loop (paths path) (cond ((endp paths) path) ((= (scg-path-start (car paths)) (scg-path-end (car paths))) (shortest-self-loop (cdr paths) (if (or (null path) (< (scg-path-length (car paths)) (scg-path-length path))) (car paths) path))) (t (shortest-self-loop (cdr paths) path))))
other
(defun-raw compose-scgs
(g h i graph-hash)
(let ((ghgraph (compose-scg-graphs (scg-graph g) (scg-graph h))) (ghpaths (compose-scg-path-lsts (sort (copy-list (scg-newest-paths g))
(function <)
:key (function scg-path-end))
(scg-newest-paths h)
nil)))
(mv-let (ni new? diff gh)
(update-scg-paths ghgraph ghpaths i graph-hash)
(if (scg-counter-example? gh diff)
(mv t
ni
(cons (scg-graph gh)
(flatten-scg-path (shortest-self-loop diff nil))))
(mv nil
ni
(if (and new? (consp diff))
gh
nil))))))
other
(defun-raw scg-predecessors (scg) (sorted-remove-duplicates (mapcar (function scg-path-start) (scg-newest-paths scg))))
other
(defun-raw scg-successors
(scg)
(list-to-sorted-set (mapcar (function scg-path-end) (scg-newest-paths scg))
(function <)))
other
(defun-raw organize-scgs-by-preds1 (scgs array) (if (endp scgs) nil (let ((scg (car scgs))) (organize-scgs-by-preds1 (cdr scgs) array) (loop for i in (scg-predecessors scg) do (setf (aref array i) (cons scg (aref array i)))))))
other
(defun-raw organize-scgs-by-preds
(scgs numsites)
(let ((array (make-array numsites
:initial-element nil
:element-type 'list)))
(organize-scgs-by-preds1 scgs array)
array))
other
(defun-raw union-scgs
(scg-array indices)
(loop for
i
in
indices
append
(aref scg-array i)
into
union
finally
(return (list-to-sorted-set union (function <) :key (function scg-num)))))
other
(defun-raw copy-scgs
(scgs)
(loop for
scg
in
scgs
collect
(make-scg :graph (scg-graph scg)
:num (scg-num scg)
:paths (scg-paths scg)
:newest-paths (scg-newest-paths scg)
:new-newest-paths (scg-new-newest-paths scg))))
print-sct-loop-reportfunction
(defun print-sct-loop-report (iteration comps state) (ccg-io? performance nil state (iteration comps) (fms "Iteration: ~x0 Compositions: ~x1." (list (cons #\0 iteration) (cons #\1 comps)) *standard-co* state nil)))
other
(defun-raw print-sct-total-report (success? comps graph-hash start-time state) (mv-let (col state) (ccg-io? size-change nil (mv col state) (success?) (fmt "~%SCT has found ~#0~[no~/a~] counter-example to ~ termination. " (list (cons #\0 (if success? 0 1))) *standard-co* state nil) :default-bindings ((col 0))) (mv-let (col state) (ccg-io? performance nil (mv col state) (comps graph-hash start-time internal-time-units-per-second) (fmt1 "In the process, ~x0 total ~#1~[compositions ~ were~/composition was~] performed and ~x2 unique ~ ~#3~[graphs were~/graph was~] created. Total time taken ~ was ~x4 seconds.~|" (list (cons #\0 comps) (cons #\1 (if (= comps 1) 1 0)) (cons #\2 (hash-table-count graph-hash)) (cons #\3 (if (= (hash-table-count graph-hash) 1) 1 0)) (cons #\4 (/ (- (get-internal-run-time) start-time) (coerce internal-time-units-per-second 'float)))) col *standard-co* state nil) :default-bindings ((col 0))) (mv-let (col state) (ccg-io? size-change nil (mv col state) nil (fmt1 "~|" nil col *standard-co* state nil)) (declare (ignore col)) state))))
other
(defun-raw sct (ccmfs numsites state) (let ((graph-hash (make-hash-table :test 'equalp)) (start-time (get-internal-run-time))) (mv-let (i newest) (ccmfs-to-scgs ccmfs graph-hash) (progn (loop for scg in newest for nnp = (scg-new-newest-paths scg) when (scg-counter-example? scg nnp) do (return-from sct (value (cons (scg-graph scg) (flatten-scg-path (shortest-self-loop nnp nil)))))) (age-scgs newest) (loop with total-comps = 0 with generators = (organize-scgs-by-preds (copy-scgs newest) numsites) until (endp newest) for iteration from 0 for new-newest = nil for comps = 0 do (loop for g in newest for gsucc = (scg-successors g) do (loop for h in (union-scgs generators gsucc) do (mv-let (counter-example? ni gh) (compose-scgs g h i graph-hash) (progn (incf comps) (incf total-comps) (setf i ni) (cond (counter-example? (pprogn (increment-timer 'other-time state) (print-sct-loop-report iteration comps state) (print-sct-total-report nil total-comps graph-hash start-time state) (increment-timer 'print-time state) (return-from sct (value gh)))) (gh (setf new-newest (cons gh new-newest)))))))) do (age-scgs (list-to-sorted-set (append newest (copy-list new-newest)) (function <) :key (function scg-num))) do (setf newest new-newest) do (pprogn (increment-timer 'other-time state) (print-sct-loop-report iteration comps state) (increment-timer 'print-time state)) finally (pprogn (increment-timer 'other-time state) (print-sct-total-report t total-comps graph-hash start-time state) (increment-timer 'print-time state) (return (value nil))))))))
other
(defun-raw find-funct (fn functs) (cond ((endp functs) (make-funct :fn fn)) ((eq fn (funct-fn (car functs))) (car functs)) (t (find-funct fn (cdr functs)))))
other
(defun-raw t-machine-to-contexts (t-machine parent-funct functs) (if (endp t-machine) nil (let* ((tac (car t-machine)) (call (access tests-and-call tac :call))) (cons (make-context :ruler (access tests-and-call tac :tests) :call call :parent-funct parent-funct :call-funct (find-funct (ffn-symb call) functs)) (t-machine-to-contexts (cdr t-machine) parent-funct functs)))))
other
(defun-raw t-machines-to-contexts1 (t-machines functs all-functs) (if (endp t-machines) nil (cons (t-machine-to-contexts (car t-machines) (car functs) all-functs) (t-machines-to-contexts1 (cdr t-machines) (cdr functs) all-functs))))
other
(defun-raw t-machines-to-contexts (t-machines functs) (t-machines-to-contexts1 t-machines functs functs))
other
(defun-raw make-funct-structs (names arglists) (if (endp names) nil (cons (make-funct :fn (car names) :formals (car arglists)) (make-funct-structs (cdr names) (cdr arglists)))))
ccg-measures-declaredfunction
(defun ccg-measures-declared (measures) (and (consp measures) (or (not (equal (car measures) *0*)) (ccg-measures-declared (cdr measures)))))
other
(defun-raw context-array
(contexts)
(let ((carray (coerce (loop for
cs
in
contexts
append
cs)
'vector)))
(loop for
i
from
0
below
(length carray)
do
(setf (context-num (aref carray i)) (list i)))
carray))
other
(defun-raw accg-scp-list (lst proved unproved) (if (endp lst) (mv proved unproved) (let* ((accg (cln-accg (copy-accg (car lst))))) (cond ((scp (copy-accg accg)) (accg-scp-list (cdr lst) (cons accg proved) unproved)) (t (accg-scp-list (cdr lst) proved (cons (car lst) unproved)))))))
other
(defun-raw accg-sct-list1 (lst i n proved unproved ces state) (if (endp lst) (pprogn (let ((plen (len proved))) (ccg-io? basics nil state (plen unproved) (fms "Size-change analysis has proven ~x0 out of ~x1 SCCs of ~ the CCG terminating.~|" `((#\0 . ,PLEN) (#\1 . ,(+ PLEN (LEN UNPROVED)))) *standard-co* state nil))) (value (list* proved unproved ces))) (pprogn (increment-timer 'other-time state) (ccg-io? size-change nil state nil (fms "We now begin size change analysis on the ~n0 SCC out of ~ ~n1." (list (cons #\0 `(,I)) (cons #\1 n)) *standard-co* state nil)) (increment-timer 'print-time state) (let* ((accg (cln-accg (copy-accg (car lst))))) (if (null accg) (pprogn (increment-timer 'other-time state) (ccg-io? size-change nil state nil (fms "A trivial analysis has revealed that this SCC is ~ potentially non-terminating. We will set it aside ~ for further refinement.~|" nil *standard-co* state nil)) (increment-timer 'print-time state) (accg-sct-list1 (cdr lst) (1+ i) n proved (cons (car lst) unproved) (cons nil ces) state)) (er-let* ((ce (sct (accg-ccmfs accg) (array-dimension accg 0) state))) (if (null ce) (pprogn (increment-timer 'other-time state) (ccg-io? size-change nil state nil (fms "We have shown this SCC to be terminating, so we ~ do not need to refine it any further.~|" nil *standard-co* state nil)) (increment-timer 'print-time state) (accg-sct-list1 (cdr lst) (1+ i) n (cons accg proved) unproved ces state)) (pprogn (increment-timer 'other-time state) (ccg-io? size-change nil state nil (fms "This SCC is potentially non-terminating. We will ~ set it aside for further refinement.~|" nil *standard-co* state nil)) (increment-timer 'print-time state) (accg-sct-list1 (cdr lst) (1+ i) n proved (cons (car lst) unproved) (cons ce ces) state)))))))))
other
(defun-raw accg-sct-list (lst proved unproved ces state) (accg-sct-list1 lst 1 (len lst) proved unproved ces state))
ccg-counter-example-fn-name1function
(defun ccg-counter-example-fn-name1 (char-lst pkg i wrld) (declare (xargs :guard (and (standard-char-listp char-lst) (stringp pkg) (natp i) (plist-worldp wrld)))) (let ((name (fix-intern$ (coerce (append char-lst `(#\_) (explode-nonnegative-integer i 10 nil)) 'string) pkg))) (cond ((new-namep name wrld) (mv name i)) (t (ccg-counter-example-fn-name1 char-lst pkg (1+ i) wrld)))))
ccg-counter-example-fn-namefunction
(defun ccg-counter-example-fn-name (root i wrld) (declare (xargs :guard (and (symbolp root) (plist-worldp wrld) (natp i)))) (ccg-counter-example-fn-name1 (coerce (symbol-name root) 'list) (symbol-package-name root) i wrld))
assoc-set-eqfunction
(defun assoc-set-eq (key value alist) (declare (xargs :guard (and (symbolp key) (alistp alist)))) (cond ((endp alist) (acons key value alist)) ((eq key (caar alist)) (acons key value (cdr alist))) (t (assoc-set-eq key value (cdr alist)))))
assoc-eq-valuefunction
(defun assoc-eq-value (key default alist) (declare (xargs :guard (and (symbolp key) (alistp alist)))) (let ((pair (assoc-eq key alist))) (if (consp pair) (cdr pair) default)))
other
(defun-raw aref-lst (array lst) (mapcar (function (lambda (x) (aref array x))) lst))
other
(defun-raw alist-add-eq (alist key val) (cond ((endp alist) (acons key (list val) nil)) ((eq (caar alist) key) (acons key (cons val (cdar alist)) (cdr alist))) (t (cons (car alist) (alist-add-eq (cdr alist) key val)))))
other
(defun-raw order-names-arglists (names arglists rv-alist) (let* ((na-arrays (coerce (mapcar (lambda (x y) (coerce (cons x y) 'vector)) names arglists) 'vector)) (maxsize (loop for v across na-arrays maximize (array-dimension v 0)))) (loop for i from 1 below maxsize append (loop for array across na-arrays when (and (< i (array-dimension array 0)) (not (member-eq (aref array i) (cdr (assoc (aref array 0) rv-alist))))) collect (cons (aref array 0) (aref array i))))))
other
(defmacro-raw ccmf-tail-fn (ccmf contexts) `(context-fn (aref ,CONTEXTS (car (ccmf-fc-num ,CCMF)))))
other
(defmacro-raw ccmf-head-fn (ccmf contexts) `(context-fn (aref ,CONTEXTS (car (ccmf-lc-num ,CCMF)))))
other
(defun-raw restrict-ccmf (ccmf ccmr1 ccmr2) (let* ((graph (ccmf-graph ccmf)) (n (array-dimension graph 0)) (ngraph (make-array n :element-type 'ccmf-node :initial-element (make-ccmf-node))) (nccmf (make-ccmf :firstsite (ccmf-firstsite ccmf) :lastsite (ccmf-lastsite ccmf) :fc-num (ccmf-fc-num ccmf) :lc-num (ccmf-lc-num ccmf) :in-sizes (ccmf-in-sizes ccmf) :out-sizes (ccmf-out-sizes ccmf) :graph ngraph)) (f (lambda (x) (aref ccmr2 x)))) (loop for i from 0 below n for node = (aref graph i) if (aref ccmr1 i) do (setf (aref ngraph i) (make-ccmf-node :>-edges (remove-if-not f (ccmf-node->-edges node)) :>=-edges (remove-if-not f (ccmf-node->=-edges node)))) else do (setf (aref ngraph i) (make-ccmf-node))) (loop for node across ngraph when (or (consp (ccmf-node->-edges node)) (consp (ccmf-node->=-edges node))) return nccmf finally (return nil))))
other
(defun-raw can-solve-restricted-accgs?
(accgs ccmrs scp? state)
(loop for
accg
in
accgs
for
n
=
(array-dimension accg 0)
for
naccg
=
(make-array n)
do
(loop for
i
from
0
below
n
for
node
=
(aref accg i)
do
(setf (aref naccg i)
(make-accg-node :context (accg-node-context node) :num i)))
do
(loop for
i
from
0
below
n
for
node
=
(aref accg i)
for
nnode1
=
(aref naccg i)
for
ccmr1
=
(aref ccmrs (car (accg-node-context-num node)))
do
(loop for
edge
in
(accg-node-fwd-edges node)
for
ccmf
=
(accg-edge-ccmf edge)
for
ccmr2
=
(aref ccmrs (accg-edge-head edge))
for
nnode2
=
(aref naccg (accg-edge-head edge))
for
nccmf
=
(restrict-ccmf ccmf ccmr1 ccmr2)
if
nccmf
do
(let ((nedge (make-accg-edge :head (accg-edge-head edge)
:tail (accg-edge-tail edge)
:ccmf nccmf)))
(setf (accg-node-fwd-edges nnode1)
(cons nedge (accg-node-fwd-edges nnode1)))
(setf (accg-node-bwd-edges nnode2)
(cons nedge (accg-node-bwd-edges nnode2))))
else
do
(return-from can-solve-restricted-accgs? (value nil))))
do
(if scp?
(unless (scp (cln-accg naccg)) (return (value nil)))
(er-let* ((caccg (value (cln-accg naccg))) (ce (if (null caccg)
(value t)
(sct (accg-ccmfs caccg) n state))))
(unless (null ce) (return (value nil)))))
finally
(return (value t))))
other
(defun-raw create-ccm-restrictions
(contexts av-alist)
(loop with
n
=
(array-dimension contexts 0)
with
ccmrs
=
(make-array n)
for
i
from
0
below
n
for
context
=
(aref contexts i)
for
ccms
=
(context-ccms context)
for
vars
=
(cdr (assoc (context-fn context) av-alist))
for
m
=
(array-dimension ccms 0)
for
ccmri
=
(make-array m :element-type 'boolean :initial-element nil)
do
(setf (aref ccmrs i) ccmri)
do
(loop for
j
from
0
below
m
do
(setf (aref ccmri j)
(subsetp (all-vars (aref ccms j)) vars)))
finally
(return ccmrs)))
other
(defun-raw ruler-vars
(names contexts)
(loop with
rv-alist
=
(pairlis$ names nil)
for
context
across
contexts
for
fn
=
(context-fn context)
for
vars
=
(all-vars1-lst (context-ruler context) nil)
for
pair
=
(assoc fn rv-alist)
do
(setf (cdr pair) (union-eq vars (cdr pair)))
finally
(return rv-alist)))
other
(defun-raw cgma-aux (nalist proved-scp proved-sct contexts av-alist i state) (cond ((zp i) (let ((ccmrs (create-ccm-restrictions contexts av-alist))) (er-let* ((p1 (can-solve-restricted-accgs? proved-scp ccmrs t state)) (p2 (if p1 (can-solve-restricted-accgs? proved-sct ccmrs nil state) (value nil)))) (if p2 (value av-alist) (value nil))))) ((endp nalist) (value nil)) (t (er-let* ((nav-alist (cgma-aux (cdr nalist) proved-scp proved-sct contexts (alist-add-eq av-alist (caar nalist) (cdar nalist)) (1- i) state))) (if nav-alist (value nav-alist) (cgma-aux (cdr nalist) proved-scp proved-sct contexts av-alist i state))))))
other
(defun-raw ccg-generate-measure-alist1 (i nalist proved-scp proved-sct contexts rv-alist state) (er-let* ((av-alist (cgma-aux nalist proved-scp proved-sct contexts rv-alist i state))) (if av-alist (value (mapcar (lambda (x) (cons (car x) (cons :? (cdr x)))) av-alist)) (ccg-generate-measure-alist1 (1+ i) nalist proved-scp proved-sct contexts rv-alist state))))
other
(defun-raw ccg-generate-measure-alist (proved-scp proved-sct names arglists contexts cpn state) (let* ((rv-alist (if cpn (pairlis$ names nil) (ruler-vars names contexts))) (nalist (order-names-arglists names arglists rv-alist))) (ccg-generate-measure-alist1 0 nalist proved-scp proved-sct contexts rv-alist state)))
other
(defun-raw name-var-pairs1 (name arglist rst) (if (endp arglist) rst (acons name (car arglist) (name-var-pairs1 name (cdr arglist) rst))))
other
(defun-raw name-var-pairs (functs rv-alist) (if (endp functs) (mv nil nil) (mv-let (free fixed) (name-var-pairs (cdr functs) rv-alist) (let* ((funct (car functs)) (fn (funct-fn funct)) (rv (cdr (assoc fn rv-alist)))) (mv (name-var-pairs1 fn (set-difference-eq (funct-formals funct) rv) free) (name-var-pairs1 fn rv fixed))))))
other
(defun-raw get-ccm-vars1 (i ccms ccm-vars) (cond ((< i 0) ccm-vars) (t (setf (aref ccm-vars i) (all-vars (aref ccms i))) (get-ccm-vars1 (1- i) ccms ccm-vars))))
other
(defun-raw get-ccm-vars (ccms) (let ((len (array-dimension ccms 0))) (get-ccm-vars1 (1- len) ccms (make-array len :element-type 'list :initial-element nil))))
other
(defun-raw fn-ccm-vars-alist (functs) (if (endp functs) nil (let ((funct (car functs))) (acons (funct-fn funct) (get-ccm-vars (funct-ccms funct)) (fn-ccm-vars-alist (cdr functs))))))
other
(defun-raw gather-relevant-ccms1 (i var ccm-vars indices) (if (< i 0) indices (gather-relevant-ccms1 (1- i) var ccm-vars (if (member-eq var (aref ccm-vars i)) (cons i indices) indices))))
other
(defun-raw gather-relevant-ccms (var ccm-vars) (gather-relevant-ccms1 (1- (array-dimension ccm-vars 0)) var ccm-vars nil))
other
(defun-raw gather-all-relevant-ccms1 (avars alist) (if (endp avars) nil (let* ((avar (car avars)) (fn (car avar)) (var (cdr avar))) (cons (gather-relevant-ccms var (cdr (assoc fn alist))) (gather-all-relevant-ccms1 (cdr avars) alist)))))
other
(defun-raw gather-all-relevant-ccms (avars functs) (gather-all-relevant-ccms1 avars (fn-ccm-vars-alist functs)))
set-difference-and-intersectionfunction
(defun set-difference-and-intersection (set1 set2) (declare (xargs :guard (and (eqlable-listp set1) (eqlable-listp set2)))) (if (endp set1) (mv nil nil) (mv-let (difference intersection) (set-difference-and-intersection (cdr set1) set2) (if (member (car set1) set2) (mv difference (cons (car set1) intersection)) (mv (cons (car set1) difference) intersection)))))
other
(defun-raw ccmf-remove-relevant-edges1 (i graph relevant-ccms1 relevant-ccms2 edges-alist) (cond ((<= (array-dimension graph 0) i) edges-alist) ((and (consp relevant-ccms1) (= i (car relevant-ccms1))) (let* ((node (aref graph i)) (>-edges-i (ccmf-node->-edges node)) (>=-edges-i (ccmf-node->=-edges node))) (setf (ccmf-node->-edges node) nil) (setf (ccmf-node->=-edges node) nil) (ccmf-remove-relevant-edges1 (1+ i) graph (cdr relevant-ccms1) relevant-ccms2 (if (and (endp >-edges-i) (endp >=-edges-i)) edges-alist (acons i (cons >-edges-i >=-edges-i) edges-alist))))) ((consp relevant-ccms2) (let* ((node (aref graph i)) (>-edges-i (ccmf-node->-edges node)) (>=-edges-i (ccmf-node->=-edges node))) (mv-let (>-diff >-intersect) (set-difference-and-intersection >-edges-i relevant-ccms2) (mv-let (>=-diff >=-intersect) (set-difference-and-intersection >=-edges-i relevant-ccms2) (progn (when (consp >-intersect) (setf (ccmf-node->-edges node) >-diff)) (when (consp >=-intersect) (setf (ccmf-node->=-edges node) >=-diff)) (ccmf-remove-relevant-edges1 (1+ i) graph relevant-ccms1 relevant-ccms2 (if (and (endp >-intersect) (endp >=-intersect)) edges-alist (acons i (cons >-intersect >=-intersect) edges-alist)))))))) (t (ccmf-remove-relevant-edges1 (1+ i) graph relevant-ccms1 relevant-ccms2 edges-alist))))
other
(defun-raw ccmf-remove-relevant-edges
(ccmf relevant-ccms1 relevant-ccms2)
(let ((graph (ccmf-graph ccmf)))
(cons ccmf
(ccmf-remove-relevant-edges1 0
graph
relevant-ccms1
relevant-ccms2
nil))))
other
(defun-raw ccmf-remove-relevant-edges-lst (ccmfs contexts fn relevant-ccms acc) (if (endp ccmfs) acc (let* ((ccmf (car ccmfs)) (tcontext (aref contexts (car (ccmf-fc-num ccmf)))) (relevant-ccms1 (if (eq (context-fn tcontext) fn) relevant-ccms nil)) (hcontext (aref contexts (car (ccmf-lc-num ccmf)))) (relevant-ccms2 (if (eq (context-fn hcontext) fn) relevant-ccms nil))) (ccmf-remove-relevant-edges-lst (cdr ccmfs) contexts fn relevant-ccms (cons (ccmf-remove-relevant-edges ccmf relevant-ccms1 relevant-ccms2) acc)))))
other
(defun-raw accg-remove-relevant-ccmf-edges1 (i accg contexts fn relevant-ccms acc) (if (< i 0) acc (let* ((node (aref accg i))) (accg-remove-relevant-ccmf-edges1 (1- i) accg contexts fn relevant-ccms (if (eq (accg-node-fn node) fn) (let ((pred (lambda (edge) (equal (accg-node-fn (aref accg (accg-edge-tail edge))) fn)))) (ccmf-remove-relevant-edges-lst (append (mapcar (function accg-edge-ccmf) (accg-node-fwd-edges node)) (mapcar (function accg-edge-ccmf) (remove-if pred (accg-node-bwd-edges node)))) contexts fn relevant-ccms acc)) acc)))))
other
(defun-raw accg-remove-relevant-ccmf-edges (accg contexts fn relevant-ccms) (accg-remove-relevant-ccmf-edges1 (1- (array-dimension accg 0)) accg contexts fn relevant-ccms nil))
other
(defun-raw accg-remove-relevant-ccmf-edges-lst-tail (accgs contexts fn relevant-ccms acc) (if (endp accgs) acc (accg-remove-relevant-ccmf-edges-lst-tail (cdr accgs) contexts fn relevant-ccms (accg-remove-relevant-ccmf-edges1 (1- (array-dimension (car accgs) 0)) (car accgs) contexts fn relevant-ccms acc))))
other
(defun-raw accg-remove-relevant-ccmf-edges-lst
(accgs contexts fn relevant-ccms)
(accg-remove-relevant-ccmf-edges-lst-tail accgs
contexts
fn
relevant-ccms
nil))
other
(defun-raw restore-edges1 (ccmf alist) (if (endp alist) nil (let* ((entry (car alist)) (i (car entry)) (>-edges (cadr entry)) (>=-edges (cddr entry)) (node (aref (ccmf-graph ccmf) i))) (setf (ccmf-node->-edges node) (merge 'list >-edges (ccmf-node->-edges node) (function <))) (setf (ccmf-node->=-edges node) (merge 'list >=-edges (ccmf-node->=-edges node) (function <))) (restore-edges1 ccmf (cdr alist)))))
other
(defun-raw restore-edges (alist) (if (endp alist) nil (progn (restore-edges1 (caar alist) (cdar alist)) (restore-edges (cdr alist)))))
other
(defun-raw can-scp-lstp (accgs) (or (endp accgs) (and (scp (cln-accg (copy-accg (car accgs)))) (can-scp-lstp (cdr accgs)))))
other
(defun-raw can-sct-lstp (accgs state) (if (endp accgs) (value t) (let ((naccg (cln-accg (copy-accg (car accgs))))) (if (null naccg) (value nil) (er-let* ((ce (sct (accg-ccmfs naccg) (array-dimension naccg 0) state))) (if (null ce) (can-sct-lstp (cdr accgs) state) (value nil)))))))
remove-covered-subsets-tailfunction
(defun remove-covered-subsets-tail (avar subsets acc) (cond ((endp subsets) acc) ((equal avar (caar subsets)) (remove-covered-subsets-tail avar (cdr subsets) acc)) (t (remove-covered-subsets-tail avar (cdr subsets) (cons (car subsets) acc)))))
remove-covered-subsetsfunction
(defun remove-covered-subsets (avar subsets) (remove-covered-subsets-tail avar subsets nil))
remove-avar-from-subsets-tailfunction
(defun remove-avar-from-subsets-tail (avar subsets acc) (if (endp subsets) acc (remove-avar-from-subsets-tail avar (cdr subsets) (cons (if (equal avar (caar subsets)) (cdar subsets) (car subsets)) acc))))
remove-avar-from-subsetsfunction
(defun remove-avar-from-subsets (avar subsets) (remove-avar-from-subsets-tail avar subsets nil))
add-avar-to-subsets-tailfunction
(defun add-avar-to-subsets-tail (avar subsets acc) (if (endp subsets) acc (add-avar-to-subsets-tail avar (cdr subsets) (acons avar (car subsets) acc))))
add-avar-to-subsetsfunction
(defun add-avar-to-subsets (avar subsets) (add-avar-to-subsets-tail avar subsets nil))
other
(defun-raw all-termination1
(proved-scp proved-sct
contexts
avars
relevant-edges
subsets
state)
(cond ((member-equal 'nil subsets) (value 'nil))
((endp avars) (value '(nil)))
(t (let* ((avar (car avars)) (fn (car avar))
(re-info (accg-remove-relevant-ccmf-edges-lst-tail proved-sct
contexts
fn
(car relevant-edges)
(accg-remove-relevant-ccmf-edges-lst proved-scp
contexts
fn
(car relevant-edges)))))
(er-let* ((p (can-sct-lstp proved-sct state)) (nsubsets (if (and p (can-scp-lstp proved-scp))
(all-termination1 proved-scp
proved-sct
contexts
(cdr avars)
(cdr relevant-edges)
(remove-covered-subsets avar subsets)
state)
(value 'nil))))
(progn (restore-edges re-info)
(er-let* ((nnsubsets (all-termination1 proved-scp
proved-sct
contexts
(cdr avars)
(cdr relevant-edges)
(append nsubsets (remove-avar-from-subsets avar subsets))
state)))
(value (append nsubsets (add-avar-to-subsets avar nnsubsets))))))))))
other
(defun-raw funct-fns-lst (functs) (if (endp functs) nil (cons (funct-fn (car functs)) (cdr functs))))
append-to-allfunction
(defun append-to-all (list list-of-lists) (if (endp list-of-lists) nil (cons (append list (car list-of-lists)) (append-to-all list (cdr list-of-lists)))))
other
(defun-raw all-termination (proved-scp proved-sct contexts functs cpn state) (if (and (endp proved-scp) (endp proved-sct)) (value '(nil)) (let ((names (funct-fns-lst functs))) (mv-let (free fixed) (name-var-pairs functs (if cpn (pairlis$ names nil) (ruler-vars names contexts))) (let ((relevant-ccms (gather-all-relevant-ccms free functs))) (er-let* ((at1 (all-termination1 proved-scp proved-sct contexts free relevant-ccms nil state))) (value (append-to-all fixed at1))))))))
get-ccms1function
(defun get-ccms1 (m edcls key ctx state) (cond ((null edcls) (value m)) ((eq (caar edcls) 'xargs) (let ((temp (assoc-keyword key (cdar edcls)))) (cond ((null temp) (get-ccms1 m (cdr edcls) key ctx state)) ((equal m *0*) (get-ccms1 (cadr temp) (cdr edcls) key ctx state)) ((and (subsetp-equal m (cadr temp)) (subsetp-equal (cadr temp) m)) (get-ccms1 m (cdr edcls) key ctx state)) (t (er soft ctx "It is illegal to declare two different ~ sets values for the key ~x0 for the admission ~ of a single function. But you have specified ~ ~x0 ~x1 and ~x1 ~x2." key m (cadr temp)))))) (t (get-ccms1 m (cdr edcls) key ctx state))))
get-ccms2function
(defun get-ccms2 (lst key ctx state) (cond ((null lst) (value nil)) (t (er-let* ((m (get-ccms1 *0* (fourth (car lst)) key ctx state)) (rst (get-ccms2 (cdr lst) key ctx state))) (value (cons m rst))))))
get-ccmsfunction
(defun get-ccms (symbol-class lst key ctx state) (cond ((eq symbol-class :program) (value (make-list (length lst) :initial-element *0*))) (t (get-ccms2 lst key ctx state))))
translate-ccms-listfunction
(defun translate-ccms-list (ccms-list ctx wrld state) (cond ((endp ccms-list) (value nil)) (t (er-let* ((tccms (if (eq (car ccms-list) *0*) (value *0*) (translate-measures (car ccms-list) t ctx wrld state))) (rst (translate-ccms-list (cdr ccms-list) ctx wrld state))) (value (cons tccms rst))))))
chk-no-overlapfunction
(defun chk-no-overlap (consider consider-only) (cond ((endp consider) nil) ((not (or (eq (car consider) *0*) (eq (car consider-only) *0*))) (cons consider consider-only)) (t (chk-no-overlap (cdr consider) (cdr consider-only)))))
combine-ccm-hintsfunction
(defun combine-ccm-hints (consider consider-only uc uco ctx state) (cond ((endp consider) (value nil)) ((eq (car consider-only) *0*) (er-let* ((rst (combine-ccm-hints (cdr consider) (cdr consider-only) (cdr uc) (cdr uco) ctx state))) (value (acons nil (car consider) rst)))) ((eq (car consider) *0*) (er-let* ((rst (combine-ccm-hints (cdr consider) (cdr consider-only) (cdr uc) (cdr uco) ctx state))) (value (acons t (car consider-only) rst)))) (t (er soft ctx "It is illegal to provide both a :CONSIDER and ~ a :CONSIDER-ONLY hint for the same function. But ~ you have specified :CONSIDER ~x0 and :CONSIDER-ONLY ~x1." (car uc) (car uco)))))
*ccg-xargs-keywords*constant
(defconst *ccg-xargs-keywords* '(:consider-ccms :consider-only-ccms :termination-method :ccg-print-proofs :time-limit :ccg-hierarchy))
get-unambiguous-xargs-val1/edclsfunction
(defun get-unambiguous-xargs-val1/edcls (key v edcls ctx state) (cond ((null edcls) (value v)) ((eq (caar edcls) 'xargs) (let ((temp (assoc-keyword key (cdar edcls)))) (cond ((null temp) (get-unambiguous-xargs-val1/edcls key v (cdr edcls) ctx state)) ((or (consp v) (equal v (cadr temp))) (get-unambiguous-xargs-val1/edcls key (cadr temp) (cdr edcls) ctx state)) (t (er soft ctx "It is illegal to specify ~x0 ~x1 in one place and ~ ~x2 in another within the same definition. The ~ functionality controlled by that flag operates on ~ the entire event or not at all." key v (cadr temp)))))) (t (get-unambiguous-xargs-val1/edcls key v (cdr edcls) ctx state))))
get-unambiguous-xargs-val1function
(defun get-unambiguous-xargs-val1 (key lst ctx state) (cond ((null lst) (value '(unspecified))) (t (er-let* ((v (get-unambiguous-xargs-val1 key (cdr lst) ctx state)) (ans (get-unambiguous-xargs-val1/edcls key v (fourth (car lst)) ctx state))) (value ans)))))
get-unambiguous-xargs-valfunction
(defun get-unambiguous-xargs-val (key lst default ctx state) (er-let* ((x (get-unambiguous-xargs-val1 key lst ctx state))) (cond ((equal x '(unspecified)) (value default)) (t (value x)))))
chk-acceptable-ccg-xargsfunction
(defun chk-acceptable-ccg-xargs (fives symbol-class ctx wrld state) (er-let* ((untranslated-consider (get-ccms symbol-class fives :consider-ccms ctx state)) (consider (translate-ccms-list untranslated-consider ctx wrld state)) (untranslated-consider-only (get-ccms symbol-class fives :consider-only-ccms ctx state)) (consider-only (translate-ccms-list untranslated-consider-only ctx wrld state)) (ccms (combine-ccm-hints consider consider-only untranslated-consider untranslated-consider-only ctx state)) (verbose (get-unambiguous-xargs-flg :ccg-print-proofs fives (get-ccg-print-proofs) ctx state)) (time-limit (get-unambiguous-xargs-val :time-limit fives (get-ccg-time-limit wrld) ctx state))) (cond ((not (booleanp verbose)) (er soft ctx "The :CCG-PRINT-PROOFS specified by XARGS must either ~ be NIL or T. ~x0 is neither." verbose)) ((not (or (null time-limit) (rationalp time-limit))) (er soft ctx "The :TIME-LIMIT specified by XARGS must either be NIL ~ or a rational number. ~x0 is neither." time-limit)) (t (value (list ccms verbose time-limit))))))
?-ccm-lstpfunction
(defun ?-ccm-lstp (lst) (or (endp lst) (let ((ccm (car lst))) (and (true-listp ccm) (eq (car ccm) :?) (arglistp (cdr ccm)) (?-ccm-lstp (cdr lst))))))
ccg-redundant-measure-for-defunpfunction
(defun ccg-redundant-measure-for-defunp (def justification wrld) (let* ((name (car def)) (measure0 (if justification (access justification justification :measure) nil)) (dcls (butlast (cddr def) 1)) (measures (fetch-dcl-field :measure dcls))) (cond ((and (consp measure0) (eq (car measure0) :?)) (if (and (consp measures) (null (cdr measures)) (eq (caar measures) :?) (set-equalp-eq (cdar measures) (cdr measure0))) 'redundant (msg "the existing measure for ~x0 is ~x1, possibly indicating ~ it was previously proven terminating using the CCG ~ analysis. The new measure must therefore be explicitly ~ declared to be a call of :? on the measured subset; for ~ example, ~x1 will serve as the new :measure." name measure0))) (t (let* ((wrld1 (decode-logical-name name wrld)) (val (scan-to-cltl-command (cdr wrld1))) (old-def (assoc-eq name (cdddr val)))) (or (non-identical-defp-chk-measures name measures (fetch-dcl-field :measure (butlast (cddr old-def) 1)) justification) 'redundant))))))
ccg-redundant-subset-for-defunpfunction
(defun ccg-redundant-subset-for-defunp (chk-measurep chk-ccmsp def wrld) (let* ((name (car def)) (justification (getprop name 'justification 'nil 'current-acl2-world wrld)) (mok (if chk-measurep (ccg-redundant-measure-for-defunp def justification wrld) 'redundant))) (cond ((consp mok) mok) ((and chk-ccmsp justification) (let ((subset (access justification justification :subset)) (ccms-lst (fetch-dcl-field :consider-only-ccms (butlast (cddr def) 1)))) (if (or (null ccms-lst) (and (consp ccms-lst) (null (cdr ccms-lst)) (?-ccm-lstp (car ccms-lst)) (set-equalp-eq (all-vars1-lst (car ccms-lst) nil) subset))) 'redundant (msg "A redundant definition using CCG termination must use ~ the xarg :consider-only-ccms to declare a list of CCMs ~ of the form (:? ...) whose arguments are equal to the ~ measured subset of the previous definition. The ~ definition of ~x0 does not do this. The previously ~ defined version of this function has measured subset ~ ~x1. Thus, an appropriate list of CCMs to declare would ~ be ~x2." name subset `((:? ,@SUBSET)))))) (t 'redundant))))
ccg-redundant-subset-for-defunsp1function
(defun ccg-redundant-subset-for-defunsp1 (chk-measurep chk-ccmsp def-lst wrld ans) (if (endp def-lst) ans (let ((ans0 (ccg-redundant-subset-for-defunp chk-measurep chk-ccmsp (car def-lst) wrld))) (cond ((consp ans0) ans0) ((eq ans ans0) (ccg-redundant-subset-for-defunsp1 chk-measurep chk-ccmsp (cdr def-lst) wrld ans)) (t nil)))))
ccg-redundant-subset-for-defunspfunction
(defun ccg-redundant-subset-for-defunsp (chk-measurep chk-ccmsp def-lst wrld) (if (null def-lst) 'redundant (let ((ans (ccg-redundant-subset-for-defunp chk-measurep chk-ccmsp (car def-lst) wrld))) (if (consp ans) ans (ccg-redundant-subset-for-defunsp1 chk-measurep chk-ccmsp (cdr def-lst) wrld ans)))))
ccg-redundant-or-reclassifying-defunspfunction
(defun ccg-redundant-or-reclassifying-defunsp (chk-measurep chk-ccmsp defun-mode symbol-class ld-skip-proofsp def-lst wrld) (let* ((dcls (butlast (cddar def-lst) 1)) (termination-method (fetch-dcl-field :termination-method dcls)) (use-acl2p (and (consp termination-method) (eq (car termination-method) :measure))) (ans (redundant-or-reclassifying-defunsp0 defun-mode symbol-class ld-skip-proofsp use-acl2p def-lst wrld))) (cond ((or use-acl2p (consp ans) (not (eq ans 'redundant)) (not (eq defun-mode :logic)) ld-skip-proofsp) ans) (t (ccg-redundant-subset-for-defunsp chk-measurep chk-ccmsp def-lst wrld)))))
get-and-chk-ccg-hierarchyfunction
(defun get-and-chk-ccg-hierarchy (fives ctx wrld state) (er-let* ((hierarchy (get-unambiguous-xargs-val :ccg-hierarchy fives *0* ctx state))) (if (equal hierarchy *0*) (value (get-ccg-hierarchy wrld)) (er-progn (chk-ccg-hierarchy hierarchy ctx state) (value (fix-ccg-hierarchy hierarchy))))))
ccg-hierarchy-kinds-of-levelsfunction
(defun ccg-hierarchy-kinds-of-levels (hierarchy has-ccgp has-measurep) (declare (xargs :guard (and (hlevel-listp hierarchy) (booleanp has-ccgp) (booleanp has-measurep)))) (cond ((and has-ccgp has-measurep) (mv t t)) ((endp hierarchy) (mv has-ccgp has-measurep)) (t (let ((is-measurep (equal (caar hierarchy) :measure))) (ccg-hierarchy-kinds-of-levels (cdr hierarchy) (or has-ccgp (not is-measurep)) (or has-measurep is-measurep))))))
ccg-chk-acceptable-defunsfunction
(defun ccg-chk-acceptable-defuns (lst ctx wrld state) (er-let* ((fives (chk-defuns-tuples lst nil ctx wrld state)) (tm (get-unambiguous-xargs-flg :termination-method fives (get-termination-method wrld) ctx state)) (term-method (if (or (eq tm :ccg) (eq tm :measure)) (value tm) (er soft ctx "The :TERMINATION-METHOD flag must be :CCG or ~ :MEASURE, but ~x0 is none of these." tm))) (names (value (strip-cars fives)))) (er-progn (chk-no-duplicate-defuns names ctx state) (chk-xargs-keywords fives (if (eq term-method :ccg) (append *ccg-xargs-keywords* *xargs-keywords*) (cons :termination-method *xargs-keywords*)) ctx state) (er-let* ((tuple (chk-acceptable-defuns0 fives ctx wrld state)) (hierarchy (if (eq term-method :ccg) (get-and-chk-ccg-hierarchy fives ctx wrld state) (value nil)))) (let* ((stobjs-in-lst (car tuple)) (defun-mode (cadr tuple)) (non-executablep (caddr tuple)) (symbol-class (cdddr tuple))) (mv-let (has-ccgp has-measurep) (if (eq term-method :measure) (mv nil t) (ccg-hierarchy-kinds-of-levels hierarchy nil nil)) (let ((rc (ccg-redundant-or-reclassifying-defunsp has-measurep has-ccgp defun-mode symbol-class (ld-skip-proofsp state) lst wrld))) (cond ((eq rc 'redundant) (chk-acceptable-defuns-redundancy names defun-mode ctx wrld state)) ((eq rc 'verify-guards) (chk-acceptable-defuns-verify-guards-er names ctx wrld state)) ((and (eq rc 'reclassifying) (conditionally-memoized-fns names (table-alist 'memoize-table wrld))) (er soft ctx "It is illegal to verify termination (i.e., convert from ~ :program to :logic mode) for function~#0~[~/s~] ~&0, because ~ ~#0~[it is~/they are~] currently memoized with conditions; you ~ need to unmemoize ~#0~[it~/them~] first. See :DOC memoize." (conditionally-memoized-fns names (table-alist 'memoize-table wrld)))) (t (er-let* ((tuple1 (chk-acceptable-defuns1 names fives stobjs-in-lst defun-mode symbol-class rc non-executablep ctx wrld state)) (tuplec (if (eq term-method :measure) (value (list nil nil nil)) (chk-acceptable-ccg-xargs fives symbol-class ctx wrld state)))) (value (append (list 'chk-acceptable-defuns term-method) (cdr tuple1) tuplec `(,HIERARCHY)))))))))))))
find-?-ccm1function
(defun find-?-ccm1 (ccm-list) (and (consp ccm-list) (let ((ccm (car ccm-list))) (or (and (consp ccm) (eq (car ccm) :?) ccm) (find-?-ccm1 (cdr ccm-list))))))
find-?-ccmfunction
(defun find-?-ccm (names ccms) (if (endp ccms) nil (let ((bad-ccm (find-?-ccm1 (car ccms)))) (if bad-ccm (cons (car names) bad-ccm) (find-?-ccm (cdr names) (cdr ccms))))))
fns-without-consider-only-ccms-hintsfunction
(defun fns-without-consider-only-ccms-hints (names ccms) (if (endp ccms) nil (let ((rst (fns-without-consider-only-ccms-hints (cdr names) (cdr ccms)))) (if (and (consp (car ccms)) (caar ccms)) rst (cons (car names) rst)))))
other
(defun-raw ccm-o-p-clauses2 (contexts term clauses) (if (endp contexts) clauses (ccm-o-p-clauses2 (cdr contexts) term (conjoin-clause-to-clause-set (add-literal term (dumb-negate-lit-lst (context-ruler (car contexts))) t) clauses))))
other
(defun-raw ccm-o-p-clauses1 (contexts ccm-list clauses) (if (endp ccm-list) clauses (ccm-o-p-clauses1 contexts (cdr ccm-list) (ccm-o-p-clauses2 contexts (mcons-term* 'o-p (car ccm-list)) clauses))))
other
(defun-raw ccm-o-p-clauses0 (contexts ccm-list clauses) (cond ((endp contexts) clauses) ((eq (car ccm-list) *0*) (ccm-o-p-clauses0 (cdr contexts) (cdr ccm-list) clauses)) (t (ccm-o-p-clauses0 (cdr contexts) (cdr ccm-list) (ccm-o-p-clauses1 (car contexts) (car ccm-list) clauses)))))
other
(defun-raw ccm-o-p-clauses (contexts ccm-list) (ccm-o-p-clauses0 contexts ccm-list nil))
other
(defun-raw ccg-intermediate-step (accgs ces new-hlevel old-hlevel proved qspv state) (er-let* ((triple (accg-refine-accgs accgs ces old-hlevel new-hlevel qspv state)) (caccgs (value (car triple))) (uaccgs (value (cadr triple))) (uces (value (cddr triple)))) (cond ((endp caccgs) (pprogn (ccg-io? basics nil state nil (fms "Since we have no new information, we skip size ~ change analysis and attempt to further refine the ~ SCCs.~|" nil *standard-co* state nil)) (value (list* proved uaccgs uces)))) (t (pprogn (let ((clen (len caccgs))) (ccg-io? basics nil state (uaccgs clen caccgs) (fms "~@0 of the CCG ~#3~[was~/were~] altered. We ~ analyze ~#3~[it~/each of these~] with the size ~ change termination analysis.~@4~|" `((#\0 . ,(IF (CONSP UACCGS) "~N1 of the ~n2 SCCs" "~#3~[The sole SCC~/All the SCCs~]")) (#\1 . ,CLEN) (#\2 . ,(+ CLEN (LEN UACCGS))) (#\3 . ,CACCGS) (#\4 . ,(IF (ENDP UACCGS) "" " The others will be set aside ~ for further refinement."))) *standard-co* state nil))) (accg-sct-list caccgs proved uaccgs uces state))))))
other
(defun-raw ccg-measure-step
(hlevel names
t-machines
measure-alist
mp
rel
bodies
verbose
qspv
state)
(if (consp measure-alist)
(let ((ctx (access query-spec-var qspv :ctx)) (wrld (access query-spec-var qspv :wrld))
(ens (access query-spec-var qspv :ens))
(stop-time (access query-spec-var qspv :stop-time))
(otf-flg (access query-spec-var qspv :otf-flg))
(pt (cadr hlevel)))
(pprogn (ccg-io? basics
nil
state
(hlevel)
(fms "The current level of the CCG hierarchy is ~x0. We ~
therefore attempt a measure proof.~|"
`((#\0 . hlevel))
*standard-co*
state
nil))
(mv-let (erp pair state)
(er-let* ((hints (if (equal pt :built-in-clauses)
(translate-hints "Measure Built-in-clauses Hint"
'(("goal" :do-not '(eliminate-destructors eliminate-irrelevance
generalize
fertilize)
:in-theory (theory 'minimal-theory)
:do-not-induct :otf-flg-override))
ctx
wrld
state)
(value (translated-limit-induction-hint (cadr pt))))))
(state-global-let* ((inhibit-output-lst (if verbose
(@ inhibit-output-lst)
(list* 'event 'error (@ inhibit-output-lst)))))
(maybe-prover-before-stop-time stop-time
ctx
state
(prove-termination names
t-machines
measure-alist
mp
rel
hints
otf-flg
bodies
nil
ctx
ens
wrld
state
(f-get-global 'accumulated-ttree state)))))
(if erp
(er-progn (time-check stop-time ctx state)
(pprogn (ccg-io? basics
nil
state
nil
(fms "Since ACL2 has failed to prove the measure ~
conjecture, we continue with the hierarchical ~
analysis.~|"
nil
*standard-co*
state
nil))
(value nil)))
(pprogn (ccg-io? basics
nil
state
nil
(fms "ACL2 has succeeded in proving the measure ~
conjecture, thereby proving termination."
nil
*standard-co*
state
nil))
(value (list* :measure (car pair) measure-alist (cdr pair))))))))
(pprogn (ccg-io? basics
nil
state
(hlevel)
(fms "Skipping level ~x0 of the hierarchy due to previously ~
mentioned error when guessing measures."
`((#\0 . hlevel))
*standard-co*
state
nil))
(value nil))))
other
(defun-raw ccg
(accgs ces
last-ccg-hlevel
hierarchy
proved
context-array
names
arglists
t-machines
measure-alist
mp
rel
bodies
verbose
qspv
state)
(cond ((endp accgs) (pprogn (increment-timer 'other-time state)
(ccg-io? basics
nil
state
nil
(fms "We have successfully proven termination! We now weed ~
out irrelevant CCMs so that we can minimize the ~
measured-subset. This may require running the size ~
change analysis several more times.~|"
nil
*standard-co*
state
nil))
(increment-timer 'print-time state)
(er-let* ((ms (ccg-generate-measure-alist nil
proved
names
arglists
context-array
(hlevel-ccmfs-per-nodep last-ccg-hlevel)
state)))
(pprogn (mv-let (col state)
(io? event
nil
(mv col state)
(names ms)
(fmt "CCG analysis has succeeded in proving termination of ~
~&0 using CCMs over the following variables~#0~[~/, ~
respectively~]: ~&1. Thus, we admit ~#0~[this ~
function~/these ~ functions~] under the principle of ~
definition."
(list (cons #\0 names) (cons #\1 (strip-cddrs ms)))
*standard-co*
state
nil)
:default-bindings ((col 0)))
(value (list* :ccg col ms (f-get-global 'accumulated-ttree state))))))))
((endp hierarchy) (pprogn (ccg-io? basics
nil
state
nil
(fms "We have completed all levels of the hierarchy, but ~
have failed to prove termination."
nil
*standard-co*
state
nil))
(if (null (car ces))
state
(ccg-io? counter-example
nil
state
nil
(print-counter-example (car accgs)
(car ces)
context-array
(access query-spec-var qspv :ctx)
(access query-spec-var qspv :ens)
(access query-spec-var qspv :wrld)
state)))
(mv t nil state)))
((eq (caar hierarchy) :measure) (er-let* ((tuple (ccg-measure-step (car hierarchy)
names
t-machines
measure-alist
mp
rel
bodies
verbose
qspv
state)))
(if tuple
(value tuple)
(ccg accgs
ces
last-ccg-hlevel
(cdr hierarchy)
proved
context-array
names
arglists
t-machines
measure-alist
mp
rel
bodies
verbose
qspv
state))))
(t (er-let* ((tuple (state-global-let* ((inhibit-output-lst (if verbose
(@ inhibit-output-lst)
(list* 'prove 'proof-tree (@ inhibit-output-lst)))))
(ccg-intermediate-step accgs
ces
(car hierarchy)
last-ccg-hlevel
proved
qspv
state))) (nproved (value (car tuple)))
(naccgs (value (cadr tuple)))
(nces (value (cddr tuple))))
(ccg naccgs
nces
(car hierarchy)
(cdr hierarchy)
nproved
context-array
names
arglists
t-machines
measure-alist
mp
rel
bodies
verbose
qspv
state)))))
other
(defun-raw build-accgs (names contexts functs ccm-hints wrld state) (let* ((context-array (context-array contexts)) (accgs (build-and-annotate-accgs names functs contexts (pairlis$ names ccm-hints)))) (pprogn (increment-timer 'other-time state) (ccg-io? basics nil state (names context-array accgs) (pprogn (fms "We begin with the Calling Context Graph (CCG), ~ containing the following contexts (if the output doesn't ~ make sense, see :DOC CCG and also the paper referenced ~ above):~|" nil *standard-co* state nil) (print-context-array1 0 names context-array state) (fms "and the following edges:~|" nil *standard-co* state nil) (print-accg-edges1 accgs state) (fms "We have annotated the CCG with the following calling ~ context measures (CCMs):~|" nil *standard-co* state nil) (print-funct-ccms functs wrld state))) (increment-timer 'print-time state) (pprogn (ccg-io? basics nil state nil (fms "Before we begin the hierarchical analysis, we run our ~ size-change analysis so we have a baseline for refinement." nil *standard-co* state nil)) (er-let* ((tuple (accg-sct-list accgs nil nil nil state))) (value (cons context-array tuple)))))))
max-induction-depth1function
(defun max-induction-depth1 (hierarchy max) (declare (xargs :guard (and (hlevel-listp hierarchy) (integerp max) (<= -1 max)))) (if (endp hierarchy) max (max-induction-depth1 (cdr hierarchy) (cond ((or (equal (caar hierarchy) :measure) (equal (hlevel-proof-technique (car hierarchy)) :built-in-clauses)) max) (t (max max (cadr (hlevel-proof-technique (car hierarchy)))))))))
max-induction-depthfunction
(defun max-induction-depth (hierarchy) (max-induction-depth1 hierarchy -1))
ruler-extender-printout1function
(defun ruler-extender-printout1 (names ruler-extenders-lst) (if (endp names) nil (cons `("function ~x0 has ruler extenders ~x1" (#\0 . ,(CAR NAMES)) (#\1 . ,(CAR RULER-EXTENDERS-LST))) (ruler-extender-printout1 (cdr names) (cdr ruler-extenders-lst)))))
ruler-extender-printoutfunction
(defun ruler-extender-printout (names ruler-extenders-lst) `("" "~@*." "~@*, and " "~@*, " ,(RULER-EXTENDER-PRINTOUT1 NAMES RULER-EXTENDERS-LST)))
other
(defun-raw prove-termination-with-ccg
(names functs
contexts
ruler-extenders-lst
ccm-hints
hierarchy
verbose
time-limit
arglists
measures
t-machines
mp
rel
otf-flg
bodies
ctx
ens
wrld
state
ttree)
(let* ((ccms (mapcar (function cdr) ccm-hints)) (entry (find-?-ccm names ccms))
(stop-time (if time-limit
(+ (get-internal-run-time)
(* internal-time-units-per-second time-limit))
nil))
(qspv (make query-spec-var
:stop-time stop-time
:mem (create-memoization (max-induction-depth hierarchy))
:otf-flg otf-flg
:ens ens
:ctx ctx
:wrld wrld)))
(cond ((and entry (not (ld-skip-proofsp state))) (let ((fn (car entry)) (ccm (cdr entry)))
(er soft
ctx
"A CCM of the form (:? v1 ... vk) is only legal when the defun is ~
redundant (see :DOC redundant-events) or when skipping proofs ~
(see :DOC ld-skip-proofsp). The CCM ~x0 supplied for function ~
symbol ~x1 is thus illegal."
ccm
fn)))
((null contexts) (mv-let (col state)
(io? event
nil
(mv col state)
(names)
(fmt "Since ~&0 is non-recursive, its admission is trivial. "
(list (cons #\0 names))
(proofs-co state)
state
nil)
:default-bindings ((col 0)))
(value (list* :ccg (or col 0) nil nil))))
((ld-skip-proofsp state) (let ((fns (fns-without-consider-only-ccms-hints names ccms)))
(if (consp fns)
(er soft
ctx
"Proofs cannot be skipped on a CCG termination proof unless ~
CCMs are defined for every function. You did not supply CCMs ~
for function~#0~[~/s~] ~&0. Therefore, proofs cannot be skipped."
fns)
(value (list* :ccg 0
(pairlis$ names
(mapcar (lambda (x) `(:? ,@(ALL-VARS1-LST (CDR X) NIL)))
ccms))
nil)))))
(t (pprogn (ccg-io? basics
nil
state
(names ruler-extenders-lst)
(fms "Attempting to prove termination using Calling Context Graph ~
(CCG) analysis. There are various ways in which users can ~
control CCG analysis. See the :DOC CCG for details. This ~
analysis is described in a 2006 CAV paper by Manolios and ~
Vroon.~|~%The ruler-extenders for each function are as follows: ~
~*0~|"
`((#\0 . ,(RULER-EXTENDER-PRINTOUT NAMES RULER-EXTENDERS-LST)))
*standard-co*
state
nil))
(simplify-contexts contexts ens wrld ctx state)
(mv-let (o-p-clauses ttree)
(clean-up-clause-set (ccm-o-p-clauses contexts ccms)
ens
wrld
ttree
state)
(er-let* ((ttree (accumulate-ttree-and-step-limit-into-state ttree
:skip state)))
(pprogn (increment-timer 'other-time state)
(er-let* ((displayed-goal (value (prettyify-clause-set o-p-clauses
(let*-abstractionp state)
wrld))) (simp-phrase (value (tilde-*-simp-phrase ttree)))
(ttree1 (if o-p-clauses
(pprogn (io? event
nil
state
(ttree displayed-goal simp-phrase)
(fms "You have told us to consider CCMs that are not ~
trivially proved to be ordinals. ~
Therefore, the conjecture that we must prove ~
before we can continue with the CCG ~
analysis~#0~[~/, given ~*1,~] is ~
~@2~%~%Goal~%~Q34."
`((#\0 . ,(IF (NTH 4 SIMP-PHRASE)
1
0)) (#\1 . ,SIMP-PHRASE)
(#\2 . ,(IF (TAGGED-OBJECTSP 'SR-LIMIT TTREE)
" as follows (where the ~
subsumption/replacement limit ~
affected this analysis; see :DOC ~
case-split-limitations)."
""))
(#\3 . ,DISPLAYED-GOAL)
(#\4 . ,(TERM-EVISC-TUPLE NIL STATE)))
(proofs-co state)
state
nil))
(increment-timer 'print-time state)
(prove (termify-clause-set o-p-clauses)
(make-pspv ens
wrld
state
:displayed-goal displayed-goal
:otf-flg otf-flg)
nil
ens
wrld
ctx
state))
(value ttree))))
(mv-let (has-ccgp has-measurep)
(ccg-hierarchy-kinds-of-levels hierarchy nil nil)
(er-let* ((ba-tuple (if has-ccgp
(build-accgs names contexts functs ccm-hints wrld state)
(list* (make-array 0
:initial-element (make-context)
:element-type 'context)
`(,(MAKE-ARRAY 0 :INITIAL-ELEMENT (MAKE-ACCG-NODE) :ELEMENT-TYPE 'ACCG-NODE))
`(,(MAKE-ARRAY 0 :INITIAL-ELEMENT (MAKE-ACCG-NODE) :ELEMENT-TYPE 'ACCG-NODE))
`(nil)))) (context-array (value (car ba-tuple)))
(proved-accgs (value (cadr ba-tuple)))
(accgs (value (caddr ba-tuple)))
(ces (value (cdddr ba-tuple)))
(measure-alist (if (not has-measurep)
(value nil)
(mv-let (erp ma state)
(guess-measure-alist names
arglists
measures
t-machines
ctx
wrld
state)
(if (not erp)
(value ma)
(pprogn (ccg-io? basics
nil
state
(names)
(fms "Since there was an error guessing the ~
measure~#0~[~/s~], we will skip all levels ~
of the hierarchy of the form (:MEASURE ~
PT).~|"
`((#\0 . ,NAMES))
*standard-co*
state
nil))
(value nil)))))))
(er-let* ((quadruple (ccg accgs
ces
nil
hierarchy
proved-accgs
context-array
names
arglists
t-machines
measure-alist
mp
rel
bodies
verbose
qspv
state)))
(let* ((term-method (car quadruple)) (col (cadr quadruple))
(measure-alist (caddr quadruple))
(ttree-new (cdddr quadruple)))
(prog2$ nil
(value (list* term-method
col
measure-alist
(cons-tag-trees ttree-new ttree1)))))))))))))))))
other
(defun-raw ccg-prove-termination-recursive
(names arglists
measures
ccm-hints
ruler-extenders-lst
t-machines
mp
rel
verbose
time-limit
hierarchy
otf-flg
bodies
ctx
ens
wrld
state)
(let ((functs (make-funct-structs names arglists)))
(prove-termination-with-ccg names
functs
(t-machines-to-contexts t-machines functs)
ruler-extenders-lst
ccm-hints
hierarchy
verbose
time-limit
arglists
measures
t-machines
mp
rel
otf-flg
bodies
ctx
ens
wrld
state
nil)))
other
(defun-raw ccg-put-induction-info
(names arglists
term-method
measures
ccms
ruler-extenders-lst
bodies
mp
rel
verbose
time-limit
hierarchy
hints
otf-flg
big-mutrec
measure-debug
ctx
ens
wrld
state)
(prog2$ (choke-on-loop$-recursion nil
names
(car bodies)
'ccg-put-induction-info)
(let ((wrld1 (putprop-recursivep-lst nil nil names bodies wrld)))
(cond ((and (null (cdr names))
(null (getprop (car names)
'recursivep
nil
'current-acl2-world
wrld1))) (er-let* ((tuple (prove-termination-non-recursive names
bodies
mp
rel
hints
otf-flg
big-mutrec
ctx
ens
wrld1
state)))
(value (cons nil tuple))))
(t (let ((t-machines (termination-machines nil
nil
names
nil
bodies
ruler-extenders-lst)))
(er-let* ((wrld1 (update-w t wrld1)) (quadruple (if (eq term-method :measure)
(er-let* ((triple (prove-termination-recursive names
arglists
measures
t-machines
mp
rel
hints
otf-flg
bodies
measure-debug
ctx
ens
wrld1
state)))
(value (cons :measure triple)))
(ccg-prove-termination-recursive names
arglists
measures
ccms
ruler-extenders-lst
t-machines
mp
rel
verbose
time-limit
hierarchy
otf-flg
bodies
ctx
ens
wrld1
state))))
(let* ((term-method (car quadruple)) (col (cadr quadruple))
(measure-alist (caddr quadruple))
(ttree (cdddr quadruple)))
(er-let* ((tuple (put-induction-info-recursive nil
names
arglists
col
ttree
measure-alist
t-machines
ruler-extenders-lst
bodies
mp
rel
wrld1
state)))
(value (cons term-method tuple)))))))))))
defun-redundant-get-ccmsfunction
(defun defun-redundant-get-ccms (fives wrld) (if (endp fives) nil (let ((subset (access justification (getprop (first (car fives)) 'justification (make justification :subset 'nil) 'current-acl2-world wrld) :subset))) (cons `((:? ,@SUBSET)) (defun-redundant-get-ccms (cdr fives) wrld)))))
defun-redundant-get-measuresfunction
(defun defun-redundant-get-measures (fives wrld) (if (endp fives) nil (let ((subset (access justification (getprop (first (car fives)) 'justification (make justification :subset 'nil) 'current-acl2-world wrld) :subset))) (cons `(:? ,@SUBSET) (defun-redundant-get-measures (cdr fives) wrld)))))
remove-keywordsfunction
(defun remove-keywords (keys lst) (cond ((endp lst) nil) ((member-eq (car lst) keys) (remove-keywords keys (cddr lst))) (t (list* (car lst) (cadr lst) (remove-keywords keys (cddr lst))))))
remove-dcls0function
(defun remove-dcls0 (edcls keys) (cond ((endp edcls) nil) ((eq (caar edcls) 'xargs) (let ((newlst (remove-keywords keys (cdar edcls)))) (if (endp newlst) (remove-dcls0 (cdr edcls) keys) (acons 'xargs newlst (remove-dcls0 (cdr edcls) keys))))) (t (cons (car edcls) (remove-dcls0 (cdr edcls) keys)))))
remove-dclsfunction
(defun remove-dcls (fives keys) (cond ((endp fives) nil) ((endp (nth 3 (car fives))) (cons (car fives) (remove-dcls (cdr fives) keys))) (t (cons (update-nth 3 (remove-dcls0 (nth 3 (car fives)) keys) (car fives)) (remove-dcls (cdr fives) keys)))))
update-keywordfunction
(defun update-keyword (key val lst) (cond ((endp lst) (list key val)) ((eq (car lst) key) (cons key (cons val (remove-keywords `(,KEY) (cddr lst))))) (t (cons (car lst) (cons (cadr lst) (update-keyword key val (cddr lst)))))))
unambiguously-fix-dcls0function
(defun unambiguously-fix-dcls0 (edcls key val) (cond ((endp edcls) (list (cons 'xargs (list key val)))) ((eq (caar edcls) 'xargs) (acons 'xargs (update-keyword key val (cdar edcls)) (remove-dcls0 (cdr edcls) `(,KEY)))) (t (cons (car edcls) (unambiguously-fix-dcls0 (cdr edcls) key val)))))
unambiguously-fix-dclsfunction
(defun unambiguously-fix-dcls (fives key vals) (cond ((endp fives) nil) (t (cons (update-nth 3 (unambiguously-fix-dcls0 (nth 3 (car fives)) key (car vals)) (car fives)) (unambiguously-fix-dcls (cdr fives) key (cdr vals))))))
fives-to-defuns0function
(defun fives-to-defuns0 (fives) (if (endp fives) nil (let* ((five (car fives)) (name (first five)) (args (second five)) (doc (third five)) (dcls (fourth five)) (body (fifth five)) (d1 (list body)) (d2 (if doc (cons doc d1) d1)) (d3 (if dcls (acons 'declare dcls d2) d2))) (cons `(defun ,NAME ,ARGS ,@D3) (fives-to-defuns0 (cdr fives))))))
fives-to-defunsfunction
(defun fives-to-defuns (fives) `(with-output :off (summary event) ,(IF (ENDP (CDR FIVES)) (CAR (FIVES-TO-DEFUNS0 FIVES)) (CONS 'MUTUAL-RECURSION (FIVES-TO-DEFUNS0 FIVES)))))
dynamic-make-event-fnfunction
(defun dynamic-make-event-fn (body event-form state) (make-event-fn `',BODY nil nil nil nil event-form state))
defun-make-eventfunction
(defun defun-make-event (names fives symbol-class term-method wrld event-form state) (if (or (eq symbol-class :program) (and (null (cdr names)) (null (getprop (car names) 'recursivep nil 'current-acl2-world wrld)))) (value (cond ((null (cdr names)) (car names)) (t names))) (let* ((fives0 (remove-dcls fives (if (eq term-method :measure) *ccg-xargs-keywords* (list* :hints :measure :well-founded-relation *ccg-xargs-keywords*)))) (fives1 (unambiguously-fix-dcls fives0 :termination-method (make-list (length fives) :initial-element :measure))) (fives2 (if (eq term-method :measure) fives1 (unambiguously-fix-dcls fives1 :measure (defun-redundant-get-measures fives wrld))))) (er-progn (state-global-let* ((accumulated-ttree nil) (inhibit-output-lst (cons 'summary (@ inhibit-output-lst)))) (dynamic-make-event-fn (fives-to-defuns fives2) event-form state)) (value (cond ((null (cdr names)) (car names)) (t names)))))))
other
(defun-raw ccg-defuns-fn0
(names arglists
docs
pairs
guards
term-method
measures
ccms
ruler-extenders-lst
mp
rel
verbose
time-limit
hierarchy
hints
guard-hints
std-hints
otf-flg
guard-debug
guard-simplify
measure-debug
bodies
symbol-class
normalizeps
split-types-terms
new-lambda$-alist-pairs
non-executablep
type-prescription-lst
ctx
wrld
state)
(cond ((eq symbol-class :program) (defuns-fn-short-cut nil
nil
names
docs
pairs
guards
measures
split-types-terms
bodies
non-executablep
ctx
wrld
state))
(t (let ((ens (ens state)) (big-mutrec (big-mutrec names)))
(er-let* ((tuple (ccg-put-induction-info names
arglists
term-method
measures
ccms
ruler-extenders-lst
bodies
mp
rel
verbose
time-limit
hierarchy
hints
otf-flg
big-mutrec
measure-debug
ctx
ens
wrld
state)))
(defuns-fn1 (cdr tuple)
ens
big-mutrec
names
arglists
docs
pairs
guards
guard-hints
std-hints
otf-flg
guard-debug
guard-simplify
bodies
symbol-class
normalizeps
split-types-terms
new-lambda$-alist-pairs
non-executablep
type-prescription-lst
ctx
state))))))
other
(defun-bridge ccg-defuns-fn (def-lst state event-form) :program (value nil) :raw (with-ctx-summarized (defun-ctx def-lst) (let ((wrld (w state)) (def-lst0 def-lst) (event-form (or event-form (list 'defuns def-lst)))) (revert-world-on-error (er-let* ((tuple (ccg-chk-acceptable-defuns def-lst ctx wrld state)) (fives (chk-defuns-tuples def-lst nil ctx wrld state))) (cond ((eq (car tuple) 'redundant) (stop-redundant-event ctx state :name (caar def-lst) :defun-mode (cdr tuple) :def-lst def-lst0)) (t (enforce-redundancy event-form ctx wrld (let ((term-method (nth 1 tuple)) (names (nth 2 tuple)) (arglists (nth 3 tuple)) (docs (nth 4 tuple)) (pairs (nth 5 tuple)) (guards (nth 6 tuple)) (measures (nth 7 tuple)) (ruler-extenders-lst (nth 8 tuple)) (mp (nth 9 tuple)) (rel (nth 10 tuple)) (hints (nth 11 tuple)) (guard-hints (nth 12 tuple)) (std-hints (nth 13 tuple)) (otf-flg (nth 14 tuple)) (bodies (nth 15 tuple)) (symbol-class (nth 16 tuple)) (normalizeps (nth 17 tuple)) (reclassifyingp (nth 18 tuple)) (wrld (nth 19 tuple)) (non-executablep (nth 20 tuple)) (guard-debug (nth 21 tuple)) (measure-debug (nth 22 tuple)) (split-types-terms (nth 23 tuple)) (new-lambda$-alist-pairs (nth 24 tuple)) (guard-simplify (nth 25 tuple)) (type-prescription-lst (nth 26 tuple)) (ccms (nth 27 tuple)) (verbose (nth 28 tuple)) (time-limit (nth 29 tuple)) (hierarchy (nth 30 tuple))) (er-let* ((pair (ccg-defuns-fn0 names arglists docs pairs guards term-method measures ccms ruler-extenders-lst mp rel verbose time-limit hierarchy hints guard-hints std-hints otf-flg guard-debug guard-simplify measure-debug bodies symbol-class normalizeps split-types-terms new-lambda$-alist-pairs non-executablep type-prescription-lst ctx wrld state))) (er-progn (chk-assumption-free-ttree nil ctx state) (install-event-defuns names event-form def-lst0 symbol-class reclassifyingp non-executablep pair ctx wrld state) (if (or (eq symbol-class :program) (ld-skip-proofsp state) (and (null (cdr names)) (null (getprop (car names) 'recursivep nil 'current-acl2-world (w state))))) (value (cond ((null (cdr names)) (car names)) (t names))) (defun-make-event names fives symbol-class term-method (car pair) event-form state)))))))))))))
other
(logic)
local
(local (set-slow-alist-action nil))
other
(program)
other
(redefun defuns-fn (def-lst state event-form) (ccg-defuns-fn def-lst state event-form))
other
(progn+touchable :all (redefun+rewrite defstobj-fn (:carpat (process-embedded-events %1% %2% %3% %4% %5% (append . %app-cdr%) . %pee-cdr%) :repl (process-embedded-events %1% %2% %3% %4% %5% (append '((set-termination-method :measure)) . %app-cdr%) . %pee-cdr%) :vars (%1% %2% %3% %4% %5% %app-cdr% %pee-cdr%) :mult 1)))
include-book
(include-book "xdoc/top" :dir :system)
other
(defxdoc ccg :parents (acl2-sedan proof-automation) :short "A powerful automated termination prover for ACL2" :long "<p>In order to see how the CCG analysis works, consider the following definition of Ackermann's function from exercise 6.15 in the ACL2 textbook:</p> @({ (defun ack (x y) (if (zp x) 1 (if (zp y) (if (equal x 1) 2 (+ x 2)) (ack (ack (1- x) y) (1- y))))) }) <p>ACL2 cannot automatically prove the termination of @('ack') using its measure-based termination proof. In order to admit the function, the user must supply a measure. An example measure is @('(make-ord 1 (1+ (acl2s-size y)) (acl2s-size x))'), which is equivalent to the ordinal @('w * (1+ (acl2s-size y)) + (acl2s-size x)'), where @('w') is the first infinite ordinal.</p> <p>The CCG analysis, on the other hand, automatically proves termination as follows. Note that there are two recursive calls. These calls, along with their rulers (i.e. the conditions under which the recursive call is reached) are called <i>calling contexts</i>, or sometimes just <i>contexts</i> (for more on rulers, see @(see ruler-extenders)). For @('ack'), these are:</p> @({ 1. (ack (1- x) y) with ruler ((not (zp x)) (not (zp y))). 2. (ack (ack (1- x) y) (1- y)) with ruler ((not (zp x)) (not (zp y))). }) <p>These calling contexts are used to build a <i>calling context graph (CCG)</i>, from which our analysis derives its name. This graph has an edge from context @('c1') to context @('c2') when it is possible that execution can move from context @('c1') to context @('c2') in one ``step'' (i.e. without visiting any other contexts). For our example, we get the complete graph, with edges from each context to both contexts.</p> <p>The analysis next attempts to guess <i>calling context measures (CCMs)</i>, or just <i>measures</i>, for each function. These are similar to ACL2 measures, in that they are ACL2 terms that must provably be able to evaluate to an ordinal value (unlike ACL2 measures, CCG currently ignores the current well-founded relation setting). However, functions may have multiple CCMs, instead of one, like ACL2, and the CCG analysis has some more sophisticated heuristics for guessing appropriate measures. However, there is a mechanism for supplying measures to the CCG analysis if you need to see @(see CCG-XARGS). In our example, the CCG analysis will guess the measures @('(acl2s-size x)'), @('(acl2s-size y)'), and @('(+ (acl2s-size x) (acl2s-size y))'). This last one turns out to be unimportant for the termination proof. However, note that the first two of these measures are components of the ordinal measure that we gave ACL2 to prove termination earlier. As one might guess, these are important for the success of our CCG analysis.</p> <p>Like ACL2's measure analysis, we are concerned with what happens to these values when a recursive call is made. However, we are concerned not just with decreasing measures, but also non-increasing measures. Thus, we construct <i>Calling Context Measure Functions (CCMFs)</i>, which tell us how one measure compares to another across recursive calls.</p> <p>In our example, note that when the recursive call of the context 1 is made, the new value of @('(acl2s-size x)') is less than the original value of @('(acl2s-size x)'). More formally, we can prove the following:</p> @({ (implies (and (not (zp x)) (not (zp y))) (o< (acl2s-size (1- x)) (acl2s-size x))) }) <p>For those of you that are familiar with measure-based termination proofs in ACL2, this should look familiar, as it has the same structure as such a termination proof. However, we also note the following trivial observation:</p> @({ (implies (and (not (zp x)) (not (zp y))) (o<= (acl2s-size y) (acl2s-size y))) }) <p>That is, @('y') stays the same across this recursive call. For the other context, we similarly note that @('(acl2s-size y)') is decreasing. However, we can say nothing about the value of @('(acl2s-size x)'). The CCG algorithm does this analysis using queries to the theorem prover that are carefully restricted to limit prover time.</p> <p>Finally, the CCG analysis uses this local information to do a global analysis of what happens to values. This analysis asks the question, for every infinite path through our CCG, @('c_1'), @('c_2'), @('c_3'), ..., is there a natural number @('N') such that there is an infinite sequence of measures @('m_N'), @('m_(N+1)'), @('m_(N+2)'), ... such that each @('m_i') is a measure for the context @('c_i') (i.e. a measure for the function containing @('ci')), we have proven that the @('m_(i+1)') is never larger than @('m_i'), and for infinitely many @('i'), it is the case that we have proven that @('m_i') is always larger than @('m_(i+)'). That's a bit of a mouthful, but what we are essentially saying is that, for every possible infinite sequence of recursions it is the case that after some finite number of steps, we can start picking out measures such that they never increase and infinitely often they decrease. Since these measures return ordinal values, we then know that there can be no infinite recursions, and we are done.</p> <p>For our example, consider two kinds of infinite paths through our CCG: those that visit context 2 infinitely often, and those that don't. In the first case, we know that @('(acl2s-size y)') is never increasing, since a visit to context 1 does not change the value of @('y'), and a visit to context 2 decreases the value of @('(acl2s-size y)'). Furthermore, since we visit context 2 infinitely often, we know that @('(acl2s-size y)') is infinitely decreasing along this path. Therefore, we have met the criteria for proving no such path is a valid computation. In the case in which we do not visit context 2 infinitely often, there must be a value @('N') such that we do not visit context 2 any more after the @('N')th context in the path. After this, we must only visit context 1, which always decreases the value of @('(acl2s-size x)'). Therefore, no such path can be a valid computation. Since all infinite paths through our CCG either visit context 2 infinitely often or not, we have proven termination. This analysis of the local data in the global context is done automatically by a decision procedure.</p> <p>That is a brief overview of the CCG analysis. Note that, can it prove many functions terminating that ACL2 cannot. It also does so using simpler measures. In the @('ack') example, we did not require any infinite ordinal measures to prove termination using CCG. Intuitively, CCG is in a way putting together the measures for you so you don't have to think about the ordinal structure. Thus, even when the CCG analysis to prove termination, it is often easier to give it multiple simple measures and allow it to put together the global termination argument than to give ACL2 the entire measure so it can prove that it decreases every single step.</p> <p>To find out more about interacting and controlling the CCG analysis, see the topics included in this section.</p>")
other
(defxdoc ccg-xargs :parents (ccg) :short "Giving hints to CCG analysis via See @(see xargs)" :long "<p>In addition to the @(tsee xargs) provided by ACL2 for passing @(see hints) to function definitions, the CCG analysis enables several others for guiding the CCG termination analysis for a given function definition. The following example is nonsensical but illustrates all of these xargs:</p> @({ (declare (xargs :termination-method :ccg :consider-ccms ((foo x) (bar y z)) :consider-only-ccms ((foo x) (bar y z)) :ccg-print-proofs nil :time-limit 120 :ccg-hierarchy *ccg-hierarchy-hybrid*)) General Form: (xargs :key1 val1 ... :keyn valn) }) <p>Where the keywords and their respective values are as shown below.</p> <p>Note that the :TERMINATION-METHOD @('xarg') is always valid, but the other @('xargs') listed above are only valid if the termination method being used for the given function is :CCG.</p> <p>@(':TERMINATION-METHOD value')<br></br> @('Value') here is either @(':CCG') or @(':MEASURE'). For details on the meaning of these settings, see the documentation for @(tsee set-termination-method). If this @('xarg') is given, it overrides the global setting for the current definition. If the current definition is part of a @(tsee mutual-recursion), and a @(':termination-method') is provided, it must match that provided by all other functions in the @('mutual-recursion').</p> <p>@(':CONSIDER-CCMS value') or @(':CONSIDER-ONLY-CCMS value')<br></br> @('Value') is a list of terms involving only the formals of the function being defined. Both suggest measures for the current function to the CCG analysis. ACL2 must be able to prove that each of these terms always evaluate to an ordinal see @(see ordinals). ACL2 will attempt to prove this before beginning the CCG analysis. The difference between @(':consider-ccms') and @(':consider-only-ccms') is that if @(':consider-ccms') is used, the CCG analysis will attempt to guess additional measures that it thinks might be useful for proving termination, whereas if @(':consider-only-ccms') is used, only the measures given will be used for the given function in the CCG analysis. These two @('xargs') may not be used together, and attempting to do so will result in an error.</p> <p>@(':CCG-PRINT-PROOFS value')<br></br> @('Value') is either @('t') or @('nil'). This is a local override of the @(tsee set-ccg-print-proofs) setting. See this documentation topic for details.</p> <p>@(':TIME-LIMIT value')<br></br> @('Value') is either a positive rational number or nil. This is a local override of the @(tsee set-ccg-time-limit) setting. See this documentation topic for details.</p> <p>@(':CCG-HIERARCHY value')<br></br> @('Value') is a CCG hierarchy. This is a local override of the @(tsee set-ccg-hierarchy) setting. See this documentation topic for details.</p>")
other
(defxdoc get-ccg-inhibit-output-lst :parents (ccg) :short "Returns the list of ``kinds'' of output that will be inhibited during CCG analysis" :long "@({ Examples: (get-ccg-inhibit-output-lst) :get-ccg-inhibit-output-lst }) <p>See See @(see set-ccg-inhibit-output-lst).</p>")
other
(defxdoc get-ccg-print-proofs :parents (ccg) :short "Returns the setting that controls whether proof attempts are printed during CCG analysis" :long "@({ Examples: (get-ccg-print-proofs) :get-ccg-print-proofs }) <p>See See @(see set-ccg-print-proofs) for details.</p>")
other
(defxdoc get-ccg-time-limit :parents (ccg) :short "Returns the current default ccg-time-limit setting." :long "@({ Examples: (get-ccg-time-limit (w state)) }) <p>This will return the time-limit as specified by the current world.</p> @({ General Form: (get-time-limit wrld) }) <p>where @('wrld') is a @(see world). For information on the settings and their meaning, see @(see set-termination-method).</p>")
other
(defxdoc get-termination-method :parents (ccg) :short "Returns the current default termination method." :long "@({ Examples: (get-termination-method (w state)) }) <p>This will return the termination-method as specified by the current world.</p> @({ General Form: (get-termination-method wrld) }) <p>where @('wrld') is a @(see world). For information on the settings and their meaning, see @(see set-termination-method).</p>")
other
(defxdoc set-ccg-hierarchy :parents (ccg) :short "Set the default hierarchy of techniques for CCG-based termination analysis." :long "@({ (set-ccg-hierarchy ((:built-in-clauses :equal t) (:measure (:induction-depth 1)) ((:induction-depth 0) :EQUAL t) ((:induction-depth 1) :EQUAL t) ((:induction-depth 1) :ALL t) ((:induction-depth 1) :SOME t) ((:induction-depth 1) :NONE t) ((:induction-depth 1) :EQUAL nil) ((:induction-depth 1) :ALL nil) ((:induction-depth 1) :SOME nil) ((:induction-depth 1) :NONE nil))) :set-ccg-hierarchy ((:built-in-clauses :equal t) ((:induction-depth 0) :EQUAL t) ((:induction-depth 1) :EQUAL t) ((:induction-depth 1) :ALL t) ((:induction-depth 1) :SOME t) ((:induction-depth 1) :NONE t)) General Form: (set-ccg-hierarchy v) }) <p>where @('v') is @(':CCG-ONLY'), @(':CCG-ONLY-CPN'), @(':HYBRID'), @(':HYBRID-CPN'), or a non-empty list of hierarchy levels, which either have the form @('(pt ccm-cs cpn)') or the form @('(:measure pt)'), where @('pt') is either @(':built-in-clauses') or @('(:induction-depth n)') for some natural number @('n'), @('ccm-cs') is one of @(':EQUAL'), @(':ALL'), @(':SOME'), or @(':NONE'), and @('cpn') is @('t') or @('nil').</p> <p>Each level of the hierarchy describes techniques used to prove termination. Termination proofs performed after admitting this event will use the specified techniques in the order in which they are listed.</p> <p>Basically, the CCG analysis as described and illustrated at a high level in the documentation for @(see CCG) can potentially be very expensive. In order to make the analysis as efficient as possible, we use less expensive (and less powerful) techniques first, and resort to more powerful and expensive techniques only when these fail.</p> <p>There are three ways of varying the CCG analysis, which are represented by each of the three elements in a hierarchy level (levels of the form @('(:measure pt)') will be explained later).</p> <p>@('Pt') tells the CCG analysis how to limit proof attempts. The idea behind this is that ACL2 is designed to prove statements that the user thinks are true. It therefore does everything it can to prove the conjecture. As ACL2 useres already know, this can lead to very long, or even non-terminating proof attempts. The CCG analysis, on the other hand, sends multiple queries to the theorem prover that may or may not be true, in order to improve the accuracy of the analysis. It is therefore necessary to reign in ACL2's proof attempts to keep them from taking too long. Of course, the trade-off is that, the more we limit ACL2's prover, the less powerful it becomes.</p> <p>@('Pt') can be @(':built-in-clauses'), which tells ACL2 to use only @(see built-in-clause)s analysis. This is a very fast, and surprisingly powerful proof technique. For example, the definition of Ackermann's function given in the documentation for @(see CCG) is solved using only this proof technique.</p> <p>@('Pt') can also be of the form @('(:induction-depth n)'), where @('n') is a natural number. This uses the full theorem prover, but limits it in two ways. First, it stops proof attempts if ACL2 has been working on a subgoal with no case splitting or induction for 20 steps (that is, at a goal of the form 1.5'20'). It also limits the <i>induction depth</i>, which describes how many times we allow induction goals to lead to further induction goals. For example, @('(:induction-depth 0)') allows no induction, while @('(:induction-depth 1)') allows goals of the form @('*1') or @('*2'), but stops if it creates a goal such as @('*1.1') or @('*2.1').</p> <p>@('Ccm-cs') limits which CCMs are compared using the theorem prover. Consider again the @('ack') example in the documentation for @(see CCG). All we needed was to compare the value of @('(acl2s-size x)') before and after the recursive call and the value of @('(acl2s-size y)') before and after the recursive call. We would learn nothing, and waste time with the theorem prover if we compared @('(acl2s-size x)') to @('(acl2s-size y)'). However, other times, it is important to compare CCMs with each other, for example, when arguments are permuted, or we are dealing with a mutual recursion.</p> <p>@('Ccm-cs') can be one of @(':EQUAL'), @(':ALL'), @(':SOME'), or @(':NONE'). These limit which CCMs we compare based on the variables they mention. Let @('c') be a recursive call in the body of function @('f') that calls function @('g'). Let @('m1') be a CCM for @('f') and @('m2') be a CCM for @('g'). Let @('v1') be the formals mentioned in @('m1') and @('v2') be the formals mentioned in @('m2'') where @('m2'') is derived from @('m2') by substituting the formals of @('g') with the actuals of @('c'). For example, consider following function:</p> @({ (defun f (x) (if (endp x) 0 (1+ (f (cdr x))))) }) <p>Now consider the case where @('m1') and @('m2') are both the measure @('(acl2s-size x)'). Then if we look at the recursive call @('(f (cdr x))') in the body of @('f'), then @('m2'') is the result of replacing @('x') with @('(cdr x)') in @('m2'), i.e., @('(acl2s-size (cdr x))').</p> <p>If @('ccm-cs') is @(':EQUAL') we will compare @('m1') to @('m2') if @('v1') and @('v2') are equal. If @('value') is @(':ALL') we will compare @('m1') to @('m2'') if @('v2') is a subset of @('v1'). If @('value') is @(':SOME') we will compare @('m1') to @('m2'') if @('v1') and @('v2') intersect. If @('value') is @(':NONE') we will compare @('m1') to @('m2') no matter what.</p> <p>There is one caveat to what was just said: if @('m1') and @('m2') are syntactically equal, then regardless of the value of @('ccm-cs') we will construct a CCMF that will indicate that @('(o>= m1 m2)').</p> <p>@('Cpn') tells us how much ruler information we will use to compare CCMs. Unlike ACL2's measure-based termination analysis, CCG has the ability to use the rulers from both the current recursive call the next recursive call when constructing the CCMFs. That is, instead of asking ``What happens when I make recursive call A?'', we can ask, ``What happens when execution moves from recursive call A to recursive call B?''. Using this information potentially strengthens the termination analysis. For a brief example, consider the following code:</p> @({ (defun half (x) (if (zp x) 0 (1+ (half (- x 2))))) }) <p>Clearly this is terminating. If we choose a measure of @('(nfix x)') we know that if @('x') is a positive integer, @('(nfix (- x 2))') is less than @('(nfix x)'). But consider the measure @('(acl2s-size x)'). The strange thing here is that if @('x') is 1, then @('(acl2s-size (- x 2))') is @('(acl2s-size -1)'), which is 1, i.e. the @('acl2s-size') of @('x'). So, the fact that we know that @('x') is a positive integer is not enough to show that this measure decreases. But notice that if @('x') is 1, we will recur just one more time. So, if we consider what happens when we move from the recursive call back to itself. In this case we know @('(and (not (zp x)) (not (zp (- x 2))))'). Under these conditions, it is trivial for ACL2 to prove that @('(acl2s-size (- x 2))') is always less than @('(acl2s-size x)'). However, this can make the CCG analysis much more expensive, since information about how values change from step to step are done on a per-edge, rather than a per-node basis in the CCG (where the nodes are the recursive calls and the edges indicate that execution can move from one call to another in one step). Thus, calculating CCMFs (how values change across recursive calls) on a per-edge basis rather than a per-node basis can require n^2 instead of n prover queries.</p> <p>If @('cpn') is @('t'), we will use only the ruler of the current recursive call to compute our CCMFs. If it is @('nil'), we will use the much more expensive technique of using the rulers of the current and next call.</p> <p>Levels of the hierarchy of the form @('(:measure pt)') specify that the CCG analysis is to be set aside for a step, and the traditional measure-based termination proof is to be attempted. Here, @('pt') has the same meaning as it does in a CCG hierarchy level. That is, it limits the measure proof in order to avoid prohibitively long termination analyses.</p> <p>The user may specify their own hierarchy in the form given above. The main restriction is that no level may be subsumed by an earlier level. That is, it should be the case at each level of the hierarchy, that it is possible to discover new information about the CCG that could help lead to a termination proof.</p> <p>In addition to constructing his or her own CCG hierarchy, the user may use several preset hierarchies:</p> @({ :CCG-ONLY ((:built-in-clauses :equal t) ((:induction-depth 0) :EQUAL t) ((:induction-depth 1) :EQUAL t) ((:induction-depth 1) :ALL t) ((:induction-depth 1) :SOME t) ((:induction-depth 1) :NONE t) ((:induction-depth 1) :EQUAL nil) ((:induction-depth 1) :ALL nil) ((:induction-depth 1) :SOME nil) ((:induction-depth 1) :NONE nil)) :CCG-ONLY-CPN ((:built-in-clauses :equal t) ((:induction-depth 0) :EQUAL t) ((:induction-depth 1) :EQUAL t) ((:induction-depth 1) :ALL t) ((:induction-depth 1) :SOME t) ((:induction-depth 1) :NONE t)) :HYBRID ((:built-in-clauses :equal t) (:measure (:induction-depth 1)) ((:induction-depth 0) :EQUAL t) ((:induction-depth 1) :EQUAL t) ((:induction-depth 1) :ALL t) ((:induction-depth 1) :SOME t) ((:induction-depth 1) :NONE t) ((:induction-depth 1) :EQUAL nil) ((:induction-depth 1) :ALL nil) ((:induction-depth 1) :SOME nil) ((:induction-depth 1) :NONE nil)) :HYBRID-CPN ((:built-in-clauses :equal t) (:measure (:induction-depth 1)) ((:induction-depth 0) :EQUAL t) ((:induction-depth 1) :EQUAL t) ((:induction-depth 1) :ALL t) ((:induction-depth 1) :SOME t) ((:induction-depth 1) :NONE t)) }) <p>The default hierarchy for CCG termination analysis is :CCG-ONLY.</p>")
other
(defxdoc set-ccg-inhibit-output-lst :parents (ccg) :short "Control output during CCG termination analysis" :long "@({ Examples: (set-ccg-inhibit-output-lst '(query)) (set-ccg-inhibit-output-lst '(build/refine size-change)) (set-ccg-inhibit-output-lst *ccg-valid-output-names*) ; inhibit all ccg output :set-ccg-inhibit-output-lst (build/refine size-change) General Form: (set-ccg-inhibit-output-lst lst) }) <p>where @('lst') is a form (which may mention @(tsee state)) that evaluates to a list of names, each of which is the name of one of the following ``kinds'' of output produced by the CCG termination analysis.</p> <code> query prints the goal, restrictions, and results of each prover query (for a discussion on displaying actual proofs, see @('set-ccg-display-proofs')(yet to be documented). basics the basic CCG output, enough to follow along, but concise enough to keep from drowning in output performance performance information for the size change analysis build/refine the details of CCG construction and refinement size-change the details of size change analysis counter-example prints out a counter-example that can be useful for debugging failed termination proof attempts. </code> <p>It is possible to inhibit each kind of output by putting the corresponding name into @('lst'). For example, if @(''query') is included in (the value of) @('lst'), then no information about individual queries is printed during CCG analysis.</p> <p>The default setting is @(''(query performance build/refine size-change)'). That is, by default only the basic CCG information and counter-example (in the case of a failed proof attempt) are printed. This should hopefully be adequate for most users.</p>")
other
(defxdoc set-ccg-print-proofs :parents (ccg) :short "Controls whether proof attempts are printed during CCG analysis" :long "@({ Examples: (set-ccg-print-proofs t) (set-ccg-print-proofs nil) :set-ccg-print-proofs t General Form: (set-ccg-print-proofs v) }) <p>If @('v') is @('nil'), no proof attempts will be printed during CCG analysis. This is the default. If @('v') is anything but @('nil'), proofs will be displayed. Fair warning: there is potentially a large amount of prover output that might be displayed. It is probably better to use See @(see set-ccg-inhibit-output-lst) to un-inhibit @(''query') output to figure out what lemmas might be needed to get a given query to go through.</p>")
other
(defxdoc set-ccg-time-limit :parents (ccg) :short "Set a global time limit for CCG-based termination proofs." :long "@({ Examples: (set-ccg-time-limit 120) ; limits termination proofs to 120 seconds. (set-ccg-time-limit 53/2) ; limits termination proofs to 53/2 seconds. (set-ccg-time-limit nil) ; removes any time limit for termination proofs. }) <p>Introduced by the CCG analysis book, this macro sets a global time limit for the completion of the CCG analysis. The time limit is given as a rational number, signifying the number of seconds to which the CCG analysis should be limited, or nil, signifying that there should be no such time limit. If CCG has not completed its attempt to prove termination in the number of seconds specified, it will immediately throw an error and the definition attempt will fail. Note: This is an event! It does not print the usual event summary but nevertheless changes the ACL2 logical @(see world) and is so recorded.</p> @({ General Form: (set-ccg-time-limit tl) }) <p>where @('tl') is a positive rational number or nil. The default is nil. If the time limit is nil, the CCG analysis will work as long as it needs to in order to complete the analysis. If the @('tl') is a positive rational number, all CCG analyses will be limited to @('tl') seconds.</p> <p>To see what the current time limit is, see @(tsee get-ccg-time-limit).</p>")
other
(defxdoc set-termination-method :parents (ccg) :short "Set the default means of proving termination." :long "@({ Examples: (set-termination-method :ccg) (set-termination-method :measure) }) <p>Introduced by the CCG analysis book, this macro sets the default means by which ACL2 will prove termination. Note: This is an event! It does not print the usual event summary but nevertheless changes the ACL2 logical @(see world) and is so recorded.</p> @({ General Form: (set-termination-method tm) }) <p>where @('tm') is @(':CCG') or @(':MEASURE'). The default is @(':MEASURE') (chosen to assure compatibility with books created without CCG). The recommended setting is @(':CCG'). This macro is equivalent to @('(table acl2-defaults-table :termination-method 'tm)'), and hence is @(tsee local) to any @(see books) and @(tsee encapsulate) @(see events) in which it occurs; see @(see acl2-defaults-table).</p> <p>When the termination-method is set to @(':CCG'), a termination proof is attempted using the the hierarchical CCG algorithm <a href='CCG-hierarchy'>CCG-hierarchy</a>.</p> <p>When the termination-method is set to @(':MEASURE'), ACL2 attempts to prove termination using its default measure-based method. Thus, in this setting, ACL2's behavior is identical to that when the CCG book is not included at all.</p> <p>To see what the current termination method setting is, use @(tsee get-termination-method).</p>")