void StatisicsPropertyintegration::setup()
{
    m_char_type = new TypeNode("char_type");

    m_char_property = new StatisticsProperty;
    m_char_property->setFlags(flag_class);
    m_char_type->addProperty("char_prop", m_char_property);

    m_char1 = new Entity("1", 1);
    m_char1->setType(m_char_type);
    m_char_property->install(m_char1, "char_prop");
    m_char_property->apply(m_char1);

    m_char2 = new Entity("2", 2);
    m_char2->setType(m_char_type);
    m_char_property->install(m_char2, "char_prop");
    m_char_property->apply(m_char2);
}
Exemple #2
0
bool TermEnumeration::isClosedEnumerableType(TypeNode tn)
{
  std::unordered_map<TypeNode, bool, TypeNodeHashFunction>::iterator it =
      d_typ_closed_enum.find(tn);
  if (it == d_typ_closed_enum.end())
  {
    d_typ_closed_enum[tn] = true;
    bool ret = true;
    if (tn.isArray() || tn.isSort() || tn.isCodatatype() || tn.isFunction())
    {
      ret = false;
    }
    else if (tn.isSet())
    {
      ret = isClosedEnumerableType(tn.getSetElementType());
    }
    else if (tn.isDatatype())
    {
      const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
      for (unsigned i = 0; i < dt.getNumConstructors(); i++)
      {
        for (unsigned j = 0; j < dt[i].getNumArgs(); j++)
        {
          TypeNode ctn = TypeNode::fromType(dt[i][j].getRangeType());
          if (tn != ctn && !isClosedEnumerableType(ctn))
          {
            ret = false;
            break;
          }
        }
        if (!ret)
        {
          break;
        }
      }
    }
    
    // other parametric sorts go here
    
    d_typ_closed_enum[tn] = ret;
    return ret;
  }
  else
  {
    return it->second;
  }
}
Exemple #3
0
void Entitytest::test_setAttr_type()
{
    TestProperty * type_property = new TestProperty;
    type_property->data() = 17;
    type_property->flags() &= flag_class;
    m_type->addProperty("test_int_property", type_property);

    PropertyBase * pb = m_entity->setAttr("test_int_property", 24);
    ASSERT_NOT_NULL(pb);
    ASSERT_NOT_EQUAL(type_property, pb);

    ASSERT_TRUE((pb->flags() & flag_class) == 0);

    auto * int_property = dynamic_cast<TestProperty *>(pb);
    ASSERT_NOT_NULL(int_property);
    ASSERT_EQUAL(int_property->data(), 24);
    ASSERT_TRUE(!m_TestProperty_install_called);
    ASSERT_TRUE(m_TestProperty_apply_called);
}
Exemple #4
0
Node DatatypesEnumerator::getTermEnum( TypeNode tn, unsigned i ){
   Node ret;
   if( i<d_terms[tn].size() ){
     ret = d_terms[tn][i];
   }else{
     Debug("dt-enum-debug") << "get term enum " << tn << " " << i << std::endl;
     std::map< TypeNode, unsigned >::iterator it = d_te_index.find( tn );
     unsigned tei;
     if( it==d_te_index.end() ){
       //initialize child enumerator for type
       tei = d_children.size();
       d_te_index[tn] = tei;
       if( tn.isDatatype() && d_has_debruijn ){
         //must indicate that this is a child enumerator (do not normalize constants for it)
         DatatypesEnumerator * dte = new DatatypesEnumerator( tn, true );
         d_children.push_back( TypeEnumerator( dte ) );
       }else{
         d_children.push_back( TypeEnumerator( tn ) );
       }
       d_terms[tn].push_back( *d_children[tei] );
     }else{
       tei = it->second;
     }
     //enumerate terms until index is reached
     while( i>=d_terms[tn].size() ){
       ++d_children[tei];
       if( d_children[tei].isFinished() ){
         Debug("dt-enum-debug") << "...fail term enum " << tn << " " << i << std::endl;
         return Node::null();
       }
       d_terms[tn].push_back( *d_children[tei] );
     }
     Debug("dt-enum-debug") << "...return term enum " << tn << " " << i << " : " << d_terms[tn][i] << std::endl;
     ret = d_terms[tn][i];
   }
   return ret;
 }
Exemple #5
0
TypeNode* TypeNameNode::getTypeNode(TemplateArguments* templateArguments)
{
	//assert(0 == templateArguments || templateArguments->m_classTypeNode->isTemplateClassInstance());
	assert(0 != m_startTypeNode);
	TypeNode* result = 0;
	if (0 == m_typeNode)// under template parameter
	{
		assert(templateArguments && m_startTypeNode 
			&& (m_startTypeNode->isTemplateParameter() || m_startTypeNode->isTypedef()) );
		if (templateArguments->m_classTypeNode->isClass())
		{
			return 0;
		}
		TypeNode* actualStartTypeNode = m_startTypeNode->getActualTypeNode(templateArguments);
		assert(actualStartTypeNode);
		std::vector<ScopeNameNode*> scopeNameNodes;
		m_scopeNameList->collectIdentifyNodes(scopeNameNodes);
		if (scopeNameNodes.size() == 1)
		{
			result = actualStartTypeNode;
		}
		else
		{
			scopeNameNodes.erase(scopeNameNodes.begin());
			TypeNode* initialTypeTreeNode = 0;
			TypeNode* finalTypeTreeNode = 0;
			if (g_typeTree.findNodeByScopeNames(initialTypeTreeNode, finalTypeTreeNode,
				scopeNameNodes, actualStartTypeNode, templateArguments))
			{
				assert(finalTypeTreeNode);
				result = finalTypeTreeNode;
			}
		}
	}
	else if (m_typeNode->isTemplateParameter())
	{
		assert(templateArguments);
		result = templateArguments->findTypeNode(m_scopeNameList->m_scopeName->m_name->m_str);
	}
	else if (m_typeNode->isTemplateClass())
	{
		assert(templateArguments);
		if (m_scopeNameList->m_scopeName->isTemplateForm())
		{
			result = g_typeTree.findNodeByScopeName(m_scopeNameList->m_scopeName, m_typeNode->m_enclosing, templateArguments);
		}
		else
		{
			assert(m_scopeNameList->m_scopeName->m_name->m_str == templateArguments->m_className);
			result = templateArguments->m_classTypeNode;
		}
	}
	else if (m_typeNode->isUnderTemplateClass())
	{
		assert(templateArguments);
		if (m_startTypeNode->isUnderTemplateClass())
		{
			std::vector<TypeNode*> typeNodes;
			TypeNode* typeNode = m_typeNode;
			while (typeNode)
			{
				if (typeNode->isTemplateClass())
				{
					break;
				}
				typeNodes.push_back(typeNode);
				typeNode = typeNode->m_enclosing;
			}
			assert(typeNode->isTemplateClass() && typeNode->m_name == templateArguments->m_className);
			typeNode = templateArguments->m_classTypeNode;
			auto it = typeNodes.rbegin();
			auto end = typeNodes.rend();
			for (; it != end; ++it)
			{
				TypeNode* tempTypeNode = *it;
				typeNode = typeNode->getChildNode(tempTypeNode->m_name);
				assert(typeNode);
			}
			if (typeNode->isTypedef())
			{
				TypeNode* actualTypeNode = typeNode->getActualTypeNode(templateArguments);
				if (actualTypeNode->isTemplateParameter())
				{
					typeNode = templateArguments->findTypeNode(actualTypeNode->m_name);
					assert(0 != typeNode);
				}
			}
			result = typeNode;
		}
		else
		{
			std::vector<ScopeNameNode*> scopeNameNodes;
			m_scopeNameList->collectIdentifyNodes(scopeNameNodes);
			TypeNode* initialTypeTreeNode = 0;
			TypeNode* finalTypeTreeNode = 0;
			if (m_startTypeNode->isTemplateClass() && !scopeNameNodes[0]->isTemplateForm())
			{
				assert(m_startTypeNode->m_name == templateArguments->m_className);
				scopeNameNodes.erase(scopeNameNodes.begin());
				if (g_typeTree.findNodeByScopeNames(initialTypeTreeNode, finalTypeTreeNode,
					scopeNameNodes, templateArguments->m_classTypeNode, templateArguments))
				{
					result = finalTypeTreeNode;
				}
			}
			else
			{
				if (g_typeTree.findNodeByScopeNames(initialTypeTreeNode, finalTypeTreeNode,
					scopeNameNodes, m_startTypeNode->m_enclosing, templateArguments))
				{
					result = finalTypeTreeNode;
				}
			}
		}
	}
	else
	{
		assert(m_typeNode->isPredefinedType() ||
			m_typeNode->isEnum() ||
			m_typeNode->isClass() ||
			m_typeNode->isTemplateClassInstance() ||
			m_typeNode->isTypedef() ||
			m_typeNode->isTypeDeclaration());
		result = m_typeNode;
	}

	if(0 == result)
	{
		RaiseError_InvalidTypeName(m_scopeNameList);
	}
	return result;
}
Exemple #6
0
void TypeNameNode::getRelativeName(std::string& typeName, ScopeNode* scopeNode)
{
	assert(m_startTypeNode && scopeNode);
	if (0 == m_scopeNameList)// predefined type
	{
		m_typeNode->getFullName(typeName);
	}
	else
	{
		if (m_typeNode)
		{
			MemberNode* memberNode = m_typeNode->getSyntaxNode();
			if (memberNode && memberNode->m_nativeName)
			{
				memberNode->getNativeName(typeName, 0);
				return;
			}
		}
		if (m_scopeNameList->isGlobal())
		{
			m_scopeNameList->getString(typeName);
		}
		else
		{
			TypeNode* scopeTypeNode = scopeNode->getTypeNode();

			std::vector<TypeNode*> enclosings;
			m_startTypeNode->getEnclosings(enclosings);
			std::vector<TypeNode*> scopeEnclosings;
			scopeTypeNode->getEnclosings(scopeEnclosings);
			scopeEnclosings.push_back(scopeTypeNode);

			auto it = enclosings.begin();
			auto end = enclosings.end();
			auto it2 = scopeEnclosings.begin();
			auto end2 = scopeEnclosings.end();
			for (; it2 != end2; ++it2)
			{
				if (it == end)
				{
					break;
				}
				if (*it != *it2)
				{
					break;
				}
				++it;
			}
			typeName.clear();
			for (; it != end; ++it)
			{
				TypeNode* typeNode = *it;
				std::string localName;
				typeNode->getLocalName(localName);
				typeName += localName + "::";
			}
			std::string str;
			m_scopeNameList->getString(str);
			typeName += str;
		}
	}
}
Exemple #7
0
TypeCategory TemplateParameterTypeNode::getTypeCategory(TemplateArguments* templateArguments)
{
	TypeNode* actualTypeNode = templateArguments->findTypeNode(m_name);
	return actualTypeNode->getTypeCategory(templateArguments);

}
Exemple #8
0
void TypeNodeProvider::value(Atlas::Message::Element& value, const TypeNode& type) const
{
    if (m_attribute_name == "name") {
        value = type.name();
    }
}
Exemple #9
0
Node DtInstantiator::solve_dt(Node v, Node a, Node b, Node sa, Node sb)
{
  Trace("cegqi-arith-debug2") << "Solve dt : " << v << " " << a << " " << b
                              << " " << sa << " " << sb << std::endl;
  Node ret;
  if (!a.isNull() && a == v)
  {
    ret = sb;
  }
  else if (!b.isNull() && b == v)
  {
    ret = sa;
  }
  else if (!a.isNull() && a.getKind() == APPLY_CONSTRUCTOR)
  {
    if (!b.isNull() && b.getKind() == APPLY_CONSTRUCTOR)
    {
      if (a.getOperator() == b.getOperator())
      {
        for (unsigned i = 0, nchild = a.getNumChildren(); i < nchild; i++)
        {
          Node s = solve_dt(v, a[i], b[i], sa[i], sb[i]);
          if (!s.isNull())
          {
            return s;
          }
        }
      }
    }
    else
    {
      NodeManager* nm = NodeManager::currentNM();
      unsigned cindex = Datatype::indexOf(a.getOperator().toExpr());
      TypeNode tn = a.getType();
      const Datatype& dt = static_cast<DatatypeType>(tn.toType()).getDatatype();
      for (unsigned i = 0, nchild = a.getNumChildren(); i < nchild; i++)
      {
        Node nn = nm->mkNode(
            APPLY_SELECTOR_TOTAL,
            Node::fromExpr(dt[cindex].getSelectorInternal(tn.toType(), i)),
            sb);
        Node s = solve_dt(v, a[i], Node::null(), sa[i], nn);
        if (!s.isNull())
        {
          return s;
        }
      }
    }
  }
  else if (!b.isNull() && b.getKind() == APPLY_CONSTRUCTOR)
  {
    // flip sides
    return solve_dt(v, b, a, sb, sa);
  }
  if (!ret.isNull())
  {
    // ensure does not contain v
    if (expr::hasSubterm(ret, v))
    {
      ret = Node::null();
    }
  }
  return ret;
}
    void setup()
    {
        m_inheritance = new Inheritance();
//Set up testing environment for Type/Soft properties
        m_b1 = new TestEntity("1", 1);
        add_entity(m_b1);

        m_thingType = new TypeNode("thing");
        types["thing"] = m_thingType;

        m_barrelType = new TypeNode("barrel");
        m_barrelType->setParent(m_thingType);
        types["barrel"] = m_barrelType;
        m_b1->setType(m_barrelType);
        m_b1->setProperty("mass", new SoftProperty(Element(30)));
        m_b1->setProperty("burn_speed", new SoftProperty(Element(0.3)));
        m_b1->setProperty("isVisible", new SoftProperty(Element(true)));

        m_b2 = new Entity("2", 2);
        add_entity(m_b2);
        m_b2->setProperty("mass", new SoftProperty(Element(20)));
        m_b2->setProperty("burn_speed", new SoftProperty(0.25));
        m_b2->setType(m_barrelType);
        m_b2->setProperty("isVisible", new SoftProperty(Element(false)));

        m_b3 = new Entity("3", 3);
        add_entity(m_b3);
        m_b3->setProperty("mass", new SoftProperty(Element(25)));
        m_b3->setProperty("burn_speed", new SoftProperty(Element(0.25)));
        m_b3->setType(m_barrelType);

        m_boulderType = new TypeNode("boulder");
        types["boulder"] = m_boulderType;
        m_bl1 = new Entity("4", 4);
        add_entity(m_bl1);
        m_bl1->setProperty("mass", new SoftProperty(Element(25)));
        m_bl1->setType(m_boulderType);

        SoftProperty* prop1 = new SoftProperty();
        prop1->set(std::vector<Element>{25.0, 20.0});
        m_bl1->setProperty("float_list", prop1);

        SoftProperty* list_prop2 = new SoftProperty();
        list_prop2->set(std::vector<Element>{"foo", "bar"});
        m_bl1->setProperty("string_list", list_prop2);

// Create an entity-related memory map
        Atlas::Message::MapType entity_memory_map{{"disposition", 25}};

        m_memory.emplace("1", entity_memory_map);

//b1 contains bl1 which contains b3
        m_b1_container = new LocatedEntitySet;
        m_b1_container->insert(m_bl1);
        m_bl1->m_location.m_parent = m_b1;
        m_b1->m_contains = m_b1_container;
        m_b1->test_setDomain(new TestDomain(*m_b1));

        m_bl1_container = new LocatedEntitySet;
        m_bl1_container->insert(m_b3);
        m_b3->m_location.m_parent = m_bl1;

        m_bl1->m_contains = m_bl1_container;

//Set up testing environment for Outfit property
        m_glovesType = new TypeNode("gloves");
        types["gloves"] = m_glovesType;
        m_bootsType = new TypeNode("boots");
        m_characterType = new TypeNode("character");
        types["character"] = m_characterType;
        TypeNode* m_clothType = new TypeNode("cloth");
        types["cloth"] = m_clothType;
        TypeNode* m_leatherType = new TypeNode("leather");

        m_glovesEntity = new Entity("5", 5);
        add_entity(m_glovesEntity);
        m_glovesEntity->setType(m_glovesType);
        m_glovesEntity->setProperty("color", new SoftProperty("brown"));
        m_glovesEntity->setProperty("mass", new SoftProperty(5));
        //Mark it with a "reach" so we can use it in the "can_reach ... with" tests
        auto reachProp = new Property<double>();
        reachProp->data() = 10.0f;
        m_glovesEntity->setProperty("reach", reachProp);

        m_bootsEntity = new Entity("6", 6);
        add_entity(m_bootsEntity);
        m_bootsEntity->setType(m_bootsType);
        m_bootsEntity->setProperty("color", new SoftProperty("black"));
        m_bootsEntity->setProperty("mass", new SoftProperty(10));


        m_cloth = new Entity("8", 8);
        add_entity(m_cloth);
        m_cloth->setType(m_clothType);
        m_cloth->setProperty("color", new SoftProperty("green"));

        m_leather = new Entity("9", 9);
        add_entity(m_leather);
        m_leather->setType(m_leatherType);
        m_leather->setProperty("color", new SoftProperty("pink"));

        //The m_cloth entity is attached to the gloves by the "thumb" attachment
        {
            auto attachedProp = new SoftProperty();
            attachedProp->data() = Atlas::Message::MapType{{"$eid", m_cloth->getId()}};
            m_glovesEntity->setProperty("attached_thumb", attachedProp);

            auto plantedOnProp = new PlantedOnProperty();
            plantedOnProp->data().entity = WeakEntityRef(m_glovesEntity.get());
            m_cloth->setProperty("planted_on", plantedOnProp);
        }

        m_ch1 = new Entity("7", 7);
        add_entity(m_ch1);
        m_ch1->setType(m_characterType);

        //The m_glovesEntity entity is attached to the m_ch1 by the "hand_primary" attachment
        {
            auto attachedHandPrimaryProp = new SoftProperty();
            attachedHandPrimaryProp->data() = Atlas::Message::MapType{{"$eid", m_glovesEntity->getId()}};
            m_ch1->setProperty("attached_hand_primary", attachedHandPrimaryProp);
        }

        {
            auto plantedOnProp = new PlantedOnProperty();
            plantedOnProp->data().entity = WeakEntityRef(m_ch1.get());
            m_glovesEntity->setProperty("planted_on", plantedOnProp);
        }

        BBoxProperty* bbox1 = new BBoxProperty;
        bbox1->set((std::vector<Element>{-1, -3, -2, 1, 3, 2}));
        m_b1->setProperty("bbox", bbox1);

        BBoxProperty* bbox2 = new BBoxProperty;
        bbox2->set(std::vector<Element>{-3, -2, -1, 1, 3, 2});
        m_bl1->setProperty("bbox", bbox2);

        m_cloth->setProperty("bbox", bbox1->copy());
    }
Exemple #11
0
PreprocessingPassResult SygusAbduct::applyInternal(
    AssertionPipeline* assertionsToPreprocess)
{
  NodeManager* nm = NodeManager::currentNM();
  Trace("sygus-abduct") << "Run sygus abduct..." << std::endl;

  Trace("sygus-abduct-debug") << "Collect symbols..." << std::endl;
  std::unordered_set<Node, NodeHashFunction> symset;
  std::vector<Node>& asserts = assertionsToPreprocess->ref();
  // do we have any assumptions, e.g. via check-sat-assuming?
  bool usingAssumptions = (assertionsToPreprocess->getNumAssumptions() > 0);
  // The following is our set of "axioms". We construct this set only when the
  // usingAssumptions (above) is true. In this case, our input formula is
  // partitioned into Fa ^ Fc as described in the header of this class, where:
  // - The conjunction of assertions marked as assumptions are the negated
  // conjecture Fc, and
  // - The conjunction of all other assertions are the axioms Fa.
  std::vector<Node> axioms;
  for (size_t i = 0, size = asserts.size(); i < size; i++)
  {
    expr::getSymbols(asserts[i], symset);
    // if we are not an assumption, add it to the set of axioms
    if (usingAssumptions && i < assertionsToPreprocess->getAssumptionsStart())
    {
      axioms.push_back(asserts[i]);
    }
  }
  Trace("sygus-abduct-debug")
      << "...finish, got " << symset.size() << " symbols." << std::endl;

  Trace("sygus-abduct-debug") << "Setup symbols..." << std::endl;
  std::vector<Node> syms;
  std::vector<Node> vars;
  std::vector<Node> varlist;
  std::vector<TypeNode> varlistTypes;
  for (const Node& s : symset)
  {
    TypeNode tn = s.getType();
    if (tn.isFirstClass())
    {
      std::stringstream ss;
      ss << s;
      Node var = nm->mkBoundVar(tn);
      syms.push_back(s);
      vars.push_back(var);
      Node vlv = nm->mkBoundVar(ss.str(), tn);
      varlist.push_back(vlv);
      varlistTypes.push_back(tn);
    }
  }
  Trace("sygus-abduct-debug") << "...finish" << std::endl;

  Trace("sygus-abduct-debug") << "Make abduction predicate..." << std::endl;
  // make the abduction predicate to synthesize
  TypeNode abdType = varlistTypes.empty() ? nm->booleanType()
                                          : nm->mkPredicateType(varlistTypes);
  Node abd = nm->mkBoundVar("A", abdType);
  Trace("sygus-abduct-debug") << "...finish" << std::endl;

  Trace("sygus-abduct-debug") << "Make abduction predicate app..." << std::endl;
  std::vector<Node> achildren;
  achildren.push_back(abd);
  achildren.insert(achildren.end(), vars.begin(), vars.end());
  Node abdApp = vars.empty() ? abd : nm->mkNode(APPLY_UF, achildren);
  Trace("sygus-abduct-debug") << "...finish" << std::endl;

  Trace("sygus-abduct-debug") << "Set attributes..." << std::endl;
  // set the sygus bound variable list
  Node abvl = nm->mkNode(BOUND_VAR_LIST, varlist);
  abd.setAttribute(theory::SygusSynthFunVarListAttribute(), abvl);
  Trace("sygus-abduct-debug") << "...finish" << std::endl;

  Trace("sygus-abduct-debug") << "Make conjecture body..." << std::endl;
  Node input = asserts.size() == 1 ? asserts[0] : nm->mkNode(AND, asserts);
  input = input.substitute(syms.begin(), syms.end(), vars.begin(), vars.end());
  // A(x) => ~input( x )
  input = nm->mkNode(OR, abdApp.negate(), input.negate());
  Trace("sygus-abduct-debug") << "...finish" << std::endl;

  Trace("sygus-abduct-debug") << "Make conjecture..." << std::endl;
  Node res = input.negate();
  if (!vars.empty())
  {
    Node bvl = nm->mkNode(BOUND_VAR_LIST, vars);
    // exists x. ~( A( x ) => ~input( x ) )
    res = nm->mkNode(EXISTS, bvl, res);
  }
  // sygus attribute
  Node sygusVar = nm->mkSkolem("sygus", nm->booleanType());
  theory::SygusAttribute ca;
  sygusVar.setAttribute(ca, true);
  Node instAttr = nm->mkNode(INST_ATTRIBUTE, sygusVar);
  std::vector<Node> iplc;
  iplc.push_back(instAttr);
  if (!axioms.empty())
  {
    Node aconj = axioms.size() == 1 ? axioms[0] : nm->mkNode(AND, axioms);
    aconj =
        aconj.substitute(syms.begin(), syms.end(), vars.begin(), vars.end());
    Trace("sygus-abduct") << "---> Assumptions: " << aconj << std::endl;
    Node sc = nm->mkNode(AND, aconj, abdApp);
    Node vbvl = nm->mkNode(BOUND_VAR_LIST, vars);
    sc = nm->mkNode(EXISTS, vbvl, sc);
    Node sygusScVar = nm->mkSkolem("sygus_sc", nm->booleanType());
    sygusScVar.setAttribute(theory::SygusSideConditionAttribute(), sc);
    instAttr = nm->mkNode(INST_ATTRIBUTE, sygusScVar);
    // build in the side condition
    //   exists x. A( x ) ^ input_axioms( x )
    // as an additional annotation on the sygus conjecture. In other words,
    // the abducts A we procedure must be consistent with our axioms.
    iplc.push_back(instAttr);
  }
  Node instAttrList = nm->mkNode(INST_PATTERN_LIST, iplc);

  Node fbvl = nm->mkNode(BOUND_VAR_LIST, abd);

  // forall A. exists x. ~( A( x ) => ~input( x ) )
  res = nm->mkNode(FORALL, fbvl, res, instAttrList);
  Trace("sygus-abduct-debug") << "...finish" << std::endl;

  res = theory::Rewriter::rewrite(res);

  Trace("sygus-abduct") << "Generate: " << res << std::endl;

  Node trueNode = nm->mkConst(true);

  assertionsToPreprocess->replace(0, res);
  for (size_t i = 1, size = assertionsToPreprocess->size(); i < size; ++i)
  {
    assertionsToPreprocess->replace(i, trueNode);
  }

  return PreprocessingPassResult::NO_CONFLICT;
}
Exemple #12
0
void PrintASTVisitor::visit(TypeNode& node)
{
    std::cout << indent() << "TypeNode: " << SymbolTable::equelleString(node.type()) << '\n';
}
Exemple #13
0
bool TypeTree::checkTypeNameNode(TypeNode*& initialTypeTreeNode, TypeNode*& finalTypeTreeNode,
	ScopeNameListNode* scopeNameListNode, TypeNode* enclosingTypeTreeNode, TemplateArguments* templateArguments)
{
	assert(0 == templateArguments || templateArguments->m_classTypeNode->isTemplateClass());
	initialTypeTreeNode = 0;
	finalTypeTreeNode = 0;
	std::vector<ScopeNameNode*> scopeNameNodes;
	scopeNameListNode->collectIdentifyNodes(scopeNameNodes);
	assert(!scopeNameNodes.empty());

	if (0 != templateArguments && !scopeNameListNode->isGlobal())
	{
		ScopeNameNode* scopeNameNode = scopeNameNodes.front();
		if (!scopeNameNode->isTemplateForm())
		{
			if (scopeNameNode->m_name->m_str == templateArguments->m_className)
			{
				initialTypeTreeNode = templateArguments->m_classTypeNode;
				if (1 == scopeNameNodes.size())
				{
					//finalTypeTreeNode->isTemplateClass()
					finalTypeTreeNode = initialTypeTreeNode; 
					return true;
				}
				else
				{
					//0 == finalTypeTreeNode || finalTypeTreeNode->isUnderTemplateClass()
					scopeNameNodes.erase(scopeNameNodes.begin());
					TypeNode* tmpTypeNode = 0;
					return findNodeByScopeNames(tmpTypeNode, finalTypeTreeNode, scopeNameNodes, initialTypeTreeNode, 0);
				}
			}
			initialTypeTreeNode = templateArguments->findTypeNode(scopeNameNode->m_name->m_str);
			if(initialTypeTreeNode)
			{
				if (1 == scopeNameNodes.size())
				{
					//finalTypeTreeNode->isTemplateParameter()
					finalTypeTreeNode = initialTypeTreeNode;
				}
				else
				{
					finalTypeTreeNode = 0;
				}
				return true;
			}
		}
	}
	if (scopeNameListNode->isGlobal())
	{
		return findNodeByScopeNames(initialTypeTreeNode, finalTypeTreeNode, scopeNameNodes, getRootNamespaceTypeNode(), templateArguments);
	}

	TypeNode* enclosing = enclosingTypeTreeNode;
	while (enclosing)
	{
		if(findNodeByScopeNames(initialTypeTreeNode, finalTypeTreeNode, scopeNameNodes, enclosing, templateArguments))
		{
			return true;
		}		
		enclosing = enclosing->getEnclosing();
	}

	initialTypeTreeNode = 0;
	finalTypeTreeNode = 0;
	bool result = false;
	auto it = m_allNamespaces.begin();
	auto end = m_allNamespaces.end();
	for (; it != end; ++it)
	{
		TypeNode* tempInitialTypeTreeNode = 0;
		TypeNode* tempFinalTypeTreeNode = 0;
		if(findNodeByScopeNames(tempInitialTypeTreeNode, tempFinalTypeTreeNode, scopeNameNodes, *it, templateArguments))
		{
			if (result)
			{
				char buf[512];
				std::string str;
				scopeNameListNode->getString(str);
				sprintf_s(buf, "\'%s\' : ambiguous type name could be %s(%d, %d) or %s(%d, %d)",
					str.c_str(),
					finalTypeTreeNode->m_sourceFile->m_fileName.c_str(), 
					finalTypeTreeNode->m_identifyNode->m_lineNo, 
					finalTypeTreeNode->m_identifyNode->m_columnNo,
					tempFinalTypeTreeNode->m_sourceFile->m_fileName.c_str(), 
					tempFinalTypeTreeNode->m_identifyNode->m_lineNo,
					tempFinalTypeTreeNode->m_identifyNode->m_columnNo);
				ErrorList_AddItem_CurrentFile(scopeNameNodes.back()->m_name->m_lineNo,
					scopeNameNodes.back()->m_name->m_columnNo, semantic_error_ambiguous_type_name, buf);
				return false;
			}
			else
			{
				initialTypeTreeNode = tempInitialTypeTreeNode;
				finalTypeTreeNode = tempFinalTypeTreeNode;
				result = true;
			}
		}
	}
	if (!result)
	{
		RaiseError_InvalidTypeName(scopeNameListNode);
	}
	return result;
}
Exemple #14
0
void SortInference::simplify( std::vector< Node >& assertions, bool doSortInference, bool doMonotonicyInference ){
  if( doSortInference ){
    Trace("sort-inference-proc") << "Calculating sort inference..." << std::endl;
    NodeManager* nm = NodeManager::currentNM();
    //process all assertions
    std::map< Node, int > visited;
    for( unsigned i=0; i<assertions.size(); i++ ){
      Trace("sort-inference-debug") << "Process " << assertions[i] << std::endl;
      std::map< Node, Node > var_bound;
      process( assertions[i], var_bound, visited );
    }
    Trace("sort-inference-proc") << "...done" << std::endl;
    for( std::map< Node, int >::iterator it = d_op_return_types.begin(); it != d_op_return_types.end(); ++it ){
      Trace("sort-inference") << it->first << " : ";
      TypeNode retTn = it->first.getType();
      if( !d_op_arg_types[ it->first ].empty() ){
        Trace("sort-inference") << "( ";
        for( size_t i=0; i<d_op_arg_types[ it->first ].size(); i++ ){
          recordSubsort( retTn[i], d_op_arg_types[ it->first ][i] );
          printSort( "sort-inference", d_op_arg_types[ it->first ][i] );
          Trace("sort-inference") << " ";
        }
        Trace("sort-inference") << ") -> ";
        retTn = retTn[(int)retTn.getNumChildren()-1];
      }
      recordSubsort( retTn, it->second );
      printSort( "sort-inference", it->second );
      Trace("sort-inference") << std::endl;
    }
    for( std::map< Node, std::map< Node, int > >::iterator it = d_var_types.begin(); it != d_var_types.end(); ++it ){
      Trace("sort-inference") << "Quantified formula : " << it->first << " : " << std::endl;
      for( unsigned i=0; i<it->first[0].getNumChildren(); i++ ){
        recordSubsort( it->first[0][i].getType(), it->second[it->first[0][i]] );
        printSort( "sort-inference", it->second[it->first[0][i]] );
        Trace("sort-inference") << std::endl;
      }
      Trace("sort-inference") << std::endl;
    }

    bool rewritten = false;
    // determine monotonicity of sorts
    Trace("sort-inference-proc") << "Calculating monotonicty for subsorts..."
                                 << std::endl;
    std::map<Node, std::map<int, bool> > visitedm;
    for (const Node& a : assertions)
    {
      Trace("sort-inference-debug") << "Process monotonicity for " << a
                                    << std::endl;
      std::map<Node, Node> var_bound;
      processMonotonic(a, true, true, var_bound, visitedm);
    }
    Trace("sort-inference-proc") << "...done" << std::endl;

    Trace("sort-inference") << "We have " << d_sub_sorts.size()
                            << " sub-sorts : " << std::endl;
    for (unsigned i = 0, size = d_sub_sorts.size(); i < size; i++)
    {
      printSort("sort-inference", d_sub_sorts[i]);
      if (d_type_types.find(d_sub_sorts[i]) != d_type_types.end())
      {
        Trace("sort-inference") << " is interpreted." << std::endl;
      }
      else if (d_non_monotonic_sorts.find(d_sub_sorts[i])
               == d_non_monotonic_sorts.end())
      {
        Trace("sort-inference") << " is monotonic." << std::endl;
      }
      else
      {
        Trace("sort-inference") << " is not monotonic." << std::endl;
      }
    }

    // simplify all assertions by introducing new symbols wherever necessary
    Trace("sort-inference-proc") << "Perform simplification..." << std::endl;
    std::map<Node, std::map<TypeNode, Node> > visited2;
    for (unsigned i = 0, size = assertions.size(); i < size; i++)
    {
      Node prev = assertions[i];
      std::map<Node, Node> var_bound;
      Trace("sort-inference-debug") << "Simplify " << prev << std::endl;
      TypeNode tnn;
      Node curr = simplifyNode(assertions[i], var_bound, tnn, visited2);
      Trace("sort-inference-debug") << "Done." << std::endl;
      if (curr != assertions[i])
      {
        Trace("sort-inference-debug") << "Rewrite " << curr << std::endl;
        curr = theory::Rewriter::rewrite(curr);
        rewritten = true;
        Trace("sort-inference-rewrite") << assertions << std::endl;
        Trace("sort-inference-rewrite") << " --> " << curr << std::endl;
        PROOF(ProofManager::currentPM()->addDependence(curr, assertions[i]););
        assertions[i] = curr;
      }
    }
void SharedTermsVisitor::visit(TNode current, TNode parent) {

  Debug("register") << "SharedTermsVisitor::visit(" << current << "," << parent << ")" << std::endl;
  if (Debug.isOn("register::internal")) {
    Debug("register::internal") << toString() << std::endl;
  }

  // Get the theories of the terms
  TheoryId currentTheoryId = Theory::theoryOf(current);
  TheoryId parentTheoryId  = Theory::theoryOf(parent);

#if 0
  bool useType = current != parent && currentTheoryId != parentTheoryId;
#else
  // Should we use the theory of the type
  bool useType = false;
  TheoryId typeTheoryId = THEORY_LAST;

  if (current != parent) {
    if (currentTheoryId != parentTheoryId) {
      // If enclosed by different theories it's shared -- in read(a, f(a)) f(a) should be shared with integers
      TypeNode type = current.getType();
      useType = true;
      typeTheoryId = Theory::theoryOf(type);
    } else {
      TypeNode type = current.getType();
      typeTheoryId = Theory::theoryOf(type);
      if (typeTheoryId != currentTheoryId) {
        if (options::finiteModelFind() && type.isSort()) {
          // We're looking for finite models
          useType = true;
        } else {
          Cardinality card = type.getCardinality();
          if (card.isFinite()) {
            useType = true;
          }
        }
      }
    }
  }
#endif

  Theory::Set visitedTheories = d_visited[current];
  Debug("register::internal") << "SharedTermsVisitor::visit(" << current << "," << parent << "): previously registered with " << Theory::setToString(visitedTheories) << std::endl;
  if (!Theory::setContains(currentTheoryId, visitedTheories)) {
    visitedTheories = Theory::setInsert(currentTheoryId, visitedTheories);
    Debug("register::internal") << "SharedTermsVisitor::visit(" << current << "," << parent << "): adding " << currentTheoryId << std::endl;
  }
  if (!Theory::setContains(parentTheoryId, visitedTheories)) {
    visitedTheories = Theory::setInsert(parentTheoryId, visitedTheories);
    Debug("register::internal") << "SharedTermsVisitor::visit(" << current << "," << parent << "): adding " << parentTheoryId << std::endl;
  }
  if (useType) {
    //////TheoryId typeTheoryId = Theory::theoryOf(current.getType());
    if (!Theory::setContains(typeTheoryId, visitedTheories)) {
      visitedTheories = Theory::setInsert(typeTheoryId, visitedTheories);
      Debug("register::internal") << "SharedTermsVisitor::visit(" << current << "," << parent << "): adding " << typeTheoryId << std::endl;
    }
  }
  Debug("register::internal") << "SharedTermsVisitor::visit(" << current << "," << parent << "): now registered with " << Theory::setToString(visitedTheories) << std::endl;

  // Record the new theories that we visited
  d_visited[current] = visitedTheories;

  // If there is more than two theories and a new one has been added notify the shared terms database
  if (Theory::setDifference(visitedTheories, Theory::setInsert(currentTheoryId))) {
    d_sharedTerms.addSharedTerm(d_atom, current, visitedTheories);
  }

  Assert(d_visited.find(current) != d_visited.end());
  Assert(alreadyVisited(current, parent));
}
bool SharedTermsVisitor::alreadyVisited(TNode current, TNode parent) const {

  Debug("register::internal") << "SharedTermsVisitor::alreadyVisited(" << current << "," << parent << ")" << std::endl;

  if( ( parent.getKind() == kind::FORALL ||
        parent.getKind() == kind::EXISTS ||
        parent.getKind() == kind::REWRITE_RULE /*||
        parent.getKind() == kind::CARDINALITY_CONSTRAINT*/  ) &&
      current != parent ) {
    Debug("register::internal") << "quantifier:true" << std::endl;
    return true;
  }
  TNodeVisitedMap::const_iterator find = d_visited.find(current);

  // If node is not visited at all, just return false
  if (find == d_visited.end()) {
    Debug("register::internal") << "1:false" << std::endl;
    return false;
  }

  Theory::Set theories = (*find).second;

  TheoryId currentTheoryId = Theory::theoryOf(current);
  TheoryId parentTheoryId  = Theory::theoryOf(parent);

  // Should we use the theory of the type
#if 0
  bool useType = current != parent && currentTheoryId != parentTheoryId;
#else
  bool useType = false;
  TheoryId typeTheoryId = THEORY_LAST;

  if (current != parent) {
    if (currentTheoryId != parentTheoryId) {
      // If enclosed by different theories it's shared -- in read(a, f(a)) f(a) should be shared with integers
      TypeNode type = current.getType();
      useType = true;
      typeTheoryId = Theory::theoryOf(type);
    } else {
      TypeNode type = current.getType();
      typeTheoryId = Theory::theoryOf(type);
      if (typeTheoryId != currentTheoryId) {
        if (options::finiteModelFind() && type.isSort()) {
          // We're looking for finite models
          useType = true;
        } else {
          Cardinality card = type.getCardinality();
          if (card.isFinite()) {
            useType = true;
          }
        }
      }
    }
  }
#endif

  if (Theory::setContains(currentTheoryId, theories)) {
      if (Theory::setContains(parentTheoryId, theories)) {
        if (useType) {
          ////TheoryId typeTheoryId = Theory::theoryOf(current.getType());
          return Theory::setContains(typeTheoryId, theories);
        } else {
          return true;
        }
      } else {
        return false;
      }
  } else {
    return false;
  }
}
Exemple #17
0
void TheoryEngineModelBuilder::buildModel(Model* m, bool fullModel)
{
  TheoryModel* tm = (TheoryModel*)m;

  // buildModel with fullModel = true should only be called once in any context
  Assert(!tm->d_modelBuilt);
  tm->d_modelBuilt = fullModel;

  // Reset model
  tm->reset();

  // Collect model info from the theories
  Trace("model-builder") << "TheoryEngineModelBuilder: Collect model info..." << std::endl;
  d_te->collectModelInfo(tm, fullModel);

  // Loop through all terms and make sure that assignable sub-terms are in the equality engine
  eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &tm->d_equalityEngine );
  {
    NodeSet cache;
    for ( ; !eqcs_i.isFinished(); ++eqcs_i) {
      eq::EqClassIterator eqc_i = eq::EqClassIterator((*eqcs_i), &tm->d_equalityEngine);
      for ( ; !eqc_i.isFinished(); ++eqc_i) {
        checkTerms(*eqc_i, tm, cache);
      }
    }
  }

  Trace("model-builder") << "Collect representatives..." << std::endl;

  // Process all terms in the equality engine, store representatives for each EC
  std::map< Node, Node > assertedReps, constantReps;
  TypeSet typeConstSet, typeRepSet, typeNoRepSet;
  std::set< TypeNode > allTypes;
  eqcs_i = eq::EqClassesIterator(&tm->d_equalityEngine);
  for ( ; !eqcs_i.isFinished(); ++eqcs_i) {

    // eqc is the equivalence class representative
    Node eqc = (*eqcs_i);
    Trace("model-builder") << "Processing EC: " << eqc << endl;
    Assert(tm->d_equalityEngine.getRepresentative(eqc) == eqc);
    TypeNode eqct = eqc.getType();
    Assert(assertedReps.find(eqc) == assertedReps.end());
    Assert(constantReps.find(eqc) == constantReps.end());

    // Loop through terms in this EC
    Node rep, const_rep;
    eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, &tm->d_equalityEngine);
    for ( ; !eqc_i.isFinished(); ++eqc_i) {
      Node n = *eqc_i;
      Trace("model-builder") << "  Processing Term: " << n << endl;
      // Record as rep if this node was specified as a representative
      if (tm->d_reps.find(n) != tm->d_reps.end()){
        Assert(rep.isNull());
        rep = tm->d_reps[n];
        Assert(!rep.isNull() );
        Trace("model-builder") << "  Rep( " << eqc << " ) = " << rep << std::endl;
      }
      // Record as const_rep if this node is constant
      if (n.isConst()) {
        Assert(const_rep.isNull());
        const_rep = n;
        Trace("model-builder") << "  ConstRep( " << eqc << " ) = " << const_rep << std::endl;
      }
      //model-specific processing of the term
      tm->addTerm(n);
    }

    // Assign representative for this EC
    if (!const_rep.isNull()) {
      // Theories should not specify a rep if there is already a constant in the EC
      Assert(rep.isNull() || rep == const_rep);
      constantReps[eqc] = const_rep;
      typeConstSet.add(eqct.getBaseType(), const_rep);
    }
    else if (!rep.isNull()) {
      assertedReps[eqc] = rep;
      typeRepSet.add(eqct.getBaseType(), eqc);
      allTypes.insert(eqct);
    }
    else {
      typeNoRepSet.add(eqct, eqc);
      allTypes.insert(eqct);
    }
  }

  // Need to ensure that each EC has a constant representative.

  Trace("model-builder") << "Processing EC's..." << std::endl;

  TypeSet::iterator it;
  set<TypeNode>::iterator type_it;
  set<Node>::iterator i, i2;
  bool changed, unassignedAssignable, assignOne = false;
  set<TypeNode> evaluableSet;

  // Double-fixed-point loop
  // Outer loop handles a special corner case (see code at end of loop for details)
  for (;;) {

    // Inner fixed-point loop: we are trying to learn constant values for every EC.  Each time through this loop, we process all of the
    // types by type and may learn some new EC values.  EC's in one type may depend on EC's in another type, so we need a fixed-point loop
    // to ensure that we learn as many EC values as possible
    do {
      changed = false;
      unassignedAssignable = false;
      evaluableSet.clear();

      // Iterate over all types we've seen
      for (type_it = allTypes.begin(); type_it != allTypes.end(); ++type_it) {
        TypeNode t = *type_it;
        TypeNode tb = t.getBaseType();
        set<Node>* noRepSet = typeNoRepSet.getSet(t);

        // 1. Try to evaluate the EC's in this type
        if (noRepSet != NULL && !noRepSet->empty()) {
          Trace("model-builder") << "  Eval phase, working on type: " << t << endl;
          bool assignable, evaluable, evaluated;
          d_normalizedCache.clear();
          for (i = noRepSet->begin(); i != noRepSet->end(); ) {
            i2 = i;
            ++i;
            assignable = false;
            evaluable = false;
            evaluated = false;
            eq::EqClassIterator eqc_i = eq::EqClassIterator(*i2, &tm->d_equalityEngine);
            for ( ; !eqc_i.isFinished(); ++eqc_i) {
              Node n = *eqc_i;
              if (isAssignable(n)) {
                assignable = true;
              }
              else {
                evaluable = true;
                Node normalized = normalize(tm, n, constantReps, true);
                if (normalized.isConst()) {
                  typeConstSet.add(tb, normalized);
                  constantReps[*i2] = normalized;
                  Trace("model-builder") << "    Eval: Setting constant rep of " << (*i2) << " to " << normalized << endl;
                  changed = true;
                  evaluated = true;
                  noRepSet->erase(i2);
                  break;
                }
              }
            }
            if (!evaluated) {
              if (evaluable) {
                evaluableSet.insert(tb);
              }
              if (assignable) {
                unassignedAssignable = true;
              }
            }
          }
        }

        // 2. Normalize any non-const representative terms for this type
        set<Node>* repSet = typeRepSet.getSet(t);
        if (repSet != NULL && !repSet->empty()) {
          Trace("model-builder") << "  Normalization phase, working on type: " << t << endl;
          d_normalizedCache.clear();
          for (i = repSet->begin(); i != repSet->end(); ) {
            Assert(assertedReps.find(*i) != assertedReps.end());
            Node rep = assertedReps[*i];
            Node normalized = normalize(tm, rep, constantReps, false);
            Trace("model-builder") << "    Normalizing rep (" << rep << "), normalized to (" << normalized << ")" << endl;
            if (normalized.isConst()) {
              changed = true;
              typeConstSet.add(t.getBaseType(), normalized);
              constantReps[*i] = normalized;
              assertedReps.erase(*i);
              i2 = i;
              ++i;
              repSet->erase(i2);
            }
            else {
              if (normalized != rep) {
                assertedReps[*i] = normalized;
                changed = true;
              }
              ++i;
            }
          }
        }
      }
    } while (changed);

    if (!fullModel || !unassignedAssignable) {
      break;
    }

    // 3. Assign unassigned assignable EC's using type enumeration - assign a value *different* from all other EC's if the type is infinite
    // Assign first value from type enumerator otherwise - for finite types, we rely on polite framework to ensure that EC's that have to be
    // different are different.

    // Only make assignments on a type if:
    // 1. fullModel is true
    // 2. there are no terms that share the same base type with un-normalized representatives
    // 3. there are no terms that share teh same base type that are unevaluated evaluable terms
    // Alternatively, if 2 or 3 don't hold but we are in a special deadlock-breaking mode where assignOne is true, go ahead and make one assignment
    changed = false;
    for (it = typeNoRepSet.begin(); it != typeNoRepSet.end(); ++it) {
      set<Node>& noRepSet = TypeSet::getSet(it);
      if (noRepSet.empty()) {
        continue;
      }
      TypeNode t = TypeSet::getType(it);
      TypeNode tb = t.getBaseType();
      if (!assignOne) {
        set<Node>* repSet = typeRepSet.getSet(tb);
        if (repSet != NULL && !repSet->empty()) {
          continue;
        }
        if (evaluableSet.find(tb) != evaluableSet.end()) {
          continue;
        }
      }
      Trace("model-builder") << "  Assign phase, working on type: " << t << endl;
      bool assignable, evaluable CVC4_UNUSED;
      for (i = noRepSet.begin(); i != noRepSet.end(); ) {
        i2 = i;
        ++i;
        eq::EqClassIterator eqc_i = eq::EqClassIterator(*i2, &tm->d_equalityEngine);
        assignable = false;
        evaluable = false;
        for ( ; !eqc_i.isFinished(); ++eqc_i) {
          Node n = *eqc_i;
          if (isAssignable(n)) {
            assignable = true;
          }
          else {
            evaluable = true;
          }
        }
        if (assignable) {
          Assert(!evaluable || assignOne);
          Assert(!t.isBoolean() || (*i2).getKind() == kind::APPLY_UF);
          Node n;
          if (t.getCardinality().isInfinite()) {
            n = typeConstSet.nextTypeEnum(t, true);
          }
          else {
            TypeEnumerator te(t);
            n = *te;
          }
          Assert(!n.isNull());
          constantReps[*i2] = n;
          Trace("model-builder") << "    Assign: Setting constant rep of " << (*i2) << " to " << n << endl;
          changed = true;
          noRepSet.erase(i2);
          if (assignOne) {
            assignOne = false;
            break;
          }
        }
      }
    }

    // Corner case - I'm not sure this can even happen - but it's theoretically possible to have a cyclical dependency
    // in EC assignment/evaluation, e.g. EC1 = {a, b + 1}; EC2 = {b, a - 1}.  In this case, neither one will get assigned because we are waiting
    // to be able to evaluate.  But we will never be able to evaluate because the variables that need to be assigned are in
    // these same EC's.  In this case, repeat the whole fixed-point computation with the difference that the first EC
    // that has both assignable and evaluable expressions will get assigned.
    if (!changed) {
      Assert(!assignOne); // check for infinite loop!
      assignOne = true;
    }
  }

#ifdef CVC4_ASSERTIONS
  if (fullModel) {
    // Assert that all representatives have been converted to constants
    for (it = typeRepSet.begin(); it != typeRepSet.end(); ++it) {
      set<Node>& repSet = TypeSet::getSet(it);
      if (!repSet.empty()) {
        Trace("model-builder") << "***Non-empty repSet, size = " << repSet.size() << ", first = " << *(repSet.begin()) << endl;
        Assert(false);
      }
    }
  }
#endif /* CVC4_ASSERTIONS */

  Trace("model-builder") << "Copy representatives to model..." << std::endl;
  tm->d_reps.clear();
  std::map< Node, Node >::iterator itMap;
  for (itMap = constantReps.begin(); itMap != constantReps.end(); ++itMap) {
    tm->d_reps[itMap->first] = itMap->second;
    tm->d_rep_set.add(itMap->second);
  }

  if (!fullModel) {
    // Make sure every EC has a rep
    for (itMap = assertedReps.begin(); itMap != assertedReps.end(); ++itMap ) {
      tm->d_reps[itMap->first] = itMap->second;
      tm->d_rep_set.add(itMap->second);
    }
    for (it = typeNoRepSet.begin(); it != typeNoRepSet.end(); ++it) {
      set<Node>& noRepSet = TypeSet::getSet(it);
      set<Node>::iterator i;
      for (i = noRepSet.begin(); i != noRepSet.end(); ++i) {
        tm->d_reps[*i] = *i;
        tm->d_rep_set.add(*i);
      }
    }
  }

  //modelBuilder-specific initialization
  processBuildModel( tm, fullModel );

#ifdef CVC4_ASSERTIONS
  if (fullModel) {
    // Check that every term evaluates to its representative in the model
    for (eqcs_i = eq::EqClassesIterator(&tm->d_equalityEngine); !eqcs_i.isFinished(); ++eqcs_i) {
      // eqc is the equivalence class representative
      Node eqc = (*eqcs_i);
      Node rep;
      itMap = constantReps.find(eqc);
      if (itMap == constantReps.end() && eqc.getType().isBoolean()) {
        rep = tm->getValue(eqc);
        Assert(rep.isConst());
      }
      else {
        Assert(itMap != constantReps.end());
        rep = itMap->second;
      }
      eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, &tm->d_equalityEngine);
      for ( ; !eqc_i.isFinished(); ++eqc_i) {
        Node n = *eqc_i;
        static int repCheckInstance = 0;
        ++repCheckInstance;

        Debug("check-model::rep-checking")
          << "( " << repCheckInstance <<") "
          << "n: " << n << endl
          << "getValue(n): " << tm->getValue(n) << endl
          << "rep: " << rep << endl;
        Assert(tm->getValue(*eqc_i) == rep);
      }
    }
  }
#endif /* CVC4_ASSERTIONS */
}
void PrintEquelleASTVisitor::visit(TypeNode& node)
{
    std::cout << SymbolTable::equelleString(node.type());
}
Exemple #19
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();
  }
}
Exemple #20
0
Node RemoveITE::run(TNode node, std::vector<Node>& output,
                    IteSkolemMap& iteSkolemMap) {
  // Current node
  Debug("ite") << "removeITEs(" << node << ")" << endl;

  // The result may be cached already
  NodeManager *nodeManager = NodeManager::currentNM();
  ITECache::iterator i = d_iteCache.find(node);
  if(i != d_iteCache.end()) {
    Node cachedRewrite = (*i).second;
    Debug("ite") << "removeITEs: in-cache: " << cachedRewrite << endl;
    return cachedRewrite.isNull() ? Node(node) : cachedRewrite;
  }

  // If an ITE replace it
  if(node.getKind() == kind::ITE) {
    TypeNode nodeType = node.getType();
    if(!nodeType.isBoolean()) {
      // Make the skolem to represent the ITE
      Node skolem = nodeManager->mkSkolem("termITE_$$", nodeType, "a variable introduced due to term-level ITE removal");

      // The new assertion
      Node newAssertion =
        nodeManager->mkNode(kind::ITE, node[0], skolem.eqNode(node[1]),
                            skolem.eqNode(node[2]));
      Debug("ite") << "removeITEs(" << node << ") => " << newAssertion << endl;

      // Attach the skolem
      d_iteCache[node] = skolem;

      // Remove ITEs from the new assertion, rewrite it and push it to the output
      newAssertion = run(newAssertion, output, iteSkolemMap);
      iteSkolemMap[skolem] = output.size();
      output.push_back(newAssertion);

      // The representation is now the skolem
      return skolem;
    }
  }

  // If not an ITE, go deep
  if( node.getKind() != kind::FORALL &&
      node.getKind() != kind::EXISTS &&
      node.getKind() != kind::REWRITE_RULE ) {
    vector<Node> newChildren;
    bool somethingChanged = false;
    if(node.getMetaKind() == kind::metakind::PARAMETERIZED) {
      newChildren.push_back(node.getOperator());
    }
    // Remove the ITEs from the children
    for(TNode::const_iterator it = node.begin(), end = node.end(); it != end; ++it) {
      Node newChild = run(*it, output, iteSkolemMap);
      somethingChanged |= (newChild != *it);
      newChildren.push_back(newChild);
    }

    // If changes, we rewrite
    if(somethingChanged) {
      Node cachedRewrite = nodeManager->mkNode(node.getKind(), newChildren);
      d_iteCache[node] = cachedRewrite;
      return cachedRewrite;
    } else {
      d_iteCache[node] = Node::null();
      return node;
    }
  } else {
    d_iteCache[node] = Node::null();
    return node;
  }
}
Exemple #21
0
 virtual void deleteAll() {
     type->deleteAll();
 }
Exemple #22
0
TypeNode* TypeTree::findNodeByScopeName(ScopeNameNode* scopeNameNode, TypeNode* enclosingTypeTreeNode, TemplateArguments* templateArguments)
{
	if (templateArguments && templateArguments->m_classTypeNode->isTemplateClass())//must be TypeNameNode::calcTypeNodes
	{
		if (scopeNameNode->isTemplateForm())
		{
			TypeNode* result = enclosingTypeTreeNode->getChildNode(scopeNameNode->m_name->m_str);
			if (0 == result || !result->isTemplateClass())
			{
				return 0;
			}
			std::vector<TypeNameNode*> paramTypeNameNodes;
			scopeNameNode->m_parameterList->collectTypeNameNodes(paramTypeNameNodes);
			assert(!paramTypeNameNodes.empty());
			if (paramTypeNameNodes.size() != static_cast<ClassTypeNode*>(result)->m_parameterNodes.size())
			{
				return 0;
			}
			bool hasUndeteminedType = false;
			std::string name = scopeNameNode->m_name->m_str;
			name += "<";
			auto begin = paramTypeNameNodes.begin();
			auto end = paramTypeNameNodes.end();
			for (auto it = begin; it != end; ++it)
			{
				if (it != begin)
				{
					name += ", ";
				}
				TypeNameNode* paramTypeNameNode = *it;
				assert(paramTypeNameNode->m_startTypeNode);
				if (0 == paramTypeNameNode->m_typeNode ||
					paramTypeNameNode->m_typeNode->isTemplateParameter() ||
					paramTypeNameNode->m_typeNode->isTemplateClass() ||
					paramTypeNameNode->m_typeNode->isUnderTemplateClass())
				{
					hasUndeteminedType = true;
					break;
				}
				else
				{
					assert(paramTypeNameNode->m_typeNode->isPredefinedType() ||
						paramTypeNameNode->m_typeNode->isEnum() ||
						paramTypeNameNode->m_typeNode->isClass() ||
						paramTypeNameNode->m_typeNode->isTemplateClassInstance() ||
						paramTypeNameNode->m_typeNode->isTypedef() ||
						paramTypeNameNode->m_typeNode->isTypeDeclaration());
					std::string paramName;
					paramTypeNameNode->m_typeNode->getActualTypeFullName(paramName);
					name += paramName;
				}
			}
			name += ">";
			if (!hasUndeteminedType)
			{
				result = enclosingTypeTreeNode->getChildNode(name);
			}
			return result;
		}
		else
		{
			TypeNode* result = enclosingTypeTreeNode->getChildNode(scopeNameNode->m_name->m_str);
			if (0 == result || result->isTemplateClass())
			{
				return 0;
			}
			return result;
		}
	}
	else
	{
		if (scopeNameNode->isTemplateForm())
		{
			TypeNode* result = enclosingTypeTreeNode->getChildNode(scopeNameNode->m_name->m_str);
			if (0 == result || !result->isTemplateClass())
			{
				return 0;
			}
			std::vector<TypeNameNode*> paramTypeNameNodes;
			scopeNameNode->m_parameterList->collectTypeNameNodes(paramTypeNameNodes);
			assert(!paramTypeNameNodes.empty());
			if (paramTypeNameNodes.size() != static_cast<ClassTypeNode*>(result)->m_parameterNodes.size())
			{
				return 0;
			}
			bool hasUndeteminedType = false;
			std::string name = scopeNameNode->m_name->m_str;
			name += "<";
			auto begin = paramTypeNameNodes.begin();
			auto end = paramTypeNameNodes.end();
			for (auto it = begin; it != end; ++it)
			{
				if (it != begin)
				{
					name += ", ";
				}
				TypeNameNode* paramTypeNameNode = *it;
				TypeNode* paramTypeNode = paramTypeNameNode->getTypeNode(templateArguments);
				if(0 == paramTypeNode)
				{
					return 0;
				}
				else
				{
					std::string paramName;
					paramTypeNode->getActualTypeFullName(paramName);
					name += paramName;
				}
			}
			name += ">";
			if (!hasUndeteminedType)
			{
				result = enclosingTypeTreeNode->getChildNode(name);
			}
			return result;
		}
		else
		{
			TypeNode* result = enclosingTypeTreeNode->getChildNode(scopeNameNode->m_name->m_str);
			if (0 == result || result->isTemplateClass())
			{
				return 0;
			}
			return result;
		}
	}
}
Exemple #23
0
//this isolates the atom into solved form
//     veq_c * pv <> val + vts_coeff_delta * delta + vts_coeff_inf * inf
//  ensures val is Int if pv is Int, and val does not contain vts symbols
int ArithInstantiator::solve_arith( CegInstantiator * ci, Node pv, Node atom, Node& veq_c, Node& val, Node& vts_coeff_inf, Node& vts_coeff_delta ) {
  int ires = 0;
  Trace("cbqi-inst-debug") << "isolate for " << pv << " in " << atom << std::endl;
  std::map< Node, Node > msum;
  if( QuantArith::getMonomialSumLit( atom, msum ) ){
    Trace("cbqi-inst-debug") << "got monomial sum: " << std::endl;
    if( Trace.isOn("cbqi-inst-debug") ){
      QuantArith::debugPrintMonomialSum( msum, "cbqi-inst-debug" );
    }
    TypeNode pvtn = pv.getType();
    //remove vts symbols from polynomial
    Node vts_coeff[2];
    for( unsigned t=0; t<2; t++ ){
      if( !d_vts_sym[t].isNull() ){
        std::map< Node, Node >::iterator itminf = msum.find( d_vts_sym[t] );
        if( itminf!=msum.end() ){
          vts_coeff[t] = itminf->second;
          if( vts_coeff[t].isNull() ){
            vts_coeff[t] = NodeManager::currentNM()->mkConst( Rational( 1 ) );
          }
          //negate if coefficient on variable is positive
          std::map< Node, Node >::iterator itv = msum.find( pv );
          if( itv!=msum.end() ){
            //multiply by the coefficient we will isolate for
            if( itv->second.isNull() ){
              vts_coeff[t] = QuantArith::negate(vts_coeff[t]);
            }else{
              if( !pvtn.isInteger() ){
                vts_coeff[t] = NodeManager::currentNM()->mkNode( MULT, NodeManager::currentNM()->mkConst( Rational(-1) / itv->second.getConst<Rational>() ), vts_coeff[t] );
                vts_coeff[t] = Rewriter::rewrite( vts_coeff[t] );
              }else if( itv->second.getConst<Rational>().sgn()==1 ){
                vts_coeff[t] = QuantArith::negate(vts_coeff[t]);
              }
            }
          }
          Trace("cbqi-inst-debug") << "vts[" << t << "] coefficient is " << vts_coeff[t] << std::endl;
          msum.erase( d_vts_sym[t] );
        }
      }
    }

    ires = QuantArith::isolate( pv, msum, veq_c, val, atom.getKind() );
    if( ires!=0 ){
      Node realPart;
      if( Trace.isOn("cbqi-inst-debug") ){
        Trace("cbqi-inst-debug") << "Isolate : ";
        if( !veq_c.isNull() ){
          Trace("cbqi-inst-debug") << veq_c << " * ";
        }
        Trace("cbqi-inst-debug") << pv << " " << atom.getKind() << " " << val << std::endl;
      }
      if( options::cbqiAll() ){
        // when not pure LIA/LRA, we must check whether the lhs contains pv
        if( TermDb::containsTerm( val, pv ) ){
          Trace("cbqi-inst-debug") << "fail : contains bad term" << std::endl;
          return 0;
        }
      }
      if( pvtn.isInteger() && ( ( !veq_c.isNull() && !veq_c.getType().isInteger() ) || !val.getType().isInteger() ) ){
        //redo, split integer/non-integer parts
        bool useCoeff = false;
        Integer coeff = ci->getQuantifiersEngine()->getTermDatabase()->d_one.getConst<Rational>().getNumerator();
        for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
          if( it->first.isNull() || it->first.getType().isInteger() ){
            if( !it->second.isNull() ){
              coeff = coeff.lcm( it->second.getConst<Rational>().getDenominator() );
              useCoeff = true;
            }
          }
        }
        //multiply everything by this coefficient
        Node rcoeff = NodeManager::currentNM()->mkConst( Rational( coeff ) );
        std::vector< Node > real_part;
        for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
          if( useCoeff ){
            if( it->second.isNull() ){
              msum[it->first] = rcoeff;
            }else{
              msum[it->first] = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MULT, it->second, rcoeff ) );
            }
          }
          if( !it->first.isNull() && !it->first.getType().isInteger() ){
            real_part.push_back( msum[it->first].isNull() ? it->first : NodeManager::currentNM()->mkNode( MULT, msum[it->first], it->first ) );
          }
        }
        //remove delta  TODO: check this
        vts_coeff[1] = Node::null();
        //multiply inf
        if( !vts_coeff[0].isNull() ){
          vts_coeff[0] = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MULT, rcoeff, vts_coeff[0] ) );
        }
        realPart = real_part.empty() ? ci->getQuantifiersEngine()->getTermDatabase()->d_zero : ( real_part.size()==1 ? real_part[0] : NodeManager::currentNM()->mkNode( PLUS, real_part ) );
        Assert( ci->getOutput()->isEligibleForInstantiation( realPart ) );
        //re-isolate
        Trace("cbqi-inst-debug") << "Re-isolate..." << std::endl;
        ires = QuantArith::isolate( pv, msum, veq_c, val, atom.getKind() );
        Trace("cbqi-inst-debug") << "Isolate for mixed Int/Real : " << veq_c << " * " << pv << " " << atom.getKind() << " " << val << std::endl;
        Trace("cbqi-inst-debug") << "                 real part : " << realPart << std::endl;
        if( ires!=0 ){
          int ires_use = ( msum[pv].isNull() || msum[pv].getConst<Rational>().sgn()==1 ) ? 1 : -1;
          val = Rewriter::rewrite( NodeManager::currentNM()->mkNode( ires_use==-1 ? PLUS : MINUS,
                                    NodeManager::currentNM()->mkNode( ires_use==-1 ? MINUS : PLUS, val, realPart ),
                                    NodeManager::currentNM()->mkNode( TO_INTEGER, realPart ) ) );  //TODO: round up for upper bounds?
          Trace("cbqi-inst-debug") << "result : " << val << std::endl;
          Assert( val.getType().isInteger() );
        }
      }
    }
    vts_coeff_inf = vts_coeff[0];
    vts_coeff_delta = vts_coeff[1];
    Trace("cbqi-inst-debug") << "Return " << veq_c << " * " << pv << " " << atom.getKind() << " " << val << ", vts = (" << vts_coeff_inf << ", " << vts_coeff_delta << ")" << std::endl;
  }else{
    Trace("cbqi-inst-debug") << "fail : could not get monomial sum" << std::endl;
  }
  return ires;
}
TypeNode exportTypeInternal(TypeNode n, NodeManager* from, NodeManager* to, ExprManagerMapCollection& vmap) {
  Debug("export") << "type: " << n << " " << n.getId() << std::endl;
  if(theory::kindToTheoryId(n.getKind()) == theory::THEORY_DATATYPES) {
    throw ExportUnsupportedException
      ("export of types belonging to theory of DATATYPES kinds unsupported");
  }
  if(n.getMetaKind() == kind::metakind::PARAMETERIZED &&
     n.getKind() != kind::SORT_TYPE) {
    throw ExportUnsupportedException
      ("export of PARAMETERIZED-kinded types (other than SORT_KIND) not supported");
  }
  if(n.getKind() == kind::TYPE_CONSTANT) {
    return to->mkTypeConst(n.getConst<TypeConstant>());
  } else if(n.getKind() == kind::BITVECTOR_TYPE) {
    return to->mkBitVectorType(n.getConst<BitVectorSize>());
  } else if(n.getKind() == kind::SUBRANGE_TYPE) {
    return to->mkSubrangeType(n.getSubrangeBounds());
  }
  Type from_t = from->toType(n);
  Type& to_t = vmap.d_typeMap[from_t];
  if(! to_t.isNull()) {
    Debug("export") << "+ mapped `" << from_t << "' to `" << to_t << "'" << std::endl;
    return *Type::getTypeNode(to_t);
  }
  NodeBuilder<> children(to, n.getKind());
  if(n.getKind() == kind::SORT_TYPE) {
    Debug("export") << "type: operator: " << n.getOperator() << std::endl;
    // make a new sort tag in target node manager
    Node sortTag = NodeBuilder<0>(to, kind::SORT_TAG);
    children << sortTag;
  }
  for(TypeNode::iterator i = n.begin(), i_end = n.end(); i != i_end; ++i) {
    Debug("export") << "type: child: " << *i << std::endl;
    children << exportTypeInternal(*i, from, to, vmap);
  }
  TypeNode out = children.constructTypeNode();// FIXME thread safety
  to_t = to->toType(out);
  return out;
}/* exportTypeInternal() */
Exemple #25
0
void CoreSolver::buildModel() {
  Debug("bv-core") << "CoreSolver::buildModel() \n";
  d_modelValues.clear();
  TNodeSet constants;
  TNodeSet constants_in_eq_engine;
  // collect constants in equality engine
  eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(&d_equalityEngine);
  while (!eqcs_i.isFinished()) {
    TNode repr = *eqcs_i;
    if  (repr.getKind() == kind::CONST_BITVECTOR) {
      // must check if it's just the constant
      eq::EqClassIterator it(repr, &d_equalityEngine);
      if (!(++it).isFinished() || true) {
        constants.insert(repr);
        constants_in_eq_engine.insert(repr);
      }
    }
    ++eqcs_i;
  }

  // build repr to value map

  eqcs_i = eq::EqClassesIterator(&d_equalityEngine);
  while (!eqcs_i.isFinished()) {
    TNode repr = *eqcs_i;
    ++eqcs_i;

    if (repr.getKind() != kind::VARIABLE &&
        repr.getKind() != kind::SKOLEM &&
        repr.getKind() != kind::CONST_BITVECTOR &&
        !d_bv->isSharedTerm(repr)) {
      continue;
    }

    TypeNode type = repr.getType();
    if (type.isBitVector() && repr.getKind()!= kind::CONST_BITVECTOR) {
      Debug("bv-core-model") << "   processing " << repr <<"\n";
      // we need to assign a value for it
      TypeEnumerator te(type);
      Node val;
      do {
        val = *te;
        ++te;
        // Debug("bv-core-model") << "  trying value " << val << "\n";
        // Debug("bv-core-model") << "  is in set? " << constants.count(val) << "\n";
        // Debug("bv-core-model") << "  enumerator done? " << te.isFinished() << "\n";
      } while (constants.count(val) != 0 && !(te.isFinished()));

      if (te.isFinished() && constants.count(val) != 0) {
        // if we cannot enumerate anymore values we just return the lemma stating that
        // at least two of the representatives are equal.
        std::vector<TNode> representatives;
        representatives.push_back(repr);

        for (TNodeSet::const_iterator it = constants_in_eq_engine.begin();
             it != constants_in_eq_engine.end(); ++it) {
          TNode constant = *it;
          if (utils::getSize(constant) == utils::getSize(repr)) {
            representatives.push_back(constant);
          }
        }
        for (ModelValue::const_iterator it = d_modelValues.begin(); it != d_modelValues.end(); ++it) {
          representatives.push_back(it->first);
        }
        std::vector<Node> equalities;
        for (unsigned i = 0; i < representatives.size(); ++i) {
          for (unsigned j = i + 1; j < representatives.size(); ++j) {
            TNode a = representatives[i];
            TNode b = representatives[j];
            if (a.getKind() == kind::CONST_BITVECTOR &&
                b.getKind() == kind::CONST_BITVECTOR) {
              Assert (a != b);
              continue;
            }
            if (utils::getSize(a) == utils::getSize(b)) {
              equalities.push_back(utils::mkNode(kind::EQUAL, a, b));
            }
          }
        }
        // better off letting the SAT solver split on values
        if (equalities.size() > d_lemmaThreshold) {
          d_isComplete = false;
          return;
        }

        Node lemma = utils::mkOr(equalities);
        d_bv->lemma(lemma);
        Debug("bv-core") << "  lemma: " << lemma << "\n";
        return;
      }
    
      Debug("bv-core-model") << "   " << repr << " => " << val <<"\n" ;
      constants.insert(val);
      d_modelValues[repr] = val;
    }
  }
}
Exemple #26
0
TypeNode NodeManager::getDatatypeForTupleRecord(TypeNode t) {
  Assert(t.isTuple() || t.isRecord());

  //AJR: not sure why .getBaseType() was used in two cases below,
  //     disabling this, which is necessary to fix bug 605/667,
  //     which involves records of INT which were mapped to records of REAL below.
  TypeNode tOrig = t;
  if(t.isTuple()) {
    vector<TypeNode> v;
    bool changed = false;
    for(size_t i = 0; i < t.getNumChildren(); ++i) {
      TypeNode tn = t[i];
      TypeNode base;
      if(tn.isTuple() || tn.isRecord()) {
        base = getDatatypeForTupleRecord(tn);
      } else {
        base = tn;//.getBaseType();
      }
      changed = changed || (tn != base);
      v.push_back(base);
    }
    if(changed) {
      t = mkTupleType(v);
    }
  } else {
    const Record& r = t.getRecord();
    std::vector< std::pair<std::string, Type> > v;
    bool changed = false;
    const Record::FieldVector& fields = r.getFields();
    for(Record::FieldVector::const_iterator i = fields.begin(); i != fields.end(); ++i) {
      Type tn = (*i).second;
      Type base;
      if(tn.isTuple() || tn.isRecord()) {
        base = getDatatypeForTupleRecord(TypeNode::fromType(tn)).toType();
      } else {
        base = tn;//.getBaseType();
      }
      changed = changed || (tn != base);
      v.push_back(std::make_pair((*i).first, base));
    }
    if(changed) {
      t = mkRecordType(Record(v));
    }
  }

  // if the type doesn't have an associated datatype, then make one for it
  TypeNode& dtt = d_tupleAndRecordTypes[t];
  if(dtt.isNull()) {
    if(t.isTuple()) {
      Datatype dt("__cvc4_tuple");
      DatatypeConstructor c("__cvc4_tuple_ctor");
      for(TypeNode::const_iterator i = t.begin(); i != t.end(); ++i) {
        c.addArg("__cvc4_tuple_stor", (*i).toType());
      }
      dt.addConstructor(c);
      dtt = TypeNode::fromType(toExprManager()->mkDatatypeType(dt));
      Debug("tuprec") << "REWROTE " << t << " to " << dtt << std::endl;
      dtt.setAttribute(DatatypeTupleAttr(), tOrig);
    } else {
      const Record& rec = t.getRecord();
      const Record::FieldVector& fields = rec.getFields();
      Datatype dt("__cvc4_record");
      DatatypeConstructor c("__cvc4_record_ctor");
      for(Record::FieldVector::const_iterator i = fields.begin(); i != fields.end(); ++i) {
        c.addArg((*i).first, (*i).second);
      }
      dt.addConstructor(c);
      dtt = TypeNode::fromType(toExprManager()->mkDatatypeType(dt));
      Debug("tuprec") << "REWROTE " << t << " to " << dtt << std::endl;
      dtt.setAttribute(DatatypeRecordAttr(), tOrig);
    }
  } else {
    Debug("tuprec") << "REUSING cached " << t << ": " << dtt << std::endl;
  }
  Assert(!dtt.isNull());
  return dtt;
}
Exemple #27
0
void BoundedIntegers::registerQuantifier( Node f ) {
  Trace("bound-int") << "Register quantifier " << f << std::endl;
  
  bool success;
  do{
    std::map< Node, unsigned > bound_lit_type_map;
    std::map< int, std::map< Node, Node > > bound_lit_map;
    std::map< int, std::map< Node, bool > > bound_lit_pol_map;
    std::map< int, std::map< Node, Node > > bound_int_range_term;
    success = false;
    process( f, f[1], true, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term );
    //for( std::map< Node, Node >::iterator it = d_bounds[0][f].begin(); it != d_bounds[0][f].end(); ++it ){
    for( std::map< Node, unsigned >::iterator it = bound_lit_type_map.begin(); it != bound_lit_type_map.end(); ++it ){
      Node v = it->first;
      if( !isBound( f, v ) ){
        bool setBoundVar = false;
        if( it->second==BOUND_INT_RANGE ){
          //must have both
          if( bound_lit_map[0].find( v )!=bound_lit_map[0].end() && bound_lit_map[1].find( v )!=bound_lit_map[1].end() ){
            setBoundedVar( f, v, BOUND_INT_RANGE );
            setBoundVar = true;
            success = true;
            for( unsigned b=0; b<2; b++ ){
              //set the bounds
              Assert( bound_int_range_term[b].find( v )!=bound_int_range_term[b].end() );
              d_bounds[b][f][v] = bound_int_range_term[b][v];
            }
            Node r = NodeManager::currentNM()->mkNode( MINUS, d_bounds[1][f][v], d_bounds[0][f][v] );
            d_range[f][v] = Rewriter::rewrite( r );
            Trace("bound-int") << "Variable " << v << " is bound because of int range literals " << bound_lit_map[0][v] << " and " << bound_lit_map[1][v] << std::endl;
          }
        }else if( it->second==BOUND_SET_MEMBER ){
          setBoundedVar( f, v, BOUND_SET_MEMBER );
          setBoundVar = true;
          d_setm_range[f][v] = bound_lit_map[0][v][1];
          Trace("bound-int") << "Variable " << v << " is bound because of set membership literal " << bound_lit_map[0][v] << std::endl;
        }
        if( setBoundVar ){
          //set Attributes on literals
          for( unsigned b=0; b<2; b++ ){
            if( bound_lit_map[b].find( v )!=bound_lit_map[b].end() ){
              Assert( bound_lit_pol_map[b].find( v )!=bound_lit_pol_map[b].end() );
              BoundIntLitAttribute bila;
              bound_lit_map[b][v].setAttribute( bila, bound_lit_pol_map[b][v] ? 1 : 0 );
            }else{
              Assert( it->second!=BOUND_INT_RANGE );
            }
          }
        }
      }
    }
  }while( success );
  
  Trace("bound-int") << "Bounds are : " << std::endl;
  for( unsigned i=0; i<d_set[f].size(); i++) {
    Node v = d_set[f][i];
    if( d_bound_type[f][v]==BOUND_INT_RANGE ){
      Trace("bound-int") << "  " << d_bounds[0][f][v] << " <= " << v << " <= " << d_bounds[1][f][v] << " (range is " << d_range[f][v] << ")" << std::endl;
    }else if( d_bound_type[f][v]==BOUND_SET_MEMBER ){
      Trace("bound-int") << "  " << v << " in " << d_setm_range[f][v] << std::endl;
    }
  }
  
  bool bound_success = true;
  for( unsigned i=0; i<f[0].getNumChildren(); i++) {
    if( d_bound_type[f].find( f[0][i] )==d_bound_type[f].end() ){
      TypeNode tn = f[0][i].getType();
      if( !tn.isSort() && !getTermDatabase()->mayComplete( tn ) ){
        Trace("bound-int-warn") << "Warning : Bounded Integers : Due to quantification on " << f[0][i] << ", could not find bounds for " << f << std::endl;
        bound_success = false;
        break;
      }
    }
  }
  
  if( bound_success ){
    d_bound_quants.push_back( f );
    for( unsigned i=0; i<d_set[f].size(); i++) {
      Node v = d_set[f][i];
      if( d_bound_type[f][v]==BOUND_INT_RANGE || d_bound_type[f][v]==BOUND_SET_MEMBER ){
        Node r;
        if( d_bound_type[f][v]==BOUND_INT_RANGE ){
          r = d_range[f][v];
        }else if( d_bound_type[f][v]==BOUND_SET_MEMBER ){
          r = NodeManager::currentNM()->mkNode( CARD, d_setm_range[f][v] );
        }
        bool isProxy = false;
        if( r.hasBoundVar() ){
          //introduce a new bound
          Node new_range = NodeManager::currentNM()->mkSkolem( "bir", r.getType(), "bound for term" );
          d_nground_range[f][v] = d_range[f][v];
          d_range[f][v] = new_range;
          r = new_range;
          isProxy = true;
        }
        if( !r.isConst() ){
          if( std::find(d_ranges.begin(), d_ranges.end(), r)==d_ranges.end() ){
            Trace("bound-int") << "For " << v << ", bounded Integer Module will try to minimize : " << r << std::endl;
            d_ranges.push_back( r );
            d_rms[r] = new IntRangeModel( this, r, d_quantEngine->getSatContext(), d_quantEngine->getUserContext(), isProxy );
            d_rms[r]->initialize();
          }
        }
      }
    }
  }
}
Exemple #28
0
bool RepSetIterator::initialize(){
  for( size_t i=0; i<d_types.size(); i++ ){
    d_index.push_back( 0 );
    //store default index order
    d_index_order.push_back( i );
    d_var_order[i] = i;
    //store default domain
    d_domain.push_back( RepDomain() );
    TypeNode tn = d_types[i];
    if( tn.isSort() ){
      if( !d_rep_set->hasType( tn ) ){
        Node var = NodeManager::currentNM()->mkSkolem( "repSet", tn, "is a variable created by the RepSetIterator" );
        Trace("mkVar") << "RepSetIterator:: Make variable " << var << " : " << tn << std::endl;
        d_rep_set->add( tn, var );
      }
    }else if( tn.isInteger() ){
      bool inc = false;
      //check if it is bound
      if( d_owner.getKind()==FORALL && d_qe && d_qe->getBoundedIntegers() ){
        if( d_qe->getBoundedIntegers()->isBoundVar( d_owner, d_owner[0][i] ) ){
          Trace("bound-int-rsi") << "Rep set iterator: variable #" << i << " is bounded integer." << std::endl;
          d_enum_type.push_back( ENUM_RANGE );
        }else{
          inc = true;
        }
      }else{
        inc = true;
      }
      if( inc ){
        //check if it is otherwise bound
        if( d_bounds[0].find(i)!=d_bounds[0].end() && d_bounds[1].find(i)!=d_bounds[1].end() ){
          Trace("bound-int-rsi") << "Rep set iterator: variable #" << i << " is bounded." << std::endl;
          d_enum_type.push_back( ENUM_RANGE );
        }else{
          Trace("fmf-incomplete") << "Incomplete because of integer quantification of " << d_owner[0][i] << "." << std::endl;
          d_incomplete = true;
        }
      }
    //enumerate if the sort is reasonably small, the upper bound of 1000 is chosen arbitrarily for now
    }else if( tn.getCardinality().isFinite() && !tn.getCardinality().isLargeFinite() &&
              tn.getCardinality().getFiniteCardinality().toUnsignedInt()<=1000 ){
      d_rep_set->complete( tn );
    }else{
      Trace("fmf-incomplete") << "Incomplete because of quantification of type " << tn << std::endl;
      d_incomplete = true;
    }
    if( d_enum_type.size()<=i ){
      d_enum_type.push_back( ENUM_DOMAIN_ELEMENTS );
      if( d_rep_set->hasType( tn ) ){
        for( size_t j=0; j<d_rep_set->d_type_reps[tn].size(); j++ ){
          d_domain[i].push_back( j );
        }
      }else{
        return false;
      }
    }
  }
  //must set a variable index order based on bounded integers
  if (d_owner.getKind()==FORALL && d_qe && d_qe->getBoundedIntegers()) {
    Trace("bound-int-rsi") << "Calculating variable order..." << std::endl;
    std::vector< int > varOrder;
    for( unsigned i=0; i<d_qe->getBoundedIntegers()->getNumBoundVars(d_owner); i++ ){
      varOrder.push_back(d_qe->getBoundedIntegers()->getBoundVarNum(d_owner,i));
    }
    for( unsigned i=0; i<d_owner[0].getNumChildren(); i++) {
      if( !d_qe->getBoundedIntegers()->isBoundVar(d_owner, d_owner[0][i])) {
        varOrder.push_back(i);
      }
    }
    Trace("bound-int-rsi") << "Variable order : ";
    for( unsigned i=0; i<varOrder.size(); i++) {
      Trace("bound-int-rsi") << varOrder[i] << " ";
    }
    Trace("bound-int-rsi") << std::endl;
    std::vector< int > indexOrder;
    indexOrder.resize(varOrder.size());
    for( unsigned i=0; i<varOrder.size(); i++){
      indexOrder[varOrder[i]] = i;
    }
    Trace("bound-int-rsi") << "Will use index order : ";
    for( unsigned i=0; i<indexOrder.size(); i++) {
      Trace("bound-int-rsi") << indexOrder[i] << " ";
    }
    Trace("bound-int-rsi") << std::endl;
    setIndexOrder(indexOrder);
  }
  //now reset the indices
  for (unsigned i=0; i<d_index.size(); i++) {
    if (!resetIndex(i, true)){
      break;
    }
  }
  return true;
}
Exemple #29
0
bool RepSetIterator::initialize( RepBoundExt* rext ){
  Trace("rsi") << "Initialize rep set iterator..." << std::endl;
  for( unsigned v=0; v<d_types.size(); v++ ){
    d_index.push_back( 0 );
    //store default index order
    d_index_order.push_back( v );
    d_var_order[v] = v;
    //store default domain
    //d_domain.push_back( RepDomain() );
    d_domain_elements.push_back( std::vector< Node >() );
    TypeNode tn = d_types[v];
    Trace("rsi") << "Var #" << v << " is type " << tn << "..." << std::endl;
    if( tn.isSort() ){
      //must ensure uninterpreted type is non-empty.
      if( !d_rep_set->hasType( tn ) ){
        //FIXME:
        // terms in rep_set are now constants which mapped to terms through TheoryModel
        // thus, should introduce a constant and a term.  for now, just a term.

        //Node c = d_qe->getTermDatabase()->getEnumerateTerm( tn, 0 );
        Node var = d_qe->getModel()->getSomeDomainElement( tn );
        Trace("mkVar") << "RepSetIterator:: Make variable " << var << " : " << tn << std::endl;
        d_rep_set->add( tn, var );
      }
    }
    bool inc = true;
    //check if it is externally bound
    if( rext && rext->setBound( d_owner, v, tn, d_domain_elements[v] ) ){
      d_enum_type.push_back( ENUM_DEFAULT );
      inc = false;
    //builtin: check if it is bound by bounded integer module
    }else if( d_owner.getKind()==FORALL && d_qe && d_qe->getBoundedIntegers() ){
      if( d_qe->getBoundedIntegers()->isBoundVar( d_owner, d_owner[0][v] ) ){
        unsigned bvt = d_qe->getBoundedIntegers()->getBoundVarType( d_owner, d_owner[0][v] );
        if( bvt!=quantifiers::BoundedIntegers::BOUND_FINITE ){
          d_enum_type.push_back( ENUM_BOUND_INT );
          inc = false;
        }else{
          //will treat in default way
        }
      }
    }
    if( !tn.isSort() ){
      if( inc ){
        if( d_qe->getTermDatabase()->mayComplete( tn ) ){
          Trace("rsi") << "  do complete, since cardinality is small (" << tn.getCardinality() << ")..." << std::endl;
          d_rep_set->complete( tn );
          //must have succeeded
          Assert( d_rep_set->hasType( tn ) );
        }else{
          Trace("rsi") << "  variable cannot be bounded." << std::endl;
          Trace("fmf-incomplete") << "Incomplete because of quantification of type " << tn << std::endl;
          d_incomplete = true;
        }
      }
    }

    //if we have yet to determine the type of enumeration
    if( d_enum_type.size()<=v ){
      if( d_rep_set->hasType( tn ) ){
        d_enum_type.push_back( ENUM_DEFAULT );
        for( unsigned j=0; j<d_rep_set->d_type_reps[tn].size(); j++ ){
          //d_domain[v].push_back( j );
          d_domain_elements[v].push_back( d_rep_set->d_type_reps[tn][j] );
        }
      }else{
        Assert( d_incomplete );
        return false;
      }
    }
  }
  //must set a variable index order based on bounded integers
  if( d_owner.getKind()==FORALL && d_qe && d_qe->getBoundedIntegers() ){
    Trace("bound-int-rsi") << "Calculating variable order..." << std::endl;
    std::vector< int > varOrder;
    for( unsigned i=0; i<d_qe->getBoundedIntegers()->getNumBoundVars( d_owner ); i++ ){
      Node v = d_qe->getBoundedIntegers()->getBoundVar( d_owner, i );
      Trace("bound-int-rsi") << "  bound var #" << i << " is " << v << std::endl;
      varOrder.push_back( d_qe->getTermDatabase()->getVariableNum( d_owner, v ) );
    }
    for( unsigned i=0; i<d_owner[0].getNumChildren(); i++) {
      if( !d_qe->getBoundedIntegers()->isBoundVar(d_owner, d_owner[0][i])) {
        varOrder.push_back(i);
      }
    }
    Trace("bound-int-rsi") << "Variable order : ";
    for( unsigned i=0; i<varOrder.size(); i++) {
      Trace("bound-int-rsi") << varOrder[i] << " ";
    }
    Trace("bound-int-rsi") << std::endl;
    std::vector< int > indexOrder;
    indexOrder.resize(varOrder.size());
    for( unsigned i=0; i<varOrder.size(); i++){
      indexOrder[varOrder[i]] = i;
    }
    Trace("bound-int-rsi") << "Will use index order : ";
    for( unsigned i=0; i<indexOrder.size(); i++) {
      Trace("bound-int-rsi") << indexOrder[i] << " ";
    }
    Trace("bound-int-rsi") << std::endl;
    setIndexOrder( indexOrder );
  }
  //now reset the indices
  do_reset_increment( -1, true );
  return true;
}
Exemple #30
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();
  }
}