LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/quantifiers - relevant_domain.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 244 249 98.0 %
Date: 2025-02-08 13:33:28 Functions: 15 15 100.0 %
Branches: 186 254 73.2 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * Top contributors (to current version):
       3                 :            :  *   Andrew Reynolds, Aina Niemetz, Andres Noetzli
       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                 :            :  * Implementation of relevant domain class.
      14                 :            :  */
      15                 :            : 
      16                 :            : #include "theory/quantifiers/relevant_domain.h"
      17                 :            : 
      18                 :            : #include "expr/term_context.h"
      19                 :            : #include "expr/term_context_stack.h"
      20                 :            : #include "theory/arith/arith_msum.h"
      21                 :            : #include "theory/quantifiers/first_order_model.h"
      22                 :            : #include "theory/quantifiers/quantifiers_registry.h"
      23                 :            : #include "theory/quantifiers/quantifiers_state.h"
      24                 :            : #include "theory/quantifiers/term_database.h"
      25                 :            : #include "theory/quantifiers/instantiate.h"
      26                 :            : #include "theory/quantifiers/term_registry.h"
      27                 :            : #include "theory/quantifiers/term_util.h"
      28                 :            : #include "util/rational.h"
      29                 :            : 
      30                 :            : using namespace cvc5::internal::kind;
      31                 :            : 
      32                 :            : namespace cvc5::internal {
      33                 :            : namespace theory {
      34                 :            : namespace quantifiers {
      35                 :            : 
      36                 :      30567 : void RelevantDomain::RDomain::merge( RDomain * r ) {
      37 [ -  + ][ -  + ]:      30567 :   Assert(!d_parent);
                 [ -  - ]
      38 [ -  + ][ -  + ]:      30567 :   Assert(!r->d_parent);
                 [ -  - ]
      39                 :      30567 :   d_parent = r;
      40         [ +  + ]:      31934 :   for( unsigned i=0; i<d_terms.size(); i++ ){
      41                 :       1367 :     r->addTerm( d_terms[i] );
      42                 :            :   }
      43                 :      30567 :   d_terms.clear();
      44                 :      30567 : }
      45                 :            : 
      46                 :      32453 : void RelevantDomain::RDomain::addTerm( Node t ) {
      47         [ +  + ]:      32453 :   if( std::find( d_terms.begin(), d_terms.end(), t )==d_terms.end() ){
      48                 :       7476 :     d_terms.push_back( t );
      49                 :            :   }
      50                 :      32453 : }
      51                 :            : 
      52                 :    1060640 : RelevantDomain::RDomain * RelevantDomain::RDomain::getParent() {
      53         [ +  + ]:    1060640 :   if( !d_parent ){
      54                 :     532144 :     return this;
      55                 :            :   }else{
      56                 :     528498 :     RDomain * p = d_parent->getParent();
      57                 :     528498 :     d_parent = p;
      58                 :     528498 :     return p;
      59                 :            :   }
      60                 :            : }
      61                 :            : 
      62                 :       3174 : void RelevantDomain::RDomain::removeRedundantTerms(QuantifiersState& qs)
      63                 :            : {
      64                 :       6348 :   std::map< Node, Node > rterms;
      65         [ +  + ]:       9283 :   for( unsigned i=0; i<d_terms.size(); i++ ){
      66                 :      12218 :     Node r = d_terms[i];
      67         [ +  - ]:       6109 :     if( !TermUtil::hasInstConstAttr( d_terms[i] ) ){
      68                 :       6109 :       r = qs.getRepresentative(d_terms[i]);
      69                 :            :     }
      70         [ +  + ]:       6109 :     if( rterms.find( r )==rterms.end() ){
      71                 :       4699 :       rterms[r] = d_terms[i];
      72                 :            :     }
      73                 :            :   }
      74                 :       3174 :   d_terms.clear();
      75         [ +  + ]:       7873 :   for( std::map< Node, Node >::iterator it = rterms.begin(); it != rterms.end(); ++it ){
      76                 :       4699 :     d_terms.push_back( it->second );
      77                 :            :   }
      78                 :       3174 : }
      79                 :            : 
      80                 :        334 : RelevantDomain::RelevantDomain(Env& env,
      81                 :            :                                QuantifiersState& qs,
      82                 :            :                                QuantifiersRegistry& qr,
      83                 :        334 :                                TermRegistry& tr)
      84                 :        334 :     : QuantifiersUtil(env), d_qs(qs), d_qreg(qr), d_treg(tr)
      85                 :            : {
      86                 :        334 :   d_is_computed = false;
      87                 :        334 : }
      88                 :            : 
      89                 :        668 : RelevantDomain::~RelevantDomain() {
      90         [ +  + ]:       2722 :   for (auto& r : d_rel_doms)
      91                 :            :   {
      92         [ +  + ]:      14748 :     for (auto& rr : r.second)
      93                 :            :     {
      94                 :      12360 :       RDomain* current = rr.second;
      95 [ -  + ][ -  + ]:      12360 :       Assert(current != NULL);
      96         [ +  - ]:      12360 :       delete current;
      97                 :            :     }
      98                 :            :   }
      99                 :        668 : }
     100                 :            : 
     101                 :     497328 : RelevantDomain::RDomain* RelevantDomain::getRDomain(Node n,
     102                 :            :                                                     size_t i,
     103                 :            :                                                     bool getParent)
     104                 :            : {
     105 [ +  + ][ +  + ]:     497328 :   if( d_rel_doms.find( n )==d_rel_doms.end() || d_rel_doms[n].find( i )==d_rel_doms[n].end() ){
                 [ +  + ]
     106                 :      12360 :     d_rel_doms[n][i] = new RDomain;
     107                 :            :   }
     108         [ +  + ]:     497328 :   return getParent ? d_rel_doms[n][i]->getParent() : d_rel_doms[n][i];
     109                 :            : }
     110                 :            : 
     111                 :       4135 : bool RelevantDomain::reset( Theory::Effort e ) {
     112                 :       4135 :   d_is_computed = false;
     113                 :       4135 :   return true;
     114                 :            : }
     115                 :            : 
     116                 :      13608 : void RelevantDomain::registerQuantifier(Node q) {}
     117                 :        466 : void RelevantDomain::compute(){
     118         [ +  - ]:        466 :   if( !d_is_computed ){
     119                 :        466 :     d_is_computed = true;
     120         [ +  + ]:       3904 :     for (auto& r : d_rel_doms)
     121                 :            :     {
     122         [ +  + ]:      25045 :       for (auto& rr : r.second)
     123                 :            :       {
     124                 :      21607 :         rr.second->reset();
     125                 :            :       }
     126                 :            :     }
     127                 :        466 :     FirstOrderModel* fm = d_treg.getModel();
     128         [ +  + ]:       4007 :     for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
     129                 :       7082 :       Node q = fm->getAssertedQuantifier( i );
     130                 :       3541 :       Node icf = d_qreg.getInstConstantBody(q);
     131         [ +  - ]:       3541 :       Trace("rel-dom-debug") << "compute relevant domain for " << icf << std::endl;
     132                 :       3541 :       computeRelevantDomain(q);
     133                 :            :     }
     134                 :            : 
     135         [ +  - ]:        466 :     Trace("rel-dom-debug") << "account for ground terms" << std::endl;
     136                 :        466 :     TermDb* db = d_treg.getTermDatabase();
     137         [ +  + ]:       2588 :     for (unsigned k = 0; k < db->getNumOperators(); k++)
     138                 :            :     {
     139                 :       4244 :       Node op = db->getOperator(k);
     140                 :       2122 :       unsigned sz = db->getNumGroundTerms( op );
     141         [ +  + ]:      12480 :       for( unsigned i=0; i<sz; i++ ){
     142                 :      20716 :         Node n = db->getGroundTerm(op, i);
     143                 :            :         //if it is a non-redundant term
     144         [ +  + ]:      10358 :         if( db->isTermActive( n ) ){
     145         [ +  + ]:      34873 :           for( unsigned j=0; j<n.getNumChildren(); j++ ){
     146                 :      27886 :             RDomain * rf = getRDomain( op, j );
     147                 :      27886 :             rf->addTerm( n[j] );
     148 [ +  - ][ -  + ]:      27886 :             Trace("rel-dom-debug") << "...add ground term " << n[j] << " to rel dom " << op << "[" << j << "]" << std::endl;
                 [ -  - ]
     149                 :            :           }
     150                 :            :         }
     151                 :            :       }
     152                 :            :     }
     153                 :            :     // print debug and verify types are correct
     154                 :        466 :     NodeManager* nm = nodeManager();
     155         [ +  + ]:       6177 :     for (std::pair<const Node, std::map<size_t, RDomain*> >& d : d_rel_doms)
     156                 :            :     {
     157         [ +  - ]:      11422 :       Trace("rel-dom") << "Relevant domain for " << d.first << " : "
     158                 :       5711 :                        << std::endl;
     159         [ +  + ]:      39452 :       for (std::pair<const size_t, RDomain*>& dd : d.second)
     160                 :            :       {
     161         [ +  - ]:      33741 :         Trace("rel-dom") << "   " << dd.first << " : ";
     162                 :      33741 :         RDomain* r = dd.second;
     163                 :      33741 :         RDomain * rp = r->getParent();
     164         [ +  + ]:      33741 :         if( r==rp ){
     165                 :       3174 :           r->removeRedundantTerms(d_qs);
     166         [ +  - ]:       3174 :           Trace("rel-dom") << r->d_terms;
     167                 :            :         }else{
     168         [ +  - ]:      30567 :           Trace("rel-dom") << "Dom( " << d.first << ", " << dd.first << " ) ";
     169                 :            :         }
     170         [ +  - ]:      33741 :         Trace("rel-dom") << std::endl;
     171         [ +  + ]:      33741 :         if (d.first.getKind() == Kind::FORALL)
     172                 :            :         {
     173                 :      67515 :           TypeNode expectedType = d.first[0][dd.first].getType();
     174         [ +  + ]:      22886 :           for (Node& t : r->d_terms)
     175                 :            :           {
     176                 :        762 :             TypeNode tt = t.getType();
     177         [ -  + ]:        381 :             if (tt != expectedType)
     178                 :            :             {
     179                 :            :               // Computation may merge Int with Real due to inequalities. We
     180                 :            :               // correct this here.
     181                 :          0 :               if (tt.isInteger() && expectedType.isReal())
     182                 :            :               {
     183                 :          0 :                 t = nm->mkNode(Kind::TO_REAL, t);
     184                 :            :               }
     185                 :            :               else
     186                 :            :               {
     187                 :          0 :                 Assert(false) << "Relevant domain: bad type " << t.getType()
     188                 :          0 :                               << ", expected " << expectedType;
     189                 :            :               }
     190                 :            :             }
     191                 :            :           }
     192                 :            :         }
     193                 :            :       }
     194                 :            :     }
     195                 :            :   }
     196                 :        466 : }
     197                 :            : 
     198                 :       3541 : void RelevantDomain::computeRelevantDomain(Node q)
     199                 :            : {
     200 [ -  + ][ -  + ]:       3541 :   Assert(q.getKind() == Kind::FORALL);
                 [ -  - ]
     201                 :       7082 :   Node n = d_qreg.getInstConstantBody(q);
     202                 :            :   // we care about polarity in the traversal, so we use a polarity term context
     203                 :       7082 :   PolarityTermContext tc;
     204                 :       7082 :   TCtxStack ctx(&tc);
     205                 :       3541 :   ctx.pushInitial(n);
     206                 :            :   std::unordered_set<std::pair<Node, uint32_t>,
     207                 :            :                      PairHashFunction<Node, uint32_t, std::hash<Node> > >
     208                 :       7082 :       visited;
     209                 :       7082 :   std::pair<Node, uint32_t> curr;
     210                 :       7082 :   Node node;
     211                 :            :   uint32_t nodeVal;
     212                 :            :   std::unordered_set<
     213                 :            :       std::pair<Node, uint32_t>,
     214                 :       3541 :       PairHashFunction<Node, uint32_t, std::hash<Node> > >::const_iterator itc;
     215                 :            :   bool hasPol, pol;
     216         [ +  + ]:     236602 :   while (!ctx.empty())
     217                 :            :   {
     218                 :     233061 :     curr = ctx.getCurrent();
     219                 :     233061 :     itc = visited.find(curr);
     220                 :     233061 :     ctx.pop();
     221         [ +  + ]:     233061 :     if (itc == visited.end())
     222                 :            :     {
     223                 :      76922 :       visited.insert(curr);
     224                 :      76922 :       node = curr.first;
     225                 :            :       // if not a quantified formula
     226         [ +  + ]:      76922 :       if (!node.isClosure())
     227                 :            :       {
     228                 :      76490 :         nodeVal = curr.second;
     229                 :            :         // get the polarity of the current term and process it
     230                 :      76490 :         PolarityTermContext::getFlags(nodeVal, hasPol, pol);
     231                 :      76490 :         computeRelevantDomainNode(q, node, hasPol, pol);
     232                 :            :         // traverse the children
     233                 :      76490 :         ctx.pushChildren(node, nodeVal);
     234                 :            :       }
     235                 :            :     }
     236                 :            :   }
     237                 :       3541 : }
     238                 :            : 
     239                 :      76490 : void RelevantDomain::computeRelevantDomainNode(Node q,
     240                 :            :                                                Node n,
     241                 :            :                                                bool hasPol,
     242                 :            :                                                bool pol)
     243                 :            : {
     244         [ +  - ]:      76490 :   Trace("rel-dom-debug") << "Compute relevant domain " << n << "..." << std::endl;
     245                 :      76490 :   Node op = d_treg.getTermDatabase()->getMatchOperator(n);
     246                 :            :   // Relevant domain only makes sense for non-parametric operators, thus we
     247                 :            :   // check op==n.getOperator() here. This otherwise would lead to bad types
     248                 :            :   // for terms in the relevant domain.
     249 [ +  + ][ +  + ]:      76490 :   if (!op.isNull() && op == n.getOperator())
         [ +  + ][ +  + ]
                 [ -  - ]
     250                 :            :   {
     251         [ +  + ]:     200828 :     for (size_t i = 0, nchild = n.getNumChildren(); i < nchild; i++)
     252                 :            :     {
     253                 :     176791 :       RDomain * rf = getRDomain( op, i );
     254         [ +  + ]:     176791 :       if (n[i].getKind() == Kind::ITE)
     255                 :            :       {
     256         [ +  + ]:         12 :         for( unsigned j=1; j<=2; j++ ){
     257                 :          8 :           computeRelevantDomainOpCh( rf, n[i][j] );
     258                 :            :         }
     259                 :            :       }
     260                 :            :       else
     261                 :            :       {
     262                 :     176787 :         computeRelevantDomainOpCh( rf, n[i] );
     263                 :            :       }
     264                 :            :     }
     265                 :            :   }
     266                 :            : 
     267                 :      79095 :   if (((n.getKind() == Kind::EQUAL && !n[0].getType().isBoolean())
     268         [ +  + ]:      73969 :        || n.getKind() == Kind::GEQ)
     269 [ +  + ][ +  - ]:     152980 :       && TermUtil::hasInstConstAttr(n))
         [ +  + ][ +  + ]
                 [ -  - ]
     270                 :            :   {
     271                 :            :     //compute the information for what this literal does
     272                 :       3003 :     computeRelevantDomainLit( q, hasPol, pol, n );
     273                 :       3003 :     RDomainLit& rdl = d_rel_dom_lit[hasPol][pol][n];
     274         [ +  + ]:       3003 :     if (rdl.d_merge)
     275                 :            :     {
     276 [ +  - ][ +  - ]:        810 :       Assert(rdl.d_rd[0] != nullptr && rdl.d_rd[1] != nullptr);
         [ -  + ][ -  - ]
     277                 :        405 :       RDomain* rd1 = rdl.d_rd[0]->getParent();
     278                 :        405 :       RDomain* rd2 = rdl.d_rd[1]->getParent();
     279         [ +  + ]:        405 :       if( rd1!=rd2 ){
     280                 :        319 :         rd1->merge( rd2 );
     281                 :            :       }
     282                 :            :     }
     283                 :            :     else
     284                 :            :     {
     285         [ +  + ]:       2598 :       if (rdl.d_rd[0] != nullptr)
     286                 :            :       {
     287                 :       1087 :         RDomain* rd = rdl.d_rd[0]->getParent();
     288         [ +  + ]:       2176 :         for (unsigned i = 0; i < rdl.d_val.size(); i++)
     289                 :            :         {
     290                 :       1089 :           rd->addTerm(rdl.d_val[i]);
     291                 :            :         }
     292                 :            :       }
     293                 :            :     }
     294                 :            :   }
     295         [ +  - ]:      76490 :   Trace("rel-dom-debug") << "...finished Compute relevant domain " << n << std::endl;
     296                 :      76490 : }
     297                 :            : 
     298                 :     176795 : void RelevantDomain::computeRelevantDomainOpCh( RDomain * rf, Node n ) {
     299         [ +  + ]:     176795 :   if (n.getKind() == Kind::INST_CONSTANT)
     300                 :            :   {
     301                 :     348110 :     Node q = TermUtil::getInstConstAttr(n);
     302                 :            :     //merge the RDomains
     303                 :     174055 :     size_t id = n.getAttribute(InstVarNumAttribute());
     304 [ -  + ][ -  + ]:     174055 :     Assert(q[0][id].getType() == n.getType());
                 [ -  - ]
     305         [ +  - ]:     174055 :     Trace("rel-dom-debug") << n << " is variable # " << id << " for " << q;
     306                 :     348110 :     Trace("rel-dom-debug") << " with body : " << d_qreg.getInstConstantBody(q)
     307                 :     174055 :                            << std::endl;
     308                 :     174055 :     RDomain * rq = getRDomain( q, id );
     309         [ +  + ]:     174055 :     if( rf!=rq ){
     310                 :      30248 :       rq->merge( rf );
     311                 :            :     }
     312                 :            :   }
     313         [ +  + ]:       2740 :   else if (!TermUtil::hasInstConstAttr(n))
     314                 :            :   {
     315         [ +  - ]:       2111 :     Trace("rel-dom-debug") << "...add ground term to rel dom " << n << std::endl;
     316                 :            :     //term to add
     317                 :       2111 :     rf->addTerm( n );
     318                 :            :   }
     319                 :     176795 : }
     320                 :            : 
     321                 :       3003 : void RelevantDomain::computeRelevantDomainLit( Node q, bool hasPol, bool pol, Node n ) {
     322         [ +  + ]:       3003 :   if (d_rel_dom_lit[hasPol][pol].find(n) != d_rel_dom_lit[hasPol][pol].end())
     323                 :            :   {
     324                 :       1790 :     return;
     325                 :            :   }
     326                 :       1321 :   NodeManager* nm = nodeManager();
     327                 :       1321 :   RDomainLit& rdl = d_rel_dom_lit[hasPol][pol][n];
     328                 :       1321 :   rdl.d_merge = false;
     329                 :       1321 :   size_t varCount = 0;
     330                 :       1321 :   size_t varCh = 0;
     331 [ -  + ][ -  + ]:       1321 :   Assert(n.getNumChildren() == 2);
                 [ -  - ]
     332         [ +  + ]:       3963 :   for (size_t i = 0; i < 2; i++)
     333                 :            :   {
     334         [ +  + ]:       2642 :     if (n[i].getKind() == Kind::INST_CONSTANT)
     335                 :            :     {
     336                 :            :       // must get the quantified formula this belongs to, which may be
     337                 :            :       // different from q
     338                 :        742 :       Node qi = TermUtil::getInstConstAttr(n[i]);
     339                 :        742 :       unsigned id = n[i].getAttribute(InstVarNumAttribute());
     340                 :        742 :       rdl.d_rd[i] = getRDomain(qi, id, false);
     341                 :        742 :       varCount++;
     342                 :        742 :       varCh = i;
     343                 :            :     }
     344                 :            :     else
     345                 :            :     {
     346                 :       1900 :       rdl.d_rd[i] = nullptr;
     347                 :            :     }
     348                 :            :   }
     349                 :            : 
     350                 :       1321 :   Node rAdd;
     351                 :       1321 :   Node rVar;
     352                 :       1321 :   bool varLhs = true;
     353         [ +  + ]:       1321 :   if (varCount == 2)
     354                 :            :   {
     355                 :            :     // don't merge Int and Real
     356                 :         87 :     rdl.d_merge = (n[0].getType() == n[1].getType());
     357                 :            :   }
     358         [ +  + ]:       1234 :   else if (varCount == 1)
     359                 :            :   {
     360                 :        568 :     rVar = n[varCh];
     361                 :        568 :     rAdd = n[1 - varCh];
     362                 :        568 :     varLhs = (varCh == 0);
     363                 :        568 :     rdl.d_rd[0] = rdl.d_rd[varCh];
     364                 :        568 :     rdl.d_rd[1] = nullptr;
     365                 :            :   }
     366         [ +  + ]:        666 :   else if (n[0].getType().isRealOrInt())
     367                 :            :   {
     368                 :            :     // solve the inequality for one/two variables, if possible
     369                 :        762 :     std::map<Node, Node> msum;
     370         [ +  - ]:        381 :     if (ArithMSum::getMonomialSumLit(n, msum))
     371                 :            :     {
     372                 :        762 :       Node var;
     373                 :        762 :       Node var2;
     374                 :        381 :       bool hasNonVar = false;
     375         [ +  + ]:       1174 :       for (std::pair<const Node, Node>& m : msum)
     376                 :            :       {
     377         [ +  + ]:        684 :         if (!m.first.isNull() && m.first.getKind() == Kind::INST_CONSTANT
     378                 :       1477 :             && TermUtil::getInstConstAttr(m.first) == q)
     379                 :            :         {
     380         [ +  + ]:        137 :           if (var.isNull())
     381                 :            :           {
     382                 :         95 :             var = m.first;
     383                 :            :           }
     384         [ +  - ]:         42 :           else if (var2.isNull())
     385                 :            :           {
     386                 :         42 :             var2 = m.first;
     387                 :            :           }
     388                 :            :           else
     389                 :            :           {
     390                 :          0 :             hasNonVar = true;
     391                 :            :           }
     392                 :            :         }
     393                 :            :         else
     394                 :            :         {
     395                 :        656 :           hasNonVar = true;
     396                 :            :         }
     397                 :            :       }
     398         [ +  - ]:        762 :       Trace("rel-dom") << "Process lit " << n << ", var/var2=" << var << "/"
     399                 :        381 :                        << var2 << std::endl;
     400         [ +  + ]:        381 :       if (!var.isNull())
     401                 :            :       {
     402 [ -  + ][ -  + ]:         95 :         Assert(var.hasAttribute(InstVarNumAttribute()));
                 [ -  - ]
     403         [ +  + ]:         95 :         if (var2.isNull())
     404                 :            :         {
     405                 :            :           // single variable solve
     406                 :        106 :           Node veq_c;
     407                 :        106 :           Node val;
     408                 :         53 :           int ires = ArithMSum::isolate(var, msum, veq_c, val, n.getKind());
     409         [ +  - ]:         53 :           if (ires != 0)
     410                 :            :           {
     411         [ +  + ]:         53 :             if (veq_c.isNull())
     412                 :            :             {
     413                 :         38 :               rVar = var;
     414                 :         38 :               rAdd = val;
     415                 :         38 :               varLhs = (ires == 1);
     416                 :         38 :               rdl.d_rd[0] =
     417                 :         38 :                   getRDomain(q, var.getAttribute(InstVarNumAttribute()), false);
     418                 :         38 :               rdl.d_rd[1] = nullptr;
     419                 :            :             }
     420                 :            :           }
     421                 :            :         }
     422         [ +  + ]:         42 :         else if (!hasNonVar)
     423                 :            :         {
     424 [ -  + ][ -  + ]:         21 :           Assert(var2.hasAttribute(InstVarNumAttribute()));
                 [ -  - ]
     425                 :            :           // merge the domains
     426                 :         21 :           rdl.d_rd[0] =
     427                 :         21 :               getRDomain(q, var.getAttribute(InstVarNumAttribute()), false);
     428                 :         21 :           rdl.d_rd[1] =
     429                 :         21 :               getRDomain(q, var2.getAttribute(InstVarNumAttribute()), false);
     430                 :         21 :           rdl.d_merge = true;
     431                 :            :         }
     432                 :            :       }
     433                 :            :     }
     434                 :            :   }
     435         [ +  + ]:       1321 :   if (rdl.d_merge)
     436                 :            :   {
     437                 :            :     // do not merge if constant negative polarity
     438 [ +  + ][ +  + ]:        108 :     if (hasPol && !pol)
     439                 :            :     {
     440                 :         21 :       rdl.d_merge = false;
     441                 :            :     }
     442                 :        108 :     return;
     443                 :            :   }
     444         [ +  + ]:       1213 :   if (!rAdd.isNull())
     445                 :            :   {
     446                 :            :     // Ensure that rAdd has the same type as the variable. This is necessary
     447                 :            :     // since GEQ may mix Int and Real, as well as the equality solving above
     448                 :            :     // may introduce mixed Int and Real.
     449                 :        606 :     rAdd = TermUtil::ensureType(rAdd, rVar.getType());
     450                 :            :   }
     451 [ +  + ][ +  + ]:       1213 :   if (!rAdd.isNull() && !TermUtil::hasInstConstAttr(rAdd))
         [ +  + ][ +  + ]
                 [ -  - ]
     452                 :            :   {
     453         [ +  - ]:       1032 :     Trace("rel-dom-debug") << "...add term " << rAdd << ", pol = " << pol
     454                 :        516 :                            << ", kind = " << n.getKind() << std::endl;
     455                 :            :     // the negative occurrence adds the term to the domain
     456 [ +  + ][ +  + ]:        516 :     if (!hasPol || !pol)
     457                 :            :     {
     458                 :        421 :       rdl.d_val.push_back(rAdd);
     459                 :            :     }
     460                 :            :     // the positive occurrence adds other terms
     461                 :        516 :     if ((!hasPol || pol) && n[0].getType().isInteger())
     462                 :            :     {
     463         [ +  + ]:        103 :       if (n.getKind() == Kind::EQUAL)
     464                 :            :       {
     465         [ +  + ]:         45 :         for (size_t i = 0; i < 2; i++)
     466                 :            :         {
     467                 :            :           Node roff = nm->mkNode(
     468         [ +  + ]:         90 :               Kind::ADD, rAdd, nm->mkConstInt(Rational(i == 0 ? 1 : -1)));
     469                 :         30 :           rdl.d_val.push_back(roff);
     470                 :            :         }
     471                 :            :       }
     472         [ +  - ]:         88 :       else if (n.getKind() == Kind::GEQ)
     473                 :            :       {
     474                 :            :         Node roff = nm->mkNode(
     475         [ +  - ]:        264 :             Kind::ADD, rAdd, nm->mkConstInt(Rational(varLhs ? 1 : -1)));
     476                 :         88 :         rdl.d_val.push_back(roff);
     477                 :            :       }
     478                 :            :     }
     479                 :            :   }
     480                 :            :   else
     481                 :            :   {
     482                 :        697 :     rdl.d_rd[0] = nullptr;
     483                 :        697 :     rdl.d_rd[1] = nullptr;
     484                 :            :   }
     485                 :            : }
     486                 :            : 
     487                 :            : }  // namespace quantifiers
     488                 :            : }  // namespace theory
     489                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14