return d_node->isConst();
}
+bool Expr::hasFreeVariable() const
+{
+ ExprManagerScope ems(*this);
+ Assert(d_node != NULL, "Unexpected NULL expression pointer!");
+ return d_node->hasFreeVar();
+}
+
void Expr::toStream(std::ostream& out, int depth, bool types, size_t dag,
OutputLanguage language) const {
ExprManagerScope ems(*this);
*/
bool isConst() const;
+ /**
+ * Check if this expression contains a free variable.
+ *
+ * @return true if this node contains a free variable.
+ */
+ bool hasFreeVariable() const;
+
/* A note on isAtomic() and isAtomicFormula() (in CVC3 parlance)..
*
* It has been decided for now to hold off on implementations of
return getAttribute(HasBoundVarAttr());
}
+template <bool ref_count>
+bool NodeTemplate<ref_count>::hasFreeVar()
+{
+ assertTNodeNotExpired();
+ std::unordered_set<TNode, TNodeHashFunction> bound_var;
+ std::unordered_map<TNode, bool, TNodeHashFunction> visited;
+ std::vector<TNode> visit;
+ TNode cur;
+ visit.push_back(*this);
+ do
+ {
+ cur = visit.back();
+ visit.pop_back();
+ // can skip if it doesn't have a bound variable
+ if (!cur.hasBoundVar())
+ {
+ continue;
+ }
+ Kind k = cur.getKind();
+ bool isQuant = k == kind::FORALL || k == kind::EXISTS || k == kind::LAMBDA
+ || k == kind::CHOICE;
+ std::unordered_map<TNode, bool, TNodeHashFunction>::iterator itv =
+ visited.find(cur);
+ if (itv == visited.end())
+ {
+ if (k == kind::BOUND_VARIABLE)
+ {
+ if (bound_var.find(cur) == bound_var.end())
+ {
+ return true;
+ }
+ }
+ else if (isQuant)
+ {
+ for (const TNode& cn : cur[0])
+ {
+ // should not shadow
+ Assert(bound_var.find(cn) == bound_var.end());
+ bound_var.insert(cn);
+ }
+ visit.push_back(cur);
+ }
+ // must visit quantifiers again to clean up below
+ visited[cur] = !isQuant;
+ for (const TNode& cn : cur)
+ {
+ visit.push_back(cn);
+ }
+ }
+ else if (!itv->second)
+ {
+ Assert(isQuant);
+ for (const TNode& cn : cur[0])
+ {
+ bound_var.erase(cn);
+ }
+ visited[cur] = true;
+ }
+ } while (!visit.empty());
+ return false;
+}
+
template bool NodeTemplate<true>::isConst() const;
template bool NodeTemplate<false>::isConst() const;
template bool NodeTemplate<true>::hasBoundVar();
template bool NodeTemplate<false>::hasBoundVar();
+template bool NodeTemplate<true>::hasFreeVar();
+template bool NodeTemplate<false>::hasFreeVar();
}/* CVC4 namespace */
*/
bool hasBoundVar();
+ /**
+ * Returns true iff this node contains a free variable.
+ * @return true iff this node contains a free variable.
+ */
+ bool hasFreeVar();
+
/**
* Convert this Node into an Expr using the currently-in-scope
* manager. Essentially this is like an "operator Expr()" but we
csen->setMuted(true);
PARSER_STATE->preemptCommand(csen);
}
+ // if sygus, check whether it has a free variable
+ // this is because, due to the sygus format, one can write assertions
+ // that have free function variables in them
+ if (PARSER_STATE->sygus())
+ {
+ if (expr.hasFreeVariable())
+ {
+ PARSER_STATE->parseError("Assertion has free variable. Perhaps you "
+ "meant constraint instead of assert?");
+ }
+ }
}
| /* check-sat */
CHECK_SAT_TOK { PARSER_STATE->checkThatLogicIsSet(); }
// now must check if it has other bound variables
std::vector<Node> bvs;
TermUtil::getBoundVars(cr, bvs);
- if (bvs.size() > d_si_vars.size())
+ // bound variables must be contained in the single invocation variables
+ for (const Node& bv : bvs)
{
- // getBoundVars also collects functions in the rare case that we are
- // synthesizing a function with 0 arguments
- // take these into account below.
- unsigned n_const_synth_fun = 0;
- for (unsigned j = 0; j < bvs.size(); j++)
+ if (std::find(d_si_vars.begin(), d_si_vars.end(), bv)
+ == d_si_vars.end())
{
- if (std::find(d_input_funcs.begin(), d_input_funcs.end(), bvs[j])
- != d_input_funcs.end())
+ // getBoundVars also collects functions in the rare case that we are
+ // synthesizing a function with 0 arguments, take this into account
+ // here.
+ if (std::find(d_input_funcs.begin(), d_input_funcs.end(), bv)
+ == d_input_funcs.end())
{
- n_const_synth_fun++;
+ Trace("si-prt")
+ << "...not ground single invocation." << std::endl;
+ ngroundSingleInvocation = true;
+ singleInvocation = false;
}
}
- if (bvs.size() - n_const_synth_fun > d_si_vars.size())
- {
- Trace("si-prt") << "...not ground single invocation." << std::endl;
- ngroundSingleInvocation = true;
- singleInvocation = false;
- }
- else
- {
- Trace("si-prt") << "...ground single invocation : success, after "
- "removing 0-arg synth functions."
- << std::endl;
- }
}
- else
+ if (singleInvocation)
{
- Trace("si-prt") << "...ground single invocation : success."
- << std::endl;
+ Trace("si-prt") << "...ground single invocation" << std::endl;
}
}
else
d_sharedTerms.addEqualityToPropagate(preprocessed);
}
+ // the atom should not have free variables
+ Assert(!preprocessed.hasFreeVar());
// Pre-register the terms in the atom
Theory::Set theories = NodeVisitor<PreRegisterVisitor>::run(d_preRegistrationVisitor, preprocessed);
theories = Theory::setRemove(THEORY_BOOL, theories);