diff options
Diffstat (limited to 'src')
156 files changed, 4342 insertions, 2370 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index a25cc5e8f..c9f928ba8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,8 +30,8 @@ libcvc4_la_LDFLAGS = -version-info $(LIBCVC4_VERSION) # as a C library, which messes up exception handling support) nodist_EXTRA_libcvc4_noinst_la_SOURCES = dummy.cpp nodist_EXTRA_libcvc4_la_SOURCES = dummy.cpp -libcvc4_noinst_la_SOURCES = subversion_versioninfo.cpp -libcvc4_la_SOURCES = subversion_versioninfo.cpp +libcvc4_noinst_la_SOURCES = git_versioninfo.cpp svn_versioninfo.cpp +libcvc4_la_SOURCES = git_versioninfo.cpp svn_versioninfo.cpp libcvc4_la_LIBADD = \ @builddir@/options/liboptions.la \ @builddir@/util/libutil.la \ @@ -67,9 +67,12 @@ libcvc4_noinst_la_LIBADD += \ endif CLEANFILES = \ - subversion_versioninfo.cpp \ + svn_versioninfo.cpp \ svninfo.tmp \ - svninfo + svninfo \ + git_versioninfo.cpp \ + gitinfo.tmp \ + gitinfo EXTRA_DIST = \ include/cvc4_private_library.h \ @@ -80,7 +83,7 @@ EXTRA_DIST = \ include/cvc4.h \ cvc4.i -subversion_versioninfo.cpp: svninfo +svn_versioninfo.cpp: svninfo $(AM_V_GEN)( \ if test -s svninfo; then \ issvn=true; \ @@ -108,6 +111,34 @@ svninfo: svninfo.tmp svninfo.tmp: $(AM_V_GEN)(cd "$(top_srcdir)" && svn info && echo "Modifications: `test -z \"\`svn status -q\`\" && echo false || echo true`") >"$@" 2>/dev/null || true +git_versioninfo.cpp: gitinfo + $(AM_V_GEN)( \ + if test -s gitinfo; then \ + isgit=true; \ + branch=`head -1 gitinfo`; \ + rev=`head -2 gitinfo | tail -1 | awk '{print$$1}'`; \ + mods=`grep '^Modifications: ' gitinfo | awk '{print$$2} END { if(!NR) print "false" }'`; \ + else \ + isgit=false; \ + branch=unknown; \ + rev=unknown; \ + mods=false; \ + fi; \ + echo "#include \"util/configuration.h\""; \ + echo "const bool ::CVC4::Configuration::IS_GIT_BUILD = $$isgit;"; \ + echo "const char* const ::CVC4::Configuration::GIT_BRANCH_NAME = \"$$branch\";"; \ + echo "const char* const ::CVC4::Configuration::GIT_COMMIT = \"$$rev\";"; \ + echo "const bool ::CVC4::Configuration::GIT_HAS_MODIFICATIONS = $$mods;"; \ + ) >"$@" +# This .tmp business is to keep from having to re-compile options.cpp +# (and then re-link the libraries) if nothing has changed. +gitinfo: gitinfo.tmp + $(AM_V_GEN)diff -q gitinfo.tmp gitinfo &>/dev/null || mv gitinfo.tmp gitinfo || true +# .PHONY ensures the .tmp version is always rebuilt (to check for any changes) +.PHONY: gitinfo.tmp +gitinfo.tmp: + $(AM_V_GEN)(cd "$(top_srcdir)" && sed 's,^ref: refs/heads/,,' .git/HEAD && git show-ref refs/heads/`sed 's,^ref: refs/heads/,,' .git/HEAD` && echo "Modifications: `test -z \"\`git status -s -uno\`\" && echo false || echo true`") >"$@" 2>/dev/null || true + install-data-local: (echo include/cvc4.h; \ echo include/cvc4_public.h; \ diff --git a/src/compat/cvc3_compat.cpp b/src/compat/cvc3_compat.cpp index 4f40fe4e8..0cd35ce0d 100644 --- a/src/compat/cvc3_compat.cpp +++ b/src/compat/cvc3_compat.cpp @@ -1107,23 +1107,38 @@ Type ValidityChecker::tupleType(const std::vector<Type>& types) { } Type ValidityChecker::recordType(const std::string& field, const Type& type) { - Unimplemented("Records not supported by CVC4 yet (sorry!)"); + std::vector< std::pair<std::string, CVC4::Type> > fields; + fields.push_back(std::make_pair(field, (const CVC4::Type&) type)); + return d_em->mkRecordType(CVC4::Record(fields)); } Type ValidityChecker::recordType(const std::string& field0, const Type& type0, const std::string& field1, const Type& type1) { - Unimplemented("Records not supported by CVC4 yet (sorry!)"); + std::vector< std::pair<std::string, CVC4::Type> > fields; + fields.push_back(std::make_pair(field0, (const CVC4::Type&) type0)); + fields.push_back(std::make_pair(field1, (const CVC4::Type&) type1)); + return d_em->mkRecordType(CVC4::Record(fields)); } Type ValidityChecker::recordType(const std::string& field0, const Type& type0, const std::string& field1, const Type& type1, const std::string& field2, const Type& type2) { - Unimplemented("Records not supported by CVC4 yet (sorry!)"); + std::vector< std::pair<std::string, CVC4::Type> > fields; + fields.push_back(std::make_pair(field0, (const CVC4::Type&) type0)); + fields.push_back(std::make_pair(field1, (const CVC4::Type&) type1)); + fields.push_back(std::make_pair(field2, (const CVC4::Type&) type2)); + return d_em->mkRecordType(CVC4::Record(fields)); } Type ValidityChecker::recordType(const std::vector<std::string>& fields, const std::vector<Type>& types) { - Unimplemented("Records not supported by CVC4 yet (sorry!)"); + CVC4::CheckArgument(fields.size() == types.size() && fields.size() > 0, + "invalid vector length(s) in recordType()"); + std::vector< std::pair<std::string, CVC4::Type> > fieldSpecs; + for(unsigned i = 0; i < fields.size(); ++i) { + fieldSpecs.push_back(std::make_pair(fields[i], (const CVC4::Type&) types[i])); + } + return d_em->mkRecordType(CVC4::Record(fieldSpecs)); } Type ValidityChecker::dataType(const std::string& name, @@ -1559,32 +1574,43 @@ Expr ValidityChecker::geExpr(const Expr& left, const Expr& right) { } Expr ValidityChecker::recordExpr(const std::string& field, const Expr& expr) { - Unimplemented("Records not supported by CVC4 yet (sorry!)"); + CVC4::Type t = recordType(field, expr.getType()); + return d_em->mkExpr(CVC4::kind::RECORD, d_em->mkConst(CVC4::RecordType(t).getRecord()), expr); } Expr ValidityChecker::recordExpr(const std::string& field0, const Expr& expr0, const std::string& field1, const Expr& expr1) { - Unimplemented("Records not supported by CVC4 yet (sorry!)"); + CVC4::Type t = recordType(field0, expr0.getType(), + field1, expr1.getType()); + return d_em->mkExpr(CVC4::kind::RECORD, d_em->mkConst(CVC4::RecordType(t).getRecord()), expr0, expr1); } Expr ValidityChecker::recordExpr(const std::string& field0, const Expr& expr0, const std::string& field1, const Expr& expr1, const std::string& field2, const Expr& expr2) { - Unimplemented("Records not supported by CVC4 yet (sorry!)"); + CVC4::Type t = recordType(field0, expr0.getType(), + field1, expr1.getType(), + field2, expr2.getType()); + return d_em->mkExpr(CVC4::kind::RECORD, d_em->mkConst(CVC4::RecordType(t).getRecord()), expr0, expr1, expr2); } Expr ValidityChecker::recordExpr(const std::vector<std::string>& fields, const std::vector<Expr>& exprs) { - Unimplemented("Records not supported by CVC4 yet (sorry!)"); + std::vector<Type> types; + for(unsigned i = 0; i < exprs.size(); ++i) { + types.push_back(exprs[i].getType()); + } + CVC4::Type t = recordType(fields, types); + return d_em->mkExpr(d_em->mkConst(CVC4::RecordType(t).getRecord()), *reinterpret_cast<const vector<CVC4::Expr>*>(&exprs)); } Expr ValidityChecker::recSelectExpr(const Expr& record, const std::string& field) { - Unimplemented("Records not supported by CVC4 yet (sorry!)"); + return d_em->mkExpr(d_em->mkConst(CVC4::RecordSelect(field)), record); } Expr ValidityChecker::recUpdateExpr(const Expr& record, const std::string& field, const Expr& newValue) { - Unimplemented("Records not supported by CVC4 yet (sorry!)"); + return d_em->mkExpr(d_em->mkConst(CVC4::RecordUpdate(field)), record, newValue); } Expr ValidityChecker::readExpr(const Expr& array, const Expr& index) { @@ -1935,12 +1961,16 @@ Expr ValidityChecker::tupleExpr(const std::vector<Expr>& exprs) { } Expr ValidityChecker::tupleSelectExpr(const Expr& tuple, int index) { - Unimplemented("Tuples not supported by CVC4 yet (sorry!)"); + CVC4::CheckArgument(index >= 0 && index < tuple.getNumChildren(), + "invalid index in tuple select"); + return d_em->mkExpr(d_em->mkConst(CVC4::TupleSelect(index)), tuple); } Expr ValidityChecker::tupleUpdateExpr(const Expr& tuple, int index, const Expr& newValue) { - Unimplemented("Tuples not supported by CVC4 yet (sorry!)"); + CVC4::CheckArgument(index >= 0 && index < tuple.getNumChildren(), + "invalid index in tuple update"); + return d_em->mkExpr(d_em->mkConst(CVC4::TupleUpdate(index)), tuple, newValue); } Expr ValidityChecker::datatypeConsExpr(const std::string& constructor, const std::vector<Expr>& args) { diff --git a/src/context/Makefile.am b/src/context/Makefile.am index e7f1dc68b..a63c990cc 100644 --- a/src/context/Makefile.am +++ b/src/context/Makefile.am @@ -16,6 +16,10 @@ libcontext_la_SOURCES = \ cdlist_forward.h \ cdqueue.h \ cdtrail_queue.h \ + cdtrail_hashmap.h \ + cdtrail_hashmap_forward.h \ + cdinsert_hashmap.h \ + cdinsert_hashmap_forward.h \ cdhashmap.h \ cdhashmap_forward.h \ cdhashset.h \ diff --git a/src/context/cdhashmap.h b/src/context/cdhashmap.h index a37fd2f23..e2ede0603 100644 --- a/src/context/cdhashmap.h +++ b/src/context/cdhashmap.h @@ -17,14 +17,19 @@ ** and operator== for the key class. For key types that don't have a ** __gnu_cxx::hash<>, you should provide an explicit HashFcn. ** + ** See also: + ** CDInsertHashMap : An "insert-once" CD hash map. + ** CDTrailHashMap : A lightweight CD hash map with poor iteration + ** characteristics and some quirks in usage. + ** ** Internal documentation: ** - ** CDMap<> is something of a work in progress at present (26 May + ** CDHashMap<> is something of a work in progress at present (26 May ** 2010), due to some recent discoveries of problems with its ** internal state. Here are some notes on the internal use of ** CDOhash_maps that may be useful in figuring out this mess: ** - ** So you have a CDMap<>. + ** So you have a CDHashMap<>. ** ** You insert some (key,value) pairs. Each allocates a CDOhash_map<> ** and goes on a doubly-linked list headed by map.d_first and @@ -36,7 +41,7 @@ ** map pointer at level 0, and a non-NULL map pointer in the ** current context level. (Remember that for later.) ** - ** When a key is associated to a new value in a CDMap, its + ** When a key is associated to a new value in a CDHashMap, its ** associated CDOhash_map calls makeCurrent(), then sets the new ** value. The save object is also a CDOhash_map (allocated in context ** memory). @@ -62,21 +67,21 @@ ** obliterate() removes it from the map and frees the CDOhash_map's ** memory. ** - ** Fourth, you might delete the cdhashmap(calling CDMap::~CDMap()). + ** Fourth, you might delete the cdhashmap(calling CDHashMap::~CDHashMap()). ** This first calls destroy(), as per ContextObj contract, but ** cdhashmapdoesn't save/restore itself, so that does nothing at the - ** CDMap-level. Then it empties the trash. Then, for each + ** CDHashMap-level. Then it empties the trash. Then, for each ** element in the map, it marks it as being "part of a complete ** map destruction", which essentially short-circuits ** CDOhash_map::restore() (see CDOhash_map::restore()), then deallocates ** it. Finally it asserts that the trash is empty (which it ** should be, since restore() was short-circuited). ** - ** Fifth, you might clear() the CDMap. This does exactly the - ** same as CDMap::~CDMap(), except that it doesn't call destroy() + ** Fifth, you might clear() the CDHashMap. This does exactly the + ** same as CDHashMap::~CDHashMap(), except that it doesn't call destroy() ** on itself. ** - ** CDMap::emptyTrash() simply goes through and calls + ** CDHashMap::emptyTrash() simply goes through and calls ** ->deleteSelf() on all elements in the trash. ** ContextObj::deleteSelf() calls the CDOhash_map destructor, then ** frees the memory associated to the CDOhash_map. CDOhash_map::~CDOhash_map() @@ -87,8 +92,8 @@ #include "cvc4_private.h" -#ifndef __CVC4__CONTEXT__CDMAP_H -#define __CVC4__CONTEXT__CDMAP_H +#ifndef __CVC4__CONTEXT__CDHASHMAP_H +#define __CVC4__CONTEXT__CDHASHMAP_H #include <vector> #include <iterator> @@ -148,9 +153,9 @@ class CDOhash_map : public ContextObj { d_next->d_prev = d_prev; d_prev->d_next = d_next; if(d_noTrash) { - Debug("gc") << "CDMap<> no-trash " << this << std::endl; + Debug("gc") << "CDHashMap<> no-trash " << this << std::endl; } else { - Debug("gc") << "CDMap<> trash push_back " << this << std::endl; + Debug("gc") << "CDHashMap<> trash push_back " << this << std::endl; //this->deleteSelf(); d_map->d_trash.push_back(this); } @@ -190,7 +195,7 @@ public: // "Initializing" map insertion: this entry will never be // removed from the map, it's inserted at level 0 as an // "initializing" element. See - // CDMap<>::insertAtContextLevelZero(). + // CDHashMap<>::insertAtContextLevelZero(). d_data = data; } else { // Normal map insertion: first makeCurrent(), then set the data @@ -417,7 +422,7 @@ public: } /** - * Version of insert() for CDMap<> that inserts data value d at + * Version of insert() for CDHashMap<> that inserts data value d at * context level zero. This is a special escape hatch for inserting * "initializing" data into the map. Imagine something happens at a * deep context level L that causes insertion into a map, such that @@ -538,7 +543,7 @@ public: const std::pair<const Key, Data>& operator*() const { return *d_pair; } - };/* class CDMap<>::iterator::Proxy */ + };/* class CDHashMap<>::iterator::Proxy */ // Actual postfix increment: returns Proxy with the old value. // Now, an expression like *i++ will return the current *i, and @@ -549,7 +554,7 @@ public: ++(*this); return e; } - };/* class CDMap<>::iterator */ + };/* class CDHashMap<>::iterator */ typedef iterator const_iterator; @@ -576,9 +581,9 @@ public: return const_cast<const CDHashMap*>(this)->find(k); } -};/* class CDMap<> */ +};/* class CDHashMap<> */ }/* CVC4::context namespace */ }/* CVC4 namespace */ -#endif /* __CVC4__CONTEXT__CDMAP_H */ +#endif /* __CVC4__CONTEXT__CDHashMAP_H */ diff --git a/src/context/cdhashmap_forward.h b/src/context/cdhashmap_forward.h index d81f5345d..60291af07 100644 --- a/src/context/cdhashmap_forward.h +++ b/src/context/cdhashmap_forward.h @@ -9,22 +9,22 @@ ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** - ** \brief This is a forward declaration header to declare the CDMap<> + ** \brief This is a forward declaration header to declare the CDHashMap<> ** template ** - ** This is a forward declaration header to declare the CDMap<> - ** template. It's useful if you want to forward-declare CDMap<> - ** without including the full cdmap.h header, for example, in a + ** This is a forward declaration header to declare the CDHashMap<> + ** template. It's useful if you want to forward-declare CDHashMap<> + ** without including the full cdhashmap.h header, for example, in a ** public header context. ** - ** For CDMap<> in particular, it's difficult to forward-declare it + ** For CDHashMap<> in particular, it's difficult to forward-declare it ** yourself, because it has a default template argument. **/ #include "cvc4_public.h" -#ifndef __CVC4__CONTEXT__CDMAP_FORWARD_H -#define __CVC4__CONTEXT__CDMAP_FORWARD_H +#ifndef __CVC4__CONTEXT__CDHASHMAP_FORWARD_H +#define __CVC4__CONTEXT__CDHASHMAP_FORWARD_H /// \cond internals @@ -41,4 +41,4 @@ namespace CVC4 { /// \endcond -#endif /* __CVC4__CONTEXT__CDMAP_FORWARD_H */ +#endif /* __CVC4__CONTEXT__CDHASHMAP_FORWARD_H */ diff --git a/src/context/cdhashset.h b/src/context/cdhashset.h index e885b7729..d7957cf3f 100644 --- a/src/context/cdhashset.h +++ b/src/context/cdhashset.h @@ -20,16 +20,15 @@ #define __CVC4__CONTEXT__CDSET_H #include "context/context.h" -#include "context/cdhashset_forward.h" -#include "context/cdhashmap.h" +#include "context/cdinsert_hashmap.h" #include "util/cvc4_assert.h" namespace CVC4 { namespace context { template <class V, class HashFcn> -class CDHashSet : protected CDHashMap<V, V, HashFcn> { - typedef CDHashMap<V, V, HashFcn> super; +class CDHashSet : protected CDInsertHashMap<V, bool, HashFcn> { + typedef CDInsertHashMap<V, bool, HashFcn> super; public: @@ -58,40 +57,30 @@ public: return super::size(); } - size_t count(const V& v) const { - return super::count(v); - } - bool insert(const V& v) { - return super::insert(v, v); - } - - void insertAtContextLevelZero(const V& v) { - return super::insertAtContextLevelZero(v, v); + return super::insert_safe(v, true); } bool contains(const V& v) { - return find(v) != end(); + return super::contains(v); } - // FIXME: no erase(), too much hassle to implement efficiently... - - class iterator { - typename super::iterator d_it; + class const_iterator { + typename super::const_iterator d_it; public: - iterator(const typename super::iterator& it) : d_it(it) {} - iterator(const iterator& it) : d_it(it.d_it) {} + const_iterator(const typename super::const_iterator& it) : d_it(it) {} + const_iterator(const const_iterator& it) : d_it(it.d_it) {} // Default constructor - iterator() {} + const_iterator() {} // (Dis)equality - bool operator==(const iterator& i) const { + bool operator==(const const_iterator& i) const { return d_it == i.d_it; } - bool operator!=(const iterator& i) const { + bool operator!=(const const_iterator& i) const { return d_it != i.d_it; } @@ -101,7 +90,7 @@ public: } // Prefix increment - iterator& operator++() { + const_iterator& operator++() { ++d_it; return *this; } @@ -131,18 +120,28 @@ public: } };/* class CDSet<>::iterator */ - typedef iterator const_iterator; - const_iterator begin() const { - return iterator(super::begin()); + return const_iterator(super::begin()); } const_iterator end() const { - return iterator(super::end()); + return const_iterator(super::end()); } const_iterator find(const V& v) const { - return iterator(super::find(v)); + return const_iterator(super::find(v)); + } + + typedef typename super::key_iterator key_iterator; + key_iterator key_begin() const { + return super::key_begin(); + } + key_iterator key_end() const { + return super::key_end(); + } + + void insertAtContextLevelZero(const V& v) { + return super::insertAtContextLevelZero(v, true); } };/* class CDSet */ diff --git a/src/context/cdinsert_hashmap.h b/src/context/cdinsert_hashmap.h new file mode 100644 index 000000000..74e2fcf28 --- /dev/null +++ b/src/context/cdinsert_hashmap.h @@ -0,0 +1,402 @@ +/********************* */ +/*! \file cdinsert_hashmap.h + ** \verbatim + ** Original author: taking + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Context-dependent insert only hashmap built using trail of edits + ** + ** Context-dependent hashmap that only allows for one insertion per element. + ** This can be viewed as a highly restricted version of CDHashMap. + ** It is significantly lighter in memory usage than CDHashMap. + ** + ** See also: + ** CDTrailHashMap : A lightweight CD hash map with poor iteration + ** characteristics and some quirks in usage. + ** CDHashMap : A fully featured CD hash map. (The closest to <ext/hash_map>) + ** + ** Notes: + ** - To iterate efficiently over the elements use the key_iterators. + ** - operator[] is only supported as a const derefence (must succeed). + ** - insert(k) must always work. + ** - Use insert_safe if you want to check if the element has been inserted + ** and only insert if it has not yet been. + ** - Does not accept TNodes as keys. + ** - Supports insertAtContextLevelZero() if the element is not in the map. + **/ + + +#include "cvc4_private.h" + +#include "context/context.h" +#include "context/cdinsert_hashmap_forward.h" +#include <utility> +#include <ext/hash_map> +#include <deque> +#include "util/cvc4_assert.h" +#include "util/output.h" + +#include "expr/node.h" +#include <boost/static_assert.hpp> + +#pragma once + +namespace CVC4 { +namespace context { + + +template <class Key, class Data, class HashFcn = __gnu_cxx::hash<Key> > +class InsertHashMap { +private: + typedef std::deque<Key> KeyVec; + /** A list of the keys in the map maintained as a stack. */ + KeyVec d_keys; + + typedef __gnu_cxx::hash_map<Key, Data, HashFcn> HashMap; + /** The hash_map used for element lookup. */ + HashMap d_hashMap; + +public: + /** + * An iterator over a list of keys. + * Use this to efficiently iterate over the elements. + * (See std::deque<>::iterator). + */ + typedef typename KeyVec::const_iterator key_iterator; + + /**An iterator over the elements in the hash_map. */ + typedef typename HashMap::const_iterator const_iterator; + + + /** + * Returns an iterator to the begining of the HashMap. + * Acts like a hash_map::const_iterator. + */ + const_iterator begin() const{ + return d_hashMap.begin(); + } + /** + * Returns an iterator to the end of the HashMap. + * Acts like a hash_map::const_iterator. + */ + const_iterator end() const{ + return d_hashMap.end(); + } + + /** + * Returns an iterator to the Key k of the map. + * See hash_map::find() + */ + const_iterator find(const Key& k) const{ + return d_hashMap.find(k); + } + + /** Returns an iterator to the start of the set of keys. */ + key_iterator key_begin() const{ + return d_keys.begin(); + } + /** Returns an iterator to the end of the set of keys. */ + key_iterator key_end() const{ + return d_keys.end(); + } + + /** Returns true if the map is empty. */ + bool empty() const { return d_keys.empty(); } + /** Returns the number of elements in the map. */ + size_t size() const { return d_keys.size(); } + + /** Returns true if k is a mapped key. */ + bool contains(const Key& k) const { + return find(k) != end(); + } + + /** + * Returns a reference the data mapped by k. + * This must succeed. + */ + const Data& operator[](const Key& k) const { + const_iterator ci = find(k); + Assert(ci != end()); + return (*ci).second; + } + + /** + * Inserts an element into the map, and pushes its key to the front + * of the stack. The key inserted must be not be currently mapped. + */ + void push_front(const Key& k, const Data& d){ + Assert(!contains(k)); + d_hashMap.insert(std::make_pair(k, d)); + d_keys.push_front(k); + } + + /** + * Inserts an element into the map, and pushes its key onto the + * back on the stack. The key inserted must be not be currently mapped. + */ + void push_back(const Key& k, const Data& d){ + Assert(!contains(k)); + d_hashMap.insert(std::make_pair(k, d)); + d_keys.push_back(k); + } + + /** + * Pops the key at the front of the list off and removes its key from the map. + */ + void pop_front(){ + Assert(!empty()); + const Key& front = d_keys.front(); + d_hashMap.erase(front); + + Debug("TrailHashMap") <<"TrailHashMap pop_front " << size() << std::endl; + d_keys.pop_front(); + } + + /** + * Pops the key at the back of the stack off and removes its key from the map. + */ + void pop_back(){ + Assert(!empty()); + const Key& back = d_keys.back(); + d_hashMap.erase(back); + + Debug("TrailHashMap") <<"TrailHashMap pop_back " << size() << std::endl; + d_keys.pop_back(); + } + + /** + * Pops the back of the stack until the size is below s. + */ + void pop_to_size(size_t s){ + while(size() > s){ + pop_back(); + } + } +};/* class TrailHashMap<> */ + +template <class Key, class Data, class HashFcn > +class CDInsertHashMap : public ContextObj { +private: + typedef InsertHashMap<Key, Data, HashFcn> IHM; + + /** An InsertHashMap that backs all of the data. */ + IHM* d_insertMap; + + /** For restores, we need to keep track of the previous size. */ + size_t d_size; + + /** + * To support insertAtContextLevelZero() and restores, + * we have called d_insertMap->d_pushFront(). + */ + size_t d_pushFronts; + + /** + * Private copy constructor used only by save(). d_insertMap is + * not copied: only the base class information and + * d_size and d_pushFronts are needed in restore. + */ + CDInsertHashMap(const CDInsertHashMap<Key, Data, HashFcn>& l) : + ContextObj(l), + d_insertMap(NULL), + d_size(l.d_size), + d_pushFronts(l.d_pushFronts) + { + Debug("CDInsertHashMap") << "copy ctor: " << this + << " from " << &l + << " size " << d_size << std::endl; + } + + /** + * Implementation of mandatory ContextObj method save: simply copies + * the current size information to a copy using the copy constructor (the + * pointer and the allocated size are *not* copied as they are not + * restored on a pop). The saved information is allocated using the + * ContextMemoryManager. + */ + ContextObj* save(ContextMemoryManager* pCMM) { + ContextObj* data = new(pCMM) CDInsertHashMap<Key, Data, HashFcn>(*this); + Debug("CDInsertHashMap") << "save " << this + << " at level " << this->getContext()->getLevel() + << " size at " << this->d_size + << " d_list is " << this->d_insertMap + << " data:" << data << std::endl; + return data; + } +protected: + /** + * Implementation of mandatory ContextObj method restore: + * restore to the previous size taking into account the number + * of new pushFront calls have happened since saving. + * The d_insertMap is untouched and d_pushFronts is also kept. + */ + void restore(ContextObj* data) { + Debug("CDInsertHashMap") << "restore " << this + << " level " << this->getContext()->getLevel() + << " data == " << data + << " d_insertMap == " << this->d_insertMap << std::endl; + size_t oldSize = ((CDInsertHashMap<Key, Data, HashFcn>*)data)->d_size; + size_t oldPushFronts = ((CDInsertHashMap<Key, Data, HashFcn>*)data)->d_pushFronts; + Assert(oldPushFronts <= d_pushFronts); + + // The size to restore to. + size_t restoreSize = oldSize + (d_pushFronts - oldPushFronts); + d_insertMap->pop_to_size(restoreSize); + d_size = restoreSize; + Assert(d_insertMap->size() == d_size); + Debug("CDInsertHashMap") << "restore " << this + << " level " << this->getContext()->getLevel() + << " size back to " << this->d_size << std::endl; + } +public: + + /** + * Main constructor: d_insertMap starts as an empty map, with the size is 0 + */ + CDInsertHashMap(Context* context) : + ContextObj(context), + d_insertMap(new IHM()), + d_size(0), + d_pushFronts(0){ + Assert(d_insertMap->size() == d_size); + } + + /** + * Destructor: delete the d_insertMap + */ + ~CDInsertHashMap() throw(AssertionException) { + this->destroy(); + delete d_insertMap; + } + + /** An iterator over the elements in the hash_map. */ + typedef typename IHM::const_iterator const_iterator; + + /** + * An iterator over a list of keys. + * Use this to efficiently iterate over the elements. + * (See std::deque<>::iterator). + */ + typedef typename IHM::key_iterator key_iterator; + + /** Returns true if the map is empty in the current context. */ + bool empty() const{ + return d_size == 0; + } + + /** Returns true the size of the map in the current context. */ + size_t size() const { + return d_size; + } + + /** + * Inserts an element into the map. + * The key inserted must be not be currently mapped. + * This is implemented using d_insertMap.push_back(). + */ + void insert(const Key& k, const Data& d){ + makeCurrent(); + ++d_size; + d_insertMap->push_back(k, d); + Assert(d_insertMap->size() == d_size); + } + + /** + * Checks if the key k is mapped already. + * If it is, this returns false. + * Otherwise it is inserted and this returns true. + */ + bool insert_safe(const Key& k, const Data& d){ + if(contains(k)){ + return false; + }else{ + insert(k,d); + return true; + } + } + + /** + * Version of insert() for CDMap<> that inserts data value d at + * context level zero. + * + * It is an error to insertAtContextLevelZero() + * a key that already is in the map. + */ + void insertAtContextLevelZero(const Key& k, const Data& d){ + makeCurrent(); + ++d_size; + ++d_pushFronts; + d_insertMap->push_front(k, d); + } + + /** Returns true if k is a mapped key in the context. */ + bool contains(const Key& k) const { + return d_insertMap->contains(k); + } + + /** + * Returns a reference the data mapped by k. + * k must be in the map in this context. + */ + const Data& operator[](const Key& k) const { + return (*d_insertMap)[k]; + } + + /** + * Returns a const_iterator to the value_type if k is a mapped key in + * the context. + */ + const_iterator find(const Key& k) const { + return d_insertMap->find(k); + } + + /** + * Returns an iterator to the begining of the map. + * Acts like a hash_map::const_iterator. + */ + const_iterator begin() const{ + return d_insertMap->begin(); + } + + /** + * Returns an iterator to the end of the map. + * Acts like a hash_map::const_iterator. + */ + const_iterator end() const{ + return d_insertMap->end(); + } + + /** Returns an iterator to the start of the set of keys. */ + key_iterator key_begin() const{ + return d_insertMap->key_begin(); + } + /** Returns an iterator to the end of the set of keys. */ + key_iterator key_end() const{ + return d_insertMap->key_end(); + } +};/* class CDInsertHashMap<> */ + + +template <class Data, class HashFcn> +class CDInsertHashMap <TNode, Data, HashFcn > : public ContextObj { + /* CDInsertHashMap is challenging to get working with TNode. + * Consider using CDHashMap<TNode,...> instead. + * + * Explanation: + * CDInsertHashMap uses keys for deallocation. + * If the key is a TNode and the backing (the hard node reference) + * for the key in another data structure removes the key at the same context + * the ref count could drop to 0. The key would then not be eligible to be + * hashed. Getting the order right with a guarantee is too hard. + */ + + BOOST_STATIC_ASSERT(sizeof(Data) == 0); +}; + +}/* CVC4::context namespace */ +}/* CVC4 namespace */ diff --git a/src/context/cdinsert_hashmap_forward.h b/src/context/cdinsert_hashmap_forward.h new file mode 100644 index 000000000..638607840 --- /dev/null +++ b/src/context/cdinsert_hashmap_forward.h @@ -0,0 +1,38 @@ +/********************* */ +/*! \file cdinsert_hashmap_forward.h + ** \verbatim + ** Original author: taking + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief This is a forward declaration header to declare the CDInsertHashMap<> + ** template + ** + ** This is a forward declaration header to declare the CDInsertHashMap<> + ** template. It's useful if you want to forward-declare CDInsertHashMap<> + ** without including the full cdinsert_hashmap.h header, for example, in a + ** public header context. + ** + ** For CDInsertHashMap<> in particular, it's difficult to forward-declare it + ** yourself, because it has a default template argument. + **/ + +#include "cvc4_public.h" + +#pragma once + +namespace __gnu_cxx { + template <class Key> struct hash; +}/* __gnu_cxx namespace */ + +namespace CVC4 { + namespace context { + template <class Key, class Data, class HashFcn = __gnu_cxx::hash<Key> > + class CDInsertHashMap; + }/* CVC4::context namespace */ +}/* CVC4 namespace */ + diff --git a/src/context/cdtrail_hashmap.h b/src/context/cdtrail_hashmap.h new file mode 100644 index 000000000..2d2020a16 --- /dev/null +++ b/src/context/cdtrail_hashmap.h @@ -0,0 +1,571 @@ +/********************* */ +/*! \file cdtrail_hashmap.h + ** \verbatim + ** Original author: taking + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Context-dependent hashmap built using trail of elements + ** + ** Context-dependent hashmap that explicitly keeps track of its edit history. + ** This is similar in functionality to CDHashMap with fewer capabilites and + ** slight changes in the interface. It has the advantage of being lighter in + ** memory usage. + ** + ** See also: + ** CDInsertHashMap : An "insert-once" CD hash map. + ** CDHashMap : A fully featured CD hash map. (The closest to <ext/hash_map>) + ** + ** Notes: + ** - To iterate efficiently over the elements use the key_iterators. + ** - operator[] is only supported as a const derefence (must succeed). + ** - Insertions to the map are done with respect to a context. + ** - Insertions can be done in two manors either with insert() or + ** insert_no_overwrite(). + ** - insert(k,d) inserts the key data pair into the hashtable and returns a + ** false if it overwrote the previous value. + ** - insert_no_overwrite(k,d) inserts key data pair into the hashtable only + ** if the value is not already there. It returns true, if an element was + ** added. This conditionally extends the trail length if it returns true. + ** - inserts are compacting. If there is another insert to the same key + ** at the same context, the memory is reused. + ** - Iterating over const_iterators has amortized time proportional to + ** O(trail length). (If this needs to be improved, please bug Tim.) + ** - contains() and operator[] are slightly faster than using stl style + ** iterator comparisons: find(), end(), etc. + **/ + + +#include "cvc4_private.h" + +#pragma once + +#include "context/context.h" +#include "context/cdtrail_hashmap_forward.h" +#include <utility> +#include <ext/hash_map> +#include <deque> +#include "util/cvc4_assert.h" +#include "util/output.h" + +#include "expr/node.h" +#include <boost/static_assert.hpp> + + +namespace CVC4 { +namespace context { + + +template <class Key, class Data, class HashFcn = __gnu_cxx::hash<Key> > +class TrailHashMap { +public: + /** A pair of Key and Data that mirrors hash_map::value_type. */ + typedef std::pair<Key, Data> value_type; + +private: + + /** The trail information from an insert. */ + struct KDT { + /** The Key Data pair. */ + value_type d_kd; + + /** + * The previous trail entry with the same key. + * On a pop, this is the element to revert to. + * This value is a self loop if there is no previous entry. + */ + size_t d_prevKey; + + /** The whether the trail element is current. */ + bool d_current; + + KDT(const Key& key, const Data& data, size_t prev, bool cur = true): + d_kd(std::make_pair(key, data)), d_prevKey(prev), d_current(cur){ } + KDT(){} + }; + + typedef std::deque<KDT> KDTVec; + typedef typename KDTVec::const_iterator KDTVec_const_iterator; + /** The trail of elements. */ + KDTVec d_kdts; + + + typedef __gnu_cxx::hash_map<Key, size_t, HashFcn> PositionMap; + typedef typename PositionMap::iterator PM_iterator; + typedef typename PositionMap::const_iterator PM_const_iterator; + + /** A map of keys to their positions in the trail. */ + PositionMap d_posMap; + + + /** The number of unique keys in the map. */ + size_t d_uniqueKeys; + + /** Internal utility class. NonConstant find on the position map.*/ + inline PM_iterator ncfind(const Key& k) { + return d_posMap.find(k); + } + + /** Internal utility class. Position Map Find.*/ + inline PM_const_iterator pmfind(const Key& k) const{ + return d_posMap.find(k); + } + /** Internal utility class. Position Map End.*/ + inline PM_const_iterator pmend() const{ + return d_posMap.end(); + } + + /** This is true if the previous entry in the trail points at itself.*/ + inline bool selfLoop(size_t pos, const KDT& kdt) const { + return pos == kdt.d_prevKey; + } + +public: + /** + * Constant iterator for TrailHashMap. + * Only supports forward iteration. + * This always points at the end or a current element in the trail. + * This is done by iterating over the trail. + */ + class const_iterator { + private: + /** A vector iterator. */ + KDTVec_const_iterator d_it; + + /** A pointer to the end of the vector.*/ + KDTVec_const_iterator d_end; + + /** Move the iterator to the end or the next current element.*/ + void findCurrent(){ + while(d_it != d_end && !(*d_it).d_current){ + ++d_it; + } + } + + public: + + /** Constructs an iterator for a TrailHashMap. */ + const_iterator(KDTVec_const_iterator it, KDTVec_const_iterator end) : + d_it(it), + d_end(end){ + findCurrent(); + } + + /** Copy constructor for an iterator for a TrailHashMap. */ + const_iterator(const const_iterator& other) : + d_it(other.d_it), d_end(other.d_end){ + // Do not need to findCurrent() + } + + /** Returns true if the iterators are the same. */ + inline bool operator==(const const_iterator& other) const { + return d_it == other.d_it; + } + + /** Returns true if the iterators are the same. */ + inline bool operator!=(const const_iterator& other) const { + return d_it != other.d_it; + } + + /** Returns a pair<Key,Data>. */ + inline const value_type& operator*() const { + return (*d_it).d_kd; + } + + /** Prefix increment */ + const_iterator& operator++() { + ++d_it; + findCurrent(); + return *this; + } + }; + + /** Returns a beginning iterator.*/ + inline const_iterator begin() const{ + return const_iterator(d_kdts.begin(), d_kdts.end()); + } + + /** Returns an end iterator.*/ + inline const_iterator end() const{ + return const_iterator(d_kdts.end(), d_kdts.end()); + } + + /** Returns true if the trail is empty.*/ + inline bool empty() const { return d_kdts.empty(); } + + /** Returns the size of the trail.*/ + inline size_t trailSize() const { return d_kdts.size(); } + + /** Returns the number of unique keys in the map.*/ + inline size_t uniqueKeys() const { return d_uniqueKeys; } + + /** Returns true if the key is in the map.*/ + inline bool contains(const Key& k) const { + return pmfind(k) != pmend(); + } + + /** + * Returns a NON const reference to an element in the Map. + * k must be a key in the Map. + * DO NOT USE THIS UNLESS YOU ARE CONFIDENT THE CHANGES MAKE SENSE. + */ + Data& lookup(const Key& k){ + Assert(contains(k)); + PM_iterator ci = ncfind(k); + KDT& kdt = d_kdts[(*ci).second]; + return kdt.d_kd.second; + } + + /** + * Returns a const reference to an element mapped by a Key k. + * k must be a key in the Map. + */ + const Data& operator[](const Key& k) const { + PM_const_iterator pci = pmfind(k); + Assert(pci != pmend()); + return d_kdts[(*pci).second].d_kd.second; + } + + /** + * If the key k is in the map, this returns a const_iterator pointing at this + * element. Otherwise, this returns end(). + */ + const_iterator find(const Key& k) const { + PM_const_iterator pci = pmfind(k); + if(pci == pmend()){ + return end(); + }else{ + size_t pos = (*pci).second; + return const_iterator(d_kdts.begin() + pos, d_kdts.end()); + } + } + + /** + * Similar to contains, but includes a notion of trail position. + * Returns <true, true> if contains(k) and the current position of k + * in the map is greater than or equal to pos. + * Returns <true, false> if it contains(k) but not the previous condition. + * Returns <false, false> if it does not contains(k). + */ + std::pair<bool, bool> hasAfter(const Key& k, size_t pos) { + PM_iterator it = ncfind(k); + if(it != d_posMap.end()){ + return std::make_pair(true, (*it).second >= pos ); + } + return std::make_pair(false, false); + } + + /** + * Inserts an element unconditionally. + * Always increases the trail size. + * Returns true if the key count increased. + */ + bool push_back(const Key& k, const Data& d){ + std::pair<bool, bool> res = compacting_push_back(k, d, trailSize()); + return res.first; + } + + /** + * This inserts an element into the trail. + * This insert can reuse the same trail element if the postion of the element + * is >= threshold. + * + * Return values: + * If pair<bool, bool> res = compacting_push_back(..), + * then res.first is true if this is a new unique key, and + * res.second is true if the trail length increased. + * + */ + std::pair<bool, bool> compacting_push_back(const Key& k, const Data& d, size_t threshold){ + size_t backPos = d_kdts.size(); + std::pair<PM_iterator, bool> res = d_posMap.insert(std::make_pair(k, backPos)); + if(!res.second){ + size_t& prevPosInPM = (*res.first).second; + + Assert(d_kdts[prevPosInPM].d_current); + + if(prevPosInPM < threshold){ + d_kdts.push_back(KDT(k,d, prevPosInPM)); + d_kdts[prevPosInPM].d_current = false; + prevPosInPM = backPos; + + return std::make_pair(false, true); + }else{ + d_kdts[prevPosInPM].d_kd.second = d; + return std::make_pair(false, false); + } + }else{ + d_kdts.push_back(KDT(k,d, backPos)); + ++d_uniqueKeys; + return std::make_pair(true, true); + } + } + + /** + * Inserts an element if the key is not already in the map. + * Returns true if the element was inserted. + */ + bool insert_no_overwrite(const Key& k, const Data& d){ + size_t backPos = d_kdts.size(); + std::pair<PM_iterator, bool> res = d_posMap.insert(std::make_pair(k, backPos)); + if(res.second){ + d_kdts.push_back(KDT(k,d, backPos)); + ++d_uniqueKeys; + } + Debug("TrailHashMap") <<"TrailHashMap insert" << k << " d " << d << " " << backPos << std::endl; + return res.second; + } + + /** Pops the element at the back of the trail. */ + void pop_back(){ + Assert(!empty()); + const KDT& back = d_kdts.back(); + const Key& k = back.d_kd.first; + if(selfLoop(trailSize()-1, back)){ + d_posMap.erase(k); + --d_uniqueKeys; + Debug("TrailHashMap") <<"TrailHashMap pop_back erase " << trailSize() <<" " << std::endl; + + }else{ + Debug("TrailHashMap") <<"TrailHashMap reset " << trailSize() <<" " << " " << back.d_prevKey << std::endl; + d_posMap[k] = back.d_prevKey; + d_kdts[back.d_prevKey].d_current = true; + } + d_kdts.pop_back(); + } + + /** Pops the element at the back of the trail until the trailSize is <= s. */ + void pop_to_size(size_t s){ + while(trailSize() > s){ + pop_back(); + } + } +};/* class TrailHashMap<> */ + +template <class Key, class Data, class HashFcn > +class CDTrailHashMap : public ContextObj { +private: + /** A short name for the templatized TrailMap that backs the CDTrailMap. */ + typedef TrailHashMap<Key, Data, HashFcn> THM; + + /** The trail map that backs the CDTrailMap. */ + THM* d_trailMap; +public: + /** Iterator for the CDTrailHashMap. */ + typedef typename THM::const_iterator const_iterator; + + /** Return value of operator* on a const_iterator (pair<Key,Data>).*/ + typedef typename THM::value_type value_type; + +private: + /** + * The length of the trail in the current context. + * This is used to support reverting. + */ + size_t d_trailSize; + + /** + * The length of the trail immediately after the previous makeCurrent(). + * This is used to support compacting inserts. + */ + size_t d_prevTrailSize; + + /** + * Private copy constructor used only by save(). d_trailMap is not copied: + * only the base class information, d_trailSize, and d_prevTrailSize + * are needed in restore. + */ + CDTrailHashMap(const CDTrailHashMap<Key, Data, HashFcn>& l) : + ContextObj(l), + d_trailMap(NULL), + d_trailSize(l.d_trailSize), + d_prevTrailSize(l.d_prevTrailSize){ + Debug("CDTrailHashMap") << "copy ctor: " << this + << " from " << &l + << " size " << d_trailSize << std::endl; + } + + /** + * Implementation of mandatory ContextObj method save: simply copies + * the current sizes to a copy using the copy constructor, + * The saved information is allocated using the ContextMemoryManager. + */ + ContextObj* save(ContextMemoryManager* pCMM) { + ContextObj* data = new(pCMM) CDTrailHashMap<Key, Data, HashFcn>(*this); + Debug("CDTrailHashMap") << "save " << this + << " at level " << this->getContext()->getLevel() + << " size at " << this->d_trailSize + << " d_list is " << this->d_trailMap + << " data:" << data << std::endl; + return data; + } +protected: + /** + * Implementation of mandatory ContextObj method restore: simply + * restores the previous size. Note that the list pointer and the + * allocated size are not changed. + */ + void restore(ContextObj* data) { + Debug("CDTrailHashMap") << "restore " << this + << " level " << this->getContext()->getLevel() + << " data == " << data + << " d_trailMap == " << this->d_trailMap << std::endl; + size_t oldSize = ((CDTrailHashMap<Key, Data, HashFcn>*)data)->d_trailSize; + d_trailMap->pop_to_size(oldSize); + d_trailSize = oldSize; + Assert(d_trailMap->trailSize() == d_trailSize); + + d_prevTrailSize = ((CDTrailHashMap<Key, Data, HashFcn>*)data)->d_prevTrailSize; + Debug("CDTrailHashMap") << "restore " << this + << " level " << this->getContext()->getLevel() + << " size back to " << this->d_trailSize << std::endl; + } + + /** + * We need to save the d_trailSize immediately after a successful makeCurrent. + * So this version needs to be used everywhere instead of maekCurrent() + * internally. + */ + void internalMakeCurrent () { + if(!isCurrent()){ + makeCurrent(); + d_prevTrailSize = d_trailSize; + } + } + +public: + + /** + * Main constructor: d_trailMap starts as an empty map, with the sizes are 0 + */ + CDTrailHashMap(Context* context) : + ContextObj(context), + d_trailMap(new THM()), + d_trailSize(0), + d_prevTrailSize(0){ + Assert(d_trailMap->trailSize() == d_trailSize); + } + + /** + * Destructor: delete the map + */ + ~CDTrailHashMap() throw(AssertionException) { + this->destroy(); + delete d_trailMap; + } + + /** Returns true if the map is empty in the current context. */ + bool empty() const{ + return d_trailSize == 0; + } + + /** Returns true the size of the map in the current context. */ + size_t size() const { + return d_trailMap->uniqueKeys(); + } + + /** + * Inserts an element into the map. + * This always succeeds. + * Returns true if the key is new. + */ + bool insert(const Key& k, const Data& d){ + internalMakeCurrent(); + std::pair<bool, bool> res = d_trailMap->compacting_push_back(k, d, d_prevTrailSize); + if(res.second){ + ++d_trailSize; + } + Assert(d_trailMap->trailSize() == d_trailSize); + return res.first; + } + + /** + * Inserts an element into the map if the key is not already there. + * This has no side effects if the insert does not happen. + * Returns true if the element was inserted. + */ + bool insert_no_overwrite(const Key& k, const Data& d){ + bool res = d_trailMap->insert_no_overwrite(k, d); + if(res){ + internalMakeCurrent(); + ++d_trailSize; + } + Assert(d_trailMap->trailSize() == d_trailSize); + return res; + } + + /** Returns true if k is a mapped key in the context. */ + bool contains(const Key& k) const { + return d_trailMap->contains(k); + } + + /** + * Returns a reference the data mapped by k. + * k must be in the map in this context. + */ + const Data& operator[](const Key& k) const { + return (*d_trailMap)[k]; + } + /* +// While the following code "works", I wonder if it is not better to disable it? +// Non-const operator[] has strange semantics for a context-dependent +// data structure. + Data& operator[](const Key& k) { + internalMakeCurrent(); + std::pair<bool, bool> res = d_trailMap->hasAfter(k, d_prevTrailSize); + if(!res.first){ + std::pair<bool, bool> res = d_trailMap->compacting_push_back(k, Data(), d_prevTrailSize); + if(res.second){ + ++d_trailSize; + } + }else if(!res.second){ + std::pair<bool, bool> res = d_trailMap->compacting_push_back(k, (*d_trailMap)[k], d_prevTrailSize); + if(res.second){ + ++d_trailSize; + } + } + return d_trailMap->lookup(k); + } + */ + + /** + * Returns a const_iterator to the value_type if k is a mapped key in + * the context. + */ + const_iterator find(const Key& k) const { + return d_trailMap->find(k); + } + + /** Returns an iterator to the beginning of the map. */ + const_iterator begin() const{ + return d_trailMap->begin(); + } + /** Returns an iterator to the end of the map. */ + const_iterator end() const{ + return d_trailMap->end(); + } + +};/* class CDTrailHashMap<> */ + +template <class Data, class HashFcn> +class CDTrailHashMap <TNode, Data, HashFcn > : public ContextObj { + /* CDTrailHashMap is challenging to get working with TNode. + * Consider using CDHashMap<TNode,...> instead. + * + * Explanation: + * CDTrailHashMap uses keys during deallocation. + * If the key is a TNode and the backing (the hard node reference) + * for the key in another data structure removes the key at the same context + * the ref count could drop to 0. The key would then not be eligible to be + * hashed. Getting the order right with a guarantee is too hard. + */ + + BOOST_STATIC_ASSERT(sizeof(Data) == 0); +}; + +}/* CVC4::context namespace */ +}/* CVC4 namespace */ diff --git a/src/context/cdtrail_hashmap_forward.h b/src/context/cdtrail_hashmap_forward.h new file mode 100644 index 000000000..549ecd738 --- /dev/null +++ b/src/context/cdtrail_hashmap_forward.h @@ -0,0 +1,38 @@ +/********************* */ +/*! \file cdtrail_hashmap_forward.h + ** \verbatim + ** Original author: taking + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief This is a forward declaration header to declare the + ** CDTrailHashMap<> template + ** + ** This is a forward declaration header to declare the CDTrailHashMap<> + ** template. It's useful if you want to forward-declare CDTrailHashMap<> + ** without including the full cdtrail_hash_map.h header, for example, in a + ** public header context. + ** + ** For CDTrailHashMap<> in particular, it's difficult to forward-declare it + ** yourself, because it has a default template argument. + **/ + +#include "cvc4_public.h" + +#pragma once + +namespace __gnu_cxx { + template <class Key> struct hash; +}/* __gnu_cxx namespace */ + +namespace CVC4 { + namespace context { + template <class Key, class Data, class HashFcn = __gnu_cxx::hash<Key> > + class CDTrailHashMap; + }/* CVC4::context namespace */ +}/* CVC4 namespace */ + diff --git a/src/decision/decision_engine.cpp b/src/decision/decision_engine.cpp index 22c70eb6d..08a3e49d0 100644 --- a/src/decision/decision_engine.cpp +++ b/src/decision/decision_engine.cpp @@ -33,7 +33,7 @@ DecisionEngine::DecisionEngine(context::Context *sc, d_enabledStrategies(), d_needIteSkolemMap(), d_relevancyStrategy(NULL), - d_assertions(), + d_assertions(uc), d_cnfStream(NULL), d_satSolver(NULL), d_satContext(sc), @@ -50,18 +50,6 @@ void DecisionEngine::init() d_engineState = 1; Trace("decision-init") << "DecisionEngine::init()" << std::endl; - if(options::incrementalSolving()) { - if(options::decisionMode() != decision::DECISION_STRATEGY_INTERNAL) { - if(options::decisionMode.wasSetByUser()) { - Warning() << "Ignorning decision option since using incremental mode (currently not supported together)" - << std::endl; - } else { - Notice() << "Using internal decision heuristic since using incremental mode (not supported currently)" - << std::endl; - } - } - return; - } Trace("decision-init") << " * options->decisionMode: " << options::decisionMode() << std:: endl; Trace("decision-init") << " * options->decisionStopOnly: " @@ -70,11 +58,16 @@ void DecisionEngine::init() if(options::decisionMode() == decision::DECISION_STRATEGY_INTERNAL) { } if(options::decisionMode() == decision::DECISION_STRATEGY_JUSTIFICATION) { ITEDecisionStrategy* ds = - new decision::JustificationHeuristic(this, d_satContext); + new decision::JustificationHeuristic(this, d_userContext, d_satContext); enableStrategy(ds); d_needIteSkolemMap.push_back(ds); } if(options::decisionMode() == decision::DECISION_STRATEGY_RELEVANCY) { + if(options::incrementalSolving()) { + Warning() << "Relevancy decision heuristic and incremental not supported together" + << std::endl; + return; // Currently not supported with incremental + } RelevancyStrategy* ds = new decision::Relevancy(this, d_satContext); enableStrategy(ds); @@ -103,7 +96,7 @@ bool DecisionEngine::isRelevant(SatVariable var) SatValue DecisionEngine::getPolarity(SatVariable var) { - Debug("decision") << "getPolariry(" << var <<")" << std::endl; + Debug("decision") << "getPolarity(" << var <<")" << std::endl; if(d_relevancyStrategy != NULL) { Assert(isRelevant(var)); return d_relevancyStrategy->getPolarity( d_cnfStream->getNode(SatLiteral(var)) ); @@ -137,7 +130,7 @@ void DecisionEngine::addAssertions(const vector<Node> &assertions, // new assertions, reset whatever result we knew d_result = SAT_VALUE_UNKNOWN; - d_assertions.reserve(assertions.size()); + // d_assertions.reserve(assertions.size()); for(unsigned i = 0; i < assertions.size(); ++i) d_assertions.push_back(assertions[i]); diff --git a/src/decision/decision_engine.h b/src/decision/decision_engine.h index 4d354af2a..ea16cec16 100644 --- a/src/decision/decision_engine.h +++ b/src/decision/decision_engine.h @@ -42,7 +42,8 @@ class DecisionEngine { vector <ITEDecisionStrategy* > d_needIteSkolemMap; RelevancyStrategy* d_relevancyStrategy; - vector <Node> d_assertions; + typedef context::CDList<Node> AssertionsList; + AssertionsList d_assertions; // PropEngine* d_propEngine; CnfStream* d_cnfStream; @@ -55,7 +56,7 @@ class DecisionEngine { context::CDO<SatValue> d_result; // Disable creating decision engine without required parameters - DecisionEngine() : d_result(NULL) {} + DecisionEngine(); // init/shutdown state unsigned d_engineState; // 0=pre-init; 1=init,pre-shutdown; 2=shutdown @@ -68,8 +69,6 @@ public: /** Destructor, currently does nothing */ ~DecisionEngine() { Trace("decision") << "Destroying decision engine" << std::endl; - for(unsigned i = 0; i < d_enabledStrategies.size(); ++i) - delete d_enabledStrategies[i]; } // void setPropEngine(PropEngine* pe) { @@ -99,14 +98,15 @@ public: /** * This is called by SmtEngine, at shutdown time, just before * destruction. It is important because there are destruction - * ordering issues between some parts of the system. For now, - * there's nothing to do here in the DecisionEngine. + * ordering issues between some parts of the system. */ void shutdown() { Assert(d_engineState == 1); d_engineState = 2; Trace("decision") << "Shutting down decision engine" << std::endl; + for(unsigned i = 0; i < d_enabledStrategies.size(); ++i) + delete d_enabledStrategies[i]; } // Interface for External World to use our services @@ -191,7 +191,7 @@ public: /** * Get the assertions. Strategies are notified when these are available. */ - const vector<Node>& getAssertions() { + AssertionsList& getAssertions() { return d_assertions; } diff --git a/src/decision/decision_strategy.h b/src/decision/decision_strategy.h index a3c0d1684..a2fda44fe 100644 --- a/src/decision/decision_strategy.h +++ b/src/decision/decision_strategy.h @@ -9,7 +9,7 @@ ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** - ** \brief Decision stategy + ** \brief Decision strategy ** ** Decision strategy **/ diff --git a/src/decision/justification_heuristic.cpp b/src/decision/justification_heuristic.cpp index 4ec4588f3..0b63dfbe1 100644 --- a/src/decision/justification_heuristic.cpp +++ b/src/decision/justification_heuristic.cpp @@ -16,25 +16,6 @@ ** ** It needs access to the simplified but non-clausal formula. **/ -/*****************************************************************************/ -/*! - * file search_sat.cpp - * brief Implementation of Search engine with generic external sat solver - * - * Author: Clark Barrett - * - * Created: Wed Dec 7 21:00:24 2005 - * - * <hr> - * - * License to use, copy, modify, sell and/or distribute this software - * and its documentation for any purpose is hereby granted without - * royalty, subject to the terms and conditions defined in the \ref - * LICENSE file provided with this distribution. - * - * <hr> - */ -/*****************************************************************************/ #include "justification_heuristic.h" @@ -43,7 +24,158 @@ #include "theory/rewriter.h" #include "util/ite_removal.h" -// JustificationHeuristic stuff + +using namespace CVC4; + +JustificationHeuristic::JustificationHeuristic(CVC4::DecisionEngine* de, + context::Context *uc, + context::Context *c): + ITEDecisionStrategy(de, c), + d_justified(c), + d_prvsIndex(c, 0), + d_helfulness("decision::jh::helpfulness", 0), + d_giveup("decision::jh::giveup", 0), + d_timestat("decision::jh::time"), + d_assertions(uc), + d_iteAssertions(uc), + d_iteCache(), + d_visited(), + d_visitedComputeITE(), + d_curDecision() { + StatisticsRegistry::registerStat(&d_helfulness); + StatisticsRegistry::registerStat(&d_giveup); + StatisticsRegistry::registerStat(&d_timestat); + Trace("decision") << "Justification heuristic enabled" << std::endl; +} + +JustificationHeuristic::~JustificationHeuristic() { + StatisticsRegistry::unregisterStat(&d_helfulness); + StatisticsRegistry::unregisterStat(&d_giveup); + StatisticsRegistry::unregisterStat(&d_timestat); +} + +CVC4::prop::SatLiteral JustificationHeuristic::getNext(bool &stopSearch) { + Trace("decision") << "JustificationHeuristic::getNext()" << std::endl; + TimerStat::CodeTimer codeTimer(d_timestat); + + d_visited.clear(); + + if(Trace.isOn("justified")) { + for(JustifiedSet::key_iterator i = d_justified.key_begin(); + i != d_justified.key_end(); ++i) { + TNode n = *i; + SatLiteral l = d_decisionEngine->hasSatLiteral(n) ? + d_decisionEngine->getSatLiteral(n) : -1; + SatValue v = tryGetSatValue(n); + Trace("justified") <<"{ "<<l<<"}" << n <<": "<<v << std::endl; + } + } + + for(unsigned i = d_prvsIndex; i < d_assertions.size(); ++i) { + Debug("decision") << "---" << std::endl << d_assertions[i] << std::endl; + + // Sanity check: if it was false, aren't we inconsistent? + Assert( tryGetSatValue(d_assertions[i]) != SAT_VALUE_FALSE); + + SatValue desiredVal = SAT_VALUE_TRUE; + SatLiteral litDecision; + + litDecision = findSplitter(d_assertions[i], desiredVal); + + if(litDecision != undefSatLiteral) { + d_prvsIndex = i; + return litDecision; + } + } + + Trace("decision") << "jh: Nothing to split on " << std::endl; + +#if defined CVC4_DEBUG + bool alljustified = true; + for(unsigned i = 0 ; i < d_assertions.size() && alljustified ; ++i) { + TNode curass = d_assertions[i]; + while(curass.getKind() == kind::NOT) + curass = curass[0]; + alljustified &= checkJustified(curass); + + if(Debug.isOn("decision")) { + if(!checkJustified(curass)) + Debug("decision") << "****** Not justified [i="<<i<<"]: " + << d_assertions[i] << std::endl; + } + } + Assert(alljustified); +#endif + + // SAT solver can stop... + stopSearch = true; + d_decisionEngine->setResult(SAT_VALUE_TRUE); + return prop::undefSatLiteral; +} + + +inline void computeXorIffDesiredValues +(Kind k, SatValue desiredVal, SatValue &desiredVal1, SatValue &desiredVal2) +{ + Assert(k == kind::IFF || k == kind::XOR); + + bool shouldInvert = + (desiredVal == SAT_VALUE_TRUE && k == kind::IFF) || + (desiredVal == SAT_VALUE_FALSE && k == kind::XOR); + + if(desiredVal1 == SAT_VALUE_UNKNOWN && + desiredVal2 == SAT_VALUE_UNKNOWN) { + // CHOICE: pick one of them arbitarily + desiredVal1 = SAT_VALUE_FALSE; + } + + if(desiredVal2 == SAT_VALUE_UNKNOWN) { + desiredVal2 = shouldInvert ? invertValue(desiredVal1) : desiredVal1; + } else if(desiredVal1 == SAT_VALUE_UNKNOWN) { + desiredVal1 = shouldInvert ? invertValue(desiredVal2) : desiredVal2; + } +} + + + +void JustificationHeuristic::addAssertions +(const std::vector<Node> &assertions, + unsigned assertionsEnd, + IteSkolemMap iteSkolemMap) { + + Trace("decision") + << "JustificationHeuristic::addAssertions()" + << " size = " << assertions.size() + << " assertionsEnd = " << assertionsEnd + << std::endl; + + // Save the 'real' assertions locally + for(unsigned i = 0; i < assertionsEnd; ++i) + d_assertions.push_back(assertions[i]); + + // Save mapping between ite skolems and ite assertions + for(IteSkolemMap::iterator i = iteSkolemMap.begin(); + i != iteSkolemMap.end(); ++i) { + + Trace("decision::jh::ite") + << " jh-ite: " << (i->first) << " maps to " + << assertions[(i->second)] << std::endl; + Assert(i->second >= assertionsEnd && i->second < assertions.size()); + + d_iteAssertions[i->first] = assertions[i->second]; + } +} + +SatLiteral JustificationHeuristic::findSplitter(TNode node, + SatValue desiredVal) +{ + d_curDecision = undefSatLiteral; + if(findSplitterRec(node, desiredVal)) { + ++d_helfulness; + } + return d_curDecision; +} + void JustificationHeuristic::setJustified(TNode n) { @@ -67,14 +199,30 @@ SatValue JustificationHeuristic::tryGetSatValue(Node n) }//end of else } +const JustificationHeuristic::IteList& +JustificationHeuristic::getITEs(TNode n) +{ + IteCache::iterator it = d_iteCache.find(n); + if(it != d_iteCache.end()) { + return it->second; + } else { + // Compute the list of ITEs + // TODO: optimize by avoiding multiple lookup for d_iteCache[n] + d_iteCache[n] = IteList(); + d_visitedComputeITE.clear(); + computeITEs(n, d_iteCache[n]); + return d_iteCache[n]; + } +} + void JustificationHeuristic::computeITEs(TNode n, IteList &l) { - Trace("jh-ite") << " computeITEs( " << n << ", &l)\n"; + Trace("decision::jh::ite") << " computeITEs( " << n << ", &l)\n"; d_visitedComputeITE.insert(n); for(unsigned i=0; i<n.getNumChildren(); ++i) { SkolemMap::iterator it2 = d_iteAssertions.find(n[i]); if(it2 != d_iteAssertions.end()) { - l.push_back(make_pair(n[i], it2->second)); + l.push_back(make_pair(n[i], (*it2).second)); Assert(n[i].getNumChildren() == 0); } if(d_visitedComputeITE.find(n[i]) == @@ -84,26 +232,19 @@ void JustificationHeuristic::computeITEs(TNode n, IteList &l) } } -const JustificationHeuristic::IteList& JustificationHeuristic::getITEs(TNode n) -{ - IteCache::iterator it = d_iteCache.find(n); - if(it != d_iteCache.end()) { - return it->second; - } else { - // Compute the list of ITEs - // TODO: optimize by avoiding multiple lookup for d_iteCache[n] - d_iteCache[n] = IteList(); - d_visitedComputeITE.clear(); - computeITEs(n, d_iteCache[n]); - return d_iteCache[n]; - } -} - bool JustificationHeuristic::findSplitterRec(TNode node, - SatValue desiredVal, - SatLiteral* litDecision) + SatValue desiredVal) { - Trace("jh-findSplitterRec") + /** + * Main idea + * + * Given a boolean formula "node", the goal is to try to make it + * evaluate to "desiredVal" (true/false). for instance if "node" is a OR + * formula we want to make it evaluate to true, we'd like one of the + * children to be true. this is done recursively. + */ + + Trace("decision::jh") << "findSplitterRec(" << node << ", " << desiredVal << ", .. )" << std::endl; @@ -113,13 +254,9 @@ bool JustificationHeuristic::findSplitterRec(TNode node, node = node[0]; } - if(Debug.isOn("decision")) { - if(checkJustified(node)) - Debug("decision") << " justified, returning" << std::endl; - } - /* Base case */ if (checkJustified(node)) { + Debug("decision::jh") << " justified, returning" << std::endl; return false; } @@ -132,7 +269,6 @@ bool JustificationHeuristic::findSplitterRec(TNode node, Debug("decision") << "no sat literal for this node" << std::endl; } } - //Assert(litPresent); -- fails #endif // Get value of sat literal for the node, if there is one @@ -142,11 +278,6 @@ bool JustificationHeuristic::findSplitterRec(TNode node, Assert(desiredVal != SAT_VALUE_UNKNOWN, "expected known value"); /* Good luck, hope you can get what you want */ - // if(not (litVal == desiredVal || litVal == SAT_VALUE_UNKNOWN)) { - // Warning() << "WARNING: IMPORTANT: Please look into this. Sat solver is asking for a decision" << std::endl - // << "when the assertion we are trying to justify is already unsat. OR there is a bug" << std::endl; - // GiveUpException(); - // } Assert(litVal == desiredVal || litVal == SAT_VALUE_UNKNOWN, "invariant violated"); @@ -155,247 +286,192 @@ bool JustificationHeuristic::findSplitterRec(TNode node, theory::TheoryId tId = theory::kindToTheoryId(k); /* Some debugging stuff */ - Debug("jh-findSplitterRec") << "kind = " << k << std::endl; - Debug("jh-findSplitterRec") << "theoryId = " << tId << std::endl; - Debug("jh-findSplitterRec") << "node = " << node << std::endl; - Debug("jh-findSplitterRec") << "litVal = " << litVal << std::endl; + Debug("decision::jh") << "kind = " << k << std::endl + << "theoryId = " << tId << std::endl + << "node = " << node << std::endl + << "litVal = " << litVal << std::endl; /** - * If not in theory of booleans, and not a "boolean" EQUAL (IFF), - * then check if this is something to split-on. + * If not in theory of booleans, check if this is something to split-on. */ - if(tId != theory::THEORY_BOOL - // && !(k == kind::EQUAL && node[0].getType().isBoolean()) - ) { - - // if node has embedded ites -- which currently happens iff it got - // replaced during ite removal -- then try to resolve that first - const IteList& l = getITEs(node); - Trace("jh-ite") << " ite size = " << l.size() << std::endl; - /*d_visited.insert(node);*/ - for(IteList::const_iterator i = l.begin(); i != l.end(); ++i) { - if(d_visited.find(i->first) == d_visited.end()) { - d_visited.insert(i->first); - Debug("jh-ite") << "jh-ite: adding visited " << i->first << std::endl; - if(findSplitterRec(i->second, SAT_VALUE_TRUE, litDecision)) - return true; - Debug("jh-ite") << "jh-ite: removing visited " << i->first << std::endl; - d_visited.erase(i->first); - } else { - Debug("jh-ite") << "jh-ite: already visited " << i->first << std::endl; - } - } + if(tId != theory::THEORY_BOOL) { + + // if node has embedded ites, resolve that first + if(handleEmbeddedITEs(node)) + return true; if(litVal != SAT_VALUE_UNKNOWN) { setJustified(node); return false; - } else { - Assert(d_decisionEngine->hasSatLiteral(node)); - /* if(not d_decisionEngine->hasSatLiteral(node)) - throw GiveUpException(); */ + } + else { Assert(d_decisionEngine->hasSatLiteral(node)); - SatVariable v = d_decisionEngine->getSatLiteral(node).getSatVariable(); - *litDecision = SatLiteral(v, desiredVal != SAT_VALUE_TRUE ); - Trace("decision") << "decision " << *litDecision << std::endl; - Trace("decision") << "Found something to split. Glad to be able to serve you." << std::endl; + SatVariable v = + d_decisionEngine->getSatLiteral(node).getSatVariable(); + d_curDecision = SatLiteral(v, desiredVal != SAT_VALUE_TRUE ); return true; } } - SatValue valHard = SAT_VALUE_FALSE; + bool ret = false; switch (k) { case kind::CONST_BOOLEAN: Assert(node.getConst<bool>() == false || desiredVal == SAT_VALUE_TRUE); - Assert(node.getConst<bool>() == true || desiredVal == SAT_VALUE_FALSE); - setJustified(node); - return false; + Assert(node.getConst<bool>() == true || desiredVal == SAT_VALUE_FALSE); + break; case kind::AND: - valHard = SAT_VALUE_TRUE; + if (desiredVal == SAT_VALUE_FALSE) + ret = handleAndOrEasy(node, desiredVal); + else + ret = handleAndOrHard(node, desiredVal); + break; case kind::OR: - if (desiredVal == valHard) { - int n = node.getNumChildren(); - for(int i = 0; i < n; ++i) { - if (findSplitterRec(node[i], valHard, litDecision)) { - return true; - } - } - Assert(litPresent == false || litVal == valHard, - "Output should be justified"); - setJustified(node); - return false; - } - else { - SatValue valEasy = invertValue(valHard); - int n = node.getNumChildren(); - for(int i = 0; i < n; ++i) { - Debug("jh-findSplitterRec") << " node[i] = " << node[i] << " " - << tryGetSatValue(node[i]) << std::endl; - if ( tryGetSatValue(node[i]) != valHard) { - Debug("jh-findSplitterRec") << "hi"<< std::endl; - if (findSplitterRec(node[i], valEasy, litDecision)) { - return true; - } - Assert(litPresent == false || litVal == valEasy, "Output should be justified"); - setJustified(node); - return false; - } - } - if(Debug.isOn("jh-findSplitterRec")) { - Debug("jh-findSplitterRec") << " * ** " << std::endl; - Debug("jh-findSplitterRec") << node.getKind() << " " - << node << std::endl; - for(unsigned i = 0; i < node.getNumChildren(); ++i) - Debug("jh-findSplitterRec") << "child: " << tryGetSatValue(node[i]) - << std::endl; - Debug("jh-findSplitterRec") << "node: " << tryGetSatValue(node) - << std::endl; - } - Assert(false, "No controlling input found (2)"); - } + if (desiredVal == SAT_VALUE_FALSE) + ret = handleAndOrHard(node, desiredVal); + else + ret = handleAndOrEasy(node, desiredVal); break; case kind::IMPLIES: - //throw GiveUpException(); - Assert(node.getNumChildren() == 2, "Expected 2 fanins"); - if (desiredVal == SAT_VALUE_FALSE) { - if (findSplitterRec(node[0], SAT_VALUE_TRUE, litDecision)) { - return true; - } - if (findSplitterRec(node[1], SAT_VALUE_FALSE, litDecision)) { - return true; - } - Assert(litPresent == false || litVal == SAT_VALUE_FALSE, - "Output should be justified"); - setJustified(node); - return false; - } - else { - if (tryGetSatValue(node[0]) != SAT_VALUE_TRUE) { - if (findSplitterRec(node[0], SAT_VALUE_FALSE, litDecision)) { - return true; - } - Assert(litPresent == false || litVal == SAT_VALUE_TRUE, - "Output should be justified"); - setJustified(node); - return false; - } - if (tryGetSatValue(node[1]) != SAT_VALUE_FALSE) { - if (findSplitterRec(node[1], SAT_VALUE_TRUE, litDecision)) { - return true; - } - Assert(litPresent == false || litVal == SAT_VALUE_TRUE, - "Output should be justified"); - setJustified(node); - return false; - } - Assert(false, "No controlling input found (3)"); - } - break; + if (desiredVal == SAT_VALUE_FALSE) + ret = handleBinaryHard(node[0], SAT_VALUE_TRUE, + node[1], SAT_VALUE_FALSE); - case kind::IFF: - //throw GiveUpException(); - { - SatValue val = tryGetSatValue(node[0]); - if (val != SAT_VALUE_UNKNOWN) { - if (findSplitterRec(node[0], val, litDecision)) { - return true; - } - if (desiredVal == SAT_VALUE_FALSE) val = invertValue(val); - - if (findSplitterRec(node[1], val, litDecision)) { - return true; - } - Assert(litPresent == false || litVal == desiredVal, - "Output should be justified"); - setJustified(node); - return false; - } - else { - val = tryGetSatValue(node[1]); - if (val == SAT_VALUE_UNKNOWN) val = SAT_VALUE_FALSE; - if (desiredVal == SAT_VALUE_FALSE) val = invertValue(val); - if (findSplitterRec(node[0], val, litDecision)) { - return true; - } - Assert(false, "Unable to find controlling input (4)"); - } + else + ret = handleBinaryEasy(node[0], SAT_VALUE_FALSE, + node[1], SAT_VALUE_TRUE); break; - } - - case kind::XOR: - //throw GiveUpException(); - { - SatValue val = tryGetSatValue(node[0]); - if (val != SAT_VALUE_UNKNOWN) { - if (findSplitterRec(node[0], val, litDecision)) { - return true; - } - if (desiredVal == SAT_VALUE_TRUE) val = invertValue(val); - if (findSplitterRec(node[1], val, litDecision)) { - return true; - } - Assert(litPresent == false || litVal == desiredVal, - "Output should be justified"); - setJustified(node); - return false; - } - else { - SatValue val = tryGetSatValue(node[1]); - if (val == SAT_VALUE_UNKNOWN) val = SAT_VALUE_FALSE; - if (desiredVal == SAT_VALUE_TRUE) val = invertValue(val); - if (findSplitterRec(node[0], val, litDecision)) { - return true; - } - Assert(false, "Unable to find controlling input (5)"); - } + case kind::XOR: + case kind::IFF: { + SatValue desiredVal1 = tryGetSatValue(node[0]); + SatValue desiredVal2 = tryGetSatValue(node[1]); + computeXorIffDesiredValues(k, desiredVal, desiredVal1, desiredVal2); + ret = handleBinaryHard(node[0], desiredVal1, + node[1], desiredVal2); break; } - case kind::ITE: { - //[0]: if, [1]: then, [2]: else - SatValue ifVal = tryGetSatValue(node[0]); - if (ifVal == SAT_VALUE_UNKNOWN) { - - // are we better off trying false? if not, try true - SatValue ifDesiredVal = - (tryGetSatValue(node[2]) == desiredVal || - tryGetSatValue(node[1]) == invertValue(desiredVal)) - ? SAT_VALUE_FALSE : SAT_VALUE_TRUE; - - if(findSplitterRec(node[0], ifDesiredVal, litDecision)) { - return true; - } - Assert(false, "No controlling input found (6)"); - } else { - - // Try to justify 'if' - if (findSplitterRec(node[0], ifVal, litDecision)) { - return true; - } - - // If that was successful, we need to go into only one of 'then' - // or 'else' - int ch = (ifVal == SAT_VALUE_TRUE) ? 1 : 2; - int chVal = tryGetSatValue(node[ch]); - if( (chVal == SAT_VALUE_UNKNOWN || chVal == desiredVal) - && findSplitterRec(node[ch], desiredVal, litDecision) ) { - return true; - } - } - Assert(litPresent == false || litVal == desiredVal, - "Output should be justified"); - setJustified(node); - return false; - } + case kind::ITE: + ret = handleITE(node, desiredVal); + break; default: Assert(false, "Unexpected Boolean operator"); break; }//end of switch(k) - Unreachable(); + if(ret == false) { + Assert(litPresent == false || litVal == desiredVal, + "Output should be justified"); + setJustified(node); + } + return ret; }/* findRecSplit method */ + +bool JustificationHeuristic::handleAndOrEasy(TNode node, + SatValue desiredVal) +{ + Assert( (node.getKind() == kind::AND and desiredVal == SAT_VALUE_FALSE) or + (node.getKind() == kind::OR and desiredVal == SAT_VALUE_TRUE) ); + + int numChildren = node.getNumChildren(); + SatValue desiredValInverted = invertValue(desiredVal); + for(int i = 0; i < numChildren; ++i) + if ( tryGetSatValue(node[i]) != desiredValInverted ) + return findSplitterRec(node[i], desiredVal); + Assert(false, "handleAndOrEasy: No controlling input found"); + return false; +} + +bool JustificationHeuristic::handleAndOrHard(TNode node, + SatValue desiredVal) { + Assert( (node.getKind() == kind::AND and desiredVal == SAT_VALUE_TRUE) or + (node.getKind() == kind::OR and desiredVal == SAT_VALUE_FALSE) ); + + int numChildren = node.getNumChildren(); + for(int i = 0; i < numChildren; ++i) + if (findSplitterRec(node[i], desiredVal)) + return true; + return false; +} + +bool JustificationHeuristic::handleBinaryEasy(TNode node1, + SatValue desiredVal1, + TNode node2, + SatValue desiredVal2) +{ + if ( tryGetSatValue(node1) != invertValue(desiredVal1) ) + return findSplitterRec(node1, desiredVal1); + if ( tryGetSatValue(node2) != invertValue(desiredVal2) ) + return findSplitterRec(node2, desiredVal2); + Assert(false, "handleBinaryEasy: No controlling input found"); + return false; +} + +bool JustificationHeuristic::handleBinaryHard(TNode node1, + SatValue desiredVal1, + TNode node2, + SatValue desiredVal2) +{ + if( findSplitterRec(node1, desiredVal1) ) + return true; + return findSplitterRec(node2, desiredVal2); +} + +bool JustificationHeuristic::handleITE(TNode node, SatValue desiredVal) +{ + Debug("decision::jh") << " handleITE (" << node << ", " + << desiredVal << std::endl; + + //[0]: if, [1]: then, [2]: else + SatValue ifVal = tryGetSatValue(node[0]); + if (ifVal == SAT_VALUE_UNKNOWN) { + + // are we better off trying false? if not, try true [CHOICE] + SatValue ifDesiredVal = + (tryGetSatValue(node[2]) == desiredVal || + tryGetSatValue(node[1]) == invertValue(desiredVal)) + ? SAT_VALUE_FALSE : SAT_VALUE_TRUE; + + if(findSplitterRec(node[0], ifDesiredVal)) return true; + + Assert(false, "No controlling input found (6)"); + } else { + // Try to justify 'if' + if(findSplitterRec(node[0], ifVal)) return true; + + // If that was successful, we need to go into only one of 'then' + // or 'else' + int ch = (ifVal == SAT_VALUE_TRUE) ? 1 : 2; + + // STALE code: remove after tests or mar 2013, whichever earlier + // int chVal = tryGetSatValue(node[ch]); + // Assert(chVal == SAT_VALUE_UNKNOWN || chVal == desiredVal); + // end STALE code: remove + + if( findSplitterRec(node[ch], desiredVal) ) { + return true; + } + }// else (...ifVal...) + return false; +} + +bool JustificationHeuristic::handleEmbeddedITEs(TNode node) +{ + const IteList& l = getITEs(node); + Trace("decision::jh::ite") << " ite size = " << l.size() << std::endl; + + for(IteList::const_iterator i = l.begin(); i != l.end(); ++i) { + if(d_visited.find(i->first) == d_visited.end()) { + d_visited.insert(i->first); + if(findSplitterRec(i->second, SAT_VALUE_TRUE)) + return true; + d_visited.erase(i->first); + } + } + return false; +} diff --git a/src/decision/justification_heuristic.h b/src/decision/justification_heuristic.h index 5d13d2dd2..91c21d981 100644 --- a/src/decision/justification_heuristic.h +++ b/src/decision/justification_heuristic.h @@ -27,6 +27,8 @@ #include "decision_strategy.h" #include "context/cdhashset.h" +#include "context/cdlist.h" +#include "context/cdhashmap.h" #include "expr/node.h" #include "prop/sat_solver_types.h" @@ -34,20 +36,13 @@ namespace CVC4 { namespace decision { -class GiveUpException : public Exception { -public: - GiveUpException() : - Exception("justification heuristic: giving up") { - } -};/* class GiveUpException */ - class JustificationHeuristic : public ITEDecisionStrategy { typedef std::vector<pair<TNode,TNode> > IteList; typedef hash_map<TNode,IteList,TNodeHashFunction> IteCache; - typedef hash_map<TNode,TNode,TNodeHashFunction> SkolemMap; + typedef context::CDHashMap<TNode,TNode,TNodeHashFunction> SkolemMap; // being 'justified' is monotonic with respect to decisions - typedef context::CDHashSet<TNode,TNodeHashFunction> JustifiedSet; + typedef context::CDHashSet<Node,NodeHashFunction> JustifiedSet; JustifiedSet d_justified; context::CDO<unsigned> d_prvsIndex; @@ -59,7 +54,7 @@ class JustificationHeuristic : public ITEDecisionStrategy { * A copy of the assertions that need to be justified * directly. Doesn't have ones introduced during during ITE-removal. */ - std::vector<TNode> d_assertions; + context::CDList<TNode> d_assertions; //TNode is fine since decisionEngine has them too /** map from ite-rewrite skolem to a boolean-ite assertion */ @@ -82,127 +77,29 @@ class JustificationHeuristic : public ITEDecisionStrategy { * function */ hash_set<TNode,TNodeHashFunction> d_visitedComputeITE; + + /** current decision for the recursive call */ + SatLiteral d_curDecision; public: - JustificationHeuristic(CVC4::DecisionEngine* de, context::Context *c): - ITEDecisionStrategy(de, c), - d_justified(c), - d_prvsIndex(c, 0), - d_helfulness("decision::jh::helpfulness", 0), - d_giveup("decision::jh::giveup", 0), - d_timestat("decision::jh::time") { - StatisticsRegistry::registerStat(&d_helfulness); - StatisticsRegistry::registerStat(&d_giveup); - StatisticsRegistry::registerStat(&d_timestat); - Trace("decision") << "Justification heuristic enabled" << std::endl; - } - ~JustificationHeuristic() { - StatisticsRegistry::unregisterStat(&d_helfulness); - StatisticsRegistry::unregisterStat(&d_timestat); - } - prop::SatLiteral getNext(bool &stopSearch) { - Trace("decision") << "JustificationHeuristic::getNext()" << std::endl; - TimerStat::CodeTimer codeTimer(d_timestat); - - d_visited.clear(); - - if(Trace.isOn("justified")) { - for(JustifiedSet::iterator i = d_justified.begin(); - i != d_justified.end(); ++i) { - TNode n = *i; - SatLiteral l = d_decisionEngine->hasSatLiteral(n) ? - d_decisionEngine->getSatLiteral(n) : -1; - SatValue v = tryGetSatValue(n); - Trace("justified") <<"{ "<<l<<"}" << n <<": "<<v << std::endl; - } - } - - for(unsigned i = d_prvsIndex; i < d_assertions.size(); ++i) { - Debug("decision") << "---" << std::endl << d_assertions[i] << std::endl; - - // Sanity check: if it was false, aren't we inconsistent? - Assert( tryGetSatValue(d_assertions[i]) != SAT_VALUE_FALSE); - - SatValue desiredVal = SAT_VALUE_TRUE; - SatLiteral litDecision; - try { - litDecision = findSplitter(d_assertions[i], desiredVal); - }catch(GiveUpException &e) { - return prop::undefSatLiteral; - } - - if(litDecision != undefSatLiteral) { - d_prvsIndex = i; - return litDecision; - } - } - - Trace("decision") << "jh: Nothing to split on " << std::endl; - -#if defined CVC4_DEBUG - bool alljustified = true; - for(unsigned i = 0 ; i < d_assertions.size() && alljustified ; ++i) { - TNode curass = d_assertions[i]; - while(curass.getKind() == kind::NOT) - curass = curass[0]; - alljustified &= checkJustified(curass); - - if(Debug.isOn("decision")) { - if(!checkJustified(curass)) - Debug("decision") << "****** Not justified [i="<<i<<"]: " - << d_assertions[i] << std::endl; - } - } - Assert(alljustified); -#endif - - // SAT solver can stop... - stopSearch = true; - d_decisionEngine->setResult(SAT_VALUE_TRUE); - return prop::undefSatLiteral; - } + JustificationHeuristic(CVC4::DecisionEngine* de, + context::Context *uc, + context::Context *c); + + ~JustificationHeuristic(); + + prop::SatLiteral getNext(bool &stopSearch); void addAssertions(const std::vector<Node> &assertions, unsigned assertionsEnd, - IteSkolemMap iteSkolemMap) { - Trace("decision") - << "JustificationHeuristic::addAssertions()" - << " size = " << assertions.size() - << " assertionsEnd = " << assertionsEnd - << std::endl; - - // Save the 'real' assertions locally - for(unsigned i = 0; i < assertionsEnd; ++i) - d_assertions.push_back(assertions[i]); - - // Save mapping between ite skolems and ite assertions - for(IteSkolemMap::iterator i = iteSkolemMap.begin(); - i != iteSkolemMap.end(); ++i) { - Trace("jh-ite") << " jh-ite: " << (i->first) << " maps to " - << assertions[(i->second)] << std::endl; - Assert(i->second >= assertionsEnd && i->second < assertions.size()); - d_iteAssertions[i->first] = assertions[i->second]; - } - } + IteSkolemMap iteSkolemMap); private: - SatLiteral findSplitter(TNode node, SatValue desiredVal) - { - bool ret; - SatLiteral litDecision; - ret = findSplitterRec(node, desiredVal, &litDecision); - if(ret == true) { - Debug("decision") << "Yippee!!" << std::endl; - ++d_helfulness; - return litDecision; - } else { - return undefSatLiteral; - } - } + SatLiteral findSplitter(TNode node, SatValue desiredVal); /** * Do all the hard work. */ - bool findSplitterRec(TNode node, SatValue value, SatLiteral* litDecision); + bool findSplitterRec(TNode node, SatValue value); /* Helper functions */ void setJustified(TNode); @@ -217,6 +114,15 @@ private: /* Compute all term-ITEs in a node recursively */ void computeITEs(TNode n, IteList &l); + + bool handleAndOrEasy(TNode node, SatValue desiredVal); + bool handleAndOrHard(TNode node, SatValue desiredVal); + bool handleBinaryEasy(TNode node1, SatValue desiredVal1, + TNode node2, SatValue desiredVal2); + bool handleBinaryHard(TNode node1, SatValue desiredVal1, + TNode node2, SatValue desiredVal2); + bool handleITE(TNode node, SatValue desiredVal); + bool handleEmbeddedITEs(TNode node); };/* class JustificationHeuristic */ }/* namespace decision */ diff --git a/src/decision/relevancy.h b/src/decision/relevancy.h index 8a6eb54ef..bfd30ddde 100644 --- a/src/decision/relevancy.h +++ b/src/decision/relevancy.h @@ -60,7 +60,7 @@ class Relevancy : public RelevancyStrategy { typedef hash_map<TNode,SatValue,TNodeHashFunction> PolarityCache; // being 'justified' is monotonic with respect to decisions - context::CDHashSet<TNode,TNodeHashFunction> d_justified; + context::CDHashSet<Node, NodeHashFunction> d_justified; context::CDO<unsigned> d_prvsIndex; IntStat d_helfulness; diff --git a/src/expr/attribute_internals.h b/src/expr/attribute_internals.h index a085161bc..9a14caec5 100644 --- a/src/expr/attribute_internals.h +++ b/src/expr/attribute_internals.h @@ -752,7 +752,7 @@ public: table_value_type table_value_type; typedef attr::AttributeTraits<table_value_type, context_dep> traits; uint64_t id = attr::LastAttributeId<table_value_type, context_dep>::s_id++; - Assert(traits::cleanup.size() == id);// sanity check + //Assert(traits::cleanup.size() == id);// sanity check traits::cleanup.push_back(attr::getCleanupStrategy<value_t, CleanupStrategy>::fn); return id; diff --git a/src/expr/command.cpp b/src/expr/command.cpp index fa2a8d1f2..9edc77e39 100644 --- a/src/expr/command.cpp +++ b/src/expr/command.cpp @@ -703,8 +703,12 @@ Expr SimplifyCommand::getTerm() const throw() { } void SimplifyCommand::invoke(SmtEngine* smtEngine) throw() { - d_result = smtEngine->simplify(d_term); - d_commandStatus = CommandSuccess::instance(); + try { + d_result = smtEngine->simplify(d_term); + d_commandStatus = CommandSuccess::instance(); + } catch(exception& e) { + d_commandStatus = new CommandFailure(e.what()); + } } Expr SimplifyCommand::getResult() const throw() { diff --git a/src/expr/command.h b/src/expr/command.h index 342aec5ff..9877044fb 100644 --- a/src/expr/command.h +++ b/src/expr/command.h @@ -401,7 +401,7 @@ public: /** * The command when an attribute is set by a user. In SMT-LIBv2 this is done - * via the syntax (! expr :atrr) + * via the syntax (! expr :attr) */ class CVC4_PUBLIC SetUserAttributeCommand : public Command { protected: diff --git a/src/expr/expr_manager_template.h b/src/expr/expr_manager_template.h index b9cae9431..09018cbfd 100644 --- a/src/expr/expr_manager_template.h +++ b/src/expr/expr_manager_template.h @@ -43,7 +43,7 @@ class SmtEngine; class NodeManager; class Options; class IntStat; -class ExprManagerMapCollection; +struct ExprManagerMapCollection; class StatisticsRegistry; namespace expr { diff --git a/src/expr/expr_template.h b/src/expr/expr_template.h index a52bc00ac..f5df63f8c 100644 --- a/src/expr/expr_template.h +++ b/src/expr/expr_template.h @@ -67,7 +67,7 @@ namespace prop { class TheoryProxy; }/* CVC4::prop namespace */ -class ExprManagerMapCollection; +struct ExprManagerMapCollection; struct ExprHashFunction; diff --git a/src/expr/kind_template.h b/src/expr/kind_template.h index 47504b0e4..0cab4e628 100644 --- a/src/expr/kind_template.h +++ b/src/expr/kind_template.h @@ -27,7 +27,7 @@ namespace CVC4 { namespace kind { -enum Kind_t { +enum CVC4_PUBLIC Kind_t { UNDEFINED_KIND = -1, /**< undefined */ NULL_EXPR, /**< Null kind */ ${kind_decls} diff --git a/src/expr/mkexpr b/src/expr/mkexpr index 5134d561e..ca89dfc91 100755 --- a/src/expr/mkexpr +++ b/src/expr/mkexpr @@ -2,7 +2,7 @@ # # mkexpr # Morgan Deters <mdeters@cs.nyu.edu> for CVC4 -# Copyright (c) 2010-2012 The CVC4 Project +# Copyright (c) 2010-2013 The CVC4 Project # # The purpose of this script is to create {expr,expr_manager}.{h,cpp} # from template files and a list of theory kinds. Basically it just @@ -15,7 +15,7 @@ # Output is to standard out. # -copyright=2010-2012 +copyright=2010-2013 filename=`basename "$1" | sed 's,_template,,'` @@ -23,7 +23,8 @@ cat <<EOF /********************* */ /** $filename ** - ** Copyright $copyright The AcSys Group, New York University, and as below. + ** Copyright $copyright New York University and The University of Iowa, + ** and as below. ** ** This file automatically generated by: ** diff --git a/src/expr/mkkind b/src/expr/mkkind index 786d6187b..f8432466d 100755 --- a/src/expr/mkkind +++ b/src/expr/mkkind @@ -2,7 +2,7 @@ # # mkkind # Morgan Deters <mdeters@cs.nyu.edu> for CVC4 -# Copyright (c) 2010-2012 The CVC4 Project +# Copyright (c) 2010-2013 The CVC4 Project # # The purpose of this script is to create kind.h (and also # type_properties.h) from a template and a list of theory kinds. @@ -14,7 +14,7 @@ # Output is to standard out. # -copyright=2010-2012 +copyright=2010-2013 filename=`basename "$1" | sed 's,_template,,'` @@ -22,7 +22,8 @@ cat <<EOF /********************* */ /** $filename ** - ** Copyright $copyright The AcSys Group, New York University, and as below. + ** Copyright $copyright New York University and The University of Iowa, + ** and as below. ** ** This header file automatically generated by: ** diff --git a/src/expr/mkmetakind b/src/expr/mkmetakind index 47ffc77f9..160a74eac 100755 --- a/src/expr/mkmetakind +++ b/src/expr/mkmetakind @@ -2,7 +2,7 @@ # # mkmetakind # Morgan Deters <mdeters@cs.nyu.edu> for CVC4 -# Copyright (c) 2010-2012 The CVC4 Project +# Copyright (c) 2010-2013 The CVC4 Project # # The purpose of this script is to create metakind.h from a template # and a list of theory kinds. @@ -17,13 +17,14 @@ # Output is to standard out. # -copyright=2010-2012 +copyright=2010-2013 cat <<EOF /********************* */ /** metakind.h ** - ** Copyright $copyright The AcSys Group, New York University, and as below. + ** Copyright $copyright New York University and The University of Iowa, + ** and as below. ** ** This header file automatically generated by: ** diff --git a/src/expr/type.cpp b/src/expr/type.cpp index cc52b11b9..4e95c0fe2 100644 --- a/src/expr/type.cpp +++ b/src/expr/type.cpp @@ -204,111 +204,48 @@ bool Type::isBoolean() const { return d_typeNode->isBoolean(); } -/** Cast to a Boolean type */ -Type::operator BooleanType() const throw(IllegalArgumentException) { - NodeManagerScope nms(d_nodeManager); - CheckArgument(isNull() || isBoolean(), this); - return BooleanType(*this); -} - /** Is this the integer type? */ bool Type::isInteger() const { NodeManagerScope nms(d_nodeManager); return d_typeNode->isInteger(); } -/** Cast to a integer type */ -Type::operator IntegerType() const throw(IllegalArgumentException) { - NodeManagerScope nms(d_nodeManager); - CheckArgument(isNull() || isInteger(), this); - return IntegerType(*this); -} - /** Is this the real type? */ bool Type::isReal() const { NodeManagerScope nms(d_nodeManager); return d_typeNode->isReal(); } -/** Cast to a real type */ -Type::operator RealType() const throw(IllegalArgumentException) { - NodeManagerScope nms(d_nodeManager); - CheckArgument(isNull() || isReal(), this); - return RealType(*this); -} - /** Is this the string type? */ bool Type::isString() const { NodeManagerScope nms(d_nodeManager); return d_typeNode->isString(); } -/** Cast to a string type */ -Type::operator StringType() const throw(IllegalArgumentException) { - NodeManagerScope nms(d_nodeManager); - CheckArgument(isNull() || isString(), this); - return StringType(*this); -} - /** Is this the bit-vector type? */ bool Type::isBitVector() const { NodeManagerScope nms(d_nodeManager); return d_typeNode->isBitVector(); } -/** Cast to a bit-vector type */ -Type::operator BitVectorType() const throw(IllegalArgumentException) { - NodeManagerScope nms(d_nodeManager); - CheckArgument(isNull() || isBitVector(), this); - return BitVectorType(*this); -} - -/** Cast to a Constructor type */ -Type::operator DatatypeType() const throw(IllegalArgumentException) { - NodeManagerScope nms(d_nodeManager); - CheckArgument(isNull() || isDatatype(), this); - return DatatypeType(*this); -} - /** Is this a datatype type? */ bool Type::isDatatype() const { NodeManagerScope nms(d_nodeManager); return d_typeNode->isDatatype() || d_typeNode->isParametricDatatype(); } -/** Cast to a Constructor type */ -Type::operator ConstructorType() const throw(IllegalArgumentException) { - NodeManagerScope nms(d_nodeManager); - CheckArgument(isNull() || isConstructor(), this); - return ConstructorType(*this); -} - /** Is this the Constructor type? */ bool Type::isConstructor() const { NodeManagerScope nms(d_nodeManager); return d_typeNode->isConstructor(); } -/** Cast to a Selector type */ -Type::operator SelectorType() const throw(IllegalArgumentException) { - NodeManagerScope nms(d_nodeManager); - CheckArgument(isNull() || isSelector(), this); - return SelectorType(*this); -} - /** Is this the Selector type? */ bool Type::isSelector() const { NodeManagerScope nms(d_nodeManager); return d_typeNode->isSelector(); } -/** Cast to a Tester type */ -Type::operator TesterType() const throw(IllegalArgumentException) { - NodeManagerScope nms(d_nodeManager); - CheckArgument(isNull() || isTester(), this); - return TesterType(*this); -} - /** Is this the Tester type? */ bool Type::isTester() const { NodeManagerScope nms(d_nodeManager); @@ -330,64 +267,30 @@ bool Type::isPredicate() const { return d_typeNode->isPredicate(); } -/** Cast to a function type */ -Type::operator FunctionType() const throw(IllegalArgumentException) { - NodeManagerScope nms(d_nodeManager); - CheckArgument(isNull() || isFunction(), this); - return FunctionType(*this); -} - /** Is this a tuple type? */ bool Type::isTuple() const { NodeManagerScope nms(d_nodeManager); return d_typeNode->isTuple(); } -/** Cast to a tuple type */ -Type::operator TupleType() const throw(IllegalArgumentException) { - NodeManagerScope nms(d_nodeManager); - CheckArgument(isNull() || isTuple(), this); - return TupleType(*this); -} - /** Is this a record type? */ bool Type::isRecord() const { NodeManagerScope nms(d_nodeManager); return d_typeNode->isRecord(); } -/** Cast to a record type */ -Type::operator RecordType() const throw(IllegalArgumentException) { - NodeManagerScope nms(d_nodeManager); - CheckArgument(isNull() || isRecord(), this); - return RecordType(*this); -} - /** Is this a symbolic expression type? */ bool Type::isSExpr() const { NodeManagerScope nms(d_nodeManager); return d_typeNode->isSExpr(); } -/** Cast to a symbolic expression type */ -Type::operator SExprType() const throw(IllegalArgumentException) { - NodeManagerScope nms(d_nodeManager); - CheckArgument(isNull() || isSExpr(), this); - return SExprType(*this); -} - /** Is this an array type? */ bool Type::isArray() const { NodeManagerScope nms(d_nodeManager); return d_typeNode->isArray(); } -/** Cast to an array type */ -Type::operator ArrayType() const throw(IllegalArgumentException) { - NodeManagerScope nms(d_nodeManager); - return ArrayType(*this); -} - /** Is this a sort kind */ bool Type::isSort() const { NodeManagerScope nms(d_nodeManager); @@ -395,25 +298,11 @@ bool Type::isSort() const { } /** Cast to a sort type */ -Type::operator SortType() const throw(IllegalArgumentException) { - NodeManagerScope nms(d_nodeManager); - CheckArgument(isNull() || isSort(), this); - return SortType(*this); -} - -/** Is this a sort constructor kind */ bool Type::isSortConstructor() const { NodeManagerScope nms(d_nodeManager); return d_typeNode->isSortConstructor(); } -/** Cast to a sort constructor type */ -Type::operator SortConstructorType() const throw(IllegalArgumentException) { - NodeManagerScope nms(d_nodeManager); - CheckArgument(isNull() || isSortConstructor(), this); - return SortConstructorType(*this); -} - /** Is this a predicate subtype */ /* - not in release 1.0 bool Type::isPredicateSubtype() const { @@ -422,28 +311,12 @@ bool Type::isPredicateSubtype() const { } */ -/** Cast to a predicate subtype */ -/* - not in release 1.0 -Type::operator PredicateSubtype() const throw(IllegalArgumentException) { - NodeManagerScope nms(d_nodeManager); - CheckArgument(isNull() || isPredicateSubtype(), this); - return PredicateSubtype(*this); -} -*/ - /** Is this an integer subrange */ bool Type::isSubrange() const { NodeManagerScope nms(d_nodeManager); return d_typeNode->isSubrange(); } -/** Cast to a predicate subtype */ -Type::operator SubrangeType() const throw(IllegalArgumentException) { - NodeManagerScope nms(d_nodeManager); - CheckArgument(isNull() || isSubrange(), this); - return SubrangeType(*this); -} - vector<Type> FunctionType::getArgTypes() const { NodeManagerScope nms(d_nodeManager); vector<Type> args; diff --git a/src/expr/type.h b/src/expr/type.h index 4223d71ab..ce6291cd8 100644 --- a/src/expr/type.h +++ b/src/expr/type.h @@ -30,15 +30,15 @@ namespace CVC4 { class NodeManager; -class ExprManager; -class Expr; +class CVC4_PUBLIC ExprManager; +class CVC4_PUBLIC Expr; class TypeNode; -class ExprManagerMapCollection; +struct CVC4_PUBLIC ExprManagerMapCollection; -class SmtEngine; +class CVC4_PUBLIC SmtEngine; -class Datatype; -class Record; +class CVC4_PUBLIC Datatype; +class CVC4_PUBLIC Record; template <bool ref_count> class NodeTemplate; @@ -240,60 +240,30 @@ public: bool isBoolean() const; /** - * Cast this type to a Boolean type - * @return the BooleanType - */ - operator BooleanType() const throw(IllegalArgumentException); - - /** * Is this the integer type? * @return true if the type is a integer type */ bool isInteger() const; /** - * Cast this type to a integer type - * @return the IntegerType - */ - operator IntegerType() const throw(IllegalArgumentException); - - /** * Is this the real type? * @return true if the type is a real type */ bool isReal() const; /** - * Cast this type to a real type - * @return the RealType - */ - operator RealType() const throw(IllegalArgumentException); - - /** * Is this the string type? * @return true if the type is the string type */ bool isString() const; /** - * Cast this type to a string type - * @return the StringType - */ - operator StringType() const throw(IllegalArgumentException); - - /** * Is this the bit-vector type? * @return true if the type is a bit-vector type */ bool isBitVector() const; /** - * Cast this type to a bit-vector type - * @return the BitVectorType - */ - operator BitVectorType() const throw(IllegalArgumentException); - - /** * Is this a function type? * @return true if the type is a function type */ @@ -307,132 +277,66 @@ public: bool isPredicate() const; /** - * Cast this type to a function type - * @return the FunctionType - */ - operator FunctionType() const throw(IllegalArgumentException); - - /** * Is this a tuple type? * @return true if the type is a tuple type */ bool isTuple() const; /** - * Cast this type to a tuple type - * @return the TupleType - */ - operator TupleType() const throw(IllegalArgumentException); - - /** * Is this a record type? * @return true if the type is a record type */ bool isRecord() const; /** - * Cast this type to a record type - * @return the RecordType - */ - operator RecordType() const throw(IllegalArgumentException); - - /** * Is this a symbolic expression type? * @return true if the type is a symbolic expression type */ bool isSExpr() const; /** - * Cast this type to a symbolic expression type - * @return the SExprType - */ - operator SExprType() const throw(IllegalArgumentException); - - /** * Is this an array type? * @return true if the type is a array type */ bool isArray() const; /** - * Cast this type to an array type - * @return the ArrayType - */ - operator ArrayType() const throw(IllegalArgumentException); - - /** * Is this a datatype type? * @return true if the type is a datatype type */ bool isDatatype() const; /** - * Cast this type to a datatype type - * @return the DatatypeType - */ - operator DatatypeType() const throw(IllegalArgumentException); - - /** * Is this a constructor type? * @return true if the type is a constructor type */ bool isConstructor() const; /** - * Cast this type to a constructor type - * @return the ConstructorType - */ - operator ConstructorType() const throw(IllegalArgumentException); - - /** * Is this a selector type? * @return true if the type is a selector type */ bool isSelector() const; /** - * Cast this type to a selector type - * @return the SelectorType - */ - operator SelectorType() const throw(IllegalArgumentException); - - /** * Is this a tester type? * @return true if the type is a tester type */ bool isTester() const; /** - * Cast this type to a tester type - * @return the TesterType - */ - operator TesterType() const throw(IllegalArgumentException); - - /** * Is this a sort kind? * @return true if this is a sort kind */ bool isSort() const; /** - * Cast this type to a sort type - * @return the sort type - */ - operator SortType() const throw(IllegalArgumentException); - - /** * Is this a sort constructor kind? * @return true if this is a sort constructor kind */ bool isSortConstructor() const; /** - * Cast this type to a sort constructor type - * @return the sort constructor type - */ - operator SortConstructorType() const throw(IllegalArgumentException); - - /** * Is this a predicate subtype? * @return true if this is a predicate subtype */ @@ -440,25 +344,12 @@ public: //bool isPredicateSubtype() const; /** - * Cast this type to a predicate subtype - * @return the predicate subtype - */ - // not in release 1.0 - //operator PredicateSubtype() const throw(IllegalArgumentException); - - /** * Is this an integer subrange type? * @return true if this is an integer subrange type */ bool isSubrange() const; /** - * Cast this type to an integer subrange type - * @return the integer subrange type - */ - operator SubrangeType() const throw(IllegalArgumentException); - - /** * Outputs a string representation of this type to the stream. * @param out the stream to output to */ diff --git a/src/expr/type.i b/src/expr/type.i index 870cb228c..e227cca23 100644 --- a/src/expr/type.i +++ b/src/expr/type.i @@ -14,24 +14,6 @@ %rename(greater) CVC4::Type::operator>(const Type&) const; %rename(greaterEqual) CVC4::Type::operator>=(const Type&) const; -%rename(toBooleanType) CVC4::Type::operator BooleanType() const; -%rename(toIntegerType) CVC4::Type::operator IntegerType() const; -%rename(toRealType) CVC4::Type::operator RealType() const; -%rename(toStringType) CVC4::Type::operator StringType() const; -%rename(toBitVectorType) CVC4::Type::operator BitVectorType() const; -%rename(toFunctionType) CVC4::Type::operator FunctionType() const; -%rename(toTupleType) CVC4::Type::operator TupleType() const; -%rename(toSExprType) CVC4::Type::operator SExprType() const; -%rename(toArrayType) CVC4::Type::operator ArrayType() const; -%rename(toDatatypeType) CVC4::Type::operator DatatypeType() const; -%rename(toConstructorType) CVC4::Type::operator ConstructorType() const; -%rename(toSelectorType) CVC4::Type::operator SelectorType() const; -%rename(toTesterType) CVC4::Type::operator TesterType() const; -%rename(toSortType) CVC4::Type::operator SortType() const; -%rename(toSortConstructorType) CVC4::Type::operator SortConstructorType() const; -%rename(toPredicateSubtype) CVC4::Type::operator PredicateSubtype() const; -%rename(toSubrangeType) CVC4::Type::operator SubrangeType() const; - namespace CVC4 { namespace expr { %ignore exportTypeInternal; diff --git a/src/include/cvc4_public.h b/src/include/cvc4_public.h index 6c546a147..9993e5f18 100644 --- a/src/include/cvc4_public.h +++ b/src/include/cvc4_public.h @@ -22,19 +22,7 @@ #include <stdint.h> #if defined _WIN32 || defined __CYGWIN__ -# ifdef BUILDING_DLL -# ifdef __GNUC__ -# define CVC4_PUBLIC __attribute__((__dllexport__)) -# else /* ! __GNUC__ */ -# define CVC4_PUBLIC __declspec(dllexport) -# endif /* __GNUC__ */ -# else /* BUILDING_DLL */ -# ifdef __GNUC__ -# define CVC4_PUBLIC __attribute__((__dllimport__)) -# else /* ! __GNUC__ */ -# define CVC4_PUBLIC __declspec(dllimport) -# endif /* __GNUC__ */ -# endif /* BUILDING_DLL */ +# define CVC4_PUBLIC #else /* !( defined _WIN32 || defined __CYGWIN__ ) */ # if __GNUC__ >= 4 # define CVC4_PUBLIC __attribute__ ((__visibility__("default"))) diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index a6ea59e95..61f9e2d70 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -15,5 +15,8 @@ libreplacements_la_LIBADD = \ EXTRA_DIST = \ replacements.h \ clock_gettime.c \ - clock_gettime.h - + clock_gettime.h \ + strtok_r.c \ + strtok_r.h \ + ffs.c \ + ffs.h diff --git a/src/lib/clock_gettime.c b/src/lib/clock_gettime.c index 77409c71a..054a8c112 100644 --- a/src/lib/clock_gettime.c +++ b/src/lib/clock_gettime.c @@ -18,25 +18,25 @@ #include "cvc4_private.h" -#include <stdio.h> -#include <errno.h> -#include <time.h> - #include "lib/clock_gettime.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -#ifndef __APPLE__ -# warning This code assumes you're on Mac OS X, and you don't seem to be. You'll likely have problems. -#endif /* __APPLE__ */ +#if !(defined(__APPLE__) || defined(__WIN32__)) +# warning "This code assumes you're on Mac OS X or Win32, and you don't seem to be. You'll likely have problems." +#endif /* !(__APPLE__ || __WIN32__) */ +#ifdef __APPLE__ + +#include <stdio.h> +#include <errno.h> #include <mach/mach_time.h> static double s_clockconv = 0.0; -long clock_gettime(clockid_t which_clock, struct timespec *tp) { +long clock_gettime(clockid_t which_clock, struct timespec* tp) { if( s_clockconv == 0.0 ) { mach_timebase_info_data_t tb; kern_return_t err = mach_timebase_info(&tb); @@ -64,6 +64,24 @@ long clock_gettime(clockid_t which_clock, struct timespec *tp) { return 0; } +#else /* else we're __WIN32__ */ + +#include <time.h> +#include <windows.h> + +long clock_gettime(clockid_t which_clock, struct timespec* tp) { + if(tp != NULL) { + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + uint64_t nanos = ((((uint64_t)ft.dwHighDateTime) << 32) | ft.dwLowDateTime) * 100; + tp->tv_sec = nanos / 1000000000ul; + tp->tv_nsec = nanos % 1000000000ul; + } + return 0; +} + +#endif /* __APPLE__ / __WIN32__ */ + #ifdef __cplusplus }/* extern "C" */ #endif /* __cplusplus */ diff --git a/src/lib/clock_gettime.h b/src/lib/clock_gettime.h index ac4ca1f85..6a8dd57ff 100644 --- a/src/lib/clock_gettime.h +++ b/src/lib/clock_gettime.h @@ -30,13 +30,34 @@ /* otherwise, we have to define it */ +#ifdef __WIN32__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +struct timespec { + uint64_t tv_sec; + int32_t tv_nsec; +};/* struct timespec */ + +#ifdef __cplusplus +}/* extern "C" */ +#endif /* __cplusplus */ + +#else /* ! __WIN32__ */ + /* get timespec from <time.h> */ #include <time.h> +#endif /* __WIN32__ */ + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ +struct timespec; + typedef enum { CLOCK_REALTIME, CLOCK_MONOTONIC, @@ -44,7 +65,7 @@ typedef enum { CLOCK_MONOTONIC_HR } clockid_t; -long clock_gettime(clockid_t which_clock, struct timespec *tp); +long clock_gettime(clockid_t which_clock, struct timespec* tp); #ifdef __cplusplus }/* extern "C" */ @@ -52,4 +73,3 @@ long clock_gettime(clockid_t which_clock, struct timespec *tp); #endif /* HAVE_CLOCK_GETTIME */ #endif /*__CVC4__LIB__CLOCK_GETTIME_H */ - diff --git a/src/lib/ffs.c b/src/lib/ffs.c new file mode 100644 index 000000000..5c25211ce --- /dev/null +++ b/src/lib/ffs.c @@ -0,0 +1,40 @@ +/********************* */ +/*! \file ffs.c + ** \verbatim + ** Original author: mdeters + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of CVC4. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Replacement for ffs() for systems without it (like Win32) + ** + ** Replacement for ffs() for systems without it (like Win32). + **/ + +#include "cvc4_private.h" + +#include "lib/ffs.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +int ffs(int i) { + long mask = 0x1; + int pos = 1; + while(pos <= sizeof(int) * 8) { + if((mask & i) != 0) { + return pos; + } + ++pos; + mask <<= 1; + } + return 0; +} + +#ifdef __cplusplus +}/* extern "C" */ +#endif /* __cplusplus */ diff --git a/src/lib/ffs.h b/src/lib/ffs.h new file mode 100644 index 000000000..9b038d429 --- /dev/null +++ b/src/lib/ffs.h @@ -0,0 +1,42 @@ +/********************* */ +/*! \file ffs.h + ** \verbatim + ** Original author: mdeters + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of CVC4. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Replacement for ffs() for systems without it (like Win32) + ** + ** Replacement for ffs() for systems without it (like Win32). + **/ + +#include "cvc4_public.h" + +#ifndef __CVC4__LIB__FFS_H +#define __CVC4__LIB__FFS_H + +#ifdef HAVE_FFS + +// available in strings.h +#include <strings.h> + +#else /* ! HAVE_FFS */ + +#include "lib/replacements.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +int ffs(int i); + +#ifdef __cplusplus +}/* extern "C" */ +#endif /* __cplusplus */ + +#endif /* HAVE_FFS */ +#endif /* __CVC4__LIB__FFS_H */ diff --git a/src/lib/strtok_r.c b/src/lib/strtok_r.c new file mode 100644 index 000000000..b8df95359 --- /dev/null +++ b/src/lib/strtok_r.c @@ -0,0 +1,41 @@ +/********************* */ +/*! \file strtok_r.c + ** \verbatim + ** Original author: mdeters + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of CVC4. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Replacement for strtok_r() for systems without it (like Win32) + ** + ** Replacement for strtok_r() for systems without it (like Win32). + **/ + +#include "cvc4_private.h" + +#include "lib/strtok_r.h" +#include <stdio.h> +#include <string.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +char* strtok_r(char *str, const char *delim, char **saveptr) { + if(str == NULL) { + char* retval = strtok(*saveptr, delim); + *saveptr = retval + strlen(retval) + 1; + return retval; + } else { + char* retval = strtok(str, delim); + *saveptr = retval + strlen(retval) + 1; + return retval; + } +} + +#ifdef __cplusplus +}/* extern "C" */ +#endif /* __cplusplus */ diff --git a/src/lib/strtok_r.h b/src/lib/strtok_r.h new file mode 100644 index 000000000..6b3387e6b --- /dev/null +++ b/src/lib/strtok_r.h @@ -0,0 +1,42 @@ +/********************* */ +/*! \file strtok_r.h + ** \verbatim + ** Original author: mdeters + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of CVC4. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Replacement for strtok_r() for systems without it (like Win32) + ** + ** Replacement for strtok_r() for systems without it (like Win32). + **/ + +#include "cvc4_public.h" + +#ifndef __CVC4__LIB__STRTOK_R_H +#define __CVC4__LIB__STRTOK_R_H + +#ifdef HAVE_STRTOK_R + +// available in string.h +#include <string.h> + +#else /* ! HAVE_STRTOK_R */ + +#include "lib/replacements.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +char* strtok_r(char *str, const char *delim, char **saveptr); + +#ifdef __cplusplus +}/* extern "C" */ +#endif /* __cplusplus */ + +#endif /* HAVE_STRTOK_R */ +#endif /* __CVC4__LIB__STRTOK_R_H */ diff --git a/src/main/Makefile.am b/src/main/Makefile.am index 952951655..64a43eb02 100644 --- a/src/main/Makefile.am +++ b/src/main/Makefile.am @@ -41,9 +41,9 @@ pcvc4_LDADD += $(BOOST_THREAD_LIBS) -lpthread pcvc4_LDADD += $(BOOST_THREAD_LDFLAGS) if STATIC_BINARY -pcvc4_LINK = $(CXXLINK) -all-static +pcvc4_LINK = $(CXXLINK) -all-static $(pcvc4_LDFLAGS) else -pcvc4_LINK = $(CXXLINK) +pcvc4_LINK = $(CXXLINK) $(pcvc4_LDFLAGS) endif endif @@ -87,8 +87,8 @@ clean-local: rm -f $(BUILT_SOURCES) if STATIC_BINARY -cvc4_LINK = $(CXXLINK) -all-static +cvc4_LINK = $(CXXLINK) -all-static $(cvc4_LDFLAGS) else -cvc4_LINK = $(CXXLINK) +cvc4_LINK = $(CXXLINK) $(cvc4_LDFLAGS) endif diff --git a/src/main/command_executor.cpp b/src/main/command_executor.cpp index 14625f1d8..6a4e18b5b 100644 --- a/src/main/command_executor.cpp +++ b/src/main/command_executor.cpp @@ -48,7 +48,7 @@ bool CommandExecutor::doCommand(Command* cmd) return status; } else { - if(d_options[options::verbosity] > 0) { + if(d_options[options::verbosity] > 2) { *d_options[options::out] << "Invoking: " << *cmd << std::endl; } @@ -59,7 +59,7 @@ bool CommandExecutor::doCommand(Command* cmd) bool CommandExecutor::doCommandSingleton(Command *cmd) { bool status = true; - if(d_options[options::verbosity] >= 0) { + if(d_options[options::verbosity] >= -1) { status = smtEngineInvoke(&d_smtEngine, cmd, d_options[options::out]); } else { status = smtEngineInvoke(&d_smtEngine, cmd, NULL); diff --git a/src/main/driver_unified.cpp b/src/main/driver_unified.cpp index 741975b11..9fa40d3ab 100644 --- a/src/main/driver_unified.cpp +++ b/src/main/driver_unified.cpp @@ -239,7 +239,9 @@ int runCvc4(int argc, char* argv[], Options& opts) { InteractiveShell shell(*exprMgr, opts); Message() << Configuration::getPackageName() << " " << Configuration::getVersionString(); - if(Configuration::isSubversionBuild()) { + if(Configuration::isGitBuild()) { + Message() << " [" << Configuration::getGitId() << "]"; + } else if(Configuration::isSubversionBuild()) { Message() << " [" << Configuration::getSubversionId() << "]"; } Message() << (Configuration::isDebugBuild() ? " DEBUG" : "") diff --git a/src/main/options_handlers.h b/src/main/options_handlers.h index c2eb489ed..f14a67d5f 100644 --- a/src/main/options_handlers.h +++ b/src/main/options_handlers.h @@ -26,14 +26,20 @@ inline void showConfiguration(std::string option, SmtEngine* smt) { fputs(Configuration::about().c_str(), stdout); printf("\n"); printf("version : %s\n", Configuration::getVersionString().c_str()); - if(Configuration::isSubversionBuild()) { - printf("subversion : yes [%s r%u%s]\n", + if(Configuration::isGitBuild()) { + printf("scm : git [%s %s%s]\n", + Configuration::getGitBranchName(), + std::string(Configuration::getGitCommit()).substr(0, 8).c_str(), + Configuration::hasGitModifications() ? + " (with modifications)" : ""); + } else if(Configuration::isSubversionBuild()) { + printf("scm : svn [%s r%u%s]\n", Configuration::getSubversionBranchName(), Configuration::getSubversionRevision(), Configuration::hasSubversionModifications() ? " (with modifications)" : ""); } else { - printf("subversion : %s\n", Configuration::isSubversionBuild() ? "yes" : "no"); + printf("scm : no\n"); } printf("\n"); printf("library : %u.%u.%u\n", diff --git a/src/main/util.cpp b/src/main/util.cpp index d4d3e96d8..a6fcddf3b 100644 --- a/src/main/util.cpp +++ b/src/main/util.cpp @@ -19,10 +19,15 @@ #include <cerrno> #include <exception> #include <string.h> + +#ifndef __WIN32__ + #include <signal.h> #include <sys/resource.h> #include <unistd.h> +#endif /* __WIN32__ */ + #include "util/exception.h" #include "options/options.h" #include "util/statistics.h" @@ -44,9 +49,6 @@ namespace CVC4 { namespace main { -size_t cvc4StackSize; -void* cvc4StackBase; - /** * If true, will not spin on segfault even when CVC4_DEBUG is on. * Useful for nightly regressions, noninteractive performance runs @@ -54,6 +56,11 @@ void* cvc4StackBase; */ bool segvNoSpin = false; +#ifndef __WIN32__ + +size_t cvc4StackSize; +void* cvc4StackBase; + /** Handler for SIGXCPU, i.e., timeout. */ void timeout_handler(int sig, siginfo_t* info, void*) { fprintf(stderr, "CVC4 interrupted by timeout.\n"); @@ -150,10 +157,12 @@ void ill_handler(int sig, siginfo_t* info, void*) { #endif /* CVC4_DEBUG */ } +#endif /* __WIN32__ */ + static terminate_handler default_terminator; void cvc4unexpected() { -#ifdef CVC4_DEBUG +#if defined(CVC4_DEBUG) && !defined(__WIN32__) fprintf(stderr, "\n" "CVC4 threw an \"unexpected\" exception (one that wasn't properly " "specified\nin the throws() specifier for the throwing function)." @@ -214,6 +223,7 @@ void cvc4terminate() { /** Initialize the driver. Sets signal handlers for SIGINT and SIGSEGV. */ void cvc4_init() throw(Exception) { +#ifndef __WIN32__ stack_t ss; ss.ss_sp = malloc(SIGSTKSZ); if(ss.ss_sp == NULL) { @@ -272,6 +282,8 @@ void cvc4_init() throw(Exception) { throw Exception(string("sigaction(SIGILL) failure: ") + strerror(errno)); } +#endif /* __WIN32__ */ + set_unexpected(cvc4unexpected); default_terminator = set_terminate(cvc4terminate); } diff --git a/src/options/mkoptions b/src/options/mkoptions index 0632cb3f9..fa6c4c260 100755 --- a/src/options/mkoptions +++ b/src/options/mkoptions @@ -2,7 +2,7 @@ # # mkoptions # Morgan Deters <mdeters@cs.nyu.edu> for CVC4 -# Copyright (c) 2011-2012 The CVC4 Project +# Copyright (c) 2011-2013 The CVC4 Project # # The purpose of this script is to create options.{h,cpp} # from template files and a list of options. @@ -12,7 +12,7 @@ # mkoptions (template-file output-file)+ -t options.h-template options.cpp-template (options-file output-dir)+ # -copyright=2011-2012 +copyright=2011-2013 me=$(basename "$0") @@ -1314,7 +1314,8 @@ function output_module { /********************* */ /** $filename ** - ** Copyright $copyright The AcSys Group, New York University, and as below. + ** Copyright $copyright New York University and The University of Iowa, + ** and as below. ** ** This file automatically generated by: ** @@ -1496,7 +1497,8 @@ cat <<EOF /********************* */ /** $filename ** - ** Copyright $copyright The AcSys Group, New York University, and as below. + ** Copyright $copyright New York University and The University of Iowa, + ** and as below. ** ** This file automatically generated by: ** diff --git a/src/options/options.h b/src/options/options.h index 2d49765f3..5f17f5a5c 100644 --- a/src/options/options.h +++ b/src/options/options.h @@ -31,7 +31,7 @@ namespace CVC4 { namespace options { - class OptionsHolder; + struct OptionsHolder; }/* CVC4::options namespace */ class ExprStream; diff --git a/src/parser/antlr_input.cpp b/src/parser/antlr_input.cpp index 8987a7572..fbf2b8650 100644 --- a/src/parser/antlr_input.cpp +++ b/src/parser/antlr_input.cpp @@ -63,8 +63,13 @@ AntlrInputStream* AntlrInputStream::newFileInputStream(const std::string& name, bool useMmap) throw (InputStreamException) { +#ifdef _WIN32 + if(useMmap) { + useMmap = false; + } +#endif pANTLR3_INPUT_STREAM input = NULL; - if( useMmap ) { + if(useMmap) { input = MemoryMappedInputBufferNew(name); } else { // libantlr3c v3.2 isn't source-compatible with v3.4 @@ -74,7 +79,7 @@ AntlrInputStream::newFileInputStream(const std::string& name, input = antlr3FileStreamNew((pANTLR3_UINT8) name.c_str(), ANTLR3_ENC_8BIT); #endif /* CVC4_ANTLR3_OLD_INPUT_STREAM */ } - if( input == NULL ) { + if(input == NULL) { throw InputStreamException("Couldn't open file: " + name); } return new AntlrInputStream( name, input ); diff --git a/src/parser/bounded_token_buffer.cpp b/src/parser/bounded_token_buffer.cpp index 904f9a7fa..6a6ae8609 100644 --- a/src/parser/bounded_token_buffer.cpp +++ b/src/parser/bounded_token_buffer.cpp @@ -512,7 +512,7 @@ static pANTLR3_COMMON_TOKEN nextToken(pBOUNDED_TOKEN_BUFFER buffer) { } -/// Return a string that represents the name assoicated with the input source +/// Return a string that represents the name associated with the input source /// /// /param[in] is The ANTLR3_INT_STREAM interface that is representing this token stream. /// diff --git a/src/parser/cvc/Cvc.g b/src/parser/cvc/Cvc.g index 1af4799be..b8ec160e8 100644 --- a/src/parser/cvc/Cvc.g +++ b/src/parser/cvc/Cvc.g @@ -416,10 +416,8 @@ Expr addNots(ExprManager* em, size_t n, Expr e) { @header { /** - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University + ** This file is part of CVC4. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information. **/ diff --git a/src/parser/memory_mapped_input_buffer.cpp b/src/parser/memory_mapped_input_buffer.cpp index 9f72ac51c..f110b1145 100644 --- a/src/parser/memory_mapped_input_buffer.cpp +++ b/src/parser/memory_mapped_input_buffer.cpp @@ -18,10 +18,15 @@ #include <stdio.h> #include <stdint.h> +#include <antlr3input.h> + +#ifndef _WIN32 + #include <cerrno> #include <sys/mman.h> #include <sys/stat.h> -#include <antlr3input.h> + +#endif /* _WIN32 */ #include "parser/memory_mapped_input_buffer.h" #include "util/exception.h" @@ -31,6 +36,14 @@ namespace parser { extern "C" { +#ifdef _WIN32 + +pANTLR3_INPUT_STREAM MemoryMappedInputBufferNew(const std::string& filename) { + return 0; +} + +#else /* ! _WIN32 */ + static ANTLR3_UINT32 MemoryMapFile(pANTLR3_INPUT_STREAM input, const std::string& filename); @@ -112,6 +125,8 @@ void UnmapFile(pANTLR3_INPUT_STREAM input) { input->close(input); } +#endif /* _WIN32 */ + }/* extern "C" */ }/* CVC4::parser namespace */ diff --git a/src/parser/smt1/Smt1.g b/src/parser/smt1/Smt1.g index 6dade9530..f8331c899 100644 --- a/src/parser/smt1/Smt1.g +++ b/src/parser/smt1/Smt1.g @@ -31,10 +31,8 @@ options { @header { /** - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University + ** This file is part of CVC4. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information. **/ @@ -235,10 +233,10 @@ annotatedFormula[CVC4::Expr& expr] Expr op; /* Operator expression FIXME: move away kill it */ } : /* a built-in operator application */ - LPAREN_TOK builtinOp[kind] annotatedFormulas[args,expr] RPAREN_TOK + LPAREN_TOK builtinOp[kind] annotatedFormulas[args,expr] { if((kind == CVC4::kind::AND || kind == CVC4::kind::OR) && args.size() == 1) { /* Unary AND/OR can be replaced with the argument. - It just so happens expr should already by the only argument. */ + * It just so happens expr should already be the only argument. */ assert( expr == args[0] ); } else if( CVC4::kind::isAssociative(kind) && args.size() > EXPR_MANAGER->maxArity(kind) ) { @@ -253,6 +251,7 @@ annotatedFormula[CVC4::Expr& expr] expr = MK_EXPR(kind, args); } } + termAnnotation[expr]* RPAREN_TOK | /* A quantifier */ LPAREN_TOK @@ -261,12 +260,13 @@ annotatedFormula[CVC4::Expr& expr] ( LPAREN_TOK let_identifier[name,CHECK_NONE] t=sortSymbol RPAREN_TOK { args.push_back(PARSER_STATE->mkBoundVar(name, t)); } )+ - annotatedFormula[expr] RPAREN_TOK + annotatedFormula[expr] { args2.push_back( MK_EXPR( kind::BOUND_VAR_LIST, args ) ); args2.push_back(expr); expr = MK_EXPR(kind, args2); - PARSER_STATE->popScope(); } + termAnnotation[expr]* RPAREN_TOK + { PARSER_STATE->popScope(); } | /* A non-built-in function application */ @@ -275,9 +275,10 @@ annotatedFormula[CVC4::Expr& expr] // { isFunction(LT(2)->getText()) }? LPAREN_TOK parameterizedOperator[op] - annotatedFormulas[args,expr] RPAREN_TOK + annotatedFormulas[args,expr] // TODO: check arity { expr = MK_EXPR(op,args); } + termAnnotation[expr]* RPAREN_TOK | /* An ite expression */ LPAREN_TOK ITE_TOK @@ -286,9 +287,9 @@ annotatedFormula[CVC4::Expr& expr] annotatedFormula[expr] { args.push_back(expr); } annotatedFormula[expr] - { args.push_back(expr); } - RPAREN_TOK - { expr = MK_EXPR(CVC4::kind::ITE, args); } + { args.push_back(expr); + expr = MK_EXPR(CVC4::kind::ITE, args); } + termAnnotation[expr]* RPAREN_TOK | /* a let/flet binding */ LPAREN_TOK @@ -298,7 +299,7 @@ annotatedFormula[CVC4::Expr& expr] { PARSER_STATE->pushScope(); PARSER_STATE->defineVar(name,expr); } annotatedFormula[expr] - RPAREN_TOK + termAnnotation[expr]* RPAREN_TOK { PARSER_STATE->popScope(); } /* constants */ @@ -310,7 +311,7 @@ annotatedFormula[CVC4::Expr& expr] { // FIXME: This doesn't work because an SMT rational is not a // valid GMP rational string expr = MK_CONST( AntlrInput::tokenToRational($RATIONAL_TOK) ); } - | n = BITVECTOR_BV_CONST '[' size = NUMERAL_TOK ']' + | n = BITVECTOR_BV_CONST '[' size = NUMERAL_TOK ']' { expr = MK_CONST( AntlrInput::tokenToBitvector($n, $size) ); } // NOTE: Theory constants go here /* TODO: quantifiers, arithmetic constants */ @@ -320,7 +321,6 @@ annotatedFormula[CVC4::Expr& expr] | let_identifier[name,CHECK_DECLARED] | flet_identifier[name,CHECK_DECLARED] ) { expr = PARSER_STATE->getVariable(name); } - ; /** @@ -458,7 +458,7 @@ functionSymbol[CVC4::Expr& fun] * Matches an attribute name from the input (:attribute_name). */ attribute[std::string& s] - : ATTR_IDENTIFIER + : ATTR_IDENTIFIER { s = AntlrInput::tokenText($ATTR_IDENTIFIER); } ; @@ -555,28 +555,56 @@ status[ CVC4::BenchmarkStatus& status ] /** * Matches an annotation, which is an attribute name, with an optional user + * value. */ annotation[CVC4::Command*& smt_command] @init { - std::string key; + std::string key, value; smt_command = NULL; + std::vector<Expr> pats; + Expr pat; } - : attribute[key] - ( USER_VALUE - { std::string value = AntlrInput::tokenText($USER_VALUE); - assert(*value.begin() == '{'); - assert(*value.rbegin() == '}'); - // trim whitespace - value.erase(value.begin(), value.begin() + 1); - value.erase(value.begin(), std::find_if(value.begin(), value.end(), std::not1(std::ptr_fun<int, int>(std::isspace)))); - value.erase(value.end() - 1); - value.erase(std::find_if(value.rbegin(), value.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), value.end()); - smt_command = new SetInfoCommand(key.c_str() + 1, value); } - )? - { if(smt_command == NULL) { - smt_command = new EmptyCommand(std::string("annotation: ") + key); + : PATTERN_ANNOTATION_BEGIN + { PARSER_STATE->warning(":pat not supported here; ignored"); } + annotatedFormulas[pats,pat] '}' + | attribute[key] + ( userValue[value] + { smt_command = new SetInfoCommand(key.c_str() + 1, value); } + | { smt_command = new EmptyCommand(std::string("annotation: ") + key); } + ) + ; + +/** + * Matches an annotation, which is an attribute name, with an optional user + * value. + */ +termAnnotation[CVC4::Expr& expr] +@init { + std::string key, value; + std::vector<Expr> pats; + Expr pat; +} + : PATTERN_ANNOTATION_BEGIN annotatedFormulas[pats,pat] '}' + { if(expr.getKind() == kind::FORALL || expr.getKind() == kind::EXISTS) { + pat = MK_EXPR(kind::INST_PATTERN, pats); + if(expr.getNumChildren() == 3) { + // we have other user patterns attached to the quantifier + // already; add this one to the existing list + pats = expr[2].getChildren(); + pats.push_back(pat); + expr = MK_EXPR(expr.getKind(), expr[0], expr[1], MK_EXPR(kind::INST_PATTERN_LIST, pats)); + } else { + // this is the only user pattern for the quantifier + expr = MK_EXPR(expr.getKind(), expr[0], expr[1], MK_EXPR(kind::INST_PATTERN_LIST, pat)); + } + } else { + PARSER_STATE->warning(":pat only supported on quantifiers"); } } + | ':pat' + { PARSER_STATE->warning("expected an instantiation pattern after :pat"); } + | attribute[key] userValue[value]? + { PARSER_STATE->attributeNotSupported(key); } ; /** @@ -752,6 +780,23 @@ FLET_IDENTIFIER * only constraint imposed on a user-defined value is that it start * with an open brace and end with closed brace. */ +userValue[std::string& s] + : USER_VALUE + { s = AntlrInput::tokenText($USER_VALUE); + assert(*s.begin() == '{'); + assert(*s.rbegin() == '}'); + // trim whitespace + s.erase(s.begin(), s.begin() + 1); + s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace)))); + s.erase(s.end() - 1); + s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end()); + } + ; + +PATTERN_ANNOTATION_BEGIN + : ':pat' (' ' | '\t' | '\f' | '\r' | '\n')* '{' + ; + USER_VALUE : '{' ('\\{' | '\\}' | ~('{' | '}'))* '}' ; diff --git a/src/parser/smt2/Smt2.g b/src/parser/smt2/Smt2.g index 648666091..1ee288aa4 100644 --- a/src/parser/smt2/Smt2.g +++ b/src/parser/smt2/Smt2.g @@ -31,10 +31,8 @@ options { @header { /** - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University + ** This file is part of CVC4. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information. **/ diff --git a/src/parser/smt2/smt2_input.h b/src/parser/smt2/smt2_input.h index 62ed33632..62959c766 100644 --- a/src/parser/smt2/smt2_input.h +++ b/src/parser/smt2/smt2_input.h @@ -41,7 +41,7 @@ class Smt2Input : public AntlrInput { /** The ANTLR3 SMT2 lexer for the input. */ pSmt2Lexer d_pSmt2Lexer; - /** The ANTLR3 CVC parser for the input. */ + /** The ANTLR3 SMT2 parser for the input. */ pSmt2Parser d_pSmt2Parser; /** diff --git a/src/parser/tptp/Tptp.g b/src/parser/tptp/Tptp.g index 2180255ca..ec6868c5b 100644 --- a/src/parser/tptp/Tptp.g +++ b/src/parser/tptp/Tptp.g @@ -32,10 +32,8 @@ options { @header { /** - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University + ** This file is part of CVC4. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information. **/ diff --git a/src/parser/tptp/tptp.cpp b/src/parser/tptp/tptp.cpp index 1e40ea63f..59b1d205b 100644 --- a/src/parser/tptp/tptp.cpp +++ b/src/parser/tptp/tptp.cpp @@ -151,7 +151,7 @@ void Tptp::includeFile(std::string fileName){ if( d_tptpDir.empty() ){ parseError("Couldn't open included file: " + fileName - + " at " + currentDirFileName + " and the TPTP directory is not specified (environnement variable TPTP)"); + + " at " + currentDirFileName + " and the TPTP directory is not specified (environment variable TPTP)"); }; std::string tptpDirFileName = d_tptpDir + fileName; diff --git a/src/printer/cvc/cvc_printer.cpp b/src/printer/cvc/cvc_printer.cpp index e0d4656f4..0206c4252 100644 --- a/src/printer/cvc/cvc_printer.cpp +++ b/src/printer/cvc/cvc_printer.cpp @@ -21,7 +21,9 @@ #include "expr/command.h" #include "theory/substitutions.h" #include "smt/smt_engine.h" +#include "smt/options.h" #include "theory/model.h" +#include "theory/arrays/theory_arrays_rewriter.h" #include <iostream> #include <vector> @@ -813,21 +815,34 @@ void CvcPrinter::toStream(std::ostream& out, Model& m, const Command* c) const t theory::TheoryModel& tm = (theory::TheoryModel&) m; if(dynamic_cast<const DeclareTypeCommand*>(c) != NULL) { TypeNode tn = TypeNode::fromType( ((const DeclareTypeCommand*)c)->getType() ); - if( tn.isSort() ){ - // print the cardinality - if( tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ - out << "; cardinality of " << tn << " is " << (*tm.d_rep_set.d_type_reps.find(tn)).second.size() << std::endl; + if( options::modelUninterpDtEnum() && tn.isSort() && + tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ + out << "DATATYPE " << std::endl; + out << " " << dynamic_cast<const DeclareTypeCommand*>(c)->getSymbol() << " = "; + for( size_t i=0; i<(*tm.d_rep_set.d_type_reps.find(tn)).second.size(); i++ ){ + if (i>0) { + out << "| "; + } + out << (*tm.d_rep_set.d_type_reps.find(tn)).second[i] << " "; } - } - out << c << std::endl; - if( tn.isSort() ){ - // print the representatives - if( tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ - for( size_t i=0; i<(*tm.d_rep_set.d_type_reps.find(tn)).second.size(); i++ ){ - if( (*tm.d_rep_set.d_type_reps.find(tn)).second[i].isVar() ){ - out << (*tm.d_rep_set.d_type_reps.find(tn)).second[i] << " : " << tn << ";" << std::endl; - }else{ - out << "% rep: " << (*tm.d_rep_set.d_type_reps.find(tn)).second[i] << std::endl; + out << std::endl << "END;" << std::endl; + } else { + if( tn.isSort() ){ + // print the cardinality + if( tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ + out << "% cardinality of " << tn << " is " << (*tm.d_rep_set.d_type_reps.find(tn)).second.size() << std::endl; + } + } + out << c << std::endl; + if( tn.isSort() ){ + // print the representatives + if( tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ + for( size_t i=0; i<(*tm.d_rep_set.d_type_reps.find(tn)).second.size(); i++ ){ + if( (*tm.d_rep_set.d_type_reps.find(tn)).second[i].isVar() ){ + out << (*tm.d_rep_set.d_type_reps.find(tn)).second[i] << " : " << tn << ";" << std::endl; + }else{ + out << "% rep: " << (*tm.d_rep_set.d_type_reps.find(tn)).second[i] << std::endl; + } } } } @@ -850,7 +865,15 @@ void CvcPrinter::toStream(std::ostream& out, Model& m, const Command* c) const t }else{ out << tn; } - out << " = " << Node::fromExpr(tm.getSmtEngine()->getValue(n.toExpr())) << ";" << std::endl; + Node val = Node::fromExpr(tm.getSmtEngine()->getValue(n.toExpr())); + if( options::modelUninterpDtEnum() && val.getKind() == kind::STORE ) { + TypeNode tn = val[1].getType(); + if (tn.isSort() && tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ + Cardinality indexCard((*tm.d_rep_set.d_type_reps.find(tn)).second.size()); + val = theory::arrays::TheoryArraysRewriter::normalizeConstant( val, indexCard ); + } + } + out << " = " << val << ";" << std::endl; /* //for table format (work in progress) diff --git a/src/printer/smt2/smt2_printer.cpp b/src/printer/smt2/smt2_printer.cpp index 5821fbc77..8541ca6ae 100644 --- a/src/printer/smt2/smt2_printer.cpp +++ b/src/printer/smt2/smt2_printer.cpp @@ -27,8 +27,10 @@ #include "theory/substitutions.h" #include "util/language.h" #include "smt/smt_engine.h" +#include "smt/options.h" #include "theory/model.h" +#include "theory/arrays/theory_arrays_rewriter.h" using namespace std; @@ -541,25 +543,41 @@ void Smt2Printer::toStream(std::ostream& out, const CommandStatus* s) const thro }/* Smt2Printer::toStream(CommandStatus*) */ +void Smt2Printer::toStream(std::ostream& out, Model& m) const throw() { + out << "(model" << std::endl; + this->Printer::toStream(out, m); + out << ")" << std::endl; +} + + void Smt2Printer::toStream(std::ostream& out, Model& m, const Command* c) const throw() { theory::TheoryModel& tm = (theory::TheoryModel&) m; if(dynamic_cast<const DeclareTypeCommand*>(c) != NULL) { TypeNode tn = TypeNode::fromType( ((const DeclareTypeCommand*)c)->getType() ); - if( tn.isSort() ){ - //print the cardinality - if( tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ - out << "; cardinality of " << tn << " is " << (*tm.d_rep_set.d_type_reps.find(tn)).second.size() << std::endl; + if( options::modelUninterpDtEnum() && tn.isSort() && + tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ + out << "(declare-datatypes () ((" << dynamic_cast<const DeclareTypeCommand*>(c)->getSymbol() << " "; + for( size_t i=0; i<(*tm.d_rep_set.d_type_reps.find(tn)).second.size(); i++ ){ + out << "(" << (*tm.d_rep_set.d_type_reps.find(tn)).second[i] << ")"; } - } - out << c << std::endl; - if( tn.isSort() ){ - //print the representatives - if( tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ - for( size_t i=0; i<(*tm.d_rep_set.d_type_reps.find(tn)).second.size(); i++ ){ - if( (*tm.d_rep_set.d_type_reps.find(tn)).second[i].isVar() ){ - out << "(declare-fun " << (*tm.d_rep_set.d_type_reps.find(tn)).second[i] << " () " << tn << ")" << std::endl; - }else{ - out << "; rep: " << (*tm.d_rep_set.d_type_reps.find(tn)).second[i] << std::endl; + out << ")))" << std::endl; + } else { + if( tn.isSort() ){ + //print the cardinality + if( tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ + out << "; cardinality of " << tn << " is " << (*tm.d_rep_set.d_type_reps.find(tn)).second.size() << std::endl; + } + } + out << c << std::endl; + if( tn.isSort() ){ + //print the representatives + if( tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ + for( size_t i=0; i<(*tm.d_rep_set.d_type_reps.find(tn)).second.size(); i++ ){ + if( (*tm.d_rep_set.d_type_reps.find(tn)).second[i].isVar() ){ + out << "(declare-fun " << (*tm.d_rep_set.d_type_reps.find(tn)).second[i] << " () " << tn << ")" << std::endl; + }else{ + out << "; rep: " << (*tm.d_rep_set.d_type_reps.find(tn)).second[i] << std::endl; + } } } } @@ -576,6 +594,13 @@ void Smt2Printer::toStream(std::ostream& out, Model& m, const Command* c) const << " " << n.getType().getRangeType() << " " << val[1] << ")" << std::endl; } else { + if( options::modelUninterpDtEnum() && val.getKind() == kind::STORE ) { + TypeNode tn = val[1].getType(); + if (tn.isSort() && tm.d_rep_set.d_type_reps.find( tn )!=tm.d_rep_set.d_type_reps.end() ){ + Cardinality indexCard((*tm.d_rep_set.d_type_reps.find(tn)).second.size()); + val = theory::arrays::TheoryArraysRewriter::normalizeConstant( val, indexCard ); + } + } out << "(define-fun " << n << " () " << n.getType() << " " << val << ")" << std::endl; } diff --git a/src/printer/smt2/smt2_printer.h b/src/printer/smt2/smt2_printer.h index c6d932457..32a0c94ba 100644 --- a/src/printer/smt2/smt2_printer.h +++ b/src/printer/smt2/smt2_printer.h @@ -30,6 +30,7 @@ namespace smt2 { class Smt2Printer : public CVC4::Printer { void toStream(std::ostream& out, TNode n, int toDepth, bool types) const throw(); void toStream(std::ostream& out, Model& m, const Command* c) const throw(); + void toStream(std::ostream& out, Model& m) 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(); diff --git a/src/proof/proof_manager.cpp b/src/proof/proof_manager.cpp index d05fe24a7..c1351c6a2 100644 --- a/src/proof/proof_manager.cpp +++ b/src/proof/proof_manager.cpp @@ -26,7 +26,7 @@ namespace CVC4 { bool ProofManager::isInitialized = false; ProofManager* ProofManager::proofManager = NULL; -ProofManager::ProofManager(ProofFormat format = LFSC): +ProofManager::ProofManager(ProofFormat format): d_satProof(NULL), d_cnfProof(NULL), d_format(format) diff --git a/src/proof/proof_manager.h b/src/proof/proof_manager.h index 3bfff1456..91eb2ed99 100644 --- a/src/proof/proof_manager.h +++ b/src/proof/proof_manager.h @@ -52,7 +52,7 @@ class ProofManager { static ProofManager* proofManager; static bool isInitialized; - ProofManager(ProofFormat format); + ProofManager(ProofFormat format = LFSC); public: static ProofManager* currentPM(); diff --git a/src/proof/sat_proof.h b/src/proof/sat_proof.h index 324988585..ccbde6e80 100644 --- a/src/proof/sat_proof.h +++ b/src/proof/sat_proof.h @@ -160,8 +160,8 @@ protected: * Does a depth first search on removed literals and adds the literals * to be removed in the proper order to the stack. * - * @param lit the literal we are recusing on - * @param removedSet the previously computed set of redundantant literals + * @param lit the literal we are recursing on + * @param removedSet the previously computed set of redundant literals * @param removeStack the stack of literals in reverse order of resolution */ void removedDfs(::Minisat::Lit lit, LitSet* removedSet, LitVector& removeStack, LitSet& inClause, LitSet& seen); diff --git a/src/prop/bvminisat/Makefile b/src/prop/bvminisat/Makefile new file mode 100644 index 000000000..71888016d --- /dev/null +++ b/src/prop/bvminisat/Makefile @@ -0,0 +1,4 @@ +topdir = ../../.. +srcdir = src/prop/bvminisat + +include $(topdir)/Makefile.subdir diff --git a/src/prop/bvminisat/core/Solver.cc b/src/prop/bvminisat/core/Solver.cc index 978ac8d7b..68969c78b 100644 --- a/src/prop/bvminisat/core/Solver.cc +++ b/src/prop/bvminisat/core/Solver.cc @@ -32,7 +32,7 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #include "theory/interrupted.h" using namespace BVMinisat; -namespace CVC4 { +namespace BVMinisat { #define OUTPUT_TAG "bvminisat: [a=" << assumptions.size() << ",l=" << decisionLevel() << "] " diff --git a/src/prop/cnf_stream.cpp b/src/prop/cnf_stream.cpp index 9f2138e9d..89cd731e9 100644 --- a/src/prop/cnf_stream.cpp +++ b/src/prop/cnf_stream.cpp @@ -108,11 +108,10 @@ void TseitinCnfStream::ensureLiteral(TNode n) { Debug("cnf") << "ensureLiteral(" << n << ")" << endl; if(hasLiteral(n)) { SatLiteral lit = getLiteral(n); - LiteralToNodeMap::iterator i = d_literalToNodeMap.find(lit); - if(i == d_literalToNodeMap.end()) { + if(!d_literalToNodeMap.contains(lit)){ // Store backward-mappings - d_literalToNodeMap[lit] = n; - d_literalToNodeMap[~lit] = n.notNode(); + d_literalToNodeMap.insert(lit, n); + d_literalToNodeMap.insert(~lit, n.notNode()); } return; } @@ -140,8 +139,9 @@ void TseitinCnfStream::ensureLiteral(TNode n) { lit = toCNF(n, false); // Store backward-mappings - d_literalToNodeMap[lit] = n; - d_literalToNodeMap[~lit] = n.notNode(); + // These may already exist + d_literalToNodeMap.insert_safe(lit, n); + d_literalToNodeMap.insert_safe(~lit, n.notNode()); } else { // We have a theory atom or variable. lit = convertAtom(n); @@ -168,8 +168,8 @@ SatLiteral CnfStream::newLiteral(TNode node, bool theoryLiteral) { } else { lit = SatLiteral(d_satSolver->newVar(theoryLiteral)); } - d_nodeToLiteralMap[node] = lit; - d_nodeToLiteralMap[node.notNode()] = ~lit; + d_nodeToLiteralMap.insert(node, lit); + d_nodeToLiteralMap.insert(node.notNode(), ~lit); } else { lit = getLiteral(node); } @@ -178,8 +178,9 @@ SatLiteral CnfStream::newLiteral(TNode node, bool theoryLiteral) { if ( theoryLiteral || d_fullLitToNodeMap || ( CVC4_USE_REPLAY && options::replayLog() != NULL ) || (Dump.isOn("clauses")) ) { - d_literalToNodeMap[lit] = node; - d_literalToNodeMap[~lit] = node.notNode(); + + d_literalToNodeMap.insert_safe(lit, node); + d_literalToNodeMap.insert_safe(~lit, node.notNode()); } // If a theory literal, we pre-register it @@ -197,11 +198,8 @@ SatLiteral CnfStream::newLiteral(TNode node, bool theoryLiteral) { TNode CnfStream::getNode(const SatLiteral& literal) { Debug("cnf") << "getNode(" << literal << ")" << endl; - LiteralToNodeMap::iterator find = d_literalToNodeMap.find(literal); - Assert(find != d_literalToNodeMap.end()); - Assert(d_nodeToLiteralMap.find((*find).second) != d_nodeToLiteralMap.end()); - Debug("cnf") << "getNode(" << literal << ") => " << (*find).second << endl; - return (*find).second; + Debug("cnf") << "getNode(" << literal << ") => " << d_literalToNodeMap[literal] << endl; + return d_literalToNodeMap[literal]; } void CnfStream::getBooleanVariables(std::vector<TNode>& outputVariables) const { @@ -229,10 +227,9 @@ SatLiteral CnfStream::convertAtom(TNode node) { } SatLiteral CnfStream::getLiteral(TNode node) { - NodeToLiteralMap::iterator find = d_nodeToLiteralMap.find(node); Assert(!node.isNull(), "CnfStream: can't getLiteral() of null node"); - Assert(find != d_nodeToLiteralMap.end(), "Literal not in the CNF Cache: %s\n", node.toString().c_str()); - SatLiteral literal = (*find).second; + Assert(d_nodeToLiteralMap.contains(node), "Literal not in the CNF Cache: %s\n", node.toString().c_str()); + SatLiteral literal = d_nodeToLiteralMap[node]; Debug("cnf") << "CnfStream::getLiteral(" << node << ") => " << literal << std::endl; return literal; } diff --git a/src/prop/cnf_stream.h b/src/prop/cnf_stream.h index 6ab639712..042cccd56 100644 --- a/src/prop/cnf_stream.h +++ b/src/prop/cnf_stream.h @@ -29,6 +29,7 @@ #include "prop/theory_proxy.h" #include "prop/registrar.h" #include "context/cdlist.h" +#include "context/cdinsert_hashmap.h" #include <ext/hash_map> @@ -47,10 +48,10 @@ class CnfStream { public: /** Cache of what nodes have been registered to a literal. */ - typedef context::CDHashMap<SatLiteral, TNode, SatLiteralHashFunction> LiteralToNodeMap; + typedef context::CDInsertHashMap<SatLiteral, TNode, SatLiteralHashFunction> LiteralToNodeMap; /** Cache of what literals have been registered to a node. */ - typedef context::CDHashMap<Node, SatLiteral, NodeHashFunction> NodeToLiteralMap; + typedef context::CDInsertHashMap<Node, SatLiteral, NodeHashFunction> NodeToLiteralMap; protected: diff --git a/src/prop/sat_solver.h b/src/prop/sat_solver.h index e5d876b48..b4807b021 100644 --- a/src/prop/sat_solver.h +++ b/src/prop/sat_solver.h @@ -130,8 +130,6 @@ public: };/* class DPLLSatSolverInterface */ -}/* CVC4::prop namespace */ - inline std::ostream& operator <<(std::ostream& out, prop::SatLiteral lit) { out << lit.toString(); return out; @@ -167,6 +165,7 @@ inline std::ostream& operator <<(std::ostream& out, prop::SatValue val) { return out; } +}/* CVC4::prop namespace */ }/* CVC4 namespace */ #endif /* __CVC4__PROP__SAT_MODULE_H */ diff --git a/src/smt/options b/src/smt/options index fc5ccf4c4..2680f4105 100644 --- a/src/smt/options +++ b/src/smt/options @@ -54,6 +54,8 @@ common-option incrementalSolving incremental -i --incremental bool option abstractValues abstract-values --abstract-values bool :default false in models, output arrays (and in future, maybe others) using abstract values, as required by the SMT-LIB standard +option modelUninterpDtEnum --model-u-dt-enum bool :default false + in models, output uninterpreted sorts as datatype enumerations option - regular-output-channel argument :handler CVC4::smt::setRegularOutputChannel :handler-include "smt/options_handlers.h" set the regular output channel of the solver diff --git a/src/smt/options_handlers.h b/src/smt/options_handlers.h index a3065f29b..a0a6429a8 100644 --- a/src/smt/options_handlers.h +++ b/src/smt/options_handlers.h @@ -23,6 +23,7 @@ #include "util/dump.h" #include "smt/modal_exception.h" #include "smt/smt_engine.h" +#include "lib/strtok_r.h" #include <cerrno> #include <cstring> diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp index af02c5186..8eb6664ca 100644 --- a/src/smt/smt_engine.cpp +++ b/src/smt/smt_engine.cpp @@ -36,6 +36,7 @@ #include "expr/metakind.h" #include "expr/node_builder.h" #include "expr/node.h" +#include "expr/node_self_iterator.h" #include "prop/prop_engine.h" #include "smt/modal_exception.h" #include "smt/smt_engine.h" @@ -111,7 +112,11 @@ struct SmtEngineStatistics { TimerStat d_rewriteBooleanTermsTime; /** time spent in non-clausal simplification */ TimerStat d_nonclausalSimplificationTime; - /** Num of constant propagations found during nonclausal simp */ + /** time spent in miplib pass */ + TimerStat d_miplibPassTime; + /** number of assertions removed by miplib pass */ + IntStat d_numMiplibAssertionsRemoved; + /** number of constant propagations found during nonclausal simp */ IntStat d_numConstantProps; /** time spent in static learning */ TimerStat d_staticLearningTime; @@ -136,6 +141,8 @@ struct SmtEngineStatistics { d_definitionExpansionTime("smt::SmtEngine::definitionExpansionTime"), d_rewriteBooleanTermsTime("smt::SmtEngine::rewriteBooleanTermsTime"), d_nonclausalSimplificationTime("smt::SmtEngine::nonclausalSimplificationTime"), + d_miplibPassTime("smt::SmtEngine::miplibPassTime"), + d_numMiplibAssertionsRemoved("smt::SmtEngine::numMiplibAssertionsRemoved", 0), d_numConstantProps("smt::SmtEngine::numConstantProps", 0), d_staticLearningTime("smt::SmtEngine::staticLearningTime"), d_simpITETime("smt::SmtEngine::simpITETime"), @@ -150,6 +157,8 @@ struct SmtEngineStatistics { StatisticsRegistry::registerStat(&d_definitionExpansionTime); StatisticsRegistry::registerStat(&d_rewriteBooleanTermsTime); StatisticsRegistry::registerStat(&d_nonclausalSimplificationTime); + StatisticsRegistry::registerStat(&d_miplibPassTime); + StatisticsRegistry::registerStat(&d_numMiplibAssertionsRemoved); StatisticsRegistry::registerStat(&d_numConstantProps); StatisticsRegistry::registerStat(&d_staticLearningTime); StatisticsRegistry::registerStat(&d_simpITETime); @@ -166,6 +175,8 @@ struct SmtEngineStatistics { StatisticsRegistry::unregisterStat(&d_definitionExpansionTime); StatisticsRegistry::unregisterStat(&d_rewriteBooleanTermsTime); StatisticsRegistry::unregisterStat(&d_nonclausalSimplificationTime); + StatisticsRegistry::unregisterStat(&d_miplibPassTime); + StatisticsRegistry::unregisterStat(&d_numMiplibAssertionsRemoved); StatisticsRegistry::unregisterStat(&d_numConstantProps); StatisticsRegistry::unregisterStat(&d_staticLearningTime); StatisticsRegistry::unregisterStat(&d_simpITETime); @@ -210,6 +221,8 @@ class SmtEnginePrivate : public NodeManagerListener { /** A circuit propagator for non-clausal propositional deduction */ booleans::CircuitPropagator d_propagator; + bool d_propagatorNeedsFinish; + std::vector<Node> d_boolVars; /** Assertions to push to sat */ vector<Node> d_assertionsToCheck; @@ -333,6 +346,14 @@ private: void constrainSubtypes(TNode n, std::vector<Node>& assertions) throw(); + // trace nodes back to their assertions using CircuitPropagator's BackEdgesMap + void traceBackToAssertions(const std::vector<Node>& nodes, std::vector<TNode>& assertions); + // remove conjuncts in toRemove from conjunction n; return # of removed conjuncts + size_t removeFromConjunction(Node& n, const std::hash_set<unsigned>& toRemove); + + // scrub miplib encodings + void doMiplibTrick(); + /** * Perform non-clausal simplification of a Node. This involves * Theory implementations, but does NOT involve the SAT solver in @@ -351,6 +372,7 @@ public: d_realAssertionsEnd(0), d_booleanTermConverter(d_smt), d_propagator(d_nonClausalLearnedLiterals, true, true), + d_propagatorNeedsFinish(false), d_assertionsToCheck(), d_fakeContext(), d_abstractValueMap(&d_fakeContext), @@ -366,6 +388,10 @@ public: } ~SmtEnginePrivate() { + if(d_propagatorNeedsFinish) { + d_propagator.finish(); + d_propagatorNeedsFinish = false; + } d_smt.d_nodeManager->unsubscribeEvents(this); } @@ -393,10 +419,13 @@ public: n.toExpr(), n.getType().toType()); d_smt.addToModelCommandAndDump(c, isGlobal); + if(n.getType().isBoolean() && !options::incrementalSolving()) { + d_boolVars.push_back(n); + } } void nmNotifyNewSkolem(TNode n, const std::string& comment, bool isGlobal) { - std::string id = n.getAttribute(expr::VarNameAttr()); + string id = n.getAttribute(expr::VarNameAttr()); DeclareFunctionCommand c(id, n.toExpr(), n.getType().toType()); @@ -404,6 +433,9 @@ public: Dump("skolems") << CommentCommand(id + " is " + comment); } d_smt.addToModelCommandAndDump(c, isGlobal, false, "skolems"); + if(n.getType().isBoolean() && !options::incrementalSolving()) { + d_boolVars.push_back(n); + } } Node applySubstitutions(TNode node) const { @@ -510,8 +542,6 @@ public: }/* namespace CVC4::smt */ -using namespace CVC4::smt; - SmtEngine::SmtEngine(ExprManager* em) throw() : d_context(em->getContext()), d_userLevels(), @@ -627,17 +657,17 @@ void SmtEngine::finalOptionsAreSet() { if(options::checkModels()) { if(! options::produceModels()) { - Notice() << "SmtEngine: turning on produce-models to support check-model" << std::endl; + Notice() << "SmtEngine: turning on produce-models to support check-model" << endl; setOption("produce-models", SExpr("true")); } if(! options::interactive()) { - Notice() << "SmtEngine: turning on interactive-mode to support check-model" << std::endl; + Notice() << "SmtEngine: turning on interactive-mode to support check-model" << endl; setOption("interactive-mode", SExpr("true")); } } if(options::produceAssignments() && !options::produceModels()) { - Notice() << "SmtEngine: turning on produce-models to support produce-assignments" << std::endl; + Notice() << "SmtEngine: turning on produce-models to support produce-assignments" << endl; setOption("produce-models", SExpr("true")); } @@ -788,15 +818,15 @@ void SmtEngine::setLogicInternal() throw() { // by default, symmetry breaker is on only for QF_UF if(! options::ufSymmetryBreaker.wasSetByUser()) { bool qf_uf = d_logic.isPure(THEORY_UF) && !d_logic.isQuantified(); - Trace("smt") << "setting uf symmetry breaker to " << qf_uf << std::endl; + Trace("smt") << "setting uf symmetry breaker to " << qf_uf << endl; options::ufSymmetryBreaker.set(qf_uf); } // by default, nonclausal simplification is off for QF_SAT and for quantifiers if(! options::simplificationMode.wasSetByUser()) { bool qf_sat = d_logic.isPure(THEORY_BOOL) && !d_logic.isQuantified(); bool quantifiers = d_logic.isQuantified(); - Trace("smt") << "setting simplification mode to <" << d_logic.getLogicString() << "> " << (!qf_sat && !quantifiers) << std::endl; - //simplifaction=none works better for SMT LIB benchmarks with quantifiers, not others + Trace("smt") << "setting simplification mode to <" << d_logic.getLogicString() << "> " << (!qf_sat && !quantifiers) << endl; + //simplification=none works better for SMT LIB benchmarks with quantifiers, not others //options::simplificationMode.set(qf_sat || quantifiers ? SIMPLIFICATION_MODE_NONE : SIMPLIFICATION_MODE_BATCH); options::simplificationMode.set(qf_sat ? SIMPLIFICATION_MODE_NONE : SIMPLIFICATION_MODE_BATCH); } @@ -812,14 +842,14 @@ void SmtEngine::setLogicInternal() throw() { bool iteSimp = !d_logic.isQuantified() && ((d_logic.isPure(THEORY_ARITH) && d_logic.isLinear() && !d_logic.isDifferenceLogic() && !d_logic.areRealsUsed()) || (d_logic.isTheoryEnabled(THEORY_ARRAY) && d_logic.isTheoryEnabled(THEORY_UF) && d_logic.isTheoryEnabled(THEORY_BV))); - Trace("smt") << "setting ite simplification to " << iteSimp << std::endl; + Trace("smt") << "setting ite simplification to " << iteSimp << endl; options::doITESimp.set(iteSimp); } // Turn on multiple-pass non-clausal simplification for QF_AUFBV if(! options::repeatSimp.wasSetByUser()) { bool repeatSimp = !d_logic.isQuantified() && (d_logic.isTheoryEnabled(THEORY_ARRAY) && d_logic.isTheoryEnabled(THEORY_UF) && d_logic.isTheoryEnabled(THEORY_BV)); - Trace("smt") << "setting repeat simplification to " << repeatSimp << std::endl; + Trace("smt") << "setting repeat simplification to " << repeatSimp << endl; options::repeatSimp.set(repeatSimp); } // Turn on unconstrained simplification for QF_AUFBV @@ -828,24 +858,24 @@ void SmtEngine::setLogicInternal() throw() { // bool uncSimp = false && !qf_sat && !options::incrementalSolving(); bool uncSimp = !options::incrementalSolving() && !d_logic.isQuantified() && !options::produceModels() && !options::checkModels() && (d_logic.isTheoryEnabled(THEORY_ARRAY) && d_logic.isTheoryEnabled(THEORY_BV)); - Trace("smt") << "setting unconstrained simplification to " << uncSimp << std::endl; + Trace("smt") << "setting unconstrained simplification to " << uncSimp << endl; options::unconstrainedSimp.set(uncSimp); } // Unconstrained simp currently does *not* support model generation if (options::unconstrainedSimp.wasSetByUser() && options::unconstrainedSimp()) { if (options::produceModels()) { - Notice() << "SmtEngine: turning off produce-models to support unconstrainedSimp" << std::endl; + Notice() << "SmtEngine: turning off produce-models to support unconstrainedSimp" << endl; setOption("produce-models", SExpr("false")); } if (options::checkModels()) { - Notice() << "SmtEngine: turning off check-models to support unconstrainedSimp" << std::endl; + Notice() << "SmtEngine: turning off check-models to support unconstrainedSimp" << endl; setOption("check-models", SExpr("false")); } } // Turn on arith rewrite equalities only for pure arithmetic if(! options::arithRewriteEq.wasSetByUser()) { bool arithRewriteEq = d_logic.isPure(THEORY_ARITH) && !d_logic.isQuantified(); - Trace("smt") << "setting arith rewrite equalities " << arithRewriteEq << std::endl; + Trace("smt") << "setting arith rewrite equalities " << arithRewriteEq << endl; options::arithRewriteEq.set(arithRewriteEq); } if(! options::arithHeuristicPivots.wasSetByUser()) { @@ -857,7 +887,7 @@ void SmtEngine::setLogicInternal() throw() { heuristicPivots = 0; } } - Trace("smt") << "setting arithHeuristicPivots " << heuristicPivots << std::endl; + Trace("smt") << "setting arithHeuristicPivots " << heuristicPivots << endl; options::arithHeuristicPivots.set(heuristicPivots); } if(! options::arithPivotThreshold.wasSetByUser()){ @@ -867,7 +897,7 @@ void SmtEngine::setLogicInternal() throw() { pivotThreshold = 16; } } - Trace("smt") << "setting arith arithPivotThreshold " << pivotThreshold << std::endl; + Trace("smt") << "setting arith arithPivotThreshold " << pivotThreshold << endl; options::arithPivotThreshold.set(pivotThreshold); } if(! options::arithStandardCheckVarOrderPivots.wasSetByUser()){ @@ -875,7 +905,7 @@ void SmtEngine::setLogicInternal() throw() { if(d_logic.isPure(THEORY_ARITH) && !d_logic.isQuantified()){ varOrderPivots = 200; } - Trace("smt") << "setting arithStandardCheckVarOrderPivots " << varOrderPivots << std::endl; + Trace("smt") << "setting arithStandardCheckVarOrderPivots " << varOrderPivots << endl; options::arithStandardCheckVarOrderPivots.set(varOrderPivots); } // Turn off early theory preprocessing if arithRewriteEq is on @@ -934,7 +964,7 @@ void SmtEngine::setLogicInternal() throw() { ? true : false ); - Trace("smt") << "setting decision mode to " << decMode << std::endl; + Trace("smt") << "setting decision mode to " << decMode << endl; options::decisionMode.set(decMode); options::decisionStopOnly.set(stoponly); } @@ -942,7 +972,7 @@ void SmtEngine::setLogicInternal() throw() { //for finite model finding if( ! options::instWhenMode.wasSetByUser()){ if( options::fmfInstEngine() ){ - Trace("smt") << "setting inst when mode to LAST_CALL" << std::endl; + Trace("smt") << "setting inst when mode to LAST_CALL" << endl; options::instWhenMode.set( INST_WHEN_LAST_CALL ); } } @@ -955,11 +985,11 @@ void SmtEngine::setLogicInternal() throw() { } else if (options::minisatUseElim()) { if (options::produceModels()) { - Notice() << "SmtEngine: turning off produce-models to support minisatUseElim" << std::endl; + Notice() << "SmtEngine: turning off produce-models to support minisatUseElim" << endl; setOption("produce-models", SExpr("false")); } if (options::checkModels()) { - Notice() << "SmtEngine: turning off check-models to support minisatUseElim" << std::endl; + Notice() << "SmtEngine: turning off check-models to support minisatUseElim" << endl; setOption("check-models", SExpr("false")); } } @@ -974,11 +1004,11 @@ void SmtEngine::setLogicInternal() throw() { if (d_logic.isTheoryEnabled(theory::THEORY_ARITH) && !d_logic.isLinear()) { if (options::produceModels()) { - Warning() << "SmtEngine: turning off produce-models because unsupported for nonlinear arith" << std::endl; + Warning() << "SmtEngine: turning off produce-models because unsupported for nonlinear arith" << endl; setOption("produce-models", SExpr("false")); } if (options::checkModels()) { - Warning() << "SmtEngine: turning off check-models because unsupported for nonlinear arith" << std::endl; + Warning() << "SmtEngine: turning off check-models because unsupported for nonlinear arith" << endl; setOption("check-models", SExpr("false")); } } @@ -999,7 +1029,7 @@ void SmtEngine::setInfo(const std::string& key, const CVC4::SExpr& value) Trace("smt") << "SMT setInfo(" << key << ", " << value << ")" << endl; if(Dump.isOn("benchmark")) { if(key == "status") { - std::string s = value.getValue(); + string s = value.getValue(); BenchmarkStatus status = (s == "sat") ? SMT_SATISFIABLE : ((s == "unsat") ? SMT_UNSATISFIABLE : SMT_UNKNOWN); @@ -1179,7 +1209,7 @@ void SmtEngine::defineFunction(Expr func, // Permit (check-sat) (define-fun ...) (get-value ...) sequences. // Otherwise, (check-sat) (get-value ((! foo :named bar))) breaks // d_haveAdditions = true; - Debug("smt") << "definedFunctions insert " << funcNode << " " << formNode << std::endl; + Debug("smt") << "definedFunctions insert " << funcNode << " " << formNode << endl; d_definedFunctions->insert(funcNode, def); } @@ -1189,7 +1219,7 @@ Node SmtEnginePrivate::getBVDivByZero(Kind k, unsigned width) { if (k == kind::BITVECTOR_UDIV) { if (d_BVDivByZero.find(width) == d_BVDivByZero.end()) { // lazily create the function symbols - std::ostringstream os; + ostringstream os; os << "BVUDivByZero_" << width; Node divByZero = nm->mkSkolem(os.str(), nm->mkFunctionType(nm->mkBitVectorType(width), nm->mkBitVectorType(width)), @@ -1200,7 +1230,7 @@ Node SmtEnginePrivate::getBVDivByZero(Kind k, unsigned width) { } else if (k == kind::BITVECTOR_UREM) { if (d_BVRemByZero.find(width) == d_BVRemByZero.end()) { - std::ostringstream os; + ostringstream os; os << "BVURemByZero_" << width; Node divByZero = nm->mkSkolem(os.str(), nm->mkFunctionType(nm->mkBitVectorType(width), nm->mkBitVectorType(width)), @@ -1240,7 +1270,7 @@ Node SmtEnginePrivate::expandDefinitions(TNode n, hash_map<Node, Node, NodeHashF if(i != d_smt.d_definedFunctions->end()) { // replacement must be closed if((*i).second.getFormals().size() > 0) { - throw TypeCheckingException(n.toExpr(), std::string("Defined function requires arguments: `") + n.toString() + "'"); + throw TypeCheckingException(n.toExpr(), string("Defined function requires arguments: `") + n.toString() + "'"); } // don't bother putting in the cache return (*i).second.getFormula(); @@ -1269,9 +1299,9 @@ Node SmtEnginePrivate::expandDefinitions(TNode n, hash_map<Node, Node, NodeHashF break; } - case kind::BITVECTOR_UDIV: - case kind::BITVECTOR_UREM: { - node = expandBVDivByZero(node); + case kind::BITVECTOR_UDIV: + case kind::BITVECTOR_UREM: { + node = expandBVDivByZero(node); break; } case kind::DIVISION: { @@ -1343,7 +1373,7 @@ Node SmtEnginePrivate::expandDefinitions(TNode n, hash_map<Node, Node, NodeHashF Debug("expand") << " : \"" << name << "\"" << endl; } if(i == d_smt.d_definedFunctions->end()) { - throw TypeCheckingException(n.toExpr(), std::string("Undefined function: `") + func.toString() + "'"); + throw TypeCheckingException(n.toExpr(), string("Undefined function: `") + func.toString() + "'"); } if(Debug.isOn("expand")) { Debug("expand") << " defn: " << def.getFunction() << endl @@ -1412,16 +1442,16 @@ static bool containsQuantifiers(Node n) { } Node SmtEnginePrivate::preSkolemizeQuantifiers( Node n, bool polarity, std::vector< Node >& fvs ){ - Trace("pre-sk") << "Pre-skolem " << n << " " << polarity << " " << fvs.size() << std::endl; + Trace("pre-sk") << "Pre-skolem " << n << " " << polarity << " " << fvs.size() << endl; if( n.getKind()==kind::NOT ){ Node nn = preSkolemizeQuantifiers( n[0], !polarity, fvs ); return nn.negate(); }else if( n.getKind()==kind::FORALL ){ if( polarity ){ - std::vector< Node > children; + vector< Node > children; children.push_back( n[0] ); //add children to current scope - std::vector< Node > fvss; + vector< Node > fvss; fvss.insert( fvss.begin(), fvs.begin(), fvs.end() ); for( int i=0; i<(int)n[0].getNumChildren(); i++ ){ fvss.push_back( n[0][i] ); @@ -1437,13 +1467,13 @@ Node SmtEnginePrivate::preSkolemizeQuantifiers( Node n, bool polarity, std::vect //process body Node nn = preSkolemizeQuantifiers( n[1], polarity, fvs ); //now, substitute skolems for the variables - std::vector< TypeNode > argTypes; + vector< TypeNode > argTypes; for( int i=0; i<(int)fvs.size(); i++ ){ argTypes.push_back( fvs[i].getType() ); } //calculate the variables and substitution - std::vector< Node > vars; - std::vector< Node > subs; + vector< Node > vars; + vector< Node > subs; for( int i=0; i<(int)n[0].getNumChildren(); i++ ){ vars.push_back( n[0][i] ); } @@ -1456,7 +1486,7 @@ Node SmtEnginePrivate::preSkolemizeQuantifiers( Node n, bool polarity, std::vect TypeNode typ = NodeManager::currentNM()->mkFunctionType( argTypes, n[0][i].getType() ); Node op = NodeManager::currentNM()->mkSkolem( "skop_$$", typ, "op created during pre-skolemization" ); //DOTHIS: set attribute on op, marking that it should not be selected as trigger - std::vector< Node > funcArgs; + vector< Node > funcArgs; funcArgs.push_back( op ); funcArgs.insert( funcArgs.end(), fvs.begin(), fvs.end() ); subs.push_back( NodeManager::currentNM()->mkNode( kind::APPLY_UF, funcArgs ) ); @@ -1496,7 +1526,7 @@ Node SmtEnginePrivate::preSkolemizeQuantifiers( Node n, bool polarity, std::vect return preSkolemizeQuantifiers( nn, polarity, fvs ); }else{ Assert( n.getKind() == kind::AND || n.getKind() == kind::OR ); - std::vector< Node > children; + vector< Node > children; for( int i=0; i<(int)n.getNumChildren(); i++ ){ children.push_back( preSkolemizeQuantifiers( n[i], polarity, fvs ) ); } @@ -1545,7 +1575,7 @@ void SmtEnginePrivate::staticLearning() { static void dumpAssertions(const char* key, const std::vector<Node>& assertionList) { if( Dump.isOn("assertions") && - Dump.isOn(std::string("assertions:") + key) ) { + Dump.isOn(string("assertions:") + key) ) { // Push the simplified assertions to the dump output stream for(unsigned i = 0; i < assertionList.size(); ++ i) { TNode n = assertionList[i]; @@ -1562,6 +1592,10 @@ bool SmtEnginePrivate::nonClausalSimplify() { Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify()" << endl; + if(d_propagatorNeedsFinish) { + d_propagator.finish(); + d_propagatorNeedsFinish = false; + } d_propagator.initialize(); // Assert all the assertions to the propagator @@ -1581,7 +1615,7 @@ bool SmtEnginePrivate::nonClausalSimplify() { << "conflict in non-clausal propagation" << endl; d_assertionsToPreprocess.clear(); d_assertionsToCheck.push_back(NodeManager::currentNM()->mkConst<bool>(false)); - d_propagator.finish(); + d_propagatorNeedsFinish = true; return false; } @@ -1616,7 +1650,7 @@ bool SmtEnginePrivate::nonClausalSimplify() { << d_nonClausalLearnedLiterals[i] << endl; d_assertionsToPreprocess.clear(); d_assertionsToCheck.push_back(NodeManager::currentNM()->mkConst<bool>(false)); - d_propagator.finish(); + d_propagatorNeedsFinish = true; return false; } } @@ -1648,7 +1682,7 @@ bool SmtEnginePrivate::nonClausalSimplify() { << learnedLiteral << endl; d_assertionsToPreprocess.clear(); d_assertionsToCheck.push_back(NodeManager::currentNM()->mkConst<bool>(false)); - d_propagator.finish(); + d_propagatorNeedsFinish = true; return false; default: if (d_doConstantProp && learnedLiteral.getKind() == kind::EQUAL && (learnedLiteral[0].isConst() || learnedLiteral[1].isConst())) { @@ -1718,6 +1752,17 @@ bool SmtEnginePrivate::nonClausalSimplify() { // Resize the learnt d_nonClausalLearnedLiterals.resize(j); + //must add substitutions to model + TheoryModel* m = d_smt.d_theoryEngine->getModel(); + if(m != NULL) { + for( SubstitutionMap::iterator pos = d_topLevelSubstitutions.begin(); pos != d_topLevelSubstitutions.end(); ++pos) { + Node n = (*pos).first; + Node v = (*pos).second; + Trace("model") << "Add substitution : " << n << " " << v << std::endl; + m->addSubstitution( n, v ); + } + } + hash_set<TNode, TNodeHashFunction> s; for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) { Node assertion = d_assertionsToPreprocess[i]; @@ -1816,7 +1861,7 @@ bool SmtEnginePrivate::nonClausalSimplify() { Rewriter::rewrite(Node(learnedBuilder)); } - d_propagator.finish(); + d_propagatorNeedsFinish = true; return true; } @@ -1898,6 +1943,366 @@ void SmtEnginePrivate::constrainSubtypes(TNode top, std::vector<Node>& assertion } while(! worklist.empty()); } +void SmtEnginePrivate::traceBackToAssertions(const std::vector<Node>& nodes, std::vector<TNode>& assertions) { + const booleans::CircuitPropagator::BackEdgesMap& backEdges = d_propagator.getBackEdges(); + for(vector<Node>::const_iterator i = nodes.begin(); i != nodes.end(); ++i) { + booleans::CircuitPropagator::BackEdgesMap::const_iterator j = backEdges.find(*i); + // term must appear in map, otherwise how did we get here?! + Assert(j != backEdges.end()); + // if term maps to empty, that means it's a top-level assertion + if(!(*j).second.empty()) { + traceBackToAssertions((*j).second, assertions); + } else { + assertions.push_back(*i); + } + } +} + +size_t SmtEnginePrivate::removeFromConjunction(Node& n, const std::hash_set<unsigned>& toRemove) { + Assert(n.getKind() == kind::AND); + Node trueNode = NodeManager::currentNM()->mkConst(true); + size_t removals = 0; + for(Node::iterator j = n.begin(); j != n.end(); ++j) { + size_t subremovals = 0; + Node sub = *j; + if(toRemove.find(sub.getId()) != toRemove.end() || + (sub.getKind() == kind::AND && (subremovals = removeFromConjunction(sub, toRemove)) > 0)) { + NodeBuilder<> b(kind::AND); + b.append(n.begin(), j); + if(subremovals > 0) { + removals += subremovals; + b << sub; + } else { + ++removals; + } + for(++j; j != n.end(); ++j) { + if(toRemove.find((*j).getId()) != toRemove.end()) { + ++removals; + } else if((*j).getKind() == kind::AND) { + sub = *j; + if((subremovals = removeFromConjunction(sub, toRemove)) > 0) { + removals += subremovals; + b << sub; + } else { + b << *j; + } + } else { + b << *j; + } + } + if(b.getNumChildren() == 0) { + n = trueNode; + b.clear(); + } else if(b.getNumChildren() == 1) { + n = b[0]; + b.clear(); + } else { + n = b; + } + n = Rewriter::rewrite(n); + return removals; + } + } + + Assert(removals == 0); + return 0; +} + +void SmtEnginePrivate::doMiplibTrick() { + Assert(d_assertionsToPreprocess.empty()); + Assert(d_realAssertionsEnd == d_assertionsToCheck.size()); + Assert(!options::incrementalSolving()); + + const booleans::CircuitPropagator::BackEdgesMap& backEdges = d_propagator.getBackEdges(); + hash_set<unsigned> removeAssertions; + + NodeManager* nm = NodeManager::currentNM(); + Node zero = nm->mkConst(Rational(0)), one = nm->mkConst(Rational(1)); + + hash_map<TNode, Node, TNodeHashFunction> intVars; + for(vector<Node>::const_iterator i = d_boolVars.begin(); i != d_boolVars.end(); ++i) { + if(d_propagator.isAssigned(*i)) { + Debug("miplib") << "ineligible: " << *i << " because assigned " << d_propagator.getAssignment(*i) << endl; + continue; + } + + vector<TNode> assertions; + booleans::CircuitPropagator::BackEdgesMap::const_iterator j = backEdges.find(*i); + // if not in back edges map, the bool var is unconstrained, showing up in no assertions. + // if maps to an empty vector, that means the bool var was asserted itself. + if(j != backEdges.end()) { + if(!(*j).second.empty()) { + traceBackToAssertions((*j).second, assertions); + } else { + assertions.push_back(*i); + } + } + Debug("miplib") << "for " << *i << endl; + bool eligible = true; + map<pair<Node, Node>, uint64_t> marks; + map<pair<Node, Node>, vector<Rational> > coef; + map<pair<Node, Node>, vector<Rational> > checks; + map<pair<Node, Node>, vector<TNode> > asserts; + for(vector<TNode>::const_iterator j = assertions.begin(); j != assertions.end(); ++j) { + Debug("miplib") << " found: " << *j << endl; + if((*j).getKind() != kind::IMPLIES) { + eligible = false; + Debug("miplib") << " -- INELIGIBLE -- (not =>)" << endl; + break; + } + Node conj = BooleanSimplification::simplify((*j)[0]); + if(conj.getKind() == kind::AND && conj.getNumChildren() > 6) { + eligible = false; + Debug("miplib") << " -- INELIGIBLE -- (N-ary /\\ too big)" << endl; + break; + } + if(conj.getKind() != kind::AND && !conj.isVar() && !(conj.getKind() == kind::NOT && conj[0].isVar())) { + eligible = false; + Debug("miplib") << " -- INELIGIBLE -- (not /\\ or literal)" << endl; + break; + } + if((*j)[1].getKind() != kind::EQUAL || + !( ( (*j)[1][0].isVar() && + (*j)[1][1].getKind() == kind::CONST_RATIONAL ) || + ( (*j)[1][0].getKind() == kind::CONST_RATIONAL && + (*j)[1][1].isVar() ) )) { + eligible = false; + Debug("miplib") << " -- INELIGIBLE -- (=> (and X X) X)" << endl; + break; + } + if(conj.getKind() == kind::AND) { + vector<Node> posv; + bool found_x = false; + map<TNode, bool> neg; + for(Node::iterator ii = conj.begin(); ii != conj.end(); ++ii) { + if((*ii).isVar()) { + posv.push_back(*ii); + neg[*ii] = false; + found_x = found_x || *i == *ii; + } else if((*ii).getKind() == kind::NOT && (*ii)[0].isVar()) { + posv.push_back((*ii)[0]); + neg[(*ii)[0]] = true; + found_x = found_x || *i == (*ii)[0]; + } else { + eligible = false; + Debug("miplib") << " -- INELIGIBLE -- (non-var: " << *ii << ")" << endl; + break; + } + if(d_propagator.isAssigned(posv.back())) { + eligible = false; + Debug("miplib") << " -- INELIGIBLE -- (" << posv.back() << " asserted)" << endl; + break; + } + } + if(!eligible) { + break; + } + if(!found_x) { + eligible = false; + Debug("miplib") << " --INELIGIBLE -- (couldn't find " << *i << " in conjunction)" << endl; + break; + } + sort(posv.begin(), posv.end()); + const Node pos = NodeManager::currentNM()->mkNode(kind::AND, posv); + const TNode var = ((*j)[1][0].getKind() == kind::CONST_RATIONAL) ? (*j)[1][1] : (*j)[1][0]; + const pair<Node, Node> pos_var(pos, var); + const Rational& constant = ((*j)[1][0].getKind() == kind::CONST_RATIONAL) ? (*j)[1][0].getConst<Rational>() : (*j)[1][1].getConst<Rational>(); + uint64_t mark = 0; + unsigned countneg = 0, thepos = 0; + for(unsigned ii = 0; ii < pos.getNumChildren(); ++ii) { + if(neg[pos[ii]]) { + ++countneg; + } else { + thepos = ii; + mark |= (0x1 << ii); + } + } + if((marks[pos_var] & (1lu << mark)) != 0) { + eligible = false; + Debug("miplib") << " -- INELIGIBLE -- (remarked)" << endl; + break; + } + Debug("miplib") << "mark is " << mark << " -- " << (1lu << mark) << endl; + marks[pos_var] |= (1lu << mark); + Debug("miplib") << "marks[" << pos << "," << var << "] now " << marks[pos_var] << endl; + if(countneg == pos.getNumChildren()) { + if(constant != 0) { + eligible = false; + Debug("miplib") << " -- INELIGIBLE -- (nonzero constant)" << endl; + break; + } + } else if(countneg == pos.getNumChildren() - 1) { + Assert(coef[pos_var].size() <= 6 && thepos < 6); + coef[pos_var].resize(6); + coef[pos_var][thepos] = constant; + } else { + if(checks[pos_var].size() <= mark) { + checks[pos_var].resize(mark + 1); + } + checks[pos_var][mark] = constant; + } + asserts[pos_var].push_back(*j); + } else { + TNode x = conj; + if(x != *i && x != (*i).notNode()) { + eligible = false; + Debug("miplib") << " -- INELIGIBLE -- (x not present where I expect it)" << endl; + break; + } + const bool xneg = (x.getKind() == kind::NOT); + x = xneg ? x[0] : x; + Debug("miplib") << " x:" << x << " " << xneg << endl; + const TNode var = ((*j)[1][0].getKind() == kind::CONST_RATIONAL) ? (*j)[1][1] : (*j)[1][0]; + const pair<Node, Node> x_var(x, var); + const Rational& constant = ((*j)[1][0].getKind() == kind::CONST_RATIONAL) ? (*j)[1][0].getConst<Rational>() : (*j)[1][1].getConst<Rational>(); + unsigned mark = (xneg ? 0 : 1); + if((marks[x_var] & (1u << mark)) != 0) { + eligible = false; + Debug("miplib") << " -- INELIGIBLE -- (remarked)" << endl; + break; + } + marks[x_var] |= (1u << mark); + if(xneg) { + if(constant != 0) { + eligible = false; + Debug("miplib") << " -- INELIGIBLE -- (nonzero constant)" << endl; + break; + } + } else { + Assert(coef[x_var].size() <= 6); + coef[x_var].resize(6); + coef[x_var][0] = constant; + if(checks[x_var].size() <= mark) { + checks[x_var].resize(mark + 1); + } + checks[x_var][mark] = constant; + } + asserts[x_var].push_back(*j); + } + } + if(eligible) { + for(map<pair<Node, Node>, uint64_t>::const_iterator j = marks.begin(); j != marks.end(); ++j) { + const TNode pos = (*j).first.first; + const TNode var = (*j).first.second; + const pair<Node, Node>& pos_var = (*j).first; + const uint64_t mark = (*j).second; + const unsigned numVars = pos.getKind() == kind::AND ? pos.getNumChildren() : 1; + uint64_t expected = (uint64_t(1) << (1 << numVars)) - 1; + expected = (expected == 0) ? -1 : expected;// fix for overflow + Debug("miplib") << "[" << pos << "] => " << hex << mark << " expect " << expected << dec << endl; + Assert(pos.getKind() == kind::AND || pos.isVar()); + if(mark != expected) { + Debug("miplib") << " -- INELIGIBLE " << pos << " -- (insufficiently marked, got " << mark << " for " << numVars << " vars, expected " << expected << endl; + } else { + if(false) { //checks[pos] != coef[pos][0] + coef[pos][1]) { + Debug("miplib") << " -- INELIGIBLE " << pos << " -- (not linear combination)" << endl; + } else { + Debug("miplib") << " -- ELIGIBLE " << *i << " , " << pos << " --" << endl; + vector<Node> newVars; + expr::NodeSelfIterator ii, iiend; + if(pos.getKind() == kind::AND) { + ii = pos.begin(); + iiend = pos.end(); + } else { + ii = expr::NodeSelfIterator::self(pos); + iiend = expr::NodeSelfIterator::selfEnd(pos); + } + for(; ii != iiend; ++ii) { + Node& varRef = intVars[*ii]; + if(varRef.isNull()) { + stringstream ss; + ss << "mipvar_" << *ii; + Node newVar = nm->mkSkolem(ss.str(), nm->integerType(), "a variable introduced due to scrubbing a miplib encoding", NodeManager::SKOLEM_EXACT_NAME); + Node geq = Rewriter::rewrite(nm->mkNode(kind::GEQ, newVar, zero)); + Node leq = Rewriter::rewrite(nm->mkNode(kind::LEQ, newVar, one)); + d_assertionsToCheck.push_back(Rewriter::rewrite(geq.andNode(leq))); + SubstitutionMap nullMap(&d_fakeContext); + Theory::PPAssertStatus status CVC4_UNUSED;// just for assertions + status = d_smt.d_theoryEngine->solve(geq, nullMap); + Assert(status == Theory::PP_ASSERT_STATUS_UNSOLVED, + "unexpected solution from arith's ppAssert()"); + Assert(nullMap.empty(), + "unexpected substitution from arith's ppAssert()"); + status = d_smt.d_theoryEngine->solve(leq, nullMap); + Assert(status == Theory::PP_ASSERT_STATUS_UNSOLVED, + "unexpected solution from arith's ppAssert()"); + Assert(nullMap.empty(), + "unexpected substitution from arith's ppAssert()"); + d_smt.d_theoryEngine->getModel()->addSubstitution(*ii, newVar.eqNode(one)); + newVars.push_back(newVar); + varRef = newVar; + } else { + newVars.push_back(varRef); + } + if(!d_smt.d_logic.areIntegersUsed()) { + d_smt.d_logic = d_smt.d_logic.getUnlockedCopy(); + d_smt.d_logic.enableIntegers(); + d_smt.d_logic.lock(); + } + } + Node sum; + if(pos.getKind() == kind::AND) { + NodeBuilder<> sumb(kind::PLUS); + for(size_t ii = 0; ii < pos.getNumChildren(); ++ii) { + sumb << nm->mkNode(kind::MULT, nm->mkConst(coef[pos_var][ii]), newVars[ii]); + } + sum = sumb; + } else { + sum = nm->mkNode(kind::MULT, nm->mkConst(coef[pos_var][0]), newVars[0]); + } + Debug("miplib") << "vars[] " << var << endl + << " eq " << Rewriter::rewrite(sum) << endl; + Node newAssertion = var.eqNode(Rewriter::rewrite(sum)); + if(d_topLevelSubstitutions.hasSubstitution(newAssertion[0])) { + //Warning() << "RE-SUBSTITUTION " << newAssertion[0] << endl; + //Warning() << "REPLACE " << newAssertion[1] << endl; + //Warning() << "ORIG " << d_topLevelSubstitutions.getSubstitution(newAssertion[0]) << endl; + Assert(d_topLevelSubstitutions.getSubstitution(newAssertion[0]) == newAssertion[1]); + } else if(pos.getNumChildren() <= options::arithMLTrickSubstitutions()) { + d_topLevelSubstitutions.addSubstitution(newAssertion[0], newAssertion[1]); + Debug("miplib") << "addSubs: " << newAssertion[0] << " to " << newAssertion[1] << endl; + } else { + Debug("miplib") << "skipSubs: " << newAssertion[0] << " to " << newAssertion[1] << " (threshold is " << options::arithMLTrickSubstitutions() << ")" << endl; + } + newAssertion = Rewriter::rewrite(newAssertion); + Debug("miplib") << " " << newAssertion << endl; + d_assertionsToCheck.push_back(newAssertion); + Debug("miplib") << " assertions to remove: " << endl; + for(vector<TNode>::const_iterator k = asserts[pos_var].begin(), k_end = asserts[pos_var].end(); k != k_end; ++k) { + Debug("miplib") << " " << *k << endl; + removeAssertions.insert((*k).getId()); + } + } + } + } + } + } + if(!removeAssertions.empty()) { + Debug("miplib") << "SmtEnginePrivate::simplify(): scrubbing miplib encoding..." << endl; + Node trueNode = nm->mkConst(true); + for(size_t i = 0; i < d_realAssertionsEnd; ++i) { + if(removeAssertions.find(d_assertionsToCheck[i].getId()) != removeAssertions.end()) { + Debug("miplib") << "SmtEnginePrivate::simplify(): - removing " << d_assertionsToCheck[i] << endl; + d_assertionsToCheck[i] = trueNode; + ++d_smt.d_stats->d_numMiplibAssertionsRemoved; + } else if(d_assertionsToCheck[i].getKind() == kind::AND) { + size_t removals = removeFromConjunction(d_assertionsToCheck[i], removeAssertions); + if(removals > 0) { + Debug("miplib") << "SmtEnginePrivate::simplify(): - reduced " << d_assertionsToCheck[i] << endl; + Debug("miplib") << "SmtEnginePrivate::simplify(): - by " << removals << " conjuncts" << endl; + d_smt.d_stats->d_numMiplibAssertionsRemoved += removals; + } + } + Debug("miplib") << "had: " << d_assertionsToCheck[i] << endl; + d_assertionsToCheck[i] = Rewriter::rewrite(d_topLevelSubstitutions.apply(d_assertionsToCheck[i])); + Debug("miplib") << "now: " << d_assertionsToCheck[i] << endl; + } + } else { + Debug("miplib") << "SmtEnginePrivate::simplify(): miplib pass found nothing." << endl; + } + d_realAssertionsEnd = d_assertionsToCheck.size(); +} + // returns false if simplification led to "false" bool SmtEnginePrivate::simplifyAssertions() throw(TypeCheckingException, LogicException) { @@ -1908,21 +2313,49 @@ bool SmtEnginePrivate::simplifyAssertions() if(options::simplificationMode() != SIMPLIFICATION_MODE_NONE) { // Perform non-clausal simplification + Chat() << "...performing nonclausal simplification..." << endl; Trace("simplify") << "SmtEnginePrivate::simplify(): " << "performing non-clausal simplification" << endl; bool noConflict = nonClausalSimplify(); - if(!noConflict) return false; + if(!noConflict) { + return false; + } + + // We piggy-back off of the BackEdgesMap in the CircuitPropagator to + // do the miplib trick. + if( // check that option is on + options::arithMLTrick() && + // miplib rewrites aren't safe in incremental mode + ! options::incrementalSolving() && + // only useful in arith + d_smt.d_logic.isTheoryEnabled(theory::THEORY_ARITH) && + // we add new assertions and need this (in practice, this + // restriction only disables miplib processing during + // re-simplification, which we don't expect to be useful anyway) + d_realAssertionsEnd == d_assertionsToCheck.size() ) { + Chat() << "...fixing miplib encodings..." << endl; + Trace("simplify") << "SmtEnginePrivate::simplify(): " + << "looking for miplib pseudobooleans..." << endl; + + TimerStat::CodeTimer miplibTimer(d_smt.d_stats->d_miplibPassTime); + + doMiplibTrick(); + } else { + Trace("simplify") << "SmtEnginePrivate::simplify(): " + << "skipping miplib pseudobooleans pass (either incrementalSolving is on, or miplib pbs are turned off)..." << endl; + } } else { Assert(d_assertionsToCheck.empty()); d_assertionsToCheck.swap(d_assertionsToPreprocess); } - Trace("smt") << "POST nonClasualSimplify" << std::endl; + Trace("smt") << "POST nonClausalSimplify" << endl; Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl; Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl; // Theory preprocessing if (d_smt.d_earlyTheoryPP) { + Chat() << "...doing early theory preprocessing..." << endl; TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_theoryPreprocessTime); // Call the theory preprocessors d_smt.d_theoryEngine->preprocessStart(); @@ -1933,31 +2366,34 @@ bool SmtEnginePrivate::simplifyAssertions() } } - Trace("smt") << "POST theoryPP" << std::endl; + Trace("smt") << "POST theoryPP" << endl; Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl; Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl; // ITE simplification if(options::doITESimp()) { + Chat() << "...doing ITE simplification..." << endl; simpITE(); } - Trace("smt") << "POST iteSimp" << std::endl; + Trace("smt") << "POST iteSimp" << endl; Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl; Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl; // Unconstrained simplification if(options::unconstrainedSimp()) { + Chat() << "...doing unconstrained simplification..." << endl; unconstrainedSimp(); } - Trace("smt") << "POST unconstrainedSimp" << std::endl; + Trace("smt") << "POST unconstrainedSimp" << endl; Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl; Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl; if(options::repeatSimp() && options::simplificationMode() != SIMPLIFICATION_MODE_NONE) { + Chat() << "...doing another round of nonclausal simplification..." << endl; Trace("simplify") << "SmtEnginePrivate::simplify(): " - << " doing repeated simplification" << std::endl; + << " doing repeated simplification" << endl; d_assertionsToCheck.swap(d_assertionsToPreprocess); Assert(d_assertionsToCheck.empty()); bool noConflict = nonClausalSimplify(); @@ -1966,7 +2402,7 @@ bool SmtEnginePrivate::simplifyAssertions() } } - Trace("smt") << "POST repeatSimp" << std::endl; + Trace("smt") << "POST repeatSimp" << endl; Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl; Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl; @@ -2016,6 +2452,7 @@ Result SmtEngine::check() { resource = d_resourceBudgetPerCall; } + Chat() << "solving..." << endl; Trace("smt") << "SmtEngine::check(): running check" << endl; Result result = d_propEngine->checkSat(millis, resource); @@ -2192,11 +2629,11 @@ void SmtEnginePrivate::processAssertions() { //apply pre-skolemization to existential quantifiers for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) { Node prev = d_assertionsToPreprocess[i]; - std::vector< Node > fvs; + vector< Node > fvs; d_assertionsToPreprocess[i] = Rewriter::rewrite( preSkolemizeQuantifiers( d_assertionsToPreprocess[i], true, fvs ) ); if( prev!=d_assertionsToPreprocess[i] ){ - Trace("quantifiers-rewrite") << "*** Pre-skolemize " << prev << std::endl; - Trace("quantifiers-rewrite") << " ...got " << d_assertionsToPreprocess[i] << std::endl; + Trace("quantifiers-rewrite") << "*** Pre-skolemize " << prev << endl; + Trace("quantifiers-rewrite") << " ...got " << d_assertionsToPreprocess[i] << endl; } } } @@ -2213,8 +2650,7 @@ void SmtEnginePrivate::processAssertions() { if( options::sortInference() ){ //sort inference technique - SortInference si; - si.simplify( d_assertionsToPreprocess ); + d_smt.d_theoryEngine->getSortInference()->simplify( d_assertionsToPreprocess ); } dumpAssertions("pre-simplify", d_assertionsToPreprocess); @@ -2246,7 +2682,7 @@ void SmtEnginePrivate::processAssertions() { dumpAssertions("pre-repeat-simplify", d_assertionsToCheck); if(options::repeatSimp()) { d_assertionsToCheck.swap(d_assertionsToPreprocess); - Chat() << "simplifying assertions..." << endl; + Chat() << "re-simplifying assertions..." << endl; noConflict &= simplifyAssertions(); if (noConflict) { // Need to fix up assertion list to maintain invariants: @@ -2604,7 +3040,7 @@ Expr SmtEngine::expandDefinitions(const Expr& ex) throw(TypeCheckingException, L return n.toExpr(); } -Expr SmtEngine::getValue(const Expr& ex) throw(ModalException, LogicException) { +Expr SmtEngine::getValue(const Expr& ex) throw(ModalException, TypeCheckingException, LogicException) { Assert(ex.getExprManager() == d_exprManager); SmtScope smts(this); diff --git a/src/smt/smt_engine.h b/src/smt/smt_engine.h index 3edcd6872..fecfba14a 100644 --- a/src/smt/smt_engine.h +++ b/src/smt/smt_engine.h @@ -47,7 +47,7 @@ namespace CVC4 { template <bool ref_count> class NodeTemplate; typedef NodeTemplate<true> Node; typedef NodeTemplate<false> TNode; -class NodeHashFunction; +struct NodeHashFunction; class Command; class GetModelCommand; @@ -77,7 +77,7 @@ namespace smt { */ class DefinedFunction; - class SmtEngineStatistics; + struct SmtEngineStatistics; class SmtEnginePrivate; class SmtScope; class BooleanTermConverter; @@ -444,7 +444,7 @@ public: * by a SAT or INVALID query). Only permitted if the SmtEngine is * set to operate interactively and produce-models is on. */ - Expr getValue(const Expr& e) throw(ModalException, LogicException); + Expr getValue(const Expr& e) throw(ModalException, TypeCheckingException, LogicException); /** * Add a function to the set of expressions whose value is to be diff --git a/src/theory/arith/Makefile.am b/src/theory/arith/Makefile.am index b2d1b9f09..76d8d9083 100644 --- a/src/theory/arith/Makefile.am +++ b/src/theory/arith/Makefile.am @@ -9,6 +9,7 @@ libarith_la_SOURCES = \ theory_arith_type_rules.h \ type_enumerator.h \ arithvar.h \ + arithvar.cpp \ arith_rewriter.h \ arith_rewriter.cpp \ arith_static_learner.h \ diff --git a/src/theory/arith/arith_static_learner.cpp b/src/theory/arith/arith_static_learner.cpp index 5b8d3befc..124fa8e2a 100644 --- a/src/theory/arith/arith_static_learner.cpp +++ b/src/theory/arith/arith_static_learner.cpp @@ -19,8 +19,7 @@ #include "theory/arith/arith_utilities.h" #include "theory/arith/arith_static_learner.h" - -#include "util/propositional_query.h" +#include "theory/arith/options.h" #include "expr/expr.h" #include "expr/convenience_node_builders.h" @@ -36,7 +35,6 @@ namespace arith { ArithStaticLearner::ArithStaticLearner(context::Context* userContext) : - d_miplibTrick(userContext), d_minMap(userContext), d_maxMap(userContext), d_statistics() @@ -44,21 +42,15 @@ ArithStaticLearner::ArithStaticLearner(context::Context* userContext) : ArithStaticLearner::Statistics::Statistics(): d_iteMinMaxApplications("theory::arith::iteMinMaxApplications", 0), - d_iteConstantApplications("theory::arith::iteConstantApplications", 0), - d_miplibtrickApplications("theory::arith::miplibtrickApplications", 0), - d_avgNumMiplibtrickValues("theory::arith::avgNumMiplibtrickValues") + d_iteConstantApplications("theory::arith::iteConstantApplications", 0) { StatisticsRegistry::registerStat(&d_iteMinMaxApplications); StatisticsRegistry::registerStat(&d_iteConstantApplications); - StatisticsRegistry::registerStat(&d_miplibtrickApplications); - StatisticsRegistry::registerStat(&d_avgNumMiplibtrickValues); } ArithStaticLearner::Statistics::~Statistics(){ StatisticsRegistry::unregisterStat(&d_iteMinMaxApplications); StatisticsRegistry::unregisterStat(&d_iteConstantApplications); - StatisticsRegistry::unregisterStat(&d_miplibtrickApplications); - StatisticsRegistry::unregisterStat(&d_avgNumMiplibtrickValues); } void ArithStaticLearner::staticLearning(TNode n, NodeBuilder<>& learned){ @@ -103,8 +95,6 @@ void ArithStaticLearner::staticLearning(TNode n, NodeBuilder<>& learned){ process(n,learned, defTrue); } - - postProcess(learned); } @@ -126,27 +116,10 @@ void ArithStaticLearner::process(TNode n, NodeBuilder<>& learned, const TNodeSet iteConstant(n, learned); } break; - case IMPLIES: - // == 3-FINITE VALUE SET : Collect information == - if(n[1].getKind() == EQUAL && - n[1][0].isVar() && - defTrue.find(n) != defTrue.end()){ - Node eqTo = n[1][1]; - Node rewriteEqTo = Rewriter::rewrite(eqTo); - if(rewriteEqTo.getKind() == CONST_RATIONAL){ - - TNode var = n[1][0]; - Node current = (d_miplibTrick.find(var) == d_miplibTrick.end()) ? - mkBoolNode(false) : d_miplibTrick[var]; - d_miplibTrick.insert(var, n.orNode(current)); - Debug("arith::miplib") << "insert " << var << " const " << n << endl; - } - } - break; case CONST_RATIONAL: // Mark constants as minmax - d_minMap[n] = n.getConst<Rational>(); - d_maxMap[n] = n.getConst<Rational>(); + d_minMap.insert(n, n.getConst<Rational>()); + d_maxMap.insert(n, n.getConst<Rational>()); break; case OR: { // Look for things like "x = 0 OR x = 1" (that are defTrue) and @@ -248,7 +221,7 @@ void ArithStaticLearner::iteConstant(TNode n, NodeBuilder<>& learned){ DeltaRational min = std::min(first, second); CDNodeToMinMaxMap::const_iterator minFind = d_minMap.find(n); if (minFind == d_minMap.end() || (*minFind).second < min) { - d_minMap[n] = min; + d_minMap.insert(n, min); Node nGeqMin; if (min.getInfinitesimalPart() == 0) { nGeqMin = NodeBuilder<2>(kind::GEQ) << n << mkRationalNode(min.getNoninfinitesimalPart()); @@ -267,7 +240,7 @@ void ArithStaticLearner::iteConstant(TNode n, NodeBuilder<>& learned){ DeltaRational max = std::max(first, second); CDNodeToMinMaxMap::const_iterator maxFind = d_maxMap.find(n); if (maxFind == d_maxMap.end() || (*maxFind).second > max) { - d_maxMap[n] = max; + d_maxMap.insert(n, max); Node nLeqMax; if (max.getInfinitesimalPart() == 0) { nLeqMax = NodeBuilder<2>(kind::LEQ) << n << mkRationalNode(max.getNoninfinitesimalPart()); @@ -291,99 +264,6 @@ std::set<Node> listToSet(TNode l){ return ret; } -void ArithStaticLearner::postProcess(NodeBuilder<>& learned){ - // == 3-FINITE VALUE SET == - CDNodeToNodeListMap::const_iterator keyIter = d_miplibTrick.begin(); - CDNodeToNodeListMap::const_iterator endKeys = d_miplibTrick.end(); - while(keyIter != endKeys) { - TNode var = (*keyIter).first; - Node list = (*keyIter).second; - const set<Node> imps = listToSet(list); - - if(imps.empty()){ - ++keyIter; - continue; - } - - Assert(!imps.empty()); - vector<Node> conditions; - set<Rational> values; - set<Node>::const_iterator j=imps.begin(), impsEnd=imps.end(); - for(; j != impsEnd; ++j){ - TNode imp = *j; - Assert(imp.getKind() == IMPLIES); - Assert(imp[1].getKind() == EQUAL); - - Node eqTo = imp[1][1]; - Node rewriteEqTo = Rewriter::rewrite(eqTo); - Assert(rewriteEqTo.getKind() == CONST_RATIONAL); - - conditions.push_back(imp[0]); - values.insert(rewriteEqTo.getConst<Rational>()); - } - - Node possibleTaut = Node::null(); - if(conditions.size() == 1){ - possibleTaut = conditions.front(); - }else{ - NodeBuilder<> orBuilder(OR); - orBuilder.append(conditions); - possibleTaut = orBuilder; - } - - - Debug("arith::miplib") << "var: " << var << endl; - Debug("arith::miplib") << "possibleTaut: " << possibleTaut << endl; - - Result isTaut = PropositionalQuery::isTautology(possibleTaut); - if(isTaut == Result(Result::VALID)){ - miplibTrick(var, values, learned); - d_miplibTrick.insert(var, mkBoolNode(false)); - } - ++keyIter; - } -} - - -void ArithStaticLearner::miplibTrick(TNode var, set<Rational>& values, NodeBuilder<>& learned){ - - Debug("arith::miplib") << var << " found a tautology!"<< endl; - - const Rational& min = *(values.begin()); - const Rational& max = *(values.rbegin()); - - Debug("arith::miplib") << "min: " << min << endl; - Debug("arith::miplib") << "max: " << max << endl; - - Assert(min <= max); - ++(d_statistics.d_miplibtrickApplications); - (d_statistics.d_avgNumMiplibtrickValues).addEntry(values.size()); - - Node nGeqMin = NodeBuilder<2>(GEQ) << var << mkRationalNode(min); - Node nLeqMax = NodeBuilder<2>(LEQ) << var << mkRationalNode(max); - Debug("arith::miplib") << nGeqMin << nLeqMax << endl; - learned << nGeqMin << nLeqMax; - set<Rational>::iterator valuesIter = values.begin(); - set<Rational>::iterator valuesEnd = values.end(); - set<Rational>::iterator valuesPrev = valuesIter; - ++valuesIter; - for(; valuesIter != valuesEnd; valuesPrev = valuesIter, ++valuesIter){ - const Rational& prev = *valuesPrev; - const Rational& curr = *valuesIter; - Assert(prev < curr); - - //The interval (last,curr) can be excluded: - //(not (and (> var prev) (< var curr)) - //<=> (or (not (> var prev)) (not (< var curr))) - //<=> (or (<= var prev) (>= var curr)) - Node leqPrev = NodeBuilder<2>(LEQ) << var << mkRationalNode(prev); - Node geqCurr = NodeBuilder<2>(GEQ) << var << mkRationalNode(curr); - Node excludedMiddle = NodeBuilder<2>(OR) << leqPrev << geqCurr; - Debug("arith::miplib") << excludedMiddle << endl; - learned << excludedMiddle; - } -} - void ArithStaticLearner::addBound(TNode n) { CDNodeToMinMaxMap::const_iterator minFind = d_minMap.find(n[0]); @@ -398,7 +278,7 @@ void ArithStaticLearner::addBound(TNode n) { /* fall through */ case kind::LEQ: if (maxFind == d_maxMap.end() || (*maxFind).second > bound) { - d_maxMap[n[0]] = bound; + d_maxMap.insert(n[0], bound); Debug("arith::static") << "adding bound " << n << endl; } break; @@ -407,7 +287,7 @@ void ArithStaticLearner::addBound(TNode n) { /* fall through */ case kind::GEQ: if (minFind == d_minMap.end() || (*minFind).second < bound) { - d_minMap[n[0]] = bound; + d_minMap.insert(n[0], bound); Debug("arith::static") << "adding bound " << n << endl; } break; diff --git a/src/theory/arith/arith_static_learner.h b/src/theory/arith/arith_static_learner.h index b047018e8..48ee6a3bb 100644 --- a/src/theory/arith/arith_static_learner.h +++ b/src/theory/arith/arith_static_learner.h @@ -27,7 +27,7 @@ #include "context/context.h" #include "context/cdlist.h" -#include "context/cdhashmap.h" +#include "context/cdtrail_hashmap.h" #include <set> namespace CVC4 { @@ -37,21 +37,10 @@ namespace arith { class ArithStaticLearner { private: - /* Maps a variable, x, to the set of defTrue nodes of the form - * (=> _ (= x c)) - * where c is a constant. - */ - //typedef __gnu_cxx::hash_map<Node, std::set<Node>, NodeHashFunction> VarToNodeSetMap; - typedef context::CDHashMap<Node, Node, NodeHashFunction> CDNodeToNodeListMap; - // The domain is an implicit list OR(x, OR(y, ..., FALSE )) - // or FALSE - CDNodeToNodeListMap d_miplibTrick; - /** * Map from a node to it's minimum and maximum. */ - //typedef __gnu_cxx::hash_map<Node, DeltaRational, NodeHashFunction> NodeToMinMaxMap; - typedef context::CDHashMap<Node, DeltaRational, NodeHashFunction> CDNodeToMinMaxMap; + typedef context::CDTrailHashMap<Node, DeltaRational, NodeHashFunction> CDNodeToMinMaxMap; CDNodeToMinMaxMap d_minMap; CDNodeToMinMaxMap d_maxMap; @@ -64,23 +53,15 @@ public: private: void process(TNode n, NodeBuilder<>& learned, const TNodeSet& defTrue); - void postProcess(NodeBuilder<>& learned); - void iteMinMax(TNode n, NodeBuilder<>& learned); void iteConstant(TNode n, NodeBuilder<>& learned); - void miplibTrick(TNode var, std::set<Rational>& values, NodeBuilder<>& learned); - - /** These fields are designed to be accessible to ArithStaticLearner methods. */ class Statistics { public: IntStat d_iteMinMaxApplications; IntStat d_iteConstantApplications; - IntStat d_miplibtrickApplications; - AverageStat d_avgNumMiplibtrickValues; - Statistics(); ~Statistics(); }; diff --git a/src/theory/arith/arith_utilities.h b/src/theory/arith/arith_utilities.h index c7f511a98..76210fc7c 100644 --- a/src/theory/arith/arith_utilities.h +++ b/src/theory/arith/arith_utilities.h @@ -168,59 +168,6 @@ inline int deltaCoeff(Kind k){ } } - -// template <bool selectLeft> -// inline TNode getSide(TNode assertion, Kind simpleKind){ -// switch(simpleKind){ -// case kind::LT: -// case kind::GT: -// case kind::DISTINCT: -// return selectLeft ? (assertion[0])[0] : (assertion[0])[1]; -// case kind::LEQ: -// case kind::GEQ: -// case kind::EQUAL: -// return selectLeft ? assertion[0] : assertion[1]; -// default: -// Unreachable(); -// return TNode::null(); -// } -// } - -// inline DeltaRational determineRightConstant(TNode assertion, Kind simpleKind){ -// TNode right = getSide<false>(assertion, simpleKind); - -// Assert(right.getKind() == kind::CONST_RATIONAL); -// const Rational& noninf = right.getConst<Rational>(); - -// Rational inf = Rational(Integer(deltaCoeff(simpleKind))); -// return DeltaRational(noninf, inf); -// } - -// inline DeltaRational asDeltaRational(TNode n){ -// Kind simp = simplifiedKind(n); -// return determineRightConstant(n, simp); -// } - -// /** -// * Takes two nodes with exactly 2 children, -// * the second child of both are of kind CONST_RATIONAL, -// * and compares value of the two children. -// * This is for comparing inequality nodes. -// * RightHandRationalLT((<= x 50), (< x 75)) == true -// */ -// struct RightHandRationalLT -// { -// bool operator()(TNode s1, TNode s2) const -// { -// TNode rh1 = s1[1]; -// TNode rh2 = s2[1]; -// const Rational& c1 = rh1.getConst<Rational>(); -// const Rational& c2 = rh2.getConst<Rational>(); -// int cmpRes = c1.cmp(c2); -// return cmpRes < 0; -// } -// }; - inline Node negateConjunctionAsClause(TNode conjunction){ Assert(conjunction.getKind() == kind::AND); NodeBuilder<> orBuilder(kind::OR); diff --git a/src/theory/arith/arithvar.cpp b/src/theory/arith/arithvar.cpp new file mode 100644 index 000000000..76b143fff --- /dev/null +++ b/src/theory/arith/arithvar.cpp @@ -0,0 +1,13 @@ + +#include "theory/arith/arithvar.h" +#include <limits> + +namespace CVC4 { +namespace theory { +namespace arith { + +const ArithVar ARITHVAR_SENTINEL = std::numeric_limits<ArithVar>::max(); + +}/* CVC4::theory::arith namespace */ +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ diff --git a/src/theory/arith/arithvar.h b/src/theory/arith/arithvar.h index 7cb6c6e99..95614a011 100644 --- a/src/theory/arith/arithvar.h +++ b/src/theory/arith/arithvar.h @@ -22,24 +22,23 @@ #ifndef __CVC4__THEORY__ARITH__ARITHVAR_H #define __CVC4__THEORY__ARITH__ARITHVAR_H -#include <limits> #include <ext/hash_map> #include "expr/node.h" #include "context/cdhashset.h" -#include "context/cdhashset.h" #include "util/index.h" +#include "util/dense_map.h" namespace CVC4 { namespace theory { namespace arith { typedef Index ArithVar; -const ArithVar ARITHVAR_SENTINEL = std::numeric_limits<ArithVar>::max(); +extern const ArithVar ARITHVAR_SENTINEL; //Maps from Nodes -> ArithVars, and vice versa typedef __gnu_cxx::hash_map<Node, ArithVar, NodeHashFunction> NodeToArithVarMap; -typedef __gnu_cxx::hash_map<ArithVar, Node> ArithVarToNodeMap; +typedef DenseMap<Node> ArithVarToNodeMap; /** * ArithVarCallBack provides a mechanism for agreeing on callbacks while @@ -50,6 +49,16 @@ public: virtual void operator()(ArithVar x) = 0; }; +/** + * Requests arithmetic variables for internal use, + * and releases arithmetic variables that are no longer being used. + */ +class ArithVarMalloc { +public: + virtual ArithVar request() = 0; + virtual void release(ArithVar v) = 0; +}; + class TNodeCallBack { public: virtual void operator()(TNode n) = 0; diff --git a/src/theory/arith/arithvar_node_map.h b/src/theory/arith/arithvar_node_map.h index 3a2cff236..e0e589e57 100644 --- a/src/theory/arith/arithvar_node_map.h +++ b/src/theory/arith/arithvar_node_map.h @@ -40,31 +40,50 @@ private: ArithVarToNodeMap d_arithVarToNodeMap; public: + + typedef ArithVarToNodeMap::const_iterator var_iterator; + ArithVarNodeMap() {} inline bool hasArithVar(TNode x) const { return d_nodeToArithVarMap.find(x) != d_nodeToArithVarMap.end(); } + inline bool hasNode(ArithVar a) const { + return d_arithVarToNodeMap.isKey(a); + } + inline ArithVar asArithVar(TNode x) const{ Assert(hasArithVar(x)); Assert((d_nodeToArithVarMap.find(x))->second <= ARITHVAR_SENTINEL); return (d_nodeToArithVarMap.find(x))->second; } + inline Node asNode(ArithVar a) const{ - Assert(d_arithVarToNodeMap.find(a) != d_arithVarToNodeMap.end()); - return (d_arithVarToNodeMap.find(a))->second; + Assert(hasNode(a)); + return d_arithVarToNodeMap[a]; } inline void setArithVar(TNode x, ArithVar a){ Assert(!hasArithVar(x)); - Assert(d_arithVarToNodeMap.find(a) == d_arithVarToNodeMap.end()); - d_arithVarToNodeMap[a] = x; + Assert(!d_arithVarToNodeMap.isKey(a)); + d_arithVarToNodeMap.set(a, x); d_nodeToArithVarMap[x] = a; } - const ArithVarToNodeMap& getArithVarToNodeMap() const { - return d_arithVarToNodeMap; + inline void remove(ArithVar x){ + Assert(hasNode(x)); + Node node = asNode(x); + + d_nodeToArithVarMap.erase(d_nodeToArithVarMap.find(node)); + d_arithVarToNodeMap.remove(x); + } + + var_iterator var_begin() const { + return d_arithVarToNodeMap.begin(); + } + var_iterator var_end() const { + return d_arithVarToNodeMap.end(); } };/* class ArithVarNodeMap */ diff --git a/src/theory/arith/congruence_manager.cpp b/src/theory/arith/congruence_manager.cpp index 5ee250c09..de4c7eac3 100644 --- a/src/theory/arith/congruence_manager.cpp +++ b/src/theory/arith/congruence_manager.cpp @@ -272,7 +272,7 @@ void ArithCongruenceManager::addWatchedPair(ArithVar s, TNode x, TNode y){ d_watchedVariables.add(s); Node eq = x.eqNode(y); - d_watchedEqualities[s] = eq; + d_watchedEqualities.set(s, eq); } void ArithCongruenceManager::assertionToEqualityEngine(bool isEquality, ArithVar s, TNode reason){ diff --git a/src/theory/arith/constraint.cpp b/src/theory/arith/constraint.cpp index 392d04f6c..4655ea34e 100644 --- a/src/theory/arith/constraint.cpp +++ b/src/theory/arith/constraint.cpp @@ -371,6 +371,10 @@ void ConstraintValue::setAssertedToTheTheory(TNode witness) { d_database->pushAssertionOrderWatch(this, witness); } +// bool ConstraintValue::isPseudoConstraint() const { +// return d_proof == d_database->d_pseudoConstraintProof; +// } + bool ConstraintValue::isSelfExplaining() const { return d_proof == d_database->d_selfExplainingProof; } @@ -481,6 +485,9 @@ ConstraintDatabase::ConstraintDatabase(context::Context* satContext, context::Co d_equalityEngineProof = d_proofs.size(); d_proofs.push_back(NullConstraint); + + // d_pseudoConstraintProof = d_proofs.size(); + // d_proofs.push_back(NullConstraint); } Constraint ConstraintDatabase::getConstraint(ArithVar v, ConstraintType t, const DeltaRational& r){ @@ -566,8 +573,32 @@ ConstraintDatabase::Statistics::~Statistics(){ } void ConstraintDatabase::addVariable(ArithVar v){ - Assert(v == d_varDatabases.size()); - d_varDatabases.push_back(new PerVariableDatabase(v)); + if(d_reclaimable.isMember(v)){ + SortedConstraintMap& scm = getVariableSCM(v); + + std::vector<Constraint> constraintList; + + for(SortedConstraintMapIterator i = scm.begin(), end = scm.end(); i != end; ++i){ + (i->second).push_into(constraintList); + } + while(!constraintList.empty()){ + Constraint c = constraintList.back(); + constraintList.pop_back(); + Assert(c->safeToGarbageCollect()); + delete c; + } + Assert(scm.empty()); + + d_reclaimable.remove(v); + }else{ + Assert(v == d_varDatabases.size()); + d_varDatabases.push_back(new PerVariableDatabase(v)); + } +} + +void ConstraintDatabase::removeVariable(ArithVar v){ + Assert(!d_reclaimable.isMember(v)); + d_reclaimable.add(v); } bool ConstraintValue::safeToGarbageCollect() const{ @@ -802,6 +833,13 @@ void ConstraintValue::impliedBy(const std::vector<Constraint>& b){ } } +// void ConstraintValue::setPseudoConstraint(){ +// Assert(truthIsUnknown()); +// Assert(!hasLiteral()); + +// d_database->pushProofWatch(this, d_database->d_pseudoConstraintProof); +// } + void ConstraintValue::setEqualityEngineProof(){ Assert(truthIsUnknown()); Assert(hasLiteral()); @@ -818,6 +856,7 @@ void ConstraintValue::markAsTrue(){ void ConstraintValue::markAsTrue(Constraint imp){ Assert(truthIsUnknown()); Assert(imp->hasProof()); + //Assert(!imp->isPseudoConstraint()); d_database->d_proofs.push_back(NullConstraint); d_database->d_proofs.push_back(imp); @@ -829,6 +868,8 @@ void ConstraintValue::markAsTrue(Constraint impA, Constraint impB){ Assert(truthIsUnknown()); Assert(impA->hasProof()); Assert(impB->hasProof()); + //Assert(!impA->isPseudoConstraint()); + //Assert(!impB->isPseudoConstraint()); d_database->d_proofs.push_back(NullConstraint); d_database->d_proofs.push_back(impA); @@ -845,6 +886,7 @@ void ConstraintValue::markAsTrue(const vector<Constraint>& a){ for(vector<Constraint>::const_iterator i = a.begin(), end = a.end(); i != end; ++i){ Constraint c_i = *i; Assert(c_i->hasProof()); + //Assert(!c_i->isPseudoConstraint()); d_database->d_proofs.push_back(c_i); } @@ -861,6 +903,7 @@ SortedConstraintMap& ConstraintValue::constraintSet() const{ bool ConstraintValue::proofIsEmpty() const{ Assert(hasProof()); bool result = d_database->d_proofs[d_proof] == NullConstraint; + //Assert((!result) || isSelfExplaining() || hasEqualityEngineProof() || isPseudoConstraint()); Assert((!result) || isSelfExplaining() || hasEqualityEngineProof()); return result; } @@ -869,6 +912,7 @@ void ConstraintValue::explainBefore(NodeBuilder<>& nb, AssertionOrder order) con Assert(hasProof()); Assert(!isSelfExplaining() || assertedToTheTheory()); + if(assertedBefore(order)){ nb << getWitness(); }else if(hasEqualityEngineProof()){ diff --git a/src/theory/arith/constraint.h b/src/theory/arith/constraint.h index 331fd2bcb..82023a48b 100644 --- a/src/theory/arith/constraint.h +++ b/src/theory/arith/constraint.h @@ -273,7 +273,7 @@ private: */ AssertionOrder _d_assertionOrder; /** - * This is guarenteed to be on the fact queue. + * This is guaranteed to be on the fact queue. * For example if x + y = x + 1 is on the fact queue, then use this */ TNode d_witness; @@ -485,6 +485,15 @@ public: void setEqualityEngineProof(); bool hasEqualityEngineProof() const; + + /** + * There cannot be a literal associated with this constraint. + * The explanation is the constant true. + * explainInto() does nothing. + */ + //void setPseudoConstraint(); + //bool isPseudoConstraint() const; + /** * Returns a explanation of the constraint that is appropriate for conflicts. * @@ -694,6 +703,14 @@ private: */ ProofId d_equalityEngineProof; + /** + * Marks a node as being true always. + * This is only okay for purely internal things. + * + * This is a special proof that is always a member of the list. + */ + //ProofId d_pseudoConstraintProof; + typedef context::CDList<Constraint, ConstraintValue::ProofCleanup> ProofCleanupList; typedef context::CDList<Constraint, ConstraintValue::CanBePropagatedCleanup> CBPList; typedef context::CDList<Constraint, ConstraintValue::AssertionOrderCleanup> AOList; @@ -817,6 +834,7 @@ public: void addVariable(ArithVar v); bool variableDatabaseIsSetup(ArithVar v) const; + void removeVariable(ArithVar v); Node eeExplain(ConstConstraint c) const; void eeExplain(ConstConstraint c, NodeBuilder<>& nb) const; @@ -881,6 +899,8 @@ public: private: void raiseUnateConflict(Constraint ant, Constraint cons); + DenseSet d_reclaimable; + class Statistics { public: IntStat d_unatePropagateCalls; diff --git a/src/theory/arith/delta_rational.h b/src/theory/arith/delta_rational.h index 19a16d558..51c1e5138 100644 --- a/src/theory/arith/delta_rational.h +++ b/src/theory/arith/delta_rational.h @@ -249,7 +249,7 @@ public: } /** - * Computes a sufficient upperbound to seperate two DeltaRationals. + * Computes a sufficient upperbound to separate two DeltaRationals. * This value is stored in res. * For any rational d such that * 0 < d < res diff --git a/src/theory/arith/linear_equality.cpp b/src/theory/arith/linear_equality.cpp index 360e45289..5063a05c7 100644 --- a/src/theory/arith/linear_equality.cpp +++ b/src/theory/arith/linear_equality.cpp @@ -80,7 +80,7 @@ void LinearEqualityModule::update(ArithVar x_i, const DeltaRational& v){ if(Debug.isOn("paranoid:check_tableau")){ debugCheckTableau(); } } -void LinearEqualityModule::pivotAndUpdate(ArithVar x_i, ArithVar x_j, DeltaRational& v){ +void LinearEqualityModule::pivotAndUpdate(ArithVar x_i, ArithVar x_j, const DeltaRational& v){ Assert(x_i != x_j); TimerStat::CodeTimer codeTimer(d_statistics.d_pivotTime); @@ -188,6 +188,23 @@ void LinearEqualityModule::debugCheckTableau(){ Assert(sum == shouldBe); } } +bool LinearEqualityModule::debugEntireLinEqIsConsistent(const string& s){ + bool result = true; + for(ArithVar var = 0, end = d_tableau.getNumColumns(); var != end; ++var){ + // for(VarIter i = d_variables.begin(), end = d_variables.end(); i != end; ++i){ + //ArithVar var = d_arithvarNodeMap.asArithVar(*i); + if(!d_partialModel.assignmentIsConsistent(var)){ + d_partialModel.printModel(var); + Warning() << s << ":" << "Assignment is not consistent for " << var ; + if(d_tableau.isBasic(var)){ + Warning() << " (basic)"; + } + Warning() << endl; + result = false; + } + } + return result; +} DeltaRational LinearEqualityModule::computeBound(ArithVar basic, bool upperBound){ DeltaRational sum(0,0); diff --git a/src/theory/arith/linear_equality.h b/src/theory/arith/linear_equality.h index f337ef0db..7df5ee9c3 100644 --- a/src/theory/arith/linear_equality.h +++ b/src/theory/arith/linear_equality.h @@ -79,7 +79,7 @@ public: * and then pivots x_i with the nonbasic variable in its row x_j. * Updates the assignment of the other basic variables accordingly. */ - void pivotAndUpdate(ArithVar x_i, ArithVar x_j, DeltaRational& v); + void pivotAndUpdate(ArithVar x_i, ArithVar x_j, const DeltaRational& v); ArithPartialModel& getPartialModel() const{ return d_partialModel; } @@ -141,6 +141,11 @@ public: /** Debugging information for a pivot. */ void debugPivot(ArithVar x_i, ArithVar x_j); + /** + * + */ + bool debugEntireLinEqIsConsistent(const std::string& s); + private: /** These fields are designed to be accessible to TheoryArith methods. */ diff --git a/src/theory/arith/matrix.cpp b/src/theory/arith/matrix.cpp index 8e7fe7894..cd7a8a9aa 100644 --- a/src/theory/arith/matrix.cpp +++ b/src/theory/arith/matrix.cpp @@ -247,7 +247,7 @@ void Tableau::rowPivot(ArithVar basicOld, ArithVar basicNew){ d_basic2RowIndex.remove(basicOld); d_basic2RowIndex.set(basicNew, rid); - d_rowIndex2basic[rid] = basicNew; + d_rowIndex2basic.set(rid, basicNew); } // void Tableau::addEntry(ArithVar row, ArithVar col, const Rational& coeff){ @@ -397,10 +397,11 @@ void Tableau::addRow(ArithVar basic, RowIndex newRow = Matrix<Rational>::addRow(coefficients, variables); addEntry(newRow, basic, Rational(-1)); - Assert(d_rowIndex2basic.size() == newRow); + Assert(!d_basic2RowIndex.isKey(basic)); + Assert(!d_rowIndex2basic.isKey(newRow)); d_basic2RowIndex.set(basic, newRow); - d_rowIndex2basic.push_back(basic); + d_rowIndex2basic.set(newRow, basic); if(Debug.isOn("matrix")){ printMatrix(); } @@ -558,6 +559,15 @@ void ReducedRowVector::enqueueNonBasicVariablesAndCoefficients(std::vector< Arit // return newId; // } +void Tableau::removeBasicRow(ArithVar basic){ + RowIndex rid = basicToRowIndex(basic); + + removeRow(rid); + d_basic2RowIndex.remove(basic); + d_rowIndex2basic.remove(rid); + +} + }/* CVC4::theory::arith namespace */ }/* CVC4::theory namespace */ diff --git a/src/theory/arith/matrix.h b/src/theory/arith/matrix.h index ea6c389b9..027397b6a 100644 --- a/src/theory/arith/matrix.h +++ b/src/theory/arith/matrix.h @@ -25,6 +25,7 @@ #include "util/dense_map.h" #include "theory/arith/arithvar.h" +#include "theory/arith/arithvar_node_map.h" #include "theory/arith/normal_form.h" #include <queue> @@ -377,6 +378,8 @@ protected: uint32_t d_entriesInUse; MatrixEntryVector<T> d_entries; + std::vector<RowIndex> d_pool; + T d_zero; public: @@ -446,6 +449,23 @@ protected: d_entries.freeEntry(id); } + private: + RowIndex requestRowIndex(){ + if(d_pool.empty()){ + RowIndex ridx = d_rows.size(); + d_rows.push_back(RowVectorT(&d_entries)); + return ridx; + }else{ + RowIndex rid = d_pool.back(); + d_pool.pop_back(); + return rid; + } + } + + void releaseRowIndex(RowIndex rid){ + d_pool.push_back(rid); + } + public: size_t getNumRows() const { @@ -485,8 +505,11 @@ public: */ RowIndex addRow(const std::vector<T>& coeffs, const std::vector<ArithVar>& variables){ - RowIndex ridx = d_rows.size(); - d_rows.push_back(RowVectorT(&d_entries)); + + RowIndex ridx = requestRowIndex(); + + //RowIndex ridx = d_rows.size(); + //d_rows.push_back(RowVectorT(&d_entries)); std::vector<Rational>::const_iterator coeffIter = coeffs.begin(); std::vector<ArithVar>::const_iterator varsIter = variables.begin(); @@ -701,36 +724,7 @@ public: EntryID id = i.getID(); removeEntry(id); } - } - - - Node rowAsEquality(RowIndex rid, const ArithVarToNodeMap& map){ - using namespace CVC4::kind; - - Assert(getRowLength(rid) >= 2); - - std::vector<Node> pairs; - for(RowIterator i = getRow(rid); !i.atEnd(); ++i){ - const Entry& entry = *i; - ArithVar colVar = entry.getColVar(); - - Node var = (map.find(colVar))->second; - Node coeff = mkRationalNode(entry.getCoefficient()); - - Node mult = NodeBuilder<2>(MULT) << coeff << var; - pairs.push_back(mult); - } - - Node sum = Node::null(); - if(pairs.size() == 1 ){ - sum = pairs.front(); - }else{ - Assert(pairs.size() >= 2); - NodeBuilder<> sumBuilder(PLUS); - sumBuilder.append(pairs); - sum = sumBuilder; - } - return NodeBuilder<2>(EQUAL) << sum << mkRationalNode(d_zero); + releaseRowIndex(rid); } double densityMeasure() const{ @@ -754,6 +748,15 @@ public: } } + void loadSignQueries(RowIndex rid, DenseMap<int>& target) const{ + + RowIterator i = getRow(rid).begin(), i_end = getRow(rid).end(); + for(; i != i_end; ++i){ + const MatrixEntry<T>& entry = *i; + target.set(entry.getColVar(), entry.getCoefficient().sgn()); + } + } + protected: uint32_t numNonZeroEntries() const { return size(); } @@ -833,8 +836,10 @@ private: // Set of all of the basic variables in the tableau. // ArithVarMap<RowIndex> : ArithVar |-> RowIndex BasicToRowMap d_basic2RowIndex; + // RowIndex |-> Basic Variable - std::vector<ArithVar> d_rowIndex2basic; + typedef DenseMap<ArithVar> RowIndexToBasicMap; + RowIndexToBasicMap d_rowIndex2basic; public: @@ -882,10 +887,6 @@ public: return getRow(basicToRowIndex(basic)).begin(); } - // RowIterator rowIterator(RowIndex r) const { - // return getRow(r).begin(); - // } - /** * Adds a row to the tableau. * The new row is equivalent to: @@ -911,7 +912,6 @@ public: void removeBasicRow(ArithVar basic); - private: /* Changes the basic variable on the row for basicOld to basicNew. */ void rowPivot(ArithVar basicOld, ArithVar basicNew); diff --git a/src/theory/arith/options b/src/theory/arith/options index 38cf07251..efe594766 100644 --- a/src/theory/arith/options +++ b/src/theory/arith/options @@ -51,4 +51,15 @@ option arithRewriteEq --enable-arith-rewrite-equalities/--disable-arith-rewrite- turns on the preprocessing rewrite turning equalities into a conjunction of inequalities /turns off the preprocessing rewrite turning equalities into a conjunction of inequalities +option arithMLTrick miplib-trick --enable-miplib-trick/--disable-miplib-trick bool :default false + turns on the preprocessing step of attempting to infer bounds on miplib problems +/turns off the preprocessing step of attempting to infer bounds on miplib problems + +option arithMLTrickSubstitutions miplib-trick-subs --miplib-trick-subs unsigned :default 1 + do substitution for miplib 'tmp' vars if defined in <= N eliminated vars + +option doCutAllBounded --enable-cut-all-bounded/--disable-cut-all-bounded bool :default false :read-write + turns on the integer solving step of periodically cutting all integer variables that have both upper and lower bounds +/turns off the integer solving step of periodically cutting all integer variables that have both upper and lower bounds + endmodule diff --git a/src/theory/arith/options_handlers.h b/src/theory/arith/options_handlers.h index 52e7cbf2a..f8f851964 100644 --- a/src/theory/arith/options_handlers.h +++ b/src/theory/arith/options_handlers.h @@ -52,7 +52,7 @@ This decides on kind of propagation arithmetic attempts to do during the search. "; static const std::string heuristicPivotRulesHelp = "\ -This decides on the rule used by simplex during hueristic rounds\n\ +This decides on the rule used by simplex during heuristic rounds\n\ for deciding the next basic variable to select.\n\ Heuristic pivot rules available:\n\ +min\n\ diff --git a/src/theory/arith/partial_model.cpp b/src/theory/arith/partial_model.cpp index 0ffe67763..5dccd8747 100644 --- a/src/theory/arith/partial_model.cpp +++ b/src/theory/arith/partial_model.cpp @@ -72,7 +72,9 @@ void ArithPartialModel::setAssignment(ArithVar x, const DeltaRational& safe, con Debug("partial_model") << "pm: updating the assignment to" << x << " now " << r <<endl; if(safe == r){ - d_hasSafeAssignment[x] = false; + if(d_hasSafeAssignment[x]){ + d_safeAssignment[x] = safe; + } }else{ d_safeAssignment[x] = safe; @@ -177,6 +179,25 @@ void ArithPartialModel::setUpperBoundConstraint(Constraint c){ d_ubc.set(x, c); } +void ArithPartialModel::forceRelaxLowerBound(ArithVar v){ + AssertArgument(inMaps(v), "Calling forceRelaxLowerBound on a variable that is not properly setup."); + AssertArgument(hasLowerBound(v), "Calling forceRelaxLowerBound on a variable without a lowerbound."); + + Debug("partial_model") << "forceRelaxLowerBound(" << v << ") dropping :" << getLowerBoundConstraint(v) << endl; + + d_lbc.set(v, NullConstraint); +} + + +void ArithPartialModel::forceRelaxUpperBound(ArithVar v){ + AssertArgument(inMaps(v), "Calling forceRelaxUpperBound on a variable that is not properly setup."); + AssertArgument(hasUpperBound(v), "Calling forceRelaxUpperBound on a variable without an upper bound."); + + Debug("partial_model") << "forceRelaxUpperBound(" << v << ") dropping :" << getUpperBoundConstraint(v) << endl; + + d_ubc.set(v, NullConstraint); +} + int ArithPartialModel::cmpToLowerBound(ArithVar x, const DeltaRational& c) const{ if(!hasLowerBound(x)){ // l = -\intfy diff --git a/src/theory/arith/partial_model.h b/src/theory/arith/partial_model.h index 49cfd44a1..fdb4a8ffa 100644 --- a/src/theory/arith/partial_model.h +++ b/src/theory/arith/partial_model.h @@ -68,16 +68,40 @@ public: ArithPartialModel(context::Context* c, RationalCallBack& deltaComputation); + /** + * This sets the lower bound for a variable in the current context. + * This must be stronger the previous constraint. + */ void setLowerBoundConstraint(Constraint lb); + + /** + * This sets the upper bound for a variable in the current context. + * This must be stronger the previous constraint. + */ void setUpperBoundConstraint(Constraint ub); + /** Returns the constraint for the upper bound of a variable. */ inline Constraint getUpperBoundConstraint(ArithVar x) const{ return d_ubc[x]; } + /** Returns the constraint for the lower bound of a variable. */ inline Constraint getLowerBoundConstraint(ArithVar x) const{ return d_lbc[x]; } + /** + * This forces the lower bound for a variable to be relaxed in the current context. + * This is done by forcing the lower bound to be NullConstraint. + * This is an expert only operation! (See primal simplex for an example.) + */ + void forceRelaxLowerBound(ArithVar x); + + /** + * This forces the upper bound for a variable to be relaxed in the current context. + * This is done by forcing the upper bound to be NullConstraint. + * This is an expert only operation! (See primal simplex for an example.) + */ + void forceRelaxUpperBound(ArithVar x); /* Initializes a variable to a safe value.*/ void initialize(ArithVar x, const DeltaRational& r); @@ -190,7 +214,6 @@ public: d_deltaIsSafe = true; } - private: /** @@ -202,7 +225,7 @@ private: bool equalSizes(); bool inMaps(ArithVar x) const{ - return 0 <= x && x < d_mapSize; + return x < d_mapSize; } };/* class ArithPartialModel */ diff --git a/src/theory/arith/theory_arith.cpp b/src/theory/arith/theory_arith.cpp index c2c005767..52f234129 100644 --- a/src/theory/arith/theory_arith.cpp +++ b/src/theory/arith/theory_arith.cpp @@ -62,6 +62,8 @@ TheoryArith::TheoryArith(context::Context* c, context::UserContext* u, OutputCha d_unknownsInARow(0), d_hasDoneWorkSinceCut(false), d_learner(u), + d_numberOfVariables(0), + d_pool(), d_setupLiteralCallback(this), d_assertionsThatDoNotMatchTheirLiterals(c), d_nextIntegerCheckVar(0), @@ -79,12 +81,14 @@ TheoryArith::TheoryArith(context::Context* c, context::UserContext* u, OutputCha d_tableauResetPeriod(10), d_conflicts(c), d_raiseConflict(d_conflicts), + d_tempVarMalloc(*this), d_congruenceManager(c, d_constraintDatabase, d_setupLiteralCallback, d_arithvarNodeMap, d_raiseConflict), d_simplex(d_linEq, d_raiseConflict), d_constraintDatabase(c, u, d_arithvarNodeMap, d_congruenceManager, d_raiseConflict), d_deltaComputeCallback(this), d_basicVarModelUpdateCallBack(d_simplex), d_DELTA_ZERO(0), + d_fullCheckCounter(0), d_statistics() { } @@ -749,8 +753,8 @@ Theory::PPAssertStatus TheoryArith::ppAssert(TNode in, SubstitutionMap& outSubst Assert(elim == Rewriter::rewrite(elim)); - static const unsigned MAX_SUB_SIZE = 20; - if(false && right.size() > MAX_SUB_SIZE){ + static const unsigned MAX_SUB_SIZE = 2; + if(right.size() > MAX_SUB_SIZE){ Debug("simplify") << "TheoryArith::solve(): did not substitute due to the right hand side containing too many terms: " << minVar << ":" << elim << endl; Debug("simplify") << right.size() << endl; }else if(elim.hasSubterm(minVar)){ @@ -822,8 +826,9 @@ void TheoryArith::setupVariable(const Variable& x){ Assert(!isSetup(n)); ++(d_statistics.d_statUserVariables); - ArithVar varN = requestArithVar(n,false); - setupInitialValue(varN); + requestArithVar(n,false); + //ArithVar varN = requestArithVar(n,false); + //setupInitialValue(varN); markSetup(n); @@ -860,8 +865,9 @@ void TheoryArith::setupVariableList(const VarList& vl){ d_nlIncomplete = true; ++(d_statistics.d_statUserVariables); - ArithVar av = requestArithVar(vlNode, false); - setupInitialValue(av); + requestArithVar(vlNode, false); + //ArithVar av = requestArithVar(vlNode, false); + //setupInitialValue(av); markSetup(vlNode); } @@ -1054,7 +1060,7 @@ void TheoryArith::setupPolynomial(const Polynomial& poly) { ArithVar varSlack = requestArithVar(polyNode, true); d_tableau.addRow(varSlack, coefficients, variables); - setupInitialValue(varSlack); + setupBasicValue(varSlack); //Add differences to the difference manager Polynomial::iterator i = poly.begin(), end = poly.end(); @@ -1125,6 +1131,14 @@ void TheoryArith::preRegisterTerm(TNode n) { Debug("arith::preregister") << "end arith::preRegisterTerm("<< n <<")" << endl; } +void TheoryArith::releaseArithVar(ArithVar v){ + Assert(d_arithvarNodeMap.hasNode(v)); + + d_constraintDatabase.removeVariable(v); + d_arithvarNodeMap.remove(v); + + d_pool.push_back(v); +} ArithVar TheoryArith::requestArithVar(TNode x, bool slack){ //TODO : The VarList trick is good enough? @@ -1135,32 +1149,73 @@ ArithVar TheoryArith::requestArithVar(TNode x, bool slack){ Assert(!d_arithvarNodeMap.hasArithVar(x)); Assert(x.getType().isReal());// real or integer - ArithVar varX = d_variables.size(); - d_variables.push_back(Node(x)); - Debug("integers") << "isInteger[[" << x << "]]: " << x.getType().isInteger() << endl; + // ArithVar varX = d_variables.size(); + // d_variables.push_back(Node(x)); + + bool reclaim = !d_pool.empty(); + ArithVar varX; + + if(reclaim){ + varX = d_pool.back(); + d_pool.pop_back(); + + d_partialModel.setAssignment(varX, d_DELTA_ZERO, d_DELTA_ZERO); + }else{ + varX = d_numberOfVariables; + ++d_numberOfVariables; + + d_slackVars.push_back(true); + d_variableTypes.push_back(ATReal); + + d_simplex.increaseMax(); + d_tableau.increaseSize(); + d_tableauSizeHasBeenModified = true; + + d_partialModel.initialize(varX, d_DELTA_ZERO); + } + + ArithType type; if(slack){ //The type computation is not quite accurate for Rationals that are integral. //We'll use the isIntegral check from the polynomial package instead. Polynomial p = Polynomial::parsePolynomial(x); - d_variableTypes.push_back(p.isIntegral() ? ATInteger : ATReal); + type = p.isIntegral() ? ATInteger : ATReal; }else{ - d_variableTypes.push_back(nodeToArithType(x)); + type = nodeToArithType(x); } + d_variableTypes[varX] = type; + d_slackVars[varX] = slack; - d_slackVars.push_back(slack); - - d_simplex.increaseMax(); + d_constraintDatabase.addVariable(varX); d_arithvarNodeMap.setArithVar(x,varX); - d_tableau.increaseSize(); - d_tableauSizeHasBeenModified = true; + // Debug("integers") << "isInteger[[" << x << "]]: " << x.getType().isInteger() << endl; - d_constraintDatabase.addVariable(varX); + // if(slack){ + // //The type computation is not quite accurate for Rationals that are integral. + // //We'll use the isIntegral check from the polynomial package instead. + // Polynomial p = Polynomial::parsePolynomial(x); + // d_variableTypes.push_back(p.isIntegral() ? ATInteger : ATReal); + // }else{ + // d_variableTypes.push_back(nodeToArithType(x)); + // } + + // d_slackVars.push_back(slack); + + // d_simplex.increaseMax(); + + // d_tableau.increaseSize(); + // d_tableauSizeHasBeenModified = true; + + // d_constraintDatabase.addVariable(varX); Debug("arith::arithvar") << x << " |-> " << varX << endl; + Assert(!d_partialModel.hasUpperBound(varX)); + Assert(!d_partialModel.hasLowerBound(varX)); + return varX; } @@ -1179,18 +1234,7 @@ void TheoryArith::asVectors(const Polynomial& p, std::vector<Rational>& coeffs, Assert(theoryOf(n) != THEORY_ARITH || d_arithvarNodeMap.hasArithVar(n)); Assert(d_arithvarNodeMap.hasArithVar(n)); - ArithVar av; - // The first if is likely dead is likely dead code: - // if (theoryOf(n) != THEORY_ARITH && !d_arithvarNodeMap.hasArithVar(n)) { - // // The only way not to get it through pre-register is if it's a foreign term - // ++(d_statistics.d_statUserVariables); - // av = requestArithVar(n,false); - // setupInitialValue(av); - // } else { - // // Otherwise, we already have it's variable - // av = d_arithvarNodeMap.asArithVar(n); - // } - av = d_arithvarNodeMap.asArithVar(n); + ArithVar av = d_arithvarNodeMap.asArithVar(n); coeffs.push_back(constant.getValue()); variables.push_back(av); @@ -1200,11 +1244,12 @@ void TheoryArith::asVectors(const Polynomial& p, std::vector<Rational>& coeffs, /* Requirements: * For basic variables the row must have been added to the tableau. */ -void TheoryArith::setupInitialValue(ArithVar x){ +void TheoryArith::setupBasicValue(ArithVar x){ + Assert(d_tableau.isBasic(x)); - if(!d_tableau.isBasic(x)){ - d_partialModel.initialize(x, d_DELTA_ZERO); - }else{ + // if(!d_tableau.isBasic(x)){ + // d_partialModel.setAssignment(x, d_DELTA_ZERO, d_DELTA_ZERO); + // }else{ //If the variable is basic, assertions may have already happened and updates //may have occured before setting this variable up. @@ -1212,9 +1257,11 @@ void TheoryArith::setupInitialValue(ArithVar x){ //time instead of register DeltaRational safeAssignment = d_linEq.computeRowValue(x, true); DeltaRational assignment = d_linEq.computeRowValue(x, false); - d_partialModel.initialize(x,safeAssignment); - d_partialModel.setAssignment(x,assignment); - } + //d_partialModel.initialize(x,safeAssignment); + //d_partialModel.setAssignment(x,assignment); + d_partialModel.setAssignment(x,safeAssignment,assignment); + + // } Debug("arith") << "setupVariable("<<x<<")"<<std::endl; } @@ -1254,8 +1301,8 @@ Node TheoryArith::dioCutting(){ context::Context::ScopedPush speculativePush(getSatContext()); //DO NOT TOUCH THE OUTPUTSTREAM - //TODO: Improve this - for(ArithVar v = 0, end = d_variables.size(); v != end; ++v){ + for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){ + ArithVar v = *vi; if(isInteger(v)){ const DeltaRational& dr = d_partialModel.getAssignment(v); if(d_partialModel.equalsUpperBound(v, dr) || d_partialModel.equalsLowerBound(v, dr)){ @@ -1369,7 +1416,7 @@ Constraint TheoryArith::constraintFromFactQueue(){ if(assertion != reAssertion){ Debug("arith::nf") << "getting non-nf assertion " << assertion << " |-> " << reAssertion << endl; Assert(constraint != NullConstraint); - d_assertionsThatDoNotMatchTheirLiterals[assertion] = constraint; + d_assertionsThatDoNotMatchTheirLiterals.insert(assertion, constraint); } } @@ -1485,7 +1532,8 @@ bool TheoryArith::assertionCases(Constraint constraint){ * If this returns true, all integer variables have an integer assignment. */ bool TheoryArith::hasIntegerModel(){ - if(d_variables.size() > 0){ + //if(d_variables.size() > 0){ + if(getNumberOfVariables()){ const ArithVar rrEnd = d_nextIntegerCheckVar; do { //Do not include slack variables @@ -1495,7 +1543,7 @@ bool TheoryArith::hasIntegerModel(){ return false; } } - } while((d_nextIntegerCheckVar = (1 + d_nextIntegerCheckVar == d_variables.size() ? 0 : 1 + d_nextIntegerCheckVar)) != rrEnd); + } while((d_nextIntegerCheckVar = (1 + d_nextIntegerCheckVar == getNumberOfVariables() ? 0 : 1 + d_nextIntegerCheckVar)) != rrEnd); } return true; } @@ -1576,6 +1624,7 @@ void TheoryArith::check(Effort effortLevel){ Assert(d_conflicts.empty()); d_qflraStatus = d_simplex.findModel(fullEffort(effortLevel)); + switch(d_qflraStatus){ case Result::SAT: if(newFacts){ @@ -1682,6 +1731,20 @@ void TheoryArith::check(Effort effortLevel){ } Assert( d_currentPropagationList.empty()); + if(!emmittedConflictOrSplit && fullEffort(effortLevel)){ + ++d_fullCheckCounter; + } + static const int CUT_ALL_BOUNDED_PERIOD = 10; + if(!emmittedConflictOrSplit && fullEffort(effortLevel) && + d_fullCheckCounter % CUT_ALL_BOUNDED_PERIOD == 1){ + vector<Node> lemmas = cutAllBounded(); + //output the lemmas + for(vector<Node>::const_iterator i = lemmas.begin(); i != lemmas.end(); ++i){ + d_out->lemma(*i); + ++(d_statistics.d_externalBranchAndBounds); + } + emmittedConflictOrSplit = lemmas.size() > 0; + } if(!emmittedConflictOrSplit && fullEffort(effortLevel)){ emmittedConflictOrSplit = splitDisequalities(); @@ -1728,6 +1791,55 @@ void TheoryArith::check(Effort effortLevel){ Debug("arith") << "TheoryArith::check end" << std::endl; } +Node TheoryArith::branchIntegerVariable(ArithVar x) const { + const DeltaRational& d = d_partialModel.getAssignment(x); + Assert(!d.isIntegral()); + const Rational& r = d.getNoninfinitesimalPart(); + const Rational& i = d.getInfinitesimalPart(); + Trace("integers") << "integers: assignment to [[" << d_arithvarNodeMap.asNode(x) << "]] is " << r << "[" << i << "]" << endl; + + Assert(! (r.getDenominator() == 1 && i.getNumerator() == 0)); + Assert(!d.isIntegral()); + TNode var = d_arithvarNodeMap.asNode(x); + Integer floor_d = d.floor(); + + Node ub = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::LEQ, var, mkRationalNode(floor_d))); + Node lb = ub.notNode(); + + + Node lem = NodeManager::currentNM()->mkNode(kind::OR, ub, lb); + Trace("integers") << "integers: branch & bound: " << lem << endl; + if(d_valuation.isSatLiteral(lem[0])) { + Debug("integers") << " " << lem[0] << " == " << d_valuation.getSatValue(lem[0]) << endl; + } else { + Debug("integers") << " " << lem[0] << " is not assigned a SAT literal" << endl; + } + if(d_valuation.isSatLiteral(lem[1])) { + Debug("integers") << " " << lem[1] << " == " << d_valuation.getSatValue(lem[1]) << endl; + } else { + Debug("integers") << " " << lem[1] << " is not assigned a SAT literal" << endl; + } + return lem; +} + +std::vector<Node> TheoryArith::cutAllBounded() const{ + vector<Node> lemmas; + if(options::doCutAllBounded() && getNumberOfVariables() > 0){ + for(ArithVar iter = 0; iter != getNumberOfVariables(); ++iter){ + //Do not include slack variables + const DeltaRational& d = d_partialModel.getAssignment(iter); + if(isInteger(iter) && !isSlackVariable(iter) && + d_partialModel.hasUpperBound(iter) && + d_partialModel.hasLowerBound(iter) && + !d.isIntegral()){ + Node lem = branchIntegerVariable(iter); + lemmas.push_back(lem); + } + } + } + return lemmas; +} + /** Returns true if the roundRobinBranching() issues a lemma. */ Node TheoryArith::roundRobinBranch(){ if(hasIntegerModel()){ @@ -1737,36 +1849,40 @@ Node TheoryArith::roundRobinBranch(){ Assert(isInteger(v)); Assert(!isSlackVariable(v)); + return branchIntegerVariable(v); - const DeltaRational& d = d_partialModel.getAssignment(v); - const Rational& r = d.getNoninfinitesimalPart(); - const Rational& i = d.getInfinitesimalPart(); - Trace("integers") << "integers: assignment to [[" << d_arithvarNodeMap.asNode(v) << "]] is " << r << "[" << i << "]" << endl; + // Assert(isInteger(v)); + // Assert(!isSlackVariable(v)); - Assert(! (r.getDenominator() == 1 && i.getNumerator() == 0)); - Assert(!d.isIntegral()); + // const DeltaRational& d = d_partialModel.getAssignment(v); + // const Rational& r = d.getNoninfinitesimalPart(); + // const Rational& i = d.getInfinitesimalPart(); + // Trace("integers") << "integers: assignment to [[" << d_arithvarNodeMap.asNode(v) << "]] is " << r << "[" << i << "]" << endl; - TNode var = d_arithvarNodeMap.asNode(v); - Integer floor_d = d.floor(); - Integer ceil_d = d.ceiling(); + // Assert(! (r.getDenominator() == 1 && i.getNumerator() == 0)); + // Assert(!d.isIntegral()); - Node leq = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::LEQ, var, mkRationalNode(floor_d))); - Node geq = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::GEQ, var, mkRationalNode(ceil_d))); + // TNode var = d_arithvarNodeMap.asNode(v); + // Integer floor_d = d.floor(); + // Integer ceil_d = d.ceiling(); + // Node leq = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::LEQ, var, mkRationalNode(floor_d))); + // Node geq = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::GEQ, var, mkRationalNode(ceil_d))); - Node lem = NodeManager::currentNM()->mkNode(kind::OR, leq, geq); - Trace("integers") << "integers: branch & bound: " << lem << endl; - if(d_valuation.isSatLiteral(lem[0])) { - Debug("integers") << " " << lem[0] << " == " << d_valuation.getSatValue(lem[0]) << endl; - } else { - Debug("integers") << " " << lem[0] << " is not assigned a SAT literal" << endl; - } - if(d_valuation.isSatLiteral(lem[1])) { - Debug("integers") << " " << lem[1] << " == " << d_valuation.getSatValue(lem[1]) << endl; - } else { - Debug("integers") << " " << lem[1] << " is not assigned a SAT literal" << endl; - } - return lem; + + // Node lem = NodeManager::currentNM()->mkNode(kind::OR, leq, geq); + // Trace("integers") << "integers: branch & bound: " << lem << endl; + // if(d_valuation.isSatLiteral(lem[0])) { + // Debug("integers") << " " << lem[0] << " == " << d_valuation.getSatValue(lem[0]) << endl; + // } else { + // Debug("integers") << " " << lem[0] << " is not assigned a SAT literal" << endl; + // } + // if(d_valuation.isSatLiteral(lem[1])) { + // Debug("integers") << " " << lem[1] << " == " << d_valuation.getSatValue(lem[1]) << endl; + // } else { + // Debug("integers") << " " << lem[1] << " is not assigned a SAT literal" << endl; + // } + // return lem; } } @@ -1822,7 +1938,8 @@ bool TheoryArith::splitDisequalities(){ */ void TheoryArith::debugPrintAssertions() { Debug("arith::print_assertions") << "Assertions:" << endl; - for (ArithVar i = 0; i < d_variables.size(); ++ i) { + for (var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){ + ArithVar i = *vi; if (d_partialModel.hasLowerBound(i)) { Constraint lConstr = d_partialModel.getLowerBoundConstraint(i); Debug("arith::print_assertions") << lConstr << endl; @@ -1842,13 +1959,15 @@ void TheoryArith::debugPrintAssertions() { void TheoryArith::debugPrintModel(){ Debug("arith::print_model") << "Model:" << endl; - - for (ArithVar i = 0; i < d_variables.size(); ++ i) { - Debug("arith::print_model") << d_variables[i] << " : " << - d_partialModel.getAssignment(i); - if(d_tableau.isBasic(i)) - Debug("arith::print_model") << " (basic)"; - Debug("arith::print_model") << endl; + for (var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){ + ArithVar i = *vi; + if(d_arithvarNodeMap.hasNode(i)){ + Debug("arith::print_model") << d_arithvarNodeMap.asNode(i) << " : " << + d_partialModel.getAssignment(i); + if(d_tableau.isBasic(i)) + Debug("arith::print_model") << " (basic)"; + Debug("arith::print_model") << endl; + } } } @@ -2057,7 +2176,8 @@ Rational TheoryArith::deltaValueForTotalOrder() const{ relevantDeltaValues.insert(val); } - for(ArithVar v = 0; v < d_variables.size(); ++v){ + for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){ + ArithVar v = *vi; const DeltaRational& value = d_partialModel.getAssignment(v); relevantDeltaValues.insert(value); if( d_partialModel.hasLowerBound(v)){ @@ -2108,7 +2228,8 @@ void TheoryArith::collectModelInfo( TheoryModel* m, bool fullModel ){ // TODO: // This is not very good for user push/pop.... // Revisit when implementing push/pop - for(ArithVar v = 0; v < d_variables.size(); ++v){ + for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){ + ArithVar v = *vi; if(!isSlackVariable(v)){ Node term = d_arithvarNodeMap.asNode(v); @@ -2187,13 +2308,13 @@ void TheoryArith::notifyRestart(){ } bool TheoryArith::entireStateIsConsistent(const string& s){ - typedef std::vector<Node>::const_iterator VarIter; bool result = true; - for(VarIter i = d_variables.begin(), end = d_variables.end(); i != end; ++i){ - ArithVar var = d_arithvarNodeMap.asArithVar(*i); + for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){ + ArithVar var = *vi; + //ArithVar var = d_arithvarNodeMap.asArithVar(*i); if(!d_partialModel.assignmentIsConsistent(var)){ d_partialModel.printModel(var); - Warning() << s << ":" << "Assignment is not consistent for " << var << *i; + Warning() << s << ":" << "Assignment is not consistent for " << var << d_arithvarNodeMap.asNode(var); if(d_tableau.isBasic(var)){ Warning() << " (basic)"; } @@ -2205,15 +2326,14 @@ bool TheoryArith::entireStateIsConsistent(const string& s){ } bool TheoryArith::unenqueuedVariablesAreConsistent(){ - typedef std::vector<Node>::const_iterator VarIter; bool result = true; - for(VarIter i = d_variables.begin(), end = d_variables.end(); i != end; ++i){ - ArithVar var = d_arithvarNodeMap.asArithVar(*i); + for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){ + ArithVar var = *vi; if(!d_partialModel.assignmentIsConsistent(var)){ if(!d_simplex.debugIsInCollectionQueue(var)){ d_partialModel.printModel(var); - Warning() << "Unenqueued var is not consistent for " << var << *i; + Warning() << "Unenqueued var is not consistent for " << var << d_arithvarNodeMap.asNode(var); if(d_tableau.isBasic(var)){ Warning() << " (basic)"; } @@ -2221,7 +2341,7 @@ bool TheoryArith::unenqueuedVariablesAreConsistent(){ result = false; } else if(Debug.isOn("arith::consistency::initial")){ d_partialModel.printModel(var); - Warning() << "Initial var is not consistent for " << var << *i; + Warning() << "Initial var is not consistent for " << var << d_arithvarNodeMap.asNode(var); if(d_tableau.isBasic(var)){ Warning() << " (basic)"; } diff --git a/src/theory/arith/theory_arith.h b/src/theory/arith/theory_arith.h index 6a83c501b..31f9bfcaf 100644 --- a/src/theory/arith/theory_arith.h +++ b/src/theory/arith/theory_arith.h @@ -22,6 +22,7 @@ #include "context/context.h" #include "context/cdlist.h" #include "context/cdhashset.h" +#include "context/cdinsert_hashmap.h" #include "context/cdqueue.h" #include "expr/node.h" @@ -88,17 +89,20 @@ private: /** Static learner. */ ArithStaticLearner d_learner; - /** - * List of the variables in the system. - * This is needed to keep a positive ref count on slack variables. - */ - std::vector<Node> d_variables; + + ArithVar d_numberOfVariables; + inline ArithVar getNumberOfVariables() const { return d_numberOfVariables; } + std::vector<ArithVar> d_pool; + void releaseArithVar(ArithVar v); /** * The map between arith variables to nodes. */ ArithVarNodeMap d_arithvarNodeMap; + typedef ArithVarNodeMap::var_iterator var_iterator; + var_iterator var_begin() const { return d_arithvarNodeMap.var_begin(); } + var_iterator var_end() const { return d_arithvarNodeMap.var_end(); } NodeSet d_setupNodes; bool isSetup(Node n) const { @@ -135,7 +139,7 @@ private: * A superset of all of the assertions that currently are not the literal for * their constraint do not match constraint literals. Not just the witnesses. */ - context::CDHashMap<TNode, Constraint, TNodeHashFunction> d_assertionsThatDoNotMatchTheirLiterals; + context::CDInsertHashMap<Node, Constraint, NodeHashFunction> d_assertionsThatDoNotMatchTheirLiterals; /** * (For the moment) the type hierarchy goes as: @@ -272,6 +276,18 @@ private: void outputConflicts(); + class TempVarMalloc : public ArithVarMalloc { + private: + TheoryArith& d_ta; + public: + TempVarMalloc(TheoryArith& ta) : d_ta(ta) {} + ArithVar request(){ + Node skolem = mkRealSkolem("tmpVar"); + return d_ta.requestArithVar(skolem, false); + } + void release(ArithVar v){ d_ta.releaseArithVar(v); } + } d_tempVarMalloc; + /** * A copy of the tableau. * This is equivalent to the original tableau if d_tableauSizeHasBeenModified @@ -432,7 +448,7 @@ private: ArithVar requestArithVar(TNode x, bool slack); /** Initial (not context dependent) sets up for a variable.*/ - void setupInitialValue(ArithVar x); + void setupBasicValue(ArithVar x); /** Initial (not context dependent) sets up for a new slack variable.*/ void setupSlack(TNode left); @@ -521,6 +537,11 @@ private: /** Debugging only routine. Prints the model. */ void debugPrintModel(); + /** Counts the number of fullCheck calls to arithmetic. */ + uint32_t d_fullCheckCounter; + std::vector<Node> cutAllBounded() const; + Node branchIntegerVariable(ArithVar x) const; + /** These fields are designed to be accessible to TheoryArith methods. */ class Statistics { public: diff --git a/src/theory/arrays/theory_arrays.cpp b/src/theory/arrays/theory_arrays.cpp index a05d30517..aabd3a62d 100644 --- a/src/theory/arrays/theory_arrays.cpp +++ b/src/theory/arrays/theory_arrays.cpp @@ -537,7 +537,7 @@ EqualityStatus TheoryArrays::getEqualityStatus(TNode a, TNode b) { void TheoryArrays::computeCareGraph() { if (d_sharedArrays.size() > 0) { - context::CDHashSet<TNode, TNodeHashFunction>::iterator it1 = d_sharedArrays.begin(), it2, iend = d_sharedArrays.end(); + CDNodeSet::key_iterator it1 = d_sharedArrays.key_begin(), it2, iend = d_sharedArrays.key_end(); for (; it1 != iend; ++it1) { for (it2 = it1, ++it2; it2 != iend; ++it2) { if ((*it1).getType() != (*it2).getType()) { @@ -1261,7 +1261,7 @@ void TheoryArrays::checkRowLemmas(TNode a, TNode b) void TheoryArrays::queueRowLemma(RowLemmaType lem) { - if (d_conflict || d_RowAlreadyAdded.count(lem) != 0) { + if (d_conflict || d_RowAlreadyAdded.contains(lem)) { return; } TNode a = lem.first; @@ -1407,7 +1407,7 @@ void TheoryArrays::dischargeLemmas() for (unsigned count = 0; count < sz; ++count) { RowLemmaType l = d_RowQueue.front(); d_RowQueue.pop(); - if (d_RowAlreadyAdded.count(l) != 0) { + if (d_RowAlreadyAdded.contains(l)) { continue; } diff --git a/src/theory/arrays/theory_arrays.h b/src/theory/arrays/theory_arrays.h index 240cfad9a..172482e71 100644 --- a/src/theory/arrays/theory_arrays.h +++ b/src/theory/arrays/theory_arrays.h @@ -333,8 +333,10 @@ class TheoryArrays : public Theory { context::CDQueue<RowLemmaType> d_RowQueue; context::CDHashSet<RowLemmaType, RowLemmaTypeHashFunction > d_RowAlreadyAdded; - context::CDHashSet<TNode, TNodeHashFunction> d_sharedArrays; - context::CDHashSet<TNode, TNodeHashFunction> d_sharedOther; + typedef context::CDHashSet<Node, NodeHashFunction> CDNodeSet; + + CDNodeSet d_sharedArrays; + CDNodeSet d_sharedOther; context::CDO<bool> d_sharedTerms; context::CDList<TNode> d_reads; std::hash_map<TNode, Node, TNodeHashFunction> d_diseqCache; diff --git a/src/theory/arrays/theory_arrays_model.cpp b/src/theory/arrays/theory_arrays_model.cpp index 86bdad53f..4f7584ac1 100644 --- a/src/theory/arrays/theory_arrays_model.cpp +++ b/src/theory/arrays/theory_arrays_model.cpp @@ -41,7 +41,7 @@ Node ArrayModel::getValue( TheoryModel* m, Node i ){ return it->second; }else{ return NodeManager::currentNM()->mkNode( SELECT, getArrayValue(), i ); - //return d_default_value; //TODO: guarentee I can return this here + //return d_default_value; //TODO: guarantee I can return this here } } diff --git a/src/theory/arrays/theory_arrays_model.h b/src/theory/arrays/theory_arrays_model.h index 4825c710d..c82c7635d 100644 --- a/src/theory/arrays/theory_arrays_model.h +++ b/src/theory/arrays/theory_arrays_model.h @@ -1,11 +1,11 @@ /********************* */ /*! \file theory_arrays_model.h ** \verbatim - ** Original author: ajreynol - ** Major contributors: none + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** diff --git a/src/theory/arrays/theory_arrays_rewriter.h b/src/theory/arrays/theory_arrays_rewriter.h index da479616d..9cbb0c9e8 100644 --- a/src/theory/arrays/theory_arrays_rewriter.h +++ b/src/theory/arrays/theory_arrays_rewriter.h @@ -37,8 +37,12 @@ typedef expr::Attribute<attr::ArrayConstantMostFrequentValueCountTag, uint64_t> typedef expr::Attribute<attr::ArrayConstantMostFrequentValueTag, Node> ArrayConstantMostFrequentValueAttr; class TheoryArraysRewriter { - static Node normalizeConstant(TNode node) { + return normalizeConstant(node, node[1].getType().getCardinality()); + } +public: + //this function is called by printers when using the option "--model-u-dt-enum" + static Node normalizeConstant(TNode node, Cardinality indexCard) { TNode store = node[0]; TNode index = node[1]; TNode value = node[2]; @@ -112,7 +116,6 @@ class TheoryArraysRewriter { return n; } - Cardinality indexCard = index.getType().getCardinality(); if (indexCard.isInfinite()) { return n; } @@ -189,13 +192,15 @@ class TheoryArraysRewriter { std::vector<Node> newIndices; TypeEnumerator te(index.getType()); bool needToSort = false; - while (!te.isFinished()) { + unsigned numTe = 0; + while (!te.isFinished() && (!indexCard.isFinite() || numTe<indexCard.getFiniteCardinality().toUnsignedInt())) { if (indexSet.find(*te) == indexSet.end()) { if (!newIndices.empty() && (!(newIndices.back() < (*te)))) { needToSort = true; } newIndices.push_back(*te); } + ++numTe; ++te; } Assert(indexCard.compare(newIndices.size() + depth) == Cardinality::EQUAL); diff --git a/src/theory/booleans/circuit_propagator.h b/src/theory/booleans/circuit_propagator.h index e62f9b7a1..de4bb30d2 100644 --- a/src/theory/booleans/circuit_propagator.h +++ b/src/theory/booleans/circuit_propagator.h @@ -64,6 +64,8 @@ public: else return ASSIGNED_TO_TRUE; } + typedef std::hash_map<Node, std::vector<Node>, NodeHashFunction> BackEdgesMap; + private: context::Context d_context; @@ -96,7 +98,7 @@ private: */ DataClearer< std::vector<TNode> > d_propagationQueueClearer; - /** Are we in conflict */ + /** Are we in conflict? */ context::CDO<bool> d_conflict; /** Map of substitutions */ @@ -107,8 +109,9 @@ private: */ DataClearer< std::vector<Node> > d_learnedLiteralClearer; - /** Back edges from nodes to where they are used */ - typedef std::hash_map<Node, std::vector<Node>, NodeHashFunction> BackEdgesMap; + /** + * Back edges from nodes to where they are used. + */ BackEdgesMap d_backEdges; /** @@ -118,7 +121,7 @@ private: /** Nodes that have been attached already (computed forward edges for) */ // All the nodes we've visited so far - context::CDHashSet<TNode, TNodeHashFunction> d_seen; + context::CDHashSet<Node, NodeHashFunction> d_seen; /** * Assignment status of each node. @@ -157,6 +160,7 @@ private: } } +public: /** True iff Node is assigned in circuit (either true or false). */ bool isAssigned(TNode n) const { AssignmentMap::const_iterator i = d_state.find(n); @@ -179,6 +183,7 @@ private: return (*i).second == ASSIGNED_TO_TRUE; } +private: /** Predicate for use in STL functions. */ class IsAssigned : public std::unary_function<TNode, bool> { CircuitPropagator& d_circuit; @@ -268,6 +273,13 @@ public: */ bool propagate() CVC4_WARN_UNUSED_RESULT; + /** + * Get the back edges of this circuit. + */ + const BackEdgesMap& getBackEdges() const { + return d_backEdges; + } + };/* class CircuitPropagator */ }/* CVC4::theory::booleans namespace */ diff --git a/src/theory/bv/theory_bv.h b/src/theory/bv/theory_bv.h index 0c8df3fca..e38f3568c 100644 --- a/src/theory/bv/theory_bv.h +++ b/src/theory/bv/theory_bv.h @@ -40,8 +40,8 @@ class TheoryBV : public Theory { context::Context* d_context; /** Context dependent set of atoms we already propagated */ - context::CDHashSet<TNode, TNodeHashFunction> d_alreadyPropagatedSet; - context::CDHashSet<TNode, TNodeHashFunction> d_sharedTermsSet; + context::CDHashSet<Node, NodeHashFunction> d_alreadyPropagatedSet; + context::CDHashSet<Node, NodeHashFunction> d_sharedTermsSet; BitblastSolver d_bitblastSolver; EqualitySolver d_equalitySolver; diff --git a/src/theory/bv/theory_bv_rewrite_rules_simplification.h b/src/theory/bv/theory_bv_rewrite_rules_simplification.h index a8aef748b..9d1cafab9 100644 --- a/src/theory/bv/theory_bv_rewrite_rules_simplification.h +++ b/src/theory/bv/theory_bv_rewrite_rules_simplification.h @@ -430,10 +430,6 @@ Node RewriteRule<BitwiseNotOr>::apply(TNode node) { template<> inline bool RewriteRule<XorNot>::applies(TNode node) { Unreachable(); - if (node.getKind() == kind::BITVECTOR_XOR && - node.getNumChildren() == 2 && - node[0].getKind() == kind::BITVECTOR_NOT && - node[1].getKind() == kind::BITVECTOR_NOT); } template<> inline diff --git a/src/theory/datatypes/options b/src/theory/datatypes/options index d250bee74..1daa30981 100644 --- a/src/theory/datatypes/options +++ b/src/theory/datatypes/options @@ -11,7 +11,7 @@ module DATATYPES "theory/datatypes/options.h" Datatypes theory # cdr( nil ) has no set value. expert-option dtRewriteErrorSel /--disable-dt-rewrite-error-sel bool :default true disable rewriting incorrectly applied selectors to arbitrary ground term -expert-option dtForceAssignment /--dt-force-assignment bool :default false :read-write +option dtForceAssignment /--dt-force-assignment bool :default false :read-write force the datatypes solver to give specific values to all datatypes terms before answering sat endmodule diff --git a/src/theory/mkrewriter b/src/theory/mkrewriter index 88ac5b9fb..2d8012bfb 100755 --- a/src/theory/mkrewriter +++ b/src/theory/mkrewriter @@ -2,7 +2,7 @@ # # mkrewriter # Morgan Deters <mdeters@cs.nyu.edu> for CVC4 -# Copyright (c) 2010-2012 The CVC4 Project +# Copyright (c) 2010-2013 The CVC4 Project # # The purpose of this script is to create rewriter_tables.h from a template # and a list of theory kinds. @@ -14,13 +14,14 @@ # Output is to standard out. # -copyright=2010-2012 +copyright=2010-2013 cat <<EOF /********************* */ /** rewriter_tables.h ** - ** Copyright $copyright The AcSys Group, New York University, and as below. + ** Copyright $copyright New York University and The University of Iowa, + ** and as below. ** ** This header file automatically generated by: ** diff --git a/src/theory/mktheorytraits b/src/theory/mktheorytraits index a44d8e9c3..3edc7c140 100755 --- a/src/theory/mktheorytraits +++ b/src/theory/mktheorytraits @@ -2,7 +2,7 @@ # # mktheorytraits # Morgan Deters <mdeters@cs.nyu.edu> for CVC4 -# Copyright (c) 2010-2012 The CVC4 Project +# Copyright (c) 2010-2013 The CVC4 Project # # The purpose of this script is to create theory_traits.h from a template # and a list of theory kinds. @@ -14,7 +14,7 @@ # Output is to standard out. # -copyright=2010-2012 +copyright=2010-2013 filename=`basename "$1" | sed 's,_template,,'` @@ -22,7 +22,8 @@ cat <<EOF /********************* */ /** $filename ** - ** Copyright $copyright The AcSys Group, New York University, and as below. + ** Copyright $copyright New York University and The University of Iowa, + ** and as below. ** ** This header file automatically generated by: ** diff --git a/src/theory/model.h b/src/theory/model.h index e283ee183..98eeda97a 100644 --- a/src/theory/model.h +++ b/src/theory/model.h @@ -87,7 +87,7 @@ public: void addSubstitution(TNode x, TNode t, bool invalidateCache = true); /** add term function * addTerm( n ) will do any model-specific processing necessary for n, - * such as contraining the interpretation of uninterpretted functions, + * such as constraining the interpretation of uninterpreted functions, * and adding n to the equality engine of this model */ virtual void addTerm(TNode n); diff --git a/src/theory/quantifiers/first_order_model.cpp b/src/theory/quantifiers/first_order_model.cpp index 3d98674a8..8272ce168 100644 --- a/src/theory/quantifiers/first_order_model.cpp +++ b/src/theory/quantifiers/first_order_model.cpp @@ -42,10 +42,6 @@ void FirstOrderModel::reset(){ TheoryModel::reset(); } -void FirstOrderModel::addTerm( Node n ){ - TheoryModel::addTerm( n ); -} - void FirstOrderModel::initialize( bool considerAxioms ){ //rebuild models d_uf_model_tree.clear(); diff --git a/src/theory/quantifiers/first_order_model.h b/src/theory/quantifiers/first_order_model.h index 3779579fd..50a941968 100644 --- a/src/theory/quantifiers/first_order_model.h +++ b/src/theory/quantifiers/first_order_model.h @@ -33,8 +33,6 @@ class TermDb; class FirstOrderModel : public TheoryModel { private: - //add term function - void addTerm( Node n ); //for initialize model void initializeModelForTerm( Node n ); /** whether an axiom is asserted */ diff --git a/src/theory/quantifiers/inst_gen.cpp b/src/theory/quantifiers/inst_gen.cpp index b5f92c5f8..dea371e9c 100755..100644 --- a/src/theory/quantifiers/inst_gen.cpp +++ b/src/theory/quantifiers/inst_gen.cpp @@ -1,13 +1,11 @@ /********************* */ /*! \file inst_gen.cpp ** \verbatim - ** Original author: ajreynol - ** Major contributors: none + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** diff --git a/src/theory/quantifiers/inst_gen.h b/src/theory/quantifiers/inst_gen.h index c8de2c642..930133954 100755..100644 --- a/src/theory/quantifiers/inst_gen.h +++ b/src/theory/quantifiers/inst_gen.h @@ -1,13 +1,11 @@ /********************* */ /*! \file inst_gen.h ** \verbatim - ** Original author: ajreynol - ** Major contributors: none + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** @@ -52,10 +50,10 @@ public: int getNumMatches() { return d_matches.size(); } bool getMatch( EqualityQuery* q, int i, InstMatch& m ); Node getMatchValue( int i ) { return d_match_values[i]; } -}; +};/* class InstGenProcess */ -} -} -} +}/* CVC4::theory::quantifiers namespace */ +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ -#endif +#endif /* __CVC4__THEORY__QUANTIFIERS__INST_GEN_H */ diff --git a/src/theory/quantifiers/inst_match.cpp b/src/theory/quantifiers/inst_match.cpp index dcd7a1b79..85a96f90a 100644 --- a/src/theory/quantifiers/inst_match.cpp +++ b/src/theory/quantifiers/inst_match.cpp @@ -103,12 +103,12 @@ void InstMatch::makeComplete( Node f, QuantifiersEngine* qe ){ } } -void InstMatch::makeInternalRepresentative( QuantifiersEngine* qe ){ - EqualityQueryQuantifiersEngine* eqqe = (EqualityQueryQuantifiersEngine*)qe->getEqualityQuery(); - for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){ - d_map[ it->first ] = eqqe->getInternalRepresentative( it->second ); - } -} +//void InstMatch::makeInternalRepresentative( QuantifiersEngine* qe ){ +// EqualityQueryQuantifiersEngine* eqqe = (EqualityQueryQuantifiersEngine*)qe->getEqualityQuery(); +// for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){ +// d_map[ it->first ] = eqqe->getInternalRepresentative( it->second ); +// } +//} void InstMatch::makeRepresentative( QuantifiersEngine* qe ){ for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){ diff --git a/src/theory/quantifiers/inst_match.h b/src/theory/quantifiers/inst_match.h index 8b2d9726b..b9e61be20 100644 --- a/src/theory/quantifiers/inst_match.h +++ b/src/theory/quantifiers/inst_match.h @@ -58,7 +58,7 @@ public: /** make complete */ void makeComplete( Node f, QuantifiersEngine* qe ); /** make internal representative */ - void makeInternalRepresentative( QuantifiersEngine* qe ); + //void makeInternalRepresentative( QuantifiersEngine* qe ); /** make representative */ void makeRepresentative( QuantifiersEngine* qe ); /** get value */ diff --git a/src/theory/quantifiers/inst_match_generator.cpp b/src/theory/quantifiers/inst_match_generator.cpp index 2822597e1..386834385 100755..100644 --- a/src/theory/quantifiers/inst_match_generator.cpp +++ b/src/theory/quantifiers/inst_match_generator.cpp @@ -1,15 +1,16 @@ /********************* */ /*! \file inst_match_generator.cpp -** \verbatim -** Original author: ajreynol -** Major contributors: bobot -** Minor contributors (to current version): barrett, mdeters -** This file is part of the CVC4 prototype. -** Copyright (c) 2009-2012 New York University and The University of Iowa -** See the file COPYING in the top-level source directory for licensing -** information.\endverbatim -** -** \brief Implementation of inst match generator class + ** \verbatim + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** [[ Add lengthier description here ]] + ** \todo document this file **/ #include "theory/quantifiers/inst_match_generator.h" @@ -29,116 +30,111 @@ namespace theory { namespace inst { -InstMatchGenerator::InstMatchGenerator( Node pat, QuantifiersEngine* qe, int matchPolicy ) : d_matchPolicy( matchPolicy ){ - initializePattern( pat, qe ); -} - -InstMatchGenerator::InstMatchGenerator( std::vector< Node >& pats, QuantifiersEngine* qe, int matchPolicy ) : d_matchPolicy( matchPolicy ){ - if( pats.size()==1 ){ - initializePattern( pats[0], qe ); - }else{ - initializePatterns( pats, qe ); - } +InstMatchGenerator::InstMatchGenerator( Node pat, int matchPolicy ) : d_matchPolicy( matchPolicy ){ + d_active_add = false; + Assert( pat.hasAttribute(InstConstantAttribute()) ); + d_pattern = pat; + d_match_pattern = pat; + d_next = NULL; } -void InstMatchGenerator::initializePatterns( std::vector< Node >& pats, QuantifiersEngine* qe ){ - int childMatchPolicy = d_matchPolicy==MATCH_GEN_EFFICIENT_E_MATCH ? 0 : d_matchPolicy; - for( int i=0; i<(int)pats.size(); i++ ){ - d_children.push_back( new InstMatchGenerator( pats[i], qe, childMatchPolicy ) ); +void InstMatchGenerator::setActiveAdd(){ + d_active_add = true; + if( d_next!=NULL ){ + d_next->setActiveAdd(); } - d_pattern = Node::null(); - d_match_pattern = Node::null(); - d_cg = NULL; } -void InstMatchGenerator::initializePattern( Node pat, QuantifiersEngine* qe ){ - Debug("inst-match-gen") << "Pattern term is " << pat << std::endl; - Assert( pat.hasAttribute(InstConstantAttribute()) ); - d_pattern = pat; - d_match_pattern = pat; - if( d_match_pattern.getKind()==NOT ){ - //we want to add the children of the NOT - d_match_pattern = d_pattern[0]; - } - if( d_match_pattern.getKind()==IFF || d_match_pattern.getKind()==EQUAL ){ - if( !d_match_pattern[0].hasAttribute(InstConstantAttribute()) ){ - Assert( d_match_pattern[1].hasAttribute(InstConstantAttribute()) ); - //swap sides - d_pattern = NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), d_match_pattern[1], d_match_pattern[0] ); - d_pattern = pat.getKind()==NOT ? d_pattern.notNode() : d_pattern; - if( pat.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching - d_match_pattern = d_match_pattern[1]; - }else{ - d_match_pattern = d_pattern[0][0]; - } - }else if( !d_match_pattern[1].hasAttribute(InstConstantAttribute()) ){ - Assert( d_match_pattern[0].hasAttribute(InstConstantAttribute()) ); - if( pat.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching - d_match_pattern = d_match_pattern[0]; +void InstMatchGenerator::initialize( QuantifiersEngine* qe, std::vector< InstMatchGenerator * > & gens ){ + if( !d_pattern.isNull() ){ + Debug("inst-match-gen") << "Pattern term is " << d_pattern << std::endl; + if( d_match_pattern.getKind()==NOT ){ + //we want to add the children of the NOT + d_match_pattern = d_pattern[0]; + } + if( d_match_pattern.getKind()==IFF || d_match_pattern.getKind()==EQUAL ){ + if( !d_match_pattern[0].hasAttribute(InstConstantAttribute()) ){ + Assert( d_match_pattern[1].hasAttribute(InstConstantAttribute()) ); + //swap sides + Node pat = d_pattern; + d_pattern = NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), d_match_pattern[1], d_match_pattern[0] ); + d_pattern = pat.getKind()==NOT ? d_pattern.notNode() : d_pattern; + if( pat.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching + d_match_pattern = d_match_pattern[1]; + }else{ + d_match_pattern = d_pattern[0][0]; + } + }else if( !d_match_pattern[1].hasAttribute(InstConstantAttribute()) ){ + Assert( d_match_pattern[0].hasAttribute(InstConstantAttribute()) ); + if( d_pattern.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching + d_match_pattern = d_match_pattern[0]; + } } } - } - int childMatchPolicy = MATCH_GEN_DEFAULT; - for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){ - if( d_match_pattern[i].hasAttribute(InstConstantAttribute()) ){ - if( d_match_pattern[i].getKind()!=INST_CONSTANT ){ - d_children.push_back( new InstMatchGenerator( d_match_pattern[i], qe, childMatchPolicy ) ); - d_children_index.push_back( i ); + int childMatchPolicy = MATCH_GEN_DEFAULT; + for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){ + if( d_match_pattern[i].hasAttribute(InstConstantAttribute()) ){ + if( d_match_pattern[i].getKind()!=INST_CONSTANT ){ + InstMatchGenerator * cimg = new InstMatchGenerator( d_match_pattern[i], childMatchPolicy ); + d_children.push_back( cimg ); + d_children_index.push_back( i ); + gens.push_back( cimg ); + } } } - } - Debug("inst-match-gen") << "Pattern is " << d_pattern << ", match pattern is " << d_match_pattern << std::endl; + Debug("inst-match-gen") << "Pattern is " << d_pattern << ", match pattern is " << d_match_pattern << std::endl; - //create candidate generator - if( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF ){ - Assert( d_matchPolicy==MATCH_GEN_DEFAULT ); - //we will be producing candidates via literal matching heuristics - if( d_pattern.getKind()!=NOT ){ - //candidates will be all equalities - d_cg = new inst::CandidateGeneratorQELitEq( qe, d_match_pattern ); - }else{ - //candidates will be all disequalities - d_cg = new inst::CandidateGeneratorQELitDeq( qe, d_match_pattern ); - } - }else if( d_pattern.getKind()==EQUAL || d_pattern.getKind()==IFF || d_pattern.getKind()==NOT ){ - Assert( d_matchPolicy==MATCH_GEN_DEFAULT ); - if( d_pattern.getKind()==NOT ){ - Unimplemented("Disequal generator unimplemented"); - }else{ - Assert( Trigger::isAtomicTrigger( d_match_pattern ) ); - //we are matching only in a particular equivalence class + //create candidate generator + if( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF ){ + Assert( d_matchPolicy==MATCH_GEN_DEFAULT ); + //we will be producing candidates via literal matching heuristics + if( d_pattern.getKind()!=NOT ){ + //candidates will be all equalities + d_cg = new inst::CandidateGeneratorQELitEq( qe, d_match_pattern ); + }else{ + //candidates will be all disequalities + d_cg = new inst::CandidateGeneratorQELitDeq( qe, d_match_pattern ); + } + }else if( d_pattern.getKind()==EQUAL || d_pattern.getKind()==IFF || d_pattern.getKind()==NOT ){ + Assert( d_matchPolicy==MATCH_GEN_DEFAULT ); + if( d_pattern.getKind()==NOT ){ + Unimplemented("Disequal generator unimplemented"); + }else{ + Assert( Trigger::isAtomicTrigger( d_match_pattern ) ); + //we are matching only in a particular equivalence class + d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern.getOperator() ); + //store the equivalence class that we will call d_cg->reset( ... ) on + d_eq_class = d_pattern[1]; + } + }else if( Trigger::isAtomicTrigger( d_match_pattern ) ){ + //if( d_matchPolicy==MATCH_GEN_EFFICIENT_E_MATCH ){ + //Warning() << "Currently efficient e matching is not taken into account for quantifiers: " << d_pattern << std::endl; + //} + //we will be scanning lists trying to find d_match_pattern.getOperator() d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern.getOperator() ); - //store the equivalence class that we will call d_cg->reset( ... ) on - d_eq_class = d_pattern[1]; - } - }else if( Trigger::isAtomicTrigger( d_match_pattern ) ){ - //if( d_matchPolicy==MATCH_GEN_EFFICIENT_E_MATCH ){ - //Warning() << "Currently efficient e matching is not taken into account for quantifiers: " << d_pattern << std::endl; - //} - //we will be scanning lists trying to find d_match_pattern.getOperator() - d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern.getOperator() ); - }else{ - d_cg = new CandidateGeneratorQueue; - if( !Trigger::getPatternArithmetic( d_match_pattern.getAttribute(InstConstantAttribute()), d_match_pattern, d_arith_coeffs ) ){ - Debug("inst-match-gen") << "(?) Unknown matching pattern is " << d_match_pattern << std::endl; - //Warning() << "(?) Unknown matching pattern is " << d_match_pattern << std::endl; - d_matchPolicy = MATCH_GEN_INTERNAL_ERROR; }else{ - Debug("matching-arith") << "Generated arithmetic pattern for " << d_match_pattern << ": " << std::endl; - for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ - Debug("matching-arith") << " " << it->first << " -> " << it->second << std::endl; + d_cg = new CandidateGeneratorQueue; + if( !Trigger::getPatternArithmetic( d_match_pattern.getAttribute(InstConstantAttribute()), d_match_pattern, d_arith_coeffs ) ){ + Debug("inst-match-gen") << "(?) Unknown matching pattern is " << d_match_pattern << std::endl; + //Warning() << "(?) Unknown matching pattern is " << d_match_pattern << std::endl; + d_matchPolicy = MATCH_GEN_INTERNAL_ERROR; + }else{ + Debug("matching-arith") << "Generated arithmetic pattern for " << d_match_pattern << ": " << std::endl; + for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ + Debug("matching-arith") << " " << it->first << " -> " << it->second << std::endl; + } + //we will treat this as match gen internal arithmetic + d_matchPolicy = MATCH_GEN_INTERNAL_ARITHMETIC; } - //we will treat this as match gen internal arithmetic - d_matchPolicy = MATCH_GEN_INTERNAL_ARITHMETIC; } } } /** get match (not modulo equality) */ -bool InstMatchGenerator::getMatch( Node t, InstMatch& m, QuantifiersEngine* qe ){ +bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngine* qe ){ Debug("matching") << "Matching " << t << " against pattern " << d_match_pattern << " (" - << m.size() << ")" << ", " << d_children.size() << std::endl; + << m << ")" << ", " << d_children.size() << std::endl; Assert( !d_match_pattern.isNull() ); if( qe->d_optMatchIgnoreModelBasis && t.getAttribute(ModelBasisAttribute()) ){ return true; @@ -148,9 +144,8 @@ bool InstMatchGenerator::getMatch( Node t, InstMatch& m, QuantifiersEngine* qe ) return false; }else{ EqualityQuery* q = qe->getEqualityQuery(); - //add m to partial match vector - std::vector< InstMatch > partial; - partial.push_back( InstMatch( &m ) ); + //save previous match + InstMatch prev( &m ); //if t is null Assert( !t.isNull() ); Assert( !t.hasAttribute(InstConstantAttribute()) ); @@ -160,13 +155,13 @@ bool InstMatchGenerator::getMatch( Node t, InstMatch& m, QuantifiersEngine* qe ) for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){ if( d_match_pattern[i].hasAttribute(InstConstantAttribute()) ){ if( d_match_pattern[i].getKind()==INST_CONSTANT ){ - if( !partial[0].setMatch( q, d_match_pattern[i], t[i] ) ){ + if( !m.setMatch( q, d_match_pattern[i], t[i] ) ){ //match is in conflict Debug("matching-debug") << "Match in conflict " << t[i] << " and " << d_match_pattern[i] << " because " - << partial[0].get(d_match_pattern[i]) + << m.get(d_match_pattern[i]) << std::endl; - Debug("matching-fail") << "Match fail: " << partial[0].get(d_match_pattern[i]) << " and " << t[i] << std::endl; + Debug("matching-fail") << "Match fail: " << m.get(d_match_pattern[i]) << " and " << t[i] << std::endl; return false; } } @@ -184,48 +179,25 @@ bool InstMatchGenerator::getMatch( Node t, InstMatch& m, QuantifiersEngine* qe ) for( int i=0; i<(int)d_children.size(); i++ ){ Node rep = q->getRepresentative( t[ d_children_index[i] ] ); reps.push_back( rep ); - d_children[i]->d_cg->reset( rep ); + d_children[i]->reset( rep, qe ); } - - //combine child matches - int index = 0; - while( index>=0 && index<(int)d_children.size() ){ - partial.push_back( InstMatch( &partial[index] ) ); - if( d_children[index]->getNextMatch2( partial[index+1], qe ) ){ - index++; - }else{ - d_children[index]->d_cg->reset( reps[index] ); - partial.pop_back(); - if( !partial.empty() ){ - partial.pop_back(); - } - index--; + bool success = true; + if( d_next!=NULL ){ + success = d_next->getNextMatch( f, m, qe ); + }else{ + if( d_active_add ){ + Trace("active-add") << "Active Adding instantiation " << m << std::endl; + success = qe->addInstantiation( f, m ); + Trace("active-add") << "Success = " << success << std::endl; } } - if( index>=0 ){ - m = partial.back(); - return true; - }else{ - return false; + if( !success ){ + m = InstMatch( &prev ); } + return success; } } -bool InstMatchGenerator::getNextMatch2( InstMatch& m, QuantifiersEngine* qe, bool saveMatched ){ - bool success = false; - Node t; - do{ - //get the next candidate term t - t = d_cg->getNextCandidate(); - //if t not null, try to fit it into match m - if( !t.isNull() && t.getType()==d_match_pattern.getType() ){ - success = getMatch( t, m, qe ); - } - }while( !success && !t.isNull() ); - if (saveMatched) m.d_matched = t; - return success; -} - bool InstMatchGenerator::getMatchArithmetic( Node t, InstMatch& m, QuantifiersEngine* qe ){ Debug("matching-arith") << "Matching " << t << " " << d_match_pattern << std::endl; if( !d_arith_coeffs.empty() ){ @@ -298,74 +270,57 @@ void InstMatchGenerator::resetInstantiationRound( QuantifiersEngine* qe ){ } void InstMatchGenerator::reset( Node eqc, QuantifiersEngine* qe ){ - if( d_match_pattern.isNull() ){ - for( int i=0; i<(int)d_children.size(); i++ ){ - d_children[i]->reset( eqc, qe ); - } - d_partial.clear(); - }else{ - if( !d_eq_class.isNull() ){ - //we have a specific equivalence class in mind - //we are producing matches for f(E) ~ t, where E is a non-ground vector of terms, and t is a ground term - //just look in equivalence class of the RHS - d_cg->reset( d_eq_class ); - }else{ - d_cg->reset( eqc ); - } + if( !eqc.isNull() ){ + d_eq_class = eqc; } + //we have a specific equivalence class in mind + //we are producing matches for f(E) ~ t, where E is a non-ground vector of terms, and t is a ground term + //just look in equivalence class of the RHS + d_cg->reset( d_eq_class ); } -bool InstMatchGenerator::getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ +bool InstMatchGenerator::getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ){ m.d_matched = Node::null(); - if( d_match_pattern.isNull() ){ - int index = (int)d_partial.size(); - while( index>=0 && index<(int)d_children.size() ){ - if( index>0 ){ - d_partial.push_back( InstMatch( &d_partial[index-1] ) ); - }else{ - d_partial.push_back( InstMatch() ); - } - if( d_children[index]->getNextMatch( d_partial[index], qe ) ){ - index++; - }else{ - d_children[index]->reset( Node::null(), qe ); - d_partial.pop_back(); - if( !d_partial.empty() ){ - d_partial.pop_back(); - } - index--; - } - } - if( index>=0 ){ - m = d_partial.back(); - d_partial.pop_back(); - return true; - }else{ - return false; + //Debug("matching") << this << " " << d_pattern << " get next match 2 " << m << " in eq class " << d_eq_class << std::endl; + bool success = false; + Node t; + do{ + //get the next candidate term t + t = d_cg->getNextCandidate(); + //if t not null, try to fit it into match m + if( !t.isNull() && t.getType()==d_match_pattern.getType() ){ + success = getMatch( f, t, m, qe ); } - }else{ - bool res = getNextMatch2( m, qe, true ); - Assert(!res || !m.d_matched.isNull()); - return res; + }while( !success && !t.isNull() ); + m.d_matched = t; + if( !success ){ + //Debug("matching") << this << " failed, reset " << d_eq_class << std::endl; + //we failed, must reset + reset( d_eq_class, qe ); } + return success; } int InstMatchGenerator::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ){ - //now, try to add instantiation for each match produced + //try to add instantiation for each match produced int addedLemmas = 0; InstMatch m; - while( getNextMatch( m, qe ) ){ - //m.makeInternal( d_quantEngine->getEqualityQuery() ); - m.add( baseMatch ); - if( qe->addInstantiation( f, m ) ){ - addedLemmas++; - if( qe->d_optInstLimitActive && qe->d_optInstLimit<=0 ){ - return addedLemmas; + while( getNextMatch( f, m, qe ) ){ + if( !d_active_add ){ + //m.makeInternal( d_quantEngine->getEqualityQuery() ); + m.add( baseMatch ); + if( qe->addInstantiation( f, m ) ){ + addedLemmas++; + if( qe->d_optInstLimitActive && qe->d_optInstLimit<=0 ){ + return addedLemmas; + } } + m.clear(); + }else{ + addedLemmas++; } - m.clear(); } //return number of lemmas added return addedLemmas; @@ -375,7 +330,7 @@ int InstMatchGenerator::addTerm( Node f, Node t, QuantifiersEngine* qe ){ Assert( options::eagerInstQuant() ); if( !d_match_pattern.isNull() ){ InstMatch m; - if( getMatch( t, m, qe ) ){ + if( getMatch( f, t, m, qe ) ){ if( qe->addInstantiation( f, m ) ){ return 1; } @@ -388,6 +343,40 @@ int InstMatchGenerator::addTerm( Node f, Node t, QuantifiersEngine* qe ){ return 0; } + +InstMatchGenerator* InstMatchGenerator::mkInstMatchGenerator( Node pat, QuantifiersEngine* qe ) { + std::vector< Node > pats; + pats.push_back( pat ); + return mkInstMatchGenerator( pats, qe ); +} + +InstMatchGenerator* InstMatchGenerator::mkInstMatchGenerator( std::vector< Node >& pats, QuantifiersEngine* qe ) { + size_t pCounter = 0; + InstMatchGenerator* prev = NULL; + InstMatchGenerator* oinit = NULL; + while( pCounter<pats.size() ){ + size_t counter = 0; + std::vector< InstMatchGenerator* > gens; + InstMatchGenerator* init = new InstMatchGenerator(pats[pCounter]); + if(pCounter==0){ + oinit = init; + } + gens.push_back(init); + //chain the resulting match generators together + while (counter<gens.size()) { + InstMatchGenerator* curr = gens[counter]; + if( prev ){ + prev->d_next = curr; + } + curr->initialize(qe, gens); + prev = curr; + counter++; + } + pCounter++; + } + return oinit; +} + /** constructors */ InstMatchGeneratorMulti::InstMatchGeneratorMulti( Node f, std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption ) : d_f( f ){ @@ -408,7 +397,7 @@ d_f( f ){ for( int i=0; i<(int)pats.size(); i++ ){ Node n = pats[i]; //make the match generator - d_children.push_back( new InstMatchGenerator( n, qe, matchOption ) ); + d_children.push_back( InstMatchGenerator::mkInstMatchGenerator( n, qe ) ); //compute unique/shared variables std::vector< int > unique_vars; std::map< int, bool > shared_vars; @@ -473,7 +462,7 @@ int InstMatchGeneratorMulti::addInstantiations( Node f, InstMatch& baseMatch, Qu Debug("smart-multi-trigger") << "Calculate matches " << i << std::endl; std::vector< InstMatch > newMatches; InstMatch m; - while( d_children[i]->getNextMatch( m, qe ) ){ + while( d_children[i]->getNextMatch( f, m, qe ) ){ m.makeRepresentative( qe ); newMatches.push_back( InstMatch( &m ) ); m.clear(); @@ -595,7 +584,7 @@ int InstMatchGeneratorMulti::addTerm( Node f, Node t, QuantifiersEngine* qe ){ if( ((InstMatchGenerator*)d_children[i])->d_match_pattern.getOperator()==t.getOperator() ){ InstMatch m; //if it produces a match, then process it with the rest - if( ((InstMatchGenerator*)d_children[i])->getMatch( t, m, qe ) ){ + if( ((InstMatchGenerator*)d_children[i])->getMatch( f, t, m, qe ) ){ processNewMatch( qe, m, i, addedLemmas ); } } diff --git a/src/theory/quantifiers/inst_match_generator.h b/src/theory/quantifiers/inst_match_generator.h index dd3663e0a..b201fa60f 100755..100644 --- a/src/theory/quantifiers/inst_match_generator.h +++ b/src/theory/quantifiers/inst_match_generator.h @@ -1,11 +1,11 @@ /********************* */ /*! \file inst_match_generator.h ** \verbatim - ** Original author: ajreynol - ** Major contributors: bobot - ** Minor contributors (to current version): mdeters - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** @@ -38,11 +38,13 @@ public: /** reset, eqc is the equivalence class to search in (any if eqc=null) */ virtual void reset( Node eqc, QuantifiersEngine* qe ) = 0; /** get the next match. must call reset( eqc ) before this function. */ - virtual bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ) = 0; + virtual bool getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ) = 0; /** add instantiations directly */ virtual int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ) = 0; /** add ground term t, called when t is added to term db */ virtual int addTerm( Node f, Node t, QuantifiersEngine* qe ) = 0; + /** set active add */ + virtual void setActiveAdd() {} };/* class IMGenerator */ class CandidateGenerator; @@ -56,15 +58,14 @@ private: /** children generators */ std::vector< InstMatchGenerator* > d_children; std::vector< int > d_children_index; - /** partial vector */ - std::vector< InstMatch > d_partial; + /** the next generator in order */ + InstMatchGenerator* d_next; /** eq class */ Node d_eq_class; /** for arithmetic matching */ std::map< Node, Node > d_arith_coeffs; /** initialize pattern */ - void initializePatterns( std::vector< Node >& pats, QuantifiersEngine* qe ); - void initializePattern( Node pat, QuantifiersEngine* qe ); + void initialize( QuantifiersEngine* qe, std::vector< InstMatchGenerator * > & gens ); public: enum { //options for producing matches @@ -75,10 +76,6 @@ public: MATCH_GEN_INTERNAL_ERROR, }; private: - /** get the next match. must call d_cg->reset( ... ) before using. - only valid for use where !d_match_pattern.isNull(). - */ - bool getNextMatch2( InstMatch& m, QuantifiersEngine* qe, bool saveMatched = false ); /** for arithmetic */ bool getMatchArithmetic( Node t, InstMatch& m, QuantifiersEngine* qe ); public: @@ -86,11 +83,10 @@ public: d_match_pattern and t should have the same shape. only valid for use where !d_match_pattern.isNull(). */ - bool getMatch( Node t, InstMatch& m, QuantifiersEngine* qe ); + bool getMatch( Node f, Node t, InstMatch& m, QuantifiersEngine* qe ); /** constructors */ - InstMatchGenerator( Node pat, QuantifiersEngine* qe, int matchOption = 0 ); - InstMatchGenerator( std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption = 0 ); + InstMatchGenerator( Node pat, int matchOption = 0 ); /** destructor */ ~InstMatchGenerator(){} /** The pattern we are producing matches for. @@ -105,11 +101,17 @@ public: /** reset, eqc is the equivalence class to search in (any if eqc=null) */ void reset( Node eqc, QuantifiersEngine* qe ); /** get the next match. must call reset( eqc ) before this function. */ - bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ); + bool getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ); /** add instantiations */ int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ); /** add ground term t */ int addTerm( Node f, Node t, QuantifiersEngine* qe ); + + bool d_active_add; + void setActiveAdd(); + + static InstMatchGenerator* mkInstMatchGenerator( Node pat, QuantifiersEngine* qe ); + static InstMatchGenerator* mkInstMatchGenerator( std::vector< Node >& pats, QuantifiersEngine* qe ); };/* class InstMatchGenerator */ /** smart multi-trigger implementation */ @@ -152,7 +154,7 @@ public: /** reset, eqc is the equivalence class to search in (any if eqc=null) */ void reset( Node eqc, QuantifiersEngine* qe ); /** get the next match. must call reset( eqc ) before this function. (not implemented) */ - bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ) { return false; } + bool getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ) { return false; } /** add instantiations */ int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ); /** add ground term t */ @@ -178,7 +180,7 @@ public: /** reset, eqc is the equivalence class to search in (any if eqc=null) */ void reset( Node eqc, QuantifiersEngine* qe ) {} /** get the next match. must call reset( eqc ) before this function. (not implemented) */ - bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ) { return false; } + bool getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ) { return false; } /** add instantiations */ int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ); /** add ground term t, possibly add instantiations */ diff --git a/src/theory/quantifiers/inst_strategy_cbqi.cpp b/src/theory/quantifiers/inst_strategy_cbqi.cpp index aba311500..b12fed619 100755..100644 --- a/src/theory/quantifiers/inst_strategy_cbqi.cpp +++ b/src/theory/quantifiers/inst_strategy_cbqi.cpp @@ -1,11 +1,11 @@ /********************* */ /*! \file inst_strategy_cbqi.cpp ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): bobot, mdeters - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** @@ -46,11 +46,12 @@ void InstStrategySimplex::processResetInstantiationRound( Theory::Effort effort d_tableaux.clear(); d_ceTableaux.clear(); //search for instantiation rows in simplex tableaux - ArithVarToNodeMap avtnm = d_th->d_arithvarNodeMap.getArithVarToNodeMap(); - for( ArithVarToNodeMap::iterator it = avtnm.begin(); it != avtnm.end(); ++it ){ - ArithVar x = (*it).first; + ArithVarNodeMap& avnm = d_th->d_arithvarNodeMap; + ArithVarNodeMap::var_iterator vi, vend; + for(vi = avnm.var_begin(), vend = avnm.var_end(); vi != vend; ++vi ){ + ArithVar x = *vi; if( d_th->d_partialModel.hasEitherBound( x ) ){ - Node n = (*it).second; + Node n = avnm.asNode(x); Node f; NodeBuilder<> t(kind::PLUS); if( n.getKind()==PLUS ){ @@ -167,10 +168,11 @@ void InstStrategySimplex::addTermToRow( ArithVar x, Node n, Node& f, NodeBuilder } void InstStrategySimplex::debugPrint( const char* c ){ - ArithVarToNodeMap avtnm = d_th->d_arithvarNodeMap.getArithVarToNodeMap(); - for( ArithVarToNodeMap::iterator it = avtnm.begin(); it != avtnm.end(); ++it ){ - ArithVar x = (*it).first; - Node n = (*it).second; + const ArithVarNodeMap& avnm = d_th->d_arithvarNodeMap; + ArithVarNodeMap::var_iterator vi, vend; + for(vi = avnm.var_begin(), vend = avnm.var_end(); vi != vend; ++vi ){ + ArithVar x = *vi; + Node n = avnm.asNode(x); //if( ((TheoryArith*)getTheory())->d_partialModel.hasEitherBound( x ) ){ Debug(c) << x << " : " << n << ", bounds = "; if( d_th->d_partialModel.hasLowerBound( x ) ){ diff --git a/src/theory/quantifiers/inst_strategy_cbqi.h b/src/theory/quantifiers/inst_strategy_cbqi.h index 1c9565de6..de548ab14 100755..100644 --- a/src/theory/quantifiers/inst_strategy_cbqi.h +++ b/src/theory/quantifiers/inst_strategy_cbqi.h @@ -1,11 +1,11 @@ /********************* */ /*! \file inst_strategy_cbqi.h ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): mdeters - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** diff --git a/src/theory/quantifiers/inst_strategy_e_matching.cpp b/src/theory/quantifiers/inst_strategy_e_matching.cpp index edf9d976c..3f5cc7666 100755..100644 --- a/src/theory/quantifiers/inst_strategy_e_matching.cpp +++ b/src/theory/quantifiers/inst_strategy_e_matching.cpp @@ -1,11 +1,11 @@ /********************* */ /*! \file inst_strategy_e_matching.cpp ** \verbatim - ** Original author: ajreynol - ** Major contributors: mdeters - ** Minor contributors (to current version): bobot - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** @@ -27,7 +27,6 @@ using namespace CVC4::theory; using namespace CVC4::theory::inst; using namespace CVC4::theory::quantifiers; -#define USE_SINGLE_TRIGGER_BEFORE_MULTI_TRIGGER //#define MULTI_TRIGGER_FULL_EFFORT_HALF #define MULTI_MULTI_TRIGGERS @@ -65,18 +64,13 @@ int InstStrategyUserPatterns::process( Node f, Theory::Effort effort, int e ){ //Notice() << "Try user-provided patterns..." << std::endl; for( int i=0; i<(int)d_user_gen[f].size(); i++ ){ bool processTrigger = true; - if( effort!=Theory::EFFORT_LAST_CALL && d_user_gen[f][i]->isMultiTrigger() ){ -//#ifdef MULTI_TRIGGER_FULL_EFFORT_HALF -// processTrigger = d_counter[f]%2==0; -//#endif - } if( processTrigger ){ //if( d_user_gen[f][i]->isMultiTrigger() ) - //Notice() << " Process (user) " << (*d_user_gen[f][i]) << " for " << f << "..." << std::endl; + Trace("process-trigger") << " Process (user) " << (*d_user_gen[f][i]) << "..." << std::endl; InstMatch baseMatch; int numInst = d_user_gen[f][i]->addInstantiations( baseMatch ); //if( d_user_gen[f][i]->isMultiTrigger() ) - //Notice() << " Done, numInst = " << numInst << "." << std::endl; + Trace("process-trigger") << " Done, numInst = " << numInst << "." << std::endl; d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_user_patterns += numInst; if( d_user_gen[f][i]->isMultiTrigger() ){ d_quantEngine->d_statistics.d_multi_trigger_instantiations += numInst; @@ -125,6 +119,7 @@ void InstStrategyAutoGenTriggers::processResetInstantiationRound( Theory::Effort itt->first->reset( Node::null() ); } } + d_processed_trigger.clear(); } int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e ){ @@ -134,6 +129,7 @@ int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e ) if( e<peffort ){ return STATUS_UNFINISHED; }else{ + int status = STATUS_UNKNOWN; bool gen = false; if( e==peffort ){ if( d_counter.find( f )==d_counter.end() ){ @@ -147,7 +143,7 @@ int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e ) gen = true; } if( gen ){ - generateTriggers( f ); + generateTriggers( f, effort, e, status ); } Debug("quant-uf-strategy") << "Try auto-generated triggers... " << d_tr_strategy << " " << e << std::endl; //Notice() << "Try auto-generated triggers..." << std::endl; @@ -155,18 +151,14 @@ int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e ) Trigger* tr = itt->first; if( tr ){ bool processTrigger = itt->second; - if( effort!=Theory::EFFORT_LAST_CALL && tr->isMultiTrigger() ){ -#ifdef MULTI_TRIGGER_FULL_EFFORT_HALF - processTrigger = d_counter[f]%2==0; -#endif - } - if( processTrigger ){ + if( processTrigger && d_processed_trigger[f].find( tr )==d_processed_trigger[f].end() ){ + d_processed_trigger[f][tr] = true; //if( tr->isMultiTrigger() ) - Debug("quant-uf-strategy-auto-gen-triggers") << " Process " << (*tr) << "..." << std::endl; + Trace("process-trigger") << " Process " << (*tr) << "..." << std::endl; InstMatch baseMatch; int numInst = tr->addInstantiations( baseMatch ); //if( tr->isMultiTrigger() ) - Debug("quant-uf-strategy-auto-gen-triggers") << " Done, numInst = " << numInst << "." << std::endl; + Trace("process-trigger") << " Done, numInst = " << numInst << "." << std::endl; if( d_tr_strategy==Trigger::TS_MIN_TRIGGER ){ d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_auto_gen_min += numInst; }else{ @@ -181,24 +173,24 @@ int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e ) } Debug("quant-uf-strategy") << "done." << std::endl; //Notice() << "done" << std::endl; + return status; } - return STATUS_UNKNOWN; } -void InstStrategyAutoGenTriggers::generateTriggers( Node f ){ - Debug("auto-gen-trigger") << "Generate trigger for " << f << std::endl; +void InstStrategyAutoGenTriggers::generateTriggers( Node f, Theory::Effort effort, int e, int & status ){ + Trace("auto-gen-trigger-debug") << "Generate trigger for " << f << std::endl; if( d_patTerms[0].find( f )==d_patTerms[0].end() ){ //determine all possible pattern terms based on trigger term selection strategy d_tr_strategy d_patTerms[0][f].clear(); d_patTerms[1][f].clear(); std::vector< Node > patTermsF; Trigger::collectPatTerms( d_quantEngine, f, d_quantEngine->getTermDatabase()->getInstConstantBody( f ), patTermsF, d_tr_strategy, true ); - Debug("auto-gen-trigger") << "Collected pat terms for " << d_quantEngine->getTermDatabase()->getInstConstantBody( f ) << std::endl; - Debug("auto-gen-trigger") << " "; + Trace("auto-gen-trigger") << "Collected pat terms for " << d_quantEngine->getTermDatabase()->getInstConstantBody( f ) << std::endl; + Trace("auto-gen-trigger") << " "; for( int i=0; i<(int)patTermsF.size(); i++ ){ - Debug("auto-gen-trigger") << patTermsF[i] << " "; + Trace("auto-gen-trigger") << patTermsF[i] << " "; } - Debug("auto-gen-trigger") << std::endl; + Trace("auto-gen-trigger") << std::endl; //extend to literal matching (if applicable) d_quantEngine->getPhaseReqTerms( f, patTermsF ); //sort into single/multi triggers @@ -214,23 +206,22 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){ } } d_made_multi_trigger[f] = false; - Debug("auto-gen-trigger") << "Single triggers for " << f << " : " << std::endl; - Debug("auto-gen-trigger") << " "; + Trace("auto-gen-trigger") << "Single triggers for " << f << " : " << std::endl; + Trace("auto-gen-trigger") << " "; for( int i=0; i<(int)d_patTerms[0][f].size(); i++ ){ - Debug("auto-gen-trigger") << d_patTerms[0][f][i] << " "; + Trace("auto-gen-trigger") << d_patTerms[0][f][i] << " "; } - Debug("auto-gen-trigger") << std::endl; - Debug("auto-gen-trigger") << "Multi-trigger term pool for " << f << " : " << std::endl; - Debug("auto-gen-trigger") << " "; + Trace("auto-gen-trigger") << std::endl; + Trace("auto-gen-trigger") << "Multi-trigger term pool for " << f << " : " << std::endl; + Trace("auto-gen-trigger") << " "; for( int i=0; i<(int)d_patTerms[1][f].size(); i++ ){ - Debug("auto-gen-trigger") << d_patTerms[1][f][i] << " "; + Trace("auto-gen-trigger") << d_patTerms[1][f][i] << " "; } - Debug("auto-gen-trigger") << std::endl; + Trace("auto-gen-trigger") << std::endl; } //populate candidate pattern term vector for the current trigger std::vector< Node > patTerms; -#ifdef USE_SINGLE_TRIGGER_BEFORE_MULTI_TRIGGER //try to add single triggers first for( int i=0; i<(int)d_patTerms[0][f].size(); i++ ){ if( !d_single_trigger_gen[d_patTerms[0][f][i]] ){ @@ -241,13 +232,9 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){ if( patTerms.empty() ){ patTerms.insert( patTerms.begin(), d_patTerms[1][f].begin(), d_patTerms[1][f].end() ); } -#else - patTerms.insert( patTerms.begin(), d_patTerms[0][f].begin(), d_patTerms[0][f].end() ); - patTerms.insert( patTerms.begin(), d_patTerms[1][f].begin(), d_patTerms[1][f].end() ); -#endif if( !patTerms.empty() ){ - Debug("auto-gen-trigger") << "Generate trigger for " << f << std::endl; + Trace("auto-gen-trigger") << "Generate trigger for " << f << std::endl; //sort terms based on relevance if( d_rlv_strategy==RELEVANCE_DEFAULT ){ sortQuantifiersForSymbol sqfs; @@ -273,6 +260,15 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){ options::smartTriggers() ); d_single_trigger_gen[ patTerms[0] ] = true; }else{ + //only generate multi trigger if effort level > 5, or if no single triggers exist + if( !d_patTerms[0][f].empty() ){ + if( e<=5 ){ + status = STATUS_UNFINISHED; + return; + }else{ + Trace("multi-trigger-debug") << "Resort to choosing multi-triggers..." << std::endl; + } + } //if we are re-generating triggers, shuffle based on some method if( d_made_multi_trigger[f] ){ #ifndef MULTI_MULTI_TRIGGERS diff --git a/src/theory/quantifiers/inst_strategy_e_matching.h b/src/theory/quantifiers/inst_strategy_e_matching.h index b5ff90a62..13d443c6a 100755..100644 --- a/src/theory/quantifiers/inst_strategy_e_matching.h +++ b/src/theory/quantifiers/inst_strategy_e_matching.h @@ -1,11 +1,11 @@ /********************* */ /*! \file inst_strategy_e_matching.h ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): bobot, mdeters - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** @@ -80,12 +80,14 @@ private: std::map< Node, bool > d_is_single_trigger; std::map< Node, bool > d_single_trigger_gen; std::map< Node, bool > d_made_multi_trigger; + //processed trigger this round + std::map< Node, std::map< inst::Trigger*, bool > > d_processed_trigger; private: /** process functions */ void processResetInstantiationRound( Theory::Effort effort ); int process( Node f, Theory::Effort effort, int e ); /** generate triggers */ - void generateTriggers( Node f ); + void generateTriggers( Node f, Theory::Effort effort, int e, int & status ); public: /** tstrt is the type of triggers to use (maximum depth, minimum depth, or all) rstrt is the relevance setting for trigger (use only relevant triggers vs. use all) diff --git a/src/theory/quantifiers/instantiation_engine.cpp b/src/theory/quantifiers/instantiation_engine.cpp index 53977ee4f..75cc10615 100644 --- a/src/theory/quantifiers/instantiation_engine.cpp +++ b/src/theory/quantifiers/instantiation_engine.cpp @@ -84,16 +84,18 @@ bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){ //add cbqi lemma //get the counterexample literal Node ceLit = d_quantEngine->getTermDatabase()->getCounterexampleLiteral( f ); - //require any decision on cel to be phase=true - d_quantEngine->getOutputChannel().requirePhase( ceLit, true ); - Debug("cbqi-debug") << "Require phase " << ceLit << " = true." << std::endl; - //add counterexample lemma - NodeBuilder<> nb(kind::OR); - nb << f << ceLit; - Node lem = nb; - Debug("cbqi-debug") << "Counterexample lemma : " << lem << std::endl; - d_quantEngine->getOutputChannel().lemma( lem ); - addedLemma = true; + if( !ceLit.isNull() ){ + //require any decision on cel to be phase=true + d_quantEngine->getOutputChannel().requirePhase( ceLit, true ); + Debug("cbqi-debug") << "Require phase " << ceLit << " = true." << std::endl; + //add counterexample lemma + NodeBuilder<> nb(kind::OR); + nb << f << ceLit; + Node lem = nb; + Debug("cbqi-debug") << "Counterexample lemma : " << lem << std::endl; + d_quantEngine->getOutputChannel().lemma( lem ); + addedLemma = true; + } } } if( addedLemma ){ diff --git a/src/theory/quantifiers/macros.cpp b/src/theory/quantifiers/macros.cpp index 5c7c9415e..bf67bdd25 100755..100644 --- a/src/theory/quantifiers/macros.cpp +++ b/src/theory/quantifiers/macros.cpp @@ -1,11 +1,11 @@ /********************* */ /*! \file macros.cpp ** \verbatim - ** Original author: ajreynol - ** Major contributors: none + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** @@ -358,7 +358,7 @@ Node QuantifierMacros::simplify( Node n ){ if( n.getKind()==APPLY_UF ){ Node op = n.getOperator(); if( d_macro_defs.find( op )!=d_macro_defs.end() && !d_macro_defs[op].isNull() ){ - //do subsitutition + //do substitution Node ret = d_macro_defs[op]; ret = ret.substitute( d_macro_basis[op].begin(), d_macro_basis[op].end(), children.begin(), children.end() ); return ret; diff --git a/src/theory/quantifiers/macros.h b/src/theory/quantifiers/macros.h index f4e58665d..140f02966 100755..100644 --- a/src/theory/quantifiers/macros.h +++ b/src/theory/quantifiers/macros.h @@ -1,11 +1,11 @@ /********************* */ /*! \file macros.h ** \verbatim - ** Original author: ajreynol - ** Major contributors: none + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** diff --git a/src/theory/quantifiers/model_builder.cpp b/src/theory/quantifiers/model_builder.cpp index 2f44140c2..d1c04ceab 100644 --- a/src/theory/quantifiers/model_builder.cpp +++ b/src/theory/quantifiers/model_builder.cpp @@ -526,7 +526,7 @@ int ModelEngineBuilderDefault::doInstGen( FirstOrderModel* fm, Node f ){ //if applicable, try to add exceptions here if( !tr_terms.empty() ){ //make a trigger for these terms, add instantiations - inst::Trigger* tr = inst::Trigger::mkTrigger( d_qe, f, tr_terms ); + inst::Trigger* tr = inst::Trigger::mkTrigger( d_qe, f, tr_terms, 0, true, inst::Trigger::TR_MAKE_NEW, options::smartTriggers() ); //Notice() << "Trigger = " << (*tr) << std::endl; tr->resetInstantiationRound(); tr->reset( Node::null() ); diff --git a/src/theory/quantifiers/model_engine.cpp b/src/theory/quantifiers/model_engine.cpp index bf6ea11f0..39377d11c 100644 --- a/src/theory/quantifiers/model_engine.cpp +++ b/src/theory/quantifiers/model_engine.cpp @@ -73,9 +73,8 @@ void ModelEngine::check( Theory::Effort e ){ if( addedLemmas==0 ){ Trace("model-engine-debug") << "Verify uf ss is minimal..." << std::endl; //let the strong solver verify that the model is minimal - uf::StrongSolverTheoryUf* uf_ss = ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getStrongSolver(); //for debugging, this will if there are terms in the model that the strong solver was not notified of - uf_ss->debugModel( fm ); + ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getStrongSolver()->debugModel( fm ); Trace("model-engine-debug") << "Check model..." << std::endl; d_incomplete_check = false; //print debug @@ -164,7 +163,7 @@ int ModelEngine::checkModel( int checkOption ){ Trace("model-engine-debug") << " "; for( size_t i=0; i<it->second.size(); i++ ){ //Trace("model-engine-debug") << it->second[i] << " "; - Node r = ((EqualityQueryQuantifiersEngine*)d_quantEngine->getEqualityQuery())->getInternalRepresentative( it->second[i] ); + Node r = ((EqualityQueryQuantifiersEngine*)d_quantEngine->getEqualityQuery())->getRepresentative( it->second[i] ); Trace("model-engine-debug") << r << " "; } Trace("model-engine-debug") << std::endl; diff --git a/src/theory/quantifiers/options b/src/theory/quantifiers/options index bc45e6051..6b204eb60 100644 --- a/src/theory/quantifiers/options +++ b/src/theory/quantifiers/options @@ -45,8 +45,8 @@ option macrosQuant --macros-quant bool :default false option smartTriggers /--disable-smart-triggers bool :default true disable smart triggers # Whether to use relevent triggers -option relevantTriggers /--relevant-triggers bool :default true - prefer triggers that are more relevant based on SInE style method +option relevantTriggers --relevant-triggers bool :default true + prefer triggers that are more relevant based on SInE style analysis # Whether to consider terms in the bodies of quantifiers for matching option registerQuantBodyTerms --register-quant-body-terms bool :default false @@ -71,7 +71,7 @@ option userPatternsQuant /--ignore-user-patterns bool :default true option flipDecision --flip-decision/ bool :default false turns on flip decision heuristic -option internalReps --disable-quant-internal-reps/ bool :default true +option internalReps /--disable-quant-internal-reps bool :default true disables instantiating with representatives chosen by quantifiers engine option finiteModelFind --finite-model-find bool :default false diff --git a/src/theory/quantifiers/quant_util.cpp b/src/theory/quantifiers/quant_util.cpp index a78cd5612..9e4a2a14a 100755..100644 --- a/src/theory/quantifiers/quant_util.cpp +++ b/src/theory/quantifiers/quant_util.cpp @@ -1,11 +1,11 @@ /********************* */ /*! \file quant_util.cpp ** \verbatim - ** Original author: ajreynol - ** Major contributors: bobot, mdeters + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** diff --git a/src/theory/quantifiers/quant_util.h b/src/theory/quantifiers/quant_util.h index 1daaf3ea1..85602dbab 100755..100644 --- a/src/theory/quantifiers/quant_util.h +++ b/src/theory/quantifiers/quant_util.h @@ -1,11 +1,11 @@ /********************* */ /*! \file quant_util.h ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): mdeters, bobot - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** diff --git a/src/theory/quantifiers/quantifiers_attributes.cpp b/src/theory/quantifiers/quantifiers_attributes.cpp index 108c09c87..b00fe45f4 100644 --- a/src/theory/quantifiers/quantifiers_attributes.cpp +++ b/src/theory/quantifiers/quantifiers_attributes.cpp @@ -1,11 +1,11 @@ /********************* */ /*! \file quantifiers_attributes.cpp ** \verbatim - ** Original author: ajreynol - ** Major contributors: none + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** diff --git a/src/theory/quantifiers/quantifiers_attributes.h b/src/theory/quantifiers/quantifiers_attributes.h index f5a8a749a..8e8ebe97a 100644 --- a/src/theory/quantifiers/quantifiers_attributes.h +++ b/src/theory/quantifiers/quantifiers_attributes.h @@ -1,11 +1,11 @@ /********************* */ /*! \file quantifiers_attributes.h ** \verbatim - ** Original author: ajreynol - ** Major contributors: none + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** diff --git a/src/theory/quantifiers/term_database.cpp b/src/theory/quantifiers/term_database.cpp index d60aa2ef4..65624686a 100644 --- a/src/theory/quantifiers/term_database.cpp +++ b/src/theory/quantifiers/term_database.cpp @@ -206,6 +206,7 @@ Node TermDb::getModelBasisTerm( TypeNode tn, int i ){ ModelBasisAttribute mba; mbt.setAttribute(mba,true); d_model_basis_term[tn] = mbt; + Trace("model-basis-term") << "Choose " << mbt << " as model basis term for " << tn << std::endl; } return d_model_basis_term[tn]; } @@ -337,6 +338,14 @@ Node TermDb::getInstConstantBody( Node f ){ Node TermDb::getCounterexampleLiteral( Node f ){ if( d_ce_lit.find( f )==d_ce_lit.end() ){ Node ceBody = getInstConstantBody( f ); + //check if any variable are of bad types, and fail if so + for( size_t i=0; i<d_inst_constants[f].size(); i++ ){ + if( d_inst_constants[f][i].getType().isBoolean() ){ + d_ce_lit[ f ] = Node::null(); + return Node::null(); + } + } + //otherwise, ensure literal Node ceLit = d_quantEngine->getValuation().ensureLiteral( ceBody.notNode() ); d_ce_lit[ f ] = ceLit; setInstantiationConstantAttr( ceLit, f ); @@ -367,6 +376,10 @@ Node TermDb::getSkolemizedBody( Node f ){ Node skv = NodeManager::currentNM()->mkSkolem( "skv_$$", f[0][i].getType(), "is a termdb-created skolemized body" ); d_skolem_constants[ f ].push_back( skv ); vars.push_back( f[0][i] ); + //carry information for sort inference + if( options::sortInference() ){ + d_quantEngine->getTheoryEngine()->getSortInference()->setSkolemVar( f, f[0][i], skv ); + } } d_skolem_body[ f ] = f[ 1 ].substitute( vars.begin(), vars.end(), d_skolem_constants[ f ].begin(), d_skolem_constants[ f ].end() ); @@ -515,6 +528,34 @@ int TermDb::isInstanceOf( Node n1, Node n2 ){ return 0; } +bool TermDb::isUnifiableInstanceOf( Node n1, Node n2, std::map< Node, Node >& subs ){ + if( n1==n2 ){ + return true; + }else if( n2.getKind()==INST_CONSTANT ){ + //if( !node_contains( n1, n2 ) ){ + // return false; + //} + if( subs.find( n2 )==subs.end() ){ + subs[n2] = n1; + }else if( subs[n2]!=n1 ){ + return false; + } + return true; + }else if( n1.getKind()==n2.getKind() && n1.getMetaKind()==kind::metakind::PARAMETERIZED ){ + if( n1.getOperator()!=n2.getOperator() ){ + return false; + } + for( int i=0; i<(int)n1.getNumChildren(); i++ ){ + if( !isUnifiableInstanceOf( n1[i], n2[i], subs ) ){ + return false; + } + } + return true; + }else{ + return false; + } +} + void TermDb::filterInstances( std::vector< Node >& nodes ){ std::vector< bool > active; active.resize( nodes.size(), true ); @@ -523,8 +564,10 @@ void TermDb::filterInstances( std::vector< Node >& nodes ){ if( active[i] && active[j] ){ int result = isInstanceOf( nodes[i], nodes[j] ); if( result==1 ){ + Trace("filter-instances") << nodes[j] << " is an instance of " << nodes[i] << std::endl; active[j] = false; }else if( result==-1 ){ + Trace("filter-instances") << nodes[i] << " is an instance of " << nodes[j] << std::endl; active[i] = false; } } diff --git a/src/theory/quantifiers/term_database.h b/src/theory/quantifiers/term_database.h index a1f1de1dc..6bfea5c44 100644 --- a/src/theory/quantifiers/term_database.h +++ b/src/theory/quantifiers/term_database.h @@ -167,7 +167,7 @@ public: /** get counterexample literal (for cbqi) */ Node getCounterexampleLiteral( Node f ); /** returns node n with bound vars of f replaced by instantiation constants of f - node n : is the futur pattern + node n : is the future pattern node f : is the quantifier containing which bind the variable return a pattern where the variable are replaced by variable for instantiation. @@ -212,6 +212,8 @@ private: std::map< TNode, std::vector< TNode > > d_var_contains; /** triggers for each operator */ std::map< Node, std::vector< inst::Trigger* > > d_op_triggers; + /** helper for is intance of */ + bool isUnifiableInstanceOf( Node n1, Node n2, std::map< Node, Node >& subs ); public: /** compute var contains */ void computeVarContains( Node n ); diff --git a/src/theory/quantifiers/trigger.cpp b/src/theory/quantifiers/trigger.cpp index bc577fda6..c4bc248d3 100644 --- a/src/theory/quantifiers/trigger.cpp +++ b/src/theory/quantifiers/trigger.cpp @@ -34,24 +34,26 @@ using namespace CVC4::theory::inst; Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool smartTriggers ) : d_quantEngine( qe ), d_f( f ){ d_nodes.insert( d_nodes.begin(), nodes.begin(), nodes.end() ); + Trace("trigger") << "Trigger for " << f << ": " << std::endl; + for( int i=0; i<(int)d_nodes.size(); i++ ){ + Trace("trigger") << " " << d_nodes[i] << std::endl; + } + Trace("trigger") << ", smart triggers = " << smartTriggers << std::endl; if( smartTriggers ){ if( d_nodes.size()==1 ){ if( isSimpleTrigger( d_nodes[0] ) ){ d_mg = new InstMatchGeneratorSimple( f, d_nodes[0] ); }else{ - d_mg = new InstMatchGenerator( d_nodes[0], qe, matchOption ); + d_mg = InstMatchGenerator::mkInstMatchGenerator( d_nodes[0], qe ); + d_mg->setActiveAdd(); } }else{ d_mg = new InstMatchGeneratorMulti( f, d_nodes, qe, matchOption ); } }else{ - d_mg = new InstMatchGenerator( d_nodes, qe, matchOption ); - } - Trace("trigger") << "Trigger for " << f << ": " << std::endl; - for( int i=0; i<(int)d_nodes.size(); i++ ){ - Trace("trigger") << " " << d_nodes[i] << std::endl; + d_mg = InstMatchGenerator::mkInstMatchGenerator( d_nodes, qe ); + d_mg->setActiveAdd(); } - Trace("trigger") << std::endl; if( d_nodes.size()==1 ){ if( isSimpleTrigger( d_nodes[0] ) ){ ++(qe->d_statistics.d_triggers); @@ -59,7 +61,7 @@ d_quantEngine( qe ), d_f( f ){ ++(qe->d_statistics.d_simple_triggers); } }else{ - Debug("multi-trigger") << "Multi-trigger " << (*this) << std::endl; + Trace("multi-trigger") << "Multi-trigger " << (*this) << " for " << f << std::endl; //Notice() << "Multi-trigger for " << f << " : " << std::endl; //Notice() << " " << (*this) << std::endl; ++(qe->d_statistics.d_multi_triggers); @@ -80,14 +82,14 @@ void Trigger::reset( Node eqc ){ d_mg->reset( eqc, d_quantEngine ); } -bool Trigger::getNextMatch( InstMatch& m ){ - bool retVal = d_mg->getNextMatch( m, d_quantEngine ); +bool Trigger::getNextMatch( Node f, InstMatch& m ){ + bool retVal = d_mg->getNextMatch( f, m, d_quantEngine ); return retVal; } -bool Trigger::getMatch( Node t, InstMatch& m ){ +bool Trigger::getMatch( Node f, Node t, InstMatch& m ){ //FIXME: this assumes d_mg is an inst match generator - return ((InstMatchGenerator*)d_mg)->getMatch( t, m, d_quantEngine ); + return ((InstMatchGenerator*)d_mg)->getMatch( f, t, m, d_quantEngine ); } int Trigger::addTerm( Node t ){ @@ -115,6 +117,7 @@ Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& temp.insert( temp.begin(), nodes.begin(), nodes.end() ); std::map< Node, bool > vars; std::map< Node, std::vector< Node > > patterns; + size_t varCount = 0; for( int i=0; i<(int)temp.size(); i++ ){ bool foundVar = false; qe->getTermDatabase()->computeVarContains( temp[i] ); @@ -122,6 +125,7 @@ Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& Node v = qe->getTermDatabase()->d_var_contains[ temp[i] ][j]; if( v.getAttribute(InstConstantAttribute())==f ){ if( vars.find( v )==vars.end() ){ + varCount++; vars[ v ] = true; foundVar = true; } @@ -134,32 +138,40 @@ Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& patterns[ v ].push_back( temp[i] ); } } - } - //now, minimalize the trigger - for( int i=0; i<(int)trNodes.size(); i++ ){ - bool keepPattern = false; - Node n = trNodes[i]; - for( int j=0; j<(int)qe->getTermDatabase()->d_var_contains[ n ].size(); j++ ){ - Node v = qe->getTermDatabase()->d_var_contains[ n ][j]; - if( patterns[v].size()==1 ){ - keepPattern = true; - break; - } + if( varCount==f[0].getNumChildren() ){ + break; } - if( !keepPattern ){ - //remove from pattern vector + } + if( varCount<f[0].getNumChildren() ){ + //do not generate multi-trigger if it does not contain all variables + return NULL; + }else{ + //now, minimize the trigger + for( int i=0; i<(int)trNodes.size(); i++ ){ + bool keepPattern = false; + Node n = trNodes[i]; for( int j=0; j<(int)qe->getTermDatabase()->d_var_contains[ n ].size(); j++ ){ Node v = qe->getTermDatabase()->d_var_contains[ n ][j]; - for( int k=0; k<(int)patterns[v].size(); k++ ){ - if( patterns[v][k]==n ){ - patterns[v].erase( patterns[v].begin() + k, patterns[v].begin() + k + 1 ); - break; + if( patterns[v].size()==1 ){ + keepPattern = true; + break; + } + } + if( !keepPattern ){ + //remove from pattern vector + for( int j=0; j<(int)qe->getTermDatabase()->d_var_contains[ n ].size(); j++ ){ + Node v = qe->getTermDatabase()->d_var_contains[ n ][j]; + for( int k=0; k<(int)patterns[v].size(); k++ ){ + if( patterns[v][k]==n ){ + patterns[v].erase( patterns[v].begin() + k, patterns[v].begin() + k + 1 ); + break; + } } } + //remove from trigger nodes + trNodes.erase( trNodes.begin() + i, trNodes.begin() + i + 1 ); + i--; } - //remove from trigger nodes - trNodes.erase( trNodes.begin() + i, trNodes.begin() + i + 1 ); - i--; } } }else{ @@ -322,16 +334,16 @@ void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vecto temp.insert( temp.begin(), patTerms2.begin(), patTerms2.end() ); qe->getTermDatabase()->filterInstances( temp ); if( temp.size()!=patTerms2.size() ){ - Debug("trigger-filter-instance") << "Filtered an instance: " << std::endl; - Debug("trigger-filter-instance") << "Old: "; + Trace("trigger-filter-instance") << "Filtered an instance: " << std::endl; + Trace("trigger-filter-instance") << "Old: "; for( int i=0; i<(int)patTerms2.size(); i++ ){ - Debug("trigger-filter-instance") << patTerms2[i] << " "; + Trace("trigger-filter-instance") << patTerms2[i] << " "; } - Debug("trigger-filter-instance") << std::endl << "New: "; + Trace("trigger-filter-instance") << std::endl << "New: "; for( int i=0; i<(int)temp.size(); i++ ){ - Debug("trigger-filter-instance") << temp[i] << " "; + Trace("trigger-filter-instance") << temp[i] << " "; } - Debug("trigger-filter-instance") << std::endl; + Trace("trigger-filter-instance") << std::endl; } if( tstrt==TS_ALL ){ patTerms.insert( patTerms.begin(), temp.begin(), temp.end() ); diff --git a/src/theory/quantifiers/trigger.h b/src/theory/quantifiers/trigger.h index 6fcd316f4..93731283b 100644 --- a/src/theory/quantifiers/trigger.h +++ b/src/theory/quantifiers/trigger.h @@ -56,12 +56,12 @@ public: /** reset, eqc is the equivalence class to search in (search in any if eqc=null) */ void reset( Node eqc ); /** get next match. must call reset( eqc ) once before this function. */ - bool getNextMatch( InstMatch& m ); + bool getNextMatch( Node f, InstMatch& m ); /** get the match against ground term or formula t. the trigger and t should have the same shape. Currently the trigger should not be a multi-trigger. */ - bool getMatch( Node t, InstMatch& m); + bool getMatch( Node f, Node t, InstMatch& m); /** add ground term t, called when t is added to the TermDb */ int addTerm( Node t ); /** return whether this is a multi-trigger */ diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp index 08bdd496b..50433facd 100644 --- a/src/theory/quantifiers_engine.cpp +++ b/src/theory/quantifiers_engine.cpp @@ -71,6 +71,7 @@ d_lemmas_produced_c(u){ d_optMatchIgnoreModelBasis = false; d_optInstLimitActive = false; d_optInstLimit = 0; + d_total_inst_count_debug = 0; } QuantifiersEngine::~QuantifiersEngine(){ @@ -142,10 +143,23 @@ void QuantifiersEngine::check( Theory::Effort e ){ } //build the model if not done so already // this happens if no quantifiers are currently asserted and no model-building module is enabled - if( options::produceModels() && e==Theory::EFFORT_LAST_CALL && !d_hasAddedLemma && !d_model->isModelSet() ){ - d_te->getModelBuilder()->buildModel( d_model, true ); + if( e==Theory::EFFORT_LAST_CALL && !d_hasAddedLemma ){ + if( options::produceModels() && !d_model->isModelSet() ){ + d_te->getModelBuilder()->buildModel( d_model, true ); + } + if( Trace.isOn("inst-per-quant") ){ + for( std::map< Node, int >::iterator it = d_total_inst_debug.begin(); it != d_total_inst_debug.end(); ++it ){ + Trace("inst-per-quant") << " * " << it->second << " for " << it->first << std::endl; + } + } + }else{ + if( Trace.isOn("inst-per-quant-round") ){ + for( std::map< Node, int >::iterator it = d_temp_inst_debug.begin(); it != d_temp_inst_debug.end(); ++it ){ + Trace("inst-per-quant-round") << " * " << it->second << " for " << it->first << std::endl; + d_temp_inst_debug[it->first] = 0; + } + } } - Trace("quant-engine") << "Finished quantifiers engine check." << std::endl; } } @@ -242,6 +256,9 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& vars, std Node lem = nb; //check for duplication if( addLemma( lem ) ){ + d_total_inst_debug[f]++; + d_temp_inst_debug[f]++; + d_total_inst_count_debug++; Trace("inst") << "*** Instantiate " << f << " with " << std::endl; uint64_t maxInstLevel = 0; for( int i=0; i<(int)terms.size(); i++ ){ @@ -354,7 +371,7 @@ bool QuantifiersEngine::addInstantiation( Node f, InstMatch& m, bool modEq, bool //make it representative, this is helpful for recognizing duplication if( mkRep ){ //pick the best possible representative for instantiation, based on past use and simplicity of term - Node r = d_eq_query->getInternalRepresentative( val ); + Node r = d_eq_query->getInternalRepresentative( val, f, i ); Trace("inst-add-debug") << "mkRep " << r << " " << val << std::endl; m.set( ic, r ); } @@ -460,56 +477,6 @@ void QuantifiersEngine::getPhaseReqTerms( Node f, std::vector< Node >& nodes ){ d_statistics.d_lit_phase_nreq += (int)nodes.size(); } } -/* -EqualityQuery* QuantifiersEngine::getEqualityQuery(TypeNode t) { - // Should use skeleton (in order to have the type and the kind - // or any needed other information) instead of only the type - - // TheoryId id = Theory::theoryOf(t); - // inst::EqualityQuery* eq = d_eq_query_arr[id]; - // if(eq == NULL) return d_eq_query_arr[theory::THEORY_UF]; - // else return eq; - - // hack because the generic one is too slow - // TheoryId id = Theory::theoryOf(t); - // if( true || id == theory::THEORY_UF){ - // uf::InstantiatorTheoryUf* ith = static_cast<uf::InstantiatorTheoryUf*>( getInstantiator( theory::THEORY_UF )); - // return new uf::EqualityQueryInstantiatorTheoryUf(ith); - // } - // inst::EqualityQuery* eq = d_eq_query_arr[id]; - // if(eq == NULL) return d_eq_query_arr[theory::THEORY_UF]; - // else return eq; - - - //Currently we use the generic EqualityQuery - return getEqualityQuery(); -} - - -rrinst::CandidateGenerator* QuantifiersEngine::getRRCanGenClasses() { - return new GenericCandidateGeneratorClasses(this); -} - -rrinst::CandidateGenerator* QuantifiersEngine::getRRCanGenClass() { - return new GenericCandidateGeneratorClass(this); -} - -rrinst::CandidateGenerator* QuantifiersEngine::getRRCanGenClasses(TypeNode t) { - // TheoryId id = Theory::theoryOf(t); - // rrinst::CandidateGenerator* eq = getInstantiator(id)->getRRCanGenClasses(); - // if(eq == NULL) return getInstantiator(id)->getRRCanGenClasses(); - // else return eq; - return getRRCanGenClasses(); -} - -rrinst::CandidateGenerator* QuantifiersEngine::getRRCanGenClass(TypeNode t) { - // TheoryId id = Theory::theoryOf(t); - // rrinst::CandidateGenerator* eq = getInstantiator(id)->getRRCanGenClass(); - // if(eq == NULL) return getInstantiator(id)->getRRCanGenClass(); - // else return eq; - return getRRCanGenClass(); -} -*/ QuantifiersEngine::Statistics::Statistics(): d_num_quant("QuantifiersEngine::Num_Quantifiers", 0), @@ -635,39 +602,57 @@ bool EqualityQueryQuantifiersEngine::areDisequal( Node a, Node b ){ return false; } -Node EqualityQueryQuantifiersEngine::getInternalRepresentative( Node a ){ +Node EqualityQueryQuantifiersEngine::getInternalRepresentative( Node a, Node f, int index ){ Node r = getRepresentative( a ); if( !options::internalReps() ){ return r; }else{ - if( d_int_rep.find( r )==d_int_rep.end() ){ + int sortId = 0; + if( optInternalRepSortInference() ){ + sortId = d_qe->getTheoryEngine()->getSortInference()->getSortId( f, f[0][index] ); + } + if( d_int_rep[sortId].find( r )==d_int_rep[sortId].end() ){ std::vector< Node > eqc; getEquivalenceClass( r, eqc ); //find best selection for representative - Node r_best = r; - int r_best_score = getRepScore( r ); + Node r_best; + int r_best_score; for( size_t i=0; i<eqc.size(); i++ ){ - int score = getRepScore( eqc[i] ); + int score = getRepScore( eqc[i], f, index ); + if( optInternalRepSortInference() ){ + int e_sortId = d_qe->getTheoryEngine()->getSortInference()->getSortId( eqc[i]); + if( score>=0 && e_sortId!=sortId ){ + score += 100; + } + } //score prefers earliest use of this term as a representative - if( score>=0 && ( r_best_score<0 || score<r_best_score ) ){ + if( r_best.isNull() || ( score>=0 && ( r_best_score<0 || score<r_best_score ) ) ){ r_best = eqc[i]; r_best_score = score; } } //now, make sure that no other member of the class is an instance - r_best = getInstance( r_best, eqc ); + if( !optInternalRepSortInference() ){ + r_best = getInstance( r_best, eqc ); + } //store that this representative was chosen at this point if( d_rep_score.find( r_best )==d_rep_score.end() ){ d_rep_score[ r_best ] = d_reset_count; } - d_int_rep[r] = r_best; + d_int_rep[sortId][r] = r_best; if( r_best!=a ){ Trace("internal-rep-debug") << "rep( " << a << " ) = " << r << ", " << std::endl; Trace("internal-rep-debug") << "int_rep( " << a << " ) = " << r_best << ", " << std::endl; } + if( optInternalRepSortInference() ){ + int sortIdBest = d_qe->getTheoryEngine()->getSortInference()->getSortId( r_best ); + if( sortId!=sortIdBest ){ + Trace("sort-inf-rep") << "Choosing representative with bad type " << r_best << " " << sortId << " " << sortIdBest << std::endl; + } + } return r_best; }else{ - return d_int_rep[r]; + return d_int_rep[sortId][r]; } } } @@ -723,7 +708,11 @@ int getDepth( Node n ){ } } -int EqualityQueryQuantifiersEngine::getRepScore( Node n ){ +int EqualityQueryQuantifiersEngine::getRepScore( Node n, Node f, int index ){ return d_rep_score.find( n )==d_rep_score.end() ? -1 : d_rep_score[n]; //initial //return ( d_rep_score.find( n )==d_rep_score.end() ? 100 : 0 ) + getDepth( n ); //term depth } + +bool EqualityQueryQuantifiersEngine::optInternalRepSortInference() { + return false; +}
\ No newline at end of file diff --git a/src/theory/quantifiers_engine.h b/src/theory/quantifiers_engine.h index 29381a309..9f520f420 100644 --- a/src/theory/quantifiers_engine.h +++ b/src/theory/quantifiers_engine.h @@ -119,6 +119,10 @@ private: rrinst::TriggerTrie* d_rr_tr_trie; /** extended model object */ quantifiers::FirstOrderModel* d_model; + /** statistics for debugging */ + std::map< Node, int > d_total_inst_debug; + std::map< Node, int > d_temp_inst_debug; + int d_total_inst_count_debug; private: KEEP_STATISTIC(TimerStat, d_time, "theory::QuantifiersEngine::time"); public: @@ -210,6 +214,7 @@ public: rrinst::TriggerTrie* getRRTriggerDatabase() { return d_rr_tr_trie; } /** add term to database */ void addTermToDatabase( Node n, bool withinQuant = false ); + /** get the master equality engine */ eq::EqualityEngine* getMasterEqualityEngine() ; public: /** statistics class */ @@ -262,7 +267,7 @@ private: /** pointer to theory engine */ QuantifiersEngine* d_qe; /** internal representatives */ - std::map< Node, Node > d_int_rep; + std::map< int, std::map< Node, Node > > d_int_rep; /** rep score */ std::map< Node, int > d_rep_score; /** reset count */ @@ -271,7 +276,9 @@ private: /** node contains */ Node getInstance( Node n, std::vector< Node >& eqc ); /** get score */ - int getRepScore( Node n ); + int getRepScore( Node n, Node f, int index ); + /** choose rep based on sort inference */ + bool optInternalRepSortInference(); public: EqualityQueryQuantifiersEngine( QuantifiersEngine* qe ) : d_qe( qe ), d_reset_count( 0 ){} ~EqualityQueryQuantifiersEngine(){} @@ -288,7 +295,7 @@ public: If cbqi is active, this will return a term in the equivalence class of "a" that does not contain instantiation constants, if such a term exists. */ - Node getInternalRepresentative( Node a ); + Node getInternalRepresentative( Node a, Node f, int index ); }; /* EqualityQueryQuantifiersEngine */ }/* CVC4::theory namespace */ diff --git a/src/theory/rep_set.cpp b/src/theory/rep_set.cpp index 3057e4a93..2df0c3f61 100644 --- a/src/theory/rep_set.cpp +++ b/src/theory/rep_set.cpp @@ -1,11 +1,11 @@ /********************* */ /*! \file rep_set.cpp ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): mdeters - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** diff --git a/src/theory/rep_set.h b/src/theory/rep_set.h index fec5d3ed8..019f69ec2 100644 --- a/src/theory/rep_set.h +++ b/src/theory/rep_set.h @@ -1,11 +1,11 @@ /********************* */ /*! \file rep_set.h ** \verbatim - ** Original author: ajreynol - ** Major contributors: none + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** @@ -14,8 +14,8 @@ #include "cvc4_private.h" -#ifndef __CVC4__REP_SET_H -#define __CVC4__REP_SET_H +#ifndef __CVC4__THEORY__REP_SET_H +#define __CVC4__THEORY__REP_SET_H #include "expr/node.h" #include <map> @@ -45,7 +45,7 @@ public: void complete( TypeNode t ); /** debug print */ void toStream(std::ostream& out); -}; +};/* class RepSet */ //representative domain typedef std::vector< int > RepDomain; @@ -104,9 +104,9 @@ public: /** debug print */ void debugPrint( const char* c ); void debugPrintSmall( const char* c ); -}; +};/* class RepSetIterator */ -} -} +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ -#endif
\ No newline at end of file +#endif /* __CVC4__THEORY__REP_SET_H */ diff --git a/src/theory/rewriterules/efficient_e_matching.cpp b/src/theory/rewriterules/efficient_e_matching.cpp index 24693d496..5ed34d46c 100755..100644 --- a/src/theory/rewriterules/efficient_e_matching.cpp +++ b/src/theory/rewriterules/efficient_e_matching.cpp @@ -1,11 +1,11 @@ /********************* */ /*! \file efficient_e_matching.cpp ** \verbatim - ** Original author: ajreynol - ** Major contributors: bobot - ** Minor contributors (to current version): mdeters - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** diff --git a/src/theory/rewriterules/efficient_e_matching.h b/src/theory/rewriterules/efficient_e_matching.h index fe65362ef..11c6b783e 100755..100644 --- a/src/theory/rewriterules/efficient_e_matching.h +++ b/src/theory/rewriterules/efficient_e_matching.h @@ -1,11 +1,11 @@ /********************* */ /*! \file efficient_e_matching.h ** \verbatim - ** Original author: ajreynol - ** Major contributors: bobot - ** Minor contributors (to current version): mdeters - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** diff --git a/src/theory/rewriterules/rr_candidate_generator.h b/src/theory/rewriterules/rr_candidate_generator.h index 97c710219..d12c67f6a 100644 --- a/src/theory/rewriterules/rr_candidate_generator.h +++ b/src/theory/rewriterules/rr_candidate_generator.h @@ -32,7 +32,7 @@ typedef CVC4::theory::rrinst::CandidateGenerator CandidateGenerator; //New CandidateGenerator. They have a simpler semantic than the old one -// Just iterate amoung the equivalence classes +// Just iterate among the equivalence classes // node::Null() must be given to reset class CandidateGeneratorTheoryEeClasses : public CandidateGenerator{ private: @@ -54,7 +54,7 @@ public: }; }; -// Just iterate amoung the equivalence class of the given node +// Just iterate among the equivalence class of the given node // node::Null() *can't* be given to reset class CandidateGeneratorTheoryEeClass : public CandidateGenerator{ private: diff --git a/src/theory/rewriterules/rr_inst_match.h b/src/theory/rewriterules/rr_inst_match.h index 63728a95b..636a4dbc1 100644 --- a/src/theory/rewriterules/rr_inst_match.h +++ b/src/theory/rewriterules/rr_inst_match.h @@ -180,7 +180,7 @@ public: /** If reset, or getNextMatch return false they remove from the InstMatch the binding that they have previously created */ - /** virtual Matcher in order to have definned behavior */ + /** virtual Matcher in order to have defined behavior */ virtual ~Matcher(){}; }; @@ -195,7 +195,7 @@ private: std::vector< triple< Matcher*, size_t, EqualityQuery* > > d_childrens; /** the variable that have been set by this matcher (during its own reset) */ std::vector< TNode > d_binded; /* TNode because the variable are already in d_pattern */ - /** the representant of the argument of the term given by the last reset */ + /** the representative of the argument of the term given by the last reset */ std::vector< Node > d_reps; public: /** The pattern we are producing matches for */ @@ -250,7 +250,7 @@ public: PatsMatcher* mkPatterns( std::vector< Node > pat, QuantifiersEngine* qe ); PatsMatcher* mkPatternsEfficient( std::vector< Node > pat, QuantifiersEngine* qe ); -/** return true if whatever Node is subsituted for the variables the +/** return true if whatever Node is substituted for the variables the given Node can't match the pattern */ bool nonunifiable( TNode t, TNode pat, const std::vector<Node> & vars); diff --git a/src/theory/rewriterules/theory_rewriterules.cpp b/src/theory/rewriterules/theory_rewriterules.cpp index c6fd9611c..a82b94f73 100644 --- a/src/theory/rewriterules/theory_rewriterules.cpp +++ b/src/theory/rewriterules/theory_rewriterules.cpp @@ -276,7 +276,7 @@ void TheoryRewriteRules::check(Effort level) { if(glast.inst == RULEINST_TRUE||glast.inst == RULEINST_FALSE) continue; // If it has a value it should already has been notified - bool value; value = value; // avoiding the warning in non debug mode + bool value CVC4_UNUSED; Assert(!getValuation().hasSatValue(g,value)); Debug("rewriterules::check") << "RewriteRules::Check Narrowing on:" << g << std::endl; /** Can split on already rewritten instrule... but... */ diff --git a/src/theory/shared_terms_database.h b/src/theory/shared_terms_database.h index 655918986..c7036a9ad 100644 --- a/src/theory/shared_terms_database.h +++ b/src/theory/shared_terms_database.h @@ -66,7 +66,7 @@ private: AlreadyNotifiedMap d_alreadyNotifiedMap; /** The registered equalities for propagation */ - typedef context::CDHashSet<TNode, TNodeHashFunction> RegisteredEqualitiesSet; + typedef context::CDHashSet<Node, NodeHashFunction> RegisteredEqualitiesSet; RegisteredEqualitiesSet d_registeredEqualities; private: diff --git a/src/theory/theory.h b/src/theory/theory.h index f317d4b92..5b2032430 100644 --- a/src/theory/theory.h +++ b/src/theory/theory.h @@ -33,6 +33,7 @@ #include "options/options.h" #include "util/statistics_registry.h" #include "util/dump.h" +#include "lib/ffs.h" #include <string> #include <iostream> @@ -49,13 +50,13 @@ namespace theory { class QuantifiersEngine; class TheoryModel; -namespace rrinst{ -class CandidateGenerator; -} +namespace rrinst { + class CandidateGenerator; +}/* CVC4::theory::rrinst namespace */ namespace eq { -class EqualityEngine; -} + class EqualityEngine; +}/* CVC4::theory::eq namespace */ /** * Information about an assertion for the theories. @@ -786,14 +787,10 @@ public: std::hash_set<TNode, TNodeHashFunction> currentlySharedTerms() const; };/* class Theory */ -std::ostream& operator<<(std::ostream& os, Theory::Effort level); - -namespace eq{ - class EqualityEngine; -} - +std::ostream& operator<<(std::ostream& os, theory::Theory::Effort level); +inline std::ostream& operator<<(std::ostream& out, const theory::Assertion& a); -inline Assertion Theory::get() { +inline theory::Assertion Theory::get() { Assert( !done(), "Theory::get() called with assertion queue empty!" ); // Get the assertion @@ -809,7 +806,9 @@ inline Assertion Theory::get() { return fact; } -}/* CVC4::theory namespace */ +inline std::ostream& operator<<(std::ostream& out, const theory::Assertion& a) { + return out << a.assertion; +} inline std::ostream& operator<<(std::ostream& out, const CVC4::theory::Theory& theory) { @@ -830,6 +829,7 @@ inline std::ostream& operator << (std::ostream& out, theory::Theory::PPAssertSta return out; } +}/* CVC4::theory namespace */ }/* CVC4 namespace */ #endif /* __CVC4__THEORY__THEORY_H */ diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp index 35ed63bed..f7f689850 100644 --- a/src/theory/theory_engine.cpp +++ b/src/theory/theory_engine.cpp @@ -286,7 +286,9 @@ void TheoryEngine::check(Theory::Effort effort) { #endif #define CVC4_FOR_EACH_THEORY_STATEMENT(THEORY) \ if (theory::TheoryTraits<THEORY>::hasCheck && d_logicInfo.isTheoryEnabled(THEORY)) { \ +Debug("theory") << "check<" << THEORY << ">" << std::endl; \ theoryOf(THEORY)->check(effort); \ +Debug("theory") << "done<" << THEORY << ">" << std::endl; \ if (d_inConflict) { \ break; \ } \ @@ -726,16 +728,6 @@ theory::Theory::PPAssertStatus TheoryEngine::solve(TNode literal, SubstitutionMa Theory::PPAssertStatus solveStatus = theoryOf(atom)->ppAssert(literal, substitutionOut); Trace("theory::solve") << "TheoryEngine::solve(" << literal << ") => " << solveStatus << endl; - //must add substitutions to model - theory::TheoryModel* m = getModel(); - if( m ){ - for( SubstitutionMap::iterator pos = substitutionOut.begin(); pos != substitutionOut.end(); ++pos) { - Node n = (*pos).first; - Node v = (*pos).second; - Trace("model") << "Add substitution : " << n << " " << v << std::endl; - m->addSubstitution( n, v ); - } - } return solveStatus; } @@ -817,7 +809,7 @@ Node TheoryEngine::preprocess(TNode assertion) { stringstream ss; ss << "The logic was specified as " << d_logicInfo.getLogicString() << ", which doesn't include " << Theory::theoryOf(current) - << ", but got a preprocesing-time fact for that theory." << endl + << ", but got a preprocessing-time fact for that theory." << endl << "The fact:" << endl << current; throw LogicException(ss.str()); diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h index 063943056..a3779f0e8 100644 --- a/src/theory/theory_engine.h +++ b/src/theory/theory_engine.h @@ -41,6 +41,7 @@ #include "util/hash.h" #include "util/cache.h" #include "util/cvc4_assert.h" +#include "util/sort_inference.h" #include "theory/ite_simplifier.h" #include "theory/unconstrained_simplifier.h" #include "theory/uf/equality_engine.h" @@ -190,7 +191,7 @@ class TheoryEngine { * context-dependent set of those theory-propagable literals that * have been propagated. */ - context::CDHashSet<TNode, TNodeHashFunction> d_hasPropagated; + context::CDHashSet<Node, NodeHashFunction> d_hasPropagated; /** * Statistics for a particular theory. @@ -268,7 +269,7 @@ class TheoryEngine { void safePoint() throw(theory::Interrupted, AssertionException) { if (d_engine->d_interrupted) throw theory::Interrupted(); - } + } void conflict(TNode conflictNode) throw(AssertionException) { Trace("theory::conflict") << "EngineOutputChannel<" << d_theory << ">::conflict(" << conflictNode << ")" << std::endl; @@ -422,6 +423,9 @@ class TheoryEngine { RemoveITE& d_iteRemover; + /** sort inference module */ + SortInference d_sortInfer; + /** Time spent in theory combination */ TimerStat d_combineTheoriesTime; @@ -732,24 +736,28 @@ public: SharedTermsDatabase* getSharedTermsDatabase() { return &d_sharedTerms; } + SortInference* getSortInference() { return &d_sortInfer; } private: std::map< std::string, std::vector< theory::Theory* > > d_attr_handle; public: - /** Set user attribute - * This function is called when an attribute is set by a user. In SMT-LIBv2 this is done - * via the syntax (! n :attr) - */ + /** + * Set user attribute. + * This function is called when an attribute is set by a user. In SMT-LIBv2 this is done + * via the syntax (! n :attr) + */ void setUserAttribute(const std::string& attr, Node n); - /** Handle user attribute - * Associates theory t with the attribute attr. Theory t will be - * notifed whenever an attribute of name attr is set. - */ + /** + * Handle user attribute. + * Associates theory t with the attribute attr. Theory t will be + * notified whenever an attribute of name attr is set. + */ void handleUserAttribute(const char* attr, theory::Theory* t); - /** Check that the theory assertions are satisfied in the model - * This function is called from the smt engine's checkModel routine + /** + * Check that the theory assertions are satisfied in the model. + * This function is called from the smt engine's checkModel routine. */ void checkTheoryAssertionsWithModel(); diff --git a/src/theory/uf/options b/src/theory/uf/options index 2569ccbff..33d1255ef 100644 --- a/src/theory/uf/options +++ b/src/theory/uf/options @@ -25,6 +25,10 @@ option ufssAbortCardinality --uf-ss-abort-card=N int :default -1 option ufssSmartSplits --uf-ss-smart-split bool :default false use smart splitting heuristic for uf strong solver option ufssExplainedCliques --uf-ss-explained-cliques bool :default false - add explained clique lemmas for uf strong solver + use explained clique lemmas for uf strong solver +option ufssSimpleCliques --uf-ss-simple-cliques bool :default true + always use simple clique lemmas for uf strong solver +option ufssDiseqPropagation --uf-ss-deq-prop bool :default false + eagerly propagate disequalities for uf strong solver endmodule diff --git a/src/theory/uf/theory_uf.cpp b/src/theory/uf/theory_uf.cpp index 3f033f3b8..bdbb79195 100644 --- a/src/theory/uf/theory_uf.cpp +++ b/src/theory/uf/theory_uf.cpp @@ -33,7 +33,7 @@ TheoryUF::TheoryUF(context::Context* c, context::UserContext* u, OutputChannel& d_notify(*this), /* The strong theory solver can be notified by EqualityEngine::init(), * so make sure it's initialized first. */ - d_thss(options::finiteModelFind() ? new StrongSolverTheoryUf(c, u, out, this) : NULL), + d_thss(options::finiteModelFind() ? new StrongSolverTheoryUF(c, u, out, this) : NULL), d_equalityEngine(d_notify, c, "theory::uf::TheoryUF"), d_conflict(c, false), d_literalsToPropagate(c), @@ -101,12 +101,10 @@ void TheoryUF::check(Effort level) { } - if (d_thss != NULL) { - if (! d_conflict) { - d_thss->check(level); - if( d_thss->isConflict() ){ - d_conflict = true; - } + if (d_thss != NULL && ! d_conflict) { + d_thss->check(level); + if( d_thss->isConflict() ){ + d_conflict = true; } } diff --git a/src/theory/uf/theory_uf.h b/src/theory/uf/theory_uf.h index fe1fc5137..00e270bd0 100644 --- a/src/theory/uf/theory_uf.h +++ b/src/theory/uf/theory_uf.h @@ -35,11 +35,11 @@ namespace theory { namespace uf { class UfTermDb; -class StrongSolverTheoryUf; +class StrongSolverTheoryUF; class TheoryUF : public Theory { - friend class StrongSolverTheoryUf; + friend class StrongSolverTheoryUF; public: @@ -116,7 +116,7 @@ private: NotifyClass d_notify; /** The associated theory strong solver (or NULL if none) */ - StrongSolverTheoryUf* d_thss; + StrongSolverTheoryUF* d_thss; /** Equaltity engine */ eq::EqualityEngine d_equalityEngine; @@ -212,7 +212,7 @@ public: return &d_equalityEngine; } - StrongSolverTheoryUf* getStrongSolver() { + StrongSolverTheoryUF* getStrongSolver() { return d_thss; } diff --git a/src/theory/uf/theory_uf_strong_solver.cpp b/src/theory/uf/theory_uf_strong_solver.cpp index 46ac5aa60..3e31faedb 100644 --- a/src/theory/uf/theory_uf_strong_solver.cpp +++ b/src/theory/uf/theory_uf_strong_solver.cpp @@ -32,11 +32,11 @@ using namespace CVC4::context; using namespace CVC4::theory; using namespace CVC4::theory::uf; -void StrongSolverTheoryUf::SortRepModel::Region::addRep( Node n ) { +void StrongSolverTheoryUF::SortModel::Region::addRep( Node n ) { setRep( n, true ); } -void StrongSolverTheoryUf::SortRepModel::Region::takeNode( StrongSolverTheoryUf::SortRepModel::Region* r, Node n ){ +void StrongSolverTheoryUF::SortModel::Region::takeNode( StrongSolverTheoryUF::SortModel::Region* r, Node n ){ Assert( !hasRep( n ) ); Assert( r->hasRep( n ) ); //add representative @@ -68,7 +68,7 @@ void StrongSolverTheoryUf::SortRepModel::Region::takeNode( StrongSolverTheoryUf: r->setRep( n, false ); } -void StrongSolverTheoryUf::SortRepModel::Region::combine( StrongSolverTheoryUf::SortRepModel::Region* r ){ +void StrongSolverTheoryUF::SortModel::Region::combine( StrongSolverTheoryUF::SortModel::Region* r ){ //take all nodes from r for( std::map< Node, RegionNodeInfo* >::iterator it = r->d_nodes.begin(); it != r->d_nodes.end(); ++it ){ if( it->second->d_valid ){ @@ -100,7 +100,7 @@ void StrongSolverTheoryUf::SortRepModel::Region::combine( StrongSolverTheoryUf:: } /** setEqual */ -void StrongSolverTheoryUf::SortRepModel::Region::setEqual( Node a, Node b ){ +void StrongSolverTheoryUF::SortModel::Region::setEqual( Node a, Node b ){ Assert( hasRep( a ) && hasRep( b ) ); //move disequalities of b over to a for( int t=0; t<2; t++ ){ @@ -108,10 +108,15 @@ void StrongSolverTheoryUf::SortRepModel::Region::setEqual( Node a, Node b ){ for( NodeBoolMap::iterator it = del->d_disequalities.begin(); it != del->d_disequalities.end(); ++it ){ if( (*it).second ){ Node n = (*it).first; + //get the region that contains the endpoint of the disequality b != ... Region* nr = d_cf->d_regions[ d_cf->d_regions_map[ n ] ]; if( !isDisequal( a, n, t ) ){ setDisequal( a, n, t, true ); nr->setDisequal( n, a, t, true ); + //notify the disequality propagator + if( options::ufssDiseqPropagation() ){ + d_cf->d_thss->getDisequalityPropagator()->assertDisequal(a, n, Node::null()); + } } setDisequal( b, n, t, false ); nr->setDisequal( n, b, t, false ); @@ -122,7 +127,7 @@ void StrongSolverTheoryUf::SortRepModel::Region::setEqual( Node a, Node b ){ setRep( b, false ); } -void StrongSolverTheoryUf::SortRepModel::Region::setDisequal( Node n1, Node n2, int type, bool valid ){ +void StrongSolverTheoryUF::SortModel::Region::setDisequal( Node n1, Node n2, int type, bool valid ){ //Debug("uf-ss-region-debug") << "set disequal " << n1 << " " << n2 << " " << type << " " << valid << std::endl; //debugPrint("uf-ss-region-debug"); //Assert( isDisequal( n1, n2, type )!=valid ); @@ -148,10 +153,10 @@ void StrongSolverTheoryUf::SortRepModel::Region::setDisequal( Node n1, Node n2, } } -void StrongSolverTheoryUf::SortRepModel::Region::setRep( Node n, bool valid ){ +void StrongSolverTheoryUF::SortModel::Region::setRep( Node n, bool valid ){ Assert( hasRep( n )!=valid ); if( valid && d_nodes.find( n )==d_nodes.end() ){ - d_nodes[n] = new RegionNodeInfo( d_cf->d_th->getSatContext() ); + d_nodes[n] = new RegionNodeInfo( d_cf->d_thss->getSatContext() ); } d_nodes[n]->d_valid = valid; d_reps_size = d_reps_size + ( valid ? 1 : -1 ); @@ -172,24 +177,24 @@ void StrongSolverTheoryUf::SortRepModel::Region::setRep( Node n, bool valid ){ } } -bool StrongSolverTheoryUf::SortRepModel::Region::isDisequal( Node n1, Node n2, int type ){ +bool StrongSolverTheoryUF::SortModel::Region::isDisequal( Node n1, Node n2, int type ){ RegionNodeInfo::DiseqList* del = d_nodes[ n1 ]->d_disequalities[type]; return del->d_disequalities.find( n2 )!=del->d_disequalities.end() && del->d_disequalities[n2]; } struct sortInternalDegree { - StrongSolverTheoryUf::SortRepModel::Region* r; + StrongSolverTheoryUF::SortModel::Region* r; bool operator() (Node i,Node j) { return (r->d_nodes[i]->getNumInternalDisequalities()>r->d_nodes[j]->getNumInternalDisequalities());} }; struct sortExternalDegree { - StrongSolverTheoryUf::SortRepModel::Region* r; + StrongSolverTheoryUF::SortModel::Region* r; bool operator() (Node i,Node j) { return (r->d_nodes[i]->getNumExternalDisequalities()>r->d_nodes[j]->getNumExternalDisequalities());} }; int gmcCount = 0; -bool StrongSolverTheoryUf::SortRepModel::Region::getMustCombine( int cardinality ){ +bool StrongSolverTheoryUF::SortModel::Region::getMustCombine( int cardinality ){ if( options::ufssRegions() && d_total_diseq_external>=long(cardinality) ){ //The number of external disequalities is greater than or equal to cardinality. //Thus, a clique of size cardinality+1 may exist between nodes in d_regions[i] and other regions @@ -228,7 +233,7 @@ bool StrongSolverTheoryUf::SortRepModel::Region::getMustCombine( int cardinality return false; } -bool StrongSolverTheoryUf::SortRepModel::Region::check( Theory::Effort level, int cardinality, std::vector< Node >& clique ){ +bool StrongSolverTheoryUF::SortModel::Region::check( Theory::Effort level, int cardinality, std::vector< Node >& clique ){ if( d_reps_size>long(cardinality) ){ if( d_total_diseq_internal==d_reps_size*( d_reps_size - 1 ) ){ if( d_reps_size>1 ){ @@ -317,7 +322,7 @@ bool StrongSolverTheoryUf::SortRepModel::Region::check( Theory::Effort level, in return false; } -void StrongSolverTheoryUf::SortRepModel::Region::getRepresentatives( std::vector< Node >& reps ){ +void StrongSolverTheoryUF::SortModel::Region::getRepresentatives( std::vector< Node >& reps ){ for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){ RegionNodeInfo* rni = it->second; if( rni->d_valid ){ @@ -326,7 +331,7 @@ void StrongSolverTheoryUf::SortRepModel::Region::getRepresentatives( std::vector } } -void StrongSolverTheoryUf::SortRepModel::Region::getNumExternalDisequalities( std::map< Node, int >& num_ext_disequalities ){ +void StrongSolverTheoryUF::SortModel::Region::getNumExternalDisequalities( std::map< Node, int >& num_ext_disequalities ){ for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){ RegionNodeInfo* rni = it->second; if( rni->d_valid ){ @@ -340,7 +345,7 @@ void StrongSolverTheoryUf::SortRepModel::Region::getNumExternalDisequalities( st } } -void StrongSolverTheoryUf::SortRepModel::Region::debugPrint( const char* c, bool incClique ){ +void StrongSolverTheoryUF::SortModel::Region::debugPrint( const char* c, bool incClique ){ Debug( c ) << "Num reps: " << d_reps_size << std::endl; for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){ RegionNodeInfo* rni = it->second; @@ -389,27 +394,27 @@ void StrongSolverTheoryUf::SortRepModel::Region::debugPrint( const char* c, bool -StrongSolverTheoryUf::SortRepModel::SortRepModel( Node n, context::Context* c, TheoryUF* th ) : RepModel( n.getType() ), - d_th( th ), d_regions_index( c, 0 ), d_regions_map( c ), d_split_score( c ), d_disequalities_index( c, 0 ), +StrongSolverTheoryUF::SortModel::SortModel( Node n, context::Context* c, StrongSolverTheoryUF* thss ) : d_type( n.getType() ), + d_thss( thss ), d_regions_index( c, 0 ), d_regions_map( c ), d_split_score( c ), d_disequalities_index( c, 0 ), d_reps( c, 0 ), d_conflict( c, false ), d_cardinality( c, 1 ), d_aloc_cardinality( 0 ), d_cardinality_assertions( c ), d_hasCard( c, false ){ d_cardinality_term = n; } /** initialize */ -void StrongSolverTheoryUf::SortRepModel::initialize( OutputChannel* out ){ +void StrongSolverTheoryUF::SortModel::initialize( OutputChannel* out ){ allocateCardinality( out ); } /** new node */ -void StrongSolverTheoryUf::SortRepModel::newEqClass( Node n ){ +void StrongSolverTheoryUF::SortModel::newEqClass( Node n ){ if( !d_conflict ){ if( d_regions_map.find( n )==d_regions_map.end() ){ if( !options::ufssTotalityLazy() ){ //must generate totality axioms for every cardinality we have allocated thus far for( std::map< int, Node >::iterator it = d_cardinality_literal.begin(); it != d_cardinality_literal.end(); ++it ){ if( applyTotality( it->first ) ){ - addTotalityAxiom( n, it->first, &d_th->getOutputChannel() ); + addTotalityAxiom( n, it->first, &d_thss->getOutputChannel() ); } } } @@ -429,14 +434,14 @@ void StrongSolverTheoryUf::SortRepModel::newEqClass( Node n ){ if( options::ufssSmartSplits() ){ setSplitScore( n, 0 ); } - Debug("uf-ss") << "StrongSolverTheoryUf: New Eq Class " << n << std::endl; + Debug("uf-ss") << "StrongSolverTheoryUF: New Eq Class " << n << std::endl; Debug("uf-ss-debug") << d_regions_index << " " << (int)d_regions.size() << std::endl; if( d_regions_index<d_regions.size() ){ d_regions[ d_regions_index ]->debugPrint("uf-ss-debug",true); d_regions[ d_regions_index ]->d_valid = true; Assert( !options::ufssRegions() || d_regions[ d_regions_index ]->getNumReps()==0 ); }else{ - d_regions.push_back( new Region( this, d_th->getSatContext() ) ); + d_regions.push_back( new Region( this, d_thss->getSatContext() ) ); } d_regions[ d_regions_index ]->addRep( n ); d_regions_index = d_regions_index + 1; @@ -447,7 +452,7 @@ void StrongSolverTheoryUf::SortRepModel::newEqClass( Node n ){ } /** merge */ -void StrongSolverTheoryUf::SortRepModel::merge( Node a, Node b ){ +void StrongSolverTheoryUF::SortModel::merge( Node a, Node b ){ if( !d_conflict ){ if( options::ufssTotality() ){ if( d_regions_map[b]==-1 ){ @@ -457,7 +462,7 @@ void StrongSolverTheoryUf::SortRepModel::merge( Node a, Node b ){ }else{ //Assert( a==d_th->d_equalityEngine.getRepresentative( a ) ); //Assert( b==d_th->d_equalityEngine.getRepresentative( b ) ); - Debug("uf-ss") << "StrongSolverTheoryUf: Merging " << a << " = " << b << "..." << std::endl; + Debug("uf-ss") << "StrongSolverTheoryUF: Merging " << a << " = " << b << "..." << std::endl; if( a!=b ){ Assert( d_regions_map.find( a )!=d_regions_map.end() ); Assert( d_regions_map.find( b )!=d_regions_map.end() ); @@ -495,21 +500,25 @@ void StrongSolverTheoryUf::SortRepModel::merge( Node a, Node b ){ d_regions_map[b] = -1; } d_reps = d_reps - 1; - Debug("uf-ss") << "Done merge." << std::endl; + + if( options::ufssDiseqPropagation() && !d_conflict ){ + //notify the disequality propagator + d_thss->getDisequalityPropagator()->merge(a, b); + } } } } /** assert terms are disequal */ -void StrongSolverTheoryUf::SortRepModel::assertDisequal( Node a, Node b, Node reason ){ +void StrongSolverTheoryUF::SortModel::assertDisequal( Node a, Node b, Node reason ){ if( !d_conflict ){ if( options::ufssTotality() ){ //do nothing }else{ //if they are not already disequal - a = d_th->d_equalityEngine.getRepresentative( a ); - b = d_th->d_equalityEngine.getRepresentative( b ); - if( !d_th->d_equalityEngine.areDisequal( a, b, true ) ){ + a = d_thss->getTheory()->d_equalityEngine.getRepresentative( a ); + b = d_thss->getTheory()->d_equalityEngine.getRepresentative( b ); + if( !d_thss->getTheory()->d_equalityEngine.areDisequal( a, b, true ) ){ Debug("uf-ss") << "Assert disequal " << a << " != " << b << "..." << std::endl; //if( reason.getKind()!=NOT || ( reason[0].getKind()!=EQUAL && reason[0].getKind()!=IFF ) || // a!=reason[0][0] || b!=reason[0][1] ){ @@ -533,6 +542,7 @@ void StrongSolverTheoryUf::SortRepModel::assertDisequal( Node a, Node b, Node re //internal disequality d_regions[ai]->setDisequal( a, b, 1, true ); d_regions[ai]->setDisequal( b, a, 1, true ); + checkRegion( ai, false ); //do not need to check if it needs to combine (no new ext. disequalities) }else{ //external disequality d_regions[ai]->setDisequal( a, b, 0, true ); @@ -540,18 +550,34 @@ void StrongSolverTheoryUf::SortRepModel::assertDisequal( Node a, Node b, Node re checkRegion( ai ); checkRegion( bi ); } - //Notice() << "done" << std::endl; + + if( options::ufssDiseqPropagation() && !d_conflict ){ + //notify the disequality propagator + d_thss->getDisequalityPropagator()->assertDisequal(a, b, Node::null()); + } } } } } +bool StrongSolverTheoryUF::SortModel::areDisequal( Node a, Node b ) { + Assert( a == d_thss->getTheory()->d_equalityEngine.getRepresentative( a ) ); + Assert( b == d_thss->getTheory()->d_equalityEngine.getRepresentative( b ) ); + if( d_regions_map.find( a )!=d_regions_map.end() && + d_regions_map.find( b )!=d_regions_map.end() ){ + int ai = d_regions_map[a]; + int bi = d_regions_map[b]; + return d_regions[ai]->isDisequal(a, b, ai==bi ? 1 : 0); + }else{ + return false; + } +} /** check */ -void StrongSolverTheoryUf::SortRepModel::check( Theory::Effort level, OutputChannel* out ){ +void StrongSolverTheoryUF::SortModel::check( Theory::Effort level, OutputChannel* out ){ if( level>=Theory::EFFORT_STANDARD && d_hasCard && !d_conflict ){ - Debug("uf-ss") << "StrongSolverTheoryUf: Check " << level << " " << d_type << std::endl; - //Notice() << "StrongSolverTheoryUf: Check " << level << std::endl; + Debug("uf-ss") << "StrongSolverTheoryUF: Check " << level << " " << d_type << std::endl; + //Notice() << "StrongSolverTheoryUF: Check " << level << std::endl; if( d_reps<=(unsigned)d_cardinality ){ Debug("uf-ss-debug") << "We have " << d_reps << " representatives for type " << d_type << ", <= " << d_cardinality << std::endl; if( level==Theory::EFFORT_FULL ){ @@ -584,7 +610,7 @@ void StrongSolverTheoryUf::SortRepModel::check( Theory::Effort level, OutputChan if( level==Theory::EFFORT_FULL ){ for( NodeIntMap::iterator it = d_regions_map.begin(); it != d_regions_map.end(); ++it ){ if( !options::ufssTotality() || d_regions_map[ (*it).first ]!=-1 ){ - addTotalityAxiom( (*it).first, d_cardinality, &d_th->getOutputChannel() ); + addTotalityAxiom( (*it).first, d_cardinality, &d_thss->getOutputChannel() ); } } } @@ -610,14 +636,33 @@ void StrongSolverTheoryUf::SortRepModel::check( Theory::Effort level, OutputChan if( level==Theory::EFFORT_FULL ){ if( !addedLemma ){ Trace("uf-ss-debug") << "No splits added. " << d_cardinality << std::endl; - if( !options::ufssColoringSat() ){ + Trace("uf-ss-si") << "Must combine region" << std::endl; + if( true || !options::ufssColoringSat() ){ bool recheck = false; //naive strategy, force region combination involving the first valid region - for( int i=0; i<(int)d_regions_index; i++ ){ - if( d_regions[i]->d_valid ){ - forceCombineRegion( i, false ); - recheck = true; - break; + if( options::sortInference()){ + std::map< int, int > sortsFound; + for( int i=0; i<(int)d_regions_index; i++ ){ + if( d_regions[i]->d_valid ){ + Node op = d_regions[i]->d_nodes.begin()->first; + int sort_id = d_thss->getTheory()->getQuantifiersEngine()->getTheoryEngine()->getSortInference()->getSortId(op) ; + if( sortsFound.find( sort_id )!=sortsFound.end() ){ + combineRegions( sortsFound[sort_id], i ); + recheck = true; + break; + }else{ + sortsFound[sort_id] = i; + } + } + } + } + if( !recheck ) { + for( int i=0; i<(int)d_regions_index; i++ ){ + if( d_regions[i]->d_valid ){ + forceCombineRegion( i, false ); + recheck = true; + break; + } } } if( recheck ){ @@ -631,11 +676,11 @@ void StrongSolverTheoryUf::SortRepModel::check( Theory::Effort level, OutputChan } } -void StrongSolverTheoryUf::SortRepModel::propagate( Theory::Effort level, OutputChannel* out ){ +void StrongSolverTheoryUF::SortModel::propagate( Theory::Effort level, OutputChannel* out ){ } -Node StrongSolverTheoryUf::SortRepModel::getNextDecisionRequest(){ +Node StrongSolverTheoryUF::SortModel::getNextDecisionRequest(){ //request the current cardinality as a decision literal, if not already asserted for( int i=1; i<=d_aloc_cardinality; i++ ){ if( !d_hasCard || i<d_cardinality ){ @@ -650,7 +695,7 @@ Node StrongSolverTheoryUf::SortRepModel::getNextDecisionRequest(){ return Node::null(); } -bool StrongSolverTheoryUf::SortRepModel::minimize( OutputChannel* out, TheoryModel* m ){ +bool StrongSolverTheoryUF::SortModel::minimize( OutputChannel* out, TheoryModel* m ){ if( options::ufssTotality() ){ //do nothing }else{ @@ -672,7 +717,7 @@ bool StrongSolverTheoryUf::SortRepModel::minimize( OutputChannel* out, TheoryMod out->split( splitEq ); //tell the sat solver to explore the equals branch first out->requirePhase( splitEq, true ); - ++( d_th->getStrongSolver()->d_statistics.d_split_lemmas ); + ++( d_thss->d_statistics.d_split_lemmas ); return false; } } @@ -706,7 +751,7 @@ bool StrongSolverTheoryUf::SortRepModel::minimize( OutputChannel* out, TheoryMod } -int StrongSolverTheoryUf::SortRepModel::getNumDisequalitiesToRegion( Node n, int ri ){ +int StrongSolverTheoryUF::SortModel::getNumDisequalitiesToRegion( Node n, int ri ){ int ni = d_regions_map[n]; int counter = 0; Region::RegionNodeInfo::DiseqList* del = d_regions[ni]->d_nodes[n]->d_disequalities[0]; @@ -720,7 +765,7 @@ int StrongSolverTheoryUf::SortRepModel::getNumDisequalitiesToRegion( Node n, int return counter; } -void StrongSolverTheoryUf::SortRepModel::getDisequalitiesToRegions( int ri, std::map< int, int >& regions_diseq ){ +void StrongSolverTheoryUF::SortModel::getDisequalitiesToRegions( int ri, std::map< int, int >& regions_diseq ){ for( std::map< Node, Region::RegionNodeInfo* >::iterator it = d_regions[ri]->d_nodes.begin(); it != d_regions[ri]->d_nodes.end(); ++it ){ if( it->second->d_valid ){ @@ -736,7 +781,7 @@ void StrongSolverTheoryUf::SortRepModel::getDisequalitiesToRegions( int ri, std: } } -void StrongSolverTheoryUf::SortRepModel::setSplitScore( Node n, int s ){ +void StrongSolverTheoryUF::SortModel::setSplitScore( Node n, int s ){ if( d_split_score.find( n )!=d_split_score.end() ){ int ss = d_split_score[ n ]; d_split_score[ n ] = s>ss ? s : ss; @@ -748,9 +793,10 @@ void StrongSolverTheoryUf::SortRepModel::setSplitScore( Node n, int s ){ } } -void StrongSolverTheoryUf::SortRepModel::assertCardinality( OutputChannel* out, int c, bool val ){ +void StrongSolverTheoryUF::SortModel::assertCardinality( OutputChannel* out, int c, bool val ){ if( !d_conflict ){ - Trace("uf-ss-assert") << "Assert cardinality " << d_type << " " << c << " " << val << " level = " << d_th->d_valuation.getAssertionLevel() << std::endl; + Trace("uf-ss-assert") << "Assert cardinality " << d_type << " " << c << " " << val << " level = "; + Trace("uf-ss-assert") << d_thss->getTheory()->d_valuation.getAssertionLevel() << std::endl; Assert( d_cardinality_literal.find( c )!=d_cardinality_literal.end() ); d_cardinality_assertions[ d_cardinality_literal[c] ] = val; if( val ){ @@ -803,15 +849,10 @@ void StrongSolverTheoryUf::SortRepModel::assertCardinality( OutputChannel* out, } } -void StrongSolverTheoryUf::SortRepModel::checkRegion( int ri, bool rec ){ +void StrongSolverTheoryUF::SortModel::checkRegion( int ri, bool checkCombine ){ if( isValid(ri) && d_hasCard ){ Assert( d_cardinality>0 ); - //first check if region is in conflict - std::vector< Node > clique; - if( d_regions[ri]->check( Theory::EFFORT_STANDARD, d_cardinality, clique ) ){ - //explain clique - addCliqueLemma( clique, &d_th->getOutputChannel() ); - }else if( d_regions[ri]->getMustCombine( d_cardinality ) ){ + if( checkCombine && d_regions[ri]->getMustCombine( d_cardinality ) ){ ////alternatively, check if we can reduce the number of external disequalities by moving single nodes //for( std::map< Node, bool >::iterator it = d_regions[i]->d_reps.begin(); it != d_regions[i]->d_reps.end(); ++it ){ // if( it->second ){ @@ -822,14 +863,20 @@ void StrongSolverTheoryUf::SortRepModel::checkRegion( int ri, bool rec ){ // } //} int riNew = forceCombineRegion( ri, true ); - if( riNew>=0 && rec ){ - checkRegion( riNew, rec ); + if( riNew>=0 ){ + checkRegion( riNew, checkCombine ); } } + //now check if region is in conflict + std::vector< Node > clique; + if( d_regions[ri]->check( Theory::EFFORT_STANDARD, d_cardinality, clique ) ){ + //explain clique + addCliqueLemma( clique, &d_thss->getOutputChannel() ); + } } } -int StrongSolverTheoryUf::SortRepModel::forceCombineRegion( int ri, bool useDensity ){ +int StrongSolverTheoryUF::SortModel::forceCombineRegion( int ri, bool useDensity ){ if( !useDensity ){ for( int i=0; i<(int)d_regions_index; i++ ){ if( ri!=i && d_regions[i]->d_valid ){ @@ -869,7 +916,7 @@ int StrongSolverTheoryUf::SortRepModel::forceCombineRegion( int ri, bool useDens } -int StrongSolverTheoryUf::SortRepModel::combineRegions( int ai, int bi ){ +int StrongSolverTheoryUF::SortModel::combineRegions( int ai, int bi ){ #ifdef COMBINE_REGIONS_SMALL_INTO_LARGE if( d_regions[ai]->getNumReps()<d_regions[bi]->getNumReps() ){ return combineRegions( bi, ai ); @@ -889,7 +936,7 @@ int StrongSolverTheoryUf::SortRepModel::combineRegions( int ai, int bi ){ return ai; } -void StrongSolverTheoryUf::SortRepModel::moveNode( Node n, int ri ){ +void StrongSolverTheoryUF::SortModel::moveNode( Node n, int ri ){ Debug("uf-ss-region") << "uf-ss: Move node " << n << " to Region #" << ri << std::endl; Assert( isValid( d_regions_map[ n ] ) ); Assert( isValid( ri ) ); @@ -898,7 +945,7 @@ void StrongSolverTheoryUf::SortRepModel::moveNode( Node n, int ri ){ d_regions_map[n] = ri; } -void StrongSolverTheoryUf::SortRepModel::allocateCardinality( OutputChannel* out ){ +void StrongSolverTheoryUF::SortModel::allocateCardinality( OutputChannel* out ){ if( d_aloc_cardinality>0 ){ Trace("uf-ss-fmf") << "No model of size " << d_aloc_cardinality << " exists for type " << d_type << " in this branch" << std::endl; if( Trace.isOn("uf-ss-cliques") ){ @@ -936,7 +983,7 @@ void StrongSolverTheoryUf::SortRepModel::allocateCardinality( OutputChannel* out //must be distinct from all other cardinality terms for( int i=0; i<(int)(d_totality_terms[0].size()-1); i++ ){ Node lem = NodeManager::currentNM()->mkNode( NOT, var.eqNode( d_totality_terms[0][i] ) ); - d_th->getOutputChannel().lemma( lem ); + d_thss->getOutputChannel().lemma( lem ); } } @@ -955,18 +1002,18 @@ void StrongSolverTheoryUf::SortRepModel::allocateCardinality( OutputChannel* out //add the appropriate lemma, propagate as decision //Trace("uf-ss-prop-as-dec") << "Propagate as decision " << lem[0] << " " << d_type << std::endl; //out->propagateAsDecision( lem[0] ); - d_th->getStrongSolver()->d_statistics.d_max_model_size.maxAssign( d_aloc_cardinality ); + d_thss->d_statistics.d_max_model_size.maxAssign( d_aloc_cardinality ); if( applyTotality( d_aloc_cardinality ) && !options::ufssTotalityLazy() ){ //must send totality axioms for each existing term for( NodeIntMap::iterator it = d_regions_map.begin(); it != d_regions_map.end(); ++it ){ - addTotalityAxiom( (*it).first, d_aloc_cardinality, &d_th->getOutputChannel() ); + addTotalityAxiom( (*it).first, d_aloc_cardinality, &d_thss->getOutputChannel() ); } } } } -bool StrongSolverTheoryUf::SortRepModel::addSplit( Region* r, OutputChannel* out ){ +bool StrongSolverTheoryUF::SortModel::addSplit( Region* r, OutputChannel* out ){ if( r->hasSplits() ){ Node s; if( !options::ufssSmartSplits() ){ @@ -996,6 +1043,13 @@ bool StrongSolverTheoryUf::SortRepModel::addSplit( Region* r, OutputChannel* out Assert( s!=Node::null() && s.getKind()==EQUAL ); s = Rewriter::rewrite( s ); Trace("uf-ss-lemma") << "*** Split on " << s << std::endl; + if( options::sortInference()) { + for( int i=0; i<2; i++ ){ + int si = d_thss->getTheory()->getQuantifiersEngine()->getTheoryEngine()->getSortInference()->getSortId( s[i] ); + Trace("uf-ss-split-si") << si << " "; + } + Trace("uf-ss-split-si") << std::endl; + } //Trace("uf-ss-lemma") << d_th->getEqualityEngine()->areEqual( s[0], s[1] ) << " "; //Trace("uf-ss-lemma") << d_th->getEqualityEngine()->areDisequal( s[0], s[1] ) << std::endl; //Trace("uf-ss-lemma") << s[0].getType() << " " << s[1].getType() << std::endl; @@ -1004,7 +1058,7 @@ bool StrongSolverTheoryUf::SortRepModel::addSplit( Region* r, OutputChannel* out out->split( s ); //tell the sat solver to explore the equals branch first out->requirePhase( s, true ); - ++( d_th->getStrongSolver()->d_statistics.d_split_lemmas ); + ++( d_thss->d_statistics.d_split_lemmas ); return true; }else{ return false; @@ -1012,126 +1066,158 @@ bool StrongSolverTheoryUf::SortRepModel::addSplit( Region* r, OutputChannel* out } -void StrongSolverTheoryUf::SortRepModel::addCliqueLemma( std::vector< Node >& clique, OutputChannel* out ){ +void StrongSolverTheoryUF::SortModel::addCliqueLemma( std::vector< Node >& clique, OutputChannel* out ){ Assert( d_hasCard ); Assert( d_cardinality>0 ); while( clique.size()>size_t(d_cardinality+1) ){ clique.pop_back(); } - if( !options::ufssExplainedCliques() ){ + if( options::ufssSimpleCliques() && !options::ufssExplainedCliques() ){ //add as lemma std::vector< Node > eqs; for( int i=0; i<(int)clique.size(); i++ ){ for( int j=0; j<i; j++ ){ + Node r1 = d_thss->getTheory()->d_equalityEngine.getRepresentative(clique[i]); + Node r2 = d_thss->getTheory()->d_equalityEngine.getRepresentative(clique[j]); eqs.push_back( clique[i].eqNode( clique[j] ) ); } } eqs.push_back( d_cardinality_literal[ d_cardinality ].notNode() ); Node lem = NodeManager::currentNM()->mkNode( OR, eqs ); + Trace("uf-ss-lemma") << "*** Add clique conflict " << lem << std::endl; + ++( d_thss->d_statistics.d_clique_lemmas ); out->lemma( lem ); - return; - } - //if( options::ufssModelInference() || - if( Trace.isOn("uf-ss-cliques") ){ - std::vector< Node > clique_vec; - clique_vec.insert( clique_vec.begin(), clique.begin(), clique.end() ); - d_cliques[ d_cardinality ].push_back( clique_vec ); - } - - //found a clique - Debug("uf-ss-cliques") << "Found a clique (cardinality=" << d_cardinality << ") :" << std::endl; - Debug("uf-ss-cliques") << " "; - for( int i=0; i<(int)clique.size(); i++ ){ - Debug("uf-ss-cliques") << clique[i] << " "; - } - Debug("uf-ss-cliques") << std::endl; - Debug("uf-ss-cliques") << "Finding clique disequalities..." << std::endl; - std::vector< Node > conflict; - //collect disequalities, and nodes that must be equal within representatives - std::map< Node, std::map< Node, bool > > explained; - std::map< Node, std::map< Node, bool > > nodesWithinRep; - for( int i=0; i<(int)d_disequalities_index; i++ ){ - //if both sides of disequality exist in clique - Node r1 = d_th->d_equalityEngine.getRepresentative( d_disequalities[i][0][0] ); - Node r2 = d_th->d_equalityEngine.getRepresentative( d_disequalities[i][0][1] ); - if( r1!=r2 && ( explained.find( r1 )==explained.end() || explained[r1].find( r2 )==explained[r1].end() ) && - std::find( clique.begin(), clique.end(), r1 )!=clique.end() && - std::find( clique.begin(), clique.end(), r2 )!=clique.end() ){ - explained[r1][r2] = true; - explained[r2][r1] = true; - conflict.push_back( d_disequalities[i] ); - Debug("uf-ss-cliques") << " -> disequality : " << d_disequalities[i] << std::endl; - nodesWithinRep[r1][ d_disequalities[i][0][0] ] = true; - nodesWithinRep[r2][ d_disequalities[i][0][1] ] = true; - if( conflict.size()==(clique.size()*( clique.size()-1 )/2) ){ - break; + }else{ + //debugging information + if( Trace.isOn("uf-ss-cliques") ){ + std::vector< Node > clique_vec; + clique_vec.insert( clique_vec.begin(), clique.begin(), clique.end() ); + d_cliques[ d_cardinality ].push_back( clique_vec ); + } + //found a clique + Debug("uf-ss-cliques") << "Found a clique (cardinality=" << d_cardinality << ") :" << std::endl; + Debug("uf-ss-cliques") << " "; + for( int i=0; i<(int)clique.size(); i++ ){ + Debug("uf-ss-cliques") << clique[i] << " "; + } + Debug("uf-ss-cliques") << std::endl; + Debug("uf-ss-cliques") << "Finding clique disequalities..." << std::endl; + + //we will scan through each of the disequaltities + bool isSatConflict = true; + std::vector< Node > conflict; + //collect disequalities, and nodes that must be equal within representatives + std::map< Node, std::map< Node, bool > > explained; + std::map< Node, std::map< Node, bool > > nodesWithinRep; + //map from the reprorted clique members to those reported in the lemma + std::map< Node, Node > cliqueRepMap; + for( int i=0; i<(int)d_disequalities_index; i++ ){ + //if both sides of disequality exist in clique + Node r1 = d_thss->getTheory()->d_equalityEngine.getRepresentative( d_disequalities[i][0][0] ); + Node r2 = d_thss->getTheory()->d_equalityEngine.getRepresentative( d_disequalities[i][0][1] ); + if( r1!=r2 && ( explained.find( r1 )==explained.end() || explained[r1].find( r2 )==explained[r1].end() ) && + std::find( clique.begin(), clique.end(), r1 )!=clique.end() && + std::find( clique.begin(), clique.end(), r2 )!=clique.end() ){ + explained[r1][r2] = true; + explained[r2][r1] = true; + if( options::ufssExplainedCliques() ){ + conflict.push_back( d_disequalities[i] ); + Debug("uf-ss-cliques") << " -> disequality : " << d_disequalities[i] << std::endl; + nodesWithinRep[r1][ d_disequalities[i][0][0] ] = true; + nodesWithinRep[r2][ d_disequalities[i][0][1] ] = true; + }else{ + //get the terms we report in the lemma + Node ru1 = r1; + if( cliqueRepMap.find( r1 )==cliqueRepMap.end() ){ + ru1 = d_disequalities[i][0][0]; + cliqueRepMap[r1] = ru1; + }else{ + ru1 = cliqueRepMap[r1]; + } + Node ru2 = r2; + if( cliqueRepMap.find( r2 )==cliqueRepMap.end() ){ + ru2 = d_disequalities[i][0][1]; + cliqueRepMap[r2] = ru2; + }else{ + ru2 = cliqueRepMap[r2]; + } + if( ru1!=d_disequalities[i][0][0] || ru2!=d_disequalities[i][0][1] ){ + //disequalities have endpoints that are not connected within an equivalence class + // we will be producing a lemma, introducing a new literal ru1 != ru2 + conflict.push_back( ru1.eqNode( ru2 ).notNode() ); + isSatConflict = false; + }else{ + conflict.push_back( d_disequalities[i] ); + } + } + if( conflict.size()==(clique.size()*( clique.size()-1 )/2) ){ + break; + } } } - } - //Debug("uf-ss-cliques") << conflict.size() << " " << clique.size() << std::endl; - Assert( (int)conflict.size()==((int)clique.size()*( (int)clique.size()-1 )/2) ); - //Assert( (int)conflict.size()==(int)clique.size()*( (int)clique.size()-1 )/2 ); - Debug("uf-ss-cliques") << "Finding clique equalities internal to eq classes..." << std::endl; - //now, we must explain equalities within each equivalence class - for( std::map< Node, std::map< Node, bool > >::iterator it = nodesWithinRep.begin(); it != nodesWithinRep.end(); ++it ){ - if( it->second.size()>1 ){ - Node prev; - //add explanation of t1 = t2 = ... = tn - Debug("uf-ss-cliques") << "Explain "; - for( std::map< Node, bool >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ - if( prev!=Node::null() ){ - Debug("uf-ss-cliques") << " = "; - //explain it2->first and prev - std::vector< TNode > expl; - d_th->d_equalityEngine.explainEquality( it2->first, prev, true, expl ); - for( int i=0; i<(int)expl.size(); i++ ){ - if( std::find( conflict.begin(), conflict.end(), expl[i] )==conflict.end() ){ - conflict.push_back( expl[i] ); + if( options::ufssExplainedCliques() ){ + //Debug("uf-ss-cliques") << conflict.size() << " " << clique.size() << std::endl; + Assert( (int)conflict.size()==((int)clique.size()*( (int)clique.size()-1 )/2) ); + //Assert( (int)conflict.size()==(int)clique.size()*( (int)clique.size()-1 )/2 ); + Debug("uf-ss-cliques") << "Finding clique equalities internal to eq classes..." << std::endl; + //now, we must explain equalities within each equivalence class + for( std::map< Node, std::map< Node, bool > >::iterator it = nodesWithinRep.begin(); it != nodesWithinRep.end(); ++it ){ + if( it->second.size()>1 ){ + Node prev; + //add explanation of t1 = t2 = ... = tn + Debug("uf-ss-cliques") << "Explain "; + for( std::map< Node, bool >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ + if( prev!=Node::null() ){ + Debug("uf-ss-cliques") << " = "; + //explain it2->first and prev + std::vector< TNode > expl; + d_thss->getTheory()->d_equalityEngine.explainEquality( it2->first, prev, true, expl ); + for( int i=0; i<(int)expl.size(); i++ ){ + if( std::find( conflict.begin(), conflict.end(), expl[i] )==conflict.end() ){ + conflict.push_back( expl[i] ); + } + } } + prev = it2->first; + Debug("uf-ss-cliques") << prev; } + Debug("uf-ss-cliques") << std::endl; } - prev = it2->first; - Debug("uf-ss-cliques") << prev; + } + Debug("uf-ss-cliques") << "Explanation of clique (size=" << conflict.size() << ") = " << std::endl; + for( int i=0; i<(int)conflict.size(); i++ ){ + Debug("uf-ss-cliques") << conflict[i] << " "; } Debug("uf-ss-cliques") << std::endl; } - } - Debug("uf-ss-cliques") << "Explanation of clique (size=" << conflict.size() << ") = " << std::endl; - for( int i=0; i<(int)conflict.size(); i++ ){ - Debug("uf-ss-cliques") << conflict[i] << " "; - //bool value; - //bool hasValue = d_th->getValuation().hasSatValue( conflict[i], value ); - //Assert( hasValue ); - //Assert( value ); - } - Debug("uf-ss-cliques") << std::endl; - //now, make the conflict -#if 1 - conflict.push_back( d_cardinality_literal[ d_cardinality ] ); - Node conflictNode = NodeManager::currentNM()->mkNode( AND, conflict ); - Trace("uf-ss-lemma") << "*** Add clique conflict " << conflictNode << std::endl; - //Notice() << "*** Add clique conflict " << conflictNode << std::endl; - out->conflict( conflictNode ); - d_conflict = true; -#else - Node conflictNode = conflict.size()==1 ? conflict[0] : NodeManager::currentNM()->mkNode( AND, conflict ); - //add cardinality constraint - Node cardNode = d_cardinality_literal[ d_cardinality ]; - //bool value; - //bool hasValue = d_th->getValuation().hasSatValue( cardNode, value ); - //Assert( hasValue ); - //Assert( value ); - conflictNode = NodeManager::currentNM()->mkNode( IMPLIES, conflictNode, cardNode.notNode() ); - Trace("uf-ss-lemma") << "*** Add clique conflict " << conflictNode << std::endl; - //Notice() << "*** Add clique conflict " << conflictNode << std::endl; - out->lemma( conflictNode ); -#endif - ++( d_th->getStrongSolver()->d_statistics.d_clique_lemmas ); + //now, make the conflict + if( isSatConflict ){ + conflict.push_back( d_cardinality_literal[ d_cardinality ] ); + Node conflictNode = NodeManager::currentNM()->mkNode( AND, conflict ); + Trace("uf-ss-lemma") << "*** Add clique conflict " << conflictNode << std::endl; + //Notice() << "*** Add clique conflict " << conflictNode << std::endl; + out->conflict( conflictNode ); + d_conflict = true; + ++( d_thss->d_statistics.d_clique_conflicts ); + }else{ + Node conflictNode = conflict.size()==1 ? conflict[0] : NodeManager::currentNM()->mkNode( AND, conflict ); + //add cardinality constraint + Node cardNode = d_cardinality_literal[ d_cardinality ]; + //bool value; + //bool hasValue = d_th->getValuation().hasSatValue( cardNode, value ); + //Assert( hasValue ); + //Assert( value ); + conflictNode = NodeManager::currentNM()->mkNode( IMPLIES, conflictNode, cardNode.notNode() ); + Trace("uf-ss-lemma") << "*** Add clique lemma " << conflictNode << std::endl; + out->lemma( conflictNode ); + ++( d_thss->d_statistics.d_clique_lemmas ); + } - //DO_THIS: ensure that the same clique is not reported??? Check standard effort after assertDisequal can produce same clique. + //DO_THIS: ensure that the same clique is not reported??? Check standard effort after assertDisequal can produce same clique. + } } -void StrongSolverTheoryUf::SortRepModel::addTotalityAxiom( Node n, int cardinality, OutputChannel* out ){ +void StrongSolverTheoryUF::SortModel::addTotalityAxiom( Node n, int cardinality, OutputChannel* out ){ Node cardLit = d_cardinality_literal[ cardinality ]; std::vector< Node > eqs; for( int i=0; i<cardinality; i++ ){ @@ -1141,25 +1227,25 @@ void StrongSolverTheoryUf::SortRepModel::addTotalityAxiom( Node n, int cardinali Node lem = NodeManager::currentNM()->mkNode( IMPLIES, cardLit, ax ); Trace("uf-ss-lemma") << "*** Add totality axiom " << lem << std::endl; //send as lemma to the output channel - d_th->getOutputChannel().lemma( lem ); - ++( d_th->getStrongSolver()->d_statistics.d_totality_lemmas ); + d_thss->getOutputChannel().lemma( lem ); + ++( d_thss->d_statistics.d_totality_lemmas ); } /** apply totality */ -bool StrongSolverTheoryUf::SortRepModel::applyTotality( int cardinality ){ +bool StrongSolverTheoryUF::SortModel::applyTotality( int cardinality ){ return options::ufssTotality() || cardinality<=options::ufssTotalityLimited(); // || ( options::ufssModelInference() && !d_totality_terms[cardinality].empty() ); } /** get totality lemma terms */ -Node StrongSolverTheoryUf::SortRepModel::getTotalityLemmaTerm( int cardinality, int i ){ +Node StrongSolverTheoryUF::SortModel::getTotalityLemmaTerm( int cardinality, int i ){ return d_totality_terms[0][i]; //}else{ // return d_totality_terms[cardinality][i]; //} } -void StrongSolverTheoryUf::SortRepModel::debugPrint( const char* c ){ +void StrongSolverTheoryUF::SortModel::debugPrint( const char* c ){ Debug( c ) << "-- Conflict Find:" << std::endl; Debug( c ) << "Number of reps = " << d_reps << std::endl; Debug( c ) << "Cardinality req = " << d_cardinality << std::endl; @@ -1184,7 +1270,7 @@ void StrongSolverTheoryUf::SortRepModel::debugPrint( const char* c ){ } } -void StrongSolverTheoryUf::SortRepModel::debugModel( TheoryModel* m ){ +void StrongSolverTheoryUF::SortModel::debugModel( TheoryModel* m ){ if( Trace.isOn("uf-ss-warn") ){ std::vector< Node > eqcs; eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &m->d_equalityEngine ); @@ -1211,7 +1297,7 @@ void StrongSolverTheoryUf::SortRepModel::debugModel( TheoryModel* m ){ } } -int StrongSolverTheoryUf::SortRepModel::getNumRegions(){ +int StrongSolverTheoryUF::SortModel::getNumRegions(){ int count = 0; for( int i=0; i<(int)d_regions_index; i++ ){ if( d_regions[i]->d_valid ){ @@ -1221,8 +1307,8 @@ int StrongSolverTheoryUf::SortRepModel::getNumRegions(){ return count; } -void StrongSolverTheoryUf::SortRepModel::getRepresentatives( std::vector< Node >& reps ){ - if( !options::ufssColoringSat() ){ +void StrongSolverTheoryUF::SortModel::getRepresentatives( std::vector< Node >& reps ){ + //if( !options::ufssColoringSat() ){ bool foundRegion = false; for( int i=0; i<(int)d_regions_index; i++ ){ //should not have multiple regions at this point @@ -1235,126 +1321,12 @@ void StrongSolverTheoryUf::SortRepModel::getRepresentatives( std::vector< Node > foundRegion = true; } } - }else{ - Unimplemented("Build representatives for fmf region sat is not implemented"); - } -} - - -/** initialize */ -void StrongSolverTheoryUf::InfRepModel::initialize( OutputChannel* out ){ - -} - -/** new node */ -void StrongSolverTheoryUf::InfRepModel::newEqClass( Node n ){ - d_rep[n] = n; - //d_const_rep[n] = n.getMetaKind()==metakind::CONSTANT; -} - -/** merge */ -void StrongSolverTheoryUf::InfRepModel::merge( Node a, Node b ){ - //d_rep[b] = false; - //d_const_rep[a] = d_const_rep[a] || d_const_rep[b]; - Node repb = d_rep[b]; - Assert( !repb.isNull() ); - if( repb.getMetaKind()==metakind::CONSTANT || isBadRepresentative( d_rep[a] ) ){ - d_rep[a] = repb; - } - d_rep[b] = Node::null(); -} - -/** check */ -void StrongSolverTheoryUf::InfRepModel::check( Theory::Effort level, OutputChannel* out ){ - -} - -/** minimize */ -bool StrongSolverTheoryUf::InfRepModel::minimize( OutputChannel* out ){ -#if 0 - bool retVal = true; -#else - bool retVal = !addSplit( out ); -#endif - if( retVal ){ - std::vector< Node > reps; - getRepresentatives( reps ); - Trace("uf-ss-fmf") << "Num representatives of type " << d_type << " : " << reps.size() << std::endl; - /* - for( int i=0; i<(int)reps.size(); i++ ){ - std::cout << reps[i] << " "; - } - std::cout << std::endl; - for( int i=0; i<(int)reps.size(); i++ ){ - std::cout << reps[i].getMetaKind() << " "; - } - std::cout << std::endl; - for( NodeNodeMap::iterator it = d_rep.begin(); it != d_rep.end(); ++it ){ - Node rep = (*it).second; - if( !rep.isNull() && !isBadRepresentative( rep ) ){ - for( NodeNodeMap::iterator it2 = d_rep.begin(); it2 != d_rep.end(); ++it2 ){ - Node rep2 = (*it2).second; - if( !rep2.isNull() && !isBadRepresentative( rep2 ) ){ - if( d_th->getQuantifiersEngine()->getEqualityQuery()->areDisequal( rep, rep2 ) ){ - std::cout << "1 "; - }else{ - std::cout << "0 "; - } - } - } - //std::cout << " : " << rep; - std::cout << std::endl; - } - } - */ - } - return retVal; -} - -/** get representatives */ -void StrongSolverTheoryUf::InfRepModel::getRepresentatives( std::vector< Node >& reps ){ - for( NodeNodeMap::iterator it = d_rep.begin(); it != d_rep.end(); ++it ){ - if( !(*it).second.isNull() ){ - reps.push_back( (*it).first ); - } - } -} - - -/** add split function */ -bool StrongSolverTheoryUf::InfRepModel::addSplit( OutputChannel* out ){ - std::vector< Node > visited; - for( NodeNodeMap::iterator it = d_rep.begin(); it != d_rep.end(); ++it ){ - Node rep = (*it).second; - if( !rep.isNull() && !isBadRepresentative( rep ) ){ - bool constRep = rep.getMetaKind()==metakind::CONSTANT; - for( size_t i=0; i<visited.size(); i++ ){ - if( !constRep || !visited[i].getMetaKind()==metakind::CONSTANT ){ - if( !d_th->getQuantifiersEngine()->getEqualityQuery()->areDisequal( rep, visited[i] ) ){ - //split on these nodes - Node eq = rep.eqNode( visited[i] ); - Trace("uf-ss-lemma") << "*** Split on " << eq << std::endl; - eq = Rewriter::rewrite( eq ); - Debug("uf-ss-lemma-debug") << "Rewritten " << eq << std::endl; - out->split( eq ); - //explore the equals branch first - out->requirePhase( eq, true ); - ++( d_th->getStrongSolver()->d_statistics.d_split_lemmas ); - return true; - } - } - } - visited.push_back( rep ); - } - } - return false; -} - -bool StrongSolverTheoryUf::InfRepModel::isBadRepresentative( Node n ){ - return n.getKind()==kind::PLUS; + //}else{ + // Unimplemented("Build representatives for fmf region sat is not implemented"); + //} } -StrongSolverTheoryUf::StrongSolverTheoryUf(context::Context* c, context::UserContext* u, OutputChannel& out, TheoryUF* th) : +StrongSolverTheoryUF::StrongSolverTheoryUF(context::Context* c, context::UserContext* u, OutputChannel& out, TheoryUF* th) : d_out( &out ), d_th( th ), d_conflict( c, false ), @@ -1367,78 +1339,129 @@ d_rep_model_init( c ) }else{ d_term_amb = NULL; } + if( options::ufssDiseqPropagation() ){ + d_deq_prop = new DisequalityPropagator( th->getQuantifiersEngine(), this ); + }else{ + d_deq_prop = NULL; + } +} + +/** get default sat context */ +context::Context* StrongSolverTheoryUF::getSatContext() { + return d_th->getSatContext(); +} + +/** get default output channel */ +OutputChannel& StrongSolverTheoryUF::getOutputChannel() { + return d_th->getOutputChannel(); } /** new node */ -void StrongSolverTheoryUf::newEqClass( Node n ){ - RepModel* c = getRepModel( n ); +void StrongSolverTheoryUF::newEqClass( Node n ){ + SortModel* c = getSortModel( n ); if( c ){ - Trace("uf-ss-solver") << "StrongSolverTheoryUf: New eq class " << n << " : " << n.getType() << std::endl; + Trace("uf-ss-solver") << "StrongSolverTheoryUF: New eq class " << n << " : " << n.getType() << std::endl; c->newEqClass( n ); } } /** merge */ -void StrongSolverTheoryUf::merge( Node a, Node b ){ - RepModel* c = getRepModel( a ); +void StrongSolverTheoryUF::merge( Node a, Node b ){ + SortModel* c = getSortModel( a ); if( c ){ - Trace("uf-ss-solver") << "StrongSolverTheoryUf: Merge " << a << " " << b << " : " << a.getType() << std::endl; + Trace("uf-ss-solver") << "StrongSolverTheoryUF: Merge " << a << " " << b << " : " << a.getType() << std::endl; c->merge( a, b ); + }else{ + if( options::ufssDiseqPropagation() ){ + d_deq_prop->merge(a, b); + } } } /** assert terms are disequal */ -void StrongSolverTheoryUf::assertDisequal( Node a, Node b, Node reason ){ - RepModel* c = getRepModel( a ); +void StrongSolverTheoryUF::assertDisequal( Node a, Node b, Node reason ){ + SortModel* c = getSortModel( a ); if( c ){ - Trace("uf-ss-solver") << "StrongSolverTheoryUf: Assert disequal " << a << " " << b << " : " << a.getType() << std::endl; + Trace("uf-ss-solver") << "StrongSolverTheoryUF: Assert disequal " << a << " " << b << " : " << a.getType() << std::endl; //Assert( d_th->d_equalityEngine.getRepresentative( a )==a ); //Assert( d_th->d_equalityEngine.getRepresentative( b )==b ); c->assertDisequal( a, b, reason ); + }else{ + if( options::ufssDiseqPropagation() ){ + d_deq_prop->assertDisequal(a, b, reason); + } } } /** assert a node */ -void StrongSolverTheoryUf::assertNode( Node n, bool isDecision ){ +void StrongSolverTheoryUF::assertNode( Node n, bool isDecision ){ Trace("uf-ss") << "Assert " << n << " " << isDecision << std::endl; - if( n.getKind()==CARDINALITY_CONSTRAINT ){ - TypeNode tn = n[0].getType(); - Assert( tn.isSort() ); - Assert( d_rep_model[tn] ); - long nCard = n[1].getConst<Rational>().getNumerator().getLong(); - d_rep_model[tn]->assertCardinality( d_out, nCard, true ); - }else if( n.getKind()==NOT && n[0].getKind()==CARDINALITY_CONSTRAINT ){ - Node nn = n[0]; - TypeNode tn = nn[0].getType(); + bool polarity = n.getKind() != kind::NOT; + TNode lit = polarity ? n : n[0]; + if( lit.getKind()==CARDINALITY_CONSTRAINT ){ + TypeNode tn = lit[0].getType(); Assert( tn.isSort() ); Assert( d_rep_model[tn] ); - long nCard = nn[1].getConst<Rational>().getNumerator().getLong(); - d_rep_model[tn]->assertCardinality( d_out, nCard, false ); + long nCard = lit[1].getConst<Rational>().getNumerator().getLong(); + d_rep_model[tn]->assertCardinality( d_out, nCard, polarity ); }else{ - ////FIXME: this is too strict: theory propagations are showing up as isDecision=true, but - //// a theory propagation is not a decision. - if( isDecision ){ - for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ - if( !it->second->hasCardinalityAsserted() ){ - Trace("uf-ss-warn") << "WARNING: Assert " << n << " as a decision before cardinality for " << it->first << "." << std::endl; - //Message() << "Error: constraint asserted before cardinality for " << it->first << std::endl; - //Unimplemented(); + if( Trace.isOn("uf-ss-warn") ){ + ////FIXME: this is too strict: theory propagations are showing up as isDecision=true, but + //// a theory propagation is not a decision. + if( isDecision ){ + for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ + if( !it->second->hasCardinalityAsserted() ){ + Trace("uf-ss-warn") << "WARNING: Assert " << n << " as a decision before cardinality for " << it->first << "." << std::endl; + //Message() << "Error: constraint asserted before cardinality for " << it->first << std::endl; + //Unimplemented(); + } } } } + if( lit.getKind()!=EQUAL ){ + //it is a predicate + if( options::ufssDiseqPropagation() ){ + d_deq_prop->assertPredicate(lit, polarity); + } + } } Trace("uf-ss") << "Assert: done " << n << " " << isDecision << std::endl; } +bool StrongSolverTheoryUF::areDisequal( Node a, Node b ) { + if( a==b ){ + return false; + }else{ + a = d_th->d_equalityEngine.getRepresentative( a ); + b = d_th->d_equalityEngine.getRepresentative( b ); + if( d_th->d_equalityEngine.areDisequal( a, b, false ) ){ + return true; + }else{ + SortModel* c = getSortModel( a ); + if( c ){ + return c->areDisequal( a, b ); + }else{ + return false; + } + } + } +} /** check */ -void StrongSolverTheoryUf::check( Theory::Effort level ){ +void StrongSolverTheoryUF::check( Theory::Effort level ){ if( !d_conflict ){ - Trace("uf-ss-solver") << "StrongSolverTheoryUf: check " << level << std::endl; + Trace("uf-ss-solver") << "StrongSolverTheoryUF: check " << level << std::endl; if( level==Theory::EFFORT_FULL ){ debugPrint( "uf-ss-debug" ); } - for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ + if( !d_conflict && level==Theory::EFFORT_FULL && options::ufssColoringSat() ){ + int lemmas = d_term_amb->disambiguateTerms( d_out ); + d_statistics.d_disamb_term_lemmas += lemmas; + if( lemmas>=0 ){ + return; + } + } + for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ it->second->check( level, d_out ); if( it->second->isConflict() ){ d_conflict = true; @@ -1446,24 +1469,24 @@ void StrongSolverTheoryUf::check( Theory::Effort level ){ } } //disambiguate terms if necessary - if( !d_conflict && level==Theory::EFFORT_FULL && options::ufssColoringSat() ){ - Assert( d_term_amb!=NULL ); - d_statistics.d_disamb_term_lemmas += d_term_amb->disambiguateTerms( d_out ); - } - Trace("uf-ss-solver") << "Done StrongSolverTheoryUf: check " << level << std::endl; + //if( !d_conflict && level==Theory::EFFORT_FULL && options::ufssColoringSat() ){ + // Assert( d_term_amb!=NULL ); + // d_statistics.d_disamb_term_lemmas += d_term_amb->disambiguateTerms( d_out ); + //} + Trace("uf-ss-solver") << "Done StrongSolverTheoryUF: check " << level << std::endl; } } /** propagate */ -void StrongSolverTheoryUf::propagate( Theory::Effort level ){ - //for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ +void StrongSolverTheoryUF::propagate( Theory::Effort level ){ + //for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ // it->second->propagate( level, d_out ); //} } /** get next decision request */ -Node StrongSolverTheoryUf::getNextDecisionRequest(){ - for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ +Node StrongSolverTheoryUF::getNextDecisionRequest(){ + for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ Node n = it->second->getNextDecisionRequest(); if( !n.isNull() ){ return n; @@ -1472,18 +1495,15 @@ Node StrongSolverTheoryUf::getNextDecisionRequest(){ return Node::null(); } -void StrongSolverTheoryUf::preRegisterTerm( TNode n ){ +void StrongSolverTheoryUF::preRegisterTerm( TNode n ){ Trace("uf-ss-register") << "Preregister " << n << "." << std::endl; //shouldn't have to preregister this type (it may be that there are no quantifiers over tn) TypeNode tn = n.getType(); if( d_rep_model.find( tn )==d_rep_model.end() ){ - RepModel* rm = NULL; + SortModel* rm = NULL; if( tn.isSort() ){ Trace("uf-ss-register") << "Preregister sort " << tn << "." << std::endl; - rm = new SortRepModel( n, d_th->getSatContext(), d_th ); - }else if( tn.isInteger() ){ - //rm = new InfRepModel( tn, d_th->getSatContext(), d_th ); - //rm = new SortRepModel( tn, d_th->getSatContext(), d_th ); + rm = new SortModel( n, d_th->getSatContext(), this ); }else{ /* if( tn==NodeManager::currentNM()->integerType() || tn==NodeManager::currentNM()->realType() ){ @@ -1509,7 +1529,7 @@ void StrongSolverTheoryUf::preRegisterTerm( TNode n ){ } } -void StrongSolverTheoryUf::registerQuantifier( Node f ){ +void StrongSolverTheoryUF::registerQuantifier( Node f ){ Debug("uf-ss-register") << "Register quantifier " << f << std::endl; //must ensure the quantifier does not quantify over arithmetic //for( int i=0; i<(int)f[0].getNumChildren(); i++ ){ @@ -1519,9 +1539,9 @@ void StrongSolverTheoryUf::registerQuantifier( Node f ){ } -StrongSolverTheoryUf::RepModel* StrongSolverTheoryUf::getRepModel( Node n ){ +StrongSolverTheoryUF::SortModel* StrongSolverTheoryUF::getSortModel( Node n ){ TypeNode tn = n.getType(); - std::map< TypeNode, RepModel* >::iterator it = d_rep_model.find( tn ); + std::map< TypeNode, SortModel* >::iterator it = d_rep_model.find( tn ); //pre-register the type if not done already if( it==d_rep_model.end() ){ preRegisterTerm( n ); @@ -1539,13 +1559,13 @@ StrongSolverTheoryUf::RepModel* StrongSolverTheoryUf::getRepModel( Node n ){ return NULL; } -void StrongSolverTheoryUf::notifyRestart(){ +void StrongSolverTheoryUF::notifyRestart(){ } /** get cardinality for sort */ -int StrongSolverTheoryUf::getCardinality( Node n ) { - RepModel* c = getRepModel( n ); +int StrongSolverTheoryUF::getCardinality( Node n ) { + SortModel* c = getSortModel( n ); if( c ){ return c->getCardinality(); }else{ @@ -1553,27 +1573,27 @@ int StrongSolverTheoryUf::getCardinality( Node n ) { } } -void StrongSolverTheoryUf::getRepresentatives( Node n, std::vector< Node >& reps ){ - RepModel* c = getRepModel( n ); +void StrongSolverTheoryUF::getRepresentatives( Node n, std::vector< Node >& reps ){ + SortModel* c = getSortModel( n ); if( c ){ c->getRepresentatives( reps ); } } -bool StrongSolverTheoryUf::minimize( TheoryModel* m ){ - for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ +bool StrongSolverTheoryUF::minimize( TheoryModel* m ){ + for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ if( !it->second->minimize( d_out, m ) ){ return false; } } - for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ + for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ Trace("uf-ss-minimize") << "Cardinality( " << it->first << " ) : " << it->second->getCardinality() << std::endl; } return true; } //print debug -void StrongSolverTheoryUf::debugPrint( const char* c ){ +void StrongSolverTheoryUF::debugPrint( const char* c ){ //EqClassesIterator< TheoryUF::NotifyClass > eqc_iter( &((TheoryUF*)d_th)->d_equalityEngine ); //while( !eqc_iter.isFinished() ){ // Debug( c ) << "Eq class [[" << (*eqc_iter) << "]]" << std::endl; @@ -1587,28 +1607,30 @@ void StrongSolverTheoryUf::debugPrint( const char* c ){ // eqc_iter++; //} - for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ + for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ Debug( c ) << "Conflict find structure for " << it->first << ": " << std::endl; it->second->debugPrint( c ); Debug( c ) << std::endl; } } -void StrongSolverTheoryUf::debugModel( TheoryModel* m ){ +void StrongSolverTheoryUF::debugModel( TheoryModel* m ){ if( Trace.isOn("uf-ss-warn") ){ - for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ + for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ it->second->debugModel( m ); } } } -StrongSolverTheoryUf::Statistics::Statistics(): - d_clique_lemmas("StrongSolverTheoryUf::Clique_Lemmas", 0), - d_split_lemmas("StrongSolverTheoryUf::Split_Lemmas", 0), - d_disamb_term_lemmas("StrongSolverTheoryUf::Disambiguate_Term_Lemmas", 0), - d_totality_lemmas("StrongSolverTheoryUf::Totality_Lemmas", 0), - d_max_model_size("StrongSolverTheoryUf::Max_Model_Size", 1) +StrongSolverTheoryUF::Statistics::Statistics(): + d_clique_conflicts("StrongSolverTheoryUF::Clique_Conflicts", 0), + d_clique_lemmas("StrongSolverTheoryUF::Clique_Lemmas", 0), + d_split_lemmas("StrongSolverTheoryUF::Split_Lemmas", 0), + d_disamb_term_lemmas("StrongSolverTheoryUF::Disambiguate_Term_Lemmas", 0), + d_totality_lemmas("StrongSolverTheoryUF::Totality_Lemmas", 0), + d_max_model_size("StrongSolverTheoryUF::Max_Model_Size", 1) { + StatisticsRegistry::registerStat(&d_clique_conflicts); StatisticsRegistry::registerStat(&d_clique_lemmas); StatisticsRegistry::registerStat(&d_split_lemmas); StatisticsRegistry::registerStat(&d_disamb_term_lemmas); @@ -1616,7 +1638,8 @@ StrongSolverTheoryUf::Statistics::Statistics(): StatisticsRegistry::registerStat(&d_max_model_size); } -StrongSolverTheoryUf::Statistics::~Statistics(){ +StrongSolverTheoryUF::Statistics::~Statistics(){ + StatisticsRegistry::unregisterStat(&d_clique_conflicts); StatisticsRegistry::unregisterStat(&d_clique_lemmas); StatisticsRegistry::unregisterStat(&d_split_lemmas); StatisticsRegistry::unregisterStat(&d_disamb_term_lemmas); @@ -1667,11 +1690,12 @@ int TermDisambiguator::disambiguateTerms( OutputChannel* out ){ } Assert( children.size()>1 ); Node lem = NodeManager::currentNM()->mkNode( OR, children ); - Debug( "uf-ss-lemma" ) << "*** Disambiguate lemma : " << lem << std::endl; + Trace( "uf-ss-lemma" ) << "*** Disambiguate lemma : " << lem << std::endl; //Notice() << "*** Disambiguate lemma : " << lem << std::endl; out->lemma( lem ); d_term_amb[ eq ] = false; lemmaAdded++; + return lemmaAdded; } } } @@ -1693,3 +1717,73 @@ bool TermDisambiguator::involvesRelevantType( Node n ){ } return false; } + +DisequalityPropagator::DisequalityPropagator(QuantifiersEngine* qe, StrongSolverTheoryUF* ufss) : + d_qe(qe), d_ufss(ufss){ + d_true = NodeManager::currentNM()->mkConst( true ); + d_false = NodeManager::currentNM()->mkConst( false ); +} + +void DisequalityPropagator::checkEquivalenceClass( Node t, Node eqc ) { + if( t.getKind()==APPLY_UF ){ + Node op = t.getOperator(); + eqc = d_ufss->getTheory()->getEqualityEngine()->getRepresentative( eqc ); + eq::EqClassIterator eqc_i(eqc, d_ufss->getTheory()->getEqualityEngine()); + while( !eqc_i.isFinished() ){ + Node s = *eqc_i; + if( s.getKind()==APPLY_UF && s.getOperator()==op ){ + int unkIndex = -1; + for( size_t i=0; i<t.getNumChildren(); i++ ){ + //should consult strong solver since it knows more disequalities + if( d_ufss->areDisequal( t[i], s[i] ) ){ + //if( d_qe->getEqualityQuery()->areDisequal( t[i], s[i] ) ){ + unkIndex = -1; + break; + }else if( !d_qe->getEqualityQuery()->areEqual( t[i], s[i] ) ){ + if( unkIndex==-1 ){ + unkIndex = i; + }else{ + unkIndex = -1; + break; + } + } + } + if( unkIndex!=-1 ){ + Trace("deq-prop") << "propagate disequality " << t[unkIndex] << " " << s[unkIndex] << std::endl; + d_ufss->assertDisequal(t[unkIndex], s[unkIndex], Node::null()); + ++( d_statistics.d_propagations ); + if( d_ufss->isConflict() ){ + return; + } + } + } + ++eqc_i; + } + } +} + +/** merge */ +void DisequalityPropagator::merge( Node a, Node b ){ + +} + +/** assert terms are disequal */ +void DisequalityPropagator::assertDisequal( Node a, Node b, Node reason ){ + Trace("deq-prop") << "Notify disequal : " << a << " " << b << std::endl; +} + + +void DisequalityPropagator::assertPredicate( Node p, bool polarity ) { + Trace("deq-prop") << "Assert predicate : " << p << " " << polarity << std::endl; + checkEquivalenceClass( p, polarity ? d_false : d_true ); +} + +DisequalityPropagator::Statistics::Statistics(): + d_propagations("StrongSolverTheoryUF::Disequality_Propagations", 0) +{ + StatisticsRegistry::registerStat(& d_propagations); +} + +DisequalityPropagator::Statistics::~Statistics(){ + StatisticsRegistry::unregisterStat(& d_propagations); +}
\ No newline at end of file diff --git a/src/theory/uf/theory_uf_strong_solver.h b/src/theory/uf/theory_uf_strong_solver.h index febae2eae..33493248d 100644 --- a/src/theory/uf/theory_uf_strong_solver.h +++ b/src/theory/uf/theory_uf_strong_solver.h @@ -31,8 +31,9 @@ namespace uf { class TheoryUF; class TermDisambiguator; +class DisequalityPropagator; -class StrongSolverTheoryUf{ +class StrongSolverTheoryUF{ protected: typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap; typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap; @@ -42,51 +43,14 @@ protected: typedef context::CDList<bool> IntList; typedef context::CDHashMap<TypeNode, bool, TypeNodeHashFunction> TypeNodeBoolMap; public: - class RepModel { - protected: - /** type */ - TypeNode d_type; - public: - RepModel( TypeNode tn ) : d_type( tn ){} - virtual ~RepModel(){} - /** initialize */ - virtual void initialize( OutputChannel* out ) = 0; - /** new node */ - virtual void newEqClass( Node n ) = 0; - /** merge */ - virtual void merge( Node a, Node b ) = 0; - /** assert terms are disequal */ - virtual void assertDisequal( Node a, Node b, Node reason ) = 0; - /** check */ - virtual void check( Theory::Effort level, OutputChannel* out ){} - /** get next decision request */ - virtual Node getNextDecisionRequest() { return Node::null(); } - /** minimize */ - virtual bool minimize( OutputChannel* out, TheoryModel* m ){ return true; } - /** assert cardinality */ - virtual void assertCardinality( OutputChannel* out, int c, bool val ){} - /** is in conflict */ - virtual bool isConflict() { return false; } - /** get cardinality */ - virtual int getCardinality() { return -1; } - /** has cardinality */ - virtual bool hasCardinalityAsserted() { return true; } - /** get representatives */ - virtual void getRepresentatives( std::vector< Node >& reps ){} - /** print debug */ - virtual void debugPrint( const char* c ){} - /** debug a model */ - virtual void debugModel( TheoryModel* m ){} - }; -public: /** information for incremental conflict/clique finding for a particular sort */ - class SortRepModel : public RepModel { + class SortModel { public: /** a partition of the current equality graph for which cliques can occur internally */ class Region { public: /** conflict find pointer */ - SortRepModel* d_cf; + SortModel* d_cf; /** information stored about each node in region */ class RegionNodeInfo { public: @@ -142,7 +106,7 @@ public: void setRep( Node n, bool valid ); public: //constructor - Region( SortRepModel* cf, context::Context* c ) : d_cf( cf ), d_testCliqueSize( c, 0 ), + Region( SortModel* cf, context::Context* c ) : d_cf( cf ), d_testCliqueSize( c, 0 ), d_splitsSize( c, 0 ), d_testClique( c ), d_splits( c ), d_reps_size( c, 0 ), d_total_diseq_external( c, 0 ), d_total_diseq_internal( c, 0 ), d_valid( c, true ) { } @@ -186,8 +150,10 @@ public: void debugPrint( const char* c, bool incClique = false ); }; private: - /** theory uf pointer */ - TheoryUF* d_th; + /** the type this model is for */ + TypeNode d_type; + /** strong solver pointer */ + StrongSolverTheoryUF* d_thss; /** regions used to d_region_index */ context::CDO< unsigned > d_regions_index; /** vector of regions */ @@ -213,7 +179,7 @@ public: void setSplitScore( Node n, int s ); private: /** check if we need to combine region ri */ - void checkRegion( int ri, bool rec = true ); + void checkRegion( int ri, bool checkCombine = true ); /** force combine region */ int forceCombineRegion( int ri, bool useDensity = true ); /** merge regions */ @@ -256,8 +222,8 @@ public: /** get totality lemma terms */ Node getTotalityLemmaTerm( int cardinality, int i ); public: - SortRepModel( Node n, context::Context* c, TheoryUF* th ); - virtual ~SortRepModel(){} + SortModel( Node n, context::Context* c, StrongSolverTheoryUF* thss ); + virtual ~SortModel(){} /** initialize */ void initialize( OutputChannel* out ); /** new node */ @@ -266,6 +232,8 @@ public: void merge( Node a, Node b ); /** assert terms are disequal */ void assertDisequal( Node a, Node b, Node reason ); + /** are disequal */ + bool areDisequal( Node a, Node b ); /** check */ void check( Theory::Effort level, OutputChannel* out ); /** propagate */ @@ -291,43 +259,7 @@ public: public: /** get number of regions (for debugging) */ int getNumRegions(); - }; /** class SortRepModel */ -private: - /** infinite rep model */ - class InfRepModel : public RepModel - { - protected: - /** theory uf pointer */ - TheoryUF* d_th; - /** list of representatives */ - NodeNodeMap d_rep; - /** whether representatives are constant */ - NodeBoolMap d_const_rep; - /** add split */ - bool addSplit( OutputChannel* out ); - /** is bad representative */ - bool isBadRepresentative( Node n ); - public: - InfRepModel( TypeNode tn, context::Context* c, TheoryUF* th ) : RepModel( tn ), - d_th( th ), d_rep( c ), d_const_rep( c ){} - virtual ~InfRepModel(){} - /** initialize */ - void initialize( OutputChannel* out ); - /** new node */ - void newEqClass( Node n ); - /** merge */ - void merge( Node a, Node b ); - /** assert terms are disequal */ - void assertDisequal( Node a, Node b, Node reason ){} - /** check */ - void check( Theory::Effort level, OutputChannel* out ); - /** minimize */ - bool minimize( OutputChannel* out ); - /** get representatives */ - void getRepresentatives( std::vector< Node >& reps ); - /** print debug */ - void debugPrint( const char* c ){} - }; + }; /** class SortModel */ private: /** The output channel for the strong solver. */ OutputChannel* d_out; @@ -336,19 +268,31 @@ private: /** Are we in conflict */ context::CDO<bool> d_conflict; /** rep model structure, one for each type */ - std::map< TypeNode, RepModel* > d_rep_model; + std::map< TypeNode, SortModel* > d_rep_model; /** all types */ std::vector< TypeNode > d_conf_types; /** whether conflict find data structures have been initialized */ TypeNodeBoolMap d_rep_model_init; /** get conflict find */ - RepModel* getRepModel( Node n ); + SortModel* getSortModel( Node n ); private: /** term disambiguator */ TermDisambiguator* d_term_amb; + /** disequality propagator */ + DisequalityPropagator* d_deq_prop; public: - StrongSolverTheoryUf(context::Context* c, context::UserContext* u, OutputChannel& out, TheoryUF* th); - ~StrongSolverTheoryUf() {} + StrongSolverTheoryUF(context::Context* c, context::UserContext* u, OutputChannel& out, TheoryUF* th); + ~StrongSolverTheoryUF() {} + /** get theory */ + TheoryUF* getTheory() { return d_th; } + /** term disambiguator */ + TermDisambiguator* getTermDisambiguator() { return d_term_amb; } + /** disequality propagator */ + DisequalityPropagator* getDisequalityPropagator() { return d_deq_prop; } + /** get default sat context */ + context::Context* getSatContext(); + /** get default output channel */ + OutputChannel& getOutputChannel(); /** new node */ void newEqClass( Node n ); /** merge */ @@ -357,6 +301,8 @@ public: void assertDisequal( Node a, Node b, Node reason ); /** assert node */ void assertNode( Node n, bool isDecision ); + /** are disequal */ + bool areDisequal( Node a, Node b ); public: /** check */ void check( Theory::Effort level ); @@ -372,7 +318,7 @@ public: void notifyRestart(); public: /** identify */ - std::string identify() const { return std::string("StrongSolverTheoryUf"); } + std::string identify() const { return std::string("StrongSolverTheoryUF"); } //print debug void debugPrint( const char* c ); /** debug a model */ @@ -393,6 +339,7 @@ public: class Statistics { public: + IntStat d_clique_conflicts; IntStat d_clique_lemmas; IntStat d_split_lemmas; IntStat d_disamb_term_lemmas; @@ -403,7 +350,7 @@ public: }; /** statistics class */ Statistics d_statistics; -};/* class StrongSolverTheoryUf */ +};/* class StrongSolverTheoryUF */ class TermDisambiguator @@ -422,6 +369,37 @@ public: int disambiguateTerms( OutputChannel* out ); }; +class DisequalityPropagator +{ +private: + /** quantifiers engine */ + QuantifiersEngine* d_qe; + /** strong solver */ + StrongSolverTheoryUF* d_ufss; + /** true,false */ + Node d_true; + Node d_false; + /** check term t against equivalence class that t is disequal from */ + void checkEquivalenceClass( Node t, Node eqc ); +public: + DisequalityPropagator(QuantifiersEngine* qe, StrongSolverTheoryUF* ufss); + /** merge */ + void merge( Node a, Node b ); + /** assert terms are disequal */ + void assertDisequal( Node a, Node b, Node reason ); + /** assert predicate */ + void assertPredicate( Node p, bool polarity ); +public: + class Statistics { + public: + IntStat d_propagations; + Statistics(); + ~Statistics(); + }; + /** statistics class */ + Statistics d_statistics; +}; + } }/* CVC4::theory namespace */ }/* CVC4 namespace */ diff --git a/src/util/configuration.cpp b/src/util/configuration.cpp index 59fe28eca..c6e951049 100644 --- a/src/util/configuration.cpp +++ b/src/util/configuration.cpp @@ -195,6 +195,33 @@ bool Configuration::isTraceTag(char const * tag){ return false; } +bool Configuration::isGitBuild() { + return IS_GIT_BUILD; +} + +const char* Configuration::getGitBranchName() { + return GIT_BRANCH_NAME; +} + +const char* Configuration::getGitCommit() { + return GIT_COMMIT; +} + +bool Configuration::hasGitModifications() { + return GIT_HAS_MODIFICATIONS; +} + +std::string Configuration::getGitId() { + if(! isGitBuild()) { + return ""; + } + + stringstream ss; + ss << "git " << getGitBranchName() << " " << string(getGitCommit()).substr(0, 8) + << ( ::CVC4::Configuration::hasGitModifications() ? " (with modifications)" : "" ); + return ss.str(); +} + bool Configuration::isSubversionBuild() { return IS_SUBVERSION_BUILD; } @@ -211,7 +238,7 @@ bool Configuration::hasSubversionModifications() { return SUBVERSION_HAS_MODIFICATIONS; } -string Configuration::getSubversionId() { +std::string Configuration::getSubversionId() { if(! isSubversionBuild()) { return ""; } diff --git a/src/util/configuration.h b/src/util/configuration.h index 3f6547872..c85f62f7f 100644 --- a/src/util/configuration.h +++ b/src/util/configuration.h @@ -38,6 +38,10 @@ class CVC4_PUBLIC Configuration { static const char* const SUBVERSION_BRANCH_NAME; static const unsigned SUBVERSION_REVISION; static const bool SUBVERSION_HAS_MODIFICATIONS; + static const bool IS_GIT_BUILD; + static const char* const GIT_BRANCH_NAME; + static const char* const GIT_COMMIT; + static const bool GIT_HAS_MODIFICATIONS; public: @@ -101,6 +105,12 @@ public: /* Test if the given argument is a known trace tag name */ static bool isTraceTag(char const *); + static bool isGitBuild(); + static const char* getGitBranchName(); + static const char* getGitCommit(); + static bool hasGitModifications(); + static std::string getGitId(); + static bool isSubversionBuild(); static const char* getSubversionBranchName(); static unsigned getSubversionRevision(); diff --git a/src/util/configuration_private.h b/src/util/configuration_private.h index c480b4318..4378badc8 100644 --- a/src/util/configuration_private.h +++ b/src/util/configuration_private.h @@ -115,13 +115,16 @@ namespace CVC4 { #define CVC4_ABOUT_STRING ( ::std::string("\ This is CVC4 version " CVC4_RELEASE_STRING ) + \ + ( ::CVC4::Configuration::isGitBuild() \ + ? ( ::std::string(" [") + ::CVC4::Configuration::getGitId() + "]" ) \ + : \ ( ::CVC4::Configuration::isSubversionBuild() \ ? ( ::std::string(" [") + ::CVC4::Configuration::getSubversionId() + "]" ) \ : ::std::string("") \ - ) + "\n\ + )) + "\n\ compiled with " + ::CVC4::Configuration::getCompiler() + "\n\ on " + ::CVC4::Configuration::getCompiledDateTime() + "\n\n\ -Copyright (C) 2009, 2010, 2011, 2012\n\ +Copyright (C) 2009, 2010, 2011, 2012, 2013\n\ New York University and The University of Iowa\n\n" + \ ( IS_CLN_BUILD ? "\ This CVC4 library uses CLN as its multi-precision arithmetic library.\n\n\ diff --git a/src/util/dense_map.h b/src/util/dense_map.h index fa78e6787..222a761c3 100644 --- a/src/util/dense_map.h +++ b/src/util/dense_map.h @@ -151,6 +151,7 @@ public: pop_back(); } + /** Returns the key at the back of a non-empty list.*/ Key back() const { return d_list.back(); } @@ -164,6 +165,27 @@ public: d_list.pop_back(); } + + /** Adds at least a constant fraction of the elements in the current map to another map. */ + void splitInto(DenseMap<T>& target){ + uint32_t targetSize = size()/2; + while(size() > targetSize){ + Key key = back(); + target.set(key, get(key)); + pop_back(); + } + } + + /** Adds the current target map to the current map.*/ + void addAll(const DenseMap<T>& target){ + for(const_iterator i = target.begin(), e = target.end(); i != e; ++i){ + Key k = *i; + set(k, target[k]); + } + } + + + private: size_t allocated() const { diff --git a/src/util/integer.h.in b/src/util/integer.h.in index 1f0174083..27b589b5a 100644 --- a/src/util/integer.h.in +++ b/src/util/integer.h.in @@ -1,5 +1,5 @@ /********************* */ -/*! \file integer.h +/*! \file integer.h.in ** \verbatim ** Original author: taking ** Major contributors: none diff --git a/src/util/node_visitor.h b/src/util/node_visitor.h index e444ba6e2..4c8e646bd 100644 --- a/src/util/node_visitor.h +++ b/src/util/node_visitor.h @@ -36,10 +36,11 @@ class NodeVisitor { /** * Guard against NodeVisitor<> being re-entrant. */ + template <class T> class GuardReentry { - bool& d_guard; + T& d_guard; public: - GuardReentry(bool& guard) + GuardReentry(T& guard) : d_guard(guard) { Assert(!d_guard); d_guard = true; @@ -71,7 +72,7 @@ public: */ static typename Visitor::return_type run(Visitor& visitor, TNode node) { - GuardReentry guard(bool(s_inRun)); + GuardReentry<CVC4_THREADLOCAL_TYPE(bool)> guard(s_inRun); // Notify of a start visitor.start(node); diff --git a/src/util/rational.h.in b/src/util/rational.h.in index c8e42a253..7f5b1feb4 100644 --- a/src/util/rational.h.in +++ b/src/util/rational.h.in @@ -1,5 +1,5 @@ /********************* */ -/*! \file rational.h +/*! \file rational.h.in ** \verbatim ** Original author: taking ** Major contributors: none diff --git a/src/util/record.h b/src/util/record.h index 2c15d30e0..27b090e1d 100644 --- a/src/util/record.h +++ b/src/util/record.h @@ -29,7 +29,7 @@ namespace CVC4 { -class Record; +class CVC4_PUBLIC Record; // operators for record select and update diff --git a/src/util/sort_inference.cpp b/src/util/sort_inference.cpp index 2a037a020..d700b70d9 100755..100644 --- a/src/util/sort_inference.cpp +++ b/src/util/sort_inference.cpp @@ -1,11 +1,11 @@ /********************* */ /*! \file sort_inference.cpp ** \verbatim - ** Original author: ajreynol - ** Major contributors: none + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** @@ -58,6 +58,14 @@ void SortInference::simplify( std::vector< Node >& assertions, bool doRewrite ){ 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( std::map< Node, int >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ + printSort( "sort-inference", it2->second ); + Trace("sort-inference") << std::endl; + } + Trace("sort-inference") << std::endl; + } } if( doRewrite ){ //simplify all assertions by introducing new symbols wherever necessary (NOTE: this is unsound for quantifiers) @@ -149,11 +157,11 @@ int SortInference::process( Node n, std::map< Node, Node >& var_bound ){ if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){ for( size_t i=0; i<n[0].getNumChildren(); i++ ){ //TODO: try applying sort inference to quantified variables - //d_var_types[n][ n[0][i] ] = sortCount; - //sortCount++; + d_var_types[n][ n[0][i] ] = sortCount; + sortCount++; //type of the quantified variable must be the same - d_var_types[n][ n[0][i] ] = getIdForType( n[0][i].getType() ); + //d_var_types[n][ n[0][i] ] = getIdForType( n[0][i].getType() ); var_bound[ n[0][i] ] = n; } } @@ -404,5 +412,17 @@ Node SortInference::simplify( Node n, std::map< Node, Node >& var_bound ){ } } +int SortInference::getSortId( Node n ) { + Node op = n.getKind()==kind::APPLY_UF ? n.getOperator() : n; + return getRepresentative( d_op_return_types[op] ); +} + +int SortInference::getSortId( Node f, Node v ) { + return getRepresentative( d_var_types[f][v] ); +} +void SortInference::setSkolemVar( Node f, Node v, Node sk ){ + d_op_return_types[sk] = getSortId( f, v ); } + +}/* CVC4 namespace */ diff --git a/src/util/sort_inference.h b/src/util/sort_inference.h index 1873688fa..0b1f96f85 100755..100644 --- a/src/util/sort_inference.h +++ b/src/util/sort_inference.h @@ -1,11 +1,11 @@ /********************* */ /*! \file sort_inference.h ** \verbatim - ** Original author: ajreynol - ** Major contributors: none + ** Original author: Andrew Reynolds <andrew.j.reynolds@gmail.com> + ** Major contributors: Morgan Deters <mdeters@cs.nyu.edu> ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** @@ -65,6 +65,10 @@ public: ~SortInference(){} void simplify( std::vector< Node >& assertions, bool doRewrite = false ); + int getSortId( Node n ); + int getSortId( Node f, Node v ); + //set that sk is the skolem variable of v for quantifier f + void setSkolemVar( Node f, Node v, Node sk ); }; } diff --git a/src/util/statistics_registry.h b/src/util/statistics_registry.h index 3bf990dbb..af9088663 100644 --- a/src/util/statistics_registry.h +++ b/src/util/statistics_registry.h @@ -23,6 +23,7 @@ #include "util/statistics.h" #include "util/exception.h" +#include "lib/clock_gettime.h" #include <sstream> #include <iomanip> @@ -612,12 +613,17 @@ public: };/* class StatisticsRegistry */ +}/* CVC4 namespace */ + /****************************************************************************/ /* Some utility functions for timespec */ /****************************************************************************/ +inline std::ostream& operator<<(std::ostream& os, const timespec& t); + /** Compute the sum of two timespecs. */ inline timespec& operator+=(timespec& a, const timespec& b) { + using namespace CVC4; // assumes a.tv_nsec and b.tv_nsec are in range const long nsec_per_sec = 1000000000L; // one thousand million CheckArgument(a.tv_nsec >= 0 && a.tv_nsec < nsec_per_sec, a); @@ -640,6 +646,7 @@ inline timespec& operator+=(timespec& a, const timespec& b) { /** Compute the difference of two timespecs. */ inline timespec& operator-=(timespec& a, const timespec& b) { + using namespace CVC4; // assumes a.tv_nsec and b.tv_nsec are in range const long nsec_per_sec = 1000000000L; // one thousand million CheckArgument(a.tv_nsec >= 0 && a.tv_nsec < nsec_per_sec, a); @@ -716,6 +723,8 @@ inline std::ostream& operator<<(std::ostream& os, const timespec& t) { << std::setfill('0') << std::setw(8) << std::right << t.tv_nsec; } +namespace CVC4 { + class CodeTimer; /** @@ -765,7 +774,6 @@ public: };/* class TimerStat */ - /** * Utility class to make it easier to call stop() at the end of a * code block. When constructed, it starts the timer. When @@ -788,7 +796,6 @@ public: } };/* class CodeTimer */ - /** * To use a statistic, you need to declare it, initialize it in your * constructor, register it in your constructor, and deregister it in diff --git a/src/util/tls.h.in b/src/util/tls.h.in index 17f1f1d6e..935586f77 100644 --- a/src/util/tls.h.in +++ b/src/util/tls.h.in @@ -1,5 +1,5 @@ /********************* */ -/*! \file tls.h +/*! \file tls.h.in ** \verbatim ** Original author: mdeters ** Major contributors: none |