By default, common subexpressions are dagified if they appear > 1 time and are not constants or variables.
This can be changed with --default-expr-dag=N --- N is a threshold such that if the subexpression occurs > N
times, it is dagified; a setting of 0 turns off dagification entirely.
If you notice strange dumping behavior (taking too long to print anything, e.g.), revert to the old behavior
with --default-expr-dag=0 and let me know of the problem.
c.toStream(out,
Node::setdepth::getDepth(out),
Node::printtypes::getPrintTypes(out),
+ Node::dag::getDag(out),
Node::setlanguage::getLanguage(out));
return out;
}
return ss.str();
}
-void Command::toStream(std::ostream& out, int toDepth, bool types,
+void Command::toStream(std::ostream& out, int toDepth, bool types, size_t dag,
OutputLanguage language) const throw() {
- Printer::getPrinter(language)->toStream(out, this, toDepth, types);
+ Printer::getPrinter(language)->toStream(out, this, toDepth, types, dag);
}
void CommandStatus::toStream(std::ostream& out, OutputLanguage language) const throw() {
virtual void invoke(SmtEngine* smtEngine) throw() = 0;
virtual void invoke(SmtEngine* smtEngine, std::ostream& out) throw();
- virtual void toStream(std::ostream& out, int toDepth = -1, bool types = false,
+ virtual void toStream(std::ostream& out, int toDepth = -1, bool types = false, size_t dag = 1,
OutputLanguage language = language::output::LANG_AST) const throw();
std::string toString() const throw();
%ignore CVC4::expr::operator<<(std::ostream&, ExprSetDepth);
%ignore CVC4::expr::operator<<(std::ostream&, ExprPrintTypes);
+%ignore CVC4::expr::operator<<(std::ostream&, ExprDag);
%ignore CVC4::expr::operator<<(std::ostream&, ExprSetLanguage);
%rename(assign) CVC4::Expr::operator=(const Expr&);
const int ExprSetDepth::s_iosIndex = std::ios_base::xalloc();
const int ExprPrintTypes::s_iosIndex = std::ios_base::xalloc();
+const int ExprDag::s_iosIndex = std::ios_base::xalloc();
const int ExprSetLanguage::s_iosIndex = std::ios_base::xalloc();
}/* CVC4::expr namespace */
return d_node->isConst();
}
-void Expr::toStream(std::ostream& out, int depth, bool types,
+void Expr::toStream(std::ostream& out, int depth, bool types, size_t dag,
OutputLanguage language) const {
ExprManagerScope ems(*this);
- d_node->toStream(out, depth, types, language);
+ d_node->toStream(out, depth, types, dag, language);
}
Node Expr::getNode() const throw() {
namespace expr {
class CVC4_PUBLIC ExprSetDepth;
class CVC4_PUBLIC ExprPrintTypes;
+ class CVC4_PUBLIC ExprDag;
class CVC4_PUBLIC ExprSetLanguage;
NodeTemplate<true> exportInternal(NodeTemplate<false> n, ExprManager* from, ExprManager* to, ExprManagerMapCollection& vmap);
* debugging expressions)
* @param language the language in which to output
*/
- void toStream(std::ostream& out, int toDepth = -1, bool types = false,
+ void toStream(std::ostream& out, int toDepth = -1, bool types = false, size_t dag = 1,
OutputLanguage language = language::output::LANG_AST) const;
/**
*/
typedef expr::ExprPrintTypes printtypes;
+ /**
+ * IOStream manipulator to print expressions as a DAG (or not).
+ */
+ typedef expr::ExprDag dag;
+
/**
* IOStream manipulator to set the output language for Exprs.
*/
*/
class CVC4_PUBLIC ExprPrintTypes {
/**
- * The allocated index in ios_base for our depth setting.
+ * The allocated index in ios_base for our setting.
*/
static const int s_iosIndex;
/**
- * The default depth to print, for ostreams that haven't yet had a
- * setdepth() applied to them.
+ * The default printtypes setting, for ostreams that haven't yet had a
+ * printtypes() applied to them.
*/
static const int s_defaultPrintTypes = false;
};/* class ExprPrintTypes */
+/**
+ * IOStream manipulator to print expressions as a dag (or not).
+ */
+class CVC4_PUBLIC ExprDag {
+ /**
+ * The allocated index in ios_base for our setting.
+ */
+ static const int s_iosIndex;
+
+ /**
+ * The default setting, for ostreams that haven't yet had a
+ * dag() applied to them.
+ */
+ static const size_t s_defaultDag = 1;
+
+ /**
+ * When this manipulator is used, the setting is stored here.
+ */
+ size_t d_dag;
+
+public:
+ /**
+ * Construct a ExprDag with the given setting (dagification on or off).
+ */
+ explicit ExprDag(bool dag) : d_dag(dag ? 1 : 0) {}
+
+ /**
+ * Construct a ExprDag with the given setting (letify only common
+ * subexpressions that appear more than 'dag' times). dag==0 means
+ * don't dagify.
+ */
+ ExprDag(size_t dag) : d_dag(dag) {}
+
+ inline void applyDag(std::ostream& out) {
+ // (offset by one to detect whether default has been set yet)
+ out.iword(s_iosIndex) = static_cast<long>(d_dag) + 1;
+ }
+
+ static inline size_t getDag(std::ostream& out) {
+ long& l = out.iword(s_iosIndex);
+ if(l == 0) {
+ // set the default dag setting on this ostream
+ // (offset by one to detect whether default has been set yet)
+ l = s_defaultDag + 1;
+ }
+ return static_cast<size_t>(l - 1);
+ }
+
+ static inline void setDag(std::ostream& out, size_t dag) {
+ // (offset by one to detect whether default has been set yet)
+ out.iword(s_iosIndex) = static_cast<long>(dag) + 1;
+ }
+
+ /**
+ * Set the dag state on the output stream for the current
+ * stack scope. This makes sure the old state is reset on the
+ * stream after normal OR exceptional exit from the scope, using the
+ * RAII C++ idiom.
+ */
+ class Scope {
+ std::ostream& d_out;
+ size_t d_oldDag;
+
+ public:
+
+ inline Scope(std::ostream& out, size_t dag) :
+ d_out(out),
+ d_oldDag(ExprDag::getDag(out)) {
+ ExprDag::setDag(out, dag);
+ }
+
+ inline ~Scope() {
+ ExprDag::setDag(d_out, d_oldDag);
+ }
+
+ };/* class ExprDag::Scope */
+
+};/* class ExprDag */
+
/**
* IOStream manipulator to set the output language for Exprs.
*/
${getConst_instantiations}
-#line 861 "${template}"
+#line 938 "${template}"
namespace expr {
/**
- * Sets the default print-types setting when pretty-printing an Expr
- * to an ostream. Use like this:
+ * Sets the default depth when pretty-printing a Expr to an ostream.
+ * Use like this:
*
* // let out be an ostream, e an Expr
* out << Expr::setdepth(n) << e << endl;
}
/**
- * Sets the default depth when pretty-printing a Expr to an ostream.
- * Use like this:
+ * Sets the default print-types setting when pretty-printing an Expr
+ * to an ostream. Use like this:
*
* // let out be an ostream, e an Expr
- * out << Expr::setprinttypes(true) << e << endl;
+ * out << Expr::printtypes(true) << e << endl;
*
* The setting stays permanently (until set again) with the stream.
*/
return out;
}
+/**
+ * Sets the default dag setting when pretty-printing a Expr to an ostream.
+ * Use like this:
+ *
+ * // let out be an ostream, e an Expr
+ * out << Expr::dag(true) << e << endl;
+ *
+ * The setting stays permanently (until set again) with the stream.
+ */
+inline std::ostream& operator<<(std::ostream& out, ExprDag d) {
+ d.applyDag(out);
+ return out;
+}
+
/**
* Sets the output language when pretty-printing a Expr to an ostream.
* Use like this:
* (might break language compliance, but good for debugging expressions)
* @param language the language in which to output
*/
- inline void toStream(std::ostream& out, int toDepth = -1, bool types = false,
+ inline void toStream(std::ostream& out, int toDepth = -1, bool types = false, size_t dag = 1,
OutputLanguage language = language::output::LANG_AST) const {
assertTNodeNotExpired();
- d_nv->toStream(out, toDepth, types, language);
+ d_nv->toStream(out, toDepth, types, dag, language);
}
/**
*/
typedef expr::ExprPrintTypes printtypes;
+ /**
+ * IOStream manipulator to print expressions as DAGs (or not).
+ */
+ typedef expr::ExprDag dag;
+
/**
* IOStream manipulator to set the output language for Exprs.
*/
n.toStream(out,
Node::setdepth::getDepth(out),
Node::printtypes::getPrintTypes(out),
+ Node::dag::getDag(out),
Node::setlanguage::getLanguage(out));
return out;
}
*/
static void __attribute__((used)) debugPrintNode(const NodeTemplate<true>& n) {
Warning() << Node::setdepth(-1)
+ << Node::printtypes(false)
+ << Node::dag(true)
+ << Node::setlanguage(language::output::LANG_AST)
+ << n << std::endl;
+ Warning().flush();
+}
+static void __attribute__((used)) debugPrintNodeNoDag(const NodeTemplate<true>& n) {
+ Warning() << Node::setdepth(-1)
+ << Node::printtypes(false)
+ << Node::dag(false)
<< Node::setlanguage(language::output::LANG_AST)
<< n << std::endl;
Warning().flush();
static void __attribute__((used)) debugPrintTNode(const NodeTemplate<false>& n) {
Warning() << Node::setdepth(-1)
+ << Node::printtypes(false)
+ << Node::dag(true)
+ << Node::setlanguage(language::output::LANG_AST)
+ << n << std::endl;
+ Warning().flush();
+}
+static void __attribute__((used)) debugPrintTNodeNoDag(const NodeTemplate<false>& n) {
+ Warning() << Node::setdepth(-1)
+ << Node::printtypes(false)
+ << Node::dag(false)
<< Node::setlanguage(language::output::LANG_AST)
<< n << std::endl;
Warning().flush();
return ss.str();
}
-void NodeValue::toStream(std::ostream& out, int toDepth, bool types,
+void NodeValue::toStream(std::ostream& out, int toDepth, bool types, size_t dag,
OutputLanguage language) const {
// Ensure that this node value is live for the length of this call.
// It really breaks things badly if we don't have a nonzero ref
// count, even just for printing.
RefCountGuard guard(this);
- Printer::getPrinter(language)->toStream(out, TNode(this), toDepth, types);
+ Printer::getPrinter(language)->toStream(out, TNode(this), toDepth, types, dag);
}
void NodeValue::printAst(std::ostream& out, int ind) const {
}
std::string toString() const;
- void toStream(std::ostream& out, int toDepth = -1, bool types = false,
+ void toStream(std::ostream& out, int toDepth = -1, bool types = false, size_t dag = 1,
OutputLanguage = language::output::LANG_AST) const;
static inline unsigned kindToDKind(Kind k) {
nv.toStream(out,
Node::setdepth::getDepth(out),
Node::printtypes::getPrintTypes(out),
+ Node::dag::getDag(out),
Node::setlanguage::getLanguage(out));
return out;
}
*/
static void __attribute__((used)) debugPrintNodeValue(const expr::NodeValue* nv) {
Warning() << Node::setdepth(-1)
+ << Node::printtypes(false)
+ << Node::dag(true)
+ << Node::setlanguage(language::output::LANG_AST)
+ << *nv << std::endl;
+ Warning().flush();
+}
+static void __attribute__((used)) debugPrintNodeValueNoDag(const expr::NodeValue* nv) {
+ Warning() << Node::setdepth(-1)
+ << Node::printtypes(false)
+ << Node::dag(false)
<< Node::setlanguage(language::output::LANG_AST)
<< *nv << std::endl;
Warning().flush();
}
-
static void __attribute__((used)) debugPrintRawNodeValue(const expr::NodeValue* nv) {
nv->printAst(Warning(), 0);
Warning().flush();
* (might break language compliance, but good for debugging expressions)
* @param language the language in which to output
*/
- inline void toStream(std::ostream& out, int toDepth = -1, bool types = false,
+ inline void toStream(std::ostream& out, int toDepth = -1, bool types = false, size_t dag = 1,
OutputLanguage language = language::output::LANG_AST) const {
- d_nv->toStream(out, toDepth, types, language);
+ d_nv->toStream(out, toDepth, types, dag, language);
}
/**
n.toStream(out,
Node::setdepth::getDepth(out),
Node::printtypes::getPrintTypes(out),
+ Node::dag::getDag(out),
Node::setlanguage::getLanguage(out));
return out;
}
*/
static void __attribute__((used)) debugPrintTypeNode(const TypeNode& n) {
Warning() << Node::setdepth(-1)
+ << Node::printtypes(false)
+ << Node::dag(true)
+ << Node::setlanguage(language::output::LANG_AST)
+ << n << std::endl;
+ Warning().flush();
+}
+static void __attribute__((used)) debugPrintTypeNodeNoDag(const TypeNode& n) {
+ Warning() << Node::setdepth(-1)
+ << Node::printtypes(false)
+ << Node::dag(false)
<< Node::setlanguage(language::output::LANG_AST)
<< n << std::endl;
Warning().flush();
noinst_LTLIBRARIES = libprinter.la
libprinter_la_SOURCES = \
+ dagification_visitor.h \
printer.h \
printer.cpp \
ast/ast_printer.h \
#include "util/language.h" // for LANG_AST
#include "expr/node_manager.h" // for VarNameAttr
#include "expr/command.h"
+#include "printer/dagification_visitor.h"
+#include "util/node_visitor.h"
#include <iostream>
#include <vector>
namespace printer {
namespace ast {
+void AstPrinter::toStream(std::ostream& out, TNode n,
+ int toDepth, bool types, size_t dag) const throw() {
+ if(dag != 0) {
+ DagificationVisitor dv(dag);
+ NodeVisitor<DagificationVisitor> visitor;
+ visitor.run(dv, n);
+ const theory::SubstitutionMap& lets = dv.getLets();
+ if(!lets.empty()) {
+ out << "(LET ";
+ bool first = true;
+ for(theory::SubstitutionMap::const_iterator i = lets.begin();
+ i != lets.end();
+ ++i) {
+ if(! first) {
+ out << ", ";
+ } else {
+ first = false;
+ }
+ toStream(out, (*i).second, toDepth, types, false);
+ out << " := ";
+ toStream(out, (*i).first, toDepth, types, false);
+ }
+ out << " IN ";
+ }
+ Node body = dv.getDagifiedBody();
+ toStream(out, body, toDepth, types);
+ if(!lets.empty()) {
+ out << ')';
+ }
+ } else {
+ toStream(out, n, toDepth, types);
+ }
+}
+
void AstPrinter::toStream(std::ostream& out, TNode n,
int toDepth, bool types) const throw() {
// null
if(types) {
// print the whole type, but not *its* type
out << ":";
- n.getType().toStream(out, -1, false, language::output::LANG_AST);
+ n.getType().toStream(out, -1, false, 0, language::output::LANG_AST);
}
return;
if(n.getMetaKind() == kind::metakind::PARAMETERIZED) {
out << ' ';
if(toDepth != 0) {
- n.getOperator().toStream(out, toDepth < 0 ? toDepth : toDepth - 1,
- types, language::output::LANG_AST);
+ toStream(out, n.getOperator(), toDepth < 0 ? toDepth : toDepth - 1, types);
} else {
out << "(...)";
}
out << ' ';
}
if(toDepth != 0) {
- (*i).toStream(out, toDepth < 0 ? toDepth : toDepth - 1,
- types, language::output::LANG_AST);
+ toStream(out, *i, toDepth < 0 ? toDepth : toDepth - 1, types);
} else {
out << "(...)";
}
static bool tryToStream(std::ostream& out, const Command* c) throw();
void AstPrinter::toStream(std::ostream& out, const Command* c,
- int toDepth, bool types) const throw() {
+ int toDepth, bool types, size_t dag) const throw() {
expr::ExprSetDepth::Scope sdScope(out, toDepth);
expr::ExprPrintTypes::Scope ptScope(out, types);
+ expr::ExprDag::Scope dagScope(out, dag);
if(tryToStream<EmptyCommand>(out, c) ||
tryToStream<AssertCommand>(out, c) ||
namespace ast {
class AstPrinter : public CVC4::Printer {
-public:
void toStream(std::ostream& out, TNode n, int toDepth, bool types) const throw();
- void toStream(std::ostream& out, const Command* c, int toDepth, bool types) const throw();
+public:
+ void toStream(std::ostream& out, TNode n, int toDepth, bool types, size_t dag) const throw();
+ void toStream(std::ostream& out, const Command* c, int toDepth, bool types, size_t dag) const throw();
void toStream(std::ostream& out, const CommandStatus* s) const throw();
};/* class AstPrinter */
namespace printer {
namespace cvc {
-void CvcPrinter::toStream(std::ostream& out, TNode n, int depth, bool types, bool bracket) const throw()
-{
+void CvcPrinter::toStream(std::ostream& out, TNode n, int toDepth, bool types, size_t dag) const throw() {
+ if(dag != 0) {
+ DagificationVisitor dv(dag);
+ NodeVisitor<DagificationVisitor> visitor;
+ visitor.run(dv, n);
+ const theory::SubstitutionMap& lets = dv.getLets();
+ if(!lets.empty()) {
+ out << "LET ";
+ bool first = true;
+ for(theory::SubstitutionMap::const_iterator i = lets.begin();
+ i != lets.end();
+ ++i) {
+ if(! first) {
+ out << ", ";
+ } else {
+ first = false;
+ }
+ toStream(out, (*i).second, toDepth, types, false);
+ out << " = ";
+ toStream(out, (*i).first, toDepth, types, false);
+ }
+ out << " IN ";
+ }
+ Node body = dv.getDagifiedBody();
+ toStream(out, body, toDepth, types, false);
+ } else {
+ toStream(out, n, toDepth, types, false);
+ }
+}
+
+void CvcPrinter::toStream(std::ostream& out, TNode n, int depth, bool types, bool bracket) const throw() {
if (depth == 0) {
out << "(...)";
} else {
static bool tryToStream(std::ostream& out, const Command* c) throw();
void CvcPrinter::toStream(std::ostream& out, const Command* c,
- int toDepth, bool types) const throw() {
+ int toDepth, bool types, size_t dag) const throw() {
expr::ExprSetDepth::Scope sdScope(out, toDepth);
expr::ExprPrintTypes::Scope ptScope(out, types);
+ expr::ExprDag::Scope dagScope(out, dag);
if(tryToStream<AssertCommand>(out, c) ||
tryToStream<PushCommand>(out, c) ||
#include <iostream>
#include "printer/printer.h"
+#include "printer/dagification_visitor.h"
+#include "theory/substitutions.h"
+#include "util/node_visitor.h"
namespace CVC4 {
namespace printer {
class CvcPrinter : public CVC4::Printer {
void toStream(std::ostream& out, TNode n, int toDepth, bool types, bool bracket) const throw();
public:
- void toStream(std::ostream& out, TNode n, int toDepth, bool types) const throw() {
- toStream(out, n, toDepth, types, false);
- }
- void toStream(std::ostream& out, const Command* c, int toDepth, bool types) const throw();
+ void toStream(std::ostream& out, TNode n, int toDepth, bool types, size_t dag) const throw();
+ void toStream(std::ostream& out, const Command* c, int toDepth, bool types, size_t dag) const throw();
void toStream(std::ostream& out, const CommandStatus* s) const throw();
};/* class CvcPrinter */
--- /dev/null
+/********************* */
+/*! \file dagification_visitor.h
+ ** \verbatim
+ ** Original author: mdeters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011, 2012 The Analysis of Computer Systems Group (ACSys)
+ ** Courant Institute of Mathematical Sciences
+ ** New York University
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__PRINTER__DAGIFICATION_VISITOR_H
+#define __CVC4__PRINTER__DAGIFICATION_VISITOR_H
+
+#include "context/context.h"
+#include "theory/substitutions.h"
+#include "expr/node.h"
+#include "util/hash.h"
+
+#include <vector>
+#include <string>
+#include <sstream>
+
+namespace CVC4 {
+namespace printer {
+
+class DagificationVisitor {
+
+ unsigned d_threshold;
+ std::string d_letVarPrefix;
+ std::hash_map<TNode, unsigned, TNodeHashFunction> d_nodeCount;
+ TNode d_top;
+ context::Context* d_context;
+ theory::SubstitutionMap* d_substitutions;
+ unsigned d_letVar;
+ bool d_done;
+ std::hash_map<TNode, TNode, TNodeHashFunction> d_uniqueParent;
+ std::vector<TNode> d_substNodes;
+
+public:
+
+ typedef void return_type;
+
+ DagificationVisitor(unsigned threshold, std::string letVarPrefix = "_let_") :
+ d_threshold(threshold),
+ d_letVarPrefix(letVarPrefix),
+ d_nodeCount(),
+ d_top(),
+ d_context(new context::Context()),
+ d_substitutions(new theory::SubstitutionMap(d_context)),
+ d_letVar(0),
+ d_done(false),
+ d_uniqueParent(),
+ d_substNodes() {
+
+ // 0 doesn't make sense
+ CheckArgument(threshold > 0, threshold);
+ }
+
+ ~DagificationVisitor() {
+ delete d_substitutions;
+ delete d_context;
+ }
+
+ /**
+ * Returns true if current has already been dagified.
+ */
+ bool alreadyVisited(TNode current, TNode parent) {
+ // don't visit variables, constants, or those exprs that we've
+ // already seen more than the threshold: if we've increased
+ // the count beyond the threshold already, we've done the same
+ // for all subexpressions, so it isn't useful to traverse and
+ // increment again (they'll be dagified anyway).
+ return current.getMetaKind() == kind::metakind::VARIABLE ||
+ current.getMetaKind() == kind::metakind::CONSTANT ||
+ ( ( current.getKind() == kind::NOT ||
+ current.getKind() == kind::UMINUS ) &&
+ ( current[0].getMetaKind() == kind::metakind::VARIABLE ||
+ current[0].getMetaKind() == kind::metakind::CONSTANT ) ) ||
+ current.getKind() == kind::SORT_TYPE ||
+ d_nodeCount[current] > d_threshold;
+ }
+
+ /**
+ * Dagify the "current" expression.
+ */
+ void visit(TNode current, TNode parent) {
+ if(d_uniqueParent.find(current) != d_uniqueParent.end()) {
+ TNode& uniqueParent = d_uniqueParent[current];
+
+ if(!uniqueParent.isNull() && uniqueParent != parent) {
+ // there is not a unique parent for this expr
+ uniqueParent = TNode::null();
+ }
+
+ unsigned count = ++d_nodeCount[current];
+
+ if(count > d_threshold) {
+ d_substNodes.push_back(current);
+ }
+ } else {
+ Assert(d_nodeCount[current] == 0);
+ d_nodeCount[current] = 1;
+ d_uniqueParent[current] = parent;
+ }
+ }
+
+ /**
+ * Marks the node as the starting literal.
+ */
+ void start(TNode node) {
+ Assert(!d_done, "DagificationVisitor cannot be re-used");
+ d_top = node;
+ }
+
+ /**
+ * Called when we're done with all visitation.
+ */
+ void done(TNode node) {
+ Assert(!d_done);
+
+ d_done = true;
+
+ // letify subexprs before parents (cascading LETs)
+ std::sort(d_substNodes.begin(), d_substNodes.end());
+
+ for(std::vector<TNode>::iterator i = d_substNodes.begin();
+ i != d_substNodes.end();
+ ++i) {
+ Assert(d_nodeCount[*i] > d_threshold);
+ TNode parent = d_uniqueParent[*i];
+ if(!parent.isNull() && d_nodeCount[parent] > d_threshold) {
+ // no need to letify this expr, because it only occurs in
+ // a single super-expression, and that one will be letified
+ continue;
+ }
+
+ std::stringstream ss;
+ ss << d_letVarPrefix << d_letVar++;
+ Node letvar = NodeManager::currentNM()->mkVar(ss.str(), (*i).getType());
+
+ Node n = d_substitutions->apply(*i);
+ // the three last arguments to addSubstitution are:
+ // invalidateCache -- the rhs of our substitution is a letvar,
+ // we're not going to use it on lhs so no cache problem
+ // backSub - no need for SubstitutionMap to do internal substitution,
+ // we did our own above
+ // forwardSub - ditto
+ Assert(! d_substitutions->hasSubstitution(n));
+ d_substitutions->addSubstitution(n, letvar);
+ }
+ }
+
+ /**
+ * Get the let substitutions.
+ */
+ const theory::SubstitutionMap& getLets() {
+ Assert(d_done, "DagificationVisitor must be used as a visitor before getting the dagified version out!");
+ return *d_substitutions;
+ }
+
+ /**
+ * Return the let-substituted expression.
+ */
+ Node getDagifiedBody() {
+ Assert(d_done, "DagificationVisitor must be used as a visitor before getting the dagified version out!");
+ return d_substitutions->apply(d_top);
+ }
+
+};/* class DagificationVisitor */
+
+}/* CVC4::printer namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__PRINTER__DAGIFICATION_VISITOR_H */
/** Write a Node out to a stream with this Printer. */
virtual void toStream(std::ostream& out, TNode n,
- int toDepth, bool types) const throw() = 0;
+ int toDepth, bool types, size_t dag) const throw() = 0;
/** Write a Command out to a stream with this Printer. */
virtual void toStream(std::ostream& out, const Command* c,
- int toDepth, bool types) const throw() = 0;
+ int toDepth, bool types, size_t dag) const throw() = 0;
/** Write a CommandStatus out to a stream with this Printer. */
virtual void toStream(std::ostream& out, const CommandStatus* s) const throw() = 0;
namespace smt {
void SmtPrinter::toStream(std::ostream& out, TNode n,
- int toDepth, bool types) const throw() {
- n.toStream(out, toDepth, types, language::output::LANG_SMTLIB_V2);
+ int toDepth, bool types, size_t dag) const throw() {
+ n.toStream(out, toDepth, types, dag, language::output::LANG_SMTLIB_V2);
}/* SmtPrinter::toStream() */
void SmtPrinter::toStream(std::ostream& out, const Command* c,
- int toDepth, bool types) const throw() {
- c->toStream(out, toDepth, types, language::output::LANG_SMTLIB_V2);
+ int toDepth, bool types, size_t dag) const throw() {
+ c->toStream(out, toDepth, types, dag, language::output::LANG_SMTLIB_V2);
}/* SmtPrinter::toStream() */
void SmtPrinter::toStream(std::ostream& out, const CommandStatus* s) const throw() {
class SmtPrinter : public CVC4::Printer {
public:
- void toStream(std::ostream& out, TNode n, int toDepth, bool types) const throw();
- void toStream(std::ostream& out, const Command* c, int toDepth, bool types) const throw();
+ void toStream(std::ostream& out, TNode n, int toDepth, bool types, size_t dag) const throw();
+ void toStream(std::ostream& out, const Command* c, int toDepth, bool types, size_t dag) const throw();
void toStream(std::ostream& out, const CommandStatus* s) const throw();
};/* class SmtPrinter */
#include <typeinfo>
#include "util/boolean_simplification.h"
+#include "printer/dagification_visitor.h"
+#include "util/node_visitor.h"
using namespace std;
static void printBvParameterizedOp(std::ostream& out, TNode n) throw();
+void Smt2Printer::toStream(std::ostream& out, TNode n,
+ int toDepth, bool types, size_t dag) const throw() {
+ if(dag != 0) {
+ DagificationVisitor dv(dag);
+ NodeVisitor<DagificationVisitor> visitor;
+ visitor.run(dv, n);
+ const theory::SubstitutionMap& lets = dv.getLets();
+ if(!lets.empty()) {
+ out << "(let (";
+ bool first = true;
+ for(theory::SubstitutionMap::const_iterator i = lets.begin();
+ i != lets.end();
+ ++i) {
+ if(!first) {
+ out << ' ';
+ } else {
+ first = false;
+ }
+ out << '(';
+ toStream(out, (*i).second, toDepth, types);
+ out << ' ';
+ toStream(out, (*i).first, toDepth, types);
+ out << ')';
+ }
+ out << ") ";
+ }
+ Node body = dv.getDagifiedBody();
+ toStream(out, body, toDepth, types);
+ if(!lets.empty()) {
+ out << ')';
+ }
+ } else {
+ toStream(out, n, toDepth, types);
+ }
+}
+
void Smt2Printer::toStream(std::ostream& out, TNode n,
int toDepth, bool types) const throw() {
// null
if(types) {
// print the whole type, but not *its* type
out << ":";
- n.getType().toStream(out, -1, false, language::output::LANG_SMTLIB_V2);
+ n.getType().toStream(out, -1, false, 0, language::output::LANG_SMTLIB_V2);
}
return;
if(n.getMetaKind() == kind::metakind::PARAMETERIZED &&
stillNeedToPrintParams) {
if(toDepth != 0) {
- n.getOperator().toStream(out, toDepth < 0 ? toDepth : toDepth - 1,
- types, language::output::LANG_SMTLIB_V2);
+ toStream(out, n.getOperator(), toDepth < 0 ? toDepth : toDepth - 1, types);
} else {
out << "(...)";
}
iend = n.end();
i != iend; ) {
if(toDepth != 0) {
- (*i).toStream(out, toDepth < 0 ? toDepth : toDepth - 1,
- types, language::output::LANG_SMTLIB_V2);
+ toStream(out, *i, toDepth < 0 ? toDepth : toDepth - 1, types);
} else {
out << "(...)";
}
out << ' ';
}
}
- if(n.getNumChildren() != 0) out << ')';
+ if(n.getNumChildren() != 0) {
+ out << ')';
+ }
}/* Smt2Printer::toStream(TNode) */
static string smtKindString(Kind k) throw() {
static bool tryToStream(std::ostream& out, const Command* c) throw();
void Smt2Printer::toStream(std::ostream& out, const Command* c,
- int toDepth, bool types) const throw() {
+ int toDepth, bool types, size_t dag) const throw() {
expr::ExprSetDepth::Scope sdScope(out, toDepth);
expr::ExprPrintTypes::Scope ptScope(out, types);
+ expr::ExprDag::Scope dagScope(out, dag);
if(tryToStream<AssertCommand>(out, c) ||
tryToStream<PushCommand>(out, c) ||
namespace smt2 {
class Smt2Printer : public CVC4::Printer {
-public:
void toStream(std::ostream& out, TNode n, int toDepth, bool types) const throw();
- void toStream(std::ostream& out, const Command* c, int toDepth, bool types) const throw();
+public:
+ void toStream(std::ostream& out, TNode n, int toDepth, bool types, size_t dag) const throw();
+ void toStream(std::ostream& out, const Command* c, int toDepth, bool types, size_t dag) const throw();
void toStream(std::ostream& out, const CommandStatus* s) const throw();
};/* class Smt2Printer */
return d_substitutions.end();
}
+ bool empty() const {
+ return d_substitutions.empty();
+ }
+
// NOTE [MGD]: removed clear() and swap() from the interface
// when this data structure became context-dependent
// because they weren't used---and it's not clear how they
- // should // best interact with cache invalidation on context
+ // should best interact with cache invalidation on context
// pops.
/**
*/
void print(std::ostream& out) const;
-};
+};/* class SubstitutionMap */
inline std::ostream& operator << (std::ostream& out, const SubstitutionMap& subst) {
subst.print(out);
class NodeVisitor {
/** For re-entry checking */
- static CVC4_THREADLOCAL(bool) d_inRun;
+ static CVC4_THREADLOCAL(bool) s_inRun;
class GuardReentry {
bool& d_guard;
*/
static typename Visitor::return_type run(Visitor& visitor, TNode node) {
- GuardReentry guard(bool(d_inRun));
+ GuardReentry guard(bool(s_inRun));
// Notify of a start
visitor.start(node);
};
template <typename Visitor>
-CVC4_THREADLOCAL(bool) NodeVisitor<Visitor>::d_inRun = false;
+CVC4_THREADLOCAL(bool) NodeVisitor<Visitor>::s_inRun = false;
}
--show-trace-tags show all avalable tags for tracing\n\
--show-sat-solvers show all available SAT solvers\n\
--default-expr-depth=N print exprs to depth N (0 == default, -1 == no limit)\n\
+ --default-dag-thresh=N dagify common subexprs appearing > N times\n\
+ (1 == default, 0 == don't dagify)\n\
--print-expr-types print types with variables when printing exprs\n\
--lazy-definition-expansion expand define-funs/LAMBDAs lazily\n\
--simplification=MODE choose simplification mode, see --simplification=help\n\
SHOW_CONFIG,
STRICT_PARSING,
DEFAULT_EXPR_DEPTH,
+ DEFAULT_DAG_THRESH,
PRINT_EXPR_TYPES,
UF_THEORY,
LAZY_DEFINITION_EXPANSION,
{ "mmap" , no_argument , NULL, USE_MMAP },
{ "strict-parsing", no_argument , NULL, STRICT_PARSING },
{ "default-expr-depth", required_argument, NULL, DEFAULT_EXPR_DEPTH },
+ { "default-dag-thresh", required_argument, NULL, DEFAULT_DAG_THRESH },
{ "print-expr-types", no_argument , NULL, PRINT_EXPR_TYPES },
{ "uf" , required_argument, NULL, UF_THEORY },
{ "lazy-definition-expansion", no_argument, NULL, LAZY_DEFINITION_EXPANSION },
}
break;
+ case DEFAULT_DAG_THRESH:
+ {
+ int dag = atoi(optarg);
+ if(dag < 0) {
+ throw OptionException("--default-dag-thresh requires a nonnegative argument.");
+ }
+ Debug.getStream() << Expr::dag(size_t(dag));
+ Trace.getStream() << Expr::dag(size_t(dag));
+ Notice.getStream() << Expr::dag(size_t(dag));
+ Chat.getStream() << Expr::dag(size_t(dag));
+ Message.getStream() << Expr::dag(size_t(dag));
+ Warning.getStream() << Expr::dag(size_t(dag));
+ Dump.getStream() << Expr::dag(size_t(dag));
+ }
+ break;
+
case PRINT_EXPR_TYPES:
Debug.getStream() << Expr::printtypes(true);
Trace.getStream() << Expr::printtypes(true);
Node o = NodeBuilder<>() << n << n << kind::XOR;
stringstream sstr;
+ sstr << Node::dag(false);
n.toStream(sstr);
TS_ASSERT(sstr.str() == "(AND w (OR x y) z)");
sstr.str(string());
- o.toStream(sstr);
+ o.toStream(sstr, -1, false, 0);
TS_ASSERT(sstr.str() == "(XOR (AND w (OR x y) z) (AND w (OR x y) z))");
sstr.str(string());