LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/arrays - theory_arrays.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 826 1231 67.1 %
Date: 2025-02-13 12:55:09 Functions: 37 48 77.1 %
Branches: 554 1002 55.3 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * Top contributors (to current version):
       3                 :            :  *   Clark Barrett, Andrew Reynolds, Morgan Deters
       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 the theory of arrays.
      14                 :            :  */
      15                 :            : 
      16                 :            : #include "theory/arrays/theory_arrays.h"
      17                 :            : 
      18                 :            : #include <map>
      19                 :            : #include <memory>
      20                 :            : 
      21                 :            : #include "expr/array_store_all.h"
      22                 :            : #include "expr/kind.h"
      23                 :            : #include "expr/node_algorithm.h"
      24                 :            : #include "options/arrays_options.h"
      25                 :            : #include "options/smt_options.h"
      26                 :            : #include "proof/proof_checker.h"
      27                 :            : #include "smt/logic_exception.h"
      28                 :            : #include "theory/arrays/skolem_cache.h"
      29                 :            : #include "theory/arrays/theory_arrays_rewriter.h"
      30                 :            : #include "theory/decision_manager.h"
      31                 :            : #include "theory/theory_model.h"
      32                 :            : #include "theory/trust_substitutions.h"
      33                 :            : #include "theory/valuation.h"
      34                 :            : 
      35                 :            : using namespace std;
      36                 :            : 
      37                 :            : namespace cvc5::internal {
      38                 :            : namespace theory {
      39                 :            : namespace arrays {
      40                 :            : 
      41                 :            : // These are the options that produce the best empirical results on QF_AX benchmarks.
      42                 :            : // eagerLemmas = true
      43                 :            : // eagerIndexSplitting = false
      44                 :            : 
      45                 :            : // Use static configuration of options for now
      46                 :            : const bool d_ccStore = false;
      47                 :            :   //const bool d_eagerLemmas = false;
      48                 :            : const bool d_preprocess = true;
      49                 :            : const bool d_solveWrite = true;
      50                 :            : const bool d_solveWrite2 = false;
      51                 :            :   // These are now options
      52                 :            :   //const bool d_propagateLemmas = true;
      53                 :            :   //bool d_useNonLinearOpt = true;
      54                 :            :   //bool d_eagerIndexSplitting = false;
      55                 :            : 
      56                 :      50855 : TheoryArrays::TheoryArrays(Env& env,
      57                 :            :                            OutputChannel& out,
      58                 :            :                            Valuation valuation,
      59                 :      50855 :                            std::string name)
      60                 :            :     : Theory(THEORY_ARRAYS, env, out, valuation, name),
      61                 :      50855 :       d_numRow(statisticsRegistry().registerInt(name + "number of Row lemmas")),
      62                 :      50855 :       d_numExt(statisticsRegistry().registerInt(name + "number of Ext lemmas")),
      63                 :            :       d_numProp(
      64                 :      50855 :           statisticsRegistry().registerInt(name + "number of propagations")),
      65                 :            :       d_numExplain(
      66                 :      50855 :           statisticsRegistry().registerInt(name + "number of explanations")),
      67                 :      50855 :       d_numNonLinear(statisticsRegistry().registerInt(
      68                 :      50855 :           name + "number of calls to setNonLinear")),
      69                 :      50855 :       d_numSharedArrayVarSplits(statisticsRegistry().registerInt(
      70                 :      50855 :           name + "number of shared array var splits")),
      71                 :      50855 :       d_numGetModelValSplits(statisticsRegistry().registerInt(
      72                 :      50855 :           name + "number of getModelVal splits")),
      73                 :      50855 :       d_numGetModelValConflicts(statisticsRegistry().registerInt(
      74                 :      50855 :           name + "number of getModelVal conflicts")),
      75                 :      50855 :       d_numSetModelValSplits(statisticsRegistry().registerInt(
      76                 :      50855 :           name + "number of setModelVal splits")),
      77                 :      50855 :       d_numSetModelValConflicts(statisticsRegistry().registerInt(
      78                 :      50855 :           name + "number of setModelVal conflicts")),
      79                 :     101710 :       d_ppEqualityEngine(env, userContext(), name + "pp", true),
      80                 :     101710 :       d_ppFacts(userContext()),
      81                 :            :       d_rewriter(env.getNodeManager(), env.getRewriter()),
      82                 :            :       d_state(env, valuation),
      83                 :      50855 :       d_im(env, *this, d_state),
      84                 :            :       d_literalsToPropagate(context()),
      85                 :          0 :       d_literalsToPropagateIndex(context(), 0),
      86                 :            :       d_isPreRegistered(context()),
      87                 :      50855 :       d_mayEqualEqualityEngine(env, context(), name + "mayEqual", true),
      88                 :            :       d_notify(*this),
      89                 :            :       d_checker(nodeManager()),
      90                 :            :       d_infoMap(statisticsRegistry(), context(), name),
      91                 :            :       d_mergeQueue(context()),
      92                 :            :       d_mergeInProgress(false),
      93                 :            :       d_RowQueue(context()),
      94                 :     101710 :       d_RowAlreadyAdded(userContext()),
      95                 :            :       d_sharedArrays(context()),
      96                 :            :       d_sharedOther(context()),
      97                 :          0 :       d_sharedTerms(context(), false),
      98                 :            :       d_reads(context()),
      99                 :            :       d_constReadsList(context()),
     100                 :      50855 :       d_constReadsContext(new context::Context()),
     101                 :            :       d_contextPopper(context(), d_constReadsContext),
     102                 :            :       d_decisionRequests(context()),
     103                 :            :       d_permRef(context()),
     104                 :            :       d_modelConstraints(context()),
     105                 :            :       d_lemmasSaved(context()),
     106                 :            :       d_defValues(context()),
     107                 :      50855 :       d_readTableContext(new context::Context()),
     108                 :            :       d_arrayMerges(context()),
     109                 :      50855 :       d_dstrat(new TheoryArraysDecisionStrategy(this)),
     110                 :     406840 :       d_dstratInit(false)
     111                 :            : {
     112                 :      50855 :   d_true = nodeManager()->mkConst<bool>(true);
     113                 :      50855 :   d_false = nodeManager()->mkConst<bool>(false);
     114                 :            : 
     115                 :            :   // The preprocessing congruence kinds
     116                 :      50855 :   d_ppEqualityEngine.addFunctionKind(Kind::SELECT);
     117                 :      50855 :   d_ppEqualityEngine.addFunctionKind(Kind::STORE);
     118                 :            : 
     119                 :            :   // indicate we are using the default theory state object, and the arrays
     120                 :            :   // inference manager
     121                 :      50855 :   d_theoryState = &d_state;
     122                 :      50855 :   d_inferManager = &d_im;
     123                 :      50855 : }
     124                 :            : 
     125                 :     101198 : TheoryArrays::~TheoryArrays() {
     126                 :      50599 :   vector<CTNodeList*>::iterator it = d_readBucketAllocations.begin(), iend = d_readBucketAllocations.end();
     127         [ -  + ]:      50599 :   for (; it != iend; ++it) {
     128                 :          0 :     (*it)->deleteSelf();
     129                 :            :   }
     130         [ +  - ]:      50599 :   delete d_readTableContext;
     131                 :      50599 :   CNodeNListMap::iterator it2 = d_constReads.begin();
     132         [ +  + ]:      51808 :   for( ; it2 != d_constReads.end(); ++it2 ) {
     133                 :       1209 :     it2->second->deleteSelf();
     134                 :            :   }
     135         [ +  - ]:      50599 :   delete d_constReadsContext;
     136                 :     101198 : }
     137                 :            : 
     138                 :      50855 : TheoryRewriter* TheoryArrays::getTheoryRewriter() { return &d_rewriter; }
     139                 :            : 
     140                 :      20017 : ProofRuleChecker* TheoryArrays::getProofChecker() { return &d_checker; }
     141                 :            : 
     142                 :      50855 : bool TheoryArrays::needsEqualityEngine(EeSetupInfo& esi)
     143                 :            : {
     144                 :      50855 :   esi.d_notify = &d_notify;
     145                 :      50855 :   esi.d_name = d_instanceName + "ee";
     146                 :      50855 :   esi.d_notifyNewClass = true;
     147                 :      50855 :   esi.d_notifyMerge = true;
     148                 :      50855 :   return true;
     149                 :            : }
     150                 :            : 
     151                 :      50855 : void TheoryArrays::finishInit()
     152                 :            : {
     153 [ -  + ][ -  + ]:      50855 :   Assert(d_equalityEngine != nullptr);
                 [ -  - ]
     154                 :            : 
     155                 :            :   // The kinds we are treating as function application in congruence
     156                 :      50855 :   d_equalityEngine->addFunctionKind(Kind::SELECT);
     157                 :            :   if (d_ccStore)
     158                 :            :   {
     159                 :            :     d_equalityEngine->addFunctionKind(Kind::STORE);
     160                 :            :   }
     161                 :      50855 : }
     162                 :            : 
     163                 :            : /////////////////////////////////////////////////////////////////////////////
     164                 :            : // PREPROCESSING
     165                 :            : /////////////////////////////////////////////////////////////////////////////
     166                 :            : 
     167                 :            : 
     168                 :       6384 : bool TheoryArrays::ppDisequal(TNode a, TNode b) {
     169                 :       6384 :   bool termsExist = d_ppEqualityEngine.hasTerm(a) && d_ppEqualityEngine.hasTerm(b);
     170                 :       6384 :   Assert(!termsExist || !a.isConst() || !b.isConst() || a == b
     171                 :            :          || d_ppEqualityEngine.areDisequal(a, b, false));
     172                 :      12768 :   return ((termsExist && d_ppEqualityEngine.areDisequal(a, b, false))
     173                 :      19152 :           || rewrite(a.eqNode(b)) == d_false);
     174                 :            : }
     175                 :            : 
     176                 :            : 
     177                 :          0 : Node TheoryArrays::solveWrite(TNode term, bool solve1, bool solve2, bool ppCheck)
     178                 :            : {
     179         [ -  - ]:          0 :   if (!solve1) {
     180                 :          0 :     return term;
     181                 :            :   }
     182                 :          0 :   if (term[0].getKind() != Kind::STORE && term[1].getKind() != Kind::STORE)
     183                 :            :   {
     184                 :          0 :     return term;
     185                 :            :   }
     186                 :          0 :   TNode left = term[0];
     187                 :          0 :   TNode right = term[1];
     188                 :          0 :   int leftWrites = 0, rightWrites = 0;
     189                 :            : 
     190                 :            :   // Count nested writes
     191                 :          0 :   TNode e1 = left;
     192         [ -  - ]:          0 :   while (e1.getKind() == Kind::STORE)
     193                 :            :   {
     194                 :          0 :     ++leftWrites;
     195                 :          0 :     e1 = e1[0];
     196                 :            :   }
     197                 :            : 
     198                 :          0 :   TNode e2 = right;
     199         [ -  - ]:          0 :   while (e2.getKind() == Kind::STORE)
     200                 :            :   {
     201                 :          0 :     ++rightWrites;
     202                 :          0 :     e2 = e2[0];
     203                 :            :   }
     204                 :            : 
     205         [ -  - ]:          0 :   if (rightWrites > leftWrites) {
     206                 :          0 :     TNode tmp = left;
     207                 :          0 :     left = right;
     208                 :          0 :     right = tmp;
     209                 :          0 :     int tmpWrites = leftWrites;
     210                 :          0 :     leftWrites = rightWrites;
     211                 :          0 :     rightWrites = tmpWrites;
     212                 :            :   }
     213                 :            : 
     214                 :          0 :   NodeManager* nm = nodeManager();
     215         [ -  - ]:          0 :   if (rightWrites == 0) {
     216         [ -  - ]:          0 :     if (e1 != e2) {
     217                 :          0 :       return term;
     218                 :            :     }
     219                 :            :     // write(store, index_0, v_0, index_1, v_1, ..., index_n, v_n) = store IFF
     220                 :            :     //
     221                 :            :     // read(store, index_n) = v_n &
     222                 :            :     // index_{n-1} != index_n -> read(store, index_{n-1}) = v_{n-1} &
     223                 :            :     // (index_{n-2} != index_{n-1} & index_{n-2} != index_n) -> read(store, index_{n-2}) = v_{n-2} &
     224                 :            :     // ...
     225                 :            :     // (index_1 != index_2 & ... & index_1 != index_n) -> read(store, index_1) = v_1
     226                 :            :     // (index_0 != index_1 & index_0 != index_2 & ... & index_0 != index_n) -> read(store, index_0) = v_0
     227                 :          0 :     TNode write_i, write_j, index_i, index_j;
     228                 :          0 :     Node conc;
     229                 :          0 :     NodeBuilder result(nm, Kind::AND);
     230                 :            :     int i, j;
     231                 :          0 :     write_i = left;
     232         [ -  - ]:          0 :     for (i = leftWrites-1; i >= 0; --i) {
     233                 :          0 :       index_i = write_i[1];
     234                 :            : 
     235                 :            :       // build: [index_i /= index_n && index_i /= index_(n-1) &&
     236                 :            :       //         ... && index_i /= index_(i+1)] -> read(store, index_i) = v_i
     237                 :          0 :       write_j = left;
     238                 :            :       {
     239                 :          0 :         NodeBuilder hyp(nm, Kind::AND);
     240         [ -  - ]:          0 :         for (j = leftWrites - 1; j > i; --j) {
     241                 :          0 :           index_j = write_j[1];
     242                 :          0 :           if (!ppCheck || !ppDisequal(index_i, index_j)) {
     243                 :          0 :             Node hyp2(index_i.eqNode(index_j));
     244                 :          0 :             hyp << hyp2.notNode();
     245                 :            :           }
     246                 :          0 :           write_j = write_j[0];
     247                 :            :         }
     248                 :            : 
     249                 :          0 :         Node r1 = nm->mkNode(Kind::SELECT, e1, index_i);
     250                 :          0 :         conc = r1.eqNode(write_i[2]);
     251         [ -  - ]:          0 :         if (hyp.getNumChildren() != 0) {
     252         [ -  - ]:          0 :           if (hyp.getNumChildren() == 1) {
     253                 :          0 :             conc = hyp.getChild(0).impNode(conc);
     254                 :            :           }
     255                 :            :           else {
     256                 :          0 :             r1 = hyp;
     257                 :          0 :             conc = r1.impNode(conc);
     258                 :            :           }
     259                 :            :         }
     260                 :            : 
     261                 :            :         // And into result
     262                 :          0 :         result << conc;
     263                 :            : 
     264                 :            :         // Prepare for next iteration
     265                 :          0 :         write_i = write_i[0];
     266                 :            :       }
     267                 :            :     }
     268                 :          0 :     Assert(result.getNumChildren() > 0);
     269         [ -  - ]:          0 :     if (result.getNumChildren() == 1) {
     270                 :          0 :       return result.getChild(0);
     271                 :            :     }
     272                 :          0 :     return result;
     273                 :            :   }
     274                 :            :   else {
     275         [ -  - ]:          0 :     if (!solve2) {
     276                 :          0 :       return term;
     277                 :            :     }
     278                 :            :     // store(...) = store(a,i,v) ==>
     279                 :            :     // store(store(...),i,select(a,i)) = a && select(store(...),i)=v
     280                 :          0 :     Node l = left;
     281                 :          0 :     Node tmp;
     282                 :          0 :     NodeBuilder nb(nm, Kind::AND);
     283         [ -  - ]:          0 :     while (right.getKind() == Kind::STORE)
     284                 :            :     {
     285                 :          0 :       tmp = nm->mkNode(Kind::SELECT, l, right[1]);
     286                 :          0 :       nb << tmp.eqNode(right[2]);
     287                 :          0 :       tmp = nm->mkNode(Kind::SELECT, right[0], right[1]);
     288                 :          0 :       l = nm->mkNode(Kind::STORE, l, right[1], tmp);
     289                 :          0 :       right = right[0];
     290                 :            :     }
     291                 :          0 :     nb << solveWrite(l.eqNode(right), solve1, solve2, ppCheck);
     292                 :          0 :     return nb;
     293                 :            :   }
     294                 :            :   Unreachable();
     295                 :            :   return term;
     296                 :            : }
     297                 :            : 
     298                 :      15955 : TrustNode TheoryArrays::ppRewrite(TNode term, std::vector<SkolemLemma>& lems)
     299                 :            : {
     300                 :            :   // first, check for logic exceptions
     301                 :      15955 :   Kind k = term.getKind();
     302         [ +  + ]:      15955 :   if (!options().arrays.arraysExp)
     303                 :            :   {
     304 [ +  + ][ -  + ]:      13784 :     if (k == Kind::EQ_RANGE || k == Kind::STORE_ALL)
     305                 :            :     {
     306                 :          2 :       std::stringstream ss;
     307                 :          1 :       ss << "Term of kind `" << k
     308                 :          1 :          << "` not supported in default mode, try `--arrays-exp`.";
     309                 :          1 :       throw LogicException(ss.str());
     310                 :            :     }
     311                 :            :   }
     312                 :            :   // see if we need to expand definitions
     313                 :      31908 :   Node texp = d_rewriter.expandDefinition(term);
     314         [ +  + ]:      15954 :   if (!texp.isNull())
     315                 :            :   {
     316                 :            :     // do not track proofs here
     317                 :         30 :     return TrustNode::mkTrustRewrite(term, texp, nullptr);
     318                 :            :   }
     319                 :            :   if (!d_preprocess)
     320                 :            :   {
     321                 :            :     return TrustNode::null();
     322                 :            :   }
     323                 :      15924 :   d_ppEqualityEngine.addTerm(term);
     324                 :      15924 :   NodeManager* nm = nodeManager();
     325                 :      31848 :   Node ret;
     326 [ +  + ][ -  + ]:      15924 :   switch (k)
     327                 :            :   {
     328                 :      11698 :     case Kind::SELECT:
     329                 :            :     {
     330                 :            :       // select(store(a,i,v),j) = select(a,j)
     331                 :            :       //    IF i != j
     332                 :      11698 :       if (term[0].getKind() == Kind::STORE && ppDisequal(term[0][1], term[1]))
     333                 :            :       {
     334                 :          0 :         ret = nm->mkNode(Kind::SELECT, term[0][0], term[1]);
     335                 :            :       }
     336                 :      11698 :       break;
     337                 :            :     }
     338                 :       3039 :     case Kind::STORE:
     339                 :            :     {
     340                 :            :       // store(store(a,i,v),j,w) = store(store(a,j,w),i,v)
     341                 :            :       //    IF i != j and j comes before i in the ordering
     342                 :       4415 :       if (term[0].getKind() == Kind::STORE && (term[1] < term[0][1])
     343                 :       4415 :           && ppDisequal(term[1], term[0][1]))
     344                 :            :       {
     345                 :          0 :         Node inner = nm->mkNode(Kind::STORE, term[0][0], term[1], term[2]);
     346                 :          0 :         Node outer = nm->mkNode(Kind::STORE, inner, term[0][1], term[0][2]);
     347                 :          0 :         ret = outer;
     348                 :            :       }
     349                 :       3039 :       break;
     350                 :            :     }
     351                 :          0 :     case Kind::EQUAL:
     352                 :            :     {
     353                 :          0 :       ret = solveWrite(term, d_solveWrite, d_solveWrite2, true);
     354                 :          0 :       break;
     355                 :            :     }
     356                 :       1187 :     default:
     357                 :       1187 :       break;
     358                 :            :   }
     359 [ -  + ][ -  - ]:      15924 :   if (!ret.isNull() && ret != term)
                 [ -  + ]
     360                 :            :   {
     361                 :          0 :     return TrustNode::mkTrustRewrite(term, ret, nullptr);
     362                 :            :   }
     363                 :      15924 :   return TrustNode::null();
     364                 :            : }
     365                 :            : 
     366                 :        696 : bool TheoryArrays::ppAssert(TrustNode tin,
     367                 :            :                             TrustSubstitutionMap& outSubstitutions)
     368                 :            : {
     369                 :       1392 :   TNode in = tin.getNode();
     370    [ +  + ][ + ]:        696 :   switch(in.getKind()) {
     371                 :        465 :     case Kind::EQUAL:
     372                 :            :     {
     373                 :        465 :       d_ppFacts.push_back(in);
     374                 :        465 :       d_ppEqualityEngine.assertEquality(in, true, in);
     375                 :        465 :       if (in[0].isVar() && d_valuation.isLegalElimination(in[0], in[1]))
     376                 :            :       {
     377                 :        156 :         outSubstitutions.addSubstitutionSolved(in[0], in[1], tin);
     378                 :        156 :         return true;
     379                 :            :       }
     380                 :        309 :       if (in[1].isVar() && d_valuation.isLegalElimination(in[1], in[0]))
     381                 :            :       {
     382                 :          0 :         outSubstitutions.addSubstitutionSolved(in[1], in[0], tin);
     383                 :          0 :         return true;
     384                 :            :       }
     385                 :        309 :       break;
     386                 :            :     }
     387                 :        134 :     case Kind::NOT:
     388                 :            :     {
     389                 :        134 :       d_ppFacts.push_back(in);
     390         [ +  + ]:        134 :       if (in[0].getKind() == Kind::EQUAL)
     391                 :            :       {
     392                 :        348 :         Node a = in[0][0];
     393                 :        232 :         Node b = in[0][1];
     394                 :        116 :         d_ppEqualityEngine.assertEquality(in[0], false, in);
     395                 :            :       }
     396                 :        134 :       break;
     397                 :            :     }
     398                 :         97 :     default:
     399                 :         97 :       break;
     400                 :            :   }
     401                 :        540 :   return false;
     402                 :            : }
     403                 :            : 
     404                 :            : 
     405                 :            : /////////////////////////////////////////////////////////////////////////////
     406                 :            : // T-PROPAGATION / REGISTRATION
     407                 :            : /////////////////////////////////////////////////////////////////////////////
     408                 :            : 
     409                 :     158473 : bool TheoryArrays::propagateLit(TNode literal)
     410                 :            : {
     411 [ +  - ][ -  + ]:     316946 :   Trace("arrays") << spaces(context()->getLevel())
                 [ -  - ]
     412                 :          0 :                   << "TheoryArrays::propagateLit(" << literal << ")"
     413                 :     158473 :                   << std::endl;
     414                 :            : 
     415                 :            :   // If already in conflict, no more propagation
     416         [ -  + ]:     158473 :   if (d_state.isInConflict())
     417                 :            :   {
     418                 :          0 :     Trace("arrays") << spaces(context()->getLevel())
     419                 :          0 :                     << "TheoryArrays::propagateLit(" << literal
     420                 :          0 :                     << "): already in conflict" << std::endl;
     421                 :          0 :     return false;
     422                 :            :   }
     423                 :            : 
     424                 :     158473 :   bool ok = d_out->propagate(literal);
     425         [ +  + ]:     158473 :   if (!ok) {
     426                 :       3617 :     d_state.notifyInConflict();
     427                 :            :   }
     428                 :     158473 :   return ok;
     429                 :            : }/* TheoryArrays::propagate(TNode) */
     430                 :            : 
     431                 :            : 
     432                 :          0 : TNode TheoryArrays::weakEquivGetRep(TNode node) {
     433                 :          0 :   TNode pointer;
     434                 :            :   while (true) {
     435                 :          0 :     pointer = d_infoMap.getWeakEquivPointer(node);
     436         [ -  - ]:          0 :     if (pointer.isNull()) {
     437                 :          0 :       return node;
     438                 :            :     }
     439                 :          0 :     node = pointer;
     440                 :            :   }
     441                 :            : }
     442                 :            : 
     443                 :          0 : TNode TheoryArrays::weakEquivGetRepIndex(TNode node, TNode index) {
     444                 :          0 :   Assert(!index.isNull());
     445                 :          0 :   TNode pointer, index2;
     446                 :            :   while (true) {
     447                 :          0 :     pointer = d_infoMap.getWeakEquivPointer(node);
     448         [ -  - ]:          0 :     if (pointer.isNull()) {
     449                 :          0 :       return node;
     450                 :            :     }
     451                 :          0 :     index2 = d_infoMap.getWeakEquivIndex(node);
     452                 :          0 :     if (index2.isNull() || !d_equalityEngine->areEqual(index, index2))
     453                 :            :     {
     454                 :          0 :       node = pointer;
     455                 :            :     }
     456                 :            :     else {
     457                 :          0 :       TNode secondary = d_infoMap.getWeakEquivSecondary(node);
     458         [ -  - ]:          0 :       if (secondary.isNull()) {
     459                 :          0 :         return node;
     460                 :            :       }
     461                 :          0 :       node = secondary;
     462                 :            :     }
     463                 :          0 :   }
     464                 :            : }
     465                 :            : 
     466                 :          0 : void TheoryArrays::visitAllLeaves(TNode reason, vector<TNode>& conjunctions) {
     467 [ -  - ][ -  - ]:          0 :   switch (reason.getKind()) {
     468                 :          0 :     case Kind::AND:
     469                 :          0 :       Assert(reason.getNumChildren() == 2);
     470                 :          0 :       visitAllLeaves(reason[0], conjunctions);
     471                 :          0 :       visitAllLeaves(reason[1], conjunctions);
     472                 :          0 :       break;
     473                 :          0 :     case Kind::NOT: conjunctions.push_back(reason); break;
     474                 :          0 :     case Kind::EQUAL:
     475                 :          0 :       d_equalityEngine->explainEquality(
     476                 :            :           reason[0], reason[1], true, conjunctions);
     477                 :          0 :       break;
     478                 :          0 :     default:
     479                 :          0 :       Unreachable();
     480                 :            :   }
     481                 :          0 : }
     482                 :            : 
     483                 :          0 : void TheoryArrays::weakEquivBuildCond(TNode node, TNode index, vector<TNode>& conjunctions) {
     484                 :          0 :   Assert(!index.isNull());
     485                 :          0 :   TNode pointer, index2;
     486                 :            :   while (true) {
     487                 :          0 :     pointer = d_infoMap.getWeakEquivPointer(node);
     488         [ -  - ]:          0 :     if (pointer.isNull()) {
     489                 :          0 :       return;
     490                 :            :     }
     491                 :          0 :     index2 = d_infoMap.getWeakEquivIndex(node);
     492         [ -  - ]:          0 :     if (index2.isNull()) {
     493                 :            :       // Null index means these two nodes became equal: explain the equality.
     494                 :          0 :       d_equalityEngine->explainEquality(node, pointer, true, conjunctions);
     495                 :          0 :       node = pointer;
     496                 :            :     }
     497         [ -  - ]:          0 :     else if (!d_equalityEngine->areEqual(index, index2))
     498                 :            :     {
     499                 :            :       // If indices are not equal in current context, need to add that to the lemma.
     500                 :          0 :       Node reason = index.eqNode(index2).notNode();
     501                 :          0 :       d_permRef.push_back(reason);
     502                 :          0 :       conjunctions.push_back(reason);
     503                 :          0 :       node = pointer;
     504                 :            :     }
     505                 :            :     else {
     506                 :          0 :       TNode secondary = d_infoMap.getWeakEquivSecondary(node);
     507         [ -  - ]:          0 :       if (secondary.isNull()) {
     508                 :          0 :         return;
     509                 :            :       }
     510                 :          0 :       TNode reason = d_infoMap.getWeakEquivSecondaryReason(node);
     511                 :          0 :       Assert(!reason.isNull());
     512                 :          0 :       visitAllLeaves(reason, conjunctions);
     513                 :          0 :       node = secondary;
     514                 :            :     }
     515                 :          0 :   }
     516                 :            : }
     517                 :            : 
     518                 :          0 : void TheoryArrays::weakEquivMakeRep(TNode node) {
     519                 :          0 :   TNode pointer = d_infoMap.getWeakEquivPointer(node);
     520         [ -  - ]:          0 :   if (pointer.isNull()) {
     521                 :          0 :     return;
     522                 :            :   }
     523                 :          0 :   weakEquivMakeRep(pointer);
     524                 :          0 :   d_infoMap.setWeakEquivPointer(pointer, node);
     525                 :          0 :   d_infoMap.setWeakEquivIndex(pointer, d_infoMap.getWeakEquivIndex(node));
     526                 :          0 :   d_infoMap.setWeakEquivPointer(node, TNode());
     527                 :          0 :   weakEquivMakeRepIndex(node);
     528                 :            : }
     529                 :            : 
     530                 :          0 : void TheoryArrays::weakEquivMakeRepIndex(TNode node) {
     531                 :          0 :   TNode secondary = d_infoMap.getWeakEquivSecondary(node);
     532         [ -  - ]:          0 :   if (secondary.isNull()) {
     533                 :          0 :     return;
     534                 :            :   }
     535                 :          0 :   TNode index = d_infoMap.getWeakEquivIndex(node);
     536                 :          0 :   Assert(!index.isNull());
     537                 :          0 :   TNode index2 = d_infoMap.getWeakEquivIndex(secondary);
     538                 :          0 :   Node reason;
     539                 :          0 :   TNode next;
     540                 :          0 :   while (index2.isNull() || !d_equalityEngine->areEqual(index, index2))
     541                 :            :   {
     542                 :          0 :     next = d_infoMap.getWeakEquivPointer(secondary);
     543                 :          0 :     d_infoMap.setWeakEquivSecondary(node, next);
     544                 :          0 :     reason = d_infoMap.getWeakEquivSecondaryReason(node);
     545         [ -  - ]:          0 :     if (index2.isNull()) {
     546                 :          0 :       reason = reason.andNode(secondary.eqNode(next));
     547                 :            :     }
     548                 :            :     else {
     549                 :          0 :       reason = reason.andNode(index.eqNode(index2).notNode());
     550                 :            :     }
     551                 :          0 :     d_permRef.push_back(reason);
     552                 :          0 :     d_infoMap.setWeakEquivSecondaryReason(node, reason);
     553         [ -  - ]:          0 :     if (next.isNull()) {
     554                 :          0 :       return;
     555                 :            :     }
     556                 :          0 :     secondary = next;
     557                 :          0 :     index2 = d_infoMap.getWeakEquivIndex(secondary);
     558                 :            :   }
     559                 :          0 :   weakEquivMakeRepIndex(secondary);
     560                 :          0 :   d_infoMap.setWeakEquivSecondary(secondary, node);
     561                 :          0 :   d_infoMap.setWeakEquivSecondaryReason(secondary, d_infoMap.getWeakEquivSecondaryReason(node));
     562                 :          0 :   d_infoMap.setWeakEquivSecondary(node, TNode());
     563                 :          0 :   d_infoMap.setWeakEquivSecondaryReason(node, TNode());
     564                 :            : }
     565                 :            : 
     566                 :          0 : void TheoryArrays::weakEquivAddSecondary(TNode index, TNode arrayFrom, TNode arrayTo, TNode reason) {
     567                 :          0 :   std::unordered_set<TNode> marked;
     568                 :          0 :   vector<TNode> index_trail;
     569                 :          0 :   vector<TNode>::iterator it, iend;
     570                 :          0 :   Node equivalence_trail = reason;
     571                 :          0 :   Node current_reason;
     572                 :          0 :   TNode pointer, indexRep;
     573         [ -  - ]:          0 :   if (!index.isNull()) {
     574                 :          0 :     index_trail.push_back(index);
     575                 :          0 :     marked.insert(d_equalityEngine->getRepresentative(index));
     576                 :            :   }
     577         [ -  - ]:          0 :   while (arrayFrom != arrayTo) {
     578                 :          0 :     index = d_infoMap.getWeakEquivIndex(arrayFrom);
     579                 :          0 :     pointer = d_infoMap.getWeakEquivPointer(arrayFrom);
     580         [ -  - ]:          0 :     if (!index.isNull()) {
     581                 :          0 :       indexRep = d_equalityEngine->getRepresentative(index);
     582                 :          0 :       if (marked.find(indexRep) == marked.end() && weakEquivGetRepIndex(arrayFrom, index) != arrayTo) {
     583                 :          0 :         weakEquivMakeRepIndex(arrayFrom);
     584                 :          0 :         d_infoMap.setWeakEquivSecondary(arrayFrom, arrayTo);
     585                 :          0 :         current_reason = equivalence_trail;
     586         [ -  - ]:          0 :         for (it = index_trail.begin(), iend = index_trail.end(); it != iend; ++it) {
     587                 :          0 :           current_reason = current_reason.andNode(index.eqNode(*it).notNode());
     588                 :            :         }
     589                 :          0 :         d_permRef.push_back(current_reason);
     590                 :          0 :         d_infoMap.setWeakEquivSecondaryReason(arrayFrom, current_reason);
     591                 :            :       }
     592                 :          0 :       marked.insert(indexRep);
     593                 :            :     }
     594                 :            :     else {
     595                 :          0 :       equivalence_trail = equivalence_trail.andNode(arrayFrom.eqNode(pointer));
     596                 :            :     }
     597                 :          0 :     arrayFrom = pointer;
     598                 :            :   }
     599                 :          0 : }
     600                 :            : 
     601                 :          0 : void TheoryArrays::checkWeakEquiv(bool arraysMerged) {
     602                 :          0 :   eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(&d_mayEqualEqualityEngine);
     603         [ -  - ]:          0 :   for (; !eqcs_i.isFinished(); ++eqcs_i) {
     604                 :          0 :     Node eqc = (*eqcs_i);
     605         [ -  - ]:          0 :     if (!eqc.getType().isArray()) {
     606                 :          0 :       continue;
     607                 :            :     }
     608                 :          0 :     eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, &d_mayEqualEqualityEngine);
     609                 :          0 :     TNode rep = d_mayEqualEqualityEngine.getRepresentative(*eqc_i);
     610                 :          0 :     TNode weakEquivRep = weakEquivGetRep(rep);
     611         [ -  - ]:          0 :     for (; !eqc_i.isFinished(); ++eqc_i) {
     612                 :          0 :       TNode n = *eqc_i;
     613                 :          0 :       Assert(!arraysMerged || weakEquivGetRep(n) == weakEquivRep);
     614                 :          0 :       TNode pointer = d_infoMap.getWeakEquivPointer(n);
     615                 :          0 :       TNode index = d_infoMap.getWeakEquivIndex(n);
     616                 :          0 :       TNode secondary = d_infoMap.getWeakEquivSecondary(n);
     617                 :          0 :       Assert(pointer.isNull() == (weakEquivGetRep(n) == n));
     618                 :          0 :       Assert(!pointer.isNull() || secondary.isNull());
     619                 :          0 :       Assert(!index.isNull() || secondary.isNull());
     620                 :          0 :       Assert(d_infoMap.getWeakEquivSecondaryReason(n).isNull()
     621                 :            :              || !secondary.isNull());
     622         [ -  - ]:          0 :       if (!pointer.isNull()) {
     623         [ -  - ]:          0 :         if (index.isNull()) {
     624                 :          0 :           Assert(d_equalityEngine->areEqual(n, pointer));
     625                 :            :         }
     626                 :            :         else {
     627                 :          0 :           Assert(
     628                 :            :               (n.getKind() == Kind::STORE && n[0] == pointer && n[1] == index)
     629                 :            :               || (pointer.getKind() == Kind::STORE && pointer[0] == n
     630                 :            :                   && pointer[1] == index));
     631                 :            :         }
     632                 :            :       }
     633                 :            :     }
     634                 :            :   }
     635                 :          0 : }
     636                 :            : 
     637                 :            : /**
     638                 :            :  * Stores in d_infoMap the following information for each term a of type array:
     639                 :            :  *
     640                 :            :  *    - all i, such that there exists a term a[i] or a = store(b i v)
     641                 :            :  *      (i.e. all indices it is being read atl; store(b i v) is implicitly read at
     642                 :            :  *      position i due to the implicit axiom store(b i v)[i] = v )
     643                 :            :  *
     644                 :            :  *    - all the stores a is congruent to (this information is context dependent)
     645                 :            :  *
     646                 :            :  *    - all store terms of the form store (a i v) (i.e. in which a appears
     647                 :            :  *      directly; this is invariant because no new store terms are created)
     648                 :            :  *
     649                 :            :  * Note: completeness depends on having pre-register called on all the input
     650                 :            :  *       terms before starting to instantiate lemmas.
     651                 :            :  */
     652                 :     119124 : void TheoryArrays::preRegisterTermInternal(TNode node)
     653                 :            : {
     654         [ +  + ]:     119124 :   if (d_state.isInConflict())
     655                 :            :   {
     656                 :      72513 :     return;
     657                 :            :   }
     658 [ +  - ][ -  + ]:     237930 :   Trace("arrays") << spaces(context()->getLevel())
                 [ -  - ]
     659                 :          0 :                   << "TheoryArrays::preRegisterTerm(" << node << ")"
     660                 :     118965 :                   << std::endl;
     661                 :     118965 :   Kind nk = node.getKind();
     662         [ +  + ]:     118965 :   if (nk == Kind::EQUAL)
     663                 :            :   {
     664                 :            :     // Add the trigger for equality
     665                 :            :     // NOTE: note that if the equality is true or false already, it might not be added
     666                 :      10215 :     d_state.addEqualityEngineTriggerPredicate(node);
     667                 :      10215 :     return;
     668                 :            :   }
     669                 :            :   // add to equality engine and the may equality engine
     670                 :     108750 :   TypeNode nodeType = node.getType();
     671         [ +  + ]:     108750 :   if (nodeType.isArray())
     672                 :            :   {
     673                 :            :     // index type should not be an array, otherwise we throw a logic exception
     674         [ -  + ]:      11498 :     if (nodeType.getArrayIndexType().isArray())
     675                 :            :     {
     676                 :          0 :       std::stringstream ss;
     677                 :          0 :       ss << "Arrays cannot be indexed by array types, offending array type is "
     678                 :          0 :          << nodeType;
     679                 :          0 :       throw LogicException(ss.str());
     680                 :            :     }
     681                 :      11498 :     d_mayEqualEqualityEngine.addTerm(node);
     682                 :            :   }
     683         [ +  + ]:     108750 :   if (d_equalityEngine->hasTerm(node))
     684                 :            :   {
     685                 :            :     // Notice that array terms may be added to its equality engine before
     686                 :            :     // being preregistered in the central equality engine architecture.
     687                 :            :     // Prior to this, an assertion in this case was:
     688                 :            :     // Assert(nk != Kind::SELECT
     689                 :            :     //         || d_isPreRegistered.find(node) != d_isPreRegistered.end());
     690                 :      62139 :     return;
     691                 :            :   }
     692                 :      46611 :   d_equalityEngine->addTerm(node);
     693                 :            : 
     694 [ +  + ][ +  + ]:      46611 :   switch (node.getKind())
     695                 :            :   {
     696                 :      35940 :     case Kind::SELECT:
     697                 :            :     {
     698                 :            :       // Reads
     699                 :      71880 :       TNode store = d_equalityEngine->getRepresentative(node[0]);
     700                 :            : 
     701                 :            :       // The may equal needs the store
     702                 :      35940 :       d_mayEqualEqualityEngine.addTerm(store);
     703                 :            : 
     704         [ -  + ]:      35940 :       Assert((d_isPreRegistered.insert(node), true));
     705                 :            : 
     706 [ -  + ][ -  + ]:      35940 :       Assert(d_equalityEngine->getRepresentative(store) == store);
                 [ -  - ]
     707                 :      35940 :       d_infoMap.addIndex(store, node[1]);
     708                 :            : 
     709                 :            :       // Synchronize d_constReadsContext with SAT context
     710 [ -  + ][ -  + ]:      35940 :       Assert(d_constReadsContext->getLevel() <= context()->getLevel());
                 [ -  - ]
     711         [ +  + ]:      71581 :       while (d_constReadsContext->getLevel() < context()->getLevel())
     712                 :            :       {
     713                 :      35641 :         d_constReadsContext->push();
     714                 :            :       }
     715                 :            : 
     716                 :            :       // Record read in sharing data structure
     717                 :      71880 :       TNode index = d_equalityEngine->getRepresentative(node[1]);
     718 [ +  - ][ +  + ]:      35940 :       if (!options().arrays.arraysWeakEquivalence && index.isConst())
                 [ +  + ]
     719                 :            :       {
     720                 :            :         CTNodeList* temp;
     721                 :       6531 :         CNodeNListMap::iterator it = d_constReads.find(index);
     722         [ +  + ]:       6531 :         if (it == d_constReads.end())
     723                 :            :         {
     724                 :        856 :           temp = new (true) CTNodeList(d_constReadsContext);
     725                 :        856 :           d_constReads[index] = temp;
     726                 :            :         }
     727                 :            :         else
     728                 :            :         {
     729                 :       5675 :           temp = (*it).second;
     730                 :            :         }
     731                 :       6531 :         temp->push_back(node);
     732                 :       6531 :         d_constReadsList.push_back(node);
     733                 :            :       }
     734                 :            :       else
     735                 :            :       {
     736                 :      29409 :         d_reads.push_back(node);
     737                 :            :       }
     738                 :            : 
     739                 :      35940 :       checkRowForIndex(node[1], store);
     740                 :      35940 :       break;
     741                 :            :     }
     742                 :       2124 :     case Kind::STORE:
     743                 :            :     {
     744                 :       4248 :       TNode a = d_equalityEngine->getRepresentative(node[0]);
     745                 :            : 
     746         [ +  + ]:       2124 :       if (node.isConst())
     747                 :            :       {
     748                 :            :         // Can't use d_mayEqualEqualityEngine to merge node with a because they
     749                 :            :         // are both constants, so just set the default value manually for node.
     750 [ -  + ][ -  + ]:         19 :         Assert(a == node[0]);
                 [ -  - ]
     751                 :         19 :         d_mayEqualEqualityEngine.addTerm(node);
     752 [ -  + ][ -  + ]:         19 :         Assert(d_mayEqualEqualityEngine.getRepresentative(node) == node);
                 [ -  - ]
     753 [ -  + ][ -  + ]:         19 :         Assert(d_mayEqualEqualityEngine.getRepresentative(a) == a);
                 [ -  - ]
     754                 :         19 :         DefValMap::iterator it = d_defValues.find(a);
     755 [ -  + ][ -  + ]:         19 :         Assert(it != d_defValues.end());
                 [ -  - ]
     756                 :         19 :         d_defValues[node] = (*it).second;
     757                 :            :       }
     758                 :            :       else
     759                 :            :       {
     760                 :       2105 :         d_mayEqualEqualityEngine.assertEquality(node.eqNode(a), true, d_true);
     761 [ -  + ][ -  + ]:       2105 :         Assert(d_mayEqualEqualityEngine.consistent());
                 [ -  - ]
     762                 :            :       }
     763                 :            : 
     764                 :       4248 :       TNode i = node[1];
     765                 :       4248 :       TNode v = node[2];
     766                 :       2124 :       NodeManager* nm = nodeManager();
     767                 :       6372 :       Node ni = nm->mkNode(Kind::SELECT, node, i);
     768         [ +  - ]:       2124 :       if (!d_equalityEngine->hasTerm(ni))
     769                 :            :       {
     770                 :       2124 :         preRegisterTermInternal(ni);
     771                 :            :       }
     772                 :            :       // Apply RIntro1 Rule
     773                 :       2124 :       d_im.assertInference(ni.eqNode(v),
     774                 :            :                            true,
     775                 :            :                            InferenceId::ARRAYS_READ_OVER_WRITE_1,
     776                 :       2124 :                            d_true,
     777                 :            :                            ProofRule::ARRAYS_READ_OVER_WRITE_1);
     778                 :            : 
     779                 :       2124 :       d_infoMap.addStore(node, node);
     780                 :       2124 :       d_infoMap.addInStore(a, node);
     781                 :       2124 :       d_infoMap.setModelRep(node, node);
     782                 :            : 
     783                 :            :       // Add-Store for Weak Equivalence
     784         [ -  + ]:       2124 :       if (options().arrays.arraysWeakEquivalence)
     785                 :            :       {
     786                 :          0 :         Assert(weakEquivGetRep(node[0]) == weakEquivGetRep(a));
     787                 :          0 :         Assert(weakEquivGetRep(node) == node);
     788                 :          0 :         d_infoMap.setWeakEquivPointer(node, node[0]);
     789                 :          0 :         d_infoMap.setWeakEquivIndex(node, node[1]);
     790                 :            : #ifdef CVC5_ASSERTIONS
     791                 :          0 :         checkWeakEquiv(false);
     792                 :            : #endif
     793                 :            :     }
     794                 :            : 
     795                 :       2124 :     checkStore(node);
     796                 :       2124 :     break;
     797                 :            :   }
     798                 :         43 :   case Kind::STORE_ALL:
     799                 :            :   {
     800                 :         86 :     ArrayStoreAll storeAll = node.getConst<ArrayStoreAll>();
     801                 :         86 :     Node defaultValue = storeAll.getValue();
     802         [ -  + ]:         43 :     if (!defaultValue.isConst()) {
     803                 :          0 :       throw LogicException("Array theory solver does not yet support non-constant default values for arrays");
     804                 :            :     }
     805                 :         43 :     d_infoMap.setConstArr(node, node);
     806 [ -  + ][ -  + ]:         43 :     Assert(d_mayEqualEqualityEngine.getRepresentative(node) == node);
                 [ -  - ]
     807                 :         43 :     d_defValues[node] = defaultValue;
     808                 :         43 :     setNonLinear(node);
     809                 :         43 :     break;
     810                 :            :   }
     811                 :       8504 :   default:
     812                 :            :     // Variables etc, already processed above
     813                 :       8504 :     break;
     814                 :            :   }
     815                 :            :   // Invariant: preregistered terms are exactly the terms in the equality engine
     816                 :            :   // Disabled, see comment above for Kind::EQUAL
     817                 :            :   // Assert(d_equalityEngine->hasTerm(node) ||
     818                 :            :   // !d_equalityEngine->consistent());
     819                 :            : }
     820                 :            : 
     821                 :      43593 : void TheoryArrays::preRegisterTerm(TNode node)
     822                 :            : {
     823                 :      43593 :   preRegisterTermInternal(node);
     824                 :            :   // If we have a select from an array of Bools, mark it as a term that can be propagated.
     825                 :            :   // Note: do this here instead of in preRegisterTermInternal to prevent internal select
     826                 :            :   // terms from being propagated out (as this results in an assertion failure).
     827 [ +  + ][ +  + ]:      43593 :   if (node.getKind() == Kind::SELECT && node.getType().isBoolean())
         [ +  + ][ +  + ]
                 [ -  - ]
     828                 :            :   {
     829                 :        231 :     d_state.addEqualityEngineTriggerPredicate(node);
     830                 :            :   }
     831                 :      43593 : }
     832                 :            : 
     833                 :      14197 : TrustNode TheoryArrays::explain(TNode literal)
     834                 :            : {
     835                 :      14197 :   return d_im.explainLit(literal);
     836                 :            : }
     837                 :            : 
     838                 :            : /////////////////////////////////////////////////////////////////////////////
     839                 :            : // SHARING
     840                 :            : /////////////////////////////////////////////////////////////////////////////
     841                 :            : 
     842                 :      73252 : void TheoryArrays::notifySharedTerm(TNode t)
     843                 :            : {
     844 [ +  - ][ -  + ]:     146504 :   Trace("arrays::sharing") << spaces(context()->getLevel())
                 [ -  - ]
     845                 :          0 :                            << "TheoryArrays::notifySharedTerm(" << t << ")"
     846                 :      73252 :                            << std::endl;
     847         [ +  + ]:      73252 :   if (t.getType().isArray()) {
     848                 :       5161 :     d_sharedArrays.insert(t);
     849                 :            :   }
     850                 :            :   else {
     851                 :            : #ifdef CVC5_ASSERTIONS
     852                 :      68091 :     d_sharedOther.insert(t);
     853                 :            : #endif
     854                 :      68091 :     d_sharedTerms = true;
     855                 :            :   }
     856                 :      73252 : }
     857                 :            : 
     858                 :     803624 : void TheoryArrays::checkPair(TNode r1, TNode r2)
     859                 :            : {
     860         [ +  - ]:     803624 :   Trace("arrays::sharing") << "TheoryArrays::computeCareGraph(): checking reads " << r1 << " and " << r2 << std::endl;
     861                 :            : 
     862                 :     803624 :   TNode x = r1[1];
     863                 :     803624 :   TNode y = r2[1];
     864 [ -  + ][ -  + ]:     803624 :   Assert(d_equalityEngine->isTriggerTerm(x, THEORY_ARRAYS));
                 [ -  - ]
     865                 :            : 
     866                 :    1607250 :   if (d_equalityEngine->hasTerm(x) && d_equalityEngine->hasTerm(y)
     867                 :    2739650 :       && (d_equalityEngine->areEqual(x, y)
     868                 :    1132400 :           || d_equalityEngine->areDisequal(x, y, false)))
     869                 :            :   {
     870         [ +  - ]:     740868 :     Trace("arrays::sharing") << "TheoryArrays::computeCareGraph(): equality known, skipping" << std::endl;
     871                 :     740868 :     return;
     872                 :            :   }
     873                 :            : 
     874                 :            :   // If the terms are already known to be equal, we are also in good shape
     875         [ +  + ]:      62756 :   if (d_equalityEngine->areEqual(r1, r2))
     876                 :            :   {
     877         [ +  - ]:      17846 :     Trace("arrays::sharing") << "TheoryArrays::computeCareGraph(): equal, skipping" << std::endl;
     878                 :      17846 :     return;
     879                 :            :   }
     880                 :            : 
     881         [ +  + ]:      44910 :   if (r1[0] != r2[0]) {
     882                 :            :     // If arrays are known to be disequal, or cannot become equal, we can continue
     883                 :      78692 :     Assert(d_mayEqualEqualityEngine.hasTerm(r1[0])
     884                 :            :            && d_mayEqualEqualityEngine.hasTerm(r2[0]));
     885                 :     118038 :     if (r1[0].getType() != r2[0].getType()
     886                 :     118038 :         || d_equalityEngine->areDisequal(r1[0], r2[0], false))
     887                 :            :     {
     888         [ +  - ]:      17452 :       Trace("arrays::sharing") << "TheoryArrays::computeCareGraph(): arrays can't be equal, skipping" << std::endl;
     889                 :      17452 :       return;
     890                 :            :     }
     891         [ +  + ]:      21894 :     else if (!d_mayEqualEqualityEngine.areEqual(r1[0], r2[0])) {
     892                 :        763 :       return;
     893                 :            :     }
     894                 :            :   }
     895                 :            : 
     896         [ +  + ]:      26695 :   if (!d_equalityEngine->isTriggerTerm(y, THEORY_ARRAYS))
     897                 :            :   {
     898         [ +  - ]:         15 :     Trace("arrays::sharing") << "TheoryArrays::computeCareGraph(): not connected to shared terms, skipping" << std::endl;
     899                 :         15 :     return;
     900                 :            :   }
     901                 :            : 
     902                 :            :   // Get representative trigger terms
     903                 :            :   TNode x_shared =
     904                 :      26680 :       d_equalityEngine->getTriggerTermRepresentative(x, THEORY_ARRAYS);
     905                 :            :   TNode y_shared =
     906                 :      26680 :       d_equalityEngine->getTriggerTermRepresentative(y, THEORY_ARRAYS);
     907                 :      26680 :   EqualityStatus eqStatusDomain = d_valuation.getEqualityStatus(x_shared, y_shared);
     908 [ -  - ][ -  + ]:      26680 :   switch (eqStatusDomain) {
                    [ + ]
     909                 :          0 :     case EQUALITY_TRUE_AND_PROPAGATED:
     910                 :            :       // Should have been propagated to us
     911                 :          0 :       Assert(false);
     912                 :            :       break;
     913                 :          0 :     case EQUALITY_TRUE:
     914                 :            :       // Missed propagation - need to add the pair so that theory engine can force propagation
     915         [ -  - ]:          0 :       Trace("arrays::sharing") << "TheoryArrays::computeCareGraph(): missed propagation" << std::endl;
     916                 :          0 :       break;
     917                 :          0 :     case EQUALITY_FALSE_AND_PROPAGATED:
     918         [ -  - ]:          0 :       Trace("arrays::sharing") << "TheoryArrays::computeCareGraph(): checkPair "
     919                 :          0 :                                   "called when false in model"
     920                 :          0 :                                << std::endl;
     921                 :            :       // Should have been propagated to us
     922                 :          0 :       Assert(false);
     923                 :            :       break;
     924                 :      18883 :     case EQUALITY_FALSE: CVC5_FALLTHROUGH;
     925                 :            :     case EQUALITY_FALSE_IN_MODEL:
     926                 :            :       // This is unlikely, but I think it could happen
     927         [ +  - ]:      18883 :       Trace("arrays::sharing") << "TheoryArrays::computeCareGraph(): checkPair called when false in model" << std::endl;
     928                 :      18883 :       return;
     929                 :       7797 :     default:
     930                 :            :       // Covers EQUALITY_TRUE_IN_MODEL (common case) and EQUALITY_UNKNOWN
     931                 :       7797 :       break;
     932                 :            :   }
     933                 :            : 
     934                 :            :   // Add this pair
     935         [ +  - ]:       7797 :   Trace("arrays::sharing") << "TheoryArrays::computeCareGraph(): adding to care-graph" << std::endl;
     936                 :       7797 :   addCarePair(x_shared, y_shared);
     937                 :            : }
     938                 :            : 
     939                 :            : 
     940                 :      28217 : void TheoryArrays::computeCareGraph()
     941                 :            : {
     942         [ +  + ]:      28217 :   if (d_sharedArrays.size() > 0) {
     943                 :        753 :     CDNodeSet::key_iterator it1 = d_sharedArrays.key_begin(), it2, iend = d_sharedArrays.key_end();
     944         [ +  + ]:       3119 :     for (; it1 != iend; ++it1) {
     945         [ +  + ]:      16232 :       for (it2 = it1, ++it2; it2 != iend; ++it2) {
     946         [ +  + ]:      13866 :         if ((*it1).getType() != (*it2).getType()) {
     947                 :       4696 :           continue;
     948                 :            :         }
     949                 :       9170 :         EqualityStatus eqStatusArr = getEqualityStatus((*it1), (*it2));
     950         [ +  + ]:       9170 :         if (eqStatusArr != EQUALITY_UNKNOWN) {
     951                 :       8974 :           continue;
     952                 :            :         }
     953 [ -  + ][ -  + ]:        196 :         Assert(d_valuation.getEqualityStatus((*it1), (*it2))
                 [ -  - ]
     954                 :            :                == EQUALITY_UNKNOWN);
     955                 :        196 :         addCarePair((*it1), (*it2));
     956                 :        196 :         ++d_numSharedArrayVarSplits;
     957                 :        196 :         return;
     958                 :            :       }
     959                 :            :     }
     960                 :            :   }
     961         [ +  + ]:      28021 :   if (d_sharedTerms) {
     962                 :            :     // Synchronize d_constReadsContext with SAT context
     963 [ -  + ][ -  + ]:       1331 :     Assert(d_constReadsContext->getLevel() <= context()->getLevel());
                 [ -  - ]
     964         [ +  + ]:      20562 :     while (d_constReadsContext->getLevel() < context()->getLevel())
     965                 :            :     {
     966                 :      19231 :       d_constReadsContext->push();
     967                 :            :     }
     968                 :            : 
     969                 :            :     // Go through the read terms and see if there are any to split on
     970                 :            : 
     971                 :            :     // Give constReadsContext a push so that all the work it does here is erased - models can change if context changes at all
     972                 :            :     // The context is popped at the end.  If this loop is interrupted for some reason, we have to make sure the context still
     973                 :            :     // gets popped or the solver will be in an inconsistent state
     974                 :       1331 :     d_constReadsContext->push();
     975                 :       1331 :     unsigned size = d_reads.size();
     976         [ +  + ]:      18546 :     for (unsigned i = 0; i < size; ++ i) {
     977                 :      17215 :       TNode r1 = d_reads[i];
     978                 :            : 
     979         [ +  - ]:      17215 :       Trace("arrays::sharing") << "TheoryArrays::computeCareGraph(): checking read " << r1 << std::endl;
     980 [ -  + ][ -  + ]:      17215 :       Assert(d_equalityEngine->hasTerm(r1));
                 [ -  - ]
     981                 :      17215 :       TNode x = r1[1];
     982                 :            : 
     983         [ +  + ]:      17215 :       if (!d_equalityEngine->isTriggerTerm(x, THEORY_ARRAYS))
     984                 :            :       {
     985         [ +  - ]:        174 :         Trace("arrays::sharing") << "TheoryArrays::computeCareGraph(): not connected to shared terms, skipping" << std::endl;
     986                 :        174 :         continue;
     987                 :            :       }
     988                 :            :       Node x_shared =
     989                 :      51123 :           d_equalityEngine->getTriggerTermRepresentative(x, THEORY_ARRAYS);
     990                 :            : 
     991                 :            :       // Get the model value of index and find all reads that read from that same model value: these are the pairs we have to check
     992                 :            :       // Also, insert this read in the list at the proper index
     993                 :            : 
     994         [ +  + ]:      17041 :       if (!x_shared.isConst()) {
     995                 :      12000 :         x_shared = d_valuation.getCandidateModelValue(x_shared);
     996                 :            :       }
     997         [ +  + ]:      17041 :       if (!x_shared.isNull()) {
     998                 :            :         CTNodeList* temp;
     999                 :      12730 :         CNodeNListMap::iterator it = d_constReads.find(x_shared);
    1000         [ +  + ]:      12730 :         if (it == d_constReads.end()) {
    1001                 :            :           // This is the only x_shared with this model value - no need to create any splits
    1002                 :        353 :           temp = new(true) CTNodeList(d_constReadsContext);
    1003                 :        353 :           d_constReads[x_shared] = temp;
    1004                 :            :         }
    1005                 :            :         else {
    1006                 :      12377 :           temp = (*it).second;
    1007         [ +  + ]:     458033 :           for (size_t j = 0; j < temp->size(); ++j) {
    1008                 :     445656 :             checkPair(r1, (*temp)[j]);
    1009                 :            :           }
    1010                 :            :         }
    1011                 :      12730 :         temp->push_back(r1);
    1012                 :            :       }
    1013                 :            :       else {
    1014                 :            :         // We don't know the model value for x.  Just do brute force examination of all pairs of reads.
    1015                 :            :         // Note that we have to loop over *all* reads here, not just subsequent reads, because there
    1016                 :            :         // may be an earlier read that *does* have a model value.  So if we don't check here, the two
    1017                 :            :         // reads won't get compared.
    1018         [ +  + ]:     344248 :         for (unsigned j = 0; j < size; ++j)
    1019                 :            :         {
    1020                 :     339937 :           TNode r2 = d_reads[j];
    1021 [ -  + ][ -  + ]:     339937 :           Assert(d_equalityEngine->hasTerm(r2));
                 [ -  - ]
    1022                 :     339937 :           checkPair(r1,r2);
    1023                 :            :         }
    1024         [ +  + ]:      22342 :         for (unsigned j = 0; j < d_constReadsList.size(); ++j) {
    1025                 :      18031 :           TNode r2 = d_constReadsList[j];
    1026 [ -  + ][ -  + ]:      18031 :           Assert(d_equalityEngine->hasTerm(r2));
                 [ -  - ]
    1027                 :      18031 :           checkPair(r1,r2);
    1028                 :            :         }
    1029                 :            :       }
    1030                 :            :     }
    1031                 :       1331 :     d_constReadsContext->pop();
    1032                 :            :   }
    1033                 :            : }
    1034                 :            : 
    1035                 :            : 
    1036                 :            : /////////////////////////////////////////////////////////////////////////////
    1037                 :            : // MODEL GENERATION
    1038                 :            : /////////////////////////////////////////////////////////////////////////////
    1039                 :            : 
    1040                 :      14918 : bool TheoryArrays::collectModelValues(TheoryModel* m,
    1041                 :            :                                       const std::set<Node>& termSet)
    1042                 :            : {
    1043                 :            :   // termSet contains terms appearing in assertions and shared terms, and also
    1044                 :            :   // includes additional reads due to the RIntro1 and RIntro2 rules.
    1045                 :      14918 :   NodeManager* nm = nodeManager();
    1046                 :            :   // Compute arrays that we need to produce representatives for
    1047                 :      29836 :   std::vector<Node> arrays;
    1048                 :            : 
    1049                 :      14918 :   eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(d_equalityEngine);
    1050         [ +  + ]:      49313 :   for (; !eqcs_i.isFinished(); ++eqcs_i)
    1051                 :            :   {
    1052                 :      34395 :     Node eqc = (*eqcs_i);
    1053         [ +  + ]:      34395 :     if (!eqc.getType().isArray())
    1054                 :            :     {
    1055                 :            :       // not an array, skip
    1056                 :      33493 :       continue;
    1057                 :            :     }
    1058                 :        902 :     eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, d_equalityEngine);
    1059         [ +  + ]:       1199 :     for (; !eqc_i.isFinished(); ++eqc_i)
    1060                 :            :     {
    1061                 :        938 :       Node n = *eqc_i;
    1062                 :            :       // If this EC is an array type and it contains something other than STORE
    1063                 :            :       // nodes, we have to compute a representative explicitly
    1064         [ +  + ]:        938 :       if (termSet.find(n) != termSet.end())
    1065                 :            :       {
    1066         [ +  + ]:        900 :         if (n.getKind() != Kind::STORE)
    1067                 :            :         {
    1068                 :        641 :           arrays.push_back(n);
    1069                 :        641 :           break;
    1070                 :            :         }
    1071                 :            :       }
    1072                 :            :     }
    1073                 :            :   }
    1074                 :            : 
    1075                 :            :   // Build a list of all the relevant reads, indexed by the store representative
    1076                 :      29836 :   std::map<Node, std::vector<Node> > selects;
    1077                 :      14918 :   set<Node>::iterator set_it = termSet.begin(), set_it_end = termSet.end();
    1078         [ +  + ]:      23324 :   for (; set_it != set_it_end; ++set_it)
    1079                 :            :   {
    1080                 :      16812 :     Node n = *set_it;
    1081                 :            :     // If this term is a select, record that the EC rep of its store parameter
    1082                 :            :     // is being read from using this term
    1083         [ +  + ]:       8406 :     if (n.getKind() == Kind::SELECT)
    1084                 :            :     {
    1085                 :       3581 :       selects[d_equalityEngine->getRepresentative(n[0])].push_back(n);
    1086                 :            :     }
    1087                 :            :   }
    1088                 :            : 
    1089                 :      29836 :   Node rep;
    1090                 :      14918 :   DefValMap::iterator it;
    1091                 :      29836 :   TypeSet defaultValuesSet;
    1092                 :            : 
    1093                 :            :   // Compute all default values already in use
    1094                 :            :   // if (fullModel) {
    1095         [ +  + ]:      15559 :   for (size_t i = 0; i < arrays.size(); ++i)
    1096                 :            :   {
    1097                 :       1282 :     TNode nrep = d_equalityEngine->getRepresentative(arrays[i]);
    1098                 :        641 :     d_mayEqualEqualityEngine.addTerm(
    1099                 :            :         nrep);  // add the term in case it isn't there already
    1100                 :       1282 :     TNode mayRep = d_mayEqualEqualityEngine.getRepresentative(nrep);
    1101                 :        641 :     it = d_defValues.find(mayRep);
    1102         [ +  + ]:        641 :     if (it != d_defValues.end())
    1103                 :            :     {
    1104                 :         87 :       defaultValuesSet.add(nrep.getType().getArrayConstituentType(),
    1105                 :         87 :                            (*it).second);
    1106                 :            :     }
    1107                 :            :   }
    1108                 :            :   //}
    1109                 :            : 
    1110                 :            :   // Loop through all array equivalence classes that need a representative
    1111                 :            :   // computed
    1112                 :            :   // The default values map for arrays not appearing in d_defValues. This map
    1113                 :            :   // is local to the current model.
    1114                 :      29836 :   std::map<Node, Node> defMap;
    1115                 :      14918 :   std::map<Node, Node>::iterator itd;
    1116         [ +  + ]:      15559 :   for (size_t i = 0; i < arrays.size(); ++i)
    1117                 :            :   {
    1118                 :        641 :     TNode n = arrays[i];
    1119                 :        641 :     TNode nrep = d_equalityEngine->getRepresentative(n);
    1120                 :            : 
    1121                 :            :     // if (fullModel) {
    1122                 :            :     // Compute default value for this array - there is one default value for
    1123                 :            :     // every mayEqual equivalence class
    1124                 :        641 :     TNode mayRep = d_mayEqualEqualityEngine.getRepresentative(nrep);
    1125                 :            :     // If this mayEqual EC doesn't have a default value associated, get the next
    1126                 :            :     // available default value for the associated array element type
    1127                 :        641 :     it = d_defValues.find(mayRep);
    1128         [ +  + ]:        641 :     if (it == d_defValues.end())
    1129                 :            :     {
    1130                 :        554 :       itd = defMap.find(mayRep);
    1131         [ +  + ]:        554 :       if (itd == defMap.end())
    1132                 :            :       {
    1133                 :        484 :         TypeNode valueType = nrep.getType().getArrayConstituentType();
    1134                 :        484 :         rep = defaultValuesSet.nextTypeEnum(valueType);
    1135         [ -  + ]:        484 :         if (rep.isNull())
    1136                 :            :         {
    1137                 :          0 :           Assert(defaultValuesSet.getSet(valueType)->begin()
    1138                 :            :                  != defaultValuesSet.getSet(valueType)->end());
    1139                 :          0 :           rep = *(defaultValuesSet.getSet(valueType)->begin());
    1140                 :            :         }
    1141         [ +  - ]:        484 :         Trace("arrays-models") << "New default value = " << rep << endl;
    1142                 :        484 :         defMap[mayRep] = rep;
    1143                 :            :       }
    1144                 :            :       else
    1145                 :            :       {
    1146                 :         70 :         rep = itd->second;
    1147                 :            :       }
    1148                 :            :     }
    1149                 :            :     else
    1150                 :            :     {
    1151                 :         87 :       rep = (*it).second;
    1152                 :            :     }
    1153                 :            : 
    1154                 :            :     // Build the STORE_ALL term with the default value
    1155                 :        641 :     rep = nm->mkConst(ArrayStoreAll(nrep.getType(), rep));
    1156                 :            : 
    1157                 :            :     // For each read, require that the rep stores the right value
    1158                 :        641 :     vector<Node>& reads = selects[nrep];
    1159         [ +  + ]:       3248 :     for (unsigned j = 0; j < reads.size(); ++j)
    1160                 :            :     {
    1161                 :       2607 :       rep = nm->mkNode(Kind::STORE, rep, reads[j][1], reads[j]);
    1162                 :            :     }
    1163         [ -  + ]:        641 :     if (!m->assertEquality(n, rep, true))
    1164                 :            :     {
    1165                 :          0 :       return false;
    1166                 :            :     }
    1167         [ +  + ]:        641 :     if (!n.isConst())
    1168                 :            :     {
    1169                 :        555 :       m->assertSkeleton(rep);
    1170                 :            :     }
    1171                 :            :   }
    1172                 :      14918 :   return true;
    1173                 :            : }
    1174                 :            : 
    1175                 :            : /////////////////////////////////////////////////////////////////////////////
    1176                 :            : // NOTIFICATIONS
    1177                 :            : /////////////////////////////////////////////////////////////////////////////
    1178                 :            : 
    1179                 :            : 
    1180                 :      50846 : void TheoryArrays::presolve()
    1181                 :            : {
    1182         [ +  - ]:      50846 :   Trace("arrays")<<"Presolving \n";
    1183         [ +  + ]:      50846 :   if (!d_dstratInit)
    1184                 :            :   {
    1185                 :      42098 :     d_dstratInit = true;
    1186                 :            :     // add the decision strategy, which is user-context-independent
    1187                 :      84196 :     d_im.getDecisionManager()->registerStrategy(
    1188                 :            :         DecisionManager::STRAT_ARRAYS,
    1189                 :      42098 :         d_dstrat.get(),
    1190                 :            :         DecisionManager::STRAT_SCOPE_CTX_INDEPENDENT);
    1191                 :            :   }
    1192                 :      50846 : }
    1193                 :            : 
    1194                 :            : 
    1195                 :            : /////////////////////////////////////////////////////////////////////////////
    1196                 :            : // MAIN SOLVER
    1197                 :            : /////////////////////////////////////////////////////////////////////////////
    1198                 :            : 
    1199                 :       3315 : Node TheoryArrays::getSkolem(TNode ref)
    1200                 :            : {
    1201                 :       3315 :   Node skolem = SkolemCache::getExtIndexSkolem(nodeManager(), ref);
    1202                 :            : 
    1203         [ +  - ]:       3315 :   Trace("pf::array") << "Pregistering a Skolem" << std::endl;
    1204                 :       3315 :   preRegisterTermInternal(skolem);
    1205         [ +  - ]:       3315 :   Trace("pf::array") << "Pregistering a Skolem DONE" << std::endl;
    1206                 :            : 
    1207         [ +  - ]:       3315 :   Trace("pf::array") << "getSkolem DONE" << std::endl;
    1208                 :       3315 :   return skolem;
    1209                 :            : }
    1210                 :            : 
    1211                 :     126790 : void TheoryArrays::postCheck(Effort level)
    1212                 :            : {
    1213                 :     126790 :   bool eagerLemmas = options().arrays.arraysEagerLemmas;
    1214                 :     126790 :   bool weakEquiv = options().arrays.arraysWeakEquivalence;
    1215                 :            : 
    1216 [ +  + ][ +  + ]:     126790 :   if ((eagerLemmas || fullEffort(level)) && !d_state.isInConflict()
    1217 [ +  + ][ -  + ]:     253580 :       && weakEquiv)
                 [ -  + ]
    1218                 :            :   {
    1219                 :            :     // Replay all array merges to update weak equivalence data structures
    1220                 :          0 :     context::CDList<Node>::iterator it = d_arrayMerges.begin(),
    1221                 :          0 :                                     iend = d_arrayMerges.end();
    1222                 :          0 :     TNode a, b, eq;
    1223         [ -  - ]:          0 :     for (; it != iend; ++it) {
    1224                 :          0 :       eq = *it;
    1225                 :          0 :       a = eq[0];
    1226                 :          0 :       b = eq[1];
    1227                 :          0 :       weakEquivMakeRep(b);
    1228         [ -  - ]:          0 :       if (weakEquivGetRep(a) == b) {
    1229                 :          0 :         weakEquivAddSecondary(TNode(), a, b, eq);
    1230                 :            :       }
    1231                 :            :       else {
    1232                 :          0 :         d_infoMap.setWeakEquivPointer(b, a);
    1233                 :          0 :         d_infoMap.setWeakEquivIndex(b, TNode());
    1234                 :            :       }
    1235                 :            : #ifdef CVC5_ASSERTIONS
    1236                 :          0 :       checkWeakEquiv(false);
    1237                 :            : #endif
    1238                 :            :     }
    1239                 :            : #ifdef CVC5_ASSERTIONS
    1240                 :          0 :     checkWeakEquiv(true);
    1241                 :            : #endif
    1242                 :            : 
    1243                 :          0 :     d_readTableContext->push();
    1244                 :          0 :     TNode mayRep, iRep;
    1245                 :          0 :     CTNodeList* bucketList = NULL;
    1246                 :          0 :     CTNodeList::const_iterator i = d_reads.begin(), readsEnd = d_reads.end();
    1247         [ -  - ]:          0 :     for (; i != readsEnd; ++i) {
    1248                 :          0 :       const TNode& r = *i;
    1249                 :            : 
    1250         [ -  - ]:          0 :       Trace("arrays::weak") << "TheoryArrays::check(): checking read " << r << std::endl;
    1251                 :            : 
    1252                 :            :       // Find the bucket for this read.
    1253                 :          0 :       mayRep = d_mayEqualEqualityEngine.getRepresentative(r[0]);
    1254                 :          0 :       iRep = d_equalityEngine->getRepresentative(r[1]);
    1255                 :          0 :       std::pair<TNode, TNode> key(mayRep, iRep);
    1256                 :          0 :       ReadBucketMap::iterator rbm_it = d_readBucketTable.find(key);
    1257         [ -  - ]:          0 :       if (rbm_it == d_readBucketTable.end())
    1258                 :            :       {
    1259                 :          0 :         bucketList = new(true) CTNodeList(d_readTableContext);
    1260                 :          0 :         d_readBucketAllocations.push_back(bucketList);
    1261                 :          0 :         d_readBucketTable[key] = bucketList;
    1262                 :            :       }
    1263                 :            :       else {
    1264                 :          0 :         bucketList = rbm_it->second;
    1265                 :            :       }
    1266                 :          0 :       CTNodeList::const_iterator ctnl_it = bucketList->begin(),
    1267                 :          0 :                                  ctnl_iend = bucketList->end();
    1268         [ -  - ]:          0 :       for (; ctnl_it != ctnl_iend; ++ctnl_it)
    1269                 :            :       {
    1270                 :          0 :         const TNode& r2 = *ctnl_it;
    1271                 :          0 :         Assert(r2.getKind() == Kind::SELECT);
    1272                 :          0 :         Assert(mayRep == d_mayEqualEqualityEngine.getRepresentative(r2[0]));
    1273                 :          0 :         Assert(iRep == d_equalityEngine->getRepresentative(r2[1]));
    1274         [ -  - ]:          0 :         if (d_equalityEngine->areEqual(r, r2))
    1275                 :            :         {
    1276                 :          0 :           continue;
    1277                 :            :         }
    1278         [ -  - ]:          0 :         if (weakEquivGetRepIndex(r[0], r[1]) == weakEquivGetRepIndex(r2[0], r[1])) {
    1279                 :            :           // add lemma: r[1] = r2[1] /\ cond(r[0],r2[0]) => r = r2
    1280                 :          0 :           vector<TNode> conjunctions;
    1281                 :          0 :           Assert(d_equalityEngine->areEqual(r, rewrite(r)));
    1282                 :          0 :           Assert(d_equalityEngine->areEqual(r2, rewrite(r2)));
    1283                 :          0 :           Node lemma = rewrite(r).eqNode(rewrite(r2)).negate();
    1284                 :          0 :           d_permRef.push_back(lemma);
    1285                 :          0 :           conjunctions.push_back(lemma);
    1286         [ -  - ]:          0 :           if (r[1] != r2[1]) {
    1287                 :          0 :             d_equalityEngine->explainEquality(r[1], r2[1], true, conjunctions);
    1288                 :            :           }
    1289                 :            :           // TODO: get smaller lemmas by eliminating shared parts of path
    1290                 :          0 :           weakEquivBuildCond(r[0], r[1], conjunctions);
    1291                 :          0 :           weakEquivBuildCond(r2[0], r[1], conjunctions);
    1292                 :          0 :           lemma = mkAnd(conjunctions, true);
    1293                 :            :           // LSH FIXME: which kind of arrays lemma is this
    1294         [ -  - ]:          0 :           Trace("arrays-lem")
    1295                 :          0 :               << "Arrays::addExtLemma (weak-eq) " << lemma << "\n";
    1296                 :          0 :           d_out->lemma(lemma, InferenceId::NONE, LemmaProperty::SEND_ATOMS);
    1297                 :          0 :           d_readTableContext->pop();
    1298                 :          0 :           Trace("arrays") << spaces(context()->getLevel())
    1299                 :          0 :                           << "Arrays::check(): done" << endl;
    1300                 :          0 :           return;
    1301                 :            :         }
    1302                 :            :       }
    1303                 :          0 :       bucketList->push_back(r);
    1304                 :            :     }
    1305                 :          0 :     d_readTableContext->pop();
    1306                 :            :   }
    1307                 :            : 
    1308 [ +  + ][ +  + ]:     126764 :   if (!eagerLemmas && fullEffort(level) && !d_state.isInConflict()
    1309 [ +  + ][ +  - ]:     253554 :       && !weakEquiv)
                 [ +  + ]
    1310                 :            :   {
    1311                 :            :     // generate the lemmas on the worklist
    1312         [ +  - ]:      69008 :     Trace("arrays-lem")<< "Arrays::discharging lemmas. Number of queued lemmas: " << d_RowQueue.size() << "\n";
    1313 [ +  + ][ +  - ]:      69353 :     while (d_RowQueue.size() > 0 && !d_state.isInConflict())
                 [ +  + ]
    1314                 :            :     {
    1315         [ +  + ]:       1658 :       if (dischargeLemmas()) {
    1316                 :       1313 :         break;
    1317                 :            :       }
    1318                 :            :     }
    1319                 :            :   }
    1320                 :            : 
    1321 [ +  - ][ -  + ]:     253580 :   Trace("arrays") << spaces(context()->getLevel()) << "Arrays::check(): done"
                 [ -  - ]
    1322                 :     126790 :                   << endl;
    1323                 :            : }
    1324                 :            : 
    1325                 :     175975 : bool TheoryArrays::preNotifyFact(
    1326                 :            :     TNode atom, bool pol, TNode fact, bool isPrereg, bool isInternal)
    1327                 :            : {
    1328 [ +  + ][ +  + ]:     175975 :   if (!isInternal && !isPrereg)
    1329                 :            :   {
    1330         [ +  + ]:     117421 :     if (atom.getKind() == Kind::EQUAL)
    1331                 :            :     {
    1332         [ +  + ]:     117297 :       if (!d_equalityEngine->hasTerm(atom[0]))
    1333                 :            :       {
    1334 [ -  + ][ -  + ]:       2307 :         Assert(atom[0].isConst());
                 [ -  - ]
    1335                 :       2307 :         d_equalityEngine->addTerm(atom[0]);
    1336                 :            :       }
    1337         [ +  + ]:     117297 :       if (!d_equalityEngine->hasTerm(atom[1]))
    1338                 :            :       {
    1339 [ -  + ][ -  + ]:        460 :         Assert(atom[1].isConst());
                 [ -  - ]
    1340                 :        460 :         d_equalityEngine->addTerm(atom[1]);
    1341                 :            :       }
    1342                 :            :     }
    1343                 :            :   }
    1344                 :     175975 :   return false;
    1345                 :            : }
    1346                 :            : 
    1347                 :     175972 : void TheoryArrays::notifyFact(TNode atom, bool pol, TNode fact, bool isInternal)
    1348                 :            : {
    1349                 :            :   // if a disequality
    1350 [ +  + ][ +  + ]:     175972 :   if (atom.getKind() == Kind::EQUAL && !pol && !isInternal)
         [ +  + ][ +  + ]
    1351                 :            :   {
    1352                 :            :     // Notice that this should be an external assertion, since we do not
    1353                 :            :     // internally infer disequalities.
    1354                 :            :     // Apply ArrDiseq Rule if diseq is between arrays
    1355                 :      43055 :     if (fact[0][0].getType().isArray() && !d_state.isInConflict())
    1356                 :            :     {
    1357                 :       3315 :       NodeManager* nm = nodeManager();
    1358                 :            : 
    1359                 :       6630 :       TNode k;
    1360                 :            :       // k is the skolem for this disequality.
    1361         [ +  - ]:       6630 :       Trace("pf::array") << "Check: Kind::NOT: array theory making a skolem"
    1362                 :       3315 :                          << std::endl;
    1363                 :            : 
    1364                 :            :       // If not in replay mode, generate a fresh skolem variable
    1365                 :       3315 :       k = getSkolem(fact);
    1366                 :            : 
    1367                 :       9945 :       Node ak = nm->mkNode(Kind::SELECT, fact[0][0], k);
    1368                 :       9945 :       Node bk = nm->mkNode(Kind::SELECT, fact[0][1], k);
    1369                 :       6630 :       Node eq = ak.eqNode(bk);
    1370                 :       9945 :       Node lemma = fact[0].orNode(eq.notNode());
    1371                 :            : 
    1372 [ +  + ][ +  + ]:       6630 :       if (options().arrays.arraysPropagate > 0 && d_equalityEngine->hasTerm(ak)
                 [ -  - ]
    1373 [ +  - ][ +  - ]:       6630 :           && d_equalityEngine->hasTerm(bk))
         [ +  + ][ +  - ]
                 [ -  - ]
    1374                 :            :       {
    1375                 :            :         // Propagate witness disequality - might produce a conflict
    1376         [ +  - ]:       5158 :         Trace("pf::array") << "Asserting to the equality engine:" << std::endl
    1377                 :          0 :                            << "\teq = " << eq << std::endl
    1378                 :       2579 :                            << "\treason = " << fact << std::endl;
    1379                 :       2579 :         d_im.assertInference(
    1380                 :            :             eq, false, InferenceId::ARRAYS_EXT, fact, ProofRule::ARRAYS_EXT);
    1381                 :       2579 :         ++d_numProp;
    1382                 :            :       }
    1383                 :            : 
    1384                 :            :       // If this is the solution pass, generate the lemma. Otherwise, don't
    1385                 :            :       // generate it - as this is the lemma that we're reproving...
    1386         [ +  - ]:       3315 :       Trace("arrays-lem") << "Arrays::addExtLemma " << lemma << "\n";
    1387                 :       6630 :       d_im.arrayLemma(
    1388                 :       6630 :           eq.notNode(), InferenceId::ARRAYS_EXT, fact, ProofRule::ARRAYS_EXT);
    1389                 :       3315 :       ++d_numExt;
    1390                 :            :     }
    1391                 :            :     else
    1392                 :            :     {
    1393         [ +  - ]:      79480 :       Trace("pf::array") << "Check: Kind::NOT: array theory NOT making a skolem"
    1394                 :      39740 :                          << std::endl;
    1395                 :      39740 :       d_modelConstraints.push_back(fact);
    1396                 :            :     }
    1397                 :            :   }
    1398                 :     175972 : }
    1399                 :            : 
    1400                 :          0 : Node TheoryArrays::mkAnd(std::vector<TNode>& conjunctions, bool invert, unsigned startIndex)
    1401                 :            : {
    1402         [ -  - ]:          0 :   if (conjunctions.empty())
    1403                 :            :   {
    1404         [ -  - ]:          0 :     return invert ? d_false : d_true;
    1405                 :            :   }
    1406                 :            : 
    1407                 :          0 :   std::set<TNode> all;
    1408                 :            : 
    1409                 :          0 :   unsigned i = startIndex;
    1410                 :          0 :   TNode t;
    1411         [ -  - ]:          0 :   for (; i < conjunctions.size(); ++i) {
    1412                 :          0 :     t = conjunctions[i];
    1413         [ -  - ]:          0 :     if (t == d_true) {
    1414                 :          0 :       continue;
    1415                 :            :     }
    1416         [ -  - ]:          0 :     else if (t.getKind() == Kind::AND)
    1417                 :            :     {
    1418         [ -  - ]:          0 :       for(TNode::iterator child_it = t.begin(); child_it != t.end(); ++child_it) {
    1419         [ -  - ]:          0 :         if (*child_it == d_true) {
    1420                 :          0 :           continue;
    1421                 :            :         }
    1422                 :          0 :         all.insert(*child_it);
    1423                 :            :       }
    1424                 :            :     }
    1425                 :            :     else {
    1426                 :          0 :       all.insert(t);
    1427                 :            :     }
    1428                 :            :   }
    1429                 :            : 
    1430         [ -  - ]:          0 :   if (all.size() == 0) {
    1431         [ -  - ]:          0 :     return invert ? d_false : d_true;
    1432                 :            :   }
    1433         [ -  - ]:          0 :   if (all.size() == 1) {
    1434                 :            :     // All the same, or just one
    1435         [ -  - ]:          0 :     if (invert) {
    1436                 :          0 :       return (*(all.begin())).negate();
    1437                 :            :     }
    1438                 :            :     else {
    1439                 :          0 :       return *(all.begin());
    1440                 :            :     }
    1441                 :            :   }
    1442                 :            : 
    1443         [ -  - ]:          0 :   NodeBuilder conjunction(nodeManager(), invert ? Kind::OR : Kind::AND);
    1444                 :          0 :   std::set<TNode>::const_iterator it = all.begin();
    1445                 :          0 :   std::set<TNode>::const_iterator it_end = all.end();
    1446         [ -  - ]:          0 :   while (it != it_end) {
    1447         [ -  - ]:          0 :     if (invert) {
    1448                 :          0 :       conjunction << (*it).negate();
    1449                 :            :     }
    1450                 :            :     else {
    1451                 :          0 :       conjunction << *it;
    1452                 :            :     }
    1453                 :          0 :     ++ it;
    1454                 :            :   }
    1455                 :            : 
    1456                 :          0 :   return conjunction;
    1457                 :            : }
    1458                 :            : 
    1459                 :            : 
    1460                 :       3518 : void TheoryArrays::setNonLinear(TNode a)
    1461                 :            : {
    1462         [ -  + ]:       3985 :   if (options().arrays.arraysWeakEquivalence) return;
    1463         [ +  + ]:       3518 :   if (d_infoMap.isNonLinear(a)) return;
    1464                 :            : 
    1465 [ +  - ][ -  + ]:       6102 :   Trace("arrays") << spaces(context()->getLevel()) << "Arrays::setNonLinear ("
                 [ -  - ]
    1466                 :       3051 :                   << a << ")\n";
    1467                 :       3051 :   d_infoMap.setNonLinear(a);
    1468                 :       3051 :   ++d_numNonLinear;
    1469                 :            : 
    1470                 :       3051 :   const CTNodeList* i_a = d_infoMap.getIndices(a);
    1471                 :       3051 :   const CTNodeList* st_a = d_infoMap.getStores(a);
    1472                 :       3051 :   const CTNodeList* inst_a = d_infoMap.getInStores(a);
    1473                 :            : 
    1474                 :       3051 :   size_t it = 0;
    1475                 :            : 
    1476                 :            :   // Propagate non-linearity down chain of stores
    1477         [ +  + ]:       5271 :   for( ; it < st_a->size(); ++it) {
    1478                 :       2220 :     TNode store = (*st_a)[it];
    1479 [ -  + ][ -  + ]:       2220 :     Assert(store.getKind() == Kind::STORE);
                 [ -  - ]
    1480                 :       2220 :     setNonLinear(store[0]);
    1481                 :            :   }
    1482                 :            : 
    1483                 :            :   // Instantiate ROW lemmas that were ignored before
    1484                 :       3051 :   size_t it2 = 0;
    1485                 :       6102 :   RowLemmaType lem;
    1486         [ +  + ]:      20521 :   for(; it2 < i_a->size(); ++it2) {
    1487                 :      34940 :     TNode i = (*i_a)[it2];
    1488                 :      17470 :     it = 0;
    1489         [ +  + ]:      33591 :     for ( ; it < inst_a->size(); ++it) {
    1490                 :      32242 :       TNode store = (*inst_a)[it];
    1491 [ -  + ][ -  + ]:      16121 :       Assert(store.getKind() == Kind::STORE);
                 [ -  - ]
    1492                 :      32242 :       TNode j = store[1];
    1493                 :      16121 :       TNode c = store[0];
    1494                 :      16121 :       lem = std::make_tuple(store, c, j, i);
    1495 [ +  - ][ -  + ]:      32242 :       Trace("arrays-lem") << spaces(context()->getLevel())
                 [ -  - ]
    1496                 :          0 :                           << "Arrays::setNonLinear (" << store << ", " << c
    1497                 :      16121 :                           << ", " << j << ", " << i << ")\n";
    1498                 :      16121 :       queueRowLemma(lem);
    1499                 :            :     }
    1500                 :            :   }
    1501                 :            : 
    1502                 :            : }
    1503                 :            : 
    1504                 :       7721 : void TheoryArrays::mergeArrays(TNode a, TNode b)
    1505                 :            : {
    1506                 :            :   // Note: a is the new representative
    1507                 :      15442 :   Assert(a.getType().isArray() && b.getType().isArray());
    1508                 :            : 
    1509         [ -  + ]:       7721 :   if (d_mergeInProgress) {
    1510                 :            :     // Nested call to mergeArrays, just push on the queue and return
    1511                 :          0 :     d_mergeQueue.push(a.eqNode(b));
    1512                 :          0 :     return;
    1513                 :            :   }
    1514                 :            : 
    1515                 :       7721 :   d_mergeInProgress = true;
    1516                 :       7721 :   bool optLinear = options().arrays.arraysOptimizeLinear;
    1517                 :       7721 :   bool weakEquiv = options().arrays.arraysWeakEquivalence;
    1518                 :            : 
    1519                 :       7724 :   Node n;
    1520                 :            :   while (true) {
    1521                 :            :     // Normally, a is its own representative, but it's possible for a to have
    1522                 :            :     // been merged with another array after it got queued up by the equality engine,
    1523                 :            :     // so we take its representative to be safe.
    1524                 :       7721 :     a = d_equalityEngine->getRepresentative(a);
    1525 [ -  + ][ -  + ]:       7721 :     Assert(d_equalityEngine->getRepresentative(b) == a);
                 [ -  - ]
    1526 [ +  - ][ -  + ]:      15442 :     Trace("arrays-merge") << spaces(context()->getLevel()) << "Arrays::merge: ("
                 [ -  - ]
    1527                 :       7721 :                           << a << ", " << b << ")\n";
    1528                 :            : 
    1529 [ +  + ][ +  - ]:       7721 :     if (optLinear && !weakEquiv)
    1530                 :            :     {
    1531                 :       6071 :       bool aNL = d_infoMap.isNonLinear(a);
    1532                 :       6071 :       bool bNL = d_infoMap.isNonLinear(b);
    1533         [ +  + ]:       6071 :       if (aNL) {
    1534         [ +  + ]:        426 :         if (bNL) {
    1535                 :            :           // already both marked as non-linear - no need to do anything
    1536                 :            :         }
    1537                 :            :         else {
    1538                 :            :           // Set b to be non-linear
    1539                 :        370 :           setNonLinear(b);
    1540                 :            :         }
    1541                 :            :       }
    1542                 :            :       else {
    1543         [ +  + ]:       5645 :         if (bNL) {
    1544                 :            :           // Set a to be non-linear
    1545                 :         63 :           setNonLinear(a);
    1546                 :            :         }
    1547                 :            :         else {
    1548                 :            :           // Check for new non-linear arrays
    1549                 :       5582 :           const CTNodeList* astores = d_infoMap.getStores(a);
    1550                 :       5582 :           const CTNodeList* bstores = d_infoMap.getStores(b);
    1551 [ +  - ][ +  - ]:      11164 :           Assert(astores->size() <= 1 && bstores->size() <= 1);
         [ -  + ][ -  - ]
    1552 [ +  + ][ +  + ]:       5582 :           if (astores->size() > 0 && bstores->size() > 0) {
                 [ +  + ]
    1553                 :        411 :             setNonLinear(a);
    1554                 :        411 :             setNonLinear(b);
    1555                 :            :           }
    1556                 :            :         }
    1557                 :            :       }
    1558                 :            :     }
    1559                 :            : 
    1560                 :       7724 :     TNode constArrA = d_infoMap.getConstArr(a);
    1561                 :       7724 :     TNode constArrB = d_infoMap.getConstArr(b);
    1562         [ +  + ]:       7721 :     if (constArrA.isNull()) {
    1563         [ -  + ]:       7638 :       if (!constArrB.isNull()) {
    1564                 :          0 :         d_infoMap.setConstArr(a,constArrB);
    1565                 :            :       }
    1566                 :            :     }
    1567         [ -  + ]:         83 :     else if (!constArrB.isNull()) {
    1568         [ -  - ]:          0 :       if (constArrA != constArrB) {
    1569                 :          0 :         conflict(constArrA,constArrB);
    1570                 :            :       }
    1571                 :            :     }
    1572                 :            : 
    1573                 :       7724 :     TNode mayRepA = d_mayEqualEqualityEngine.getRepresentative(a);
    1574                 :       7724 :     TNode mayRepB = d_mayEqualEqualityEngine.getRepresentative(b);
    1575                 :            : 
    1576                 :            :     // If a and b have different default values associated with their mayequal equivalence classes,
    1577                 :            :     // things get complicated.  Similarly, if two mayequal equivalence classes have different
    1578                 :            :     // constant representatives, it's not clear what to do. - disallow these cases for now.  -Clark
    1579                 :       7721 :     DefValMap::iterator it = d_defValues.find(mayRepA);
    1580                 :       7721 :     DefValMap::iterator it2 = d_defValues.find(mayRepB);
    1581                 :       7724 :     TNode defValue;
    1582                 :            : 
    1583         [ +  + ]:       7721 :     if (it != d_defValues.end()) {
    1584                 :         88 :       defValue = (*it).second;
    1585 [ +  + ][ +  + ]:        174 :       if ((it2 != d_defValues.end() && (defValue != (*it2).second)) ||
                 [ +  + ]
    1586 [ +  - ][ +  + ]:         86 :           (mayRepA.isConst() && mayRepB.isConst() && mayRepA != mayRepB)) {
                 [ +  - ]
    1587                 :          3 :         throw LogicException("Array theory solver does not yet support write-chains connecting two different constant arrays");
    1588                 :            :       }
    1589                 :            :     }
    1590         [ -  + ]:       7633 :     else if (it2 != d_defValues.end()) {
    1591                 :          0 :       defValue = (*it2).second;
    1592                 :            :     }
    1593                 :       7718 :     d_mayEqualEqualityEngine.assertEquality(a.eqNode(b), true, d_true);
    1594 [ -  + ][ -  + ]:       7718 :     Assert(d_mayEqualEqualityEngine.consistent());
                 [ -  - ]
    1595         [ +  + ]:       7718 :     if (!defValue.isNull()) {
    1596                 :         85 :       mayRepA = d_mayEqualEqualityEngine.getRepresentative(a);
    1597                 :         85 :       d_defValues[mayRepA] = defValue;
    1598                 :            :     }
    1599                 :            : 
    1600                 :       7718 :     checkRowLemmas(a,b);
    1601                 :       7718 :     checkRowLemmas(b,a);
    1602                 :            : 
    1603                 :            :     // merge info adds the list of the 2nd argument to the first
    1604                 :       7718 :     d_infoMap.mergeInfo(a, b);
    1605                 :            : 
    1606         [ -  + ]:       7718 :     if (weakEquiv)
    1607                 :            :     {
    1608                 :          0 :       d_arrayMerges.push_back(a.eqNode(b));
    1609                 :            :     }
    1610                 :            : 
    1611                 :            :     // If no more to do, break
    1612 [ +  - ][ +  - ]:       7718 :     if (d_state.isInConflict() || d_mergeQueue.empty())
                 [ +  - ]
    1613                 :            :     {
    1614                 :       7718 :       break;
    1615                 :            :     }
    1616                 :            : 
    1617                 :            :     // Otherwise, prepare for next iteration
    1618                 :          0 :     n = d_mergeQueue.front();
    1619                 :          0 :     a = n[0];
    1620                 :          0 :     b = n[1];
    1621                 :          0 :     d_mergeQueue.pop();
    1622                 :          0 :   }
    1623                 :       7718 :   d_mergeInProgress = false;
    1624                 :            : }
    1625                 :            : 
    1626                 :       2124 : void TheoryArrays::checkStore(TNode a)
    1627                 :            : {
    1628         [ -  + ]:       2124 :   if (options().arrays.arraysWeakEquivalence) return;
    1629                 :            : 
    1630         [ +  - ]:       2124 :   Trace("arrays-cri")<<"Arrays::checkStore "<<a<<"\n";
    1631                 :            : 
    1632         [ -  + ]:       2124 :   if(TraceIsOn("arrays-cri")) {
    1633                 :          0 :     d_infoMap.getInfo(a)->print();
    1634                 :            :   }
    1635 [ -  + ][ -  + ]:       2124 :   Assert(a.getType().isArray());
                 [ -  - ]
    1636 [ -  + ][ -  + ]:       2124 :   Assert(a.getKind() == Kind::STORE);
                 [ -  - ]
    1637                 :       4248 :   TNode b = a[0];
    1638                 :       4248 :   TNode i = a[1];
    1639                 :            : 
    1640                 :       4248 :   TNode brep = d_equalityEngine->getRepresentative(b);
    1641                 :            : 
    1642 [ +  + ][ +  + ]:       2124 :   if (!options().arrays.arraysOptimizeLinear || d_infoMap.isNonLinear(brep))
         [ +  + ][ +  + ]
                 [ -  - ]
    1643                 :            :   {
    1644                 :        460 :     const CTNodeList* js = d_infoMap.getIndices(brep);
    1645                 :        460 :     size_t it = 0;
    1646                 :        920 :     RowLemmaType lem;
    1647         [ +  + ]:        792 :     for(; it < js->size(); ++it) {
    1648                 :        332 :       TNode j = (*js)[it];
    1649         [ +  + ]:        332 :       if (i == j) continue;
    1650                 :        291 :       lem = std::make_tuple(a, b, i, j);
    1651 [ +  - ][ -  + ]:        582 :       Trace("arrays-lem") << spaces(context()->getLevel())
                 [ -  - ]
    1652                 :          0 :                           << "Arrays::checkStore (" << a << ", " << b << ", "
    1653                 :        291 :                           << i << ", " << j << ")\n";
    1654                 :        291 :       queueRowLemma(lem);
    1655                 :            :     }
    1656                 :            :   }
    1657                 :            : }
    1658                 :            : 
    1659                 :      35940 : void TheoryArrays::checkRowForIndex(TNode i, TNode a)
    1660                 :            : {
    1661         [ -  + ]:      35940 :   if (options().arrays.arraysWeakEquivalence) return;
    1662                 :            : 
    1663         [ +  - ]:      35940 :   Trace("arrays-cri")<<"Arrays::checkRowForIndex "<<a<<"\n";
    1664         [ +  - ]:      35940 :   Trace("arrays-cri")<<"                   index "<<i<<"\n";
    1665                 :            : 
    1666         [ -  + ]:      35940 :   if(TraceIsOn("arrays-cri")) {
    1667                 :          0 :     d_infoMap.getInfo(a)->print();
    1668                 :            :   }
    1669 [ -  + ][ -  + ]:      35940 :   Assert(a.getType().isArray());
                 [ -  - ]
    1670 [ -  + ][ -  + ]:      35940 :   Assert(d_equalityEngine->getRepresentative(a) == a);
                 [ -  - ]
    1671                 :            : 
    1672                 :      71880 :   TNode constArr = d_infoMap.getConstArr(a);
    1673         [ +  + ]:      35940 :   if (!constArr.isNull()) {
    1674                 :       1408 :     ArrayStoreAll storeAll = constArr.getConst<ArrayStoreAll>();
    1675                 :       1408 :     Node defValue = storeAll.getValue();
    1676                 :       1408 :     Node selConst = nodeManager()->mkNode(Kind::SELECT, constArr, i);
    1677         [ +  + ]:        704 :     if (!d_equalityEngine->hasTerm(selConst))
    1678                 :            :     {
    1679                 :         20 :       preRegisterTermInternal(selConst);
    1680                 :            :     }
    1681                 :            :     // not currently supported in proofs, use TRUST
    1682                 :        704 :     d_im.assertInference(selConst.eqNode(defValue),
    1683                 :            :                          true,
    1684                 :            :                          InferenceId::ARRAYS_CONST_ARRAY_DEFAULT,
    1685                 :        704 :                          d_true,
    1686                 :            :                          ProofRule::TRUST);
    1687                 :            :   }
    1688                 :            : 
    1689                 :      35940 :   const CTNodeList* stores = d_infoMap.getStores(a);
    1690                 :      35940 :   const CTNodeList* instores = d_infoMap.getInStores(a);
    1691                 :      35940 :   size_t it = 0;
    1692                 :      71880 :   RowLemmaType lem;
    1693                 :            : 
    1694         [ +  + ]:      58198 :   for(; it < stores->size(); ++it) {
    1695                 :      22258 :     TNode store = (*stores)[it];
    1696 [ -  + ][ -  + ]:      22258 :     Assert(store.getKind() == Kind::STORE);
                 [ -  - ]
    1697                 :      22258 :     TNode j = store[1];
    1698         [ +  + ]:      22258 :     if (i == j) continue;
    1699                 :      21888 :     lem = std::make_tuple(store, store[0], j, i);
    1700 [ +  - ][ -  - ]:      43776 :     Trace("arrays-lem") << spaces(context()->getLevel())
    1701                 :          0 :                         << "Arrays::checkRowForIndex (" << store << ", "
    1702 [ -  + ][ -  + ]:      21888 :                         << store[0] << ", " << j << ", " << i << ")\n";
                 [ -  - ]
    1703                 :      21888 :     queueRowLemma(lem);
    1704                 :            :   }
    1705                 :            : 
    1706 [ +  + ][ +  + ]:      35940 :   if (!options().arrays.arraysOptimizeLinear || d_infoMap.isNonLinear(a))
         [ +  + ][ +  + ]
                 [ -  - ]
    1707                 :            :   {
    1708                 :      10206 :     it = 0;
    1709         [ +  + ]:      18222 :     for(; it < instores->size(); ++it) {
    1710                 :       8016 :       TNode instore = (*instores)[it];
    1711 [ -  + ][ -  + ]:       8016 :       Assert(instore.getKind() == Kind::STORE);
                 [ -  - ]
    1712                 :       8016 :       TNode j = instore[1];
    1713         [ +  + ]:       8016 :       if (i == j) continue;
    1714                 :       7348 :       lem = std::make_tuple(instore, instore[0], j, i);
    1715 [ +  - ][ -  - ]:      14696 :       Trace("arrays-lem") << spaces(context()->getLevel())
    1716                 :          0 :                           << "Arrays::checkRowForIndex (" << instore << ", "
    1717 [ -  + ][ -  + ]:       7348 :                           << instore[0] << ", " << j << ", " << i << ")\n";
                 [ -  - ]
    1718                 :       7348 :       queueRowLemma(lem);
    1719                 :            :     }
    1720                 :            :   }
    1721                 :            : }
    1722                 :            : 
    1723                 :            : 
    1724                 :            : // a just became equal to b
    1725                 :            : // look for new ROW lemmas
    1726                 :      15436 : void TheoryArrays::checkRowLemmas(TNode a, TNode b)
    1727                 :            : {
    1728         [ -  + ]:      15436 :   if (options().arrays.arraysWeakEquivalence) return;
    1729                 :            : 
    1730         [ +  - ]:      15436 :   Trace("arrays-crl")<<"Arrays::checkLemmas begin \n"<<a<<"\n";
    1731         [ -  + ]:      15436 :   if(TraceIsOn("arrays-crl"))
    1732                 :          0 :     d_infoMap.getInfo(a)->print();
    1733         [ +  - ]:      15436 :   Trace("arrays-crl")<<"  ------------  and "<<b<<"\n";
    1734         [ -  + ]:      15436 :   if(TraceIsOn("arrays-crl"))
    1735                 :          0 :     d_infoMap.getInfo(b)->print();
    1736                 :            : 
    1737                 :      15436 :   const CTNodeList* i_a = d_infoMap.getIndices(a);
    1738                 :      15436 :   size_t it = 0;
    1739                 :      30872 :   TNode constArr = d_infoMap.getConstArr(b);
    1740         [ +  + ]:      15436 :   if (!constArr.isNull()) {
    1741         [ +  + ]:        739 :     for( ; it < i_a->size(); ++it) {
    1742                 :       1312 :       TNode i = (*i_a)[it];
    1743                 :       1968 :       Node selConst = nodeManager()->mkNode(Kind::SELECT, constArr, i);
    1744         [ +  - ]:        656 :       if (!d_equalityEngine->hasTerm(selConst))
    1745                 :            :       {
    1746                 :        656 :         preRegisterTermInternal(selConst);
    1747                 :            :       }
    1748                 :            :     }
    1749                 :            :   }
    1750                 :            : 
    1751                 :      15436 :   const CTNodeList* st_b = d_infoMap.getStores(b);
    1752                 :      15436 :   const CTNodeList* inst_b = d_infoMap.getInStores(b);
    1753                 :            :   size_t its;
    1754                 :            : 
    1755                 :      15436 :   RowLemmaType lem;
    1756                 :            : 
    1757         [ +  + ]:      82070 :   for(it = 0 ; it < i_a->size(); ++it) {
    1758                 :     133268 :     TNode i = (*i_a)[it];
    1759                 :      66634 :     its = 0;
    1760         [ +  + ]:     102975 :     for ( ; its < st_b->size(); ++its) {
    1761                 :      72682 :       TNode store = (*st_b)[its];
    1762 [ -  + ][ -  + ]:      36341 :       Assert(store.getKind() == Kind::STORE);
                 [ -  - ]
    1763                 :      72682 :       TNode j = store[1];
    1764                 :      36341 :       TNode c = store[0];
    1765                 :      36341 :       lem = std::make_tuple(store, c, j, i);
    1766 [ +  - ][ -  + ]:      72682 :       Trace("arrays-lem") << spaces(context()->getLevel())
                 [ -  - ]
    1767                 :          0 :                           << "Arrays::checkRowLemmas (" << store << ", " << c
    1768                 :      36341 :                           << ", " << j << ", " << i << ")\n";
    1769                 :      36341 :       queueRowLemma(lem);
    1770                 :            :     }
    1771                 :            :   }
    1772                 :            : 
    1773 [ +  + ][ +  + ]:      15436 :   if (!options().arrays.arraysOptimizeLinear || d_infoMap.isNonLinear(b))
         [ +  + ][ +  + ]
                 [ -  - ]
    1774                 :            :   {
    1775         [ +  + ]:      37815 :     for(it = 0 ; it < i_a->size(); ++it ) {
    1776                 :      65442 :       TNode i = (*i_a)[it];
    1777                 :      32721 :       its = 0;
    1778         [ +  + ]:      57308 :       for ( ; its < inst_b->size(); ++its) {
    1779                 :      49174 :         TNode store = (*inst_b)[its];
    1780 [ -  + ][ -  + ]:      24587 :         Assert(store.getKind() == Kind::STORE);
                 [ -  - ]
    1781                 :      49174 :         TNode j = store[1];
    1782                 :      24587 :         TNode c = store[0];
    1783                 :      24587 :         lem = std::make_tuple(store, c, j, i);
    1784         [ +  - ]:      49174 :         Trace("arrays-lem")
    1785 [ -  + ][ -  - ]:      24587 :             << spaces(context()->getLevel()) << "Arrays::checkRowLemmas ("
    1786                 :      24587 :             << store << ", " << c << ", " << j << ", " << i << ")\n";
    1787                 :      24587 :         queueRowLemma(lem);
    1788                 :            :       }
    1789                 :            :     }
    1790                 :            :   }
    1791         [ +  - ]:      15436 :   Trace("arrays-crl")<<"Arrays::checkLemmas done.\n";
    1792                 :            : }
    1793                 :            : 
    1794                 :      32706 : void TheoryArrays::propagateRowLemma(RowLemmaType lem)
    1795                 :            : {
    1796         [ +  - ]:      65412 :   Trace("pf::array") << "TheoryArrays: RowLemma Propagate called. "
    1797                 :          0 :                         "arraysPropagate = "
    1798                 :      32706 :                      << options().arrays.arraysPropagate << std::endl;
    1799                 :            : 
    1800                 :      32706 :   TNode a, b, i, j;
    1801                 :      32706 :   std::tie(a, b, i, j) = lem;
    1802                 :            : 
    1803                 :      65412 :   Assert(a.getType().isArray() && b.getType().isArray());
    1804                 :      32706 :   if (d_equalityEngine->areEqual(a, b) || d_equalityEngine->areEqual(i, j))
    1805                 :            :   {
    1806                 :          0 :     return;
    1807                 :            :   }
    1808                 :            : 
    1809                 :      32706 :   NodeManager* nm = nodeManager();
    1810                 :      65412 :   Node aj = nm->mkNode(Kind::SELECT, a, j);
    1811                 :      65412 :   Node bj = nm->mkNode(Kind::SELECT, b, j);
    1812                 :            : 
    1813                 :            :   // Try to avoid introducing new read terms: track whether these already exist
    1814                 :      32706 :   bool ajExists = d_equalityEngine->hasTerm(aj);
    1815                 :      32706 :   bool bjExists = d_equalityEngine->hasTerm(bj);
    1816 [ +  + ][ +  + ]:      32706 :   bool bothExist = ajExists && bjExists;
    1817                 :            : 
    1818                 :            :   // If propagating, check propagations
    1819                 :      32706 :   int64_t prop = options().arrays.arraysPropagate;
    1820         [ +  - ]:      32706 :   if (prop > 0) {
    1821                 :      32706 :     if (d_equalityEngine->areDisequal(i, j, true) && (bothExist || prop > 1))
    1822                 :            :     {
    1823 [ +  - ][ -  + ]:      33970 :       Trace("arrays-lem") << spaces(context()->getLevel())
                 [ -  - ]
    1824                 :          0 :                           << "Arrays::queueRowLemma: propagating aj = bj ("
    1825                 :      16985 :                           << aj << ", " << bj << ")\n";
    1826                 :      33970 :       Node aj_eq_bj = aj.eqNode(bj);
    1827                 :            :       Node reason =
    1828 [ +  + ][ +  + ]:      20799 :           (i.isConst() && j.isConst()) ? d_true : i.eqNode(j).notNode();
         [ +  + ][ -  - ]
    1829                 :      16985 :       d_permRef.push_back(reason);
    1830         [ +  + ]:      16985 :       if (!ajExists) {
    1831                 :       5251 :         preRegisterTermInternal(aj);
    1832                 :            :       }
    1833         [ +  + ]:      16985 :       if (!bjExists) {
    1834                 :       9489 :         preRegisterTermInternal(bj);
    1835                 :            :       }
    1836                 :      16985 :       d_im.assertInference(aj_eq_bj,
    1837                 :            :                            true,
    1838                 :            :                            InferenceId::ARRAYS_READ_OVER_WRITE,
    1839                 :            :                            reason,
    1840                 :            :                            ProofRule::ARRAYS_READ_OVER_WRITE);
    1841                 :      16985 :       ++d_numProp;
    1842                 :      16985 :       return;
    1843                 :            :     }
    1844                 :      15721 :     if (bothExist && d_equalityEngine->areDisequal(aj, bj, true))
    1845                 :            :     {
    1846 [ +  - ][ -  + ]:         62 :       Trace("arrays-lem") << spaces(context()->getLevel())
                 [ -  - ]
    1847                 :          0 :                           << "Arrays::queueRowLemma: propagating i = j (" << i
    1848                 :         31 :                           << ", " << j << ")\n";
    1849                 :            :       Node reason =
    1850 [ -  + ][ -  - ]:         62 :           (aj.isConst() && bj.isConst()) ? d_true : aj.eqNode(bj).notNode();
         [ +  - ][ -  - ]
    1851                 :         31 :       Node j_eq_i = j.eqNode(i);
    1852                 :         31 :       d_im.assertInference(j_eq_i,
    1853                 :            :                            true,
    1854                 :            :                            InferenceId::ARRAYS_READ_OVER_WRITE_CONTRA,
    1855                 :            :                            reason,
    1856                 :            :                            ProofRule::ARRAYS_READ_OVER_WRITE_CONTRA);
    1857                 :         31 :       ++d_numProp;
    1858                 :         31 :       return;
    1859                 :            :     }
    1860                 :            :   }
    1861                 :            : }
    1862                 :            : 
    1863                 :     106576 : void TheoryArrays::queueRowLemma(RowLemmaType lem)
    1864                 :            : {
    1865         [ +  - ]:     106576 :   Trace("pf::array") << "Array solver: queue row lemma called" << std::endl;
    1866                 :            : 
    1867 [ +  + ][ +  + ]:     106576 :   if (d_state.isInConflict() || d_RowAlreadyAdded.contains(lem))
                 [ +  + ]
    1868                 :            :   {
    1869                 :      79587 :     return;
    1870                 :            :   }
    1871                 :      49105 :   TNode a, b, i, j;
    1872                 :      49105 :   std::tie(a, b, i, j) = lem;
    1873                 :            : 
    1874                 :      98210 :   Assert(a.getType().isArray() && b.getType().isArray());
    1875                 :      49105 :   if (d_equalityEngine->areEqual(a, b) || d_equalityEngine->areEqual(i, j))
    1876                 :            :   {
    1877                 :      19748 :     return;
    1878                 :            :   }
    1879                 :            : 
    1880                 :      29357 :   NodeManager* nm = nodeManager();
    1881                 :      58714 :   Node aj = nm->mkNode(Kind::SELECT, a, j);
    1882                 :      58714 :   Node bj = nm->mkNode(Kind::SELECT, b, j);
    1883                 :            : 
    1884                 :            :   // Try to avoid introducing new read terms: track whether these already exist
    1885                 :      29357 :   bool ajExists = d_equalityEngine->hasTerm(aj);
    1886                 :      29357 :   bool bjExists = d_equalityEngine->hasTerm(bj);
    1887 [ +  + ][ +  + ]:      29357 :   bool bothExist = ajExists && bjExists;
    1888                 :            : 
    1889                 :            :   // If propagating, check propagations
    1890                 :      29357 :   int64_t prop = options().arrays.arraysPropagate;
    1891                 :            : 
    1892         [ +  - ]:      29357 :   if (prop > 0) {
    1893                 :      29357 :     propagateRowLemma(lem);
    1894                 :            :   }
    1895                 :            : 
    1896                 :            :   // Prefer equality between indexes so as not to introduce new read terms
    1897         [ +  + ]:      22152 :   if (options().arrays.arraysEagerIndexSplitting && !bothExist
    1898                 :      51509 :       && !d_equalityEngine->areDisequal(i, j, false))
    1899                 :            :   {
    1900                 :      16150 :     Node i_eq_j;
    1901                 :       8075 :     i_eq_j = d_valuation.ensureLiteral(i.eqNode(j));  // TODO: think about this
    1902                 :            : #if 0
    1903                 :            :     i_eq_j = i.eqNode(j);
    1904                 :            : #endif
    1905                 :       8075 :     getOutputChannel().preferPhase(i_eq_j, true);
    1906                 :       8075 :     d_decisionRequests.push(i_eq_j);
    1907                 :            :   }
    1908                 :            : 
    1909                 :            :   // TODO: maybe add triggers here
    1910                 :            : 
    1911 [ +  + ][ +  + ]:      29357 :   if (options().arrays.arraysEagerLemmas || bothExist)
                 [ +  + ]
    1912                 :            :   {
    1913                 :            :     // Make sure that any terms introduced by rewriting are appropriately stored in the equality database
    1914                 :       5064 :     Node aj2 = rewrite(aj);
    1915         [ +  + ]:       5064 :     if (aj != aj2) {
    1916         [ -  + ]:       2368 :       if (!ajExists) {
    1917                 :          0 :         preRegisterTermInternal(aj);
    1918                 :            :       }
    1919         [ -  + ]:       2368 :       if (!d_equalityEngine->hasTerm(aj2))
    1920                 :            :       {
    1921                 :          0 :         preRegisterTermInternal(aj2);
    1922                 :            :       }
    1923                 :       2368 :       d_im.assertInference(aj.eqNode(aj2),
    1924                 :            :                            true,
    1925                 :            :                            InferenceId::ARRAYS_EQ_TAUTOLOGY,
    1926                 :       2368 :                            d_true,
    1927                 :            :                            ProofRule::MACRO_SR_PRED_INTRO);
    1928                 :            :     }
    1929                 :       5064 :     Node bj2 = rewrite(bj);
    1930         [ +  + ]:       5064 :     if (bj != bj2) {
    1931         [ -  + ]:       1246 :       if (!bjExists) {
    1932                 :          0 :         preRegisterTermInternal(bj);
    1933                 :            :       }
    1934         [ -  + ]:       1246 :       if (!d_equalityEngine->hasTerm(bj2))
    1935                 :            :       {
    1936                 :          0 :         preRegisterTermInternal(bj2);
    1937                 :            :       }
    1938                 :       1246 :       d_im.assertInference(bj.eqNode(bj2),
    1939                 :            :                            true,
    1940                 :            :                            InferenceId::ARRAYS_EQ_TAUTOLOGY,
    1941                 :       1246 :                            d_true,
    1942                 :            :                            ProofRule::MACRO_SR_PRED_INTRO);
    1943                 :            :     }
    1944         [ +  + ]:       5064 :     if (aj2 == bj2) {
    1945                 :       2368 :       return;
    1946                 :            :     }
    1947                 :            : 
    1948                 :            :     // construct lemma
    1949                 :       2696 :     Node eq1 = aj2.eqNode(bj2);
    1950                 :       2696 :     Node eq1_r = rewrite(eq1);
    1951         [ -  + ]:       2696 :     if (eq1_r == d_true) {
    1952         [ -  - ]:          0 :       if (!d_equalityEngine->hasTerm(aj2))
    1953                 :            :       {
    1954                 :          0 :         preRegisterTermInternal(aj2);
    1955                 :            :       }
    1956         [ -  - ]:          0 :       if (!d_equalityEngine->hasTerm(bj2))
    1957                 :            :       {
    1958                 :          0 :         preRegisterTermInternal(bj2);
    1959                 :            :       }
    1960                 :          0 :       d_im.assertInference(eq1,
    1961                 :            :                            true,
    1962                 :            :                            InferenceId::ARRAYS_EQ_TAUTOLOGY,
    1963                 :          0 :                            d_true,
    1964                 :            :                            ProofRule::MACRO_SR_PRED_INTRO);
    1965                 :          0 :       return;
    1966                 :            :     }
    1967                 :            : 
    1968                 :       2696 :     Node eq2 = i.eqNode(j);
    1969                 :       2696 :     Node eq2_r = rewrite(eq2);
    1970         [ -  + ]:       2696 :     if (eq2_r == d_true) {
    1971                 :          0 :       d_im.assertInference(eq2,
    1972                 :            :                            true,
    1973                 :            :                            InferenceId::ARRAYS_EQ_TAUTOLOGY,
    1974                 :          0 :                            d_true,
    1975                 :            :                            ProofRule::MACRO_SR_PRED_INTRO);
    1976                 :          0 :       return;
    1977                 :            :     }
    1978                 :            : 
    1979                 :       8088 :     Node lemma = nm->mkNode(Kind::OR, eq2_r, eq1_r);
    1980                 :            : 
    1981         [ +  - ]:       2696 :     Trace("arrays-lem") << "Arrays::addRowLemma (1) adding " << lemma << "\n";
    1982                 :       2696 :     d_RowAlreadyAdded.insert(lem);
    1983                 :            :     // use non-rewritten nodes
    1984                 :       2696 :     d_im.arrayLemma(aj.eqNode(bj),
    1985                 :            :                     InferenceId::ARRAYS_READ_OVER_WRITE,
    1986                 :       5392 :                     eq2.notNode(),
    1987                 :            :                     ProofRule::ARRAYS_READ_OVER_WRITE);
    1988                 :       2696 :     ++d_numRow;
    1989                 :            :   }
    1990                 :            :   else {
    1991                 :      24293 :     d_RowQueue.push(lem);
    1992                 :            :   }
    1993                 :            : }
    1994                 :            : 
    1995                 :   12044800 : Node TheoryArrays::getNextDecisionRequest()
    1996                 :            : {
    1997         [ +  + ]:   12044800 :   if(! d_decisionRequests.empty()) {
    1998                 :      91640 :     Node n = d_decisionRequests.front();
    1999                 :      45820 :     d_decisionRequests.pop();
    2000                 :      45820 :     return n;
    2001                 :            :   }
    2002                 :   11999000 :   return Node::null();
    2003                 :            : }
    2004                 :            : 
    2005                 :            : 
    2006                 :       1658 : bool TheoryArrays::dischargeLemmas()
    2007                 :            : {
    2008                 :       1658 :   bool reduceSharing = options().arrays.arraysReduceSharing;
    2009                 :       1658 :   bool lemmasAdded = false;
    2010                 :            : 
    2011         [ +  + ]:      29327 :   for (size_t count = 0, sz = d_RowQueue.size(); count < sz; ++count)
    2012                 :            :   {
    2013                 :      28384 :     RowLemmaType l = d_RowQueue.front();
    2014                 :      28384 :     d_RowQueue.pop();
    2015         [ +  + ]:      28384 :     if (d_RowAlreadyAdded.contains(l)) {
    2016                 :      19788 :       continue;
    2017                 :            :     }
    2018                 :            : 
    2019                 :       8596 :     TNode a, b, i, j;
    2020                 :       8596 :     std::tie(a, b, i, j) = l;
    2021                 :      17192 :     Assert(a.getType().isArray() && b.getType().isArray());
    2022                 :            : 
    2023                 :       8596 :     NodeManager* nm = nodeManager();
    2024                 :      17192 :     Node aj = nm->mkNode(Kind::SELECT, a, j);
    2025                 :      17192 :     Node bj = nm->mkNode(Kind::SELECT, b, j);
    2026                 :       8596 :     bool ajExists = d_equalityEngine->hasTerm(aj);
    2027                 :       8596 :     bool bjExists = d_equalityEngine->hasTerm(bj);
    2028                 :            : 
    2029                 :            :     // Check for redundant lemma
    2030                 :            :     // TODO: more checks possible (i.e. check d_RowAlreadyAdded in context)
    2031                 :      17192 :     if (!d_equalityEngine->hasTerm(i) || !d_equalityEngine->hasTerm(j)
    2032                 :      17192 :         || d_equalityEngine->areEqual(i, j) || !d_equalityEngine->hasTerm(a)
    2033                 :      14252 :         || !d_equalityEngine->hasTerm(b) || d_equalityEngine->areEqual(a, b)
    2034                 :      17192 :         || (ajExists && bjExists && d_equalityEngine->areEqual(aj, bj)))
    2035                 :            :     {
    2036                 :       5247 :       continue;
    2037                 :            :     }
    2038                 :            : 
    2039                 :       3349 :     int64_t prop = options().arrays.arraysPropagate;
    2040         [ +  - ]:       3349 :     if (prop > 0) {
    2041                 :       3349 :       propagateRowLemma(l);
    2042         [ +  + ]:       3349 :       if (d_state.isInConflict())
    2043                 :            :       {
    2044                 :        715 :         return true;
    2045                 :            :       }
    2046                 :            :     }
    2047                 :            : 
    2048                 :            :     // Make sure that any terms introduced by rewriting are appropriately stored in the equality database
    2049                 :       2634 :     Node aj2 = rewrite(aj);
    2050         [ +  + ]:       2634 :     if (aj != aj2) {
    2051         [ +  - ]:        144 :       if (!ajExists) {
    2052                 :        144 :         preRegisterTermInternal(aj);
    2053                 :            :       }
    2054         [ -  + ]:        144 :       if (!d_equalityEngine->hasTerm(aj2))
    2055                 :            :       {
    2056                 :          0 :         preRegisterTermInternal(aj2);
    2057                 :            :       }
    2058                 :        144 :       d_im.assertInference(aj.eqNode(aj2),
    2059                 :            :                            true,
    2060                 :            :                            InferenceId::ARRAYS_EQ_TAUTOLOGY,
    2061                 :        144 :                            d_true,
    2062                 :            :                            ProofRule::MACRO_SR_PRED_INTRO);
    2063                 :            :     }
    2064                 :       2634 :     Node bj2 = rewrite(bj);
    2065         [ +  + ]:       2634 :     if (bj != bj2) {
    2066         [ +  + ]:        269 :       if (!bjExists) {
    2067                 :         19 :         preRegisterTermInternal(bj);
    2068                 :            :       }
    2069         [ -  + ]:        269 :       if (!d_equalityEngine->hasTerm(bj2))
    2070                 :            :       {
    2071                 :          0 :         preRegisterTermInternal(bj2);
    2072                 :            :       }
    2073                 :        269 :       d_im.assertInference(bj.eqNode(bj2),
    2074                 :            :                            true,
    2075                 :            :                            InferenceId::ARRAYS_EQ_TAUTOLOGY,
    2076                 :        269 :                            d_true,
    2077                 :            :                            ProofRule::MACRO_SR_PRED_INTRO);
    2078                 :            :     }
    2079         [ +  + ]:       2634 :     if (aj2 == bj2) {
    2080                 :        144 :       continue;
    2081                 :            :     }
    2082                 :            : 
    2083                 :            :     // construct lemma
    2084                 :       2490 :     Node eq1 = aj2.eqNode(bj2);
    2085                 :       2490 :     Node eq1_r = rewrite(eq1);
    2086         [ -  + ]:       2490 :     if (eq1_r == d_true) {
    2087         [ -  - ]:          0 :       if (!d_equalityEngine->hasTerm(aj2))
    2088                 :            :       {
    2089                 :          0 :         preRegisterTermInternal(aj2);
    2090                 :            :       }
    2091         [ -  - ]:          0 :       if (!d_equalityEngine->hasTerm(bj2))
    2092                 :            :       {
    2093                 :          0 :         preRegisterTermInternal(bj2);
    2094                 :            :       }
    2095                 :          0 :       d_im.assertInference(eq1,
    2096                 :            :                            true,
    2097                 :            :                            InferenceId::ARRAYS_EQ_TAUTOLOGY,
    2098                 :          0 :                            d_true,
    2099                 :            :                            ProofRule::MACRO_SR_PRED_INTRO);
    2100                 :          0 :       continue;
    2101                 :            :     }
    2102                 :            : 
    2103                 :       2490 :     Node eq2 = i.eqNode(j);
    2104                 :       2490 :     Node eq2_r = rewrite(eq2);
    2105         [ -  + ]:       2490 :     if (eq2_r == d_true) {
    2106                 :          0 :       d_im.assertInference(eq2,
    2107                 :            :                            true,
    2108                 :            :                            InferenceId::ARRAYS_EQ_TAUTOLOGY,
    2109                 :          0 :                            d_true,
    2110                 :            :                            ProofRule::MACRO_SR_PRED_INTRO);
    2111                 :          0 :       continue;
    2112                 :            :     }
    2113                 :            : 
    2114                 :       4980 :     Node lem = nm->mkNode(Kind::OR, eq2_r, eq1_r);
    2115                 :            : 
    2116         [ +  - ]:       2490 :     Trace("arrays-lem") << "Arrays::addRowLemma (2) adding " << lem << "\n";
    2117                 :       2490 :     d_RowAlreadyAdded.insert(l);
    2118                 :            :     // use non-rewritten nodes, theory preprocessing will rewrite
    2119                 :       2490 :     d_im.arrayLemma(aj.eqNode(bj),
    2120                 :            :                     InferenceId::ARRAYS_READ_OVER_WRITE,
    2121                 :       4980 :                     eq2.notNode(),
    2122                 :            :                     ProofRule::ARRAYS_READ_OVER_WRITE);
    2123                 :       2490 :     ++d_numRow;
    2124                 :       2490 :     lemmasAdded = true;
    2125         [ -  + ]:       2490 :     if (reduceSharing)
    2126                 :            :     {
    2127                 :          0 :       return true;
    2128                 :            :     }
    2129                 :            :   }
    2130                 :        943 :   return lemmasAdded;
    2131                 :            : }
    2132                 :            : 
    2133                 :        172 : void TheoryArrays::conflict(TNode a, TNode b) {
    2134         [ +  - ]:        172 :   Trace("pf::array") << "TheoryArrays::Conflict called" << std::endl;
    2135                 :        172 :   d_im.conflictEqConstantMerge(a, b);
    2136                 :        172 : }
    2137                 :            : 
    2138                 :      50855 : TheoryArrays::TheoryArraysDecisionStrategy::TheoryArraysDecisionStrategy(
    2139                 :      50855 :     TheoryArrays* ta)
    2140                 :      50855 :     : DecisionStrategy(ta->d_env), d_ta(ta)
    2141                 :            : {
    2142                 :      50855 : }
    2143                 :      42098 : void TheoryArrays::TheoryArraysDecisionStrategy::initialize() {}
    2144                 :   12044800 : Node TheoryArrays::TheoryArraysDecisionStrategy::getNextDecisionRequest()
    2145                 :            : {
    2146                 :   12044800 :   return d_ta->getNextDecisionRequest();
    2147                 :            : }
    2148                 :          0 : std::string TheoryArrays::TheoryArraysDecisionStrategy::identify() const
    2149                 :            : {
    2150                 :          0 :   return std::string("th_arrays_dec");
    2151                 :            : }
    2152                 :            : 
    2153                 :      14918 : void TheoryArrays::computeRelevantTerms(std::set<Node>& termSet)
    2154                 :            : {
    2155                 :      14918 :   NodeManager* nm = nodeManager();
    2156                 :            :   // make sure RIntro1 reads are included in the relevant set of reads
    2157                 :      14918 :   eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(d_equalityEngine);
    2158         [ +  + ]:      49313 :   for (; !eqcs_i.isFinished(); ++eqcs_i)
    2159                 :            :   {
    2160                 :      34395 :     Node eqc = (*eqcs_i);
    2161         [ +  + ]:      34395 :     if (!eqc.getType().isArray())
    2162                 :            :     {
    2163                 :            :       // not an array, skip
    2164                 :      33493 :       continue;
    2165                 :            :     }
    2166                 :        902 :     eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, d_equalityEngine);
    2167         [ +  + ]:       2638 :     for (; !eqc_i.isFinished(); ++eqc_i)
    2168                 :            :     {
    2169                 :       3472 :       Node n = *eqc_i;
    2170         [ +  + ]:       1736 :       if (termSet.find(n) != termSet.end())
    2171                 :            :       {
    2172         [ +  + ]:       1694 :         if (n.getKind() == Kind::STORE)
    2173                 :            :         {
    2174                 :            :           // Make sure RIntro1 reads are included
    2175                 :       1257 :           Node r = nm->mkNode(Kind::SELECT, n, n[1]);
    2176         [ +  - ]:        838 :           Trace("arrays::collectModelInfo")
    2177                 :          0 :               << "TheoryArrays::collectModelInfo, adding RIntro1 read: " << r
    2178                 :        419 :               << endl;
    2179                 :        419 :           termSet.insert(r);
    2180                 :            :         }
    2181                 :            :       }
    2182                 :            :     }
    2183                 :            :   }
    2184                 :            : 
    2185                 :            :   // Now do a fixed-point iteration to get all reads that need to be included
    2186                 :            :   // because of RIntro2 rule
    2187                 :            :   bool changed;
    2188         [ +  + ]:      14959 :   do
    2189                 :            :   {
    2190                 :      14959 :     changed = false;
    2191                 :      14959 :     eqcs_i = eq::EqClassesIterator(d_equalityEngine);
    2192         [ +  + ]:      50073 :     for (; !eqcs_i.isFinished(); ++eqcs_i)
    2193                 :            :     {
    2194                 :      70228 :       Node eqc = (*eqcs_i);
    2195                 :      35114 :       eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, d_equalityEngine);
    2196         [ +  + ]:      82503 :       for (; !eqc_i.isFinished(); ++eqc_i)
    2197                 :            :       {
    2198                 :      94778 :         Node n = *eqc_i;
    2199 [ +  + ][ +  + ]:      47389 :         if (n.getKind() == Kind::SELECT && termSet.find(n) != termSet.end())
                 [ +  + ]
    2200                 :            :         {
    2201                 :            :           // Find all terms equivalent to n[0] and get corresponding read terms
    2202                 :      14757 :           Node array_eqc = d_equalityEngine->getRepresentative(n[0]);
    2203                 :            :           eq::EqClassIterator array_eqc_i =
    2204                 :       4919 :               eq::EqClassIterator(array_eqc, d_equalityEngine);
    2205         [ +  + ]:      18017 :           for (; !array_eqc_i.isFinished(); ++array_eqc_i)
    2206                 :            :           {
    2207                 :      26196 :             Node arr = *array_eqc_i;
    2208                 :      39294 :             if (arr.getKind() == Kind::STORE
    2209         [ +  - ]:       4900 :                 && termSet.find(arr) != termSet.end()
    2210                 :      17998 :                 && !d_equalityEngine->areEqual(arr[1], n[1]))
    2211                 :            :             {
    2212                 :       8301 :               Node r = nm->mkNode(Kind::SELECT, arr, n[1]);
    2213                 :       2767 :               if (termSet.find(r) == termSet.end()
    2214 [ +  + ][ +  + ]:       5534 :                   && d_equalityEngine->hasTerm(r))
         [ +  + ][ +  + ]
                 [ -  - ]
    2215                 :            :               {
    2216         [ +  - ]:         76 :                 Trace("arrays::collectModelInfo")
    2217                 :            :                     << "TheoryArrays::collectModelInfo, adding RIntro2(a) "
    2218                 :          0 :                        "read: "
    2219                 :         38 :                     << r << endl;
    2220                 :         38 :                 termSet.insert(r);
    2221                 :         38 :                 changed = true;
    2222                 :            :               }
    2223                 :       2767 :               r = nm->mkNode(Kind::SELECT, arr[0], n[1]);
    2224                 :       2767 :               if (termSet.find(r) == termSet.end()
    2225 [ +  + ][ +  + ]:       5534 :                   && d_equalityEngine->hasTerm(r))
         [ +  + ][ +  + ]
                 [ -  - ]
    2226                 :            :               {
    2227         [ +  - ]:         98 :                 Trace("arrays::collectModelInfo")
    2228                 :            :                     << "TheoryArrays::collectModelInfo, adding RIntro2(b) "
    2229                 :          0 :                        "read: "
    2230                 :         49 :                     << r << endl;
    2231                 :         49 :                 termSet.insert(r);
    2232                 :         49 :                 changed = true;
    2233                 :            :               }
    2234                 :            :             }
    2235                 :            :           }
    2236                 :            : 
    2237                 :            :           // Find all stores in which n[0] appears and get corresponding read
    2238                 :            :           // terms
    2239                 :       4919 :           const CTNodeList* instores = d_infoMap.getInStores(array_eqc);
    2240                 :       4919 :           size_t it = 0;
    2241         [ +  + ]:       9692 :           for (; it < instores->size(); ++it)
    2242                 :            :           {
    2243                 :       9546 :             TNode instore = (*instores)[it];
    2244 [ -  + ][ -  + ]:       4773 :             Assert(instore.getKind() == Kind::STORE);
                 [ -  - ]
    2245 [ +  + ][ -  - ]:       9546 :             if (termSet.find(instore) != termSet.end()
    2246                 :       9546 :                 && !d_equalityEngine->areEqual(instore[1], n[1]))
    2247                 :            :             {
    2248                 :       9108 :               Node r = nm->mkNode(Kind::SELECT, instore, n[1]);
    2249                 :       3036 :               if (termSet.find(r) == termSet.end()
    2250 [ +  + ][ +  + ]:       6072 :                   && d_equalityEngine->hasTerm(r))
         [ +  + ][ +  + ]
                 [ -  - ]
    2251                 :            :               {
    2252         [ +  - ]:        282 :                 Trace("arrays::collectModelInfo")
    2253                 :            :                     << "TheoryArrays::collectModelInfo, adding RIntro2(c) "
    2254                 :          0 :                        "read: "
    2255                 :        141 :                     << r << endl;
    2256                 :        141 :                 termSet.insert(r);
    2257                 :        141 :                 changed = true;
    2258                 :            :               }
    2259                 :       3036 :               r = nm->mkNode(Kind::SELECT, instore[0], n[1]);
    2260                 :       3036 :               if (termSet.find(r) == termSet.end()
    2261 [ +  + ][ +  + ]:       6072 :                   && d_equalityEngine->hasTerm(r))
         [ +  + ][ +  + ]
                 [ -  - ]
    2262                 :            :               {
    2263         [ +  - ]:         32 :                 Trace("arrays::collectModelInfo")
    2264                 :            :                     << "TheoryArrays::collectModelInfo, adding RIntro2(d) "
    2265                 :          0 :                        "read: "
    2266                 :         16 :                     << r << endl;
    2267                 :         16 :                 termSet.insert(r);
    2268                 :         16 :                 changed = true;
    2269                 :            :               }
    2270                 :            :             }
    2271                 :            :           }
    2272                 :            :         }
    2273                 :            :       }
    2274                 :            :     }
    2275                 :            :   } while (changed);
    2276                 :      14918 : }
    2277                 :            : 
    2278                 :            : }  // namespace arrays
    2279                 :            : }  // namespace theory
    2280                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14