LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/preprocessing/passes - real_to_int.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 116 123 94.3 %
Date: 2026-02-22 11:44:16 Functions: 3 3 100.0 %
Branches: 89 132 67.4 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * Top contributors (to current version):
       3                 :            :  *   Haniel Barbosa, Andrew Reynolds, Aina Niemetz
       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 RealToInt preprocessing pass.
      14                 :            :  *
      15                 :            :  * Converts real operations into integer operations.
      16                 :            :  */
      17                 :            : 
      18                 :            : #include "preprocessing/passes/real_to_int.h"
      19                 :            : 
      20                 :            : #include <string>
      21                 :            : 
      22                 :            : #include "expr/skolem_manager.h"
      23                 :            : #include "preprocessing/assertion_pipeline.h"
      24                 :            : #include "preprocessing/preprocessing_pass_context.h"
      25                 :            : #include "theory/arith/arith_msum.h"
      26                 :            : #include "theory/rewriter.h"
      27                 :            : #include "theory/theory_model.h"
      28                 :            : #include "util/rational.h"
      29                 :            : 
      30                 :            : using namespace cvc5::internal::kind;
      31                 :            : using namespace cvc5::internal::theory;
      32                 :            : 
      33                 :            : namespace cvc5::internal {
      34                 :            : namespace preprocessing {
      35                 :            : namespace passes {
      36                 :            : 
      37                 :      50592 : RealToInt::RealToInt(PreprocessingPassContext* preprocContext)
      38                 :      50592 :     : PreprocessingPass(preprocContext, "real-to-int"), d_cache(userContext())
      39                 :            : {
      40                 :      50592 : }
      41                 :            : 
      42                 :        241 : Node RealToInt::realToIntInternal(TNode n, NodeMap& cache, std::vector<Node>& var_eq)
      43                 :            : {
      44         [ +  - ]:        241 :   Trace("real-as-int-debug") << "Convert : " << n << std::endl;
      45                 :        241 :   NodeMap::iterator find = cache.find(n);
      46         [ +  + ]:        241 :   if (find != cache.end())
      47                 :            :   {
      48                 :         53 :     return (*find).second;
      49                 :            :   }
      50                 :            :   else
      51                 :            :   {
      52                 :        188 :     NodeManager* nm = nodeManager();
      53                 :        188 :     SkolemManager* sm = nm->getSkolemManager();
      54                 :        188 :     Node ret = n;
      55         [ +  + ]:        188 :     if (n.getNumChildren() > 0)
      56                 :            :     {
      57                 :        127 :       if ((n.getKind() == Kind::EQUAL && n[0].getType().isReal())
      58 [ +  + ][ +  - ]:         98 :           || n.getKind() == Kind::GEQ || n.getKind() == Kind::LT
      59 [ +  + ][ +  - ]:        218 :           || n.getKind() == Kind::GT || n.getKind() == Kind::LEQ)
         [ -  + ][ +  + ]
      60                 :            :       {
      61                 :         43 :         ret = rewrite(n);
      62         [ +  - ]:         43 :         Trace("real-as-int-debug") << "Now looking at : " << ret << std::endl;
      63         [ +  - ]:         43 :         if (!ret.isConst())
      64                 :            :         {
      65         [ -  + ]:         43 :           Node ret_lit = ret.getKind() == Kind::NOT ? ret[0] : ret;
      66                 :         43 :           bool ret_pol = ret.getKind() != Kind::NOT;
      67                 :         43 :           std::map<Node, Node> msum;
      68         [ +  - ]:         43 :           if (ArithMSum::getMonomialSumLit(ret_lit, msum))
      69                 :            :           {
      70                 :            :             // get common coefficient
      71                 :         43 :             std::vector<Node> coeffs;
      72                 :         43 :             for (std::map<Node, Node>::iterator itm = msum.begin();
      73         [ +  + ]:        120 :                  itm != msum.end();
      74                 :         77 :                  ++itm)
      75                 :            :             {
      76                 :         77 :               Node v = itm->first;
      77                 :         77 :               Node c = itm->second;
      78         [ +  + ]:         77 :               if (!c.isNull())
      79                 :            :               {
      80 [ -  + ][ -  + ]:         51 :                 Assert(c.isConst());
                 [ -  - ]
      81                 :         51 :                 coeffs.push_back(nm->mkConstInt(
      82                 :        102 :                     Rational(c.getConst<Rational>().getDenominator())));
      83                 :            :               }
      84                 :         77 :             }
      85                 :         43 :             Node cc = coeffs.empty()
      86                 :            :                           ? Node::null()
      87                 :         67 :                           : (coeffs.size() == 1 ? coeffs[0]
      88         [ -  - ]:          9 :                                                 : rewrite(nodeManager()->mkNode(
      89 [ +  + ][ +  + ]:        128 :                                                     Kind::MULT, coeffs)));
         [ +  + ][ +  + ]
                 [ -  - ]
      90                 :         43 :             std::vector<Node> sum;
      91                 :         43 :             for (std::map<Node, Node>::iterator itm = msum.begin();
      92         [ +  + ]:        120 :                  itm != msum.end();
      93                 :         77 :                  ++itm)
      94                 :            :             {
      95                 :         77 :               Node v = itm->first;
      96                 :         77 :               Node c = itm->second;
      97                 :         77 :               Node s;
      98         [ +  + ]:         77 :               if (c.isNull())
      99                 :            :               {
     100 [ +  + ][ +  + ]:         26 :                 c = cc.isNull() ? nodeManager()->mkConstInt(Rational(1)) : cc;
                 [ -  - ]
     101                 :            :               }
     102                 :            :               else
     103                 :            :               {
     104         [ +  - ]:         51 :                 if (!cc.isNull())
     105                 :            :                 {
     106                 :        102 :                   c = nm->mkConstInt(c.getConst<Rational>()
     107                 :        153 :                                      * cc.getConst<Rational>());
     108                 :            :                 }
     109                 :            :               }
     110 [ -  + ][ -  + ]:         77 :               Assert(c.getType().isInteger());
                 [ -  - ]
     111         [ +  + ]:         77 :               if (v.isNull())
     112                 :            :               {
     113                 :         17 :                 sum.push_back(c);
     114                 :            :               }
     115                 :            :               else
     116                 :            :               {
     117                 :         60 :                 Node vv = realToIntInternal(v, cache, var_eq);
     118         [ +  - ]:         60 :                 if (vv.getType().isInteger())
     119                 :            :                 {
     120                 :         60 :                   sum.push_back(nodeManager()->mkNode(Kind::MULT, c, vv));
     121                 :            :                 }
     122                 :            :                 else
     123                 :            :                 {
     124                 :          0 :                   throw TypeCheckingExceptionPrivate(
     125                 :            :                       v,
     126                 :          0 :                       std::string("Cannot translate to Int: ") + v.toString());
     127                 :            :                 }
     128                 :         60 :               }
     129                 :         77 :             }
     130                 :            :             Node sumt =
     131                 :         43 :                 sum.empty()
     132 [ -  + ][ -  - ]:         43 :                     ? nm->mkConstInt(Rational(0))
     133 [ -  + ][ +  + ]:         43 :                     : (sum.size() == 1 ? sum[0] : nm->mkNode(Kind::ADD, sum));
     134                 :         86 :             ret = nm->mkNode(
     135                 :        129 :                 ret_lit.getKind(), sumt, nm->mkConstInt(Rational(0)));
     136         [ -  + ]:         43 :             if (!ret_pol)
     137                 :            :             {
     138                 :          0 :               ret = ret.negate();
     139                 :            :             }
     140         [ +  - ]:         43 :             Trace("real-as-int") << "Convert : " << std::endl;
     141         [ +  - ]:         43 :             Trace("real-as-int") << "   " << n << std::endl;
     142         [ +  - ]:         43 :             Trace("real-as-int") << "   " << ret << std::endl;
     143                 :         43 :           }
     144                 :         43 :         }
     145                 :            :       }
     146                 :            :       else
     147                 :            :       {
     148                 :         66 :         bool childChanged = false;
     149                 :         66 :         std::vector<Node> children;
     150                 :         66 :         Kind k = n.getKind();
     151                 :         66 :         bool preserveTypes = true;
     152                 :            :         // We change Real equalities to Int equalities, we handle other kinds
     153                 :            :         // here as well.
     154 [ +  + ][ +  - ]:         66 :         if (k==Kind::EQUAL || k==Kind::MULT || k==Kind::NONLINEAR_MULT ||
         [ +  + ][ +  - ]
     155 [ +  - ][ -  + ]:         47 :           k==Kind::ADD || k==Kind::SUB || k==Kind::NEG)
     156                 :            :         {
     157                 :         19 :           preserveTypes = false;
     158                 :            :         }
     159         [ +  + ]:        158 :         for (size_t i = 0; i < n.getNumChildren(); i++)
     160                 :            :         {
     161                 :         92 :           Node nc = realToIntInternal(n[i], cache, var_eq);
     162                 :            :           // must preserve types if we don't belong to arithmetic, cast back
     163         [ +  + ]:         92 :           if (preserveTypes)
     164                 :            :           {
     165                 :         52 :             if (!n[i].getType().isInteger() && nc.getType().isInteger())
     166                 :            :             {
     167                 :          4 :               nc = nm->mkNode(Kind::TO_REAL, nc);
     168                 :            :             }
     169                 :            :           }
     170 [ +  + ][ +  + ]:         92 :           childChanged = childChanged || nc != n[i];
         [ +  + ][ -  - ]
     171                 :         92 :           children.push_back(nc);
     172                 :         92 :         }
     173         [ +  + ]:         66 :         if (childChanged)
     174                 :            :         {
     175         [ +  + ]:         56 :           if (n.getMetaKind() == kind::metakind::PARAMETERIZED)
     176                 :            :           {
     177                 :          2 :             children.insert(children.begin(), n.getOperator());
     178                 :            :           }
     179                 :         56 :           ret = nm->mkNode(k, children);
     180                 :            :         }
     181                 :         66 :       }
     182                 :            :     }
     183                 :            :     else
     184                 :            :     {
     185                 :         79 :       TypeNode tn = n.getType();
     186         [ +  + ]:         79 :       if (tn.isReal())
     187                 :            :       {
     188         [ -  + ]:         36 :         if (n.getKind() == Kind::BOUND_VARIABLE)
     189                 :            :         {
     190                 :            :           // cannot change the type of quantified variables, since this leads
     191                 :            :           // to incompleteness.
     192                 :          0 :           throw TypeCheckingExceptionPrivate(
     193                 :            :               n,
     194                 :          0 :               std::string("Cannot translate bound variable to Int: ")
     195                 :          0 :                   + n.toString());
     196                 :            :         }
     197         [ +  + ]:         36 :         else if (n.isVar())
     198                 :            :         {
     199                 :         35 :           Node toIntN = nm->mkNode(Kind::TO_INTEGER, n);
     200                 :         35 :           ret = sm->mkPurifySkolem(toIntN);
     201                 :         35 :           Node retToReal = nm->mkNode(Kind::TO_REAL, ret);
     202                 :         35 :           var_eq.push_back(n.eqNode(retToReal));
     203                 :            :           // add the substitution to the preprocessing context, which ensures
     204                 :            :           // the model for n is correct, as well as substituting it in the input
     205                 :            :           // assertions when necessary.
     206                 :            :           // The model value for the Real variable n we are eliminating is
     207                 :            :           // (to_real k), where k is the Int skolem whose unpurified form is
     208                 :            :           // (to_int n).
     209                 :         35 :           d_preprocContext->addSubstitution(n, retToReal);
     210                 :         35 :         }
     211                 :            :       }
     212                 :         79 :     }
     213                 :        188 :     cache[n] = ret;
     214                 :        188 :     return ret;
     215                 :        188 :   }
     216                 :            : }
     217                 :            : 
     218                 :         31 : PreprocessingPassResult RealToInt::applyInternal(
     219                 :            :     AssertionPipeline* assertionsToPreprocess)
     220                 :            : {
     221                 :         31 :   std::vector<Node> var_eq;
     222         [ +  + ]:        120 :   for (unsigned i = 0, size = assertionsToPreprocess->size(); i < size; ++i)
     223                 :            :   {
     224                 :         89 :     Node a = (*assertionsToPreprocess)[i];
     225                 :         89 :     Node ac = realToIntInternal(a, d_cache, var_eq);
     226         [ +  + ]:         89 :     if (ac != a)
     227                 :            :     {
     228                 :            :       // this pass is refutation unsound, "unsat" will be "unknown"
     229                 :         47 :       assertionsToPreprocess->markRefutationUnsound();
     230         [ +  - ]:         47 :       Trace("real-to-int") << "Converted " << a << " to " << ac << std::endl;
     231                 :         47 :       assertionsToPreprocess->replace(
     232                 :            :           i, ac, nullptr, TrustId::PREPROCESS_REAL_TO_INT);
     233                 :         47 :       assertionsToPreprocess->ensureRewritten(i);
     234         [ -  + ]:         47 :       if (assertionsToPreprocess->isInConflict())
     235                 :            :       {
     236                 :          0 :         return PreprocessingPassResult::CONFLICT;
     237                 :            :       }
     238                 :            :     }
     239 [ +  - ][ +  - ]:         89 :   }
     240                 :         31 :   return PreprocessingPassResult::NO_CONFLICT;
     241                 :         31 : }
     242                 :            : 
     243                 :            : 
     244                 :            : }  // namespace passes
     245                 :            : }  // namespace preprocessing
     246                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14