Example #1
0
Node CandidateGeneratorQEAll::getNextCandidate() {
  while( !d_eq.isFinished() ){
    TNode n = (*d_eq);
    ++d_eq;
    if( n.getType().isSubtypeOf( d_match_pattern_type ) ){
      TNode nh = d_qe->getTermDatabase()->getEligibleTermInEqc( n );
      if( !nh.isNull() ){
        if( options::instMaxLevel()!=-1 || options::lteRestrictInstClosure() ){
          nh = d_qe->getEqualityQuery()->getInternalRepresentative( nh, d_f, d_index );
          //don't consider this if already the instantiation is ineligible
          if( !d_qe->getTermDatabase()->isTermEligibleForInstantiation( nh, d_f, false ) ){
            nh = Node::null();
          }
        }
        if( !nh.isNull() ){
          d_firstTime = false;
          //an equivalence class with the same type as the pattern, return it
          return nh;
        }
      }
    }
  }
  if( d_firstTime ){
    Assert( d_qe->getTermDatabase()->d_type_map[d_match_pattern_type].empty() );
    //must return something
    d_firstTime = false;
    return d_qe->getTermDatabase()->getModelBasisTerm( d_match_pattern_type );
  }
  return Node::null();
}
Example #2
0
TNode EqualityQueryInstProp::getCongruentTerm( Node f, std::vector< TNode >& args ) {
  TNode t = d_qe->getTermDatabase()->getCongruentTerm( f, args );
  if( !t.isNull() ){
    return t;
  }else{
    //TODO?
    return TNode::null();
  }
}
Example #3
0
void AbsDef::construct_def_entry( FirstOrderModelAbs * m, TNode q, TNode n, int v, unsigned depth ) {
  d_value = v;
  if( depth<n.getNumChildren() ){
    TypeNode tn = q.isNull() ? n[depth].getType() : m->getVariable( q, depth ).getType();
    unsigned dom = m->d_domain[tn] ;
    d_def[dom].construct_def_entry( m, q, n, v, depth+1 );
    d_default = dom;
  }
}
Example #4
0
SatLiteral TheoryProxy::getNextTheoryDecisionRequest() {
  TNode n = d_theoryEngine->getNextDecisionRequest();
  return n.isNull() ? undefSatLiteral : d_cnfStream->getLiteral(n);
}
Example #5
0
//this is identical to TermDb::evaluateTerm2, but tracks more information
Node EqualityQueryInstProp::evaluateTermExp( Node n, std::vector< Node >& exp, std::map< Node, Node >& visited, bool hasPol, bool pol,
                                             std::map< Node, bool >& watch_list_out, std::vector< Node >& props ) {
  std::map< Node, Node >::iterator itv = visited.find( n );
  if( itv != visited.end() ){
    return itv->second;
  }else{
    visited[n] = n;
    Trace("qip-eval") << "evaluate term : " << n << std::endl;
    std::vector< Node > exp_n;
    Node ret = getRepresentativeExp( n, exp_n );
    if( ret.isNull() ){
      //term is not known to be equal to a representative in equality engine, evaluate it
      Kind k = n.getKind();
      if( k==FORALL ){
        ret = Node::null();
      }else{
        std::map< Node, bool > watch_list_out_curr;
        TNode f = d_qe->getTermDatabase()->getMatchOperator( n );
        std::vector< Node > args;
        bool ret_set = false;
        bool childChanged = false;
        int abort_i = -1;
        //get the child entailed polarity
        Assert( n.getKind()!=IMPLIES );
        bool newHasPol, newPol;
        QuantPhaseReq::getEntailPolarity( n, 0, hasPol, pol, newHasPol, newPol );
        //for each child
        for( unsigned i=0; i<n.getNumChildren(); i++ ){
          Node c = evaluateTermExp( n[i], exp, visited, newHasPol, newPol, watch_list_out_curr, props );
          if( c.isNull() ){
            ret = Node::null();
            ret_set = true;
            break;
          }else if( c==d_true || c==d_false ){
            //short-circuiting
            if( k==kind::AND || k==kind::OR ){
              if( (k==kind::AND)==(c==d_false) ){
                ret = c;
                ret_set = true;
                break;
              }else{
                //redundant
                c = Node::null();
                childChanged = true;
              }
            }else if( k==kind::ITE && i==0 ){
              Assert( watch_list_out_curr.empty() );
              ret = evaluateTermExp( n[ c==d_true ? 1 : 2], exp, visited, hasPol, pol, watch_list_out_curr, props );
              ret_set = true;
              break;
            }else if( k==kind::NOT ){
              ret = c==d_true ? d_false : d_true;
              ret_set = true;
              break;
            }
          }
          if( !c.isNull() ){
            childChanged = childChanged || n[i]!=c;
            if( !f.isNull() && !watch_list_out_curr.empty() ){
              // we are done if this is an UF application and an argument is unevaluated
              args.push_back( c );
              abort_i = i;
              break;
            }else if( ( k==kind::AND || k==kind::OR ) ){
              if( c.getKind()==k ){
                //flatten
                for( unsigned j=0; j<c.getNumChildren(); j++ ){
                  addArgument( args, props, c[j], newHasPol, newPol );
                }
              }else{
                addArgument( args, props, c, newHasPol, newPol );
              }
              //if we are in a branching position
              if( hasPol && !newHasPol && args.size()>=2 ){
                //we are done if at least two args are unevaluated
                abort_i = i;
                break;
              }
            }else if( k==kind::ITE ){
              //we are done if we are ITE and condition is unevaluated
              Assert( i==0 );
              args.push_back( c );
              abort_i = i;
              break;
            }else{
              args.push_back( c );
            }
          }
        }
        //add remaining children if we aborted
        if( abort_i!=-1 ){
          for( int i=(abort_i+1); i<(int)n.getNumChildren(); i++ ){
            args.push_back( n[i] );
          }
        }
        //copy over the watch list
        for( std::map< Node, bool >::iterator itc = watch_list_out_curr.begin(); itc != watch_list_out_curr.end(); ++itc ){
          watch_list_out[itc->first] = itc->second;
        }

        //if we have not short-circuited evaluation
        if( !ret_set ){
          //if it is an indexed term, return the congruent term
          if( !f.isNull() && watch_list_out.empty() ){
            std::vector< TNode > t_args;
            for( unsigned i=0; i<args.size(); i++ ) {
              t_args.push_back( args[i] );
            }
            Assert( args.size()==n.getNumChildren() );
            //args contains terms known by the equality engine
            TNode nn = getCongruentTerm( f, t_args );
            Trace("qip-eval") << "  got congruent term " << nn << " from DB for " << n << std::endl;
            if( !nn.isNull() ){
              //successfully constructed representative in EE
              Assert( exp_n.empty() );
              ret = getRepresentativeExp( nn, exp_n );
              Trace("qip-eval") << "return rep, exp size = " << exp_n.size() << std::endl;
              merge_exp( exp, exp_n );
              ret_set = true;
              Assert( !ret.isNull() );
            }
          }
          if( !ret_set ){
            if( childChanged ){
              Trace("qip-eval") << "return rewrite" << std::endl;
              if( ( k==kind::AND || k==kind::OR ) ){
                if( args.empty() ){
                  ret = k==kind::AND ? d_true : d_false;
                  ret_set = true;
                }else if( args.size()==1 ){
                  ret = args[0];
                  ret_set = true;
                }
              }else{
                Assert( args.size()==n.getNumChildren() );
              }
              if( !ret_set ){
                if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
                  args.insert( args.begin(), n.getOperator() );
                }
                ret = NodeManager::currentNM()->mkNode( k, args );
                ret = Rewriter::rewrite( ret );
                //re-evaluate
                Node ret_eval = getRepresentativeExp( ret, exp_n );
                if( !ret_eval.isNull() ){
                  ret = ret_eval;
                  watch_list_out.clear();
                }else{            
                  watch_list_out[ret] = true;
                }
              }
            }else{
              ret = n;
              watch_list_out[ret] = true;
            }
          }
        }
      }
    }else{
      Trace("qip-eval") << "...exists in ee, return rep, exp size = " << exp_n.size() << std::endl;
      merge_exp( exp, exp_n );
    }
    Trace("qip-eval") << "evaluated term : " << n << ", got : " << ret << ", exp size = " << exp.size() << std::endl;
    visited[n] = ret;
    return ret;
  }
}
Example #6
0
void UnconstrainedSimplifier::processUnconstrained()
{
  TNodeSet::iterator it = d_unconstrained.begin(), iend = d_unconstrained.end();
  vector<TNode> workList;
  for ( ; it != iend; ++it) {
    workList.push_back(*it);
  }
  Node currentSub;
  TNode parent;
  bool swap;
  bool isSigned;
  bool strict;
  vector<TNode> delayQueueLeft;
  vector<Node> delayQueueRight;

  TNode current = workList.back();
  workList.pop_back();
  for (;;) {
    Assert(d_visitedOnce.find(current) != d_visitedOnce.end());
    parent = d_visitedOnce[current];
    if (!parent.isNull()) {
      swap = isSigned = strict = false;
      switch (parent.getKind()) {

        // If-then-else operator - any two unconstrained children makes the parent unconstrained
        case kind::ITE: {
          Assert(parent[0] == current || parent[1] == current || parent[2] == current);
          bool uCond = parent[0] == current || d_unconstrained.find(parent[0]) != d_unconstrained.end();
          bool uThen = parent[1] == current || d_unconstrained.find(parent[1]) != d_unconstrained.end();
          bool uElse = parent[2] == current || d_unconstrained.find(parent[2]) != d_unconstrained.end();
          if ((uCond && uThen) || (uCond && uElse) || (uThen && uElse)) {
            if (d_unconstrained.find(parent) == d_unconstrained.end() &&
                !d_substitutions.hasSubstitution(parent)) {
              ++d_numUnconstrainedElim;
              if (uThen) {
                if (parent[1] != current) {
                  if (parent[1].isVar()) {
                    currentSub = parent[1];
                  }
                  else {
                    Assert(d_substitutions.hasSubstitution(parent[1]));
                    currentSub = d_substitutions.apply(parent[1]);
                  }
                }
                else if (currentSub.isNull()) {
                  currentSub = current;
                }
              }
              else if (parent[2] != current) {
                if (parent[2].isVar()) {
                  currentSub = parent[2];
                }
                else {
                  Assert(d_substitutions.hasSubstitution(parent[2]));
                  currentSub = d_substitutions.apply(parent[2]);
                }
              }
              else if (currentSub.isNull()) {
                currentSub = current;
              }
              current = parent;
            }
            else {
              currentSub = Node();
            }
          }
          else if (uCond) {
            Cardinality card = parent.getType().getCardinality();
            if (card.isFinite() && !card.isLargeFinite() && card.getFiniteCardinality() == 2) {
              // Special case: condition is unconstrained, then and else are different, and total cardinality of the type is 2, then the result
              // is unconstrained
              Node test;
              if (parent.getType().isBoolean()) {
                test = Rewriter::rewrite(parent[1].iffNode(parent[2]));
              }
              else {
                test = Rewriter::rewrite(parent[1].eqNode(parent[2]));
              }
              if (test == NodeManager::currentNM()->mkConst<bool>(false)) {
                ++d_numUnconstrainedElim;
                if (currentSub.isNull()) {
                  currentSub = current;
                }
                currentSub = newUnconstrainedVar(parent.getType(), currentSub);
                current = parent;
              }
            }
          }
          break;
        }

        // Comparisons that return a different type - assuming domains are larger than 1, any
        // unconstrained child makes parent unconstrained as well
        case kind::EQUAL:
          if (parent[0].getType() != parent[1].getType()) {
            TNode other = (parent[0] == current) ? parent[1] : parent[0];
            if (current.getType().isSubtypeOf(other.getType())) {
              break;
            }
          }
          if( parent[0].getType().isDatatype() ){
            TypeNode tn = parent[0].getType();
            const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
            if( dt.isRecursiveSingleton( tn.toType() ) ){
              //domain size may be 1
              break;
            }
          }
        case kind::BITVECTOR_COMP:
        case kind::LT:
        case kind::LEQ:
        case kind::GT:
        case kind::GEQ:
        {
          if (d_unconstrained.find(parent) == d_unconstrained.end() &&
              !d_substitutions.hasSubstitution(parent)) {
            ++d_numUnconstrainedElim;
            Assert(parent[0] != parent[1] &&
                   (parent[0] == current || parent[1] == current));
            if (currentSub.isNull()) {
              currentSub = current;
            }
            currentSub = newUnconstrainedVar(parent.getType(), currentSub);
            current = parent;
          }
          else {
            currentSub = Node();
          }
          break;
        }

        // Unary operators that propagate unconstrainedness
        case kind::NOT:
        case kind::BITVECTOR_NOT:
        case kind::BITVECTOR_NEG:
        case kind::UMINUS:
          ++d_numUnconstrainedElim;
          Assert(parent[0] == current);
          if (currentSub.isNull()) {
            currentSub = current;
          }
          current = parent;
          break;

        // Unary operators that propagate unconstrainedness and return a different type
        case kind::BITVECTOR_EXTRACT:
          ++d_numUnconstrainedElim;
          Assert(parent[0] == current);
          if (currentSub.isNull()) {
            currentSub = current;
          }
          currentSub = newUnconstrainedVar(parent.getType(), currentSub);
          current = parent;
          break;

        // Operators returning same type requiring all children to be unconstrained
        case kind::AND:
        case kind::OR:
        case kind::IMPLIES:
        case kind::BITVECTOR_AND:
        case kind::BITVECTOR_OR:
        case kind::BITVECTOR_NAND:
        case kind::BITVECTOR_NOR:
        {
          bool allUnconstrained = true;
          for(TNode::iterator child_it = parent.begin(); child_it != parent.end(); ++child_it) {
            if (d_unconstrained.find(*child_it) == d_unconstrained.end()) {
              allUnconstrained = false;
              break;
            }
          }
          if (allUnconstrained) {
            if (d_unconstrained.find(parent) == d_unconstrained.end() &&
                !d_substitutions.hasSubstitution(parent)) {
              ++d_numUnconstrainedElim;
              if (currentSub.isNull()) {
                currentSub = current;
              }
              current = parent;
            }
            else {
              currentSub = Node();
            }
          }
        }
        break;

        // Require all children to be unconstrained and different
        case kind::BITVECTOR_SHL:
        case kind::BITVECTOR_LSHR:
        case kind::BITVECTOR_ASHR:
        case kind::BITVECTOR_UDIV_TOTAL:
        case kind::BITVECTOR_UREM_TOTAL:
        case kind::BITVECTOR_SDIV:
        case kind::BITVECTOR_SREM:
        case kind::BITVECTOR_SMOD: {
          bool allUnconstrained = true;
          bool allDifferent = true;
          for(TNode::iterator child_it = parent.begin(); child_it != parent.end(); ++child_it) {
            if (d_unconstrained.find(*child_it) == d_unconstrained.end()) {
              allUnconstrained = false;
              break;
            }
            for(TNode::iterator child_it2 = child_it + 1; child_it2 != parent.end(); ++child_it2) {
              if (*child_it == *child_it2) {
                allDifferent = false;
                break;
              }
            }
          }
          if (allUnconstrained && allDifferent) {
            if (d_unconstrained.find(parent) == d_unconstrained.end() &&
                !d_substitutions.hasSubstitution(parent)) {
              ++d_numUnconstrainedElim;
              if (currentSub.isNull()) {
                currentSub = current;
              }
              current = parent;
            }
            else {
              currentSub = Node();
            }
          }
          break;
        }

        // Requires all children to be unconstrained and different, and returns a different type
        case kind::BITVECTOR_CONCAT:
        {
          bool allUnconstrained = true;
          bool allDifferent = true;
          for(TNode::iterator child_it = parent.begin(); child_it != parent.end(); ++child_it) {
            if (d_unconstrained.find(*child_it) == d_unconstrained.end()) {
              allUnconstrained = false;
              break;
            }
            for(TNode::iterator child_it2 = child_it + 1; child_it2 != parent.end(); ++child_it2) {
              if (*child_it == *child_it2) {
                allDifferent = false;
                break;
              }
            }
          }
          if (allUnconstrained && allDifferent) {
            if (d_unconstrained.find(parent) == d_unconstrained.end() &&
                !d_substitutions.hasSubstitution(parent)) {
              ++d_numUnconstrainedElim;
              if (currentSub.isNull()) {
                currentSub = current;
              }
              currentSub = newUnconstrainedVar(parent.getType(), currentSub);
              current = parent;
            }
            else {
              currentSub = Node();
            }
          }
        }
        break;

        // N-ary operators returning same type requiring at least one child to be unconstrained
        case kind::PLUS:
        case kind::MINUS:
          if (current.getType().isInteger() &&
              !parent.getType().isInteger()) {
            break;
          }
        case kind::IFF:
        case kind::XOR:
        case kind::BITVECTOR_XOR:
        case kind::BITVECTOR_XNOR:
        case kind::BITVECTOR_PLUS:
        case kind::BITVECTOR_SUB:
          if (d_unconstrained.find(parent) == d_unconstrained.end() &&
              !d_substitutions.hasSubstitution(parent)) {
            ++d_numUnconstrainedElim;
            if (currentSub.isNull()) {
              currentSub = current;
            }
            current = parent;
          }
          else {
            currentSub = Node();
          }
          break;

        // Multiplication/division: must be non-integer and other operand must be non-zero
        case kind::MULT: {
        case kind::DIVISION:
          Assert(parent.getNumChildren() == 2);
          TNode other;
          if (parent[0] == current) {
            other = parent[1];
          }
          else {
            Assert(parent[1] == current);
            other = parent[0];
          }
          if (d_unconstrained.find(other) != d_unconstrained.end()) {
            if (d_unconstrained.find(parent) == d_unconstrained.end() &&
                !d_substitutions.hasSubstitution(parent)) {
              if (current.getType().isInteger() && other.getType().isInteger()) {
                Assert(parent.getKind() == kind::DIVISION || parent.getType().isInteger());
                if (parent.getKind() == kind::DIVISION) {
                  break;
                }
              }
              ++d_numUnconstrainedElim;
              if (currentSub.isNull()) {
                currentSub = current;
              }
              current = parent;
            }
            else {
              currentSub = Node();
            }
          }
          else {
            // if only the denominator of a division is unconstrained, can't set it to 0 so the result is not unconstrained
            if (parent.getKind() == kind::DIVISION && current == parent[1]) {
              break;
            }
            NodeManager* nm = NodeManager::currentNM();
            // if we are an integer, the only way we are unconstrained is if we are a MULT by -1
            if (current.getType().isInteger()) {
              // div/mult by 1 should have been simplified
              Assert(other != nm->mkConst<Rational>(1));
              if (other == nm->mkConst<Rational>(-1)) {
                // div by -1 should have been simplified
                Assert(parent.getKind() == kind::MULT);
                Assert(parent.getType().isInteger());
              }
              else {
                break;
              }
            }
            else {
              // TODO: could build ITE here
              Node test = other.eqNode(nm->mkConst<Rational>(0));
              if (Rewriter::rewrite(test) != nm->mkConst<bool>(false)) {
                break;
              }
            }
            ++d_numUnconstrainedElim;
            if (currentSub.isNull()) {
              currentSub = current;
            }
            current = parent;
          }
          break;
        }

        // Bitvector MULT - current must only appear once in the children:
        // all other children must be unconstrained or odd
        case kind::BITVECTOR_MULT:
        {
          bool found = false;
          bool done = false;
          for(TNode::iterator child_it = parent.begin(); child_it != parent.end(); ++child_it) {
            if ((*child_it) == current) {
              if (found) {
                done = true;
                break;
              }
              found = true;
              continue;
            }
            else if (d_unconstrained.find(*child_it) != d_unconstrained.end()) {
              continue;
            }
            else {
              NodeManager* nm = NodeManager::currentNM();
              Node extractOp = nm->mkConst<BitVectorExtract>(BitVectorExtract(0,0));
              vector<Node> children;
              children.push_back(*child_it);
              Node test = nm->mkNode(extractOp, children);
              BitVector one(1,unsigned(1));
              test = test.eqNode(nm->mkConst<BitVector>(one));
              if (Rewriter::rewrite(test) != nm->mkConst<bool>(true)) {
                done = true;
                break;
              }
            }
          }
          if (done) {
            break;
          }
          if (d_unconstrained.find(parent) == d_unconstrained.end() &&
              !d_substitutions.hasSubstitution(parent)) {
            ++d_numUnconstrainedElim;
            if (currentSub.isNull()) {
              currentSub = current;
            }
            current = parent;
          }
          else {
            currentSub = Node();
          }
          break;
        }

        // Uninterpreted function - if domain is infinite, no quantifiers are used, and any child is unconstrained, result is unconstrained
        case kind::APPLY_UF:
          if (d_logicInfo.isQuantified() || !current.getType().getCardinality().isInfinite()) {
            break;
          }
          if (d_unconstrained.find(parent) == d_unconstrained.end() &&
              !d_substitutions.hasSubstitution(parent)) {
            ++d_numUnconstrainedElim;
            if (currentSub.isNull()) {
              currentSub = current;
            }
            if (parent.getType() != current.getType()) {
              currentSub = newUnconstrainedVar(parent.getType(), currentSub);
            }
            current = parent;
          }
          else {
            currentSub = Node();
          }
          break;

        // Array select - if array is unconstrained, so is result
        case kind::SELECT:
          if (parent[0] == current) {
            ++d_numUnconstrainedElim;
            Assert(current.getType().isArray());
            if (currentSub.isNull()) {
              currentSub = current;
            }
            currentSub = newUnconstrainedVar(current.getType().getArrayConstituentType(), currentSub);
            current = parent;
          }
          break;

        // Array store - if both store and value are unconstrained, so is resulting store
        case kind::STORE:
          if (((parent[0] == current &&
                d_unconstrained.find(parent[2]) != d_unconstrained.end()) ||
               (parent[2] == current &&
                d_unconstrained.find(parent[0]) != d_unconstrained.end()))) {
            if (d_unconstrained.find(parent) == d_unconstrained.end() &&
                !d_substitutions.hasSubstitution(parent)) {
              ++d_numUnconstrainedElim;
              if (parent[0] != current) {
                if (parent[0].isVar()) {
                  currentSub = parent[0];
                }
                else {
                  Assert(d_substitutions.hasSubstitution(parent[0]));
                  currentSub = d_substitutions.apply(parent[0]);
                }
              }
              else if (currentSub.isNull()) {
                currentSub = current;
              }
              current = parent;
            }
            else {
              currentSub = Node();
            }
          }
          break;

        // Bit-vector comparisons: replace with new Boolean variable, but have
        // to also conjoin with a side condition as there is always one case
        // when the comparison is forced to be false
        case kind::BITVECTOR_ULT:
        case kind::BITVECTOR_UGE:
        case kind::BITVECTOR_UGT:
        case kind::BITVECTOR_ULE:
        case kind::BITVECTOR_SLT:
        case kind::BITVECTOR_SGE:
        case kind::BITVECTOR_SGT:
        case kind::BITVECTOR_SLE: {
          // Tuples over (signed, swap, strict).
          switch (parent.getKind()) {
            case kind::BITVECTOR_UGE:
              break;
            case kind::BITVECTOR_ULT:
              strict = true;
              break;
            case kind::BITVECTOR_ULE:
              swap = true;
              break;
            case kind::BITVECTOR_UGT:
              swap = true;
              strict = true;
              break;
            case kind::BITVECTOR_SGE:
              isSigned = true;
              break;
            case kind::BITVECTOR_SLT:
              isSigned = true;
              strict = true;
              break;
            case kind::BITVECTOR_SLE:
              isSigned = true;
              swap = true;
              break;
            case kind::BITVECTOR_SGT:
              isSigned = true;
              swap = true;
              strict = true;
              break;
            default:
              Unreachable();
          }
          TNode other;
          bool left = false;
          if (parent[0] == current) {
            other = parent[1];
            left = true;
          } else {
            Assert(parent[1] == current);
            other = parent[0];
          }
          if (d_unconstrained.find(other) != d_unconstrained.end()) {
            if (d_unconstrained.find(parent) == d_unconstrained.end() &&
                !d_substitutions.hasSubstitution(parent)) {
              ++d_numUnconstrainedElim;
              if (currentSub.isNull()) {
                currentSub = current;
              }
              currentSub = newUnconstrainedVar(parent.getType(), currentSub);
              current = parent;
            } else {
              currentSub = Node();
            }
          } else {
            unsigned size = current.getType().getBitVectorSize();
            BitVector bv =
                isSigned ? BitVector(size, Integer(1).multiplyByPow2(size - 1))
                         : BitVector(size, unsigned(0));
            if (swap == left) {
              bv = ~bv;
            }
            if (currentSub.isNull()) {
              currentSub = current;
            }
            currentSub = newUnconstrainedVar(parent.getType(), currentSub);
            current = parent;
            NodeManager* nm = NodeManager::currentNM();
            Node test =
                Rewriter::rewrite(other.eqNode(nm->mkConst<BitVector>(bv)));
            if (test == nm->mkConst<bool>(false)) {
              break;
            }
            if (strict) {
              currentSub = currentSub.andNode(test.notNode());
            } else {
              currentSub = currentSub.orNode(test);
            }
            // Delay adding this substitution - see comment at end of function
            delayQueueLeft.push_back(current);
            delayQueueRight.push_back(currentSub);
            currentSub = Node();
            parent = TNode();
          }
          break;
        }

        // Do nothing 
        case kind::BITVECTOR_SIGN_EXTEND:
        case kind::BITVECTOR_ZERO_EXTEND:
        case kind::BITVECTOR_REPEAT:
        case kind::BITVECTOR_ROTATE_LEFT:
        case kind::BITVECTOR_ROTATE_RIGHT:

        default:
          break;
      }
      if (current == parent && d_visited[parent] == 1) {
        d_unconstrained.insert(parent);
        continue;
      }
    }
    if (!currentSub.isNull()) {
      Assert(currentSub.isVar());
      d_substitutions.addSubstitution(current, currentSub, false);
    }
    if (workList.empty()) {
      break;
    }
    current = workList.back();
    currentSub = Node();
    workList.pop_back();
  }
  TNode left;
  Node right;
  // All substitutions except those arising from bitvector comparisons are
  // substitutions t -> x where x is a variable.  This allows us to build the
  // substitution very quickly (never invalidating the substitution cache).
  // Bitvector comparisons are more complicated and may require
  // back-substitution and cache-invalidation.  So we do these last.
  while (!delayQueueLeft.empty()) {
    left = delayQueueLeft.back();
    if (!d_substitutions.hasSubstitution(left)) {
      right = d_substitutions.apply(delayQueueRight.back());
      d_substitutions.addSubstitution(delayQueueLeft.back(), right);
    }
    delayQueueLeft.pop_back();
    delayQueueRight.pop_back();
  }
}