LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/preprocessing/passes - distinct_elim.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 59 64 92.2 %
Date: 2026-09-12 10:08:15 Functions: 3 3 100.0 %
Branches: 43 69 62.3 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * This file is part of the cvc5 project.
       3                 :            :  *
       4                 :            :  * Copyright (c) 2009-2026 by the authors listed in the file AUTHORS
       5                 :            :  * in the top-level source directory and their institutional affiliations.
       6                 :            :  * All rights reserved.  See the file COPYING in the top-level source
       7                 :            :  * directory for licensing information.
       8                 :            :  * ****************************************************************************
       9                 :            :  *
      10                 :            :  * The distinct_elim preprocessing pass.
      11                 :            :  *
      12                 :            :  * Eagerly eliminates (blasts) distinct terms into pairwise disequalities,
      13                 :            :  * based on a configurable threshold on the number of children.
      14                 :            :  */
      15                 :            : 
      16                 :            : #include "preprocessing/passes/distinct_elim.h"
      17                 :            : 
      18                 :            : #include "options/smt_options.h"
      19                 :            : #include "preprocessing/assertion_pipeline.h"
      20                 :            : #include "theory/uf/theory_uf_rewriter.h"
      21                 :            : 
      22                 :            : namespace cvc5::internal {
      23                 :            : namespace preprocessing {
      24                 :            : namespace passes {
      25                 :            : 
      26                 :      28895 : DistinctElim::DistinctElim(PreprocessingPassContext* preprocContext)
      27                 :            :     : PreprocessingPass(preprocContext, "distinct-elim"),
      28                 :      28895 :       d_threshold(options().smt.distinctElimThreshold)
      29                 :            : {
      30         [ +  + ]:      28895 :   if (options().smt.produceProofs)
      31                 :            :   {
      32                 :      30750 :     d_tpg.reset(new TConvProofGenerator(d_env,
      33                 :      15375 :                                         userContext(),
      34                 :            :                                         TConvPolicy::FIXPOINT,
      35                 :            :                                         TConvCachePolicy::NEVER,
      36                 :      15375 :                                         "DistinctElim::tpg"));
      37                 :            :   }
      38                 :      28895 : }
      39                 :            : 
      40                 :         12 : PreprocessingPassResult DistinctElim::applyInternal(
      41                 :            :     AssertionPipeline* assertionsToPreprocess)
      42                 :            : {
      43         [ +  + ]:         48 :   for (size_t i = 0, nasserts = assertionsToPreprocess->size(); i < nasserts;
      44                 :            :        ++i)
      45                 :            :   {
      46                 :         36 :     TrustNode trn = eliminate((*assertionsToPreprocess)[i]);
      47         [ +  + ]:         36 :     if (trn.isNull())
      48                 :            :     {
      49                 :         22 :       continue;
      50                 :            :     }
      51                 :         14 :     assertionsToPreprocess->replaceTrusted(i, trn);
      52         [ -  + ]:         14 :     if (assertionsToPreprocess->isInConflict())
      53                 :            :     {
      54                 :          0 :       return PreprocessingPassResult::CONFLICT;
      55                 :            :     }
      56    [ +  + ][ - ]:         36 :   }
      57                 :         12 :   return PreprocessingPassResult::NO_CONFLICT;
      58                 :            : }
      59                 :            : 
      60                 :         36 : TrustNode DistinctElim::eliminate(TNode n)
      61                 :            : {
      62                 :         36 :   NodeManager* nm = nodeManager();
      63                 :         36 :   std::unordered_map<TNode, Node> visited;
      64                 :         36 :   std::unordered_map<TNode, Node>::iterator it;
      65                 :            :   // to ensure all intermediate nodes are ref counted
      66                 :         36 :   std::unordered_set<Node> keep;
      67                 :         36 :   std::vector<TNode> visit;
      68                 :         36 :   visit.push_back(n);
      69                 :            :   do
      70                 :            :   {
      71                 :        560 :     TNode cur = visit.back();
      72                 :        560 :     it = visited.find(cur);
      73         [ +  + ]:        560 :     if (it == visited.end())
      74                 :            :     {
      75                 :        280 :       visited[cur] = Node::null();
      76                 :        280 :       visit.insert(visit.end(), cur.begin(), cur.end());
      77                 :            :     }
      78         [ +  - ]:        280 :     else if (it->second.isNull())
      79                 :            :     {
      80                 :            :       // reconstruct with processed children
      81                 :        280 :       Node ret = cur;
      82                 :        280 :       bool childChanged = false;
      83                 :        280 :       std::vector<Node> children;
      84         [ -  + ]:        280 :       if (cur.getMetaKind() == kind::metakind::PARAMETERIZED)
      85                 :            :       {
      86                 :          0 :         children.push_back(cur.getOperator());
      87                 :            :       }
      88         [ +  + ]:        524 :       for (const Node& cn : cur)
      89                 :            :       {
      90 [ -  + ][ -  + ]:        244 :         Assert(visited.find(cn) != visited.end());
                 [ -  - ]
      91 [ -  + ][ -  + ]:        244 :         Assert(!visited[cn].isNull());
                 [ -  - ]
      92 [ +  - ][ -  + ]:        244 :         childChanged = childChanged || cn != visited[cn];
         [ +  - ][ -  - ]
      93                 :        244 :         children.push_back(visited[cn]);
      94                 :        244 :       }
      95         [ -  + ]:        280 :       if (childChanged)
      96                 :            :       {
      97                 :          0 :         ret = nm->mkNode(cur.getKind(), children);
      98                 :          0 :         keep.insert(ret);
      99                 :            :       }
     100                 :            :       // blast distinct if it is within the threshold (0 means no limit)
     101                 :        280 :       if (ret.getKind() == Kind::DISTINCT
     102 [ +  + ][ +  + ]:        280 :           && (d_threshold == 0 || ret.getNumChildren() <= d_threshold))
         [ +  + ][ +  + ]
     103                 :            :       {
     104                 :         14 :         Node blasted = theory::uf::TheoryUfRewriter::blastDistinct(nm, ret);
     105                 :         14 :         keep.insert(blasted);
     106         [ +  + ]:         14 :         if (d_tpg != nullptr)
     107                 :            :         {
     108                 :            :           // justify (= ret blasted) via the DISTINCT_ELIM proof rewrite rule
     109                 :          8 :           d_tpg->addTheoryRewriteStep(
     110                 :            :               ret, blasted, ProofRewriteRule::DISTINCT_ELIM);
     111                 :            :         }
     112                 :         14 :         ret = blasted;
     113                 :         14 :       }
     114                 :        280 :       visited[cur] = ret;
     115                 :        280 :       visit.pop_back();
     116                 :        280 :     }
     117                 :            :     else
     118                 :            :     {
     119                 :          0 :       visit.pop_back();
     120                 :            :     }
     121         [ +  + ]:        560 :   } while (!visit.empty());
     122 [ -  + ][ -  + ]:         36 :   Assert(visited.find(n) != visited.end());
                 [ -  - ]
     123 [ -  + ][ -  + ]:         36 :   Assert(!visited.find(n)->second.isNull());
                 [ -  - ]
     124                 :         36 :   Node ret = visited[n];
     125         [ +  + ]:         36 :   if (ret == n)
     126                 :            :   {
     127                 :         22 :     return TrustNode::null();
     128                 :            :   }
     129                 :            :   // use the term conversion proof generator if it exists
     130         [ +  + ]:         14 :   return TrustNode::mkTrustRewrite(n, ret, d_tpg.get());
     131                 :         36 : }
     132                 :            : 
     133                 :            : }  // namespace passes
     134                 :            : }  // namespace preprocessing
     135                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14