LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/proof - lazy_tree_proof_generator.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 6 6 100.0 %
Date: 2025-01-27 13:33:02 Functions: 2 2 100.0 %
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * Top contributors (to current version):
       3                 :            :  *   Gereon Kremer, Andrew Reynolds, Hans-Joerg Schurr
       4                 :            :  *
       5                 :            :  * This file is part of the cvc5 project.
       6                 :            :  *
       7                 :            :  * Copyright (c) 2009-2025 by the authors listed in the file AUTHORS
       8                 :            :  * in the top-level source directory and their institutional affiliations.
       9                 :            :  * All rights reserved.  See the file COPYING in the top-level source
      10                 :            :  * directory for licensing information.
      11                 :            :  * ****************************************************************************
      12                 :            :  *
      13                 :            :  * The lazy tree proof generator class.
      14                 :            :  */
      15                 :            : 
      16                 :            : #include "cvc5_private.h"
      17                 :            : 
      18                 :            : #ifndef CVC5__PROOF__LAZY_TREE_PROOF_GENERATOR_H
      19                 :            : #define CVC5__PROOF__LAZY_TREE_PROOF_GENERATOR_H
      20                 :            : 
      21                 :            : #include <iostream>
      22                 :            : 
      23                 :            : #include "expr/node.h"
      24                 :            : #include "proof/proof_generator.h"
      25                 :            : #include "proof/proof_node_manager.h"
      26                 :            : #include "smt/env_obj.h"
      27                 :            : 
      28                 :            : namespace cvc5::internal {
      29                 :            : namespace detail {
      30                 :            : /**
      31                 :            :  * A single node in the proof tree created by the LazyTreeProofGenerator.
      32                 :            :  * A node directly represents a ProofNode that is eventually constructed from
      33                 :            :  * it. The Nodes of the additional field d_premise are added to d_children as
      34                 :            :  * new assumptions via ASSUME.
      35                 :            :  * The object id can be used to store an arbitrary id to identify tree nodes
      36                 :            :  * and map them back to some other type, for example during pruning.
      37                 :            :  */
      38                 :            : struct TreeProofNode
      39                 :            : {
      40                 :            :   /** Storage for some custom object identifier, used for pruning */
      41                 :            :   size_t d_objectId;
      42                 :            :   /** The proof rule */
      43                 :            :   ProofRule d_rule = ProofRule::UNKNOWN;
      44                 :            :   /** Assumptions used as premise for this proof step */
      45                 :            :   std::vector<Node> d_premise;
      46                 :            :   /** Arguments for this proof step */
      47                 :            :   std::vector<Node> d_args;
      48                 :            :   /** Conclusion of this proof step */
      49                 :            :   Node d_proven;
      50                 :            :   /** Children of this proof step */
      51                 :            :   std::vector<TreeProofNode> d_children;
      52                 :            : };
      53                 :            : }  // namespace detail
      54                 :            : 
      55                 :            : /**
      56                 :            :  * This class supports the lazy creation of a tree-shaped proof.
      57                 :            :  * The core idea is that the lazy creation is necessary because proof rules
      58                 :            :  * depend on assumptions that are only known after the whole subtree has been
      59                 :            :  * finished.
      60                 :            :  *
      61                 :            :  * We indend to argue about proofs that roughly go as follows:
      62                 :            :  * - we assume a set of assumptions
      63                 :            :  * - we do a case split
      64                 :            :  * - for every case, we derive false, possibly by nested case splits
      65                 :            :  *
      66                 :            :  * Every case is represented by a SCOPE whose child derives false. When
      67                 :            :  * composing the final proof, we explicitly extend the premise of every proof
      68                 :            :  * step with the scope (the currently selected case) that this proof step lives
      69                 :            :  * in. When doing this, we ignore the outermost scope (which assumes the
      70                 :            :  * assertion set) to allow for having conflicts that are only a subset of the
      71                 :            :  * assertion set.
      72                 :            :  *
      73                 :            :  * Consider the example  x*x<1 and x>2  and the intended proof
      74                 :            :  *  (SCOPE
      75                 :            :  *    (ARITH_NL_COVERING_RECURSIVE
      76                 :            :  *      (SCOPE
      77                 :            :  *        (ARITH_NL_COVERING_DIRECT  (x<=2  and  x>2) ==> false)
      78                 :            :  *        :args [x<=2]
      79                 :            :  *      )
      80                 :            :  *      (SCOPE
      81                 :            :  *        (ARITH_NL_COVERING_DIRECT  (x>=1  and  x*x<1) ==> false)
      82                 :            :  *        :args [x>=1]
      83                 :            :  *      )
      84                 :            :  *    )
      85                 :            :  *    :args [ x*x<1, x>2 ]
      86                 :            :  *  )
      87                 :            :  * We obtain this proof in a way that (in general) gives us the assumptions
      88                 :            :  * for the scopes (x<=2, x>=1) only when the scope children have been fully
      89                 :            :  * computed. Thus, we store the proof in an intermediate form and add the scope
      90                 :            :  * arguments when we learn them. Once we have completed the proof, we can easily
      91                 :            :  * transform it into proper ProofNodes.
      92                 :            :  *
      93                 :            :  * This class is stateful in the sense that the interface (in particular
      94                 :            :  * openChild() and closeChild()) navigates the proof tree (and creating it
      95                 :            :  * on-the-fly). Initially, and after reset() has been called, the proof consists
      96                 :            :  * of one empty proof node (with proof rule UNKNOWN). It stores the current
      97                 :            :  * position in the proof tree internally to make the interface easier to use.
      98                 :            :  *
      99                 :            :  * THIS MAKES THIS CLASS INHERENTLY NOT THREAD-SAFE!
     100                 :            :  *
     101                 :            :  * To construct the above proof, use this class roughly as follows:
     102                 :            :  *  setCurrent(SCOPE, {}, assertions, false);
     103                 :            :  *  openChild();
     104                 :            :  *  // First nested scope
     105                 :            :  *  openChild();
     106                 :            :  *  setCurrent(SCOPE, {}, {}, false);
     107                 :            :  *  openChild();
     108                 :            :  *  setCurrent(ARITH_NL_COVERING_DIRECT, {x>2}, {}, false);
     109                 :            :  *  closeChild();
     110                 :            :  *  getCurrent().args = {x<=2};
     111                 :            :  *  closeChild();
     112                 :            :  *  // Second nested scope
     113                 :            :  *  openChild();
     114                 :            :  *  setCurrent(SCOPE, {}, {}, false);
     115                 :            :  *  openChild();
     116                 :            :  *  setCurrent(ARITH_NL_COVERING_DIRECT, {x*x<1}, {}, false);
     117                 :            :  *  closeChild();
     118                 :            :  *  getCurrent().args = {x>=1};
     119                 :            :  *  closeChild();
     120                 :            :  *  // Finish split
     121                 :            :  *  setCurrent(ARITH_NL_COVERING_RECURSIVE, {}, {}, false);
     122                 :            :  *  closeChild();
     123                 :            :  *  closeChild();
     124                 :            :  *
     125                 :            :  * To explicitly finish proof construction, we need to call closeChild() one
     126                 :            :  * additional time.
     127                 :            :  */
     128                 :            : class LazyTreeProofGenerator : protected EnvObj, public ProofGenerator
     129                 :            : {
     130                 :            :  public:
     131                 :            :   friend std::ostream& operator<<(std::ostream& os,
     132                 :            :                                   const LazyTreeProofGenerator& ltpg);
     133                 :            : 
     134                 :            :   LazyTreeProofGenerator(Env& env,
     135                 :            :                          const std::string& name = "LazyTreeProofGenerator");
     136                 :            : 
     137                 :          6 :   std::string identify() const override { return d_name; }
     138                 :            :   /** Create a new child and make it the current node */
     139                 :            :   void openChild();
     140                 :            :   /**
     141                 :            :    * Finish the current node and return to its parent
     142                 :            :    * Checks that the current node has a proof rule different from UNKNOWN.
     143                 :            :    * When called on the root node, this finishes the proof construction: we can
     144                 :            :    * no longer call getCurrent(), setCurrent() openChild() and closeChild(), but
     145                 :            :    * instead can call getProof() now.
     146                 :            :    */
     147                 :            :   void closeChild();
     148                 :            :   /**
     149                 :            :    * Return a reference to the current node
     150                 :            :    */
     151                 :            :   detail::TreeProofNode& getCurrent();
     152                 :            :   /** Set the current node / proof step */
     153                 :            :   void setCurrent(size_t objectId,
     154                 :            :                   ProofRule rule,
     155                 :            :                   const std::vector<Node>& premise,
     156                 :            :                   std::vector<Node> args,
     157                 :            :                   Node proven);
     158                 :            :   /**
     159                 :            :    * Same as above, but with a trusted proof step.
     160                 :            :    */
     161                 :            :   void setCurrentTrust(size_t objectId,
     162                 :            :                        TrustId tid,
     163                 :            :                        const std::vector<Node>& premise,
     164                 :            :                        std::vector<Node> args,
     165                 :            :                        Node proven);
     166                 :            :   /** Construct the proof as a ProofNode */
     167                 :            :   std::shared_ptr<ProofNode> getProof() const;
     168                 :            :   /** Return the constructed proof. Checks that we have proven f */
     169                 :            :   std::shared_ptr<ProofNode> getProofFor(Node f) override;
     170                 :            :   /** Checks whether we have proven f */
     171                 :            :   bool hasProofFor(Node f) override;
     172                 :            : 
     173                 :            :   /**
     174                 :            :    * Removes children from the current node based on the given predicate.
     175                 :            :    * It can be used for cases where facts (and their proofs) are eagerly
     176                 :            :    * generated and then later pruned, for example to produce smaller conflicts.
     177                 :            :    * The predicate is given as a Callable f that is called for every child with
     178                 :            :    * the id of the child and the child itself.
     179                 :            :    * f should return false if the child should be kept, true if the child should
     180                 :            :    * be removed.
     181                 :            :    * @param f a Callable bool(std::size_t, const detail::TreeProofNode&)
     182                 :            :    */
     183                 :            :   template <typename F>
     184                 :       2848 :   void pruneChildren(F&& f)
     185                 :            :   {
     186                 :       2848 :     auto& children = getCurrent().d_children;
     187                 :            : 
     188                 :            :     auto it =
     189                 :       2848 :         std::remove_if(children.begin(), children.end(), std::forward<F>(f));
     190                 :       2848 :     children.erase(it, children.end());
     191                 :       2848 :   }
     192                 :            : 
     193                 :            :  private:
     194                 :            :   /** recursive proof construction used by getProof() */
     195                 :            :   std::shared_ptr<ProofNode> getProof(
     196                 :            :       std::vector<std::shared_ptr<ProofNode>>& scope,
     197                 :            :       const detail::TreeProofNode& pn) const;
     198                 :            : 
     199                 :            :   /** recursive debug printing used by operator<<() */
     200                 :            :   void print(std::ostream& os,
     201                 :            :              const std::string& prefix,
     202                 :            :              const detail::TreeProofNode& pn) const;
     203                 :            : 
     204                 :            :   /** The trace to the current node */
     205                 :            :   std::vector<detail::TreeProofNode*> d_stack;
     206                 :            :   /** The root node of the proof tree */
     207                 :            :   detail::TreeProofNode d_proof;
     208                 :            :   /** Caches the result of getProof() */
     209                 :            :   mutable std::shared_ptr<ProofNode> d_cached;
     210                 :            :   /** Name of this proof generator */
     211                 :            :   std::string d_name;
     212                 :            : };
     213                 :            : 
     214                 :            : /**
     215                 :            :  * Prints the current state of a LazyTreeProofGenerator. Can also be used on a
     216                 :            :  * partially constructed proof. It is intended for debugging only and attempts
     217                 :            :  * to pretty-print itself using indentation.
     218                 :            :  */
     219                 :            : std::ostream& operator<<(std::ostream& os, const LazyTreeProofGenerator& ltpg);
     220                 :            : 
     221                 :            : }  // namespace cvc5::internal
     222                 :            : 
     223                 :            : #endif

Generated by: LCOV version 1.14