In some SyGuS applications, the bottleneck is the rewriter. This PR makes a few simple optimizations to the core rewriter, namely:
(1) Minimize the overhead of `theoryOf` calls, which take about 10-15% of the runtime in the rewriter. This PR avoids many calls to `theoryOf` by the observation that nodes with zero children never rewrite, hence we can return the node itself immediately. Furthermore, the `theoryOf` call can be simplified to hardcode the context under which we were using it: get the theory (based on type) where due to the above, we can assume that the node is not a variable.
The one (negligible) change in behavior due to this change is that nodes with more than one child for which `isConst` returns true (this is limited to the case of `APPLY_CONSTRUCTOR` in datatypes) lookup their theory based on the Kind, not their type, which should always be the same theory unless a theory had a way of constructing constant nodes of a type belonging to another theory.
(2) Remove deprecated infrastrastructure for a "neverIsConst" function, which was adding about a 1% of the runtime for some SyGuS benchmarks.
This makes SyGuS for some sets of benchmarks roughly 3% faster.
typerules=
construles=
-neverconstrules=
seen_theory=false
seen_theory_builtin=false
case kind::$1:
#line $lineno \"$kf\"
return $2::computeIsConst(nodeManager, n);
-"
- neverconstrules="${neverconstrules}
-#line $lineno \"$kf\"
- case kind::$1:
-#line $lineno \"$kf\"
- return false;
"
}
typechecker_includes \
typerules \
construles \
- neverconstrules \
; do
eval text="\${text//\\\$\\{$var\\}/\${$var}}"
done
Debug("isConst") << "Node::isConst() returning false, it's a VARIABLE" << std::endl;
return false;
default:
- if(expr::TypeChecker::neverIsConst(NodeManager::currentNM(), *this)){
- Debug("isConst") << "Node::isConst() returning false, the kind is never const" << std::endl;
- return false;
- }
if(getAttribute(IsConstComputedAttr())) {
bool bval = getAttribute(IsConstAttr());
Debug("isConst") << "Node::isConst() returning cached value " << (bval ? "true" : "false") << " for: " << *this << std::endl;
static bool computeIsConst(NodeManager* nodeManager, TNode n);
- static bool neverIsConst(NodeManager* nodeManager, TNode n);
-
};/* class TypeChecker */
}/* CVC4::expr namespace */
}/* TypeChecker::computeIsConst */
-bool TypeChecker::neverIsConst(NodeManager* nodeManager, TNode n)
-{
- Assert(n.getMetaKind() == kind::metakind::OPERATOR
- || n.getMetaKind() == kind::metakind::PARAMETERIZED
- || n.getMetaKind() == kind::metakind::NULLARY_OPERATOR);
-
- switch(n.getKind()) {
-${neverconstrules}
-
-#line 90 "${template}"
-
- default:;
- }
-
- return true;
-
-}/* TypeChecker::neverIsConst */
-
}/* CVC4::expr namespace */
}/* CVC4 namespace */
namespace CVC4 {
namespace theory {
+// Note that this function is a simplified version of Theory::theoryOf for
+// (type-based) theoryOfMode. We expand and simplify it here for the sake of
+// efficiency.
static TheoryId theoryOf(TNode node) {
- return Theory::theoryOf(THEORY_OF_TYPE_BASED, node);
+ if (node.getKind() == kind::EQUAL)
+ {
+ // Equality is owned by the theory that owns the domain
+ return Theory::theoryOf(node[0].getType());
+ }
+ // Regular nodes are owned by the kind
+ return kindToTheoryId(node.getKind());
}
/**
};
Node Rewriter::rewrite(TNode node) {
+ if (node.getNumChildren() == 0)
+ {
+ // Nodes with zero children should never change via rewriting. We return
+ // eagerly for the sake of efficiency here.
+ return node;
+ }
Rewriter& rewriter = getInstance();
return rewriter.rewriteTo(theoryOf(node), node);
}