LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/quantifiers/fmf - bounded_integers.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 525 573 91.6 %
Date: 2026-03-30 10:41:07 Functions: 29 29 100.0 %
Branches: 367 558 65.8 %

           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                 :            :  * Bounded integers module
      11                 :            :  *
      12                 :            :  * This class manages integer bounds for quantifiers.
      13                 :            :  */
      14                 :            : 
      15                 :            : #include "theory/quantifiers/fmf/bounded_integers.h"
      16                 :            : 
      17                 :            : #include "expr/dtype_cons.h"
      18                 :            : #include "expr/emptyset.h"
      19                 :            : #include "expr/node_algorithm.h"
      20                 :            : #include "expr/skolem_manager.h"
      21                 :            : #include "options/datatypes_options.h"
      22                 :            : #include "options/quantifiers_options.h"
      23                 :            : #include "theory/arith/arith_msum.h"
      24                 :            : #include "theory/datatypes/theory_datatypes_utils.h"
      25                 :            : #include "theory/decision_manager.h"
      26                 :            : #include "theory/quantifiers/first_order_model.h"
      27                 :            : #include "theory/quantifiers/fmf/model_engine.h"
      28                 :            : #include "theory/quantifiers/term_enumeration.h"
      29                 :            : #include "theory/quantifiers/term_util.h"
      30                 :            : #include "theory/rep_set_iterator.h"
      31                 :            : #include "theory/rewriter.h"
      32                 :            : #include "theory/sets/normal_form.h"
      33                 :            : #include "util/rational.h"
      34                 :            : 
      35                 :            : using namespace cvc5::internal::kind;
      36                 :            : 
      37                 :            : namespace cvc5::internal {
      38                 :            : namespace theory {
      39                 :            : namespace quantifiers {
      40                 :            : 
      41                 :       1107 : BoundedIntegers::IntRangeDecisionHeuristic::IntRangeDecisionHeuristic(
      42                 :       1107 :     Env& env, Node r, Valuation valuation, bool isProxy)
      43                 :            :     : DecisionStrategyFmf(env, valuation),
      44                 :       1107 :       d_range(r),
      45                 :       1107 :       d_ranges_proxied(userContext())
      46                 :            : {
      47                 :            :   // we require a proxy if the term is set.card
      48 [ +  + ][ +  + ]:       1107 :   if (options().quantifiers.fmfBoundLazy || r.getKind() == Kind::SET_CARD)
                 [ +  + ]
      49                 :            :   {
      50                 :            :     d_proxy_range =
      51                 :         64 :         isProxy ? r : NodeManager::mkDummySkolem("pbir", r.getType());
      52                 :            :   }
      53                 :            :   else
      54                 :            :   {
      55                 :       1043 :     d_proxy_range = r;
      56                 :            :   }
      57         [ +  + ]:       1107 :   if( !isProxy ){
      58         [ +  - ]:        980 :     Trace("bound-int") << "Introduce proxy " << d_proxy_range << " for " << d_range << std::endl;
      59                 :            :   }
      60                 :       1107 : }
      61                 :       3122 : Node BoundedIntegers::IntRangeDecisionHeuristic::mkLiteral(unsigned n)
      62                 :            : {
      63                 :       3122 :   NodeManager* nm = nodeManager();
      64         [ +  + ]:       3122 :   Node cn = nm->mkConstInt(Rational(n == 0 ? 0 : n - 1));
      65         [ +  + ]:       6244 :   return nm->mkNode(n == 0 ? Kind::LT : Kind::LEQ, d_proxy_range, cn);
      66                 :       3122 : }
      67                 :            : 
      68                 :       2950 : Node BoundedIntegers::IntRangeDecisionHeuristic::proxyCurrentRangeLemma()
      69                 :            : {
      70         [ +  + ]:       2950 :   if (d_range == d_proxy_range)
      71                 :            :   {
      72                 :       2577 :     return Node::null();
      73                 :            :   }
      74                 :        373 :   unsigned curr = 0;
      75         [ +  + ]:        373 :   if (!getAssertedLiteralIndex(curr))
      76                 :            :   {
      77                 :          2 :     return Node::null();
      78                 :            :   }
      79         [ +  + ]:        371 :   if (d_ranges_proxied.find(curr) != d_ranges_proxied.end())
      80                 :            :   {
      81                 :        154 :     return Node::null();
      82                 :            :   }
      83                 :        217 :   d_ranges_proxied[curr] = true;
      84                 :        217 :   NodeManager* nm = nodeManager();
      85                 :        217 :   Node currLit = getLiteral(curr);
      86                 :        217 :   Node lit;
      87         [ +  + ]:        217 :   if (d_range.getKind() == Kind::SET_CARD)
      88                 :            :   {
      89                 :            :     // Instead of introducing (set.card s) < n, we introduce the literal
      90                 :            :     // s = characteristicSet(s, n-1) for n>0 and false for n=0. We do this
      91                 :            :     // to avoid introducing set.card.
      92         [ +  + ]:        210 :     if (curr == 0)
      93                 :            :     {
      94                 :         57 :       lit = nodeManager()->mkConst(false);
      95                 :            :     }
      96                 :            :     else
      97                 :            :     {
      98                 :            :       Node cset = sets::NormalForm::getCharacteristicSet(
      99                 :        153 :           nodeManager(), d_range[0], curr - 1);
     100                 :        153 :       lit = d_range[0].eqNode(cset);
     101                 :        153 :     }
     102                 :            :   }
     103                 :            :   else
     104                 :            :   {
     105         [ +  - ]:         21 :     lit = nm->mkNode(curr == 0 ? Kind::LT : Kind::LEQ,
     106                 :          7 :                      d_range,
     107         [ -  + ]:         21 :                      nm->mkConstInt(Rational(curr == 0 ? 0 : curr - 1)));
     108                 :            :   }
     109                 :        434 :   Node lem = nm->mkNode(Kind::EQUAL, currLit, lit);
     110                 :        217 :   return lem;
     111                 :        217 : }
     112                 :            : 
     113                 :      32832 : BoundedIntegers::BoundedIntegers(Env& env,
     114                 :            :                                  QuantifiersState& qs,
     115                 :            :                                  QuantifiersInferenceManager& qim,
     116                 :            :                                  QuantifiersRegistry& qr,
     117                 :      32832 :                                  TermRegistry& tr)
     118         [ +  + ]:      98496 :     : QuantifiersModule(env, qs, qim, qr, tr)
     119                 :            : {
     120                 :      32832 : }
     121                 :            : 
     122 [ +  - ][ +  + ]:     130220 : BoundedIntegers::~BoundedIntegers() {}
     123                 :            : 
     124                 :      29400 : void BoundedIntegers::presolve() {
     125                 :      29400 :   d_bnd_it.clear();
     126                 :      29400 : }
     127                 :            : 
     128                 :      24922 : bool BoundedIntegers::hasNonBoundVar( Node f, Node b, std::map< Node, bool >& visited ) {
     129         [ +  + ]:      24922 :   if( visited.find( b )==visited.end() ){
     130                 :      20976 :     visited[b] = true;
     131         [ +  + ]:      20976 :     if (b.getKind() == Kind::BOUND_VARIABLE)
     132                 :            :     {
     133         [ +  + ]:       1649 :       if( !isBound( f, b ) ){
     134                 :        856 :         return true;
     135                 :            :       }
     136                 :            :     }
     137                 :            :     else
     138                 :            :     {
     139         [ +  + ]:      37811 :       for( unsigned i=0; i<b.getNumChildren(); i++ ){
     140         [ +  + ]:      19961 :         if( hasNonBoundVar( f, b[i], visited ) ){
     141                 :       1477 :           return true;
     142                 :            :         }
     143                 :            :       }
     144                 :            :     }
     145                 :            :   }
     146                 :      22589 :   return false;
     147                 :            : }
     148                 :       4961 : bool BoundedIntegers::hasNonBoundVar( Node f, Node b ) {
     149                 :       4961 :   std::map< Node, bool > visited;
     150                 :       9922 :   return hasNonBoundVar( f, b, visited );
     151                 :       4961 : }
     152                 :            : 
     153                 :       1004 : bool BoundedIntegers::processEqDisjunct( Node q, Node n, Node& v, std::vector< Node >& v_cases ) {
     154         [ +  + ]:       1004 :   if (n.getKind() == Kind::EQUAL)
     155                 :            :   {
     156         [ +  + ]:       2910 :     for( unsigned i=0; i<2; i++ ){
     157                 :       1964 :       Node t = n[i];
     158         [ +  + ]:       1964 :       if( !hasNonBoundVar( q, n[1-i] ) ){
     159         [ +  + ]:       1353 :         if( t==v ){
     160                 :         24 :           v_cases.push_back( n[1-i] );
     161                 :         24 :           return true;
     162                 :            :         }
     163 [ +  + ][ +  + ]:       1329 :         else if (v.isNull() && t.getKind() == Kind::BOUND_VARIABLE)
                 [ +  + ]
     164                 :            :         {
     165                 :         26 :           v = t;
     166                 :         26 :           v_cases.push_back( n[1-i] );
     167                 :         26 :           return true;
     168                 :            :         }
     169                 :            :       }
     170         [ +  + ]:       1964 :     }
     171                 :            :   }
     172                 :        954 :   return false;
     173                 :            : }
     174                 :            : 
     175                 :        400 : void BoundedIntegers::processMatchBoundVars( Node q, Node n, std::vector< Node >& bvs, std::map< Node, bool >& visited ){
     176         [ +  - ]:        400 :   if( visited.find( n )==visited.end() ){
     177                 :        400 :     visited[n] = true;
     178                 :        400 :     if (n.getKind() == Kind::BOUND_VARIABLE && !isBound(q, n))
     179                 :            :     {
     180                 :        125 :       bvs.push_back( n );
     181                 :            :     //injective operators
     182                 :            :     }
     183         [ +  + ]:        275 :     else if (n.getKind() == Kind::APPLY_CONSTRUCTOR)
     184                 :            :     {
     185         [ +  + ]:        308 :       for( unsigned i=0; i<n.getNumChildren(); i++ ){
     186                 :        172 :         processMatchBoundVars( q, n[i], bvs, visited );
     187                 :            :       }
     188                 :            :     }
     189                 :            :   }
     190                 :        400 : }
     191                 :            : 
     192                 :      16338 : void BoundedIntegers::process( Node q, Node n, bool pol,
     193                 :            :                                std::map< Node, unsigned >& bound_lit_type_map,
     194                 :            :                                std::map< int, std::map< Node, Node > >& bound_lit_map,
     195                 :            :                                std::map< int, std::map< Node, bool > >& bound_lit_pol_map,
     196                 :            :                                std::map< int, std::map< Node, Node > >& bound_int_range_term,
     197                 :            :                                std::map< Node, std::vector< Node > >& bound_fixed_set ){
     198 [ +  + ][ +  + ]:      16338 :   if (n.getKind() == Kind::OR || n.getKind() == Kind::AND)
                 [ +  + ]
     199                 :            :   {
     200         [ +  + ]:       3425 :     if ((n.getKind() == Kind::OR) == pol)
     201                 :            :     {
     202         [ +  + ]:      11354 :       for( unsigned i=0; i<n.getNumChildren(); i++) {
     203                 :       8843 :         process( q, n[i], pol, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term, bound_fixed_set );
     204                 :            :       }
     205                 :            :     }
     206                 :            :     else
     207                 :            :     {
     208                 :            :       //if we are ( x != t1 ^ ...^ x != tn ), then x can be bound to { t1...tn }
     209                 :        914 :       Node conj = n;
     210         [ -  + ]:        914 :       if( !pol ){
     211                 :          0 :         conj = TermUtil::simpleNegate( conj );
     212                 :            :       }
     213         [ +  - ]:        914 :       Trace("bound-int-debug") << "Process possible finite disequality conjunction : " << conj << std::endl;
     214 [ -  + ][ -  + ]:        914 :       Assert(conj.getKind() == Kind::AND);
                 [ -  - ]
     215                 :        914 :       Node v;
     216                 :        914 :       std::vector< Node > v_cases;
     217                 :        914 :       bool success = true;
     218         [ +  + ]:        964 :       for( unsigned i=0; i<conj.getNumChildren(); i++ ){
     219 [ +  + ][ -  - ]:        940 :         if (conj[i].getKind() == Kind::NOT
     220                 :        940 :             && processEqDisjunct(q, conj[i][0], v, v_cases))
     221                 :            :         {
     222                 :            :           //continue
     223                 :            :         }
     224                 :            :         else
     225                 :            :         {
     226 [ +  - ][ -  + ]:        890 :           Trace("bound-int-debug") << "...failed due to " << conj[i] << std::endl;
                 [ -  - ]
     227                 :        890 :           success = false;
     228                 :        890 :           break;
     229                 :            :         }
     230                 :            :       }
     231                 :        914 :       if( success && !isBound( q, v ) ){
     232         [ +  - ]:         10 :         Trace("bound-int-debug") << "Success with variable " << v << std::endl;
     233                 :         10 :         bound_lit_type_map[v] = BOUND_FIXED_SET;
     234                 :         10 :         bound_lit_map[3][v] = n;
     235                 :         10 :         bound_lit_pol_map[3][v] = pol;
     236                 :         10 :         bound_fixed_set[v].clear();
     237                 :         10 :         bound_fixed_set[v].insert( bound_fixed_set[v].end(), v_cases.begin(), v_cases.end() );
     238                 :            :       }
     239                 :        914 :     }
     240                 :            :   }
     241         [ +  + ]:      12913 :   else if (n.getKind() == Kind::EQUAL)
     242                 :            :   {
     243         [ +  + ]:       1618 :     if( !pol ){
     244                 :            :       // non-applied DER on x != t, x can be bound to { t }
     245                 :        746 :       Node v;
     246                 :        746 :       std::vector< Node > v_cases;
     247         [ -  + ]:        746 :       if( processEqDisjunct( q, n, v, v_cases ) ){
     248         [ -  - ]:          0 :         if( !isBound( q, v ) ){
     249                 :          0 :           bound_lit_type_map[v] = BOUND_FIXED_SET;
     250                 :          0 :           bound_lit_map[3][v] = n;
     251                 :          0 :           bound_lit_pol_map[3][v] = pol;
     252                 :          0 :           Assert(v_cases.size() == 1);
     253                 :          0 :           bound_fixed_set[v].clear();
     254                 :          0 :           bound_fixed_set[v].push_back( v_cases[0] );
     255                 :            :         }
     256                 :            :       }
     257                 :        746 :     }
     258                 :            :   }
     259         [ +  + ]:      11295 :   else if (n.getKind() == Kind::NOT)
     260                 :            :   {
     261                 :       4718 :     process( q, n[0], !pol, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term, bound_fixed_set );
     262                 :            :   }
     263         [ +  + ]:       6577 :   else if (n.getKind() == Kind::GEQ)
     264                 :            :   {
     265         [ +  + ]:       5462 :     if( n[0].getType().isInteger() ){
     266                 :       5457 :       std::map< Node, Node > msum;
     267         [ +  - ]:       5457 :       if (ArithMSum::getMonomialSumLit(n, msum))
     268                 :            :       {
     269                 :       5457 :         NodeManager* nm = nodeManager();
     270         [ +  - ]:       5457 :         Trace("bound-int-debug") << "literal (polarity = " << pol << ") " << n << " is monomial sum : " << std::endl;
     271                 :       5457 :         ArithMSum::debugPrintMonomialSum(msum, "bound-int-debug");
     272         [ +  + ]:      16487 :         for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
     273         [ +  + ]:      19939 :           if (!it->first.isNull() && it->first.getKind() == Kind::BOUND_VARIABLE
     274                 :      30969 :               && !isBound(q, it->first))
     275                 :            :           {
     276                 :            :             //if not bound in another way
     277 [ +  + ][ +  + ]:       2797 :             if( bound_lit_type_map.find( it->first )==bound_lit_type_map.end() || bound_lit_type_map[it->first] == BOUND_INT_RANGE ){
                 [ +  + ]
     278                 :       2762 :               Node veq;
     279         [ +  - ]:       2762 :               if (ArithMSum::isolate(it->first, msum, veq, Kind::GEQ) != 0)
     280                 :            :               {
     281                 :       2762 :                 Node n1 = veq[0];
     282                 :       2762 :                 Node n2 = veq[1];
     283         [ +  + ]:       2762 :                 if(pol){
     284                 :            :                   //flip
     285                 :       1219 :                   n1 = veq[1];
     286                 :       1219 :                   n2 = veq[0];
     287         [ +  + ]:       1219 :                   if (n1.getKind() == Kind::BOUND_VARIABLE)
     288                 :            :                   {
     289                 :          2 :                     n2 = nm->mkNode(Kind::ADD, n2, nm->mkConstInt(Rational(1)));
     290                 :            :                   }
     291                 :            :                   else
     292                 :            :                   {
     293                 :            :                     n1 =
     294                 :       1217 :                         nm->mkNode(Kind::ADD, n1, nm->mkConstInt(Rational(-1)));
     295                 :            :                   }
     296                 :       1219 :                   veq = nm->mkNode(Kind::GEQ, n1, n2);
     297                 :            :                 }
     298         [ +  - ]:       2762 :                 Trace("bound-int-debug") << "Isolated for " << it->first << " : (" << n1 << " >= " << n2 << ")" << std::endl;
     299         [ +  + ]:       2762 :                 Node t = n1==it->first ? n2 : n1;
     300         [ +  + ]:       2762 :                 if( !hasNonBoundVar( q, t ) ) {
     301         [ +  - ]:       2524 :                   Trace("bound-int-debug") << "The bound is relevant." << std::endl;
     302         [ +  + ]:       2524 :                   int loru = n1==it->first ? 0 : 1;
     303                 :       2524 :                   bound_lit_type_map[it->first] = BOUND_INT_RANGE;
     304                 :       2524 :                   bound_int_range_term[loru][it->first] = t;
     305                 :       2524 :                   bound_lit_map[loru][it->first] = n;
     306                 :       2524 :                   bound_lit_pol_map[loru][it->first] = pol;
     307                 :            :                 }else{
     308         [ +  - ]:        238 :                   Trace("bound-int-debug") << "The term " << t << " has non-bound variable." << std::endl;
     309                 :            :                 }
     310                 :       2762 :               }
     311                 :       2762 :             }
     312                 :            :           }
     313                 :            :         }
     314                 :            :       }
     315                 :       5457 :     }
     316                 :            :   }
     317         [ +  + ]:       1115 :   else if (n.getKind() == Kind::SET_MEMBER)
     318                 :            :   {
     319                 :            :     // Note this is incomplete when combined with cardinality constraints,
     320                 :            :     // since we may introduce slack elements during model construction.
     321                 :            :     // Here, fmfBound should be enabled, otherwise the incompleteness check
     322                 :            :     // in the theory of sets is out of sync.
     323 [ -  + ][ -  + ]:        235 :     Assert(options().quantifiers.fmfBound);
                 [ -  - ]
     324                 :        235 :     if( !pol && !hasNonBoundVar( q, n[1] ) ){
     325                 :        228 :       std::vector< Node > bound_vars;
     326                 :        228 :       std::map< Node, bool > visited;
     327                 :        228 :       processMatchBoundVars( q, n[0], bound_vars, visited );
     328         [ +  + ]:        353 :       for( unsigned i=0; i<bound_vars.size(); i++ ){
     329                 :        125 :         Node v = bound_vars[i];
     330         [ +  - ]:        125 :         Trace("bound-int-debug") << "literal (polarity = " << pol << ") " << n << " is membership." << std::endl;
     331                 :        125 :         bound_lit_type_map[v] = BOUND_SET_MEMBER;
     332                 :        125 :         bound_lit_map[2][v] = n;
     333                 :        125 :         bound_lit_pol_map[2][v] = pol;
     334                 :        125 :       }
     335                 :        228 :     }
     336                 :            :   }
     337                 :            :   else
     338                 :            :   {
     339 [ +  - ][ +  - ]:        880 :     Assert(n.getKind() != Kind::LEQ && n.getKind() != Kind::LT
         [ +  - ][ +  - ]
         [ -  + ][ -  + ]
                 [ -  - ]
     340                 :            :            && n.getKind() != Kind::GT);
     341                 :            :   }
     342                 :      16338 : }
     343                 :            : 
     344                 :      80342 : bool BoundedIntegers::needsCheck( Theory::Effort e ) {
     345                 :      80342 :   return e==Theory::EFFORT_LAST_CALL;
     346                 :            : }
     347                 :            : 
     348                 :      28337 : void BoundedIntegers::check(CVC5_UNUSED Theory::Effort e, QEffort quant_e)
     349                 :            : {
     350         [ +  + ]:      28337 :   if (quant_e != QEFFORT_STANDARD)
     351                 :            :   {
     352                 :      18544 :     return;
     353                 :            :   }
     354         [ +  - ]:       9793 :   Trace("bint-engine") << "---Bounded Integers---" << std::endl;
     355                 :       9793 :   bool addedLemma = false;
     356                 :            :   // make sure proxies are up-to-date with range
     357         [ +  + ]:      12743 :   for (const Node& r : d_ranges)
     358                 :            :   {
     359                 :       2950 :     Node prangeLem = d_rms[r]->proxyCurrentRangeLemma();
     360         [ +  + ]:       2950 :     if (!prangeLem.isNull())
     361                 :            :     {
     362         [ +  - ]:        434 :       Trace("bound-int-lemma")
     363                 :        217 :           << "*** bound int : proxy lemma : " << prangeLem << std::endl;
     364                 :        217 :       d_qim.addPendingLemma(prangeLem, InferenceId::QUANTIFIERS_BINT_PROXY);
     365                 :        217 :       addedLemma = true;
     366                 :            :     }
     367                 :       2950 :   }
     368         [ +  - ]:       9793 :   Trace("bint-engine") << "   addedLemma = " << addedLemma << std::endl;
     369                 :            : }
     370                 :       1471 : void BoundedIntegers::setBoundedVar(Node q, Node v, BoundVarType bound_type)
     371                 :            : {
     372                 :       1471 :   d_bound_type[q][v] = bound_type;
     373                 :       1471 :   d_set_nums[q][v] = d_set[q].size();
     374                 :       1471 :   d_set[q].push_back( v );
     375         [ +  - ]:       2942 :   Trace("bound-int-var") << "Bound variable #" << d_set_nums[q][v] << " : " << v
     376                 :       1471 :                          << std::endl;
     377                 :       1471 : }
     378                 :            : 
     379                 :      25356 : void BoundedIntegers::checkOwnership(Node f)
     380                 :            : {
     381                 :            :   //this needs to be done at preregister since it affects e.g. QuantDSplit's preregister
     382         [ +  - ]:      25356 :   Trace("bound-int") << "check ownership quantifier " << f << std::endl;
     383                 :            : 
     384                 :            :   // determine if we should look at the quantified formula at all
     385         [ +  + ]:      25356 :   if (!options().quantifiers.fmfBound)
     386                 :            :   {
     387                 :            :     // only applying it to internal quantifiers
     388                 :      24935 :     QuantAttributes& qattr = d_qreg.getQuantAttributes();
     389         [ +  + ]:      24935 :     if (!qattr.isQuantBounded(f))
     390                 :            :     {
     391         [ +  - ]:      24025 :       Trace("bound-int") << "...not bounded, skip" << std::endl;
     392                 :      24025 :       return;
     393                 :            :     }
     394                 :            :   }
     395                 :            : 
     396                 :       1331 :   NodeManager* nm = nodeManager();
     397                 :            : 
     398                 :            :   bool success;
     399         [ +  + ]:       2777 :   do{
     400                 :       2777 :     std::map< Node, unsigned > bound_lit_type_map;
     401                 :       2777 :     std::map< int, std::map< Node, Node > > bound_lit_map;
     402                 :       2777 :     std::map< int, std::map< Node, bool > > bound_lit_pol_map;
     403                 :       2777 :     std::map< int, std::map< Node, Node > > bound_int_range_term;
     404                 :       2777 :     std::map< Node, std::vector< Node > > bound_fixed_set;
     405                 :       2777 :     success = false;
     406                 :       2777 :     process( f, f[1], true, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term, bound_fixed_set );
     407                 :            :     //for( std::map< Node, Node >::iterator it = d_bounds[0][f].begin(); it != d_bounds[0][f].end(); ++it ){
     408         [ +  + ]:       4184 :     for( std::map< Node, unsigned >::iterator it = bound_lit_type_map.begin(); it != bound_lit_type_map.end(); ++it ){
     409                 :       1407 :       Node v = it->first;
     410         [ +  - ]:       1407 :       if( !isBound( f, v ) ){
     411                 :       1407 :         bool setBoundVar = false;
     412         [ +  + ]:       1407 :         if( it->second==BOUND_INT_RANGE ){
     413                 :            :           //must have both
     414                 :       1284 :           std::map<Node, Node>& blm0 = bound_lit_map[0];
     415                 :       1284 :           std::map<Node, Node>& blm1 = bound_lit_map[1];
     416 [ +  + ][ +  + ]:       1284 :           if (blm0.find(v) != blm0.end() && blm1.find(v) != blm1.end())
                 [ +  + ]
     417                 :            :           {
     418                 :       1157 :             setBoundedVar( f, v, BOUND_INT_RANGE );
     419                 :       1157 :             setBoundVar = true;
     420         [ +  + ]:       3471 :             for( unsigned b=0; b<2; b++ ){
     421                 :            :               //set the bounds
     422 [ -  + ][ -  + ]:       2314 :               Assert(bound_int_range_term[b].find(v)
                 [ -  - ]
     423                 :            :                      != bound_int_range_term[b].end());
     424                 :       2314 :               d_bounds[b][f][v] = bound_int_range_term[b][v];
     425                 :            :             }
     426                 :            :             Node r =
     427                 :       2314 :                 nm->mkNode(Kind::SUB, d_bounds[1][f][v], d_bounds[0][f][v]);
     428                 :       1157 :             d_range[f][v] = rewrite(r);
     429         [ +  - ]:       1157 :             Trace("bound-int") << "Variable " << v << " is bound because of int range literals " << bound_lit_map[0][v] << " and " << bound_lit_map[1][v] << std::endl;
     430                 :       1157 :           }
     431         [ +  + ]:        123 :         }else if( it->second==BOUND_SET_MEMBER ){
     432                 :        113 :           setBoundedVar(f, v, BOUND_SET_MEMBER);
     433                 :        113 :           setBoundVar = true;
     434                 :        113 :           d_setm_range[f][v] = bound_lit_map[2][v][1];
     435                 :        113 :           d_setm_range_lit[f][v] = bound_lit_map[2][v];
     436                 :        113 :           Node cardTerm = nm->mkNode(Kind::SET_CARD, d_setm_range[f][v]);
     437                 :            :           // Note that we avoid reasoning about cardinality by eagerly
     438                 :            :           // eliminating set.card for literals as they are introduced.
     439                 :        113 :           d_range[f][v] = cardTerm;
     440         [ +  - ]:        226 :           Trace("bound-int") << "Variable " << v
     441                 :          0 :                              << " is bound because of set membership literal "
     442                 :        113 :                              << bound_lit_map[2][v] << std::endl;
     443         [ +  - ]:        123 :         }else if( it->second==BOUND_FIXED_SET ){
     444                 :         10 :           setBoundedVar(f, v, BOUND_FIXED_SET);
     445                 :         10 :           setBoundVar = true;
     446         [ +  + ]:         30 :           for (unsigned i = 0; i < bound_fixed_set[v].size(); i++)
     447                 :            :           {
     448                 :         20 :             Node t = bound_fixed_set[v][i];
     449         [ +  + ]:         20 :             if (expr::hasBoundVar(t))
     450                 :            :             {
     451                 :          6 :               d_fixed_set_ngr_range[f][v].push_back(t);
     452                 :            :             }
     453                 :            :             else
     454                 :            :             {
     455                 :         14 :               d_fixed_set_gr_range[f][v].push_back(t);
     456                 :            :             }
     457                 :         20 :           }
     458         [ +  - ]:         20 :           Trace("bound-int") << "Variable " << v
     459                 :          0 :                              << " is bound because of disequality conjunction "
     460                 :         10 :                              << bound_lit_map[3][v] << std::endl;
     461                 :            :         }
     462         [ +  + ]:       1407 :         if( setBoundVar ){
     463                 :       1280 :           success = true;
     464                 :            :           //set Attributes on literals
     465         [ +  + ]:       3840 :           for( unsigned b=0; b<2; b++ ){
     466                 :       2560 :             std::map<Node, Node>& blm = bound_lit_map[b];
     467         [ +  + ]:       2560 :             if (blm.find(v) != blm.end())
     468                 :            :             {
     469                 :       2321 :               std::map<Node, bool>& blmp = bound_lit_pol_map[b];
     470                 :            :               // WARNING_CANDIDATE:
     471                 :            :               // This assertion may fail. We intentionally do not enable this in
     472                 :            :               // production as it is considered safe for this to fail. We fail
     473                 :            :               // the assertion in debug mode to have this instance raised to
     474                 :            :               // our attention.
     475 [ -  + ][ -  + ]:       2321 :               Assert(blmp.find(v) != blmp.end());
                 [ -  - ]
     476                 :            :               BoundIntLitAttribute bila;
     477         [ +  + ]:       2321 :               bound_lit_map[b][v].setAttribute(bila, blmp[v] ? 1 : 0);
     478                 :            :             }
     479                 :            :             else
     480                 :            :             {
     481 [ -  + ][ -  + ]:        239 :               Assert(it->second != BOUND_INT_RANGE);
                 [ -  - ]
     482                 :            :             }
     483                 :            :           }
     484                 :            :         }
     485                 :            :       }
     486                 :       1407 :     }
     487         [ +  + ]:       2777 :     if( !success ){
     488                 :            :       //resort to setting a finite bound on a variable
     489         [ +  + ]:       3130 :       for( unsigned i=0; i<f[0].getNumChildren(); i++) {
     490         [ +  + ]:       1799 :         if( d_bound_type[f].find( f[0][i] )==d_bound_type[f].end() ){
     491                 :        566 :           TypeNode tn = f[0][i].getType();
     492 [ +  + ][ +  + ]:        332 :           if ((tn.isUninterpretedSort() && d_env.isFiniteType(tn))
                 [ -  - ]
     493 [ +  + ][ +  + ]:        332 :               || d_qreg.getQuantifiersBoundInference().mayComplete(tn))
         [ +  + ][ +  + ]
                 [ -  - ]
     494                 :            :           {
     495                 :        191 :             success = true;
     496                 :        191 :             setBoundedVar( f, f[0][i], BOUND_FINITE );
     497                 :        191 :             break;
     498                 :            :           }
     499         [ +  + ]:        283 :         }
     500                 :            :       }
     501                 :            :     }
     502                 :       2777 :   }while( success );
     503                 :            :   
     504         [ -  + ]:       1331 :   if( TraceIsOn("bound-int") ){
     505         [ -  - ]:          0 :     Trace("bound-int") << "Bounds are : " << std::endl;
     506         [ -  - ]:          0 :     for( unsigned i=0; i<f[0].getNumChildren(); i++) {
     507                 :          0 :       Node v = f[0][i];
     508         [ -  - ]:          0 :       if( std::find( d_set[f].begin(), d_set[f].end(), v )!=d_set[f].end() ){
     509                 :          0 :         Assert(d_bound_type[f].find(v) != d_bound_type[f].end());
     510         [ -  - ]:          0 :         if( d_bound_type[f][v]==BOUND_INT_RANGE ){
     511         [ -  - ]:          0 :           Trace("bound-int") << "  " << d_bounds[0][f][v] << " <= " << v << " <= " << d_bounds[1][f][v] << " (range is " << d_range[f][v] << ")" << std::endl;
     512         [ -  - ]:          0 :         }else if( d_bound_type[f][v]==BOUND_SET_MEMBER ){
     513         [ -  - ]:          0 :           if( d_setm_range_lit[f][v][0]==v ){
     514         [ -  - ]:          0 :             Trace("bound-int") << "  " << v << " in " << d_setm_range[f][v] << std::endl;
     515                 :            :           }else{
     516         [ -  - ]:          0 :             Trace("bound-int") << "  " << v << " unifiable in " << d_setm_range_lit[f][v] << std::endl;
     517                 :            :           }
     518         [ -  - ]:          0 :         }else if( d_bound_type[f][v]==BOUND_FIXED_SET ){
     519         [ -  - ]:          0 :           Trace("bound-int") << "  " << v << " in { ";
     520         [ -  - ]:          0 :           for (TNode fnr : d_fixed_set_ngr_range[f][v])
     521                 :            :           {
     522         [ -  - ]:          0 :             Trace("bound-int") << fnr << " ";
     523                 :          0 :           }
     524         [ -  - ]:          0 :           for (TNode fgr : d_fixed_set_gr_range[f][v])
     525                 :            :           {
     526         [ -  - ]:          0 :             Trace("bound-int") << fgr << " ";
     527                 :          0 :           }
     528         [ -  - ]:          0 :           Trace("bound-int") << "}" << std::endl;
     529         [ -  - ]:          0 :         }else if( d_bound_type[f][v]==BOUND_FINITE ){
     530         [ -  - ]:          0 :           Trace("bound-int") << "  " << v << " has small finite type." << std::endl;
     531                 :            :         }else{
     532         [ -  - ]:          0 :           Trace("bound-int") << "  " << v << " has unknown bound." << std::endl;
     533                 :          0 :           DebugUnhandled();
     534                 :            :         }
     535                 :            :       }else{
     536         [ -  - ]:          0 :         Trace("bound-int") << "  " << "*** " << v << " is unbounded." << std::endl;
     537                 :            :       }
     538                 :          0 :     }
     539                 :            :   }
     540                 :            :   
     541                 :       1331 :   bool bound_success = true;
     542         [ +  + ]:       2800 :   for( unsigned i=0; i<f[0].getNumChildren(); i++) {
     543         [ +  + ]:       1537 :     if( d_bound_type[f].find( f[0][i] )==d_bound_type[f].end() ){
     544                 :         68 :       Trace("bound-int-warn") << "Warning : Bounded Integers : Due to quantification on " << f[0][i] << ", could not find bounds for " << f << std::endl;
     545                 :         68 :       bound_success = false;
     546                 :         68 :       break;
     547                 :            :     }
     548                 :            :   }
     549                 :            :   
     550         [ +  + ]:       1331 :   if( bound_success ){
     551                 :       1263 :     d_bound_quants.push_back( f );
     552                 :       1263 :     DecisionManager* dm = d_qim.getDecisionManager();
     553         [ +  + ]:       2729 :     for( unsigned i=0; i<d_set[f].size(); i++) {
     554                 :       1466 :       Node v = d_set[f][i];
     555                 :       1466 :       std::map< Node, Node >::iterator itr = d_range[f].find( v );
     556         [ +  + ]:       1466 :       if( itr != d_range[f].end() ){
     557                 :       1268 :         Node r = itr->second;
     558 [ -  + ][ -  + ]:       1268 :         Assert(!r.isNull());
                 [ -  - ]
     559                 :       1268 :         bool isProxy = false;
     560         [ +  + ]:       1268 :         if (expr::hasBoundVar(r))
     561                 :            :         {
     562                 :            :           // introduce a new bound
     563                 :        254 :           Node new_range = NodeManager::mkDummySkolem("bir", r.getType());
     564                 :        127 :           d_nground_range[f][v] = r;
     565                 :        127 :           d_range[f][v] = new_range;
     566                 :        127 :           r = new_range;
     567                 :        127 :           isProxy = true;
     568                 :        127 :         }
     569         [ +  + ]:       1268 :         if( !r.isConst() ){
     570         [ +  + ]:       1211 :           if (d_rms.find(r) == d_rms.end())
     571                 :            :           {
     572         [ +  - ]:       1107 :             Trace("bound-int") << "For " << v << ", bounded Integer Module will try to minimize : " << r << std::endl;
     573                 :       1107 :             d_ranges.push_back( r );
     574                 :       2214 :             d_rms[r].reset(new IntRangeDecisionHeuristic(
     575                 :       1107 :                 d_env, r, d_qstate.getValuation(), isProxy));
     576                 :       1107 :             dm->registerStrategy(DecisionManager::STRAT_QUANT_BOUND_INT_SIZE,
     577                 :       1107 :                                  d_rms[r].get());
     578                 :            :           }
     579                 :            :         }
     580                 :       1268 :       }
     581                 :       1466 :     }
     582                 :            :   }
     583                 :            : }
     584                 :            : 
     585                 :      16219 : bool BoundedIntegers::isBound(Node q, Node v) const
     586                 :            : {
     587                 :      16219 :   std::map<Node, std::vector<Node> >::const_iterator its = d_set.find(q);
     588         [ +  + ]:      16219 :   if (its == d_set.end())
     589                 :            :   {
     590                 :      10732 :     return false;
     591                 :            :   }
     592                 :       5487 :   return std::find(its->second.begin(), its->second.end(), v)
     593                 :      10974 :          != its->second.end();
     594                 :            : }
     595                 :            : 
     596                 :      10095 : BoundVarType BoundedIntegers::getBoundVarType(Node q, Node v) const
     597                 :            : {
     598                 :            :   std::map<Node, std::map<Node, BoundVarType> >::const_iterator itb =
     599                 :      10095 :       d_bound_type.find(q);
     600         [ +  + ]:      10095 :   if (itb == d_bound_type.end())
     601                 :            :   {
     602                 :       1852 :     return BOUND_NONE;
     603                 :            :   }
     604                 :       8243 :   std::map<Node, BoundVarType>::const_iterator it = itb->second.find(v);
     605         [ +  + ]:       8243 :   if (it == itb->second.end())
     606                 :            :   {
     607                 :        346 :     return BOUND_NONE;
     608                 :            :   }
     609                 :       7897 :   return it->second;
     610                 :            : }
     611                 :            : 
     612                 :       8713 : void BoundedIntegers::getBoundVarIndices(Node q,
     613                 :            :                                          std::vector<size_t>& indices) const
     614                 :            : {
     615                 :       8713 :   std::map<Node, std::vector<Node> >::const_iterator it = d_set.find(q);
     616         [ +  + ]:       8713 :   if (it != d_set.end())
     617                 :            :   {
     618         [ +  + ]:      11632 :     for (const Node& v : it->second)
     619                 :            :     {
     620                 :       6619 :       indices.push_back(TermUtil::getVariableNum(q, v));
     621                 :            :     }
     622                 :            :   }
     623                 :       8713 : }
     624                 :            : 
     625                 :       5155 : void BoundedIntegers::getBounds( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u ) {
     626                 :       5155 :   l = d_bounds[0][f][v];
     627                 :       5155 :   u = d_bounds[1][f][v];
     628         [ +  + ]:       5155 :   if( d_nground_range[f].find(v)!=d_nground_range[f].end() ){
     629                 :            :     //get the substitution
     630                 :       1427 :     std::vector< Node > vars;
     631                 :       1427 :     std::vector< Node > subs;
     632         [ +  + ]:       1427 :     if( getRsiSubsitution( f, v, vars, subs, rsi ) ){
     633                 :       1346 :       u = u.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
     634                 :       1346 :       l = l.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
     635                 :            :     }else{
     636                 :         81 :       u = Node::null();
     637                 :         81 :       l = Node::null();
     638                 :            :     }
     639                 :       1427 :   }
     640                 :       5155 : }
     641                 :            : 
     642                 :       2618 : void BoundedIntegers::getBoundValues( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u ) {
     643                 :       2618 :   getBounds( f, v, rsi, l, u );
     644         [ +  - ]:       2618 :   Trace("bound-int-rsi") << "Get value in model for..." << l << " and " << u << std::endl;
     645         [ +  + ]:       2618 :   if( !l.isNull() ){
     646                 :       2537 :     l = d_treg.getModel()->getValue(l);
     647                 :            :   }
     648         [ +  + ]:       2618 :   if( !u.isNull() ){
     649                 :       2537 :     u = d_treg.getModel()->getValue(u);
     650                 :            :   }
     651         [ +  - ]:       2618 :   Trace("bound-int-rsi") << "Value is " << l << " ... " << u << std::endl;
     652                 :       2618 :   return;
     653                 :            : }
     654                 :            : 
     655                 :        834 : bool BoundedIntegers::isGroundRange(Node q, Node v)
     656                 :            : {
     657         [ +  - ]:        834 :   if (isBound(q, v))
     658                 :            :   {
     659         [ +  + ]:        834 :     if (d_bound_type[q][v] == BOUND_INT_RANGE)
     660                 :            :     {
     661                 :       1300 :       return !expr::hasBoundVar(getLowerBound(q, v))
     662                 :       1300 :              && !expr::hasBoundVar(getUpperBound(q, v));
     663                 :            :     }
     664         [ +  + ]:        184 :     else if (d_bound_type[q][v] == BOUND_SET_MEMBER)
     665                 :            :     {
     666                 :         52 :       return !expr::hasBoundVar(d_setm_range[q][v]);
     667                 :            :     }
     668         [ +  - ]:        132 :     else if (d_bound_type[q][v] == BOUND_FIXED_SET)
     669                 :            :     {
     670                 :        132 :       return !d_fixed_set_ngr_range[q][v].empty();
     671                 :            :     }
     672                 :            :   }
     673                 :          0 :   return false;
     674                 :            : }
     675                 :            : 
     676                 :        239 : Node BoundedIntegers::getSetRange( Node q, Node v, RepSetIterator * rsi ) {
     677                 :        239 :   Node sr = d_setm_range[q][v];
     678         [ +  + ]:        239 :   if( d_nground_range[q].find(v)!=d_nground_range[q].end() ){
     679         [ +  - ]:         28 :     Trace("bound-int-rsi-debug")
     680                 :         14 :         << sr << " is non-ground, apply substitution..." << std::endl;
     681                 :            :     //get the substitution
     682                 :         14 :     std::vector< Node > vars;
     683                 :         14 :     std::vector< Node > subs;
     684         [ +  + ]:         14 :     if( getRsiSubsitution( q, v, vars, subs, rsi ) ){
     685         [ +  - ]:         14 :       Trace("bound-int-rsi-debug")
     686                 :          7 :           << "  apply " << vars << " -> " << subs << std::endl;
     687                 :          7 :       sr = sr.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
     688                 :            :     }else{
     689                 :          7 :       sr = Node::null();
     690                 :            :     }
     691                 :         14 :   }
     692                 :        239 :   return sr;
     693                 :          0 : }
     694                 :            : 
     695                 :        239 : Node BoundedIntegers::getSetRangeValue( Node q, Node v, RepSetIterator * rsi ) {
     696                 :        478 :   Node sr = getSetRange( q, v, rsi );
     697         [ +  + ]:        239 :   if (sr.isNull())
     698                 :            :   {
     699                 :          7 :     return sr;
     700                 :            :   }
     701         [ +  - ]:        232 :   Trace("bound-int-rsi") << "Get value in model for..." << sr << std::endl;
     702 [ -  + ][ -  + ]:        232 :   Assert(!expr::hasFreeVar(sr));
                 [ -  - ]
     703                 :        232 :   Node sro = sr;
     704                 :        232 :   sr = d_treg.getModel()->getValue(sr);
     705                 :            :   // if non-constant, then sr does not occur in the model, we fail
     706         [ -  + ]:        232 :   if (!sr.isConst())
     707                 :            :   {
     708                 :          0 :     return Node::null();
     709                 :            :   }
     710         [ +  - ]:        232 :   Trace("bound-int-rsi") << "Value is " << sr << std::endl;
     711         [ +  + ]:        232 :   if (sr.getKind() == Kind::SET_EMPTY)
     712                 :            :   {
     713                 :          4 :     return sr;
     714                 :            :   }
     715                 :            :   // we can use choice functions for canonical symbolic instantiations
     716                 :        228 :   unsigned srCard = 0;
     717         [ +  + ]:        445 :   while (sr.getKind() == Kind::SET_UNION)
     718                 :            :   {
     719 [ -  + ][ -  + ]:        217 :     Assert(sr[0].getKind() == Kind::SET_SINGLETON);
                 [ -  - ]
     720                 :        217 :     srCard++;
     721                 :        217 :     sr = sr[1];
     722                 :            :   }
     723 [ -  + ][ -  + ]:        228 :   Assert(sr.getKind() == Kind::SET_SINGLETON);
                 [ -  - ]
     724                 :        228 :   srCard++;
     725         [ +  - ]:        228 :   Trace("bound-int-rsi") << "...cardinality is " << srCard << std::endl;
     726                 :            :   // get the characteristic set
     727                 :        228 :   Node nsr = sets::NormalForm::getCharacteristicSet(nodeManager(), sro, srCard);
     728                 :            :   // turns the concrete set value of sro into a canonical representation
     729                 :            :   //   e.g.
     730                 :            :   // singleton(0) union singleton(1)
     731                 :            :   //   becomes
     732                 :            :   // C1 union (set.singleton (set.choose (set.minus S C1)))
     733                 :            :   // where C1 = (set.singleton (set.choose S)).
     734         [ +  - ]:        228 :   Trace("bound-int-rsi") << "...reconstructed " << nsr << std::endl;
     735                 :        228 :   return nsr;
     736                 :        239 : }
     737                 :            : 
     738                 :       1493 : bool BoundedIntegers::getRsiSubsitution( Node q, Node v, std::vector< Node >& vars, std::vector< Node >& subs, RepSetIterator * rsi ) {
     739                 :            : 
     740         [ +  - ]:       1493 :   Trace("bound-int-rsi") << "Get bound value in model of variable " << v << std::endl;
     741 [ -  + ][ -  + ]:       1493 :   Assert(d_set_nums[q].find(v) != d_set_nums[q].end());
                 [ -  - ]
     742                 :       1493 :   int vindex = d_set_nums[q][v];
     743 [ -  + ][ -  + ]:       1493 :   Assert(d_set_nums[q][v] == vindex);
                 [ -  - ]
     744         [ +  - ]:       1493 :   Trace("bound-int-rsi-debug") << "  index order is " << vindex << std::endl;
     745                 :            :   //must take substitution for all variables that are iterating at higher level
     746         [ +  + ]:       3266 :   for( int i=0; i<vindex; i++) {
     747 [ -  + ][ -  + ]:       1773 :     Assert(d_set_nums[q][d_set[q][i]] == i);
                 [ -  - ]
     748         [ +  - ]:       1773 :     Trace("bound-int-rsi") << "Look up the value for " << d_set[q][i] << " " << i << std::endl;
     749                 :       1773 :     int vo = rsi->getVariableOrder(i);
     750 [ -  + ][ -  + ]:       1773 :     Assert(q[0][vo] == d_set[q][i]);
                 [ -  - ]
     751                 :       1773 :     TypeNode tn = d_set[q][i].getType();
     752                 :            :     // If the type of tn is not closed enumerable, we must map the value back
     753                 :            :     // to a term that appears in the same equivalence class as the constant.
     754                 :            :     // Notice that this is to ensure that unhandled values (e.g. uninterpreted
     755                 :            :     // constants, datatype values) do not enter instantiations/lemmas, which
     756                 :            :     // can lead to refutation unsoundness. However, it is important that we
     757                 :            :     // conversely do *not* map terms to values in other cases. In particular,
     758                 :            :     // replacing a constant c with a term t can lead to solution unsoundness
     759                 :            :     // if we are instantiating a quantified formula that corresponds to a
     760                 :            :     // reduction for t, since then the reduction is using circular reasoning:
     761                 :            :     // the current value of t is being used to reason about the range of
     762                 :            :     // its axiomatization. This is limited to reductions in the theory of
     763                 :            :     // strings, which use quantification on integers only. Note this
     764                 :            :     // impacts only quantified formulas with 2+ dimensions and dependencies
     765                 :            :     // between dimensions, e.g. str.indexof_re reduction.
     766                 :       1773 :     Node t = rsi->getCurrentTerm(vo, !tn.isClosedEnumerable());
     767         [ +  - ]:       1773 :     Trace("bound-int-rsi") << "term : " << t << std::endl;
     768                 :       1773 :     vars.push_back( d_set[q][i] );
     769                 :       1773 :     subs.push_back( t );
     770                 :       1773 :   }
     771                 :            :   
     772                 :            :   //check if it has been instantiated
     773 [ +  - ][ +  + ]:       1493 :   if( !vars.empty() && !d_bnd_it[q][v].hasInstantiated(subs) ){
                 [ +  + ]
     774 [ +  + ][ +  + ]:         96 :     if( d_bound_type[q][v]==BOUND_INT_RANGE || d_bound_type[q][v]==BOUND_SET_MEMBER ){
                 [ +  + ]
     775                 :            :       //must add the lemma
     776                 :         88 :       Node nn = d_nground_range[q][v];
     777                 :         88 :       nn = nn.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
     778                 :        176 :       Node lem = nodeManager()->mkNode(Kind::LEQ, nn, d_range[q][v]);
     779         [ +  - ]:         88 :       Trace("bound-int-lemma") << "*** Add lemma to minimize instantiated non-ground term " << lem << std::endl;
     780                 :         88 :       d_qim.lemma(lem, InferenceId::QUANTIFIERS_BINT_MIN_NG);
     781                 :         88 :     }
     782                 :         96 :     return false;
     783                 :            :   }else{
     784                 :       1397 :     return true;
     785                 :            :   }
     786                 :            : }
     787                 :            : 
     788                 :        680 : Node BoundedIntegers::matchBoundVar( Node v, Node t, Node e ){
     789         [ +  + ]:        680 :   if( t==v ){
     790                 :        302 :     return e;
     791                 :            :   }
     792         [ +  + ]:        378 :   else if (t.getKind() == Kind::APPLY_CONSTRUCTOR)
     793                 :            :   {
     794         [ -  + ]:        302 :     if (e.getKind() == Kind::APPLY_CONSTRUCTOR)
     795                 :            :     {
     796         [ -  - ]:          0 :       if( t.getOperator() != e.getOperator() ) {
     797                 :          0 :         return Node::null();
     798                 :            :       }
     799                 :            :     }
     800                 :        302 :     const DType& dt = datatypes::utils::datatypeOf(t.getOperator());
     801                 :        302 :     unsigned index = datatypes::utils::indexOf(t.getOperator());
     802                 :        302 :     bool sharedSel = options().datatypes.dtSharedSelectors;
     803         [ +  - ]:        378 :     for( unsigned i=0; i<t.getNumChildren(); i++ ){
     804                 :        378 :       Node u;
     805         [ -  + ]:        378 :       if (e.getKind() == Kind::APPLY_CONSTRUCTOR)
     806                 :            :       {
     807                 :          0 :         u = matchBoundVar( v, t[i], e[i] );
     808                 :            :       }
     809                 :            :       else
     810                 :            :       {
     811                 :        378 :         Node se = datatypes::utils::applySelector(dt[index], i, sharedSel, e);
     812                 :        378 :         u = matchBoundVar( v, t[i], se );
     813                 :        378 :       }
     814         [ +  + ]:        378 :       if( !u.isNull() ){
     815                 :        302 :         return u;
     816                 :            :       }
     817         [ +  + ]:        378 :     }
     818                 :            :   }
     819                 :         76 :   return Node::null();
     820                 :            : }
     821                 :            : 
     822                 :       3429 : bool BoundedIntegers::getBoundElements( RepSetIterator * rsi, bool initial, Node q, Node v, std::vector< Node >& elements ) {
     823                 :       3429 :   if( initial || !isGroundRange( q, v ) ){
     824                 :       3119 :     elements.clear();
     825                 :       3119 :     BoundVarType bvt = getBoundVarType(q, v);
     826         [ +  + ]:       3119 :     if( bvt==BOUND_INT_RANGE ){
     827                 :       2618 :       Node l, u;
     828                 :       2618 :       getBoundValues( q, v, rsi, l, u );
     829 [ +  + ][ -  + ]:       2618 :       if( l.isNull() || u.isNull() ){
                 [ +  + ]
     830         [ +  - ]:         81 :         Trace("bound-int-warn") << "WARNING: Could not find integer bounds in model for " << v << " in " << q << std::endl;
     831                 :            :         //failed, abort the iterator
     832                 :         81 :         return false;
     833                 :            :       }else{
     834                 :       2537 :         NodeManager* nm = nodeManager();
     835         [ +  - ]:       2537 :         Trace("bound-int-rsi") << "Can limit bounds of " << v << " to " << l << "..." << u << std::endl;
     836                 :       5074 :         Node range = rewrite(nm->mkNode(Kind::SUB, u, l));
     837         [ -  + ]:       2537 :         if (!range.isConst())
     838                 :            :         {
     839         [ -  - ]:          0 :           Trace("fmf-incomplete") << "Incomplete because of integer "
     840                 :          0 :                                      "quantification, bounds are unknown for "
     841                 :          0 :                                   << v << "." << std::endl;
     842                 :          0 :           return false;
     843                 :            :         }
     844                 :       2537 :         Rational rat = range.getConst<Rational>();
     845                 :            :         // 9999 is an arbitrary range past which we do not do exhaustive
     846                 :            :         // bounded instantation, based on the check below.
     847                 :       2537 :         Node tl = l;
     848                 :       2537 :         Node tu = u;
     849                 :       2537 :         getBounds( q, v, rsi, tl, tu );
     850 [ +  - ][ +  - ]:       2537 :         Assert(!tl.isNull() && !tu.isNull());
         [ -  + ][ -  + ]
                 [ -  - ]
     851         [ +  - ]:       2537 :         if (rat < Rational(9999))
     852                 :            :         {
     853                 :            :           // if negative, elements are empty
     854         [ +  + ]:       2537 :           if (rat.sgn() >= 0)
     855                 :            :           {
     856                 :       2201 :             long rr = rat.getNumerator().getLong() + 1;
     857         [ +  - ]:       4402 :             Trace("bound-int-rsi")
     858                 :       2201 :                 << "Actual bound range is " << rr << std::endl;
     859         [ +  + ]:      10941 :             for (long k = 0; k < rr; k++)
     860                 :            :             {
     861                 :      17480 :               Node t = nm->mkNode(Kind::ADD, tl, nm->mkConstInt(Rational(k)));
     862                 :       8740 :               t = rewrite(t);
     863                 :       8740 :               elements.push_back(t);
     864                 :       8740 :             }
     865                 :            :           }
     866                 :       2537 :           return true;
     867                 :            :         }else{
     868         [ -  - ]:          0 :           Trace("fmf-incomplete") << "Incomplete because of integer quantification, bounds are too big for " << v << "." << std::endl;
     869                 :          0 :           return false;
     870                 :            :         }
     871                 :       2537 :       }
     872         [ +  + ]:       3119 :     }else if( bvt==BOUND_SET_MEMBER  ){ 
     873                 :        478 :       Node srv = getSetRangeValue( q, v, rsi );
     874         [ +  + ]:        239 :       if( srv.isNull() ){
     875         [ +  - ]:          7 :         Trace("bound-int-warn") << "WARNING: Could not find set bound in model for " << v << " in " << q << std::endl;
     876                 :          7 :         return false;
     877                 :            :       }else{
     878         [ +  - ]:        232 :         Trace("bound-int-rsi") << "Bounded by set membership : " << srv << std::endl;
     879         [ +  + ]:        232 :         if (srv.getKind() != Kind::SET_EMPTY)
     880                 :            :         {
     881                 :            :           //collect the elements
     882         [ +  + ]:        445 :           while (srv.getKind() == Kind::SET_UNION)
     883                 :            :           {
     884 [ -  + ][ -  + ]:        217 :             Assert(srv[1].getKind() == Kind::SET_SINGLETON);
                 [ -  - ]
     885                 :        217 :             elements.push_back( srv[1][0] );
     886                 :        217 :             srv = srv[0];
     887                 :            :           }
     888 [ -  + ][ -  + ]:        228 :           Assert(srv.getKind() == Kind::SET_SINGLETON);
                 [ -  - ]
     889                 :        228 :           elements.push_back( srv[0] );
     890                 :            :           //check if we need to do matching, for literals like ( tuple( v ) in S )
     891                 :        228 :           Node t = d_setm_range_lit[q][v][0];
     892         [ +  + ]:        228 :           if( t!=v ){
     893                 :        157 :             std::vector< Node > elements_tmp;
     894                 :        157 :             elements_tmp.insert( elements_tmp.end(), elements.begin(), elements.end() );
     895                 :        157 :             elements.clear();
     896         [ +  + ]:        459 :             for( unsigned i=0; i<elements_tmp.size(); i++ ){
     897                 :            :               //do matching to determine v -> u
     898                 :        604 :               Node u = matchBoundVar( v, t, elements_tmp[i] );
     899         [ +  - ]:        302 :               Trace("bound-int-rsi-debug") << "  unification : " << elements_tmp[i] << " = " << t << " yields " << v << " -> " << u << std::endl;
     900         [ +  - ]:        302 :               if( !u.isNull() ){
     901                 :        302 :                 elements.push_back( u );
     902                 :            :               }
     903                 :        302 :             }
     904                 :        157 :           }
     905                 :        228 :         }
     906                 :        232 :         return true;
     907                 :            :       }
     908         [ +  + ]:        501 :     }else if( bvt==BOUND_FIXED_SET ){
     909                 :         82 :       std::map< Node, std::vector< Node > >::iterator it = d_fixed_set_gr_range[q].find( v );
     910         [ +  + ]:         82 :       if( it!=d_fixed_set_gr_range[q].end() ){
     911         [ +  + ]:        166 :         for( unsigned i=0; i<it->second.size(); i++ ){
     912                 :        104 :           elements.push_back( it->second[i] );
     913                 :            :         }
     914                 :            :       }
     915                 :         82 :       it = d_fixed_set_ngr_range[q].find( v );
     916         [ +  + ]:         82 :       if( it!=d_fixed_set_ngr_range[q].end() ){
     917                 :         52 :         std::vector< Node > vars;
     918                 :         52 :         std::vector< Node > subs;
     919         [ +  + ]:         52 :         if( getRsiSubsitution( q, v, vars, subs, rsi ) ){
     920         [ +  + ]:         98 :           for( unsigned i=0; i<it->second.size(); i++ ){
     921                 :         54 :             Node t = it->second[i].substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
     922                 :         54 :             elements.push_back( t );
     923                 :         54 :           }
     924                 :         44 :           return true;
     925                 :            :         }else{
     926                 :          8 :           return false;
     927                 :            :         }
     928                 :         52 :       }else{
     929                 :         30 :         return true;
     930                 :            :       }
     931                 :            :     }else{
     932                 :        180 :       return false;
     933                 :            :     }
     934                 :            :   }else{
     935                 :            :     //no change required
     936                 :        310 :     return true;
     937                 :            :   }
     938                 :            : }
     939                 :            : 
     940                 :            : /**
     941                 :            :  * Attribute true for quantifiers that have been internally generated and
     942                 :            :  * should be processed with the bounded integers module, e.g. quantified
     943                 :            :  * formulas from reductions of string operators.
     944                 :            :  *
     945                 :            :  * Currently, this attribute is used for indicating that E-matching should
     946                 :            :  * not be applied, as E-matching should not be applied to quantifiers
     947                 :            :  * generated internally.
     948                 :            :  *
     949                 :            :  * This attribute can potentially be generalized to an identifier indicating
     950                 :            :  * the internal source of the quantified formula (of which strings reduction
     951                 :            :  * is one possibility).
     952                 :            :  */
     953                 :            : struct BoundedQuantAttributeId
     954                 :            : {
     955                 :            : };
     956                 :            : typedef expr::Attribute<BoundedQuantAttributeId, bool> BoundedQuantAttribute;
     957                 :            : /**
     958                 :            :  * Mapping to a dummy node for marking an attribute on internal quantified
     959                 :            :  * formulas. This ensures that reductions are deterministic.
     960                 :            :  */
     961                 :            : struct QInternalVarAttributeId
     962                 :            : {
     963                 :            : };
     964                 :            : typedef expr::Attribute<QInternalVarAttributeId, Node> QInternalVarAttribute;
     965                 :            : 
     966                 :       1314 : Node BoundedIntegers::mkBoundedForall(NodeManager* nm, Node bvl, Node body)
     967                 :            : {
     968                 :            :   QInternalVarAttribute qiva;
     969                 :       1314 :   Node qvar;
     970         [ +  + ]:       1314 :   if (bvl.hasAttribute(qiva))
     971                 :            :   {
     972                 :        406 :     qvar = bvl.getAttribute(qiva);
     973                 :            :   }
     974                 :            :   else
     975                 :            :   {
     976                 :        908 :     qvar = NodeManager::mkDummySkolem("qinternal", nm->booleanType());
     977                 :            :     // this dummy variable marks that the quantified formula is internal
     978                 :        908 :     qvar.setAttribute(BoundedQuantAttribute(), true);
     979                 :            :     // remember the dummy variable
     980                 :        908 :     bvl.setAttribute(qiva, qvar);
     981                 :            :   }
     982                 :            :   // make the internal attribute, and put it in a singleton list
     983                 :       1314 :   Node ip = nm->mkNode(Kind::INST_ATTRIBUTE, qvar);
     984                 :       1314 :   Node ipl = nm->mkNode(Kind::INST_PATTERN_LIST, ip);
     985                 :            :   // make the overall formula
     986                 :       2628 :   return nm->mkNode(Kind::FORALL, bvl, body, ipl);
     987                 :       1314 : }
     988                 :            : 
     989                 :      37462 : bool BoundedIntegers::isBoundedForallAttribute(Node var)
     990                 :            : {
     991                 :      37462 :   return var.getAttribute(BoundedQuantAttribute());
     992                 :            : }
     993                 :            : 
     994                 :            : }  // namespace quantifiers
     995                 :            : }  // namespace theory
     996                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14