• Top
    • Documentation
    • Books
    • Boolean-reasoning
    • Projects
    • Debugging
    • Community
    • Std
    • Proof-automation
    • Macro-libraries
    • ACL2
      • Theories
      • Rule-classes
      • Proof-builder
      • Recursion-and-induction
      • Hons-and-memoization
      • Events
      • Parallelism
      • History
      • Programming
        • Defun
        • Declare
        • System-utilities
        • Stobj
        • State
        • Mutual-recursion
        • Memoize
        • Mbe
        • Io
        • Defpkg
        • Apply$
        • Loop$
          • Loop$-primer
          • Do-loop$
          • For-loop$
          • Loop$-recursion
          • Stating-and-proving-lemmas-about-loop$s
          • Loop$-recursion-induction
            • Do$
          • Programming-with-state
          • Arrays
          • Characters
          • Time$
          • Defconst
          • Fast-alists
          • Defmacro
          • Loop$-primer
          • Evaluation
          • Guard
          • Equality-variants
          • Compilation
          • Hons
          • ACL2-built-ins
          • Developers-guide
          • System-attachments
          • Advanced-features
          • Set-check-invariant-risk
          • Numbers
          • Efficiency
          • Irrelevant-formals
          • Introduction-to-programming-in-ACL2-for-those-who-know-lisp
          • Redefining-programs
          • Lists
          • Invariant-risk
          • Errors
          • Defabbrev
          • Conses
          • Alists
          • Set-register-invariant-risk
          • Strings
          • Program-wrapper
          • Get-internal-time
          • Basics
          • Packages
          • Oracle-eval
          • Defmacro-untouchable
          • <<
          • Primitive
          • Revert-world
          • Unmemoize
          • Set-duplicate-keys-action
          • Symbols
          • Def-list-constructor
          • Easy-simplify-term
          • Defiteration
          • Fake-oracle-eval
          • Defopen
          • Sleep
        • Operational-semantics
        • Real
        • Start-here
        • Miscellaneous
        • Output-controls
        • Bdd
        • Macros
        • Installation
        • Mailing-lists
      • Interfacing-tools
      • Hardware-verification
      • Software-verification
      • Math
      • Testing-utilities
    • Loop$

    Loop$-recursion-induction

    Advice on inductive theorems about loop$-recursive functions

    Warning: This documentation topic is fairly preliminary because we do not have a lot of experience yet with apply$, loop$, and loop$-recursion. We assume here that readers are familiar with the topics cited above.

    Definductor

    The principles sketched here are illustrated concretely in the tutorial community book projects/apply/copy-nat-tree.lisp. As noted in that book, the inductions are hinted manually so the reader can see from first principles what is involved. However, in the book projects/apply/top we provide a utility that sometimes automates the creation of the inductive hint function and associates it with the given loop$-recursive function. See definductor. The examples worked manually in copy-nat-tree.lisp are recapitulated towards the end of projects/apply/definductor-tests.lisp, without the manually provided hints. In addition, the book projects/apply/loop-recursion-examples.lisp gives some other examples of loop$-recursive functions and inductive theorems about them.

    Some Basic Principles for Inductive Proofs about Loop$-Recursive Functions

    If ACL2 did not have loop$, functions defined in terms of loop$-recursion would have to be defined with mutual-recursion. Reconsider the example presented in loop$-recursion.

    (defun$ nat-treep (x)
      (declare (xargs :loop$-recursion t
                      :measure (acl2-count x)))
      (cond
       ((atom x) (natp x))
       (t (and (true-listp x)
               (eq (car x) 'NATS)
               (loop$ for e in (cdr x) always (nat-treep e))))))
    
    (defun$ copy-nat-tree (x)
      (declare (xargs :loop$-recursion t
                      :measure (acl2-count x)))
      (cond
       ((atom x)
        (if (natp x)
            (if (equal x 0)
                0
                (+ 1 (copy-nat-tree (- x 1))))
            x))
       (t (cons 'nats
                (loop$ for e in (cdr x) collect (copy-nat-tree e))))))

    Without loop$ the latter function would have to be defined this way. We name it mr-copy-nat-tree, where the ``mr'' reminds us this is part of a mutually recursive clique.

    (mutual-recursion
     (defun mr-copy-nat-tree (x)
       (cond
        ((atom x)
         (if (natp x)
             (if (equal x 0)
                 0
                 (+ 1 (mr-copy-nat-tree (- x 1))))
             x))
        (t (cons 'nats
                 (mr-copy-nat-tree-list (cdr x))))))
    
     (defun mr-copy-nat-tree-list (x)
       (cond
        ((endp x) nil)
        (t (cons (mr-copy-nat-tree (car x))
                 (mr-copy-nat-tree-list (cdr x)))))))

    Note that we define mr-copy-nat-tree by copying the definition of copy-nat-tree (renaming recursive calls appropriately) but replacing the use of loop$ in copy-nat-tree with a call of a mutually-recursive function here called mr-copy-nat-tree-list. We call mr-copy-nat-tree-list the ``list counterpart'' of mr-copy-nat-tree. However, in general there may be more than just two functions in the clique and so we refer generically to mr-copy-nat-tree-list as a ``co-member'' of the clique.

    How would you prove theorems about mr-copy-nat-tree? Four principles are known to most ACL2 users of mutual-recursion. These principles apply to loop$-recursive functions as well as to mutually recursive ones. We state them here in terms of both kinds of definitions.

    • While simple recursive functions suggest ``appropriate'' inductions, mutually recursive functions and loop$-recursive functions do not. If you want to prove a theorem about such functions you have to arrange some kind of induction hint.
    • You can't generally prove an isolated theorem about a single member of a mutually recursive clique or a loop$-recursive function. Instead, you must state a conjecture about every member of the clique, conjoin all those theorems together, and prove them inductively all at once. Applied to proving a theorem about mr-copy-nat-tree this advice means we must conjoin the theorem about that function with ``the same'' theorem about mr-copy-nat-tree-list, and more generally with theorems about every co-member of the clique. Of course, what we mean by ``the same'' theorem about different members of the clique depends on what each member contributes to the overall computation. Applied to the loop$-recursive function copy-nat-tree this advice means we must simultaneously prove a theorem about every loop$ in the function.
    • Inductively provable theorems must be sufficiently general. When dealing with a mutually recursive clique, each conjunct must address itself to the ``general'' call of the co-member in question, e.g., to (mr-copy-nat-tree-list x) not to the specific call inside mr-copy-nat-tree, which is (mr-copy-nat-tree-list (cdr x)). When dealing with a loop$-recursive function, each conjunct must address itself to the general target, not to specific target in the loop$ recursive function. In the case of the loop$-recursive function copy-nat-tree we need a conjunct about (loop$ for e in x collect (copy-nat-tree e)), not about (loop$ for e in (cdr x) collect (copy-nat-tree e)).
    • Finally, the induction scheme used must provide an inductive hypothesis about every recursive call of every co-member of the clique or, in the case of loop$-recursion, about every recursive unwinding of each loop$.

    Remember: Because loop$-recursive functions call themselves recursively with apply$, any theorem about a loop$ recursive function must almost certainly include a warrant hypothesis for that function!

    We illustrate these principles in the community book projects/apply/copy-nat-list.lisp.