Example #1
0
bool SharedTermsDatabase::areDisequal(TNode a, TNode b) const {
  if (d_equalityEngine.hasTerm(a) && d_equalityEngine.hasTerm(b)) {
    return d_equalityEngine.areDisequal(a,b,false);
  } else {
    Assert(d_equalityEngine.hasTerm(a) || a.isConst());
    Assert(d_equalityEngine.hasTerm(b) || b.isConst());
    // one (or both) are in the equality engine
    return false;
  }
}
Example #2
0
bool SharedTermsDatabase::areEqual(TNode a, TNode b) const {
  if (d_equalityEngine.hasTerm(a) && d_equalityEngine.hasTerm(b)) {
    return d_equalityEngine.areEqual(a,b);
  } else {
    Assert(d_equalityEngine.hasTerm(a) || a.isConst());
    Assert(d_equalityEngine.hasTerm(b) || b.isConst());
    // since one (or both) of them is a constant, and the other is in the equality engine, they are not same
    return false;
  }
}
Example #3
0
bool ITESimplifier::leavesAreConst(TNode e, TheoryId tid)
{
  Assert((e.getKind() == kind::ITE && !e.getType().isBoolean()) ||
         Theory::theoryOf(e) != THEORY_BOOL);
  if (e.isConst()) {
    return true;
  }

  hash_map<Node, bool, NodeHashFunction>::iterator it;
  it = d_leavesConstCache.find(e); 
  if (it != d_leavesConstCache.end()) {
    return (*it).second;
  }

  if (!containsTermITE(e) && Theory::isLeafOf(e, tid)) {
    d_leavesConstCache[e] = false;
    return false;
  }

  Assert(e.getNumChildren() > 0);
  size_t k = 0, sz = e.getNumChildren();

  if (e.getKind() == kind::ITE) {
    k = 1;
  }

  for (; k < sz; ++k) {
    if (!leavesAreConst(e[k], tid)) {
      d_leavesConstCache[e] = false;
      return false;
    }
  }
  d_leavesConstCache[e] = true;
  return true;
}
Example #4
0
Node ModelPostprocessor::rewriteAs(TNode n, TypeNode asType) {
  if(n.getType().isSubtypeOf(asType)) {
    // good to go, we have the right type
    return n;
  }
  if(!n.isConst()) {
    // we don't handle non-const right now
    return n;
  }
  if(asType.isBoolean()) {
    if(n.getType().isBitVector(1u)) {
      // type mismatch: should only happen for Boolean-term conversion under
      // datatype constructor applications; rewrite from BV(1) back to Boolean
      bool tf = (n.getConst<BitVector>().getValue() == 1);
      return NodeManager::currentNM()->mkConst(tf);
    }
    if(n.getType().isDatatype() && n.getType().hasAttribute(BooleanTermAttr())) {
      // type mismatch: should only happen for Boolean-term conversion under
      // datatype constructor applications; rewrite from datatype back to Boolean
      Assert(n.getKind() == kind::APPLY_CONSTRUCTOR);
      Assert(n.getNumChildren() == 0);
      // we assume (by construction) false is first; see boolean_terms.cpp
      bool tf = (Datatype::indexOf(n.getOperator().toExpr()) == 1);
      Debug("boolean-terms") << "+++ rewriteAs " << n << " : " << asType << " ==> " << tf << endl;
      return NodeManager::currentNM()->mkConst(tf);
    }
  }
  if(n.getType().isBoolean()) {
    bool tf = n.getConst<bool>();
    if(asType.isBitVector(1u)) {
      return NodeManager::currentNM()->mkConst(BitVector(1u, tf ? 1u : 0u));
    }
    if(asType.isDatatype() && asType.hasAttribute(BooleanTermAttr())) {
      const Datatype& asDatatype = asType.getConst<Datatype>();
      return NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, (tf ? asDatatype[0] : asDatatype[1]).getConstructor());
    }
  }
  if(n.getType().isRecord() && asType.isRecord()) {
    Debug("boolean-terms") << "+++ got a record - rewriteAs " << n << " : " << asType << endl;
    const Record& rec CVC4_UNUSED = n.getType().getConst<Record>();
    const Record& asRec = asType.getConst<Record>();
    Assert(rec.getNumFields() == asRec.getNumFields());
    Assert(n.getNumChildren() == asRec.getNumFields());
    NodeBuilder<> b(n.getKind());
    b << asType;
    for(size_t i = 0; i < n.getNumChildren(); ++i) {
      b << rewriteAs(n[i], TypeNode::fromType(asRec[i].second));
    }
    Node out = b;
    Debug("boolean-terms") << "+++ returning record " << out << endl;
    return out;
  }
Example #5
0
void AbstractionModule::makeFreshSkolems(TNode node, SubstitutionMap& map, SubstitutionMap& reverse_map) {
  if (map.hasSubstitution(node)) {
    return;
  }
  if (node.getMetaKind() == kind::metakind::VARIABLE) {
    Node skolem = utils::mkVar(utils::getSize(node));
    map.addSubstitution(node, skolem);
    reverse_map.addSubstitution(skolem, node);
    return;
  }
  if (node.isConst())
    return;

  for (unsigned i = 0; i < node.getNumChildren(); ++i) {
    makeFreshSkolems(node[i], map, reverse_map);
  }
}
Example #6
0
Node RePairAssocCommutativeOperators::case_other(TNode n){
  if(n.isConst() || n.isVar()){
    return n;
  }

  NodeBuilder<> nb(n.getKind());

  if(n.getMetaKind() == kind::metakind::PARAMETERIZED) {
    nb << n.getOperator();
  }

  // Remove the ITEs from the children
  for(TNode::const_iterator i = n.begin(), end = n.end(); i != end; ++i) {
    Node newChild = rePairAssocCommutativeOperators(*i);
    nb << newChild;
  }

  Node result = (Node)nb;
  return result;
}
Example #7
0
void AbstractionModule::makeFreshArgs(TNode func, std::vector<Node>& fresh_args) {
  Assert (fresh_args.size() == 0);
  Assert (func.getKind() == kind::APPLY_UF);
  TNodeNodeMap d_map; 
  for (unsigned i = 0; i < func.getNumChildren(); ++i) {
    TNode arg = func[i];
    if (arg.isConst()) {
      fresh_args.push_back(arg);
      continue;
    }
    Assert (arg.getMetaKind() == kind::metakind::VARIABLE);
    TNodeNodeMap::iterator it = d_map.find(arg); 
    if (it != d_map.end()) {
      fresh_args.push_back(it->second); 
    } else {
      Node skolem = utils::mkVar(utils::getSize(arg));
      d_map[arg] = skolem;
      fresh_args.push_back(skolem);
    }
  }
  Assert (fresh_args.size() == func.getNumChildren());
}
Example #8
0
Node TheoryModel::getModelValue(TNode n, bool hasBoundVars) const
{
  Assert(n.getKind() != kind::FORALL && n.getKind() != kind::EXISTS);
  if(n.getKind() == kind::LAMBDA) {
    NodeManager* nm = NodeManager::currentNM();
    Node body = getModelValue(n[1], true);
    // This is a bit ugly, but cache inside simplifier can change, so can't be const
    // The ite simplifier is needed to get rid of artifacts created by Boolean terms
    body = const_cast<ITESimplifier*>(&d_iteSimp)->simpITE(body);
    body = Rewriter::rewrite(body);
    return nm->mkNode(kind::LAMBDA, n[0], body);
  }
  if(n.isConst() || (hasBoundVars && n.getKind() == kind::BOUND_VARIABLE)) {
    return n;
  }

  TypeNode t = n.getType();
  if (t.isFunction() || t.isPredicate()) {
    if (d_enableFuncModels) {
      std::map< Node, Node >::const_iterator it = d_uf_models.find(n);
      if (it != d_uf_models.end()) {
        // Existing function
        return it->second;
      }
      // Unknown function symbol: return LAMBDA x. c, where c is the first constant in the enumeration of the range type
      vector<TypeNode> argTypes = t.getArgTypes();
      vector<Node> args;
      NodeManager* nm = NodeManager::currentNM();
      for (unsigned i = 0; i < argTypes.size(); ++i) {
        args.push_back(nm->mkBoundVar(argTypes[i]));
      }
      Node boundVarList = nm->mkNode(kind::BOUND_VAR_LIST, args);
      TypeEnumerator te(t.getRangeType());
      return nm->mkNode(kind::LAMBDA, boundVarList, *te);
    }
    // TODO: if func models not enabled, throw an error?
    Unreachable();
  }

  if (n.getNumChildren() > 0) {
    std::vector<Node> children;
    if (n.getKind() == APPLY_UF) {
      Node op = getModelValue(n.getOperator(), hasBoundVars);
      children.push_back(op);
    }
    else if (n.getMetaKind() == kind::metakind::PARAMETERIZED) {
      children.push_back(n.getOperator());
    }
    //evaluate the children
    for (unsigned i = 0; i < n.getNumChildren(); ++i) {
      Node val = getModelValue(n[i], hasBoundVars);
      children.push_back(val);
    }
    Node val = Rewriter::rewrite(NodeManager::currentNM()->mkNode(n.getKind(), children));
    Assert(hasBoundVars || val.isConst());
    return val;
  }

  if (!d_equalityEngine.hasTerm(n)) {
    // Unknown term - return first enumerated value for this type
    TypeEnumerator te(n.getType());
    return *te;
  }
  Node val = d_equalityEngine.getRepresentative(n);
  Assert(d_reps.find(val) != d_reps.end());
  std::map< Node, Node >::const_iterator it = d_reps.find( val );
  if( it!=d_reps.end() ){
    return it->second;
  }else{
    return Node::null();
  }
}
Example #9
0
bool AlgebraicSolver::check(Theory::Effort e) {
  Assert(options::bitblastMode() == theory::bv::BITBLAST_MODE_LAZY); 

  if (!Theory::fullEffort(e))
    return true;

  if (!useHeuristic())
    return true;
  
  ++(d_numCalls);
  
  TimerStat::CodeTimer algebraicTimer(d_statistics.d_solveTime);
  Debug("bv-subtheory-algebraic") << "AlgebraicSolver::check (" << e << ")\n";
  ++(d_statistics.d_numCallstoCheck);

  d_explanations.clear();
  d_ids.clear(); 
  d_inputAssertions.clear(); 

  std::vector<WorklistElement> worklist;

  uint64_t original_bb_cost = 0;

  NodeSet seen_assertions;
  // Processing assertions from scratch
  for (AssertionQueue::const_iterator it = assertionsBegin(); it != assertionsEnd(); ++it) {
    Debug("bv-subtheory-algebraic") << "   " << *it << "\n";
    TNode assertion = *it;
    unsigned id = worklist.size();
    d_ids[assertion] = id; 
    worklist.push_back(WorklistElement(assertion, id));
    d_inputAssertions.insert(assertion); 
    storeExplanation(assertion);

    uint64_t assertion_size = d_quickSolver->computeAtomWeight(assertion, seen_assertions);
    Assert (original_bb_cost <= original_bb_cost + assertion_size);
    original_bb_cost+= assertion_size; 
  }

  for (unsigned i = 0; i < worklist.size(); ++i) {
    d_ids[worklist[i].node] = worklist[i].id;
  }
  
  Debug("bv-subtheory-algebraic") << "Assertions " << worklist.size() <<" : \n";

  Assert (d_explanations.size() == worklist.size()); 

  delete d_modelMap;
  d_modelMap = new SubstitutionMap(d_context);
  SubstitutionEx subst(d_modelMap);

  // first round of substitutions
  processAssertions(worklist, subst); 

  if (!d_isDifficult.get()) {
    // skolemize all possible extracts
    ExtractSkolemizer skolemizer(d_modelMap);
    skolemizer.skolemize(worklist);
    // second round of substitutions
    processAssertions(worklist, subst); 
  }
  
  NodeSet subst_seen;
  uint64_t subst_bb_cost = 0;

  unsigned r = 0;
  unsigned w = 0;

  for (; r < worklist.size(); ++r) {

    TNode fact = worklist[r].node;
    unsigned id = worklist[r].id;
    
    if (Dump.isOn("bv-algebraic")) {
      Node expl = d_explanations[id];
      Node query = utils::mkNot(utils::mkNode(kind::IMPLIES, expl, fact));
      Dump("bv-algebraic") << EchoCommand("ThoeryBV::AlgebraicSolver::substitution explanation"); 
      Dump("bv-algebraic") << PushCommand(); 
      Dump("bv-algebraic") << AssertCommand(query.toExpr());
      Dump("bv-algebraic") << CheckSatCommand();
      Dump("bv-algebraic") << PopCommand(); 
    }

    if (fact.isConst() &&
        fact.getConst<bool>() == true) {
      continue;
    }

    if (fact.isConst() &&
        fact.getConst<bool>() == false) {
      // we have a conflict
      Node conflict = BooleanSimplification::simplify(d_explanations[id]);
      d_bv->setConflict(conflict);
      d_isComplete.set(true);
      Debug("bv-subtheory-algebraic") << " UNSAT: assertion simplfies to false with conflict: "<< conflict << "\n";
       
      if (Dump.isOn("bv-algebraic")) {
        Dump("bv-algebraic") << EchoCommand("TheoryBV::AlgebraicSolver::conflict"); 
        Dump("bv-algebraic") << PushCommand(); 
        Dump("bv-algebraic") << AssertCommand(conflict.toExpr());
        Dump("bv-algebraic") << CheckSatCommand();
        Dump("bv-algebraic") << PopCommand(); 
      }

      
      ++(d_statistics.d_numSimplifiesToFalse);
      ++(d_numSolved);
      return false;
    }

    subst_bb_cost+= d_quickSolver->computeAtomWeight(fact, subst_seen);
    worklist[w] = WorklistElement(fact, id);
    Node expl =  BooleanSimplification::simplify(d_explanations[id]);
    storeExplanation(id, expl);
    d_ids[fact] = id;
    ++w;
  }

  worklist.resize(w);

  
  if(Debug.isOn("bv-subtheory-algebraic")) {
    Debug("bv-subtheory-algebraic") << "Assertions post-substitutions " << worklist.size() << ":\n";
    for (unsigned i = 0; i < worklist.size(); ++i) {
      Debug("bv-subtheory-algebraic") << "   " << worklist[i].node << "\n";
    }
  }

  
  // all facts solved to true
  if (worklist.empty()) {
    Debug("bv-subtheory-algebraic") << " SAT: everything simplifies to true.\n";
    ++(d_statistics.d_numSimplifiesToTrue);
    ++(d_numSolved);
    return true;
  }

  double ratio = ((double)subst_bb_cost)/original_bb_cost;
  if (ratio > 0.5 ||
      !d_isDifficult.get()) {
    // give up if problem not reduced enough
    d_isComplete.set(false);
    return true;
  }
  
  d_quickSolver->clearSolver();

  d_quickSolver->push();
  std::vector<Node> facts;
  for (unsigned i = 0; i < worklist.size(); ++i) {
    facts.push_back(worklist[i].node); 
  }
  bool ok = quickCheck(facts);

  Debug("bv-subtheory-algebraic") << "AlgebraicSolver::check done " << ok << ".\n";
  return ok;
}
Example #10
0
TheoryId Theory::theoryOf(TheoryOfMode mode, TNode node) {
  TheoryId tid = THEORY_BUILTIN;
  switch(mode) {
  case THEORY_OF_TYPE_BASED:
    // Constants, variables, 0-ary constructors
    if (node.isVar() || node.isConst()) {
      tid = Theory::theoryOf(node.getType());
    } else if (node.getKind() == kind::EQUAL) {
      // Equality is owned by the theory that owns the domain
      tid = Theory::theoryOf(node[0].getType());
    } else {
      // Regular nodes are owned by the kind
      tid = kindToTheoryId(node.getKind());
    }
    break;
  case THEORY_OF_TERM_BASED:
    // Variables
    if (node.isVar()) {
      if (Theory::theoryOf(node.getType()) != theory::THEORY_BOOL) {
        // We treat the variables as uninterpreted
        tid = s_uninterpretedSortOwner;
      } else {
        // Except for the Boolean ones, which we just ignore anyhow
        tid = theory::THEORY_BOOL;
      }
    } else if (node.isConst()) {
      // Constants go to the theory of the type
      tid = Theory::theoryOf(node.getType());
    } else if (node.getKind() == kind::EQUAL) { // Equality
      // If one of them is an ITE, it's irelevant, since they will get replaced out anyhow
      if (node[0].getKind() == kind::ITE) {
        tid = Theory::theoryOf(node[0].getType());
      } else if (node[1].getKind() == kind::ITE) {
        tid = Theory::theoryOf(node[1].getType());
      } else {
        TNode l = node[0];
        TNode r = node[1];
        TypeNode ltype = l.getType();
        TypeNode rtype = r.getType();
        if( ltype != rtype ){
          tid = Theory::theoryOf(l.getType());
        }else {
          // If both sides belong to the same theory the choice is easy
          TheoryId T1 = Theory::theoryOf(l);
          TheoryId T2 = Theory::theoryOf(r);
          if (T1 == T2) {
            tid = T1;
          } else {
            TheoryId T3 = Theory::theoryOf(ltype);
            // This is a case of
            // * x*y = f(z) -> UF
            // * x = c      -> UF
            // * f(x) = read(a, y) -> either UF or ARRAY
            // at least one of the theories has to be parametric, i.e. theory of the type is different
            // from the theory of the term
            if (T1 == T3) {
              tid = T2;
            } else if (T2 == T3) {
              tid = T1;
            } else {
              // If both are parametric, we take the smaller one (arbitrary)
              tid = T1 < T2 ? T1 : T2;
            }
          }
        }
      }
    } else {
      // Regular nodes are owned by the kind
      tid = kindToTheoryId(node.getKind());
    }
    break;
  default:
    Unreachable();
  }
  Trace("theory::internal") << "theoryOf(" << mode << ", " << node << ") -> " << tid << std::endl;
  return tid;
}