LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/preprocessing/passes - ite_simp.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 50 132 37.9 %
Date: 2026-04-30 10:45:04 Functions: 5 6 83.3 %
Branches: 21 84 25.0 %

           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                 :            :  * ITE simplification preprocessing pass.
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "preprocessing/passes/ite_simp.h"
      14                 :            : 
      15                 :            : #include <vector>
      16                 :            : 
      17                 :            : #include "options/base_options.h"
      18                 :            : #include "options/smt_options.h"
      19                 :            : #include "preprocessing/assertion_pipeline.h"
      20                 :            : #include "preprocessing/preprocessing_pass_context.h"
      21                 :            : #include "theory/arith/arith_ite_utils.h"
      22                 :            : #include "theory/theory_engine.h"
      23                 :            : 
      24                 :            : using namespace std;
      25                 :            : using namespace cvc5::internal;
      26                 :            : using namespace cvc5::internal::theory;
      27                 :            : 
      28                 :            : namespace cvc5::internal {
      29                 :            : namespace preprocessing {
      30                 :            : namespace passes {
      31                 :            : 
      32                 :          0 : Node mkAssocAnd(NodeManager* nm, const std::vector<Node>& children)
      33                 :            : {
      34         [ -  - ]:          0 :   if (children.size() == 0)
      35                 :            :   {
      36                 :          0 :     return nm->mkConst(true);
      37                 :            :   }
      38         [ -  - ]:          0 :   else if (children.size() == 1)
      39                 :            :   {
      40                 :          0 :     return children[0];
      41                 :            :   }
      42                 :            :   else
      43                 :            :   {
      44                 :          0 :     const uint32_t max = kind::metakind::getMaxArityForKind(Kind::AND);
      45                 :          0 :     const uint32_t min = kind::metakind::getMinArityForKind(Kind::AND);
      46                 :            : 
      47                 :          0 :     Assert(min <= children.size());
      48                 :            : 
      49                 :          0 :     unsigned int numChildren = children.size();
      50         [ -  - ]:          0 :     if (numChildren <= max)
      51                 :            :     {
      52                 :          0 :       return nm->mkNode(Kind::AND, children);
      53                 :            :     }
      54                 :            : 
      55                 :            :     typedef std::vector<Node>::const_iterator const_iterator;
      56                 :          0 :     const_iterator it = children.begin();
      57                 :          0 :     const_iterator end = children.end();
      58                 :            : 
      59                 :            :     /* The new top-level children and the children of each sub node */
      60                 :          0 :     std::vector<Node> newChildren;
      61                 :          0 :     std::vector<Node> subChildren;
      62                 :            : 
      63 [ -  - ][ -  - ]:          0 :     while (it != end && numChildren > max)
                 [ -  - ]
      64                 :            :     {
      65                 :            :       /* Grab the next max children and make a node for them. */
      66         [ -  - ]:          0 :       for (const_iterator next = it + max; it != next; ++it, --numChildren)
      67                 :            :       {
      68                 :          0 :         subChildren.push_back(*it);
      69                 :            :       }
      70                 :          0 :       Node subNode = nm->mkNode(Kind::AND, subChildren);
      71                 :          0 :       newChildren.push_back(subNode);
      72                 :          0 :       subChildren.clear();
      73                 :          0 :     }
      74                 :            : 
      75                 :            :     /* If there's children left, "top off" the Expr. */
      76         [ -  - ]:          0 :     if (numChildren > 0)
      77                 :            :     {
      78                 :            :       /* If the leftovers are too few, just copy them into newChildren;
      79                 :            :        * otherwise make a new sub-node  */
      80         [ -  - ]:          0 :       if (numChildren < min)
      81                 :            :       {
      82         [ -  - ]:          0 :         for (; it != end; ++it)
      83                 :            :         {
      84                 :          0 :           newChildren.push_back(*it);
      85                 :            :         }
      86                 :            :       }
      87                 :            :       else
      88                 :            :       {
      89         [ -  - ]:          0 :         for (; it != end; ++it)
      90                 :            :         {
      91                 :          0 :           subChildren.push_back(*it);
      92                 :            :         }
      93                 :          0 :         Node subNode = nm->mkNode(Kind::AND, subChildren);
      94                 :          0 :         newChildren.push_back(subNode);
      95                 :          0 :       }
      96                 :            :     }
      97                 :            : 
      98                 :            :     /* It's inconceivable we could have enough children for this to fail
      99                 :            :      * (more than 2^32, in most cases?). */
     100                 :          0 :     AlwaysAssert(newChildren.size() <= max)
     101                 :          0 :         << "Too many new children in mkAssociative";
     102                 :            : 
     103                 :            :     /* It would be really weird if this happened (it would require
     104                 :            :      * min > 2, for one thing), but let's make sure. */
     105                 :          0 :     AlwaysAssert(newChildren.size() >= min)
     106                 :          0 :         << "Too few new children in mkAssociative";
     107                 :            : 
     108                 :          0 :     return nm->mkNode(Kind::AND, newChildren);
     109                 :          0 :   }
     110                 :            : }
     111                 :            : 
     112                 :            : /* -------------------------------------------------------------------------- */
     113                 :            : 
     114                 :      51756 : ITESimp::Statistics::Statistics(StatisticsRegistry& reg)
     115                 :      51756 :     : d_arithSubstitutionsAdded(reg.registerInt(
     116                 :            :           "preprocessing::passes::ITESimp::ArithSubstitutionsAdded"))
     117                 :            : {
     118                 :      51756 : }
     119                 :            : 
     120                 :         12 : Node ITESimp::simpITE(util::ITEUtilities* ite_utils, TNode assertion)
     121                 :            : {
     122         [ +  + ]:         12 :   if (!ite_utils->containsTermITE(assertion))
     123                 :            :   {
     124                 :         11 :     return assertion;
     125                 :            :   }
     126                 :            :   else
     127                 :            :   {
     128                 :          1 :     Node result = ite_utils->simpITE(assertion);
     129                 :          1 :     Node res_rewritten = rewrite(result);
     130                 :            : 
     131         [ -  + ]:          1 :     if (options().smt.simplifyWithCareEnabled)
     132                 :            :     {
     133                 :          0 :       verbose(2) << "starting simplifyWithCare()" << endl;
     134                 :          0 :       Node postSimpWithCare = ite_utils->simplifyWithCare(res_rewritten);
     135                 :          0 :       verbose(2) << "ending simplifyWithCare()"
     136                 :          0 :                  << " post simplifyWithCare()" << postSimpWithCare.getId()
     137                 :          0 :                  << endl;
     138                 :          0 :       result = rewrite(postSimpWithCare);
     139                 :          0 :     }
     140                 :            :     else
     141                 :            :     {
     142                 :          1 :       result = res_rewritten;
     143                 :            :     }
     144                 :          1 :     return result;
     145                 :          1 :   }
     146                 :            : }
     147                 :            : 
     148                 :          5 : bool ITESimp::doneSimpITE(AssertionPipeline* assertionsToPreprocess)
     149                 :            : {
     150                 :          5 :   bool result = true;
     151                 :          5 :   bool simpDidALotOfWork = d_iteUtilities.simpIteDidALotOfWorkHeuristic();
     152         [ +  + ]:          5 :   if (simpDidALotOfWork)
     153                 :            :   {
     154         [ +  - ]:          1 :     if (options().smt.compressItes)
     155                 :            :     {
     156                 :          1 :       result = d_iteUtilities.compress(assertionsToPreprocess);
     157                 :            :     }
     158                 :            :   }
     159                 :            : 
     160                 :            :   // Do theory specific preprocessing passes
     161                 :          5 :   if (logicInfo().isTheoryEnabled(theory::THEORY_ARITH)
     162 [ +  - ][ +  - ]:          5 :       && !options().base.incrementalSolving)
                 [ +  - ]
     163                 :            :   {
     164         [ +  + ]:          5 :     if (!simpDidALotOfWork)
     165                 :            :     {
     166                 :            :       util::ContainsTermITEVisitor& contains =
     167                 :          4 :           *(d_iteUtilities.getContainsVisitor());
     168                 :            :       arith::ArithIteUtils aiteu(
     169                 :          4 :           d_env, contains, d_preprocContext->getTopLevelSubstitutions().get());
     170                 :          4 :       bool anyItes = false;
     171         [ +  + ]:         12 :       for (size_t i = 0, size = assertionsToPreprocess->size(); i < size; ++i)
     172                 :            :       {
     173                 :          8 :         Node curr = (*assertionsToPreprocess)[i];
     174         [ -  + ]:          8 :         if (contains.containsTermITE(curr))
     175                 :            :         {
     176                 :          0 :           anyItes = true;
     177                 :          0 :           Node res = aiteu.reduceVariablesInItes(curr);
     178         [ -  - ]:          0 :           Trace("arith::ite::red") << "@ " << i << " ... " << curr << endl
     179                 :          0 :                                    << "   ->" << res << endl;
     180         [ -  - ]:          0 :           if (curr != res)
     181                 :            :           {
     182                 :          0 :             Node more = aiteu.reduceConstantIteByGCD(res);
     183         [ -  - ]:          0 :             Trace("arith::ite::red") << "  gcd->" << more << endl;
     184                 :          0 :             Node morer = rewrite(more);
     185                 :          0 :             assertionsToPreprocess->replace(
     186                 :            :                 i, morer, nullptr, TrustId::PREPROCESS_ITE_SIMP);
     187                 :          0 :           }
     188                 :          0 :         }
     189                 :          8 :       }
     190         [ +  - ]:          4 :       if (!anyItes)
     191                 :            :       {
     192                 :          4 :         unsigned prevSubCount = aiteu.getSubCount();
     193                 :          4 :         aiteu.learnSubstitutions(assertionsToPreprocess->ref());
     194         [ -  + ]:          4 :         if (prevSubCount < aiteu.getSubCount())
     195                 :            :         {
     196                 :            :           d_statistics.d_arithSubstitutionsAdded +=
     197                 :          0 :               aiteu.getSubCount() - prevSubCount;
     198                 :          0 :           bool anySuccess = false;
     199         [ -  - ]:          0 :           for (size_t i = 0, N = assertionsToPreprocess->size(); i < N; ++i)
     200                 :            :           {
     201                 :          0 :             Node curr = (*assertionsToPreprocess)[i];
     202                 :          0 :             Node next = rewrite(aiteu.applySubstitutions(curr));
     203                 :          0 :             Node res = aiteu.reduceVariablesInItes(next);
     204         [ -  - ]:          0 :             Trace("arith::ite::red") << "@ " << i << " ... " << next << endl
     205                 :          0 :                                      << "   ->" << res << endl;
     206                 :          0 :             Node more = aiteu.reduceConstantIteByGCD(res);
     207         [ -  - ]:          0 :             Trace("arith::ite::red") << "  gcd->" << more << endl;
     208         [ -  - ]:          0 :             if (more != next)
     209                 :            :             {
     210                 :          0 :               anySuccess = true;
     211                 :          0 :               break;
     212                 :            :             }
     213 [ -  - ][ -  - ]:          0 :           }
         [ -  - ][ -  - ]
     214                 :          0 :           for (size_t i = 0, N = assertionsToPreprocess->size();
     215 [ -  - ][ -  - ]:          0 :                anySuccess && i < N;
     216                 :            :                ++i)
     217                 :            :           {
     218                 :          0 :             Node curr = (*assertionsToPreprocess)[i];
     219                 :          0 :             Node next = rewrite(aiteu.applySubstitutions(curr));
     220                 :          0 :             Node res = aiteu.reduceVariablesInItes(next);
     221         [ -  - ]:          0 :             Trace("arith::ite::red") << "@ " << i << " ... " << next << endl
     222                 :          0 :                                      << "   ->" << res << endl;
     223                 :          0 :             Node more = aiteu.reduceConstantIteByGCD(res);
     224         [ -  - ]:          0 :             Trace("arith::ite::red") << "  gcd->" << more << endl;
     225                 :          0 :             Node morer = rewrite(more);
     226                 :          0 :             assertionsToPreprocess->replace(
     227                 :            :                 i, morer, nullptr, TrustId::PREPROCESS_ITE_SIMP);
     228                 :          0 :           }
     229                 :            :         }
     230                 :            :       }
     231                 :          4 :     }
     232                 :            :   }
     233                 :          5 :   return result;
     234                 :            : }
     235                 :            : 
     236                 :            : /* -------------------------------------------------------------------------- */
     237                 :            : 
     238                 :      51756 : ITESimp::ITESimp(PreprocessingPassContext* preprocContext)
     239                 :            :     : PreprocessingPass(preprocContext, "ite-simp"),
     240                 :      51756 :       d_iteUtilities(d_env),
     241                 :      51756 :       d_statistics(statisticsRegistry())
     242                 :            : {
     243                 :      51756 : }
     244                 :            : 
     245                 :          5 : PreprocessingPassResult ITESimp::applyInternal(
     246                 :            :     AssertionPipeline* assertionsToPreprocess)
     247                 :            : {
     248                 :          5 :   d_preprocContext->spendResource(Resource::PreprocessStep);
     249                 :            : 
     250                 :          5 :   size_t nasserts = assertionsToPreprocess->size();
     251         [ +  + ]:         17 :   for (size_t i = 0; i < nasserts; ++i)
     252                 :            :   {
     253                 :         12 :     d_preprocContext->spendResource(Resource::PreprocessStep);
     254                 :         12 :     Node simp = simpITE(&d_iteUtilities, (*assertionsToPreprocess)[i]);
     255                 :         12 :     assertionsToPreprocess->replace(
     256                 :            :         i, simp, nullptr, TrustId::PREPROCESS_ITE_SIMP);
     257         [ -  + ]:         12 :     if (assertionsToPreprocess->isInConflict())
     258                 :            :     {
     259                 :          0 :       return PreprocessingPassResult::CONFLICT;
     260                 :            :     }
     261         [ +  - ]:         12 :   }
     262                 :          5 :   bool done = doneSimpITE(assertionsToPreprocess);
     263         [ +  - ]:          5 :   return done ? PreprocessingPassResult::NO_CONFLICT
     264                 :          5 :               : PreprocessingPassResult::CONFLICT;
     265                 :            : }
     266                 :            : 
     267                 :            : /* -------------------------------------------------------------------------- */
     268                 :            : 
     269                 :            : }  // namespace passes
     270                 :            : }  // namespace preprocessing
     271                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14