diff options
author | PaulMeng <baolmeng@gmail.com> | 2016-04-20 14:43:18 -0500 |
---|---|---|
committer | PaulMeng <baolmeng@gmail.com> | 2016-04-20 14:43:18 -0500 |
commit | 904ffb6e73402bae537aa89e7fd8f0ab2e9d60e2 (patch) | |
tree | d96bb0c974bdea6170957d3e39d47a98f5c85ca0 /src/theory/quantifiers | |
parent | a0054e9cc78822416d745e955c30f69cbb2a3aa7 (diff) |
update from the master
Diffstat (limited to 'src/theory/quantifiers')
77 files changed, 5535 insertions, 2241 deletions
diff --git a/src/theory/quantifiers/alpha_equivalence.cpp b/src/theory/quantifiers/alpha_equivalence.cpp index b72f15a01..80066d690 100644 --- a/src/theory/quantifiers/alpha_equivalence.cpp +++ b/src/theory/quantifiers/alpha_equivalence.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file alpha_equivalence.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2015 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Alpha equivalence checking ** @@ -29,7 +29,7 @@ struct sortTypeOrder { } }; -bool AlphaEquivalenceNode::registerNode( AlphaEquivalenceNode* aen, QuantifiersEngine* qe, Node q, std::vector< Node >& tt, std::vector< int >& arg_index ) { +Node AlphaEquivalenceNode::registerNode( AlphaEquivalenceNode* aen, QuantifiersEngine* qe, Node q, std::vector< Node >& tt, std::vector< int >& arg_index ) { while( !tt.empty() ){ if( tt.size()==arg_index.size()+1 ){ Node t = tt.back(); @@ -49,21 +49,25 @@ bool AlphaEquivalenceNode::registerNode( AlphaEquivalenceNode* aen, QuantifiersE } } } + Node lem; Trace("aeq-debug") << std::endl; if( aen->d_quant.isNull() ){ aen->d_quant = q; - return true; }else{ - //lemma ( q <=> d_quant ) - Trace("quant-ae") << "Alpha equivalent : " << std::endl; - Trace("quant-ae") << " " << q << std::endl; - Trace("quant-ae") << " " << aen->d_quant << std::endl; - qe->getOutputChannel().lemma( q.iffNode( aen->d_quant ) ); - return false; + if( q.getNumChildren()==2 ){ + //lemma ( q <=> d_quant ) + Trace("quant-ae") << "Alpha equivalent : " << std::endl; + Trace("quant-ae") << " " << q << std::endl; + Trace("quant-ae") << " " << aen->d_quant << std::endl; + lem = q.iffNode( aen->d_quant ); + }else{ + //do not reduce annotated quantified formulas based on alpha equivalence + } } + return lem; } -bool AlphaEquivalenceTypeNode::registerNode( AlphaEquivalenceTypeNode* aetn, +Node AlphaEquivalenceTypeNode::registerNode( AlphaEquivalenceTypeNode* aetn, QuantifiersEngine* qe, Node q, Node t, std::vector< TypeNode >& typs, std::map< TypeNode, int >& typ_count, int index ){ while( index<(int)typs.size() ){ TypeNode curr = typs[index]; @@ -79,7 +83,7 @@ bool AlphaEquivalenceTypeNode::registerNode( AlphaEquivalenceTypeNode* aetn, return AlphaEquivalenceNode::registerNode( &(aetn->d_data), qe, q, tt, arg_index ); } -bool AlphaEquivalence::registerQuantifier( Node q ) { +Node AlphaEquivalence::reduceQuantifier( Node q ) { Assert( q.getKind()==FORALL ); Trace("aeq") << "Alpha equivalence : register " << q << std::endl; //construct canonical quantified formula @@ -99,7 +103,7 @@ bool AlphaEquivalence::registerQuantifier( Node q ) { sto.d_tdb = d_qe->getTermDatabase(); std::sort( typs.begin(), typs.end(), sto ); Trace("aeq-debug") << " "; - bool ret = AlphaEquivalenceTypeNode::registerNode( &d_ae_typ_trie, d_qe, q, t, typs, typ_count ); + Node ret = AlphaEquivalenceTypeNode::registerNode( &d_ae_typ_trie, d_qe, q, t, typs, typ_count ); Trace("aeq") << " ...result : " << ret << std::endl; return ret; } diff --git a/src/theory/quantifiers/alpha_equivalence.h b/src/theory/quantifiers/alpha_equivalence.h index 99517fd2a..8e7556eb6 100644 --- a/src/theory/quantifiers/alpha_equivalence.h +++ b/src/theory/quantifiers/alpha_equivalence.h @@ -1,13 +1,13 @@ /********************* */ /*! \file alpha_equivalence.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2015 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Alpha equivalence checking **/ @@ -28,14 +28,14 @@ class AlphaEquivalenceNode { public: std::map< Node, std::map< int, AlphaEquivalenceNode > > d_children; Node d_quant; - static bool registerNode( AlphaEquivalenceNode* aen, QuantifiersEngine* qe, Node q, std::vector< Node >& tt, std::vector< int >& arg_index ); + static Node registerNode( AlphaEquivalenceNode* aen, QuantifiersEngine* qe, Node q, std::vector< Node >& tt, std::vector< int >& arg_index ); }; class AlphaEquivalenceTypeNode { public: std::map< TypeNode, std::map< int, AlphaEquivalenceTypeNode > > d_children; AlphaEquivalenceNode d_data; - static bool registerNode( AlphaEquivalenceTypeNode* aetn, + static Node registerNode( AlphaEquivalenceTypeNode* aetn, QuantifiersEngine* qe, Node q, Node t, std::vector< TypeNode >& typs, std::map< TypeNode, int >& typ_count, int index = 0 ); }; @@ -47,8 +47,8 @@ private: public: AlphaEquivalence( QuantifiersEngine* qe ) : d_qe( qe ){} ~AlphaEquivalence(){} - - bool registerQuantifier( Node q ); + /** reduce quantifier, return value (if non-null) is lemma justifying why q ia reducible. */ + Node reduceQuantifier( Node q ); }; } diff --git a/src/theory/quantifiers/ambqi_builder.cpp b/src/theory/quantifiers/ambqi_builder.cpp index b18676cbc..5192da7de 100644 --- a/src/theory/quantifiers/ambqi_builder.cpp +++ b/src/theory/quantifiers/ambqi_builder.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file ambqi_builder.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Morgan Deters, Tim King, Andrew Reynolds ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Implementation of abstract MBQI builder **/ @@ -159,7 +159,7 @@ bool AbsDef::addInstantiations( FirstOrderModelAbs * m, QuantifiersEngine * qe, return true; }else{ if( depth==q[0].getNumChildren() ){ - if( qe->addInstantiation( q, terms ) ){ + if( qe->addInstantiation( q, terms, true ) ){ Trace("ambqi-inst-debug") << "-> Added instantiation." << std::endl; inst++; return true; @@ -190,7 +190,7 @@ bool AbsDef::addInstantiations( FirstOrderModelAbs * m, QuantifiersEngine * qe, success = true; } } - }while( !success && index<32 ); + }while( !qe->inConflict() && !success && index<32 ); //mark if we are incomplete osuccess = osuccess && success; } diff --git a/src/theory/quantifiers/ambqi_builder.h b/src/theory/quantifiers/ambqi_builder.h index b2c49c8a3..3669d38b7 100644 --- a/src/theory/quantifiers/ambqi_builder.h +++ b/src/theory/quantifiers/ambqi_builder.h @@ -1,13 +1,13 @@ /********************* */ /*! \file ambqi_builder.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Morgan Deters, Tim King, Clark Barrett ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Abstract MBQI model builder class **/ diff --git a/src/theory/quantifiers/anti_skolem.cpp b/src/theory/quantifiers/anti_skolem.cpp new file mode 100644 index 000000000..c8d18aced --- /dev/null +++ b/src/theory/quantifiers/anti_skolem.cpp @@ -0,0 +1,269 @@ +/********************* */ +/*! \file anti_skolem.cpp + ** \verbatim + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim + ** + ** \brief Implementation of anti-skolemization + ** ( forall x. P[ f( x ) ] ^ forall x. Q[ f( x ) ] ) => forall x. exists y. ( P[ y ] ^ Q[ y ] ) + **/ + +#include "theory/quantifiers/anti_skolem.h" +#include "theory/quantifiers/term_database.h" +#include "theory/quantifiers_engine.h" +#include "theory/quantifiers/first_order_model.h" +#include "options/quantifiers_options.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::quantifiers; + + +struct sortTypeOrder { + TermDb* d_tdb; + bool operator() (TypeNode i, TypeNode j) { + return d_tdb->getIdForType( i )<d_tdb->getIdForType( j ); + } +}; + +void QuantAntiSkolem::SkQuantTypeCache::add( std::vector< TypeNode >& typs, Node q, unsigned index ) { + if( index==typs.size() ){ + Assert( std::find( d_quants.begin(), d_quants.end(), q )==d_quants.end() ); + d_quants.push_back( q ); + }else{ + d_children[typs[index]].add( typs, q, index+1 ); + } +} + +void QuantAntiSkolem::SkQuantTypeCache::sendLemmas( QuantAntiSkolem * ask ) { + for( std::map< TypeNode, SkQuantTypeCache >::iterator it = d_children.begin(); it != d_children.end(); ++it ){ + it->second.sendLemmas( ask ); + } + if( !d_quants.empty() ){ + ask->sendAntiSkolemizeLemma( d_quants ); + } +} + +bool QuantAntiSkolem::CDSkQuantCache::add( context::Context* c, std::vector< Node >& quants, unsigned index ) { + if( index==quants.size() ){ + if( !d_valid.get() ){ + d_valid.set( true ); + return true; + }else{ + return false; + } + }else{ + Node n = quants[index]; + std::map< Node, CDSkQuantCache* >::iterator it = d_data.find( n ); + CDSkQuantCache* skc; + if( it==d_data.end() ){ + skc = new CDSkQuantCache( c ); + d_data[n] = skc; + }else{ + skc = it->second; + } + return skc->add( c, quants, index+1 ); + } +} + +QuantAntiSkolem::QuantAntiSkolem( QuantifiersEngine * qe ) : QuantifiersModule( qe ){ + d_sqc = new CDSkQuantCache( qe->getUserContext() ); +} + +/* Call during quantifier engine's check */ +void QuantAntiSkolem::check( Theory::Effort e, unsigned quant_e ) { + if( quant_e==QuantifiersEngine::QEFFORT_STANDARD ){ + d_sqtc.clear(); + for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ + Node q = d_quantEngine->getModel()->getAssertedQuantifier( i ); + if( d_quant_processed.find( q )==d_quant_processed.end() ){ + d_quant_processed[q] = true; + Trace("anti-sk") << "Process quantified formula : " << q << std::endl; + bool success = false; + if( d_quant_sip[q].init( q[1] ) ){ + Trace("anti-sk") << "- Partitioned to single invocation parts : " << std::endl; + d_quant_sip[q].debugPrint( "anti-sk" ); + //check if it is single invocation + if( d_quant_sip[q].isPurelySingleInvocation() ){ + //for now, only do purely single invocation + success = true; + } + }else{ + Trace("anti-sk") << "- Failed to initialize." << std::endl; + } + if( success ){ + //sort the argument variables + d_ask_types[q].insert( d_ask_types[q].end(), d_quant_sip[q].d_arg_types.begin(), d_quant_sip[q].d_arg_types.end() ); + std::map< TypeNode, std::vector< unsigned > > indices; + for( unsigned j=0; j<d_ask_types[q].size(); j++ ){ + indices[d_ask_types[q][j]].push_back( j ); + } + sortTypeOrder sto; + sto.d_tdb = d_quantEngine->getTermDatabase(); + std::sort( d_ask_types[q].begin(), d_ask_types[q].end(), sto ); + //increment j on inner loop + for( unsigned j=0; j<d_ask_types[q].size(); ){ + TypeNode curr = d_ask_types[q][j]; + for( unsigned k=0; k<indices[curr].size(); k++ ){ + Assert( d_ask_types[q][j]==curr ); + d_ask_types_index[q].push_back( indices[curr][k] ); + j++; + } + } + Assert( d_ask_types_index[q].size()==d_ask_types[q].size() ); + }else{ + d_quant_sip.erase( q ); + } + } + //now, activate the quantified formula + std::map< Node, std::vector< TypeNode > >::iterator it = d_ask_types.find( q ); + if( it!=d_ask_types.end() ){ + d_sqtc.add( it->second, q ); + } + } + Trace("anti-sk-debug") << "Process lemmas..." << std::endl; + //send out lemmas for each anti-skolemizable group of quantified formulas + d_sqtc.sendLemmas( this ); + Trace("anti-sk-debug") << "...Finished process lemmas" << std::endl; + } +} + +bool QuantAntiSkolem::sendAntiSkolemizeLemma( std::vector< Node >& quants, bool pconnected ) { + Assert( !quants.empty() ); + std::sort( quants.begin(), quants.end() ); + if( d_sqc->add( d_quantEngine->getUserContext(), quants ) ){ + //partition into connected components + if( pconnected && quants.size()>1 ){ + Trace("anti-sk-debug") << "Partition into connected components..." << std::endl; + int eqc_count = 0; + std::map< Node, int > func_to_eqc; + std::map< int, std::vector< Node > > eqc_to_func; + std::map< int, std::vector< Node > > eqc_to_quant; + for( unsigned i=0; i<quants.size(); i++ ){ + Node q = quants[i]; + std::vector< int > eqcs; + for( std::map< Node, bool >::iterator it = d_quant_sip[q].d_funcs.begin(); it != d_quant_sip[q].d_funcs.end(); ++it ){ + Node f = it->first; + std::map< Node, int >::iterator itf = func_to_eqc.find( f ); + if( itf == func_to_eqc.end() ){ + if( eqcs.empty() ){ + func_to_eqc[f] = eqc_count; + eqc_to_func[eqc_count].push_back( f ); + eqc_count++; + }else{ + func_to_eqc[f] = eqcs[0]; + eqc_to_func[eqcs[0]].push_back( f ); + } + } + if( std::find( eqcs.begin(), eqcs.end(), func_to_eqc[f] )==eqcs.end() ){ + eqcs.push_back( func_to_eqc[f] ); + } + } + Assert( !eqcs.empty() ); + //merge equivalence classes + int id = eqcs[0]; + eqc_to_quant[id].push_back( q ); + for( unsigned j=1; j<eqcs.size(); j++ ){ + int id2 = eqcs[j]; + std::map< int, std::vector< Node > >::iterator itef = eqc_to_func.find( id2 ); + if( itef!=eqc_to_func.end() ){ + for( unsigned k=0; k<itef->second.size(); k++ ){ + func_to_eqc[itef->second[k]] = id; + eqc_to_func[id].push_back( itef->second[k] ); + } + eqc_to_func.erase( id2 ); + } + itef = eqc_to_quant.find( id2 ); + if( itef!=eqc_to_quant.end() ){ + eqc_to_quant[id].insert( eqc_to_quant[id].end(), itef->second.begin(), itef->second.end() ); + eqc_to_quant.erase( id2 ); + } + } + } + if( eqc_to_quant.size()>1 ){ + bool addedLemma = false; + for( std::map< int, std::vector< Node > >::iterator it = eqc_to_quant.begin(); it != eqc_to_quant.end(); ++it ){ + Assert( it->second.size()<quants.size() ); + bool ret = sendAntiSkolemizeLemma( it->second, false ); + addedLemma = addedLemma || ret; + } + return addedLemma; + } + } + + Trace("anti-sk") << "Anti-skolemize group : " << std::endl; + for( unsigned i=0; i<quants.size(); i++ ){ + Trace("anti-sk") << " " << quants[i] << std::endl; + } + + std::vector< Node > outer_vars; + std::vector< Node > inner_vars; + Node q = quants[0]; + for( unsigned i=0; i<d_ask_types[q].size(); i++ ){ + Node v = NodeManager::currentNM()->mkBoundVar( d_ask_types[q][i] ); + Trace("anti-sk-debug") << "Outer var " << i << " : " << v << std::endl; + outer_vars.push_back( v ); + } + + std::map< Node, Node > func_to_var; + std::vector< Node > conj; + for( unsigned i=0; i<quants.size(); i++ ){ + Node q = quants[i]; + Trace("anti-sk-debug") << "Process " << q << std::endl; + std::vector< Node > subs_lhs; + std::vector< Node > subs_rhs; + //get outer variable substitution + Assert( d_ask_types_index[q].size()==d_ask_types[q].size() ); + for( unsigned j=0; j<d_ask_types_index[q].size(); j++ ){ + Trace("anti-sk-debug") << " o_subs : " << d_quant_sip[q].d_si_vars[d_ask_types_index[q][j]] << " -> " << outer_vars[j] << std::endl; + subs_lhs.push_back( d_quant_sip[q].d_si_vars[d_ask_types_index[q][j]] ); + subs_rhs.push_back( outer_vars[j] ); + } + //get function substitution + for( std::map< Node, bool >::iterator it = d_quant_sip[q].d_funcs.begin(); it != d_quant_sip[q].d_funcs.end(); ++it ){ + Node f = it->first; + Node fv = d_quant_sip[q].d_func_fo_var[it->first]; + if( func_to_var.find( f )==func_to_var.end() ){ + Node v = NodeManager::currentNM()->mkBoundVar( fv.getType() ); + Trace("anti-sk-debug") << "Inner var for " << f << " : " << v << std::endl; + inner_vars.push_back( v ); + func_to_var[f] = v; + } + subs_lhs.push_back( fv ); + subs_rhs.push_back( func_to_var[f] ); + Trace("anti-sk-debug") << " i_subs : " << fv << " -> " << func_to_var[f] << std::endl; + } + Node c = d_quant_sip[q].getSingleInvocation(); + if( !subs_lhs.empty() ){ + c = c.substitute( subs_lhs.begin(), subs_lhs.end(), subs_rhs.begin(), subs_rhs.end() ); + } + conj.push_back( c ); + } + Node body = conj.size()==1 ? conj[0] : NodeManager::currentNM()->mkNode( kind::AND, conj ); + if( !inner_vars.empty() ){ + Node bvl = NodeManager::currentNM()->mkNode( kind::BOUND_VAR_LIST, inner_vars ); + body = NodeManager::currentNM()->mkNode( kind::EXISTS, bvl, body ); + } + if( !outer_vars.empty() ){ + Node bvl = NodeManager::currentNM()->mkNode( kind::BOUND_VAR_LIST, outer_vars ); + body = NodeManager::currentNM()->mkNode( kind::FORALL, bvl, body ); + } + Trace("anti-sk") << "Produced : " << body << std::endl; + quants.push_back( body.negate() ); + Node lem = NodeManager::currentNM()->mkNode( kind::AND, quants ).negate(); + Trace("anti-sk-lemma") << "Anti-skolemize lemma : " << lem << std::endl; + quants.pop_back(); + return d_quantEngine->addLemma( lem ); + }else{ + return false; + } +} + diff --git a/src/theory/quantifiers/anti_skolem.h b/src/theory/quantifiers/anti_skolem.h new file mode 100644 index 000000000..721371159 --- /dev/null +++ b/src/theory/quantifiers/anti_skolem.h @@ -0,0 +1,75 @@ +/********************* */ +/*! \file anti_skolem.h + ** \verbatim + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim + ** + ** \brief dynamic quantifiers splitting + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY__QUANT_ANTI_SKOLEM_H +#define __CVC4__THEORY__QUANT_ANTI_SKOLEM_H + +#include "theory/quantifiers_engine.h" +#include "context/cdo.h" +#include "theory/quantifiers/ce_guided_single_inv.h" + +namespace CVC4 { +namespace theory { +namespace quantifiers { + +class QuantAntiSkolem : public QuantifiersModule { + typedef context::CDHashSet<Node, NodeHashFunction> NodeSet; +private: + std::map< Node, bool > d_quant_processed; + std::map< Node, SingleInvocationPartition > d_quant_sip; + std::map< Node, std::vector< TypeNode > > d_ask_types; + std::map< Node, std::vector< unsigned > > d_ask_types_index; + + class SkQuantTypeCache { + public: + std::map< TypeNode, SkQuantTypeCache > d_children; + std::vector< Node > d_quants; + void add( std::vector< TypeNode >& typs, Node q, unsigned index = 0 ); + void clear() { + d_children.clear(); + d_quants.clear(); + } + void sendLemmas( QuantAntiSkolem * ask ); + }; + SkQuantTypeCache d_sqtc; + + class CDSkQuantCache { + public: + CDSkQuantCache( context::Context* c ) : d_valid( c, false ){} + std::map< Node, CDSkQuantCache* > d_data; + context::CDO< bool > d_valid; + bool add( context::Context* c, std::vector< Node >& quants, unsigned index = 0 ); + }; + CDSkQuantCache * d_sqc; +public: + bool sendAntiSkolemizeLemma( std::vector< Node >& quants, bool pconnected = true ); +public: + QuantAntiSkolem( QuantifiersEngine * qe ); + + /* Call during quantifier engine's check */ + void check( Theory::Effort e, unsigned quant_e ); + /* Called for new quantifiers */ + void registerQuantifier( Node q ) {} + void assertNode( Node n ) {} + /** Identify this module (for debugging, dynamic configuration, etc..) */ + std::string identify() const { return "QuantAntiSkolem"; } +}; + +} +} +} + +#endif diff --git a/src/theory/quantifiers/bounded_integers.cpp b/src/theory/quantifiers/bounded_integers.cpp index ceab8394f..d32ef59a1 100644 --- a/src/theory/quantifiers/bounded_integers.cpp +++ b/src/theory/quantifiers/bounded_integers.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file bounded_integers.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): Kshitij Bansal + ** Top contributors (to current version): + ** Morgan Deters, Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Bounded integers module ** diff --git a/src/theory/quantifiers/bounded_integers.h b/src/theory/quantifiers/bounded_integers.h index dd241b15e..7d15097bd 100644 --- a/src/theory/quantifiers/bounded_integers.h +++ b/src/theory/quantifiers/bounded_integers.h @@ -1,13 +1,13 @@ /********************* */ /*! \file bounded_integers.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Morgan Deters, Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** [[ Add lengthier description here ]] ** \todo document this file diff --git a/src/theory/quantifiers/candidate_generator.cpp b/src/theory/quantifiers/candidate_generator.cpp index 0cdb22be4..43f5ee2fd 100644 --- a/src/theory/quantifiers/candidate_generator.cpp +++ b/src/theory/quantifiers/candidate_generator.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file candidate_generator.cpp ** \verbatim - ** Original author: Morgan Deters - ** Major contributors: Andrew Reynolds - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Implementation of theory uf candidate generator class **/ @@ -58,10 +58,13 @@ Node CandidateGeneratorQueue::getNextCandidate(){ } } -CandidateGeneratorQE::CandidateGeneratorQE( QuantifiersEngine* qe, Node op ) : - d_op( op ), d_qe( qe ), d_term_iter( -1 ){ +CandidateGeneratorQE::CandidateGeneratorQE( QuantifiersEngine* qe, Node pat ) : + d_qe( qe ), d_term_iter( -1 ){ + d_op = qe->getTermDatabase()->getMatchOperator( pat ); Assert( !d_op.isNull() ); + d_op_arity = pat.getNumChildren(); } + void CandidateGeneratorQE::resetInstantiationRound(){ d_term_iter_limit = d_qe->getTermDatabase()->getNumGroundTerms( d_op ); } @@ -71,26 +74,38 @@ void CandidateGeneratorQE::reset( Node eqc ){ if( eqc.isNull() ){ d_mode = cand_term_db; }else{ - //create an equivalence class iterator in eq class eqc - //d_qe->getEqualityQuery()->getEquivalenceClass( eqc, d_eqc ); - - eq::EqualityEngine* ee = d_qe->getEqualityQuery()->getEngine(); - if( ee->hasTerm( eqc ) ){ - Node rep = ee->getRepresentative( eqc ); - d_eqc_iter = eq::EqClassIterator( rep, ee ); - d_mode = cand_term_eqc; + if( isExcludedEqc( eqc ) ){ + d_mode = cand_term_none; }else{ - d_n = eqc; - d_mode = cand_term_ident; + eq::EqualityEngine* ee = d_qe->getEqualityQuery()->getEngine(); + if( ee->hasTerm( eqc ) ){ + quantifiers::TermArgTrie * tat = d_qe->getTermDatabase()->getTermArgTrie( eqc, d_op ); + if( tat ){ +#if 1 + //create an equivalence class iterator in eq class eqc + Node rep = ee->getRepresentative( eqc ); + d_eqc_iter = eq::EqClassIterator( rep, ee ); + d_mode = cand_term_eqc; +#else + d_tindex.push_back( tat ); + d_tindex_iter.push_back( tat->d_data.begin() ); + d_mode = cand_term_tindex; +#endif + }else{ + d_mode = cand_term_none; + } + }else{ + //the only match is this term itself + d_n = eqc; + d_mode = cand_term_ident; + } } - //a should be in its equivalence class - //Assert( std::find( eqc.begin(), eqc.end(), a )!=eqc.end() ); } } bool CandidateGeneratorQE::isLegalOpCandidate( Node n ) { if( n.hasOperator() ){ if( isLegalCandidate( n ) ){ - return d_qe->getTermDatabase()->getOperator( n )==d_op; + return d_qe->getTermDatabase()->getMatchOperator( n )==d_op; } } return false; @@ -98,25 +113,67 @@ bool CandidateGeneratorQE::isLegalOpCandidate( Node n ) { Node CandidateGeneratorQE::getNextCandidate(){ if( d_mode==cand_term_db ){ + Debug("cand-gen-qe") << "...get next candidate in tbd" << std::endl; //get next candidate term in the uf term database while( d_term_iter<d_term_iter_limit ){ Node n = d_qe->getTermDatabase()->getGroundTerm( d_op, d_term_iter ); d_term_iter++; if( isLegalCandidate( n ) ){ if( d_qe->getTermDatabase()->hasTermCurrent( n ) ){ - return n; + if( d_exclude_eqc.empty() ){ + return n; + }else{ + Node r = d_qe->getEqualityQuery()->getRepresentative( n ); + if( d_exclude_eqc.find( r )==d_exclude_eqc.end() ){ + Debug("cand-gen-qe") << "...returning " << n << std::endl; + return n; + } + } } } } }else if( d_mode==cand_term_eqc ){ + Debug("cand-gen-qe") << "...get next candidate in eqc" << std::endl; while( !d_eqc_iter.isFinished() ){ Node n = *d_eqc_iter; ++d_eqc_iter; if( isLegalOpCandidate( n ) ){ + Debug("cand-gen-qe") << "...returning " << n << std::endl; return n; } } + }else if( d_mode==cand_term_tindex ){ + Debug("cand-gen-qe") << "...get next candidate in tindex " << d_op << " " << d_op_arity << std::endl; + //increment the term index iterator + if( !d_tindex.empty() ){ + //populate the vector + while( d_tindex_iter.size()<=d_op_arity ){ + Assert( !d_tindex_iter.empty() ); + Assert( !d_tindex_iter.back()->second.d_data.empty() ); + d_tindex.push_back( &(d_tindex_iter.back()->second) ); + d_tindex_iter.push_back( d_tindex_iter.back()->second.d_data.begin() ); + } + //get the current node + Assert( d_tindex_iter.back()->second.hasNodeData() ); + Node n = d_tindex_iter.back()->second.getNodeData(); + Debug("cand-gen-qe") << "...returning " << n << std::endl; + Assert( !n.isNull() ); + Assert( isLegalOpCandidate( n ) ); + //increment + bool success = false; + do{ + ++d_tindex_iter.back(); + if( d_tindex_iter.back()==d_tindex.back()->d_data.end() ){ + d_tindex.pop_back(); + d_tindex_iter.pop_back(); + }else{ + success = true; + } + }while( !success && !d_tindex.empty() ); + return n; + } }else if( d_mode==cand_term_ident ){ + Debug("cand-gen-qe") << "...get next candidate identity" << std::endl; if( !d_n.isNull() ){ Node n = d_n; d_n = Node::null(); @@ -130,21 +187,37 @@ Node CandidateGeneratorQE::getNextCandidate(){ CandidateGeneratorQELitEq::CandidateGeneratorQELitEq( QuantifiersEngine* qe, Node mpat ) : d_match_pattern( mpat ), d_qe( qe ){ - + Assert( mpat.getKind()==EQUAL ); + for( unsigned i=0; i<2; i++ ){ + if( !quantifiers::TermDb::hasInstConstAttr(mpat[i]) ){ + d_match_gterm = mpat[i]; + } + } } void CandidateGeneratorQELitEq::resetInstantiationRound(){ } void CandidateGeneratorQELitEq::reset( Node eqc ){ - d_eq = eq::EqClassesIterator( d_qe->getEqualityQuery()->getEngine() ); + if( d_match_gterm.isNull() ){ + d_eq = eq::EqClassesIterator( d_qe->getEqualityQuery()->getEngine() ); + }else{ + d_do_mgt = true; + } } Node CandidateGeneratorQELitEq::getNextCandidate(){ - while( !d_eq.isFinished() ){ - Node n = (*d_eq); - ++d_eq; - if( n.getType().isComparableTo( d_match_pattern[0].getType() ) ){ - //an equivalence class with the same type as the pattern, return reflexive equality - return NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), n, n ); + if( d_match_gterm.isNull() ){ + while( !d_eq.isFinished() ){ + Node n = (*d_eq); + ++d_eq; + if( n.getType().isComparableTo( d_match_pattern[0].getType() ) ){ + //an equivalence class with the same type as the pattern, return reflexive equality + return NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), n, n ); + } + } + }else{ + if( d_do_mgt ){ + d_do_mgt = false; + return NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), d_match_gterm, d_match_gterm ); } } return Node::null(); @@ -225,7 +298,6 @@ Node CandidateGeneratorQEAll::getNextCandidate() { } } if( d_firstTime ){ - Assert( d_qe->getTermDatabase()->d_type_map[d_match_pattern_type].empty() ); //must return something d_firstTime = false; return d_qe->getTermDatabase()->getModelBasisTerm( d_match_pattern_type ); diff --git a/src/theory/quantifiers/candidate_generator.h b/src/theory/quantifiers/candidate_generator.h index fb120dd08..18ef6a086 100644 --- a/src/theory/quantifiers/candidate_generator.h +++ b/src/theory/quantifiers/candidate_generator.h @@ -1,13 +1,13 @@ /********************* */ /*! \file candidate_generator.h ** \verbatim - ** Original author: Morgan Deters - ** Major contributors: Andrew Reynolds - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Morgan Deters, Andrew Reynolds, Clark Barrett ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Theory uf candidate generator **/ @@ -23,6 +23,10 @@ namespace CVC4 { namespace theory { +namespace quantifiers { + class TermArgTrie; +} + class QuantifiersEngine; namespace inst { @@ -79,6 +83,9 @@ private: //instantiator pointer QuantifiersEngine* d_qe; //the equality class iterator + unsigned d_op_arity; + std::vector< quantifiers::TermArgTrie* > d_tindex; + std::vector< std::map< TNode, quantifiers::TermArgTrie >::iterator > d_tindex_iter; eq::EqClassIterator d_eqc_iter; //std::vector< Node > d_eqc; int d_term_iter; @@ -88,17 +95,22 @@ private: cand_term_db, cand_term_ident, cand_term_eqc, + cand_term_tindex, + cand_term_none, }; short d_mode; bool isLegalOpCandidate( Node n ); Node d_n; + std::map< Node, bool > d_exclude_eqc; public: - CandidateGeneratorQE( QuantifiersEngine* qe, Node op ); + CandidateGeneratorQE( QuantifiersEngine* qe, Node pat ); ~CandidateGeneratorQE() throw() {} void resetInstantiationRound(); void reset( Node eqc ); Node getNextCandidate(); + void excludeEqc( Node r ) { d_exclude_eqc[r] = true; } + bool isExcludedEqc( Node r ) { return d_exclude_eqc.find( r )!=d_exclude_eqc.end(); } }; class CandidateGeneratorQELitEq : public CandidateGenerator @@ -108,6 +120,8 @@ private: eq::EqClassesIterator d_eq; //equality you are trying to match equalities for Node d_match_pattern; + Node d_match_gterm; + bool d_do_mgt; //einstantiator pointer QuantifiersEngine* d_qe; public: diff --git a/src/theory/quantifiers/ce_guided_instantiation.cpp b/src/theory/quantifiers/ce_guided_instantiation.cpp index 345a5eaef..d9059a3e6 100644 --- a/src/theory/quantifiers/ce_guided_instantiation.cpp +++ b/src/theory/quantifiers/ce_guided_instantiation.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file ce_guided_instantiation.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King, Morgan Deters ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief counterexample guided instantiation class ** @@ -22,19 +22,25 @@ #include "theory/quantifiers/term_database.h" #include "theory/theory_engine.h" -using namespace CVC4; using namespace CVC4::kind; -using namespace CVC4::theory; -using namespace CVC4::theory::quantifiers; using namespace std; namespace CVC4 { +namespace theory { +namespace quantifiers { -CegConjecture::CegConjecture( QuantifiersEngine * qe, context::Context* c ) : d_qe( qe ), d_curr_lit( c, 0 ){ + +CegConjecture::CegConjecture( QuantifiersEngine * qe, context::Context* c ) + : d_qe( qe ), d_curr_lit( c, 0 ) +{ d_refine_count = 0; d_ceg_si = new CegConjectureSingleInv( qe, this ); } +CegConjecture::~CegConjecture() { + delete d_ceg_si; +} + void CegConjecture::assign( Node q ) { Assert( d_quant.isNull() ); Assert( q.getKind()==FORALL ); @@ -149,7 +155,7 @@ CegqiFairMode CegConjecture::getCegqiFairMode() { return isSingleInvocation() ? CEGQI_FAIR_NONE : options::ceGuidedInstFair(); } -bool CegConjecture::isSingleInvocation() { +bool CegConjecture::isSingleInvocation() const { return d_ceg_si->isSingleInvocation(); } @@ -219,11 +225,13 @@ bool CegInstantiation::needsCheck( Theory::Effort e ) { } unsigned CegInstantiation::needsModel( Theory::Effort e ) { - return d_conj->d_ceg_si->isSingleInvocation() ? QuantifiersEngine::QEFFORT_STANDARD : QuantifiersEngine::QEFFORT_MODEL; + return d_conj->getCegConjectureSingleInv()->isSingleInvocation() + ? QuantifiersEngine::QEFFORT_STANDARD : QuantifiersEngine::QEFFORT_MODEL; } void CegInstantiation::check( Theory::Effort e, unsigned quant_e ) { - unsigned echeck = d_conj->d_ceg_si->isSingleInvocation() ? QuantifiersEngine::QEFFORT_STANDARD : QuantifiersEngine::QEFFORT_MODEL; + unsigned echeck = d_conj->getCegConjectureSingleInv()->isSingleInvocation() ? + QuantifiersEngine::QEFFORT_STANDARD : QuantifiersEngine::QEFFORT_MODEL; if( quant_e==echeck ){ Trace("cegqi-engine") << "---Counterexample Guided Instantiation Engine---" << std::endl; Trace("cegqi-engine-debug") << std::endl; @@ -294,12 +302,13 @@ Node CegInstantiation::getNextDecisionRequest() { if( d_conj->isAssigned() ){ d_conj->initializeGuard( d_quantEngine ); std::vector< Node > req_dec; - if( !d_conj->d_ceg_si->d_full_guard.isNull() ){ - req_dec.push_back( d_conj->d_ceg_si->d_full_guard ); + const CegConjectureSingleInv* ceg_si = d_conj->getCegConjectureSingleInv(); + if( ! ceg_si->d_full_guard.isNull() ){ + req_dec.push_back( ceg_si->d_full_guard ); } //must decide ns guard before s guard - if( !d_conj->d_ceg_si->d_ns_guard.isNull() ){ - req_dec.push_back( d_conj->d_ceg_si->d_ns_guard ); + if( !ceg_si->d_ns_guard.isNull() ){ + req_dec.push_back( ceg_si->d_ns_guard ); } req_dec.push_back( d_conj->getGuard() ); for( unsigned i=0; i<req_dec.size(); i++ ){ @@ -348,9 +357,9 @@ void CegInstantiation::checkCegConjecture( CegConjecture * conj ) { if( conj->d_ce_sk.empty() ){ Trace("cegqi-engine") << " *** Check candidate phase..." << std::endl; if( conj->d_syntax_guided ){ - if( conj->d_ceg_si ){ + if( conj->getCegConjectureSingleInv() != NULL ){ std::vector< Node > lems; - if( conj->d_ceg_si->check( lems ) ){ + if( conj->doCegConjectureCheck( lems ) ){ if( !lems.empty() ){ d_last_inst_si = true; for( unsigned j=0; j<lems.size(); j++ ){ @@ -423,7 +432,7 @@ void CegInstantiation::checkCegConjecture( CegConjecture * conj ) { Assert( aq==q ); std::vector< Node > model_terms; if( getModelValues( conj, conj->d_candidates, model_terms ) ){ - d_quantEngine->addInstantiation( q, model_terms, false ); + d_quantEngine->addInstantiation( q, model_terms ); } } }else{ @@ -600,39 +609,53 @@ void CegInstantiation::printSynthSolution( std::ostream& out ) { Node sol; int status; if( d_last_inst_si ){ - Assert( d_conj->d_ceg_si ); - sol = d_conj->d_ceg_si->getSolution( i, tn, status ); + Assert( d_conj->getCegConjectureSingleInv() != NULL ); + sol = d_conj->getSingleInvocationSolution( i, tn, status ); sol = sol.getKind()==LAMBDA ? sol[1] : sol; }else{ if( !d_conj->d_candidate_inst[i].empty() ){ sol = d_conj->d_candidate_inst[i].back(); - //check if this was based on a template, if so, we must do reconstruction + // Check if this was based on a template, if so, we must do + // Reconstruction if( d_conj->d_assert_quant!=d_conj->d_quant ){ Node sygus_sol = sol; - Trace("cegqi-inv") << "Sygus version of solution is : " << sol << ", type : " << sol.getType() << std::endl; + Trace("cegqi-inv") << "Sygus version of solution is : " << sol + << ", type : " << sol.getType() << std::endl; std::vector< Node > subs; Expr svl = dt.getSygusVarList(); for( unsigned j=0; j<svl.getNumChildren(); j++ ){ subs.push_back( Node::fromExpr( svl[j] ) ); } if( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_PRE ){ - if( d_conj->d_ceg_si->d_trans_pre.find( prog )!=d_conj->d_ceg_si->d_trans_pre.end() ){ - Assert( d_conj->d_ceg_si->d_prog_templ_vars[prog].size()==subs.size() ); - Node pre = d_conj->d_ceg_si->d_trans_pre[prog]; - pre = pre.substitute( d_conj->d_ceg_si->d_prog_templ_vars[prog].begin(), d_conj->d_ceg_si->d_prog_templ_vars[prog].end(), + const CegConjectureSingleInv* ceg_si = + d_conj->getCegConjectureSingleInv(); + if(ceg_si->d_trans_pre.find( prog ) != ceg_si->d_trans_pre.end()){ + std::vector<Node>& templ_vars = d_conj->getProgTempVars(prog); + Assert(templ_vars.size() == subs.size()); + Node pre = ceg_si->getTransPre(prog); + pre = pre.substitute( templ_vars.begin(), templ_vars.end(), subs.begin(), subs.end() ); - sol = getTermDatabase()->getTermDatabaseSygus()->sygusToBuiltin( sol, sol.getType() ); - Trace("cegqi-inv") << "Builtin version of solution is : " << sol << ", type : " << sol.getType() << std::endl; + TermDbSygus* sygusDb = getTermDatabase()->getTermDatabaseSygus(); + sol = sygusDb->sygusToBuiltin( sol, sol.getType() ); + Trace("cegqi-inv") << "Builtin version of solution is : " + << sol << ", type : " << sol.getType() + << std::endl; sol = NodeManager::currentNM()->mkNode( OR, sol, pre ); } - }else if( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_POST ){ - if( d_conj->d_ceg_si->d_trans_post.find( prog )!=d_conj->d_ceg_si->d_trans_post.end() ){ - Assert( d_conj->d_ceg_si->d_prog_templ_vars[prog].size()==subs.size() ); - Node post = d_conj->d_ceg_si->d_trans_post[prog]; - post = post.substitute( d_conj->d_ceg_si->d_prog_templ_vars[prog].begin(), d_conj->d_ceg_si->d_prog_templ_vars[prog].end(), + }else if(options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_POST){ + const CegConjectureSingleInv* ceg_si = + d_conj->getCegConjectureSingleInv(); + if(ceg_si->d_trans_post.find(prog) != ceg_si->d_trans_post.end()){ + std::vector<Node>& templ_vars = d_conj->getProgTempVars(prog); + Assert( templ_vars.size()==subs.size() ); + Node post = ceg_si->getTransPost(prog); + post = post.substitute( templ_vars.begin(), templ_vars.end(), subs.begin(), subs.end() ); - sol = getTermDatabase()->getTermDatabaseSygus()->sygusToBuiltin( sol, sol.getType() ); - Trace("cegqi-inv") << "Builtin version of solution is : " << sol << ", type : " << sol.getType() << std::endl; + TermDbSygus* sygusDb = getTermDatabase()->getTermDatabaseSygus(); + sol = sygusDb->sygusToBuiltin( sol, sol.getType() ); + Trace("cegqi-inv") << "Builtin version of solution is : " + << sol << ", type : " << sol.getType() + << std::endl; sol = NodeManager::currentNM()->mkNode( AND, sol, post ); } } @@ -643,7 +666,7 @@ void CegInstantiation::printSynthSolution( std::ostream& out ) { Trace("cegqi-inv-debug") << "With template : " << sol << std::endl; sol = Rewriter::rewrite( sol ); Trace("cegqi-inv-debug") << "Simplified : " << sol << std::endl; - sol = d_conj->d_ceg_si->reconstructToSyntax( sol, tn, status ); + sol = d_conj->reconstructToSyntaxSingleInvocation(sol, tn, status); sol = sol.getKind()==LAMBDA ? sol[1] : sol; } }else{ @@ -712,5 +735,6 @@ CegInstantiation::Statistics::~Statistics(){ smtStatisticsRegistry()->unregisterStat(&d_cegqi_si_lemmas); } - -} +}/* namespace CVC4::theory::quantifiers */ +}/* namespace CVC4::theory */ +}/* namespace CVC4 */ diff --git a/src/theory/quantifiers/ce_guided_instantiation.h b/src/theory/quantifiers/ce_guided_instantiation.h index 8274561ca..57dc31850 100644 --- a/src/theory/quantifiers/ce_guided_instantiation.h +++ b/src/theory/quantifiers/ce_guided_instantiation.h @@ -1,13 +1,13 @@ /********************* */ /*! \file ce_guided_instantiation.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief counterexample guided instantiation class **/ @@ -33,6 +33,8 @@ private: QuantifiersEngine * d_qe; public: CegConjecture( QuantifiersEngine * qe, context::Context* c ); + ~CegConjecture(); + /** quantified formula asserted */ Node d_assert_quant; /** quantified formula (after processing) */ @@ -56,12 +58,36 @@ public: unsigned d_refine_count; /** current extential quantifeirs whose couterexamples we must refine */ std::vector< std::vector< Node > > d_ce_sk; + + const CegConjectureSingleInv* getCegConjectureSingleInv() const { + return d_ceg_si; + } + + bool doCegConjectureCheck(std::vector< Node >& lems) { + return d_ceg_si->check(lems); + } + + Node getSingleInvocationSolution(unsigned sol_index, TypeNode stn, + int& reconstructed, bool rconsSygus=true){ + return d_ceg_si->getSolution(sol_index, stn, reconstructed, rconsSygus); + } + + Node reconstructToSyntaxSingleInvocation( + Node s, TypeNode stn, int& reconstructed, bool rconsSygus = true ) { + return d_ceg_si->reconstructToSyntax(s, stn, reconstructed, rconsSygus); + } + + std::vector<Node>& getProgTempVars(Node prog) { + return d_ceg_si->d_prog_templ_vars[prog]; + } + + private: /** single invocation utility */ CegConjectureSingleInv * d_ceg_si; public: //non-syntax guided (deprecated) /** guard */ bool d_syntax_guided; - Node d_nsg_guard; + Node d_nsg_guard; public: //for fairness /** the cardinality literals */ std::map< int, Node > d_lits; @@ -76,7 +102,7 @@ public: //for fairness /** fairness */ CegqiFairMode getCegqiFairMode(); /** is single invocation */ - bool isSingleInvocation(); + bool isSingleInvocation() const; /** is single invocation */ bool isFullySingleInvocation(); /** needs check */ @@ -151,10 +177,10 @@ public: ~Statistics(); };/* class CegInstantiation::Statistics */ Statistics d_statistics; -}; +}; /* class CegInstantiation */ -} -} -} +} /* namespace CVC4::theory::quantifiers */ +} /* namespace CVC4::theory */ +} /* namespace CVC4 */ #endif diff --git a/src/theory/quantifiers/ce_guided_single_inv.cpp b/src/theory/quantifiers/ce_guided_single_inv.cpp index 7ef23077f..33856d226 100644 --- a/src/theory/quantifiers/ce_guided_single_inv.cpp +++ b/src/theory/quantifiers/ce_guided_single_inv.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file ce_guided_single_inv.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief utility for processing single invocation synthesis conjectures ** @@ -33,8 +33,8 @@ using namespace std; namespace CVC4 { -bool CegqiOutputSingleInv::addInstantiation( std::vector< Node >& subs ) { - return d_out->addInstantiation( subs ); +bool CegqiOutputSingleInv::doAddInstantiation( std::vector< Node >& subs ) { + return d_out->doAddInstantiation( subs ); } bool CegqiOutputSingleInv::isEligibleForInstantiation( Node n ) { @@ -55,12 +55,12 @@ CegConjectureSingleInv::CegConjectureSingleInv( QuantifiersEngine * qe, CegConje } d_cosi = new CegqiOutputSingleInv( this ); // third and fourth arguments set to (false,false) until we have solution reconstruction for delta and infinity - d_cinst = new CegInstantiator( d_qe, d_cosi, false, false ); + d_cinst = new CegInstantiator( d_qe, d_cosi, false, false ); d_sol = new CegConjectureSingleInvSol( qe ); d_sip = new SingleInvocationPartition; - + if( options::cegqiSingleInvPartial() ){ d_ei = new CegEntailmentInfer( qe, d_sip ); }else{ @@ -104,7 +104,7 @@ void CegConjectureSingleInv::getInitialSingleInvLemma( std::vector< Node >& lems if( d_cinst ){ delete d_cinst; } - d_cinst = new CegInstantiator( d_qe, d_cosi, false, false ); + d_cinst = new CegInstantiator( d_qe, d_cosi, false, false ); d_cinst->registerCounterexampleLemma( lems, d_single_inv_sk ); } } @@ -149,8 +149,7 @@ void CegConjectureSingleInv::initialize( Node q ) { bool singleInvocation = true; if( type_valid==0 ){ //process the single invocation-ness of the property - d_sip->init( types ); - d_sip->process( qq ); + d_sip->init( types, qq ); Trace("cegqi-si") << "- Partitioned to single invocation parts : " << std::endl; d_sip->debugPrint( "cegqi-si" ); //map from program to bound variables @@ -481,7 +480,7 @@ void CegConjectureSingleInv::initializeNextSiConjecture() { if( d_single_inv.isNull() ){ if( d_ei->getEntailedConjecture( d_single_inv, d_single_inv_exp ) ){ Trace("cegqi-nsi") << "NSI : got : " << d_single_inv << std::endl; - Trace("cegqi-nsi") << "NSI : exp : " << d_single_inv_exp << std::endl; + Trace("cegqi-nsi") << "NSI : exp : " << d_single_inv_exp << std::endl; }else{ Trace("cegqi-nsi") << "NSI : failed to construct next conjecture." << std::endl; Notice() << "Incomplete due to --cegqi-si-partial." << std::endl; @@ -492,7 +491,7 @@ void CegConjectureSingleInv::initializeNextSiConjecture() { Trace("cegqi-nsi") << "NSI : have : " << d_single_inv << std::endl; Assert( d_single_inv_exp.isNull() ); } - + d_si_guard = Node::null(); d_ns_guard = Rewriter::rewrite( NodeManager::currentNM()->mkSkolem( "GS", NodeManager::currentNM()->booleanType() ) ); d_ns_guard = d_qe->getValuation().ensureLiteral( d_ns_guard ); @@ -509,7 +508,7 @@ void CegConjectureSingleInv::initializeNextSiConjecture() { Trace("cegqi-nsi") << "NSI : conjecture is " << d_single_inv << std::endl; } -bool CegConjectureSingleInv::addInstantiation( std::vector< Node >& subs ){ +bool CegConjectureSingleInv::doAddInstantiation( std::vector< Node >& subs ){ std::stringstream siss; if( Trace.isOn("cegqi-si-inst-debug") || Trace.isOn("cegqi-engine") ){ siss << " * single invocation: " << std::endl; @@ -839,7 +838,42 @@ void CegConjectureSingleInv::preregisterConjecture( Node q ) { d_orig_conjecture = q; } -void SingleInvocationPartition::init( std::vector< TypeNode >& typs ){ +bool SingleInvocationPartition::init( Node n ) { + //first, get types of arguments for functions + std::vector< TypeNode > typs; + std::map< Node, bool > visited; + if( inferArgTypes( n, typs, visited ) ){ + return init( typs, n ); + }else{ + Trace("si-prt") << "Could not infer argument types." << std::endl; + return false; + } +} + +bool SingleInvocationPartition::inferArgTypes( Node n, std::vector< TypeNode >& typs, std::map< Node, bool >& visited ) { + if( visited.find( n )==visited.end() ){ + visited[n] = true; + if( n.getKind()!=FORALL ){ + //if( TermDb::hasBoundVarAttr( n ) ){ + if( n.getKind()==d_checkKind ){ + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + typs.push_back( n[i].getType() ); + } + return true; + }else{ + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + if( inferArgTypes( n[i], typs, visited ) ){ + return true; + } + } + } + //} + } + } + return false; +} + +bool SingleInvocationPartition::init( std::vector< TypeNode >& typs, Node n ){ Assert( d_arg_types.empty() ); Assert( d_si_vars.empty() ); d_arg_types.insert( d_arg_types.end(), typs.begin(), typs.end() ); @@ -849,6 +883,9 @@ void SingleInvocationPartition::init( std::vector< TypeNode >& typs ){ Node si_v = NodeManager::currentNM()->mkBoundVar( ss.str(), d_arg_types[j] ); d_si_vars.push_back( si_v ); } + Trace("si-prt") << "Process the formula..." << std::endl; + process( n ); + return true; } @@ -874,6 +911,7 @@ void SingleInvocationPartition::process( Node n ) { std::vector< Node > terms; std::vector< Node > subs; bool singleInvocation = true; + bool ngroundSingleInvocation = false; if( processConjunct( cr, visited, args, terms, subs ) ){ for( unsigned j=0; j<terms.size(); j++ ){ si_terms.push_back( subs[j] ); @@ -909,6 +947,7 @@ void SingleInvocationPartition::process( Node n ) { TermDb::getBoundVars( cr, bvs ); if( bvs.size()>d_si_vars.size() ){ Trace("si-prt") << "...not ground single invocation." << std::endl; + ngroundSingleInvocation = true; singleInvocation = false; }else{ Trace("si-prt") << "...ground single invocation : success." << std::endl; @@ -949,6 +988,9 @@ void SingleInvocationPartition::process( Node n ) { d_conjuncts[0].push_back( cr ); }else{ d_conjuncts[1].push_back( cr ); + if( ngroundSingleInvocation ){ + d_conjuncts[3].push_back( cr ); + } } } }else{ @@ -984,43 +1026,45 @@ bool SingleInvocationPartition::processConjunct( Node n, std::map< Node, bool >& return true; }else{ bool ret = true; - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - if( !processConjunct( n[i], visited, args, terms, subs ) ){ - ret = false; + //if( TermDb::hasBoundVarAttr( n ) ){ + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + if( !processConjunct( n[i], visited, args, terms, subs ) ){ + ret = false; + } } - } - if( ret ){ - if( n.getKind()==APPLY_UF ){ - if( std::find( terms.begin(), terms.end(), n )==terms.end() ){ - Node f = n.getOperator(); - //check if it matches the type requirement - if( isAntiSkolemizableType( f ) ){ - if( args.empty() ){ - //record arguments - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - args.push_back( n[i] ); - } - }else{ - //arguments must be the same as those already recorded - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - if( args[i]!=n[i] ){ - Trace("si-prt-debug") << "...bad invocation : " << n << " at arg " << i << "." << std::endl; - ret = false; - break; + if( ret ){ + if( n.getKind()==d_checkKind ){ + if( std::find( terms.begin(), terms.end(), n )==terms.end() ){ + Node f = n.getOperator(); + //check if it matches the type requirement + if( isAntiSkolemizableType( f ) ){ + if( args.empty() ){ + //record arguments + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + args.push_back( n[i] ); + } + }else{ + //arguments must be the same as those already recorded + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + if( args[i]!=n[i] ){ + Trace("si-prt-debug") << "...bad invocation : " << n << " at arg " << i << "." << std::endl; + ret = false; + break; + } } } + if( ret ){ + terms.push_back( n ); + subs.push_back( d_func_inv[f] ); + } + }else{ + Trace("si-prt-debug") << "... " << f << " is a bad operator." << std::endl; + ret = false; } - if( ret ){ - terms.push_back( n ); - subs.push_back( d_func_inv[f] ); - } - }else{ - Trace("si-prt-debug") << "... " << f << " is a bad operator." << std::endl; - ret = false; } } } - } + //} visited[n] = ret; return ret; } @@ -1037,6 +1081,7 @@ bool SingleInvocationPartition::isAntiSkolemizableType( Node f ) { ret = true; std::vector< Node > children; children.push_back( f ); + //TODO: permutations of arguments for( unsigned i=0; i<d_arg_types.size(); i++ ){ children.push_back( d_si_vars[i] ); if( tn[i]!=d_arg_types[i] ){ @@ -1045,7 +1090,7 @@ bool SingleInvocationPartition::isAntiSkolemizableType( Node f ) { } } if( ret ){ - Node t = NodeManager::currentNM()->mkNode( APPLY_UF, children ); + Node t = NodeManager::currentNM()->mkNode( d_checkKind, children ); d_func_inv[f] = t; d_inv_to_func[t] = f; std::stringstream ss; @@ -1079,7 +1124,7 @@ Node SingleInvocationPartition::getSpecificationInst( Node n, std::map< Node, No childChanged = childChanged || ( nn!=n[i] ); } Node ret; - if( n.getKind()==APPLY_UF ){ + if( n.getKind()==d_checkKind ){ std::map< Node, Node >::iterator itl = lam.find( n.getOperator() ); if( itl!=lam.end() ){ Assert( itl->second[0].getNumChildren()==children.size() ); @@ -1176,8 +1221,8 @@ void SingleInvocationPartition::debugPrint( const char * c ) { Trace(c) << "not incorporated." << std::endl; } } - for( unsigned i=0; i<3; i++ ){ - Trace(c) << ( i==0 ? "Single invocation" : ( i==1 ? "Non-single invocation" : "All" ) ); + for( unsigned i=0; i<4; i++ ){ + Trace(c) << ( i==0 ? "Single invocation" : ( i==1 ? "Non-single invocation" : ( i==2 ? "All" : "Non-ground single invocation" ) ) ); Trace(c) << " conjuncts: " << std::endl; for( unsigned j=0; j<d_conjuncts[i].size(); j++ ){ Trace(c) << " " << (j+1) << " : " << d_conjuncts[i][j] << std::endl; diff --git a/src/theory/quantifiers/ce_guided_single_inv.h b/src/theory/quantifiers/ce_guided_single_inv.h index c414a51bd..4d2f9a0e5 100644 --- a/src/theory/quantifiers/ce_guided_single_inv.h +++ b/src/theory/quantifiers/ce_guided_single_inv.h @@ -1,13 +1,13 @@ /********************* */ /*! \file ce_guided_single_inv.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King, Clark Barrett ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief utility for processing single invocation synthesis conjectures **/ @@ -37,7 +37,7 @@ public: CegqiOutputSingleInv( CegConjectureSingleInv * out ) : d_out( out ){} ~CegqiOutputSingleInv() {} CegConjectureSingleInv * d_out; - bool addInstantiation( std::vector< Node >& subs ); + bool doAddInstantiation( std::vector< Node >& subs ); bool isEligibleForInstantiation( Node n ); bool addLemma( Node lem ); }; @@ -58,13 +58,21 @@ private: CegqiOutputSingleInv * d_cosi; CegInstantiator * d_cinst; //for recognizing templates for invariant synthesis - Node substituteInvariantTemplates( Node n, std::map< Node, Node >& prog_templ, std::map< Node, std::vector< Node > >& prog_templ_vars ); + Node substituteInvariantTemplates( + Node n, std::map< Node, Node >& prog_templ, + std::map< Node, std::vector< Node > >& prog_templ_vars ); // partially single invocation - Node removeDeepEmbedding( Node n, std::vector< Node >& progs, std::vector< TypeNode >& types, int& type_valid, std::map< Node, Node >& visited ); + Node removeDeepEmbedding( Node n, std::vector< Node >& progs, + std::vector< TypeNode >& types, int& type_valid, + std::map< Node, Node >& visited ); Node addDeepEmbedding( Node n, std::map< Node, Node >& visited ); //presolve - void collectPresolveEqTerms( Node n, std::map< Node, std::vector< Node > >& teq ); - void getPresolveEqConjuncts( std::vector< Node >& vars, std::vector< Node >& terms, std::map< Node, std::vector< Node > >& teq, Node n, std::vector< Node >& conj ); + void collectPresolveEqTerms( Node n, + std::map< Node, std::vector< Node > >& teq ); + void getPresolveEqConjuncts( std::vector< Node >& vars, + std::vector< Node >& terms, + std::map< Node, std::vector< Node > >& teq, + Node n, std::vector< Node >& conj ); //constructing solution Node constructSolution( std::vector< unsigned >& indices, unsigned i, unsigned index ); Node postProcessSolution( Node n ); @@ -94,7 +102,7 @@ public: private: std::vector< Node > d_curr_lemmas; //add instantiation - bool addInstantiation( std::vector< Node >& subs ); + bool doAddInstantiation( std::vector< Node >& subs ); //is eligible for instantiation bool isEligibleForInstantiation( Node n ); // add lemma @@ -113,7 +121,7 @@ public: Node d_full_inv; Node d_full_guard; //explanation for current single invocation conjecture - Node d_single_inv_exp; + Node d_single_inv_exp; // transition relation version per program std::map< Node, Node > d_trans_pre; std::map< Node, Node > d_trans_post; @@ -132,19 +140,33 @@ public: //get solution Node getSolution( unsigned sol_index, TypeNode stn, int& reconstructed, bool rconsSygus = true ); //reconstruct to syntax - Node reconstructToSyntax( Node s, TypeNode stn, int& reconstructed, bool rconsSygus = true ); + Node reconstructToSyntax( Node s, TypeNode stn, int& reconstructed, + bool rconsSygus = true ); // has ites bool hasITEs() { return d_has_ites; } // is single invocation - bool isSingleInvocation() { return !d_single_inv.isNull(); } + bool isSingleInvocation() const { return !d_single_inv.isNull(); } // is single invocation - bool isFullySingleInvocation() { return !d_single_inv.isNull() && d_nsingle_inv.isNull(); } + bool isFullySingleInvocation() const { + return !d_single_inv.isNull() && d_nsingle_inv.isNull(); + } //needs check bool needsCheck(); /** preregister conjecture */ void preregisterConjecture( Node q ); //initialize next candidate si conjecture (if not fully single invocation) - void initializeNextSiConjecture(); + void initializeNextSiConjecture(); + + Node getTransPre(Node prog) const { + std::map<Node, Node>::const_iterator location = d_trans_pre.find(prog); + return location->second; + } + + Node getTransPost(Node prog) const { + std::map<Node, Node>::const_iterator location = d_trans_post.find(prog); + return location->second; + } + }; // partitions any formulas given to it into single invocation/non-single invocation @@ -153,18 +175,23 @@ public: class SingleInvocationPartition { private: + //options + Kind d_checkKind; + bool inferArgTypes( Node n, std::vector< TypeNode >& typs, std::map< Node, bool >& visited ); + void process( Node n ); bool collectConjuncts( Node n, bool pol, std::vector< Node >& conj ); bool processConjunct( Node n, std::map< Node, bool >& visited, std::vector< Node >& args, std::vector< Node >& terms, std::vector< Node >& subs ); Node getSpecificationInst( Node n, std::map< Node, Node >& lam, std::map< Node, Node >& visited ); void extractInvariant2( Node n, Node& func, int& pol, std::vector< Node >& disjuncts, bool hasPol, std::map< Node, bool >& visited ); public: - void init( std::vector< TypeNode >& typs ); - //inputs - void process( Node n ); - std::vector< TypeNode > d_arg_types; + SingleInvocationPartition( Kind checkKind = kind::APPLY_UF ) : d_checkKind( checkKind ){} + ~SingleInvocationPartition(){} + bool init( Node n ); + bool init( std::vector< TypeNode >& typs, Node n ); //outputs (everything is with bound var) + std::vector< TypeNode > d_arg_types; std::map< Node, bool > d_funcs; std::map< Node, Node > d_func_inv; std::map< Node, Node > d_inv_to_func; @@ -173,8 +200,8 @@ public: std::vector< Node > d_func_vars; //the first-order variables corresponding to all functions std::vector< Node > d_si_vars; //the arguments that we based the anti-skolemization on std::vector< Node > d_all_vars; //every free variable of conjuncts[2] - // si, nsi, all - std::vector< Node > d_conjuncts[3]; + // si, nsi, all, non-ground si + std::vector< Node > d_conjuncts[4]; bool isAntiSkolemizableType( Node f ); @@ -187,12 +214,14 @@ public: void extractInvariant( Node n, Node& func, int& pol, std::vector< Node >& disjuncts ); + bool isPurelySingleInvocation() { return d_conjuncts[1].empty(); } + bool isNonGroundSingleInvocation() { return d_conjuncts[3].size()==d_conjuncts[1].size(); } + void debugPrint( const char * c ); }; - -} -} -} +}/* namespace CVC4::theory::quantifiers */ +}/* namespace CVC4::theory */ +}/* namespace CVC4 */ #endif diff --git a/src/theory/quantifiers/ce_guided_single_inv_ei.cpp b/src/theory/quantifiers/ce_guided_single_inv_ei.cpp index f45285851..6394fca3d 100644 --- a/src/theory/quantifiers/ce_guided_single_inv_ei.cpp +++ b/src/theory/quantifiers/ce_guided_single_inv_ei.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file ce_guided_single_inv_ei.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief utility for inferring entailments for cegqi ** diff --git a/src/theory/quantifiers/ce_guided_single_inv_ei.h b/src/theory/quantifiers/ce_guided_single_inv_ei.h index 0645c406a..42e0b0820 100644 --- a/src/theory/quantifiers/ce_guided_single_inv_ei.h +++ b/src/theory/quantifiers/ce_guided_single_inv_ei.h @@ -1,13 +1,13 @@ /********************* */ /*! \file ce_guided_single_inv_ei.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief utility for inferring entailments for cegqi **/ diff --git a/src/theory/quantifiers/ce_guided_single_inv_sol.cpp b/src/theory/quantifiers/ce_guided_single_inv_sol.cpp index 6ba5bed02..240c2ed12 100644 --- a/src/theory/quantifiers/ce_guided_single_inv_sol.cpp +++ b/src/theory/quantifiers/ce_guided_single_inv_sol.cpp @@ -1,13 +1,13 @@ /********************* */ -/*! \file ce_guided_single_inv.cpp +/*! \file ce_guided_single_inv_sol.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief utility for processing single invocation synthesis conjectures ** diff --git a/src/theory/quantifiers/ce_guided_single_inv_sol.h b/src/theory/quantifiers/ce_guided_single_inv_sol.h index adcc7bf85..cb6f6bc41 100644 --- a/src/theory/quantifiers/ce_guided_single_inv_sol.h +++ b/src/theory/quantifiers/ce_guided_single_inv_sol.h @@ -1,13 +1,13 @@ /********************* */ /*! \file ce_guided_single_inv_sol.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief utility for reconstructing solutions for single invocation synthesis conjectures **/ diff --git a/src/theory/quantifiers/ceg_instantiator.cpp b/src/theory/quantifiers/ceg_instantiator.cpp index b02c9a740..da488ea98 100644 --- a/src/theory/quantifiers/ceg_instantiator.cpp +++ b/src/theory/quantifiers/ceg_instantiator.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file ceg_instantiator.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Implementation of counterexample-guided quantifier instantiation **/ @@ -65,9 +65,9 @@ void CegInstantiator::computeProgVars( Node n ){ } } -bool CegInstantiator::addInstantiation( SolvedForm& sf, SolvedForm& ssf, std::vector< Node >& vars, - std::vector< int >& btyp, Node theta, unsigned i, unsigned effort, - std::map< Node, Node >& cons, std::vector< Node >& curr_var ){ +bool CegInstantiator::doAddInstantiation( SolvedForm& sf, SolvedForm& ssf, std::vector< Node >& vars, + std::vector< int >& btyp, Node theta, unsigned i, unsigned effort, + std::map< Node, Node >& cons, std::vector< Node >& curr_var ){ if( i==d_vars.size() ){ //solved for all variables, now construct instantiation if( !sf.d_has_coeff.empty() ){ @@ -75,12 +75,12 @@ bool CegInstantiator::addInstantiation( SolvedForm& sf, SolvedForm& ssf, std::ve //use symbolic solved forms SolvedForm csf; csf.copy( ssf ); - return addInstantiationCoeff( csf, vars, btyp, 0, cons ); + return doAddInstantiationCoeff( csf, vars, btyp, 0, cons ); }else{ - return addInstantiationCoeff( sf, vars, btyp, 0, cons ); + return doAddInstantiationCoeff( sf, vars, btyp, 0, cons ); } }else{ - return addInstantiation( sf.d_subs, vars, cons ); + return doAddInstantiation( sf.d_subs, vars, cons ); } }else{ std::map< Node, std::map< Node, bool > > subs_proc; @@ -94,16 +94,17 @@ bool CegInstantiator::addInstantiation( SolvedForm& sf, SolvedForm& ssf, std::ve is_cv = true; } TypeNode pvtn = pv.getType(); - Trace("cbqi-inst-debug") << "[Find instantiation for " << pv << "]" << std::endl; + TypeNode pvtnb = pvtn.getBaseType(); + Node pvr = pv; + if( d_qe->getMasterEqualityEngine()->hasTerm( pv ) ){ + pvr = d_qe->getMasterEqualityEngine()->getRepresentative( pv ); + } + Trace("cbqi-inst-debug") << "[Find instantiation for " << pv << "], rep=" << pvr << std::endl; Node pv_value; if( options::cbqiModel() ){ pv_value = getModelValue( pv ); Trace("cbqi-bound2") << "...M( " << pv << " ) = " << pv_value << std::endl; } - Node pvr = pv; - if( d_qe->getMasterEqualityEngine()->hasTerm( pv ) ){ - pvr = d_qe->getMasterEqualityEngine()->getRepresentative( pv ); - } //if in effort=2, we must choose at least one model value if( (i+1)<d_vars.size() || effort!=2 ){ @@ -138,53 +139,89 @@ bool CegInstantiator::addInstantiation( SolvedForm& sf, SolvedForm& ssf, std::ve if( proc ){ //try the substitution subs_proc[ns][pv_coeff] = true; - if( addInstantiationInc( ns, pv, pv_coeff, 0, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ + if( doAddInstantiationInc( ns, pv, pv_coeff, 0, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ return true; } } } } } + if( pvtn.isDatatype() ){ + Trace("cbqi-inst-debug") << "[2] try based on constructors in equivalence class." << std::endl; + //[2] look in equivalence class for a constructor + for( unsigned k=0; k<it_eqc->second.size(); k++ ){ + Node n = it_eqc->second[k]; + if( n.getKind()==APPLY_CONSTRUCTOR ){ + Trace("cbqi-inst-debug") << "... " << i << "...try based on constructor term " << n << std::endl; + cons[pv] = n.getOperator(); + const Datatype& dt = ((DatatypeType)(pvtn).toType()).getDatatype(); + unsigned cindex = Datatype::indexOf( n.getOperator().toExpr() ); + if( is_cv ){ + curr_var.pop_back(); + } + //now must solve for selectors applied to pv + for( unsigned j=0; j<dt[cindex].getNumArgs(); j++ ){ + curr_var.push_back( NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[cindex][j].getSelector() ), pv ) ); + } + if( doAddInstantiation( sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ + return true; + }else{ + //cleanup + cons.erase( pv ); + Assert( curr_var.size()>=dt[cindex].getNumArgs() ); + for( unsigned j=0; j<dt[cindex].getNumArgs(); j++ ){ + curr_var.pop_back(); + } + if( is_cv ){ + curr_var.push_back( pv ); + } + break; + } + } + } + } }else{ Trace("cbqi-inst-debug2") << "...eqc not found." << std::endl; } - //[2] : we can solve an equality for pv - if( pvtn.isInteger() || pvtn.isReal() ){ - ///iterate over equivalence classes to find cases where we can solve for the variable - TypeNode pvtnb = pvtn.getBaseType(); - Trace("cbqi-inst-debug") << "[2] try based on solving arithmetic equivalence classes." << std::endl; - for( unsigned k=0; k<d_curr_type_eqc[pvtnb].size(); k++ ){ - Node r = d_curr_type_eqc[pvtnb][k]; - std::map< Node, std::vector< Node > >::iterator it_reqc = d_curr_eqc.find( r ); - std::vector< Node > lhs; - std::vector< bool > lhs_v; - std::vector< Node > lhs_coeff; - Assert( it_reqc!=d_curr_eqc.end() ); - for( unsigned kk=0; kk<it_reqc->second.size(); kk++ ){ - Node n = it_reqc->second[kk]; - Trace("cbqi-inst-debug2") << "...look at term " << n << std::endl; - //compute the variables in n - computeProgVars( n ); - //must be an eligible term - if( d_inelig.find( n )==d_inelig.end() ){ - Node ns; - Node pv_coeff; - if( !d_prog_var[n].empty() ){ - ns = applySubstitution( pvtn, n, sf, vars, pv_coeff ); - if( !ns.isNull() ){ - computeProgVars( ns ); - } - }else{ - ns = n; - } + //[3] : we can solve an equality for pv + ///iterate over equivalence classes to find cases where we can solve for the variable + Trace("cbqi-inst-debug") << "[3] try based on solving equalities." << std::endl; + for( unsigned k=0; k<d_curr_type_eqc[pvtnb].size(); k++ ){ + Node r = d_curr_type_eqc[pvtnb][k]; + std::map< Node, std::vector< Node > >::iterator it_reqc = d_curr_eqc.find( r ); + std::vector< Node > lhs; + std::vector< bool > lhs_v; + std::vector< Node > lhs_coeff; + Assert( it_reqc!=d_curr_eqc.end() ); + for( unsigned kk=0; kk<it_reqc->second.size(); kk++ ){ + Node n = it_reqc->second[kk]; + Trace("cbqi-inst-debug2") << "...look at term " << n << std::endl; + //compute the variables in n + computeProgVars( n ); + //must be an eligible term + if( d_inelig.find( n )==d_inelig.end() ){ + Node ns; + Node pv_coeff; + if( !d_prog_var[n].empty() ){ + ns = applySubstitution( pvtn, n, sf, vars, pv_coeff ); if( !ns.isNull() ){ - bool hasVar = d_prog_var[ns].find( pv )!=d_prog_var[ns].end(); - Trace("cbqi-inst-debug2") << "... " << ns << " has var " << pv << " : " << hasVar << std::endl; - for( unsigned j=0; j<lhs.size(); j++ ){ - //if this term or the another has pv in it, try to solve for it - if( hasVar || lhs_v[j] ){ - Trace("cbqi-inst-debug") << "... " << i << "...try based on equality " << lhs[j] << " = " << ns << std::endl; + computeProgVars( ns ); + } + }else{ + ns = n; + } + if( !ns.isNull() ){ + bool hasVar = d_prog_var[ns].find( pv )!=d_prog_var[ns].end(); + Trace("cbqi-inst-debug2") << "... " << ns << " has var " << pv << " : " << hasVar << std::endl; + for( unsigned j=0; j<lhs.size(); j++ ){ + //if this term or the another has pv in it, try to solve for it + if( hasVar || lhs_v[j] ){ + Trace("cbqi-inst-debug") << "... " << i << "...try based on equality " << lhs[j] << " = " << ns << std::endl; + Node val; + Node veq_c; + bool success = false; + if( pvtnb.isReal() ){ Node eq_lhs = lhs[j]; Node eq_rhs = ns; //make the same coefficient @@ -204,17 +241,10 @@ bool CegInstantiator::addInstantiation( SolvedForm& sf, SolvedForm& ssf, std::ve eq = Rewriter::rewrite( eq ); Node vts_coeff_inf; Node vts_coeff_delta; - Node val; - Node veq_c; //isolate pv in the equality - int ires = isolate( pv, eq, veq_c, val, vts_coeff_inf, vts_coeff_delta ); + int ires = solve_arith( pv, eq, veq_c, val, vts_coeff_inf, vts_coeff_delta ); if( ires!=0 ){ - if( subs_proc[val].find( veq_c )==subs_proc[val].end() ){ - subs_proc[val][veq_c] = true; - if( addInstantiationInc( val, pv, veq_c, 0, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ - return true; - } - } + success = true; } /* //cannot contain infinity? @@ -240,67 +270,43 @@ bool CegInstantiator::addInstantiation( SolvedForm& sf, SolvedForm& ssf, std::ve Node val = veq[1]; if( subs_proc[val].find( veq_c )==subs_proc[val].end() ){ subs_proc[val][veq_c] = true; - if( addInstantiationInc( val, pv, veq_c, 0, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ + if( doAddInstantiationInc( val, pv, veq_c, 0, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ return true; } } } } */ + }else if( pvtnb.isDatatype() ){ + val = solve_dt( pv, lhs[j], ns, lhs[j], ns ); + if( !val.isNull() ){ + success = true; + } + } + if( success ){ + if( subs_proc[val].find( veq_c )==subs_proc[val].end() ){ + subs_proc[val][veq_c] = true; + if( doAddInstantiationInc( val, pv, veq_c, 0, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ + return true; + } + } } } - lhs.push_back( ns ); - lhs_v.push_back( hasVar ); - lhs_coeff.push_back( pv_coeff ); - }else{ - Trace("cbqi-inst-debug2") << "... term " << n << " is ineligible after substitution." << std::endl; } + lhs.push_back( ns ); + lhs_v.push_back( hasVar ); + lhs_coeff.push_back( pv_coeff ); }else{ - Trace("cbqi-inst-debug2") << "... term " << n << " is ineligible." << std::endl; - } - } - } - }else if( pvtn.isDatatype() ){ - Trace("cbqi-inst-debug") << "[2] try based on constructors in equivalence class." << std::endl; - //look in equivalence class for a constructor - if( it_eqc!=d_curr_eqc.end() ){ - for( unsigned k=0; k<it_eqc->second.size(); k++ ){ - Node n = it_eqc->second[k]; - if( n.getKind()==APPLY_CONSTRUCTOR ){ - Trace("cbqi-inst-debug") << "... " << i << "...try based on constructor term " << n << std::endl; - cons[pv] = n.getOperator(); - const Datatype& dt = ((DatatypeType)(pvtn).toType()).getDatatype(); - unsigned cindex = Datatype::indexOf( n.getOperator().toExpr() ); - if( is_cv ){ - curr_var.pop_back(); - } - //now must solve for selectors applied to pv - for( unsigned j=0; j<dt[cindex].getNumArgs(); j++ ){ - curr_var.push_back( NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[cindex][j].getSelector() ), pv ) ); - } - if( addInstantiation( sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ - return true; - }else{ - //cleanup - cons.erase( pv ); - Assert( curr_var.size()>=dt[cindex].getNumArgs() ); - for( unsigned j=0; j<dt[cindex].getNumArgs(); j++ ){ - curr_var.pop_back(); - } - if( is_cv ){ - curr_var.push_back( pv ); - } - break; - } + Trace("cbqi-inst-debug2") << "... term " << n << " is ineligible after substitution." << std::endl; } + }else{ + Trace("cbqi-inst-debug2") << "... term " << n << " is ineligible." << std::endl; } - }else{ - Trace("cbqi-inst-debug2") << "... " << i << " does not have an eqc." << std::endl; } } - //[3] directly look at assertions - Trace("cbqi-inst-debug") << "[3] try based on assertions." << std::endl; + //[4] directly look at assertions + Trace("cbqi-inst-debug") << "[4] try based on assertions." << std::endl; d_vts_sym[0] = d_qe->getTermDatabase()->getVtsInfinity( pvtn, false, false ); d_vts_sym[1] = d_qe->getTermDatabase()->getVtsDelta( false, false ); std::vector< Node > mbp_bounds[2]; @@ -360,7 +366,7 @@ bool CegInstantiator::addInstantiation( SolvedForm& sf, SolvedForm& ssf, std::ve Node val; Node veq_c; //isolate pv in the inequality - int ires = isolate( pv, satom, veq_c, val, vts_coeff_inf, vts_coeff_delta ); + int ires = solve_arith( pv, satom, veq_c, val, vts_coeff_inf, vts_coeff_delta ); if( ires!=0 ){ //disequalities are either strict upper or lower bounds unsigned rmax = ( atom.getKind()==GEQ && options::cbqiModel() ) ? 1 : 2; @@ -449,7 +455,7 @@ bool CegInstantiator::addInstantiation( SolvedForm& sf, SolvedForm& ssf, std::ve //try this bound if( subs_proc[uval].find( veq_c )==subs_proc[uval].end() ){ subs_proc[uval][veq_c] = true; - if( addInstantiationInc( uval, pv, veq_c, uires>0 ? 1 : -1, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ + if( doAddInstantiationInc( uval, pv, veq_c, uires>0 ? 1 : -1, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ return true; } } @@ -486,7 +492,7 @@ bool CegInstantiator::addInstantiation( SolvedForm& sf, SolvedForm& ssf, std::ve val = NodeManager::currentNM()->mkNode( UMINUS, val ); val = Rewriter::rewrite( val ); } - if( addInstantiationInc( val, pv, Node::null(), 0, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ + if( doAddInstantiationInc( val, pv, Node::null(), 0, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ return true; } } @@ -582,7 +588,7 @@ bool CegInstantiator::addInstantiation( SolvedForm& sf, SolvedForm& ssf, std::ve if( !val.isNull() ){ if( subs_proc[val].find( mbp_coeff[rr][best] )==subs_proc[val].end() ){ subs_proc[val][mbp_coeff[rr][best]] = true; - if( addInstantiationInc( val, pv, mbp_coeff[rr][best], rr==0 ? 1 : -1, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ + if( doAddInstantiationInc( val, pv, mbp_coeff[rr][best], rr==0 ? 1 : -1, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ return true; } } @@ -599,7 +605,7 @@ bool CegInstantiator::addInstantiation( SolvedForm& sf, SolvedForm& ssf, std::ve if( !val.isNull() ){ if( subs_proc[val].find( c )==subs_proc[val].end() ){ subs_proc[val][c] = true; - if( addInstantiationInc( val, pv, c, 0, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ + if( doAddInstantiationInc( val, pv, c, 0, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ return true; } } @@ -643,7 +649,7 @@ bool CegInstantiator::addInstantiation( SolvedForm& sf, SolvedForm& ssf, std::ve if( !val.isNull() ){ if( subs_proc[val].find( Node::null() )==subs_proc[val].end() ){ subs_proc[val][Node::null()] = true; - if( addInstantiationInc( val, pv, Node::null(), 0, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ + if( doAddInstantiationInc( val, pv, Node::null(), 0, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ return true; } } @@ -664,7 +670,7 @@ bool CegInstantiator::addInstantiation( SolvedForm& sf, SolvedForm& ssf, std::ve if( !val.isNull() ){ if( subs_proc[val].find( mbp_coeff[rr][j] )==subs_proc[val].end() ){ subs_proc[val][mbp_coeff[rr][j]] = true; - if( addInstantiationInc( val, pv, mbp_coeff[rr][j], rr==0 ? 1 : -1, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ + if( doAddInstantiationInc( val, pv, mbp_coeff[rr][j], rr==0 ? 1 : -1, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ return true; } } @@ -677,18 +683,18 @@ bool CegInstantiator::addInstantiation( SolvedForm& sf, SolvedForm& ssf, std::ve } } - //[4] resort to using value in model + //[5] resort to using value in model // do so if we are in effort=1, or if the variable is boolean, or if we are solving for a subfield of a datatype if( ( effort>0 || pvtn.isBoolean() || !curr_var.empty() ) && d_qe->getTermDatabase()->isClosedEnumerableType( pvtn ) ){ Node mv = getModelValue( pv ); Node pv_coeff_m; - Trace("cbqi-inst-debug") << "[4] " << i << "...try model value " << mv << std::endl; + Trace("cbqi-inst-debug") << "[5] " << i << "...try model value " << mv << std::endl; int new_effort = pvtn.isBoolean() ? effort : 1; #ifdef MBP_STRICT_ASSERTIONS //we only resort to values in the case of booleans Assert( ( pvtn.isInteger() ? !options::cbqiUseInfInt() : !options::cbqiUseInfReal() ) || pvtn.isBoolean() ); #endif - if( addInstantiationInc( mv, pv, pv_coeff_m, 0, sf, ssf, vars, btyp, theta, i, new_effort, cons, curr_var ) ){ + if( doAddInstantiationInc( mv, pv, pv_coeff_m, 0, sf, ssf, vars, btyp, theta, i, new_effort, cons, curr_var ) ){ return true; } } @@ -698,9 +704,9 @@ bool CegInstantiator::addInstantiation( SolvedForm& sf, SolvedForm& ssf, std::ve } -bool CegInstantiator::addInstantiationInc( Node n, Node pv, Node pv_coeff, int bt, SolvedForm& sf, SolvedForm& ssf, std::vector< Node >& vars, - std::vector< int >& btyp, Node theta, unsigned i, unsigned effort, - std::map< Node, Node >& cons, std::vector< Node >& curr_var ) { +bool CegInstantiator::doAddInstantiationInc( Node n, Node pv, Node pv_coeff, int bt, SolvedForm& sf, SolvedForm& ssf, std::vector< Node >& vars, + std::vector< int >& btyp, Node theta, unsigned i, unsigned effort, + std::map< Node, Node >& cons, std::vector< Node >& curr_var ) { if( Trace.isOn("cbqi-inst") ){ for( unsigned j=0; j<sf.d_subs.size(); j++ ){ Trace("cbqi-inst") << " "; @@ -794,7 +800,7 @@ bool CegInstantiator::addInstantiationInc( Node n, Node pv, Node pv_coeff, int b curr_var.pop_back(); is_cv = true; } - success = addInstantiation( sf, ssf, vars, btyp, new_theta, curr_var.empty() ? i+1 : i, effort, cons, curr_var ); + success = doAddInstantiation( sf, ssf, vars, btyp, new_theta, curr_var.empty() ? i+1 : i, effort, cons, curr_var ); if( !success ){ if( is_cv ){ curr_var.push_back( pv ); @@ -825,12 +831,12 @@ bool CegInstantiator::addInstantiationInc( Node n, Node pv, Node pv_coeff, int b } } -bool CegInstantiator::addInstantiationCoeff( SolvedForm& sf, std::vector< Node >& vars, std::vector< int >& btyp, +bool CegInstantiator::doAddInstantiationCoeff( SolvedForm& sf, std::vector< Node >& vars, std::vector< int >& btyp, unsigned j, std::map< Node, Node >& cons ) { if( j==sf.d_has_coeff.size() ){ - return addInstantiation( sf.d_subs, vars, cons ); + return doAddInstantiation( sf.d_subs, vars, cons ); }else{ Assert( std::find( vars.begin(), vars.end(), sf.d_has_coeff[j] )!=vars.end() ); unsigned index = std::find( vars.begin(), vars.end(), sf.d_has_coeff[j] )-vars.begin(); @@ -888,7 +894,7 @@ bool CegInstantiator::addInstantiationCoeff( SolvedForm& sf, std::vector< Node > } } } - if( addInstantiationCoeff( sf, vars, btyp, j+1, cons ) ){ + if( doAddInstantiationCoeff( sf, vars, btyp, j+1, cons ) ){ return true; } } @@ -899,7 +905,7 @@ bool CegInstantiator::addInstantiationCoeff( SolvedForm& sf, std::vector< Node > } } -bool CegInstantiator::addInstantiation( std::vector< Node >& subs, std::vector< Node >& vars, std::map< Node, Node >& cons ) { +bool CegInstantiator::doAddInstantiation( std::vector< Node >& subs, std::vector< Node >& vars, std::map< Node, Node >& cons ) { if( vars.size()>d_vars.size() ){ Trace("cbqi-inst-debug") << "Reconstructing instantiations...." << std::endl; std::map< Node, Node > subs_map; @@ -921,7 +927,7 @@ bool CegInstantiator::addInstantiation( std::vector< Node >& subs, std::vector< subs.push_back( subs_orig[d_var_order_index[i]] ); } } - bool ret = d_out->addInstantiation( subs ); + bool ret = d_out->doAddInstantiation( subs ); #ifdef MBP_STRICT_ASSERTIONS Assert( ret ); #endif @@ -1121,7 +1127,7 @@ bool CegInstantiator::check() { std::map< Node, Node > cons; std::vector< Node > curr_var; //try to add an instantiation - if( addInstantiation( sf, ssf, vars, btyp, theta, 0, r==0 ? 0 : 2, cons, curr_var ) ){ + if( doAddInstantiation( sf, ssf, vars, btyp, theta, 0, r==0 ? 0 : 2, cons, curr_var ) ){ return true; } } @@ -1493,8 +1499,10 @@ void CegInstantiator::registerCounterexampleLemma( std::vector< Node >& lems, st } } -//this isolates the monomial sum into solved form (pv k t), ensures t is Int if pv is Int, and t does not contain vts symbols -int CegInstantiator::isolate( Node pv, Node atom, Node& veq_c, Node& val, Node& vts_coeff_inf, Node& vts_coeff_delta ) { +//this isolates the atom into solved form +// veq_c * pv <> val + vts_coeff_delta * delta + vts_coeff_inf * inf +// ensures val is Int if pv is Int, and val does not contain vts symbols +int CegInstantiator::solve_arith( Node pv, Node atom, Node& veq_c, Node& val, Node& vts_coeff_inf, Node& vts_coeff_delta ) { int ires = 0; Trace("cbqi-inst-debug") << "isolate for " << pv << " in " << atom << std::endl; std::map< Node, Node > msum; @@ -1602,6 +1610,46 @@ int CegInstantiator::isolate( Node pv, Node atom, Node& veq_c, Node& val, Node& vts_coeff_inf = vts_coeff[0]; vts_coeff_delta = vts_coeff[1]; } - return ires; } + +Node CegInstantiator::solve_dt( Node v, Node a, Node b, Node sa, Node sb ) { + Trace("cbqi-inst-debug2") << "Solve dt : " << v << " " << a << " " << b << " " << sa << " " << sb << std::endl; + Node ret; + if( !a.isNull() && a==v ){ + ret = sb; + }else if( !b.isNull() && b==v ){ + ret = sa; + }else if( !a.isNull() && a.getKind()==APPLY_CONSTRUCTOR ){ + if( !b.isNull() && b.getKind()==APPLY_CONSTRUCTOR ){ + if( a.getOperator()==b.getOperator() ){ + for( unsigned i=0; i<a.getNumChildren(); i++ ){ + Node s = solve_dt( v, a[i], b[i], sa[i], sb[i] ); + if( !s.isNull() ){ + return s; + } + } + } + }else{ + unsigned cindex = Datatype::indexOf( a.getOperator().toExpr() ); + TypeNode tn = a.getType(); + const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype(); + for( unsigned i=0; i<a.getNumChildren(); i++ ){ + Node nn = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[cindex][i].getSelector() ), sb ); + Node s = solve_dt( v, a[i], Node::null(), sa[i], nn ); + if( !s.isNull() ){ + return s; + } + } + } + }else if( !b.isNull() && b.getKind()==APPLY_CONSTRUCTOR ){ + return solve_dt( v, b, a, sb, sa ); + } + if( !ret.isNull() ){ + //ensure does not contain + if( TermDb::containsTerm( ret, v ) ){ + ret = Node::null(); + } + } + return ret; +} diff --git a/src/theory/quantifiers/ceg_instantiator.h b/src/theory/quantifiers/ceg_instantiator.h index 9504bd407..3d7bbcb55 100644 --- a/src/theory/quantifiers/ceg_instantiator.h +++ b/src/theory/quantifiers/ceg_instantiator.h @@ -1,13 +1,13 @@ /********************* */ /*! \file ceg_instantiator.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief counterexample-guided quantifier instantiation **/ @@ -33,7 +33,7 @@ namespace quantifiers { class CegqiOutput { public: virtual ~CegqiOutput() {} - virtual bool addInstantiation( std::vector< Node >& subs ) = 0; + virtual bool doAddInstantiation( std::vector< Node >& subs ) = 0; virtual bool isEligibleForInstantiation( Node n ) = 0; virtual bool addLemma( Node lem ) = 0; }; @@ -108,16 +108,16 @@ private: }; */ // effort=0 : do not use model value, 1: use model value, 2: one must use model value - bool addInstantiation( SolvedForm& sf, SolvedForm& ssf, std::vector< Node >& vars, + bool doAddInstantiation( SolvedForm& sf, SolvedForm& ssf, std::vector< Node >& vars, std::vector< int >& btyp, Node theta, unsigned i, unsigned effort, std::map< Node, Node >& cons, std::vector< Node >& curr_var ); - bool addInstantiationInc( Node n, Node pv, Node pv_coeff, int bt, SolvedForm& sf, SolvedForm& ssf, std::vector< Node >& vars, + bool doAddInstantiationInc( Node n, Node pv, Node pv_coeff, int bt, SolvedForm& sf, SolvedForm& ssf, std::vector< Node >& vars, std::vector< int >& btyp, Node theta, unsigned i, unsigned effort, std::map< Node, Node >& cons, std::vector< Node >& curr_var ); - bool addInstantiationCoeff( SolvedForm& sf, + bool doAddInstantiationCoeff( SolvedForm& sf, std::vector< Node >& vars, std::vector< int >& btyp, unsigned j, std::map< Node, Node >& cons ); - bool addInstantiation( std::vector< Node >& subs, std::vector< Node >& vars, std::map< Node, Node >& cons ); + bool doAddInstantiation( std::vector< Node >& subs, std::vector< Node >& vars, std::map< Node, Node >& cons ); Node constructInstantiation( Node n, std::map< Node, Node >& subs_map, std::map< Node, Node >& cons ); Node applySubstitution( TypeNode tn, Node n, SolvedForm& sf, std::vector< Node >& vars, Node& pv_coeff, bool try_coeff = true ) { return applySubstitution( tn, n, sf.d_subs, sf.d_coeff, sf.d_has_coeff, vars, pv_coeff, try_coeff ); @@ -130,7 +130,8 @@ private: //get model value Node getModelValue( Node n ); private: - int isolate( Node v, Node atom, Node & veq_c, Node & val, Node& vts_coeff_inf, Node& vts_coeff_delta ); + int solve_arith( Node v, Node atom, Node & veq_c, Node & val, Node& vts_coeff_inf, Node& vts_coeff_delta ); + Node solve_dt( Node v, Node a, Node b, Node sa, Node sb ); public: CegInstantiator( QuantifiersEngine * qe, CegqiOutput * out, bool use_vts_delta = true, bool use_vts_inf = true ); //check : add instantiations based on valuation of d_vars diff --git a/src/theory/quantifiers/conjecture_generator.cpp b/src/theory/quantifiers/conjecture_generator.cpp index 8e083ae1e..2cc49ef5a 100644 --- a/src/theory/quantifiers/conjecture_generator.cpp +++ b/src/theory/quantifiers/conjecture_generator.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file conjecture_generator.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Clark Barrett, Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief conjecture generator class ** @@ -34,7 +34,7 @@ struct sortConjectureScore { }; -void OpArgIndex::addTerm( ConjectureGenerator * s, TNode n, unsigned index ){ +void OpArgIndex::addTerm( std::vector< TNode >& terms, TNode n, unsigned index ){ if( index==n.getNumChildren() ){ Assert( n.hasOperator() ); if( std::find( d_ops.begin(), d_ops.end(), n.getOperator() )==d_ops.end() ){ @@ -42,7 +42,7 @@ void OpArgIndex::addTerm( ConjectureGenerator * s, TNode n, unsigned index ){ d_op_terms.push_back( n ); } }else{ - d_child[s->getTermDatabase()->d_arg_reps[n][index]].addTerm( s, n, index+1 ); + d_child[terms[index]].addTerm( terms, n, index+1 ); } } @@ -369,7 +369,7 @@ void ConjectureGenerator::check( Theory::Effort e, unsigned quant_e ) { TNode n = (*ieqc_i); if( getTermDatabase()->hasTermCurrent( n ) ){ if( isHandledTerm( n ) ){ - d_op_arg_index[r].addTerm( this, n ); + d_op_arg_index[r].addTerm( getTermDatabase()->d_arg_reps[n], n ); } } ++ieqc_i; @@ -489,7 +489,7 @@ void ConjectureGenerator::check( Theory::Effort e, unsigned quant_e ) { d_thm_index.clear(); std::vector< Node > provenConj; quantifiers::FirstOrderModel* m = d_quantEngine->getModel(); - for( int i=0; i<m->getNumAssertedQuantifiers(); i++ ){ + for( unsigned i=0; i<m->getNumAssertedQuantifiers(); i++ ){ Node q = m->getAssertedQuantifier( i ); Trace("thm-db-debug") << "Is " << q << " a relevant theorem?" << std::endl; Node conjEq; @@ -605,7 +605,8 @@ void ConjectureGenerator::check( Theory::Effort e, unsigned quant_e ) { std::vector< TypeNode > rt_types; std::map< TypeNode, std::map< int, std::vector< Node > > > conj_lhs; unsigned addedLemmas = 0; - for( unsigned depth=1; depth<=3; depth++ ){ + unsigned maxDepth = options::conjectureGenMaxDepth(); + for( unsigned depth=1; depth<=maxDepth; depth++ ){ Trace("sg-proc") << "Generate relevant LHS at depth " << depth << "..." << std::endl; Trace("sg-rel-term") << "Relevant terms of depth " << depth << " : " << std::endl; //set up environment @@ -1167,6 +1168,8 @@ void ConjectureGenerator::processCandidateConjecture( TNode lhs, TNode rhs, unsi d_waiting_conjectures_score.push_back( score ); d_waiting_conjectures[lhs].push_back( rhs ); d_waiting_conjectures[rhs].push_back( lhs ); + }else{ + Trace("sg-conjecture-debug2") << "...do not consider " << lhs << " == " << rhs << ", score = " << score << std::endl; } } @@ -1273,7 +1276,7 @@ bool ConjectureGenerator::notifySubstitution( TNode glhs, std::map< TNode, TNode } Trace("sg-cconj-debug") << "Evaluate RHS : : " << rhs << std::endl; //get the representative of rhs with substitution subs - TNode grhs = getTermDatabase()->evaluateTerm( rhs, subs, true ); + TNode grhs = getTermDatabase()->getEntailedTerm( rhs, subs, true ); Trace("sg-cconj-debug") << "...done evaluating term, got : " << grhs << std::endl; if( !grhs.isNull() ){ if( glhs!=grhs ){ @@ -1569,10 +1572,12 @@ bool TermGenerator::getNextMatch( TermGenEnv * s, TNode eqc, std::map< TypeNode, if( d_match_status_child_num==0 ){ //initial binding TNode f = s->getTgFunc( d_typ, d_status_num ); - std::map< TNode, TermArgTrie >::iterator it = s->getTermDatabase()->d_func_map_eqc_trie[f].d_data.find( eqc ); - if( it!=s->getTermDatabase()->d_func_map_eqc_trie[f].d_data.end() ){ - d_match_children.push_back( it->second.d_data.begin() ); - d_match_children_end.push_back( it->second.d_data.end() ); + //std::map< TNode, TermArgTrie >::iterator it = s->getTermDatabase()->d_func_map_eqc_trie[f].d_data.find( eqc ); + Assert( !eqc.isNull() ); + TermArgTrie * tat = s->getTermDatabase()->getTermArgTrie( eqc, f ); + if( tat ){ + d_match_children.push_back( tat->d_data.begin() ); + d_match_children_end.push_back( tat->d_data.end() ); }else{ d_match_status++; d_match_status_child_num--; diff --git a/src/theory/quantifiers/conjecture_generator.h b/src/theory/quantifiers/conjecture_generator.h index 3aa932296..c89d0f2ee 100644 --- a/src/theory/quantifiers/conjecture_generator.h +++ b/src/theory/quantifiers/conjecture_generator.h @@ -1,13 +1,13 @@ /********************* */ /*! \file conjecture_generator.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Clark Barrett, Tim King, Andrew Reynolds ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief conjecture generator class **/ @@ -39,7 +39,7 @@ public: std::map< TNode, OpArgIndex > d_child; std::vector< TNode > d_ops; std::vector< TNode > d_op_terms; - void addTerm( ConjectureGenerator * s, TNode n, unsigned index = 0 ); + void addTerm( std::vector< TNode >& terms, TNode n, unsigned index = 0 ); Node getGroundTerm( ConjectureGenerator * s, std::vector< TNode >& args ); void getGroundTerms( ConjectureGenerator * s, std::vector< TNode >& terms ); }; diff --git a/src/theory/quantifiers/equality_infer.cpp b/src/theory/quantifiers/equality_infer.cpp new file mode 100644 index 000000000..c3064116f --- /dev/null +++ b/src/theory/quantifiers/equality_infer.cpp @@ -0,0 +1,427 @@ +/********************* */ +/*! \file equality_infer.cpp + ** \verbatim + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim + ** + ** \brief Method for inferring equalities between arithmetic equivalence classes, + ** inspired by "A generalization of Shostak's method for combining decision procedures" Barrett et al. Figure 1. + ** + **/ + +#include "theory/quantifiers/equality_infer.h" +#include "theory/quantifiers/quant_util.h" +#include "context/context_mm.h" + +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::theory; +using namespace CVC4::theory::quantifiers; +using namespace std; + +namespace CVC4 { + +EqualityInference::EqcInfo::EqcInfo(context::Context* c) : d_rep( c ), d_valid( c, false ), d_solved( c, false ), d_master(c) +//, d_rep_exp(c), d_uselist(c) +{ + +} + +EqualityInference::EqualityInference( context::Context* c, bool trackExp ) : +d_c( c ), d_trackExplain( trackExp ), d_elim_vars( c ), +d_rep_to_eqc( c ), d_rep_exp( c ), d_uselist( c ), d_pending_merges( c ), d_pending_merge_exp( c ){ + d_one = NodeManager::currentNM()->mkConst( Rational( 1 ) ); + d_true = NodeManager::currentNM()->mkConst( true ); +} + +EqualityInference::~EqualityInference(){ + for( std::map< Node, EqcInfo * >::iterator it = d_eqci.begin(); it != d_eqci.end(); ++it ){ + delete it->second; + } +} + +void EqualityInference::addToExplanation( std::vector< Node >& exp, Node e ) { + if( std::find( exp.begin(), exp.end(), e )==exp.end() ){ + Trace("eq-infer-debug2") << "......add to explanation " << e << std::endl; + exp.push_back( e ); + } +} + +void EqualityInference::addToExplanationEqc( std::vector< Node >& exp, Node eqc ) { + NodeListMap::iterator re_i = d_rep_exp.find( eqc ); + if( re_i!=d_rep_exp.end() ){ + for( unsigned i=0; i<(*re_i).second->size(); i++ ){ + addToExplanation( exp, (*(*re_i).second)[i] ); + } + } + //for( unsigned i=0; i<d_eqci[n]->d_rep_exp.size(); i++ ){ + // addToExplanation( exp, d_eqci[n]->d_rep_exp[i] ); + //} +} + +void EqualityInference::addToExplanationEqc( Node eqc, std::vector< Node >& exp_to_add ) { + NodeListMap::iterator re_i = d_rep_exp.find( eqc ); + NodeList* re; + if( re_i != d_rep_exp.end() ){ + re = (*re_i).second; + }else{ + re = new(d_c->getCMM()) NodeList( true, d_c, false, context::ContextMemoryAllocator<TNode>(d_c->getCMM()) ); + d_rep_exp.insertDataFromContextMemory( eqc, re ); + } + for( unsigned i=0; i<exp_to_add.size(); i++ ){ + re->push_back( exp_to_add[i] ); + } + //for( unsigned i=0; i<exp_to_add.size(); i++ ){ + // eqci->d_rep_exp.push_back( exp_to_add[i] ); + //} +} + +Node EqualityInference::getMaster( Node t, EqcInfo * eqc, bool& updated, Node new_m ) { + if( !eqc->d_master.get().isNull() ){ + if( eqc->d_master.get()==t ){ + if( !new_m.isNull() && t!=new_m ){ + eqc->d_master = new_m; + updated = true; + return new_m; + }else{ + return t; + } + }else{ + Assert( d_eqci.find( eqc->d_master.get() )!=d_eqci.end() ); + EqcInfo * eqc_m = d_eqci[eqc->d_master.get()]; + Node m = getMaster( eqc->d_master.get(), eqc_m, updated, new_m ); + eqc->d_master = m; + return m; + } + }else{ + return Node::null(); + } +} + +//update the internal "master" representative of the equivalence class, return true if the merge was non-redundant +bool EqualityInference::updateMaster( Node t1, Node t2, EqcInfo * eqc1, EqcInfo * eqc2 ) { + bool updated = false; + Node m1 = getMaster( t1, eqc1, updated ); + if( m1.isNull() ){ + eqc1->d_master = t2; + if( eqc2->d_master.get().isNull() ){ + eqc2->d_master = t2; + } + return true; + }else{ + updated = false; + Node m2 = getMaster( t2, eqc2, updated, m1); + if( m2.isNull() ){ + eqc2->d_master = m1; + return true; + }else{ + return updated; + } + } +} + +void EqualityInference::eqNotifyNewClass(TNode t) { + if( t.getType().isReal() ){ + Trace("eq-infer") << "Notify equivalence class : " << t << std::endl; + EqcInfo * eqci; + std::map< Node, EqcInfo * >::iterator itec = d_eqci.find( t ); + if( itec==d_eqci.end() ){ + eqci = new EqcInfo( d_c ); + d_eqci[t] = eqci; + }else{ + eqci = itec->second; + } + Assert( !eqci->d_valid.get() ); + if( !eqci->d_solved.get() ){ + //somewhat strange: t may not be in rewritten form + Node r = Rewriter::rewrite( t ); + std::map< Node, Node > msum; + if( QuantArith::getMonomialSum( r, msum ) ){ + Trace("eq-infer-debug2") << "...process monomial sum, size = " << msum.size() << std::endl; + eqci->d_valid = true; + bool changed = false; + std::vector< Node > exp; + std::vector< Node > children; + for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ) { + Trace("eq-infer-debug2") << "...process child " << it->first << ", " << it->second << std::endl; + if( !it->first.isNull() ){ + Node n = it->first; + BoolMap::const_iterator itv = d_elim_vars.find( n ); + if( itv!=d_elim_vars.end() ){ + changed = true; + Assert( d_eqci.find( n )!=d_eqci.end() ); + Assert( n!=t ); + Assert( d_eqci[n]->d_solved.get() ); + Trace("eq-infer-debug2") << "......its solved form is " << d_eqci[n]->d_rep.get() << std::endl; + if( d_trackExplain ){ + //track the explanation: justified by explanation for each substitution + addToExplanationEqc( exp, n ); + } + n = d_eqci[n]->d_rep; + Assert( !n.isNull() ); + } + if( it->second.isNull() ){ + children.push_back( n ); + }else{ + children.push_back( NodeManager::currentNM()->mkNode( MULT, it->second, n ) ); + } + }else{ + Assert( !it->second.isNull() ); + children.push_back( it->second ); + } + } + Trace("eq-infer-debug2") << "...children size = " << children.size() << std::endl; + bool mvalid = true; + if( changed ){ + r = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( PLUS, children ); + Trace("eq-infer-debug2") << "...pre-rewrite : " << r << std::endl; + r = Rewriter::rewrite( r ); + msum.clear(); + if( !QuantArith::getMonomialSum( r, msum ) ){ + mvalid = false; + } + } + Trace("eq-infer") << "...value is " << r << std::endl; + setEqcRep( t, r, exp, eqci ); + if( mvalid ){ + for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){ + if( !it->first.isNull() ){ + addToUseList( it->first, t ); + } + } + } + }else{ + eqci->d_valid = false; + } + } + } +} + +void EqualityInference::addToUseList( Node used, Node eqc ) { +#if 1 + NodeListMap::iterator ul_i = d_uselist.find( used ); + NodeList* ul; + if( ul_i != d_uselist.end() ){ + ul = (*ul_i).second; + }else{ + ul = new(d_c->getCMM()) NodeList( true, d_c, false, context::ContextMemoryAllocator<TNode>(d_c->getCMM()) ); + d_uselist.insertDataFromContextMemory( used, ul ); + } + Trace("eq-infer-debug") << " add to use list : " << used << " -> " << eqc << std::endl; + (*ul).push_back( eqc ); +#else + std::map< Node, EqcInfo * >::iterator itu = d_eqci.find( used ); + EqcInfo * eqci_used; + if( itu==d_eqci.end() ){ + eqci_used = new EqcInfo( d_c ); + d_eqci[used] = eqci_used; + }else{ + eqci_used = itu->second; + } + Trace("eq-infer-debug") << " add to use list : " << used << " -> " << eqc << std::endl; + eqci_used->d_uselist.push_back( eqc ); +#endif +} + +void EqualityInference::setEqcRep( Node t, Node r, std::vector< Node >& exp_to_add, EqcInfo * eqci ) { + eqci->d_rep = r; + if( d_trackExplain ){ + addToExplanationEqc( t, exp_to_add ); + } + //if this is an active equivalence class + if( eqci->d_valid.get() ){ + Trace("eq-infer-debug") << "Set eqc rep " << t << " -> " << r << std::endl; + NodeMap::const_iterator itr = d_rep_to_eqc.find( r ); + if( itr==d_rep_to_eqc.end() ){ + d_rep_to_eqc[r] = t; + }else{ + //merge two equivalence classes + Node t2 = (*itr).second; + //check if it is valid + std::map< Node, EqcInfo * >::iterator itc = d_eqci.find( t2 ); + if( itc!=d_eqci.end() && itc->second->d_valid.get() ){ + //if we haven't already determined they should be merged + if( updateMaster( t, t2, eqci, itc->second ) ){ + Trace("eq-infer") << "Infer two equivalence classes are equal : " << t << " " << t2 << std::endl; + Trace("eq-infer") << " since they both normalize to : " << r << std::endl; + d_pending_merges.push_back( t.eqNode( t2 ) ); + if( d_trackExplain ){ + std::vector< Node > exp; + for( unsigned j=0; j<2; j++ ){ + addToExplanationEqc( exp, j==0 ? t : t2 ); + } + Node exp_n = exp.empty() ? d_true : ( exp.size()==1 ? exp[0] : NodeManager::currentNM()->mkNode( AND, exp ) ); + Trace("eq-infer") << " explanation : " << exp_n << std::endl; + d_pending_merge_exp.push_back( exp_n ); + } + } + } + } + } +} + +void EqualityInference::eqNotifyMerge(TNode t1, TNode t2) { + Assert( !t1.isNull() ); + Assert( !t2.isNull() ); + std::map< Node, EqcInfo * >::iterator itv1 = d_eqci.find( t1 ); + if( itv1!=d_eqci.end() ){ + std::map< Node, EqcInfo * >::iterator itv2 = d_eqci.find( t2 ); + if( itv2!=d_eqci.end() ){ + Trace("eq-infer") << "Merge equivalence classes : " << t2 << " into " << t1 << std::endl; + Node tr1 = itv1->second->d_rep; + Node tr2 = itv2->second->d_rep; + itv2->second->d_valid = false; + Trace("eq-infer") << "Representatives : " << tr2 << " into " << tr1 << std::endl; + if( tr1!=tr2 ){ + Node eq = tr1.eqNode( tr2 ); + std::map< Node, Node > msum; + if( QuantArith::getMonomialSumLit( eq, msum ) ){ + Node v_solve; + //solve for variables with no coefficient + if( Trace.isOn("eq-infer-debug2") ){ + Trace("eq-infer-debug2") << "Monomial sum : " << std::endl; + for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ) { + Trace("eq-infer-debug2") << " " << it->first << " * " << it->second << std::endl; + } + } + for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ) { + Node n = it->first; + if( !n.isNull() ){ + bool canSolve = false; + if( it->second.isNull() ){ + canSolve = true; + }else{ + //Assert( it->second.isConst() ); + Rational r = it->second.getConst<Rational>(); + canSolve = r.isOne() || r.isNegativeOne(); + } + if( canSolve ){ + v_solve = n; + break; + } + } + } + Trace("eq-infer-debug") << "solve for variable : " << v_solve << std::endl; + if( !v_solve.isNull() ){ + //solve for v_solve + Node veq; + if( QuantArith::isolate( v_solve, msum, veq, kind::EQUAL, true )==1 ){ + Node v_value = veq[1]; + Trace("eq-infer") << "...solved " << v_solve << " == " << v_value << std::endl; + Assert( d_elim_vars.find( v_solve )==d_elim_vars.end() ); + d_elim_vars[v_solve] = true; + //store value in eqc info + EqcInfo * eqci_solved; + std::map< Node, EqcInfo * >::iterator itec = d_eqci.find( v_solve ); + if( itec==d_eqci.end() ){ + eqci_solved = new EqcInfo( d_c ); + d_eqci[v_solve] = eqci_solved; + }else{ + eqci_solved = itec->second; + } + eqci_solved->d_solved = true; + eqci_solved->d_rep = v_value; + //track the explanation + std::vector< Node > exp; + if( d_trackExplain ){ + //explanation is t1 = t2 + their explanations + exp.push_back( t1.eqNode( t2 ) ); + for( unsigned i=0; i<2; i++ ){ + addToExplanationEqc( exp, i==0 ? t1 : t2 ); + } + if( Trace.isOn("eq-infer-debug") ){ + Trace("eq-infer-debug") << " explanation for solving " << v_solve << " is "; + for( unsigned i=0; i<exp.size(); i++ ){ + Trace("eq-infer-debug") << exp[i] << " "; + } + Trace("eq-infer-debug") << std::endl; + } + addToExplanationEqc( v_solve, exp ); + } + + std::vector< Node > new_use; + for( std::map< Node, Node >::iterator itmm = msum.begin(); itmm != msum.end(); ++itmm ){ + Node n = itmm->first; + if( !n.isNull() && n!=v_solve ){ + new_use.push_back( n ); + addToUseList( n, v_solve ); + } + } + + //go through all equivalence classes that may refer to v_solve + std::map< Node, bool > processed; + processed[v_solve] = true; + NodeListMap::iterator ul_i = d_uselist.find( v_solve ); + if( ul_i != d_uselist.end() ){ + NodeList* ul = (*ul_i).second; + Trace("eq-infer-debug") << " use list size = " << ul->size() << std::endl; + for( unsigned j=0; j<ul->size(); j++ ){ + Node r = (*ul)[j]; + //Trace("eq-infer-debug") << " use list size = " << eqci_solved->d_uselist.size() << std::endl; + //for( unsigned j=0; j<eqci_solved->d_uselist.size(); j++ ){ + // Node r = eqci_solved->d_uselist[j]; + if( processed.find( r )==processed.end() ){ + processed[r] = true; + std::map< Node, EqcInfo * >::iterator itt = d_eqci.find( r ); + if( itt!=d_eqci.end() && ( itt->second->d_valid || itt->second->d_solved ) ){ + std::map< Node, Node > msum2; + if( QuantArith::getMonomialSum( itt->second->d_rep.get(), msum2 ) ){ + std::map< Node, Node >::iterator itm = msum2.find( v_solve ); + if( itm!=msum2.end() ){ + //substitute in solved form + std::map< Node, Node >::iterator itm2 = msum2.find( v_value ); + if( itm2 == msum2.end() ){ + msum2[v_value] = itm->second; + }else{ + msum2[v_value] = NodeManager::currentNM()->mkNode( PLUS, itm2->second.isNull() ? d_one : itm2->second, + itm->second.isNull() ? d_one : itm->second ); + } + msum2.erase( itm ); + Node rr = QuantArith::mkNode( msum2 ); + rr = Rewriter::rewrite( rr ); + Trace("eq-infer") << "......update " << itt->first << " => " << rr << std::endl; + setEqcRep( itt->first, rr, exp, itt->second ); + //update use list + for( unsigned i=0; i<new_use.size(); i++ ){ + addToUseList( new_use[i], r ); + } + } + }else{ + itt->second->d_valid = false; + } + } + } + } + } + Trace("eq-infer") << "...finished solved." << std::endl; + } + } + } + } + }else{ + //no information to merge + } + }else{ + //carry information (this might happen for non-linear t1 and linear t2?) + std::map< Node, EqcInfo * >::iterator itv2 = d_eqci.find( t2 ); + if( itv2!=d_eqci.end() ){ + d_eqci[t1] = d_eqci[t2]; + d_eqci[t2] = NULL; + } + } +} + +Node EqualityInference::getPendingMergeExplanation( unsigned i ) { + if( d_trackExplain ){ + return d_pending_merge_exp[i]; + }else{ + return d_pending_merges[i]; + } +} + +} diff --git a/src/theory/quantifiers/equality_infer.h b/src/theory/quantifiers/equality_infer.h new file mode 100644 index 000000000..93c7bd080 --- /dev/null +++ b/src/theory/quantifiers/equality_infer.h @@ -0,0 +1,103 @@ +/********************* */ +/*! \file equality_infer.h + ** \verbatim + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim + ** + ** \brief additional inference for equalities + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY__QUANTIFIERS__EQUALITY_INFER_H +#define __CVC4__THEORY__QUANTIFIERS__EQUALITY_INFER_H + +#include <ext/hash_set> +#include <iostream> +#include <map> +#include <vector> + +#include "context/context.h" +#include "context/context_mm.h" +#include "context/cdhashmap.h" +#include "context/cdchunk_list.h" +#include "context/cdhashset.h" +#include "theory/theory.h" + + +namespace CVC4 { +namespace theory { +namespace quantifiers { + +class EqualityInference +{ + typedef context::CDHashMap< Node, Node, NodeHashFunction > NodeMap; + typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap; + typedef context::CDChunkList<Node> NodeList; + typedef context::CDHashMap< Node, NodeList *, NodeHashFunction > NodeListMap; +private: + context::Context * d_c; + Node d_one; + Node d_true; + class EqcInfo { + public: + EqcInfo(context::Context* c); + ~EqcInfo(){} + context::CDO< Node > d_rep; + //whether the eqc of this info is a representative and d_rep can been computed successfully + context::CDO< bool > d_valid; + //whether the eqc of this info is a solved variable + context::CDO< bool > d_solved; + //master equivalence class (a union find) + context::CDO< Node > d_master; + //a vector of equalities t1=t2 for which eqNotifyMerge(t1,t2) was called that explains d_rep + //NodeList d_rep_exp; + //the list of other eqc where this variable may be appear + //NodeList d_uselist; + }; + + /** track explanations */ + bool d_trackExplain; + /** information necessary for equivalence classes */ + BoolMap d_elim_vars; + std::map< Node, EqcInfo * > d_eqci; + NodeMap d_rep_to_eqc; + NodeListMap d_rep_exp; + /** set eqc rep */ + void setEqcRep( Node t, Node r, std::vector< Node >& exp_to_add, EqcInfo * eqci ); + /** use list */ + NodeListMap d_uselist; + void addToUseList( Node used, Node eqc ); + /** pending merges */ + NodeList d_pending_merges; + NodeList d_pending_merge_exp; + /** add to explanation */ + void addToExplanation( std::vector< Node >& exp, Node e ); + void addToExplanationEqc( std::vector< Node >& exp, Node eqc ); + void addToExplanationEqc( Node eqc, std::vector< Node >& exp_to_add ); + /** for setting master/slave */ + Node getMaster( Node t, EqcInfo * eqc, bool& updated, Node new_m = Node::null() ); + bool updateMaster( Node t1, Node t2, EqcInfo * eqc1, EqcInfo * eqc2 ); +public: + //second argument is whether explanations should be tracked + EqualityInference(context::Context* c, bool trackExp = false); + virtual ~EqualityInference(); + /** input : notification when equality engine is updated */ + void eqNotifyNewClass(TNode t); + void eqNotifyMerge(TNode t1, TNode t2); + /** output : inferred equalities */ + unsigned getNumPendingMerges() { return d_pending_merges.size(); } + Node getPendingMerge( unsigned i ) { return d_pending_merges[i]; } + Node getPendingMergeExplanation( unsigned i ); +}; + +} +} +} + +#endif diff --git a/src/theory/quantifiers/first_order_model.cpp b/src/theory/quantifiers/first_order_model.cpp index 272f16be8..a833f48d2 100644 --- a/src/theory/quantifiers/first_order_model.cpp +++ b/src/theory/quantifiers/first_order_model.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file first_order_model.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): Kshitij Bansal, Morgan Deters + ** Top contributors (to current version): + ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Implementation of model engine model class **/ @@ -30,24 +30,43 @@ using namespace CVC4::theory; using namespace CVC4::theory::quantifiers; using namespace CVC4::theory::quantifiers::fmcheck; +struct sortQuantifierRelevance { + FirstOrderModel * d_fm; + bool operator() (Node i, Node j) { + int wi = d_fm->getRelevanceValue( i ); + int wj = d_fm->getRelevanceValue( j ); + if( wi==wj ){ + return i<j; + }else{ + return wi<wj; + } + } +}; + FirstOrderModel::FirstOrderModel(QuantifiersEngine * qe, context::Context* c, std::string name ) : TheoryModel( c, name, true ), d_qe( qe ), d_forall_asserts( c ), d_isModelSet( c, false ){ + d_rlv_count = 0; +} + +void FirstOrderModel::assertQuantifier( Node n ){ + if( n.getKind()==FORALL ){ + d_forall_asserts.push_back( n ); + }else if( n.getKind()==NOT ){ + Assert( n[0].getKind()==FORALL ); + } +} +unsigned FirstOrderModel::getNumAssertedQuantifiers() { + return d_forall_asserts.size(); } -void FirstOrderModel::assertQuantifier( Node n, bool reduced ){ - if( !reduced ){ - if( n.getKind()==FORALL ){ - d_forall_asserts.push_back( n ); - }else if( n.getKind()==NOT ){ - Assert( n[0].getKind()==FORALL ); - } +Node FirstOrderModel::getAssertedQuantifier( unsigned i, bool ordered ) { + if( !ordered || d_forall_rlv_assert.empty() ){ + return d_forall_asserts[i]; }else{ - Assert( n.getKind()==FORALL ); - Assert( d_forall_to_reduce.find( n )==d_forall_to_reduce.end() ); - d_forall_to_reduce[n] = true; - Trace("quant") << "Mark to reduce : " << n << std::endl; + Assert( d_forall_rlv_assert.size()==d_forall_asserts.size() ); + return d_forall_rlv_assert[i]; } } @@ -81,11 +100,11 @@ void FirstOrderModel::initialize() { processInitialize( true ); //this is called after representatives have been chosen and the equality engine has been built //for each quantifier, collect all operators we care about - for( int i=0; i<getNumAssertedQuantifiers(); i++ ){ + for( unsigned i=0; i<getNumAssertedQuantifiers(); i++ ){ Node f = getAssertedQuantifier( i ); if( d_quant_var_id.find( f )==d_quant_var_id.end() ){ - for(unsigned i=0; i<f[0].getNumChildren(); i++){ - d_quant_var_id[f][f[0][i]] = i; + for(unsigned j=0; j<f[0].getNumChildren(); j++){ + d_quant_var_id[f][f[0][j]] = j; } } processInitializeQuantifier( f ); @@ -122,20 +141,72 @@ Node FirstOrderModel::getSomeDomainElement(TypeNode tn){ /** needs check */ bool FirstOrderModel::checkNeeded() { - return d_forall_asserts.size()>0 || !d_forall_to_reduce.empty(); -} - -/** mark reduced */ -void FirstOrderModel::markQuantifierReduced( Node q ) { - Assert( d_forall_to_reduce.find( q )!=d_forall_to_reduce.end() ); - d_forall_to_reduce.erase( q ); - Trace("quant") << "Mark reduced : " << q << std::endl; + return d_forall_asserts.size()>0; } void FirstOrderModel::reset_round() { d_quant_active.clear(); + + //order the quantified formulas + if( !d_forall_rlv_vec.empty() ){ + Trace("fm-relevant") << "Build sorted relevant list..." << std::endl; + d_forall_rlv_assert.clear(); + Trace("fm-relevant-debug") << "Mark asserted quantified formulas..." << std::endl; + std::map< Node, bool > qassert; + for( unsigned i=0; i<d_forall_asserts.size(); i++ ){ + qassert[d_forall_asserts[i]] = true; + } + Trace("fm-relevant-debug") << "Sort the relevant quantified formulas..." << std::endl; + sortQuantifierRelevance sqr; + sqr.d_fm = this; + std::sort( d_forall_rlv_vec.begin(), d_forall_rlv_vec.end(), sqr ); + Trace("fm-relevant-debug") << "Add relevant asserted formulas..." << std::endl; + for( int i=(int)(d_forall_rlv_vec.size()-1); i>=0; i-- ){ + Node q = d_forall_rlv_vec[i]; + if( qassert.find( q )!=qassert.end() ){ + Trace("fm-relevant") << " " << d_forall_rlv[q] << " : " << q << std::endl; + d_forall_rlv_assert.push_back( q ); + } + } + Trace("fm-relevant-debug") << "Add remaining asserted formulas..." << std::endl; + for( unsigned i=0; i<d_forall_asserts.size(); i++ ){ + Node q = d_forall_asserts[i]; + if( std::find( d_forall_rlv_assert.begin(), d_forall_rlv_assert.end(), q )==d_forall_rlv_assert.end() ){ + d_forall_rlv_assert.push_back( q ); + }else{ + Trace("fm-relevant-debug") << "...already included " << q << std::endl; + } + } + Trace("fm-relevant-debug") << "Sizes : " << d_forall_rlv_assert.size() << " " << d_forall_asserts.size() << std::endl; + Assert( d_forall_rlv_assert.size()==d_forall_asserts.size() ); + } +} + +void FirstOrderModel::markRelevant( Node q ) { + if( q!=d_last_forall_rlv ){ + Trace("fm-relevant") << "Mark relevant : " << q << std::endl; + if( std::find( d_forall_rlv_vec.begin(), d_forall_rlv_vec.end(), q )==d_forall_rlv_vec.end() ){ + d_forall_rlv_vec.push_back( q ); + } + d_forall_rlv[ q ] = d_rlv_count; + d_rlv_count++; + d_last_forall_rlv = q; + } } +int FirstOrderModel::getRelevanceValue( Node q ) { + std::map< Node, unsigned >::iterator it = d_forall_rlv.find( q ); + if( it==d_forall_rlv.end() ){ + return -1; + }else{ + return it->second; + } +} + +//bool FirstOrderModel::isQuantifierAsserted( TNode q ) { +// return d_forall_asserts.find( q )!=d_forall_asserts.end(); +//} + void FirstOrderModel::setQuantifierActive( TNode q, bool active ) { d_quant_active[q] = active; } diff --git a/src/theory/quantifiers/first_order_model.h b/src/theory/quantifiers/first_order_model.h index d42eb61e3..cbe83cfa5 100644 --- a/src/theory/quantifiers/first_order_model.h +++ b/src/theory/quantifiers/first_order_model.h @@ -1,13 +1,13 @@ /********************* */ /*! \file first_order_model.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Model extended classes **/ @@ -49,8 +49,12 @@ protected: QuantifiersEngine * d_qe; /** list of quantifiers asserted in the current context */ context::CDList<Node> d_forall_asserts; - /** list of quantifiers that have been marked to reduce */ - std::map< Node, bool > d_forall_to_reduce; + /** quantified formulas marked as relevant */ + unsigned d_rlv_count; + std::map< Node, unsigned > d_forall_rlv; + std::vector< Node > d_forall_rlv_vec; + Node d_last_forall_rlv; + std::vector< Node > d_forall_rlv_assert; /** is model set */ context::CDO< bool > d_isModelSet; /** get variable id */ @@ -59,13 +63,11 @@ protected: virtual Node getCurrentUfModelValue( Node n, std::vector< Node > & args, bool partial ) = 0; public: //for Theory Quantifiers: /** assert quantifier */ - void assertQuantifier( Node n, bool reduced = false ); + void assertQuantifier( Node n ); /** get number of asserted quantifiers */ - int getNumAssertedQuantifiers() { return (int)d_forall_asserts.size(); } + unsigned getNumAssertedQuantifiers(); /** get asserted quantifier */ - Node getAssertedQuantifier( int i ) { return d_forall_asserts[i]; } - /** get number to reduce quantifiers */ - unsigned getNumToReduceQuantifiers() { return d_forall_to_reduce.size(); } + Node getAssertedQuantifier( unsigned i, bool ordered = false ); /** initialize model for term */ void initializeModelForTerm( Node n, std::map< Node, bool >& visited ); virtual void processInitializeModelForTerm( Node n ) = 0; @@ -94,14 +96,16 @@ public: Node getSomeDomainElement(TypeNode tn); /** do we need to do any work? */ bool checkNeeded(); - /** mark reduced */ - void markQuantifierReduced( Node q ); private: //list of inactive quantified formulas std::map< TNode, bool > d_quant_active; public: /** reset round */ void reset_round(); + /** mark quantified formula relevant */ + void markRelevant( Node q ); + /** get relevance value */ + int getRelevanceValue( Node q ); /** set quantified formula active/inactive * a quantified formula may be set inactive if for instance: * - it is entailed by other quantified formulas diff --git a/src/theory/quantifiers/full_model_check.cpp b/src/theory/quantifiers/full_model_check.cpp index ff0da13e1..33c853328 100644 --- a/src/theory/quantifiers/full_model_check.cpp +++ b/src/theory/quantifiers/full_model_check.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file full_model_check.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): Kshitij Bansal + ** Top contributors (to current version): + ** Morgan Deters, Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Implementation of full model check class **/ @@ -350,11 +350,11 @@ void FullModelChecker::preProcessBuildModel(TheoryModel* m, bool fullModel) { } //do not have to introduce terms for sorts of domains of quantified formulas if we are allowed to assume empty sorts if( !options::fmfEmptySorts() ){ - for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){ + for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){ Node q = fm->getAssertedQuantifier( i ); //make sure all types are set - for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ - preInitializeType( fm, q[0][i].getType() ); + for( unsigned j=0; j<q[0].getNumChildren(); j++ ){ + preInitializeType( fm, q[0][j].getType() ); } } } @@ -411,6 +411,11 @@ void FullModelChecker::processBuildModel(TheoryModel* m, bool fullModel){ Node r = fm->getUsedRepresentative(n); Trace("fmc-model-debug") << n << " -> " << r << std::endl; //AlwaysAssert( fm->areEqual( fm->d_uf_terms[op][i], r ) ); + }else{ + if( Trace.isOn("fmc-model-debug") ){ + Node r = fm->getUsedRepresentative(n); + Trace("fmc-model-debug") << "[redundant] " << n << " -> " << r << std::endl; + } } } Trace("fmc-model-debug") << std::endl; @@ -456,7 +461,7 @@ void FullModelChecker::processBuildModel(TheoryModel* m, bool fullModel){ } } if( !isStar && !ri.isConst() ){ - Trace("fmc-warn") << "Warning : model has non-constant argument in model " << ri << " (from " << c[i] << ")" << std::endl; + Trace("fmc-warn") << "Warning : model for " << op << " has non-constant argument in model " << ri << " (from " << c[i] << ")" << std::endl; Assert( false ); } entry_children.push_back(ri); @@ -464,7 +469,7 @@ void FullModelChecker::processBuildModel(TheoryModel* m, bool fullModel){ Node n = NodeManager::currentNM()->mkNode( APPLY_UF, children ); Node nv = fm->getUsedRepresentative( v ); if( !nv.isConst() ){ - Trace("fmc-warn") << "Warning : model has non-constant value in model " << nv << std::endl; + Trace("fmc-warn") << "Warning : model for " << op << " has non-constant value in model " << nv << std::endl; Assert( false ); } Node en = (useSimpleModels() && hasNonStar) ? n : NodeManager::currentNM()->mkNode( APPLY_UF, entry_children ); @@ -586,6 +591,7 @@ void FullModelChecker::debugPrint(const char * tr, Node n, bool dispStar) { bool FullModelChecker::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) { Trace("fmc") << "Full model check " << f << ", effort = " << effort << "..." << std::endl; + Assert( !d_qe->inConflict() ); if( optUseModel() ){ FirstOrderModelFmc * fmfmc = fm->asFirstOrderModelFmc(); if (effort==0) { @@ -614,7 +620,7 @@ bool FullModelChecker::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, //consider all entries going to non-true for (unsigned i=0; i<d_quant_models[f].d_cond.size(); i++) { - if( d_quant_models[f].d_value[i]!=d_true) { + if( d_quant_models[f].d_value[i]!=d_true ) { Trace("fmc-inst") << "Instantiate based on " << d_quant_models[f].d_cond[i] << "..." << std::endl; bool hasStar = false; std::vector< Node > inst; @@ -676,15 +682,21 @@ bool FullModelChecker::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, }else{ //just add the instance d_triedLemmas++; - if( d_qe->addInstantiation( f, inst ) ){ + if( d_qe->addInstantiation( f, inst, true ) ){ Trace("fmc-debug-inst") << "** Added instantiation." << std::endl; d_addedLemmas++; - if( options::fmfOneInstPerRound() ){ + if( d_qe->inConflict() || options::fmfOneInstPerRound() ){ break; } }else{ Trace("fmc-debug-inst") << "** Instantiation was duplicate." << std::endl; - //this can happen if evaluation is unknown + //this can happen if evaluation is unknown, or if we are generalizing a star that already has a value + //if( !hasStar && d_quant_models[f].d_value[i]==d_false ){ + // Trace("fmc-warn") << "**** FMC warning: inconsistent duplicate instantiation." << std::endl; + //} + //this assertion can happen if two instantiations from this round are identical + // (0,1)->false (1,0)->false for forall xy. f( x, y ) = f( y, x ) + //Assert( hasStar || d_quant_models[f].d_value[i]!=d_false ); //might try it next effort level d_star_insts[f].push_back(i); } @@ -733,12 +745,14 @@ bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, No for( unsigned i=0; i<c.getNumChildren(); i++ ){ if( c[i].getType().isInteger() ){ if( fm->isInterval(c[i]) ){ + Trace("fmc-exh-debug") << "...set " << i << " based on interval." << std::endl; for( unsigned b=0; b<2; b++ ){ if( !fm->isStar(c[i][b]) ){ riter.d_bounds[b][i] = c[i][b]; } } }else if( !fm->isStar(c[i]) ){ + Trace("fmc-exh-debug") << "...set " << i << " based on point." << std::endl; riter.d_bounds[0][i] = c[i]; riter.d_bounds[1][i] = QuantArith::offset( c[i], 1 ); } @@ -780,11 +794,11 @@ bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, No for( int i=0; i<riter.getNumTerms(); i++ ){ Node rr = riter.getTerm( i ); Node r = rr; - if( r.getType().isSort() ){ - r = fm->getUsedRepresentative( r ); - }else{ - r = fm->getCurrentModelValue( r ); - } + //if( r.getType().isSort() ){ + r = fm->getUsedRepresentative( r ); + //}else{ + // r = fm->getCurrentModelValue( r ); + //} debugPrint("fmc-exh-debug", r); Trace("fmc-exh-debug") << " (term : " << rr << ")"; ev_inst.push_back( r ); @@ -796,10 +810,10 @@ bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, No if (ev!=d_true) { Trace("fmc-exh-debug") << ", add!"; //add as instantiation - if( d_qe->addInstantiation( f, inst ) ){ + if( d_qe->addInstantiation( f, inst, true ) ){ Trace("fmc-exh-debug") << " ...success."; addedLemmas++; - if( options::fmfOneInstPerRound() ){ + if( d_qe->inConflict() || options::fmfOneInstPerRound() ){ break; } }else{ @@ -846,38 +860,12 @@ void FullModelChecker::doCheck(FirstOrderModelFmc * fm, Node f, Def & d, Node n d.addEntry(fm, mkCondDefault(fm, f), Node::null()); } else if( n.getType().isArray() ){ - //make the definition - bool success = false; - /* - Node r = fm->getRepresentative(n); - Trace("fmc-debug") << "Representative for array is " << r << std::endl; - while( r.getKind() == kind::STORE ){ - Node i = fm->getUsedRepresentative( r[1] ); - Node e = fm->getUsedRepresentative( r[2] ); - d.addEntry(fm, mkArrayCond(i), e ); - r = fm->getRepresentative( r[0] ); - } - Node defC = mkArrayCond(fm->getStar(n.getType().getArrayIndexType())); - bool success = false; - Node odefaultValue; - if( r.getKind() == kind::STORE_ALL ){ - ArrayStoreAll storeAll = r.getConst<ArrayStoreAll>(); - odefaultValue = Node::fromExpr(storeAll.getExpr()); - Node defaultValue = fm->getUsedRepresentative( odefaultValue, true ); - if( !defaultValue.isNull() ){ - d.addEntry(fm, defC, defaultValue); - success = true; - } - } - */ - if( !success ){ - //Trace("fmc-warn") << "WARNING : ARRAYS : Can't process base array " << r << std::endl; - //Trace("fmc-warn") << " Default value was : " << odefaultValue << std::endl; - //Trace("fmc-debug") << "Can't process base array " << r << std::endl; - //can't process this array - d.reset(); - d.addEntry(fm, mkCondDefault(fm, f), Node::null()); - } + //Trace("fmc-warn") << "WARNING : ARRAYS : Can't process base array " << r << std::endl; + //Trace("fmc-warn") << " Default value was : " << odefaultValue << std::endl; + //Trace("fmc-debug") << "Can't process base array " << r << std::endl; + //can't process this array + d.reset(); + d.addEntry(fm, mkCondDefault(fm, f), Node::null()); } else if( n.getNumChildren()==0 ){ Node r = n; diff --git a/src/theory/quantifiers/full_model_check.h b/src/theory/quantifiers/full_model_check.h index c7bfcd189..411b7a5eb 100644 --- a/src/theory/quantifiers/full_model_check.h +++ b/src/theory/quantifiers/full_model_check.h @@ -1,13 +1,13 @@ /********************* */ /*! \file full_model_check.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Morgan Deters, Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Full model check class **/ diff --git a/src/theory/quantifiers/fun_def_engine.cpp b/src/theory/quantifiers/fun_def_engine.cpp index 56214f540..cf1d14663 100644 --- a/src/theory/quantifiers/fun_def_engine.cpp +++ b/src/theory/quantifiers/fun_def_engine.cpp @@ -1,13 +1,13 @@ /********************* */ -/*! \file fun_def_process.cpp +/*! \file fun_def_engine.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** This class implements specialized techniques for (recursively) defined functions **/ diff --git a/src/theory/quantifiers/fun_def_engine.h b/src/theory/quantifiers/fun_def_engine.h index be73d51a9..3b95281c0 100644 --- a/src/theory/quantifiers/fun_def_engine.h +++ b/src/theory/quantifiers/fun_def_engine.h @@ -1,13 +1,13 @@ /********************* */ /*! \file fun_def_engine.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Specialized techniques for (recursively) defined functions **/ diff --git a/src/theory/quantifiers/fun_def_process.cpp b/src/theory/quantifiers/fun_def_process.cpp index 7d5e33fdb..9109aab8a 100644 --- a/src/theory/quantifiers/fun_def_process.cpp +++ b/src/theory/quantifiers/fun_def_process.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file fun_def_process.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): Kshitij Bansal + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Sort inference module ** diff --git a/src/theory/quantifiers/fun_def_process.h b/src/theory/quantifiers/fun_def_process.h index 8cff6c952..1f6ee6562 100644 --- a/src/theory/quantifiers/fun_def_process.h +++ b/src/theory/quantifiers/fun_def_process.h @@ -1,13 +1,13 @@ /********************* */ /*! \file fun_def_process.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Pre-process steps for well-defined functions **/ diff --git a/src/theory/quantifiers/inst_match.cpp b/src/theory/quantifiers/inst_match.cpp index 5eca87903..8818175db 100644 --- a/src/theory/quantifiers/inst_match.cpp +++ b/src/theory/quantifiers/inst_match.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file inst_match.cpp ** \verbatim - ** Original author: Morgan Deters - ** Major contributors: Andrew Reynolds - ** Minor contributors (to current version): Kshitij Bansal, Francois Bobot, Clark Barrett + ** Top contributors (to current version): + ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Implementation of inst match class **/ @@ -142,7 +142,7 @@ bool InstMatch::set( QuantifiersEngine* qe, int i, TNode n ) { } bool InstMatchTrie::addInstMatch( QuantifiersEngine* qe, Node f, std::vector< Node >& m, bool modEq, - bool modInst, ImtIndexOrder* imtio, bool onlyExist, int index ) { + ImtIndexOrder* imtio, bool onlyExist, int index ) { if( index==(int)f[0].getNumChildren() || ( imtio && index==(int)imtio->d_order.size() ) ){ return false; }else{ @@ -150,25 +150,11 @@ bool InstMatchTrie::addInstMatch( QuantifiersEngine* qe, Node f, std::vector< No Node n = m[i_index]; std::map< Node, InstMatchTrie >::iterator it = d_data.find( n ); if( it!=d_data.end() ){ - bool ret = it->second.addInstMatch( qe, f, m, modEq, modInst, imtio, onlyExist, index+1 ); + bool ret = it->second.addInstMatch( qe, f, m, modEq, imtio, onlyExist, index+1 ); if( !onlyExist || !ret ){ return ret; } } - /* - //check if m is an instance of another instantiation if modInst is true - if( modInst ){ - if( !n.isNull() ){ - Node nl; - std::map< Node, InstMatchTrie >::iterator itm = d_data.find( nl ); - if( itm!=d_data.end() ){ - if( !itm->second.addInstMatch( qe, f, m, modEq, modInst, imtio, true, index+1 ) ){ - return false; - } - } - } - } - */ if( modEq ){ //check modulo equality if any other instantiation match exists if( !n.isNull() && qe->getEqualityQuery()->getEngine()->hasTerm( n ) ){ @@ -179,7 +165,7 @@ bool InstMatchTrie::addInstMatch( QuantifiersEngine* qe, Node f, std::vector< No if( en!=n ){ std::map< Node, InstMatchTrie >::iterator itc = d_data.find( en ); if( itc!=d_data.end() ){ - if( itc->second.addInstMatch( qe, f, m, modEq, modInst, imtio, true, index+1 ) ){ + if( itc->second.addInstMatch( qe, f, m, modEq, imtio, true, index+1 ) ){ return false; } } @@ -189,12 +175,30 @@ bool InstMatchTrie::addInstMatch( QuantifiersEngine* qe, Node f, std::vector< No } } if( !onlyExist ){ - d_data[n].addInstMatch( qe, f, m, modEq, modInst, imtio, false, index+1 ); + d_data[n].addInstMatch( qe, f, m, modEq, imtio, false, index+1 ); } return true; } } +bool InstMatchTrie::removeInstMatch( QuantifiersEngine* qe, Node q, std::vector< Node >& m, ImtIndexOrder* imtio, int index ) { + Assert( index<(int)q[0].getNumChildren() ); + Assert( !imtio || index<(int)imtio->d_order.size() ); + int i_index = imtio ? imtio->d_order[index] : index; + Node n = m[i_index]; + std::map< Node, InstMatchTrie >::iterator it = d_data.find( n ); + if( it!=d_data.end() ){ + if( (index+1)==(int)q[0].getNumChildren() || ( imtio && (index+1)==(int)imtio->d_order.size() ) ){ + d_data.erase( n ); + return true; + }else{ + return it->second.removeInstMatch( qe, q, m, imtio, index+1 ); + } + }else{ + return false; + } +} + void InstMatchTrie::print( std::ostream& out, Node q, std::vector< TNode >& terms ) const { if( terms.size()==q[0].getNumChildren() ){ out << " ( "; @@ -212,9 +216,31 @@ void InstMatchTrie::print( std::ostream& out, Node q, std::vector< TNode >& term } } +void InstMatchTrie::getInstantiations( std::vector< Node >& insts, Node q, std::vector< Node >& terms, QuantifiersEngine * qe ) const { + if( terms.size()==q[0].getNumChildren() ){ + //insts.push_back( q[1].substitute( vars.begin(), vars.end(), terms.begin(), terms.end() ) ); + insts.push_back( qe->getInstantiation( q, terms, true ) ); + }else{ + for( std::map< Node, InstMatchTrie >::const_iterator it = d_data.begin(); it != d_data.end(); ++it ){ + terms.push_back( it->first ); + it->second.getInstantiations( insts, q, terms, qe ); + terms.pop_back(); + } + } +} + +CDInstMatchTrie::~CDInstMatchTrie() { + for(std::map< Node, CDInstMatchTrie* >::iterator i = d_data.begin(), + iend = d_data.end(); i != iend; ++i) { + CDInstMatchTrie* current = (*i).second; + delete current; + } + d_data.clear(); +} + bool CDInstMatchTrie::addInstMatch( QuantifiersEngine* qe, Node f, std::vector< Node >& m, - context::Context* c, bool modEq, bool modInst, int index, bool onlyExist ){ + context::Context* c, bool modEq, int index, bool onlyExist ){ bool reset = false; if( !d_valid.get() ){ if( onlyExist ){ @@ -230,25 +256,11 @@ bool CDInstMatchTrie::addInstMatch( QuantifiersEngine* qe, Node f, std::vector< Node n = m[ index ]; std::map< Node, CDInstMatchTrie* >::iterator it = d_data.find( n ); if( it!=d_data.end() ){ - bool ret = it->second->addInstMatch( qe, f, m, c, modEq, modInst, index+1, onlyExist ); + bool ret = it->second->addInstMatch( qe, f, m, c, modEq, index+1, onlyExist ); if( !onlyExist || !ret ){ return reset || ret; } } - //check if m is an instance of another instantiation if modInst is true - /* - if( modInst ){ - if( !n.isNull() ){ - Node nl; - std::map< Node, CDInstMatchTrie* >::iterator itm = d_data.find( nl ); - if( itm!=d_data.end() ){ - if( !itm->second->addInstMatch( qe, f, m, c, modEq, modInst, index+1, true ) ){ - return false; - } - } - } - } - */ if( modEq ){ //check modulo equality if any other instantiation match exists if( !n.isNull() && qe->getEqualityQuery()->getEngine()->hasTerm( n ) ){ @@ -259,7 +271,7 @@ bool CDInstMatchTrie::addInstMatch( QuantifiersEngine* qe, Node f, std::vector< if( en!=n ){ std::map< Node, CDInstMatchTrie* >::iterator itc = d_data.find( en ); if( itc!=d_data.end() ){ - if( itc->second->addInstMatch( qe, f, m, c, modEq, modInst, index+1, true ) ){ + if( itc->second->addInstMatch( qe, f, m, c, modEq, index+1, true ) ){ return false; } } @@ -272,13 +284,33 @@ bool CDInstMatchTrie::addInstMatch( QuantifiersEngine* qe, Node f, std::vector< if( !onlyExist ){ // std::map< Node, CDInstMatchTrie* >::iterator it = d_data.find( n ); CDInstMatchTrie* imt = new CDInstMatchTrie( c ); + Assert(d_data.find(n) == d_data.end()); d_data[n] = imt; - imt->addInstMatch( qe, f, m, c, modEq, modInst, index+1, false ); + imt->addInstMatch( qe, f, m, c, modEq, index+1, false ); } return true; } } +bool CDInstMatchTrie::removeInstMatch( QuantifiersEngine* qe, Node q, std::vector< Node >& m, int index ) { + if( index==(int)q[0].getNumChildren() ){ + if( d_valid.get() ){ + d_valid.set( false ); + return true; + }else{ + return false; + } + }else{ + Node n = m[index]; + std::map< Node, CDInstMatchTrie* >::iterator it = d_data.find( n ); + if( it!=d_data.end() ){ + return it->second->removeInstMatch( qe, q, m, index+1 ); + }else{ + return false; + } + } +} + void CDInstMatchTrie::print( std::ostream& out, Node q, std::vector< TNode >& terms ) const{ if( d_valid.get() ){ if( terms.size()==q[0].getNumChildren() ){ @@ -298,6 +330,21 @@ void CDInstMatchTrie::print( std::ostream& out, Node q, std::vector< TNode >& te } } +void CDInstMatchTrie::getInstantiations( std::vector< Node >& insts, Node q, std::vector< Node >& terms, QuantifiersEngine * qe ) const{ + if( d_valid.get() ){ + if( terms.size()==q[0].getNumChildren() ){ + //insts.push_back( q[1].substitute( vars.begin(), vars.end(), terms.begin(), terms.end() ) ); + insts.push_back( qe->getInstantiation( q, terms, true ) ); + }else{ + for( std::map< Node, CDInstMatchTrie* >::const_iterator it = d_data.begin(); it != d_data.end(); ++it ){ + terms.push_back( it->first ); + it->second->getInstantiations( insts, q, terms, qe ); + terms.pop_back(); + } + } + } +} + }/* CVC4::theory::inst namespace */ }/* CVC4::theory namespace */ }/* CVC4 namespace */ diff --git a/src/theory/quantifiers/inst_match.h b/src/theory/quantifiers/inst_match.h index f1c1c952a..ad287c1a3 100644 --- a/src/theory/quantifiers/inst_match.h +++ b/src/theory/quantifiers/inst_match.h @@ -1,13 +1,13 @@ /********************* */ /*! \file inst_match.h ** \verbatim - ** Original author: Morgan Deters - ** Major contributors: Andrew Reynolds - ** Minor contributors (to current version): Francois Bobot + ** Top contributors (to current version): + ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief inst match class **/ @@ -96,11 +96,12 @@ public: public: std::vector< int > d_order; };/* class InstMatchTrie ImtIndexOrder */ -public: + /** the data */ std::map< Node, InstMatchTrie > d_data; private: void print( std::ostream& out, Node q, std::vector< TNode >& terms ) const; + void getInstantiations( std::vector< Node >& insts, Node q, std::vector< Node >& terms, QuantifiersEngine * qe ) const; public: InstMatchTrie(){} ~InstMatchTrie(){} @@ -110,69 +111,80 @@ public: modInst is if we return true if m is an instance of a match that exists */ bool existsInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m, bool modEq = false, - bool modInst = false, ImtIndexOrder* imtio = NULL, int index = 0 ) { - return !addInstMatch( qe, f, m, modEq, modInst, imtio, true, index ); + ImtIndexOrder* imtio = NULL, int index = 0 ) { + return !addInstMatch( qe, f, m, modEq, imtio, true, index ); } bool existsInstMatch( QuantifiersEngine* qe, Node f, std::vector< Node >& m, bool modEq = false, - bool modInst = false, ImtIndexOrder* imtio = NULL, int index = 0 ) { - return !addInstMatch( qe, f, m, modEq, modInst, imtio, true, index ); + ImtIndexOrder* imtio = NULL, int index = 0 ) { + return !addInstMatch( qe, f, m, modEq, imtio, true, index ); } /** add match m for quantifier f, take into account equalities if modEq = true, if imtio is non-null, this is the order to add to trie return true if successful */ bool addInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m, bool modEq = false, - bool modInst = false, ImtIndexOrder* imtio = NULL, bool onlyExist = false, int index = 0 ){ - return addInstMatch( qe, f, m.d_vals, modEq, modInst, imtio, onlyExist, index ); + ImtIndexOrder* imtio = NULL, bool onlyExist = false, int index = 0 ){ + return addInstMatch( qe, f, m.d_vals, modEq, imtio, onlyExist, index ); } bool addInstMatch( QuantifiersEngine* qe, Node f, std::vector< Node >& m, bool modEq = false, - bool modInst = false, ImtIndexOrder* imtio = NULL, bool onlyExist = false, int index = 0 ); + ImtIndexOrder* imtio = NULL, bool onlyExist = false, int index = 0 ); + bool removeInstMatch( QuantifiersEngine* qe, Node f, std::vector< Node >& m, ImtIndexOrder* imtio = NULL, int index = 0 ); void print( std::ostream& out, Node q ) const{ std::vector< TNode > terms; print( out, q, terms ); } + void getInstantiations( std::vector< Node >& insts, Node q, QuantifiersEngine * qe ) { + std::vector< Node > terms; + getInstantiations( insts, q, terms, qe ); + } void clear() { d_data.clear(); } };/* class InstMatchTrie */ /** trie for InstMatch objects */ class CDInstMatchTrie { -public: +private: /** the data */ std::map< Node, CDInstMatchTrie* > d_data; /** is valid */ context::CDO< bool > d_valid; -private: + void print( std::ostream& out, Node q, std::vector< TNode >& terms ) const; + void getInstantiations( std::vector< Node >& insts, Node q, std::vector< Node >& terms, QuantifiersEngine * qe ) const; public: CDInstMatchTrie( context::Context* c ) : d_valid( c, false ){} - ~CDInstMatchTrie(){} -public: + ~CDInstMatchTrie(); + /** return true if m exists in this trie modEq is if we check modulo equality modInst is if we return true if m is an instance of a match that exists */ - bool existsInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m, context::Context* c, bool modEq = false, - bool modInst = false, int index = 0 ) { - return !addInstMatch( qe, f, m, c, modEq, modInst, index, true ); + bool existsInstMatch( QuantifiersEngine* qe, Node q, InstMatch& m, context::Context* c, bool modEq = false, + int index = 0 ) { + return !addInstMatch( qe, q, m, c, modEq, index, true ); } - bool existsInstMatch( QuantifiersEngine* qe, Node f, std::vector< Node >& m, context::Context* c, bool modEq = false, - bool modInst = false, int index = 0 ) { - return !addInstMatch( qe, f, m, c, modEq, modInst, index, true ); + bool existsInstMatch( QuantifiersEngine* qe, Node q, std::vector< Node >& m, context::Context* c, bool modEq = false, + int index = 0 ) { + return !addInstMatch( qe, q, m, c, modEq, index, true ); } /** add match m for quantifier f, take into account equalities if modEq = true, if imtio is non-null, this is the order to add to trie return true if successful */ - bool addInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m, context::Context* c, bool modEq = false, - bool modInst = false, int index = 0, bool onlyExist = false ) { - return addInstMatch( qe, f, m.d_vals, c, modEq, modInst, index, onlyExist ); + bool addInstMatch( QuantifiersEngine* qe, Node q, InstMatch& m, context::Context* c, bool modEq = false, + int index = 0, bool onlyExist = false ) { + return addInstMatch( qe, q, m.d_vals, c, modEq, index, onlyExist ); } - bool addInstMatch( QuantifiersEngine* qe, Node f, std::vector< Node >& m, context::Context* c, bool modEq = false, - bool modInst = false, int index = 0, bool onlyExist = false ); + bool addInstMatch( QuantifiersEngine* qe, Node q, std::vector< Node >& m, context::Context* c, bool modEq = false, + int index = 0, bool onlyExist = false ); + bool removeInstMatch( QuantifiersEngine* qe, Node q, std::vector< Node >& m, int index = 0 ); void print( std::ostream& out, Node q ) const{ std::vector< TNode > terms; print( out, q, terms ); } + void getInstantiations( std::vector< Node >& insts, Node q, QuantifiersEngine * qe ) { + std::vector< Node > terms; + getInstantiations( insts, q, terms, qe ); + } };/* class CDInstMatchTrie */ @@ -190,10 +202,10 @@ public: public: /** add match m, return true if successful */ bool addInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m, bool modEq = false, bool modInst = false ){ - return d_imt.addInstMatch( qe, f, m, modEq, modInst, d_imtio ); + return d_imt.addInstMatch( qe, f, m, modEq, d_imtio ); } bool existsInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m, bool modEq = false, bool modInst = false ){ - return d_imt.existsInstMatch( qe, f, m, modEq, modInst, d_imtio ); + return d_imt.existsInstMatch( qe, f, m, modEq, d_imtio ); } };/* class InstMatchTrieOrdered */ diff --git a/src/theory/quantifiers/inst_match_generator.cpp b/src/theory/quantifiers/inst_match_generator.cpp index 89c2d4868..bf05de3bb 100644 --- a/src/theory/quantifiers/inst_match_generator.cpp +++ b/src/theory/quantifiers/inst_match_generator.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file inst_match_generator.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** [[ Add lengthier description here ]] ** \todo document this file @@ -40,7 +40,6 @@ InstMatchGenerator::InstMatchGenerator( Node pat ){ d_match_pattern_type = pat.getType(); d_next = NULL; d_matchPolicy = MATCH_GEN_DEFAULT; - d_eq_class_rel = false; } InstMatchGenerator::InstMatchGenerator() { @@ -59,7 +58,7 @@ void InstMatchGenerator::setActiveAdd(bool val){ void InstMatchGenerator::initialize( Node q, QuantifiersEngine* qe, std::vector< InstMatchGenerator * > & gens ){ if( !d_pattern.isNull() ){ - Debug("inst-match-gen") << "Pattern term is " << d_pattern << std::endl; + Trace("inst-match-gen") << "Initialize, 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]; @@ -67,29 +66,23 @@ void InstMatchGenerator::initialize( Node q, QuantifiersEngine* qe, std::vector< if( d_match_pattern.getKind()==IFF || d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==GEQ ){ //make sure the matching portion of the equality is on the LHS of d_pattern // and record what d_match_pattern is - if( !quantifiers::TermDb::hasInstConstAttr(d_match_pattern[0]) || d_match_pattern[0].getKind()==INST_CONSTANT ){ - if( d_match_pattern[1].getKind()!=INST_CONSTANT ){ - Assert( quantifiers::TermDb::hasInstConstAttr(d_match_pattern[1]) ); - Node mp = d_match_pattern[1]; - //swap sides - Node pat = d_pattern; - if(d_match_pattern.getKind()==GEQ){ - d_pattern = NodeManager::currentNM()->mkNode( kind::GT, d_match_pattern[1], d_match_pattern[0] ); - d_pattern = d_pattern.negate(); - }else{ - d_pattern = NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), d_match_pattern[1], d_match_pattern[0] ); - } - d_pattern = pat.getKind()==NOT ? d_pattern.negate() : d_pattern; - d_match_pattern = mp; - } - }else if( !quantifiers::TermDb::hasInstConstAttr(d_match_pattern[1]) || d_match_pattern[1].getKind()==INST_CONSTANT ){ - if( d_match_pattern[0].getKind()!=INST_CONSTANT ){ - Assert( quantifiers::TermDb::hasInstConstAttr(d_match_pattern[0]) ); - if( d_pattern.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching - d_match_pattern = d_match_pattern[0]; - }else if( d_match_pattern[1].getKind()==INST_CONSTANT ){ - d_match_pattern = d_match_pattern[0]; + for( unsigned i=0; i<2; i++ ){ + if( !quantifiers::TermDb::hasInstConstAttr(d_match_pattern[i]) || d_match_pattern[i].getKind()==INST_CONSTANT ){ + Node mp = d_match_pattern[1-i]; + Node mpo = d_match_pattern[i]; + if( mp.getKind()!=INST_CONSTANT ){ + if( i==0 ){ + if( d_match_pattern.getKind()==GEQ ){ + d_pattern = NodeManager::currentNM()->mkNode( kind::GT, mp, mpo ); + d_pattern = d_pattern.negate(); + }else{ + d_pattern = NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), mp, mpo ); + } + } + d_eq_class_rel = mpo; + d_match_pattern = mp; } + break; } } }else if( d_match_pattern.getKind()==APPLY_SELECTOR_TOTAL && d_match_pattern[0].getKind()==INST_CONSTANT && options::purifyDtTriggers() ){ @@ -97,11 +90,10 @@ void InstMatchGenerator::initialize( Node q, QuantifiersEngine* qe, std::vector< } d_match_pattern_type = d_match_pattern.getType(); Trace("inst-match-gen") << "Pattern is " << d_pattern << ", match pattern is " << d_match_pattern << std::endl; - d_match_pattern_op = qe->getTermDatabase()->getOperator( d_match_pattern ); + d_match_pattern_op = qe->getTermDatabase()->getMatchOperator( d_match_pattern ); //now, collect children of d_match_pattern - //int childMatchPolicy = MATCH_GEN_DEFAULT; - for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){ + for( unsigned i=0; i<d_match_pattern.getNumChildren(); i++ ){ Node qa = quantifiers::TermDb::getInstConstAttr(d_match_pattern[i]); if( !qa.isNull() ){ InstMatchGenerator * cimg = Trigger::getInstMatchGenerator( q, d_match_pattern[i] ); @@ -127,9 +119,17 @@ void InstMatchGenerator::initialize( Node q, QuantifiersEngine* qe, std::vector< } //create candidate generator - if( d_match_pattern.getKind()==INST_CONSTANT ){ + if( Trigger::isAtomicTrigger( d_match_pattern ) ){ + //we will be scanning lists trying to find d_match_pattern.getOperator() + d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern ); + //if matching on disequality, inform the candidate generator not to match on eqc + if( d_pattern.getKind()==NOT && ( d_pattern[0].getKind()==IFF || d_pattern[0].getKind()==EQUAL ) ){ + ((inst::CandidateGeneratorQE*)d_cg)->excludeEqc( d_eq_class_rel ); + d_eq_class_rel = Node::null(); + } + }else if( d_match_pattern.getKind()==INST_CONSTANT ){ if( d_pattern.getKind()==APPLY_SELECTOR_TOTAL ){ - Expr selectorExpr = qe->getTermDatabase()->getOperator( d_pattern ).toExpr(); + Expr selectorExpr = qe->getTermDatabase()->getMatchOperator( d_pattern ).toExpr(); size_t selectorIndex = Datatype::cindexOf(selectorExpr); const Datatype& dt = Datatype::datatypeOf(selectorExpr); const DatatypeConstructor& c = dt[selectorIndex]; @@ -139,7 +139,8 @@ void InstMatchGenerator::initialize( Node q, QuantifiersEngine* qe, std::vector< }else{ d_cg = new CandidateGeneratorQEAll( qe, d_match_pattern ); } - }else if( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF ){ + }else if( ( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF ) && + d_match_pattern[0].getKind()==INST_CONSTANT && d_match_pattern[1].getKind()==INST_CONSTANT ){ //we will be producing candidates via literal matching heuristics if( d_pattern.getKind()!=NOT ){ //candidates will be all equalities @@ -148,26 +149,6 @@ void InstMatchGenerator::initialize( Node q, QuantifiersEngine* qe, std::vector< //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()==GEQ || d_pattern.getKind()==GT || d_pattern.getKind()==NOT ){ - Assert( d_matchPolicy==MATCH_GEN_DEFAULT ); - if( d_pattern.getKind()==NOT ){ - if (d_pattern[0][1].getKind()!=INST_CONSTANT) { - Unimplemented("Disequal generator unimplemented"); - }else{ - d_eq_class = d_pattern[0][1]; - } - }else{ - //store the equivalence class that we will call d_cg->reset( ... ) on - d_eq_class = d_pattern[1]; - } - d_eq_class_rel = true; - Assert( Trigger::isAtomicTrigger( d_match_pattern ) ); - //we are matching only in a particular equivalence class - d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern_op ); - }else if( Trigger::isAtomicTrigger( d_match_pattern ) ){ - //we will be scanning lists trying to find d_match_pattern.getOperator() - d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern_op ); }else{ d_cg = new CandidateGeneratorQueue; Trace("inst-match-gen-warn") << "(?) Unknown matching pattern is " << d_match_pattern << std::endl; @@ -197,7 +178,7 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi Assert( !Trigger::isAtomicTrigger( d_match_pattern ) || t.getOperator()==d_match_pattern.getOperator() ); //first, check if ground arguments are not equal, or a match is in conflict Trace("matching-debug2") << "Setting immediate matches..." << std::endl; - for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){ + for( unsigned i=0; i<d_match_pattern.getNumChildren(); i++ ){ if( d_children_types[i]==0 ){ Trace("matching-debug2") << "Setting " << d_var_num[i] << " to " << t[i] << "..." << std::endl; bool addToPrev = m.get( d_var_num[i] ).isNull(); @@ -231,8 +212,8 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi } } //for relational matching - }else if( d_eq_class_rel && d_eq_class.getKind()==INST_CONSTANT ){ - int v = d_eq_class.getAttribute(InstVarNumAttribute()); + }else if( !d_eq_class_rel.isNull() && d_eq_class_rel.getKind()==INST_CONSTANT ){ + int v = d_eq_class_rel.getAttribute(InstVarNumAttribute()); //also must fit match to equivalence class bool pol = d_pattern.getKind()!=NOT; Node pat = d_pattern.getKind()==NOT ? d_pattern[0] : d_pattern; @@ -289,7 +270,7 @@ bool InstMatchGenerator::continueNextMatch( Node f, InstMatch& m, QuantifiersEng return d_next->getNextMatch( f, m, qe ); }else{ if( d_active_add ){ - return qe->addInstantiation( f, m, false ); + return qe->addInstantiation( f, m ); }else{ return true; } @@ -313,20 +294,22 @@ void InstMatchGenerator::resetInstantiationRound( QuantifiersEngine* qe ){ void InstMatchGenerator::reset( Node eqc, QuantifiersEngine* qe ){ eqc = qe->getEqualityQuery()->getRepresentative( eqc ); Trace("matching-debug2") << this << " reset " << eqc << "." << std::endl; - if( !eqc.isNull() ){ + if( !d_eq_class_rel.isNull() && d_eq_class_rel.getKind()!=INST_CONSTANT ){ + d_eq_class = d_eq_class_rel; + }else 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_rel ? Node::null() : d_eq_class ); + d_cg->reset( d_eq_class ); d_needsReset = false; } bool InstMatchGenerator::getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ){ if( d_needsReset ){ Trace("matching") << "Reset not done yet, must do the reset..." << std::endl; - reset( d_eq_class_rel ? Node::null() : d_eq_class, qe ); + reset( d_eq_class, qe ); } m.d_matched = Node::null(); Trace("matching") << this << " " << d_match_pattern << " get next match " << m << " in eq class " << d_eq_class << std::endl; @@ -346,7 +329,7 @@ bool InstMatchGenerator::getNextMatch( Node f, InstMatch& m, QuantifiersEngine* if( !success ){ Trace("matching") << this << " failed, reset " << d_eq_class << std::endl; //we failed, must reset - reset( d_eq_class_rel ? Node::null() : d_eq_class, qe ); + reset( d_eq_class, qe ); } return success; } @@ -360,11 +343,17 @@ int InstMatchGenerator::addInstantiations( Node f, InstMatch& baseMatch, Quantif while( getNextMatch( f, m, qe ) ){ if( !d_active_add ){ m.add( baseMatch ); - if( qe->addInstantiation( f, m, false ) ){ + if( qe->addInstantiation( f, m ) ){ addedLemmas++; + if( qe->inConflict() ){ + break; + } } }else{ addedLemmas++; + if( qe->inConflict() ){ + break; + } } m.clear(); } @@ -377,12 +366,12 @@ int InstMatchGenerator::addTerm( Node f, Node t, QuantifiersEngine* qe ){ if( !d_match_pattern.isNull() ){ InstMatch m( f ); if( getMatch( f, t, m, qe ) ){ - if( qe->addInstantiation( f, m, false ) ){ + if( qe->addInstantiation( f, m ) ){ return 1; } } }else{ - for( int i=0; i<(int)d_children.size(); i++ ){ + for( unsigned i=0; i<d_children.size(); i++ ){ d_children[i]->addTerm( f, t, qe ); } } @@ -544,14 +533,14 @@ d_f( q ){ /** reset instantiation round (call this whenever equivalence classes have changed) */ void InstMatchGeneratorMulti::resetInstantiationRound( QuantifiersEngine* qe ){ - for( int i=0; i<(int)d_children.size(); i++ ){ + for( unsigned i=0; i<d_children.size(); i++ ){ d_children[i]->resetInstantiationRound( qe ); } } /** reset, eqc is the equivalence class to search in (any if eqc=null) */ void InstMatchGeneratorMulti::reset( Node eqc, QuantifiersEngine* qe ){ - for( int i=0; i<(int)d_children.size(); i++ ){ + for( unsigned i=0; i<d_children.size(); i++ ){ d_children[i]->reset( eqc, qe ); } } @@ -559,7 +548,7 @@ void InstMatchGeneratorMulti::reset( Node eqc, QuantifiersEngine* qe ){ int InstMatchGeneratorMulti::addInstantiations( Node q, InstMatch& baseMatch, QuantifiersEngine* qe ){ int addedLemmas = 0; Debug("smart-multi-trigger") << "Process smart multi trigger" << std::endl; - for( int i=0; i<(int)d_children.size(); i++ ){ + for( unsigned i=0; i<d_children.size(); i++ ){ Debug("smart-multi-trigger") << "Calculate matches " << i << std::endl; std::vector< InstMatch > newMatches; InstMatch m( q ); @@ -569,8 +558,11 @@ int InstMatchGeneratorMulti::addInstantiations( Node q, InstMatch& baseMatch, Qu m.clear(); } Debug("smart-multi-trigger") << "Made " << newMatches.size() << " new matches for index " << i << std::endl; - for( int j=0; j<(int)newMatches.size(); j++ ){ + for( unsigned j=0; j<newMatches.size(); j++ ){ processNewMatch( qe, newMatches[j], i, addedLemmas ); + if( qe->inConflict() ){ + return addedLemmas; + } } } return addedLemmas; @@ -593,6 +585,7 @@ void InstMatchGeneratorMulti::processNewMatch( QuantifiersEngine* qe, InstMatch& void InstMatchGeneratorMulti::processNewInstantiations( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, InstMatchTrie* tr, std::vector< IndexedTrie >& unique_var_tries, int trieIndex, int childIndex, int endChildIndex, bool modEq ){ + Assert( !qe->inConflict() ); if( childIndex==endChildIndex ){ //now, process unique variables processNewInstantiations2( qe, m, addedLemmas, unique_var_tries, 0 ); @@ -614,6 +607,9 @@ void InstMatchGeneratorMulti::processNewInstantiations( QuantifiersEngine* qe, I mn.setValue( curr_index, it->first); processNewInstantiations( qe, mn, addedLemmas, &(it->second), unique_var_tries, trieIndex+1, childIndex, endChildIndex, modEq ); + if( qe->inConflict() ){ + break; + } } //} }else{ @@ -635,6 +631,9 @@ void InstMatchGeneratorMulti::processNewInstantiations( QuantifiersEngine* qe, I if( itc!=tr->d_data.end() ){ processNewInstantiations( qe, m, addedLemmas, &(itc->second), unique_var_tries, trieIndex+1, childIndex, endChildIndex, modEq ); + if( qe->inConflict() ){ + break; + } } } ++eqc; @@ -666,13 +665,16 @@ void InstMatchGeneratorMulti::processNewInstantiations2( QuantifiersEngine* qe, InstMatch mn( &m ); mn.setValue( curr_index, it->first); processNewInstantiations2( qe, mn, addedLemmas, unique_var_tries, uvtIndex, &(it->second), trieIndex+1 ); + if( qe->inConflict() ){ + break; + } } }else{ processNewInstantiations2( qe, m, addedLemmas, unique_var_tries, uvtIndex+1 ); } }else{ //m is an instantiation - if( qe->addInstantiation( d_f, m, false ) ){ + if( qe->addInstantiation( d_f, m ) ){ addedLemmas++; Debug("smart-multi-trigger") << "-> Produced instantiation " << m << std::endl; } @@ -683,7 +685,7 @@ int InstMatchGeneratorMulti::addTerm( Node q, Node t, QuantifiersEngine* qe ){ Assert( options::eagerInstQuant() ); int addedLemmas = 0; for( int i=0; i<(int)d_children.size(); i++ ){ - Node t_op = qe->getTermDatabase()->getOperator( t ); + Node t_op = qe->getTermDatabase()->getMatchOperator( t ); if( ((InstMatchGenerator*)d_children[i])->d_match_pattern_op==t_op ){ InstMatch m( q ); //if it produces a match, then process it with the rest @@ -696,6 +698,18 @@ int InstMatchGeneratorMulti::addTerm( Node q, Node t, QuantifiersEngine* qe ){ } InstMatchGeneratorSimple::InstMatchGeneratorSimple( Node q, Node pat ) : d_f( q ), d_match_pattern( pat ) { + if( d_match_pattern.getKind()==NOT ){ + d_match_pattern = d_match_pattern[0]; + d_pol = false; + }else{ + d_pol = true; + } + if( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF ){ + d_eqc = d_match_pattern[1]; + d_match_pattern = d_match_pattern[0]; + Assert( !quantifiers::TermDb::hasInstConstAttr( d_eqc ) ); + } + Assert( Trigger::isSimpleTrigger( d_match_pattern ) ); for( unsigned i=0; i<d_match_pattern.getNumChildren(); i++ ){ if( d_match_pattern[i].getKind()==INST_CONSTANT ){ if( !options::cbqi() || quantifiers::TermDb::getInstConstAttr(d_match_pattern[i])==q ){ @@ -709,15 +723,39 @@ InstMatchGeneratorSimple::InstMatchGeneratorSimple( Node q, Node pat ) : d_f( q } void InstMatchGeneratorSimple::resetInstantiationRound( QuantifiersEngine* qe ) { - d_op = qe->getTermDatabase()->getOperator( d_match_pattern ); + d_op = qe->getTermDatabase()->getMatchOperator( d_match_pattern ); } int InstMatchGeneratorSimple::addInstantiations( Node q, InstMatch& baseMatch, QuantifiersEngine* qe ){ - InstMatch m( q ); - m.add( baseMatch ); int addedLemmas = 0; - - addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_func_map_trie[ d_op ]) ); + quantifiers::TermArgTrie* tat; + if( d_eqc.isNull() ){ + tat = qe->getTermDatabase()->getTermArgTrie( d_op ); + }else{ + if( d_pol ){ + tat = qe->getTermDatabase()->getTermArgTrie( d_eqc, d_op ); + }else{ + Node r = qe->getEqualityQuery()->getRepresentative( d_eqc ); + //iterate over all classes except r + tat = qe->getTermDatabase()->getTermArgTrie( Node::null(), d_op ); + for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = tat->d_data.begin(); it != tat->d_data.end(); ++it ){ + if( it->first!=r ){ + InstMatch m( q ); + m.add( baseMatch ); + addInstantiations( m, qe, addedLemmas, 0, &(it->second) ); + if( qe->inConflict() ){ + break; + } + } + } + tat = NULL; + } + } + if( tat ){ + InstMatch m( q ); + m.add( baseMatch ); + addInstantiations( m, qe, addedLemmas, 0, tat ); + } return addedLemmas; } @@ -725,14 +763,14 @@ void InstMatchGeneratorSimple::addInstantiations( InstMatch& m, QuantifiersEngin Debug("simple-trigger-debug") << "Add inst " << argIndex << " " << d_match_pattern << std::endl; if( argIndex==(int)d_match_pattern.getNumChildren() ){ Assert( !tat->d_data.empty() ); - Node t = tat->d_data.begin()->first; + TNode t = tat->getNodeData(); Debug("simple-trigger") << "Actual term is " << t << std::endl; //convert to actual used terms for( std::map< int, int >::iterator it = d_var_num.begin(); it != d_var_num.end(); ++it ){ Debug("simple-trigger") << "...set " << it->second << " " << t[it->first] << std::endl; m.setValue( it->second, t[it->first] ); } - if( qe->addInstantiation( d_f, m, false ) ){ + if( qe->addInstantiation( d_f, m ) ){ addedLemmas++; Debug("simple-trigger") << "-> Produced instantiation " << m << std::endl; } @@ -749,10 +787,14 @@ void InstMatchGeneratorSimple::addInstantiations( InstMatch& m, QuantifiersEngin m.setValue( v, t); addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) ); m.setValue( v, prev); + if( qe->inConflict() ){ + break; + } } } return; } + //inst constant from another quantified formula, treat as ground term TODO: remove this? } Node r = qe->getEqualityQuery()->getRepresentative( d_match_pattern[argIndex] ); std::map< TNode, quantifiers::TermArgTrie >::iterator it = tat->d_data.find( r ); @@ -763,16 +805,17 @@ void InstMatchGeneratorSimple::addInstantiations( InstMatch& m, QuantifiersEngin } int InstMatchGeneratorSimple::addTerm( Node q, Node t, QuantifiersEngine* qe ){ + //for eager instantiation only Assert( options::eagerInstQuant() ); InstMatch m( q ); - for( int i=0; i<(int)t.getNumChildren(); i++ ){ + for( unsigned i=0; i<t.getNumChildren(); i++ ){ if( d_match_pattern[i].getKind()==INST_CONSTANT ){ m.setValue(d_var_num[i], t[i]); }else if( !qe->getEqualityQuery()->areEqual( d_match_pattern[i], t[i] ) ){ return 0; } } - return qe->addInstantiation( q, m, false ) ? 1 : 0; + return qe->addInstantiation( q, m ) ? 1 : 0; } }/* CVC4::theory::inst namespace */ diff --git a/src/theory/quantifiers/inst_match_generator.h b/src/theory/quantifiers/inst_match_generator.h index 75adeb2d8..a1d907001 100644 --- a/src/theory/quantifiers/inst_match_generator.h +++ b/src/theory/quantifiers/inst_match_generator.h @@ -1,13 +1,13 @@ /********************* */ /*! \file inst_match_generator.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Morgan Deters, Andrew Reynolds, Clark Barrett ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief inst match generator class **/ @@ -64,7 +64,7 @@ protected: InstMatchGenerator* d_next; /** eq class */ Node d_eq_class; - bool d_eq_class_rel; + Node d_eq_class_rel; /** variable numbers */ std::map< int, int > d_var_num; /** initialize pattern */ @@ -211,6 +211,9 @@ private: Node d_f; /** match term */ Node d_match_pattern; + /** equivalence class */ + bool d_pol; + Node d_eqc; /** match pattern arg types */ std::vector< TypeNode > d_match_pattern_arg_types; /** operator */ diff --git a/src/theory/quantifiers/inst_propagator.cpp b/src/theory/quantifiers/inst_propagator.cpp new file mode 100644 index 000000000..d4be58636 --- /dev/null +++ b/src/theory/quantifiers/inst_propagator.cpp @@ -0,0 +1,761 @@ +/********************* */ +/*! \file inst_propagator.cpp + ** \verbatim + ** Top contributors (to current version): + ** Andrew Reynolds + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim + ** + ** Propagate mechanism for instantiations + **/ + +#include <vector> + +#include "theory/quantifiers/inst_propagator.h" +#include "theory/rewriter.h" +#include "theory/quantifiers/term_database.h" + +using namespace CVC4; +using namespace std; +using namespace CVC4::theory; +using namespace CVC4::theory::quantifiers; +using namespace CVC4::kind; + + +EqualityQueryInstProp::EqualityQueryInstProp( QuantifiersEngine* qe ) : d_qe( qe ){ + d_true = NodeManager::currentNM()->mkConst( true ); + d_false = NodeManager::currentNM()->mkConst( false ); +} + +bool EqualityQueryInstProp::reset( Theory::Effort e ) { + d_uf.clear(); + d_uf_exp.clear(); + d_diseq_list.clear(); + return true; +} + +/** contains term */ +bool EqualityQueryInstProp::hasTerm( Node a ) { + if( getEngine()->hasTerm( a ) ){ + return true; + }else{ + std::vector< Node > exp; + Node ar = getUfRepresentative( a, exp ); + return !ar.isNull() && getEngine()->hasTerm( ar ); + } +} + +/** get the representative of the equivalence class of a */ +Node EqualityQueryInstProp::getRepresentative( Node a ) { + if( getEngine()->hasTerm( a ) ){ + a = getEngine()->getRepresentative( a ); + } + std::vector< Node > exp; + Node ar = getUfRepresentative( a, exp ); + return ar.isNull() ? a : ar; +} + +/** returns true if a and b are equal in the current context */ +bool EqualityQueryInstProp::areEqual( Node a, Node b ) { + if( a==b ){ + return true; + }else{ + eq::EqualityEngine* ee = getEngine(); + if( ee->hasTerm( a ) && ee->hasTerm( b ) ){ + if( ee->areEqual( a, b ) ){ + return true; + } + } + return false; + } +} + +/** returns true is a and b are disequal in the current context */ +bool EqualityQueryInstProp::areDisequal( Node a, Node b ) { + if( a==b ){ + return false; + }else{ + eq::EqualityEngine* ee = getEngine(); + if( ee->hasTerm( a ) && ee->hasTerm( b ) ){ + if( ee->areDisequal( a, b, false ) ){ + return true; + } + } + return false; + } +} + +/** get the equality engine associated with this query */ +eq::EqualityEngine* EqualityQueryInstProp::getEngine() { + return d_qe->getMasterEqualityEngine(); +} + +/** get the equivalence class of a */ +void EqualityQueryInstProp::getEquivalenceClass( Node a, std::vector< Node >& eqc ) { + //TODO? +} + +TNode EqualityQueryInstProp::getCongruentTerm( Node f, std::vector< TNode >& args ) { + TNode t = d_qe->getTermDatabase()->getCongruentTerm( f, args ); + if( !t.isNull() ){ + return t; + }else{ + //TODO? + return TNode::null(); + } +} + +Node EqualityQueryInstProp::getRepresentativeExp( Node a, std::vector< Node >& exp ) { + bool engine_has_a = getEngine()->hasTerm( a ); + if( engine_has_a ){ + a = getEngine()->getRepresentative( a ); + } + //get union find representative, if this occurs in the equality engine, return it + unsigned prev_size = exp.size(); + Node ar = getUfRepresentative( a, exp ); + if( !ar.isNull() ){ + if( engine_has_a || getEngine()->hasTerm( ar ) ){ + Assert( getEngine()->hasTerm( ar ) ); + Assert( getEngine()->getRepresentative( ar )==ar ); + return ar; + } + }else{ + if( engine_has_a ){ + return a; + } + } + //retract explanation + while( exp.size()>prev_size ){ + exp.pop_back(); + } + return Node::null(); +} + +bool EqualityQueryInstProp::areEqualExp( Node a, Node b, std::vector< Node >& exp ) { + if( areEqual( a, b ) ){ + return true; + }else{ + std::vector< Node > exp_a; + Node ar = getUfRepresentative( a, exp_a ); + if( !ar.isNull() ){ + std::vector< Node > exp_b; + if( ar==getUfRepresentative( b, exp_b ) ){ + merge_exp( exp, exp_a ); + merge_exp( exp, exp_b ); + return true; + } + } + return false; + } +} + +bool EqualityQueryInstProp::areDisequalExp( Node a, Node b, std::vector< Node >& exp ) { + if( areDisequal( a, b ) ){ + return true; + }else{ + //Assert( getRepresentative( a )==a ); + //Assert( getRepresentative( b )==b ); + std::map< Node, std::vector< Node > >::iterator itd = d_diseq_list[a].find( b ); + if( itd!=d_diseq_list[a].end() ){ + exp.insert( exp.end(), itd->second.begin(), itd->second.end() ); + return true; + }else{ + return false; + } + } +} + +Node EqualityQueryInstProp::getUfRepresentative( Node a, std::vector< Node >& exp ) { + Assert( exp.empty() ); + std::map< Node, Node >::iterator it = d_uf.find( a ); + if( it!=d_uf.end() ){ + if( it->second==a ){ + Assert( d_uf_exp[ a ].empty() ); + return it->second; + }else{ + Node m = getUfRepresentative( it->second, exp ); + Assert( !m.isNull() ); + if( m!=it->second ){ + //update union find + d_uf[ a ] = m; + //update explanation : merge the explanation of the parent + merge_exp( d_uf_exp[ a ], exp ); + Trace("qip-eq") << "EqualityQueryInstProp::getUfRepresentative : merge " << a << " -> " << m << ", exp size=" << d_uf_exp[ a ].size() << std::endl; + } + //add current explanation to exp: note that exp is a subset of d_uf_exp[ a ], reset + exp.clear(); + exp.insert( exp.end(), d_uf_exp[ a ].begin(), d_uf_exp[ a ].end() ); + return m; + } + }else{ + return Node::null(); + } +} + +// set a == b with reason, return status, modify a and b to representatives pre-merge +int EqualityQueryInstProp::setEqual( Node& a, Node& b, bool pol, std::vector< Node >& reason ) { + if( a==b ){ + return pol ? STATUS_NONE : STATUS_CONFLICT; + } + int status = pol ? STATUS_MERGED_UNKNOWN : STATUS_NONE; + Trace("qip-eq") << "EqualityQueryInstProp::setEqual " << a << ", " << b << ", pol = " << pol << ", reason size = " << reason.size() << std::endl; + //get the representative for a + std::vector< Node > exp_a; + Node ar = getUfRepresentative( a, exp_a ); + if( ar.isNull() ){ + Assert( exp_a.empty() ); + ar = a; + } + if( ar==b ){ + Trace("qip-eq") << "EqualityQueryInstProp::setEqual : already equal" << std::endl; + if( pol ){ + return STATUS_NONE; + }else{ + merge_exp( reason, exp_a ); + return STATUS_CONFLICT; + } + } + bool swap = false; + //get the representative for b + std::vector< Node > exp_b; + Node br = getUfRepresentative( b, exp_b ); + if( br.isNull() ){ + Assert( exp_b.empty() ); + br = b; + if( !getEngine()->hasTerm( br ) ){ + if( ar!=a || getEngine()->hasTerm( ar ) ){ + swap = true; + } + }else{ + if( getEngine()->hasTerm( ar ) ){ + status = STATUS_MERGED_KNOWN; + } + } + }else{ + if( ar==br ){ + Trace("qip-eq") << "EqualityQueryInstProp::setEqual : already equal" << std::endl; + if( pol ){ + return STATUS_NONE; + }else{ + merge_exp( reason, exp_a ); + merge_exp( reason, exp_b ); + return STATUS_CONFLICT; + } + }else if( getEngine()->hasTerm( ar ) ){ + if( getEngine()->hasTerm( br ) ){ + status = STATUS_MERGED_KNOWN; + }else{ + swap = true; + } + } + } + + if( swap ){ + //swap + Node temp_r = ar; + ar = br; + br = temp_r; + } + + Assert( !getEngine()->hasTerm( ar ) || getEngine()->hasTerm( br ) ); + Assert( ar!=br ); + + std::vector< Node > exp_d; + if( areDisequalExp( ar, br, exp_d ) ){ + if( pol ){ + merge_exp( reason, exp_b ); + merge_exp( reason, exp_b ); + merge_exp( reason, exp_d ); + return STATUS_CONFLICT; + }else{ + return STATUS_NONE; + } + }else{ + if( pol ){ + //update the union find + Assert( d_uf_exp[ar].empty() ); + Assert( d_uf_exp[br].empty() ); + + d_uf[ar] = br; + merge_exp( d_uf_exp[ar], exp_a ); + merge_exp( d_uf_exp[ar], exp_b ); + merge_exp( d_uf_exp[ar], reason ); + + d_uf[br] = br; + d_uf_exp[br].clear(); + + Trace("qip-eq") << "EqualityQueryInstProp::setEqual : merge " << ar << " -> " << br << ", exp size = " << d_uf_exp[ar].size() << ", status = " << status << std::endl; + a = ar; + b = br; + + //carry disequality list + std::map< Node, std::map< Node, std::vector< Node > > >::iterator itd = d_diseq_list.find( ar ); + if( itd!=d_diseq_list.end() ){ + for( std::map< Node, std::vector< Node > >::iterator itdd = itd->second.begin(); itdd != itd->second.end(); ++itdd ){ + Node d = itdd->first; + if( d_diseq_list[br].find( d )==d_diseq_list[br].end() ){ + merge_exp( d_diseq_list[br][d], itdd->second ); + merge_exp( d_diseq_list[br][d], d_uf_exp[ar] ); + } + } + } + + return status; + }else{ + Trace("qip-eq") << "EqualityQueryInstProp::setEqual : disequal " << ar << " <> " << br << std::endl; + Assert( d_diseq_list[ar].find( br )==d_diseq_list[ar].end() ); + Assert( d_diseq_list[br].find( ar )==d_diseq_list[br].end() ); + + merge_exp( d_diseq_list[ar][br], reason ); + merge_exp( d_diseq_list[br][ar], reason ); + return STATUS_NONE; + } + } +} + +void EqualityQueryInstProp::addArgument( std::vector< Node >& args, std::vector< Node >& props, Node n, bool is_prop, bool pol ) { + if( is_prop ){ + if( isLiteral( n ) ){ + props.push_back( pol ? n : n.negate() ); + return; + } + } + args.push_back( n ); +} + +bool EqualityQueryInstProp::isLiteral( Node n ) { + Kind ak = n.getKind()==NOT ? n[0].getKind() : n.getKind(); + Assert( ak!=NOT ); + return ak!=AND && ak!=OR && ak!=IFF && ak!=ITE; +} + +//this is identical to TermDb::evaluateTerm2, but tracks more information +Node EqualityQueryInstProp::evaluateTermExp( Node n, std::vector< Node >& exp, std::map< Node, Node >& visited, bool hasPol, bool pol, + std::map< Node, bool >& watch_list_out, std::vector< Node >& props ) { + std::map< Node, Node >::iterator itv = visited.find( n ); + if( itv != visited.end() ){ + return itv->second; + }else{ + visited[n] = n; + Trace("qip-eval") << "evaluate term : " << n << std::endl; + std::vector< Node > exp_n; + Node ret = getRepresentativeExp( n, exp_n ); + if( ret.isNull() ){ + //term is not known to be equal to a representative in equality engine, evaluate it + Kind k = n.getKind(); + if( k==FORALL ){ + ret = Node::null(); + }else{ + std::map< Node, bool > watch_list_out_curr; + TNode f = d_qe->getTermDatabase()->getMatchOperator( n ); + std::vector< Node > args; + bool ret_set = false; + bool childChanged = false; + int abort_i = -1; + //get the child entailed polarity + Assert( n.getKind()!=IMPLIES ); + bool newHasPol, newPol; + QuantPhaseReq::getEntailPolarity( n, 0, hasPol, pol, newHasPol, newPol ); + //for each child + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + Node c = evaluateTermExp( n[i], exp, visited, newHasPol, newPol, watch_list_out_curr, props ); + if( c.isNull() ){ + ret = Node::null(); + ret_set = true; + break; + }else if( c==d_true || c==d_false ){ + //short-circuiting + if( k==kind::AND || k==kind::OR ){ + if( (k==kind::AND)==(c==d_false) ){ + ret = c; + ret_set = true; + break; + }else{ + //redundant + c = Node::null(); + childChanged = true; + } + }else if( k==kind::ITE && i==0 ){ + Assert( watch_list_out_curr.empty() ); + ret = evaluateTermExp( n[ c==d_true ? 1 : 2], exp, visited, hasPol, pol, watch_list_out_curr, props ); + ret_set = true; + break; + }else if( k==kind::NOT ){ + ret = c==d_true ? d_false : d_true; + ret_set = true; + break; + } + } + if( !c.isNull() ){ + childChanged = childChanged || n[i]!=c; + if( !f.isNull() && !watch_list_out_curr.empty() ){ + // we are done if this is an UF application and an argument is unevaluated + args.push_back( c ); + abort_i = i; + break; + }else if( ( k==kind::AND || k==kind::OR ) ){ + if( c.getKind()==k ){ + //flatten + for( unsigned j=0; j<c.getNumChildren(); j++ ){ + addArgument( args, props, c[j], newHasPol, newPol ); + } + }else{ + addArgument( args, props, c, newHasPol, newPol ); + } + //if we are in a branching position + if( hasPol && !newHasPol && args.size()>=2 ){ + //we are done if at least two args are unevaluated + abort_i = i; + break; + } + }else if( k==kind::ITE ){ + //we are done if we are ITE and condition is unevaluated + Assert( i==0 ); + args.push_back( c ); + abort_i = i; + break; + }else{ + args.push_back( c ); + } + } + } + //add remaining children if we aborted + if( abort_i!=-1 ){ + for( int i=(abort_i+1); i<(int)n.getNumChildren(); i++ ){ + args.push_back( n[i] ); + } + } + //copy over the watch list + for( std::map< Node, bool >::iterator itc = watch_list_out_curr.begin(); itc != watch_list_out_curr.end(); ++itc ){ + watch_list_out[itc->first] = itc->second; + } + + //if we have not short-circuited evaluation + if( !ret_set ){ + //if it is an indexed term, return the congruent term + if( !f.isNull() && watch_list_out.empty() ){ + std::vector< TNode > t_args; + for( unsigned i=0; i<args.size(); i++ ) { + t_args.push_back( args[i] ); + } + Assert( args.size()==n.getNumChildren() ); + //args contains terms known by the equality engine + TNode nn = getCongruentTerm( f, t_args ); + Trace("qip-eval") << " got congruent term " << nn << " from DB for " << n << std::endl; + if( !nn.isNull() ){ + //successfully constructed representative in EE + Assert( exp_n.empty() ); + ret = getRepresentativeExp( nn, exp_n ); + Trace("qip-eval") << "return rep, exp size = " << exp_n.size() << std::endl; + merge_exp( exp, exp_n ); + ret_set = true; + Assert( !ret.isNull() ); + } + } + if( !ret_set ){ + if( childChanged ){ + Trace("qip-eval") << "return rewrite" << std::endl; + if( ( k==kind::AND || k==kind::OR ) ){ + if( args.empty() ){ + ret = k==kind::AND ? d_true : d_false; + ret_set = true; + }else if( args.size()==1 ){ + ret = args[0]; + ret_set = true; + } + }else{ + Assert( args.size()==n.getNumChildren() ); + } + if( !ret_set ){ + if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){ + args.insert( args.begin(), n.getOperator() ); + } + ret = NodeManager::currentNM()->mkNode( k, args ); + ret = Rewriter::rewrite( ret ); + //re-evaluate + Node ret_eval = getRepresentativeExp( ret, exp_n ); + if( !ret_eval.isNull() ){ + ret = ret_eval; + watch_list_out.clear(); + }else{ + watch_list_out[ret] = true; + } + } + }else{ + ret = n; + watch_list_out[ret] = true; + } + } + } + } + }else{ + Trace("qip-eval") << "...exists in ee, return rep, exp size = " << exp_n.size() << std::endl; + merge_exp( exp, exp_n ); + } + Trace("qip-eval") << "evaluated term : " << n << ", got : " << ret << ", exp size = " << exp.size() << std::endl; + visited[n] = ret; + return ret; + } +} + +void EqualityQueryInstProp::merge_exp( std::vector< Node >& v, std::vector< Node >& v_to_merge, int up_to_size ) { + //TODO : optimize + if( v.empty() ){ + Assert( up_to_size==-1 || up_to_size==(int)v_to_merge.size() ); + v.insert( v.end(), v_to_merge.begin(), v_to_merge.end() ); + }else{ + //std::vector< Node >::iterator v_end = v.end(); + up_to_size = up_to_size==-1 ? (int)v_to_merge.size() : up_to_size; + for( int j=0; j<up_to_size; j++ ){ + if( std::find( v.begin(), v.end(), v_to_merge[j] )==v.end() ){ + v.push_back( v_to_merge[j] ); + } + } + } +} + + +void InstPropagator::InstInfo::init( Node q, Node lem, std::vector< Node >& terms, Node body ) { + d_active = true; + //information about the instance + d_q = q; + d_lem = lem; + Assert( d_terms.empty() ); + d_terms.insert( d_terms.end(), terms.begin(), terms.end() ); + //the current lemma + d_curr = body; + d_curr_exp.push_back( body ); +} + +InstPropagator::InstPropagator( QuantifiersEngine* qe ) : +d_qe( qe ), d_notify(*this), d_qy( qe ){ +} + +bool InstPropagator::reset( Theory::Effort e ) { + d_icount = 1; + d_ii.clear(); + for( unsigned i=0; i<2; i++ ){ + d_conc_to_id[i].clear(); + d_conc_to_id[i][d_qy.d_true] = 0; + } + d_conflict = false; + d_watch_list.clear(); + d_update_list.clear(); + d_relevant_inst.clear(); + return d_qy.reset( e ); +} + +bool InstPropagator::notifyInstantiation( unsigned quant_e, Node q, Node lem, std::vector< Node >& terms, Node body ) { + if( !d_conflict ){ + if( Trace.isOn("qip-prop") ){ + Trace("qip-prop") << "InstPropagator:: Notify instantiation " << q << " : " << std::endl; + for( unsigned i=0; i<terms.size(); i++ ){ + Trace("qip-prop") << " " << terms[i] << std::endl; + } + } + unsigned id = d_icount; + d_icount++; + Trace("qip-prop") << "...assign id=" << id << std::endl; + d_ii[id].init( q, lem, terms, body ); + //initialize the information + if( cacheConclusion( id, body ) ){ + Assert( d_update_list.empty() ); + d_update_list.push_back( id ); + bool firstTime = true; + //update infos in the update list until empty + do { + unsigned uid = d_update_list.back(); + d_update_list.pop_back(); + if( d_ii[uid].d_active ){ + update( uid, d_ii[uid], firstTime ); + } + firstTime = false; + }while( !d_conflict && !d_update_list.empty() ); + }else{ + d_ii[id].d_active = false; + Trace("qip-prop") << "...duplicate." << std::endl; + } + Trace("qip-prop") << "...finished notify instantiation." << std::endl; + return !d_conflict; + }else{ + Assert( false ); + return true; + } +} + +bool InstPropagator::update( unsigned id, InstInfo& ii, bool firstTime ) { + Assert( !d_conflict ); + Assert( ii.d_active ); + Trace("qip-prop-debug") << "Update info [" << id << "]..." << std::endl; + //update the evaluation of the current lemma + std::map< Node, Node > visited; + std::map< Node, bool > watch_list; + std::vector< Node > props; + Node eval = d_qy.evaluateTermExp( ii.d_curr, ii.d_curr_exp, visited, true, true, watch_list, props ); + if( eval.isNull() ){ + ii.d_active = false; + }else if( firstTime || eval!=ii.d_curr ){ + if( EqualityQueryInstProp::isLiteral( eval ) ){ + props.push_back( eval ); + eval = d_qy.d_true; + watch_list.clear(); + } + if( Trace.isOn("qip-prop") ){ + Trace("qip-prop") << "Update info [" << id << "]..." << std::endl; + Trace("qip-prop") << "...updated lemma " << ii.d_curr << " -> " << eval << ", exp = "; + debugPrintExplanation( ii.d_curr_exp, "qip-prop" ); + Trace("qip-prop") << std::endl; + Trace("qip-prop") << "...watch list: " << std::endl; + for( std::map< Node, bool >::iterator itw = watch_list.begin(); itw!=watch_list.end(); ++itw ){ + Trace("qip-prop") << " " << itw->first << std::endl; + } + Trace("qip-prop") << "...new propagations: " << std::endl; + for( unsigned i=0; i<props.size(); i++ ){ + Trace("qip-prop") << " " << props[i] << std::endl; + } + Trace("qip-prop") << std::endl; + } + //determine the status of eval + if( eval==d_qy.d_false ){ + Assert( props.empty() ); + //we have inferred a conflict + conflict( ii.d_curr_exp ); + return false; + }else{ + for( unsigned i=0; i<props.size(); i++ ){ + Trace("qip-prop-debug2") << "Process propagation " << props[i] << std::endl; + //if we haven't propagated this literal yet + if( cacheConclusion( id, props[i], 1 ) ){ + Node lit = props[i].getKind()==NOT ? props[i][0] : props[i]; + bool pol = props[i].getKind()!=NOT; + if( lit.getKind()==EQUAL ){ + propagate( lit[0], lit[1], pol, ii.d_curr_exp ); + }else{ + propagate( lit, pol ? d_qy.d_true : d_qy.d_false, true, ii.d_curr_exp ); + } + if( d_conflict ){ + return false; + } + } + Trace("qip-prop-debug2") << "Done process propagation " << props[i] << std::endl; + } + //if we have not inferred this conclusion yet + if( cacheConclusion( id, eval ) ){ + ii.d_curr = eval; + //update the watch list + Trace("qip-prop-debug") << "...updating watch list for [" << id << "], curr is " << ii.d_curr << std::endl; + //Here, we need to be notified of enough terms such that if we are not notified, then update( ii ) will return no propagations. + // Similar to two-watched literals, but since we are in UF, we need to watch all terms on a complete path of two terms. + for( std::map< Node, bool >::iterator itw = watch_list.begin(); itw != watch_list.end(); ++itw ){ + d_watch_list[ itw->first ][ id ] = true; + } + }else{ + Trace("qip-prop-debug") << "...conclusion " << eval << " is duplicate." << std::endl; + ii.d_active = false; + } + } + }else{ + Trace("qip-prop-debug") << "...did not update." << std::endl; + } + Assert( !d_conflict ); + return true; +} + +void InstPropagator::propagate( Node a, Node b, bool pol, std::vector< Node >& exp ) { + if( Trace.isOn("qip-propagate") ){ + Trace("qip-propagate") << "* Propagate " << a << ( pol ? " == " : " != " ) << b << ", exp = "; + debugPrintExplanation( exp, "qip-propagate" ); + Trace("qip-propagate") << "..." << std::endl; + } + //set equal + int status = d_qy.setEqual( a, b, pol, exp ); + if( status==EqualityQueryInstProp::STATUS_NONE ){ + Trace("qip-prop-debug") << "...already equal/no conflict." << std::endl; + return; + }else if( status==EqualityQueryInstProp::STATUS_CONFLICT ){ + Trace("qip-prop-debug") << "...conflict." << std::endl; + conflict( exp ); + return; + } + if( pol ){ + if( status==EqualityQueryInstProp::STATUS_MERGED_KNOWN ){ + Assert( d_qy.getEngine()->hasTerm( a ) ); + Assert( d_qy.getEngine()->hasTerm( b ) ); + Trace("qip-prop-debug") << "...equality between known terms." << std::endl; + addRelevantInstances( exp, "qip-propagate" ); + } + Trace("qip-prop-debug") << "...merged representatives " << a << " and " << b << std::endl; + for( unsigned i=0; i<2; i++ ){ + //update terms from watched lists + Node c = i==0 ? a : b; + std::map< Node, std::map< unsigned, bool > >::iterator it = d_watch_list.find( c ); + if( it!=d_watch_list.end() ){ + Trace("qip-prop-debug") << "...update ids from watch list of " << c << ", size=" << it->second.size() << "..." << std::endl; + for( std::map< unsigned, bool >::iterator itw = it->second.begin(); itw != it->second.end(); ++itw ){ + unsigned idw = itw->first; + if( std::find( d_update_list.begin(), d_update_list.end(), idw )==d_update_list.end() ){ + Trace("qip-prop-debug") << "...will update " << idw << std::endl; + d_update_list.push_back( idw ); + } + } + d_watch_list.erase( c ); + } + } + } +} + +void InstPropagator::conflict( std::vector< Node >& exp ) { + Trace("qip-propagate") << "Conflict, exp size =" << exp.size() << std::endl; + d_conflict = true; + d_relevant_inst.clear(); + addRelevantInstances( exp, "qip-propagate" ); + + //now, inform quantifiers engine which instances should be retracted + Trace("qip-prop-debug") << "...remove instantiation ids : "; + for( std::map< unsigned, InstInfo >::iterator it = d_ii.begin(); it != d_ii.end(); ++it ){ + if( d_relevant_inst.find( it->first )==d_relevant_inst.end() ){ + if( !d_qe->removeInstantiation( it->second.d_q, it->second.d_lem, it->second.d_terms ) ){ + Trace("qip-warn") << "WARNING : did not remove instantiation id " << it->first << std::endl; + Assert( false ); + }else{ + Trace("qip-prop-debug") << it->first << " "; + } + }else{ + //mark the quantified formula as relevant + d_qe->markRelevant( it->second.d_q ); + } + } + Trace("qip-prop-debug") << std::endl; + //will interupt the quantifiers engine + Trace("quant-engine-conflict") << "-----> InstPropagator::conflict with " << exp.size() << " instances." << std::endl; +} + +bool InstPropagator::cacheConclusion( unsigned id, Node body, int prop_index ) { + Assert( prop_index==0 || prop_index==1 ); + //check if the conclusion is non-redundant + if( d_conc_to_id[prop_index].find( body )==d_conc_to_id[prop_index].end() ){ + d_conc_to_id[prop_index][body] = id; + return true; + }else{ + return false; + } +} + +void InstPropagator::addRelevantInstances( std::vector< Node >& exp, const char * c ) { + for( unsigned i=0; i<exp.size(); i++ ){ + Assert( d_conc_to_id[0].find( exp[i] )!=d_conc_to_id[0].end() ); + Trace(c) << " relevant instance id : " << d_conc_to_id[0][ exp[i] ] << std::endl; + d_relevant_inst[ d_conc_to_id[0][ exp[i] ] ] = true; + } +} + +void InstPropagator::debugPrintExplanation( std::vector< Node >& exp, const char * c ) { + for( unsigned i=0; i<exp.size(); i++ ){ + Assert( d_conc_to_id[0].find( exp[i] )!=d_conc_to_id[0].end() ); + Trace(c) << d_conc_to_id[0][ exp[i] ] << " "; + } +} + diff --git a/src/theory/quantifiers/inst_propagator.h b/src/theory/quantifiers/inst_propagator.h new file mode 100644 index 000000000..0c02c7f95 --- /dev/null +++ b/src/theory/quantifiers/inst_propagator.h @@ -0,0 +1,163 @@ +/********************* */ +/*! \file inst_propagator.h + ** \verbatim + ** Top contributors (to current version): + ** Andrew Reynolds + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim + ** + ** \brief Propagate mechanism for instantiations + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__QUANTIFIERS_INST_PROPAGATOR_H +#define __CVC4__QUANTIFIERS_INST_PROPAGATOR_H + +#include <iostream> +#include <string> +#include <vector> +#include <map> +#include "expr/node.h" +#include "expr/type_node.h" +#include "theory/quantifiers_engine.h" +#include "theory/quantifiers/term_database.h" + +namespace CVC4 { +namespace theory { +namespace quantifiers { + +class EqualityQueryInstProp : public EqualityQuery { +private: + /** pointer to quantifiers engine */ + QuantifiersEngine* d_qe; +public: + EqualityQueryInstProp( QuantifiersEngine* qe ); + ~EqualityQueryInstProp(){}; + /** reset */ + bool reset( Theory::Effort e ); + /** identify */ + std::string identify() const { return "EqualityQueryInstProp"; } + /** extends engine */ + bool extendsEngine() { return true; } + /** contains term */ + bool hasTerm( Node a ); + /** get the representative of the equivalence class of a */ + Node getRepresentative( Node a ); + /** returns true if a and b are equal in the current context */ + bool areEqual( Node a, Node b ); + /** returns true is a and b are disequal in the current context */ + bool areDisequal( Node a, Node b ); + /** get the equality engine associated with this query */ + eq::EqualityEngine* getEngine(); + /** get the equivalence class of a */ + void getEquivalenceClass( Node a, std::vector< Node >& eqc ); + /** get congruent term */ + TNode getCongruentTerm( Node f, std::vector< TNode >& args ); +public: + /** get the representative of the equivalence class of a, with explanation */ + Node getRepresentativeExp( Node a, std::vector< Node >& exp ); + /** returns true if a and b are equal in the current context */ + bool areEqualExp( Node a, Node b, std::vector< Node >& exp ); + /** returns true is a and b are disequal in the current context */ + bool areDisequalExp( Node a, Node b, std::vector< Node >& exp ); +private: + /** term index */ + std::map< Node, TermArgTrie > d_func_map_trie; + /** union find for terms beyond what is stored in equality engine */ + std::map< Node, Node > d_uf; + std::map< Node, std::vector< Node > > d_uf_exp; + Node getUfRepresentative( Node a, std::vector< Node >& exp ); + /** disequality list, stores explanations */ + std::map< Node, std::map< Node, std::vector< Node > > > d_diseq_list; + /** add arg */ + void addArgument( std::vector< Node >& args, std::vector< Node >& props, Node n, bool is_prop, bool pol ); +public: + enum { + STATUS_CONFLICT, + STATUS_MERGED_KNOWN, + STATUS_MERGED_UNKNOWN, + STATUS_NONE, + }; + /** set equal */ + int setEqual( Node& a, Node& b, bool pol, std::vector< Node >& reason ); + Node d_true; + Node d_false; +public: + //for explanations + static void merge_exp( std::vector< Node >& v, std::vector< Node >& v_to_merge, int up_to_size = -1 ); + + Node evaluateTermExp( Node n, std::vector< Node >& exp, std::map< Node, Node >& visited, bool hasPol, bool pol, + std::map< Node, bool >& watch_list_out, std::vector< Node >& props ); + static bool isLiteral( Node n ); +}; + +class InstPropagator : public QuantifiersUtil { +private: + /** pointer to quantifiers engine */ + QuantifiersEngine* d_qe; + /** notify class */ + class InstantiationNotifyInstPropagator : public InstantiationNotify { + InstPropagator& d_ip; + public: + InstantiationNotifyInstPropagator(InstPropagator& ip): d_ip(ip) {} + virtual bool notifyInstantiation( unsigned quant_e, Node q, Node lem, std::vector< Node >& terms, Node body ) { + return d_ip.notifyInstantiation( quant_e, q, lem, terms, body ); + } + }; + InstantiationNotifyInstPropagator d_notify; + /** notify instantiation method */ + bool notifyInstantiation( unsigned quant_e, Node q, Node lem, std::vector< Node >& terms, Node body ); + /** equality query */ + EqualityQueryInstProp d_qy; + class InstInfo { + public: + bool d_active; + Node d_q; + Node d_lem; + std::vector< Node > d_terms; + // the current entailed body + Node d_curr; + //explanation for current entailed body + std::vector< Node > d_curr_exp; + void init( Node q, Node lem, std::vector< Node >& terms, Node body ); + }; + /** instantiation count/info */ + unsigned d_icount; + std::map< unsigned, InstInfo > d_ii; + std::map< Node, unsigned > d_conc_to_id[2]; + /** are we in conflict */ + bool d_conflict; + /** watch list */ + std::map< Node, std::map< unsigned, bool > > d_watch_list; + /** update list */ + std::vector< unsigned > d_update_list; + /** relevant instances */ + std::map< unsigned, bool > d_relevant_inst; +private: + bool update( unsigned id, InstInfo& i, bool firstTime = false ); + void propagate( Node a, Node b, bool pol, std::vector< Node >& exp ); + void conflict( std::vector< Node >& exp ); + bool cacheConclusion( unsigned id, Node body, int prop_index = 0 ); + void addRelevantInstances( std::vector< Node >& exp, const char * c ); + + void debugPrintExplanation( std::vector< Node >& exp, const char * c ); +public: + InstPropagator( QuantifiersEngine* qe ); + ~InstPropagator(){} + /** reset */ + bool reset( Theory::Effort e ); + /** identify */ + std::string identify() const { return "InstPropagator"; } + /** get the notify mechanism */ + InstantiationNotify* getInstantiationNotify() { return &d_notify; } +}; + +} +} +} + +#endif diff --git a/src/theory/quantifiers/inst_strategy_cbqi.cpp b/src/theory/quantifiers/inst_strategy_cbqi.cpp index d5ef2e290..149330c61 100644 --- a/src/theory/quantifiers/inst_strategy_cbqi.cpp +++ b/src/theory/quantifiers/inst_strategy_cbqi.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file inst_strategy_cbqi.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): Tim King + ** Top contributors (to current version): + ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Implementation of counterexample-guided quantifier instantiation strategies **/ @@ -34,8 +34,9 @@ using namespace CVC4::theory::arith; #define ARITH_INSTANTIATOR_USE_MINUS_DELTA InstStrategyCbqi::InstStrategyCbqi( QuantifiersEngine * qe ) - : QuantifiersModule( qe ) - , d_added_cbqi_lemma( qe->getUserContext() ){ + : QuantifiersModule( qe ), d_added_cbqi_lemma( qe->getUserContext() ) +//, d_added_inst( qe->getUserContext() ) +{ } InstStrategyCbqi::~InstStrategyCbqi() throw(){} @@ -45,7 +46,7 @@ bool InstStrategyCbqi::needsCheck( Theory::Effort e ) { } unsigned InstStrategyCbqi::needsModel( Theory::Effort e ) { - for( int i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ + for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ Node q = d_quantEngine->getModel()->getAssertedQuantifier( i ); if( doCbqi( q ) && d_quantEngine->getModel()->isQuantifierActive( q ) ){ return QuantifiersEngine::QEFFORT_STANDARD; @@ -58,7 +59,7 @@ void InstStrategyCbqi::reset_round( Theory::Effort effort ) { d_cbqi_set_quant_inactive = false; d_incomplete_check = false; //check if any cbqi lemma has not been added yet - for( int i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ + for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ Node q = d_quantEngine->getModel()->getAssertedQuantifier( i ); //it is not active if it corresponds to a rewrite rule: we will process in rewrite engine if( doCbqi( q ) ){ @@ -106,6 +107,7 @@ void InstStrategyCbqi::reset_round( Theory::Effort effort ) { void InstStrategyCbqi::check( Theory::Effort e, unsigned quant_e ) { if( quant_e==QuantifiersEngine::QEFFORT_STANDARD ){ + Assert( !d_quantEngine->inConflict() ); double clSet = 0; if( Trace.isOn("cbqi-engine") ){ clSet = double(clock())/double(CLOCKS_PER_SEC); @@ -113,13 +115,16 @@ void InstStrategyCbqi::check( Theory::Effort e, unsigned quant_e ) { } unsigned lastWaiting = d_quantEngine->getNumLemmasWaiting(); for( int ee=0; ee<=1; ee++ ){ - for( int i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ + for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ Node q = d_quantEngine->getModel()->getAssertedQuantifier( i ); if( doCbqi( q ) && d_quantEngine->getModel()->isQuantifierActive( q ) ){ process( q, e, ee ); + if( d_quantEngine->inConflict() ){ + break; + } } } - if( d_quantEngine->getNumLemmasWaiting()>lastWaiting ){ + if( d_quantEngine->inConflict() || d_quantEngine->getNumLemmasWaiting()>lastWaiting ){ break; } } @@ -162,13 +167,15 @@ void InstStrategyCbqi::registerCounterexampleLemma( Node q, Node lem ){ bool InstStrategyCbqi::hasNonCbqiOperator( Node n, std::map< Node, bool >& visited ){ if( visited.find( n )==visited.end() ){ visited[n] = true; - if( n.getKind()!=INST_CONSTANT && TermDb::hasInstConstAttr( n ) ){ + if( n.getKind()!=BOUND_VARIABLE && TermDb::hasBoundVarAttr( n ) ){ if( !inst::Trigger::isCbqiKind( n.getKind() ) ){ Trace("cbqi-debug2") << "Non-cbqi kind : " << n.getKind() << " in " << n << std::endl; return true; }else if( n.getKind()==MULT && ( n.getNumChildren()!=2 || !n[0].isConst() ) ){ Trace("cbqi-debug2") << "Non-linear arithmetic : " << n << std::endl; return true; + }else if( n.getKind()==FORALL ){ + return hasNonCbqiOperator( n[1], visited ); }else{ for( unsigned i=0; i<n.getNumChildren(); i++ ){ if( hasNonCbqiOperator( n[i], visited ) ){ @@ -201,20 +208,25 @@ bool InstStrategyCbqi::doCbqi( Node q ){ std::map< Node, bool >::iterator it = d_do_cbqi.find( q ); if( it==d_do_cbqi.end() ){ bool ret = false; - //if has an instantiation pattern, don't do it - if( q.getNumChildren()==3 && options::eMatching() && options::userPatternsQuant()!=USER_PAT_MODE_IGNORE ){ - ret = false; + if( d_quantEngine->getTermDatabase()->isQAttrQuantElim( q ) ){ + ret = true; }else{ - if( options::cbqiAll() ){ - ret = true; + //if has an instantiation pattern, don't do it + if( q.getNumChildren()==3 && options::eMatching() && options::userPatternsQuant()!=USER_PAT_MODE_IGNORE ){ + ret = false; }else{ - //if quantifier has a non-arithmetic variable, then do not use cbqi - //if quantifier has an APPLY_UF term, then do not use cbqi - Node cb = d_quantEngine->getTermDatabase()->getInstConstantBody( q ); - std::map< Node, bool > visited; - ret = !hasNonCbqiVariable( q ) && !hasNonCbqiOperator( cb, visited ); + if( options::cbqiAll() ){ + ret = true; + }else{ + //if quantifier has a non-arithmetic variable, then do not use cbqi + //if quantifier has an APPLY_UF term, then do not use cbqi + //Node cb = d_quantEngine->getTermDatabase()->getInstConstantBody( q ); + std::map< Node, bool > visited; + ret = !hasNonCbqiVariable( q ) && !hasNonCbqiOperator( q[1], visited ); + } } } + Trace("cbqi") << "doCbqi " << q << " returned " << ret << std::endl; d_do_cbqi[q] = ret; return ret; }else{ @@ -224,7 +236,7 @@ bool InstStrategyCbqi::doCbqi( Node q ){ Node InstStrategyCbqi::getNextDecisionRequest(){ // all counterexample literals that are not asserted - for( int i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ + for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ Node q = d_quantEngine->getModel()->getAssertedQuantifier( i ); if( hasAddedCbqiLemma( q ) ){ Node cel = d_quantEngine->getTermDatabase()->getCounterexampleLiteral( q ); @@ -304,8 +316,10 @@ void InstStrategySimplex::processResetInstantiationRound( Theory::Effort effort } } //print debug - Debug("quant-arith-debug") << std::endl; - debugPrint( "quant-arith-debug" ); + if( Debug.isOn("quant-arith-debug") ){ + Debug("quant-arith-debug") << std::endl; + debugPrint( "quant-arith-debug" ); + } d_counter++; } @@ -343,10 +357,10 @@ void InstStrategySimplex::process( Node f, Theory::Effort effort, int e ){ bool m_point_valid = true; int lem = 0; //scan over all instantiation rows - for( int i=0; i<d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); i++ ){ + for( unsigned i=0; i<d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); i++ ){ Node ic = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i ); Debug("quant-arith-simplex") << "InstStrategySimplex check " << ic << ", rows = " << d_instRows[ic].size() << std::endl; - for( int j=0; j<(int)d_instRows[ic].size(); j++ ){ + for( unsigned j=0; j<d_instRows[ic].size(); j++ ){ ArithVar x = d_instRows[ic][j]; if( !d_ceTableaux[ic][x].empty() ){ if( Debug.isOn("quant-arith-simplex") ){ @@ -462,25 +476,25 @@ void InstStrategySimplex::debugPrint( const char* c ){ } Debug(c) << std::endl; - for( int i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ + for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ Node f = d_quantEngine->getModel()->getAssertedQuantifier( i ); Debug(c) << f << std::endl; Debug(c) << " Inst constants: "; - for( int i=0; i<(int)d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); i++ ){ - if( i>0 ){ + for( unsigned j=0; j<d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); i++ ){ + if( j>0 ){ Debug( c ) << ", "; } Debug( c ) << d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i ); } Debug(c) << std::endl; - for( int j=0; j<d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); j++ ){ + for( unsigned j=0; j<d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); j++ ){ Node ic = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, j ); Debug(c) << " Instantiation rows for " << ic << " : "; - for( int i=0; i<(int)d_instRows[ic].size(); i++ ){ - if( i>0 ){ + for( unsigned k=0; k<d_instRows[ic].size(); k++ ){ + if( k>0 ){ Debug(c) << ", "; } - Debug(c) << d_instRows[ic][i]; + Debug(c) << d_instRows[ic][k]; } Debug(c) << std::endl; } @@ -559,8 +573,8 @@ Node InstStrategySimplex::getTableauxValue( ArithVar v, bool minus_delta ){ //new implementation -bool CegqiOutputInstStrategy::addInstantiation( std::vector< Node >& subs ) { - return d_out->addInstantiation( subs ); +bool CegqiOutputInstStrategy::doAddInstantiation( std::vector< Node >& subs ) { + return d_out->doAddInstantiation( subs ); } bool CegqiOutputInstStrategy::isEligibleForInstantiation( Node n ) { @@ -580,24 +594,33 @@ InstStrategyCegqi::InstStrategyCegqi( QuantifiersEngine * qe ) InstStrategyCegqi::~InstStrategyCegqi() throw () { delete d_out; + + for(std::map< Node, CegInstantiator * >::iterator i = d_cinst.begin(), + iend = d_cinst.end(); i != iend; ++i) { + CegInstantiator * instantiator = (*i).second; + delete instantiator; + } + d_cinst.clear(); } void InstStrategyCegqi::processResetInstantiationRound( Theory::Effort effort ) { - d_check_vts_lemma_lc = true; + d_check_vts_lemma_lc = false; } -void InstStrategyCegqi::process( Node f, Theory::Effort effort, int e ) { +void InstStrategyCegqi::process( Node q, Theory::Effort effort, int e ) { if( e==0 ){ - CegInstantiator * cinst = getInstantiator( f ); - Trace("inst-alg") << "-> Run cegqi for " << f << std::endl; - d_curr_quant = f; + CegInstantiator * cinst = getInstantiator( q ); + Trace("inst-alg") << "-> Run cegqi for " << q << std::endl; + d_curr_quant = q; if( !cinst->check() ){ d_incomplete_check = true; + d_check_vts_lemma_lc = true; } d_curr_quant = Node::null(); }else if( e==1 ){ //minimize the free delta heuristically on demand if( d_check_vts_lemma_lc ){ + Trace("inst-alg") << "-> Minimize delta heuristic, for " << q << std::endl; d_check_vts_lemma_lc = false; d_small_const = NodeManager::currentNM()->mkNode( MULT, d_small_const, d_small_const ); d_small_const = Rewriter::rewrite( d_small_const ); @@ -619,11 +642,24 @@ void InstStrategyCegqi::process( Node f, Theory::Effort effort, int e ) { } } -bool InstStrategyCegqi::addInstantiation( std::vector< Node >& subs ) { +bool InstStrategyCegqi::doAddInstantiation( std::vector< Node >& subs ) { Assert( !d_curr_quant.isNull() ); - //check if we need virtual term substitution (if used delta or infinity) - bool used_vts = d_quantEngine->getTermDatabase()->containsVtsTerm( subs, false ); - return d_quantEngine->addInstantiation( d_curr_quant, subs, false, false, false, used_vts ); + //if doing partial quantifier elimination, record the instantiation and set the incomplete flag instead of sending instantiation lemma + if( d_quantEngine->getTermDatabase()->isQAttrQuantElimPartial( d_curr_quant ) ){ + d_cbqi_set_quant_inactive = true; + d_incomplete_check = true; + d_quantEngine->recordInstantiationInternal( d_curr_quant, subs, false, false ); + return true; + }else{ + //check if we need virtual term substitution (if used delta or infinity) + bool used_vts = d_quantEngine->getTermDatabase()->containsVtsTerm( subs, false ); + if( d_quantEngine->addInstantiation( d_curr_quant, subs, false, false, used_vts ) ){ + //d_added_inst.insert( d_curr_quant ); + return true; + }else{ + return false; + } + } } bool InstStrategyCegqi::addLemma( Node lem ) { @@ -665,7 +701,7 @@ void InstStrategyCegqi::registerCounterexampleLemma( Node q, Node lem ) { //must register with the instantiator //must explicitly remove ITEs so that we record dependencies std::vector< Node > ce_vars; - for( int i=0; i<d_quantEngine->getTermDatabase()->getNumInstantiationConstants( q ); i++ ){ + for( unsigned i=0; i<d_quantEngine->getTermDatabase()->getNumInstantiationConstants( q ); i++ ){ ce_vars.push_back( d_quantEngine->getTermDatabase()->getInstantiationConstant( q, i ) ); } std::vector< Node > lems; diff --git a/src/theory/quantifiers/inst_strategy_cbqi.h b/src/theory/quantifiers/inst_strategy_cbqi.h index 5511af209..8ed59778b 100644 --- a/src/theory/quantifiers/inst_strategy_cbqi.h +++ b/src/theory/quantifiers/inst_strategy_cbqi.h @@ -1,13 +1,13 @@ /********************* */ /*! \file inst_strategy_cbqi.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): Tim King + ** Top contributors (to current version): + ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief counterexample-guided quantifier instantiation **/ @@ -39,6 +39,8 @@ protected: bool d_incomplete_check; /** whether we have added cbqi lemma */ NodeSet d_added_cbqi_lemma; + /** whether we have instantiated quantified formulas */ + //NodeSet d_added_inst; /** whether to do cbqi for this quantified formula */ std::map< Node, bool > d_do_cbqi; /** register ce lemma */ @@ -120,7 +122,7 @@ class CegqiOutputInstStrategy : public CegqiOutput { public: CegqiOutputInstStrategy( InstStrategyCegqi * out ) : d_out( out ){} InstStrategyCegqi * d_out; - bool addInstantiation( std::vector< Node >& subs ); + bool doAddInstantiation( std::vector< Node >& subs ); bool isEligibleForInstantiation( Node n ); bool addLemma( Node lem ); }; @@ -141,7 +143,7 @@ public: InstStrategyCegqi( QuantifiersEngine * qe ); ~InstStrategyCegqi() throw(); - bool addInstantiation( std::vector< Node >& subs ); + bool doAddInstantiation( std::vector< Node >& subs ); bool isEligibleForInstantiation( Node n ); bool addLemma( Node lem ); /** identify */ diff --git a/src/theory/quantifiers/inst_strategy_e_matching.cpp b/src/theory/quantifiers/inst_strategy_e_matching.cpp index 299eb51fd..630880690 100644 --- a/src/theory/quantifiers/inst_strategy_e_matching.cpp +++ b/src/theory/quantifiers/inst_strategy_e_matching.cpp @@ -1,20 +1,18 @@ /********************* */ /*! \file inst_strategy_e_matching.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Implementation of e matching instantiation strategies **/ #include "theory/quantifiers/inst_strategy_e_matching.h" - -#include "options/quantifiers_options.h" #include "theory/quantifiers/inst_match_generator.h" #include "theory/quantifiers/relevant_domain.h" #include "theory/quantifiers/term_database.h" @@ -51,15 +49,18 @@ struct sortQuantifiersForSymbol { struct sortTriggers { bool operator() (Node i, Node j) { - if( Trigger::isAtomicTrigger( i ) ){ - return i<j || !Trigger::isAtomicTrigger( j ); + int wi = Trigger::getTriggerWeight( i ); + int wj = Trigger::getTriggerWeight( j ); + if( wi==wj ){ + return i<j; }else{ - return i<j && !Trigger::isAtomicTrigger( j ); + return wi<wj; } } }; void InstStrategyUserPatterns::processResetInstantiationRound( Theory::Effort effort ){ + Trace("inst-alg-debug") << "reset user triggers" << std::endl; //reset triggers for( std::map< Node, std::vector< Trigger* > >::iterator it = d_user_gen.begin(); it != d_user_gen.end(); ++it ){ for( unsigned i=0; i<it->second.size(); i++ ){ @@ -67,6 +68,7 @@ void InstStrategyUserPatterns::processResetInstantiationRound( Theory::Effort ef it->second[i]->reset( Node::null() ); } } + Trace("inst-alg-debug") << "done reset user triggers" << std::endl; } int InstStrategyUserPatterns::process( Node f, Theory::Effort effort, int e ){ @@ -83,7 +85,7 @@ int InstStrategyUserPatterns::process( Node f, Theory::Effort effort, int e ){ if( d_quantEngine->getInstUserPatMode()==USER_PAT_MODE_RESORT ){ int matchOption = 0; for( unsigned i=0; i<d_user_gen_wait[f].size(); i++ ){ - Trigger * t = Trigger::mkTrigger( d_quantEngine, f, d_user_gen_wait[f][i], matchOption, true, Trigger::TR_RETURN_NULL, options::smartTriggers() ); + Trigger * t = Trigger::mkTrigger( d_quantEngine, f, d_user_gen_wait[f][i], matchOption, true, Trigger::TR_RETURN_NULL ); if( t ){ d_user_gen[f].push_back( t ); } @@ -104,7 +106,9 @@ int InstStrategyUserPatterns::process( Node f, Theory::Effort effort, int e ){ if( d_user_gen[f][i]->isMultiTrigger() ){ d_quantEngine->d_statistics.d_multi_trigger_instantiations += numInst; } - //d_quantEngine->d_hasInstantiated[f] = true; + if( d_quantEngine->inConflict() ){ + break; + } } } } @@ -118,11 +122,13 @@ void InstStrategyUserPatterns::addUserPattern( Node q, Node pat ){ bool usable = true; std::vector< Node > nodes; for( unsigned i=0; i<pat.getNumChildren(); i++ ){ - nodes.push_back( pat[i] ); - if( pat[i].getKind()!=INST_CONSTANT && !Trigger::isUsableTrigger( pat[i], q ) ){ + Node pat_use = Trigger::getIsUsableTrigger( pat[i], q ); + if( pat_use.isNull() ){ Trace("trigger-warn") << "User-provided trigger is not usable : " << pat << " because of " << pat[i] << std::endl; usable = false; break; + }else{ + nodes.push_back( pat_use ); } } if( usable ){ @@ -132,19 +138,22 @@ void InstStrategyUserPatterns::addUserPattern( Node q, Node pat ){ if( d_quantEngine->getInstUserPatMode()==USER_PAT_MODE_RESORT ){ d_user_gen_wait[q].push_back( nodes ); }else{ - d_user_gen[q].push_back( Trigger::mkTrigger( d_quantEngine, q, nodes, matchOption, true, Trigger::TR_MAKE_NEW, options::smartTriggers() ) ); + Trigger * t = Trigger::mkTrigger( d_quantEngine, q, nodes, matchOption, true, Trigger::TR_MAKE_NEW ); + if( t ){ + d_user_gen[q].push_back( t ); + }else{ + Trace("trigger-warn") << "Failed to construct trigger : " << pat << " due to variable mismatch" << std::endl; + } } } } InstStrategyAutoGenTriggers::InstStrategyAutoGenTriggers( QuantifiersEngine* qe ) : InstStrategy( qe ){ //how to select trigger terms - if( options::triggerSelMode()==TRIGGER_SEL_MIN ){ - d_tr_strategy = Trigger::TS_MIN_TRIGGER; - }else if( options::triggerSelMode()==TRIGGER_SEL_MAX ){ - d_tr_strategy = Trigger::TS_MAX_TRIGGER; + if( options::triggerSelMode()==quantifiers::TRIGGER_SEL_DEFAULT ){ + d_tr_strategy = quantifiers::TRIGGER_SEL_MIN; }else{ - d_tr_strategy = Trigger::TS_ALL; + d_tr_strategy = options::triggerSelMode(); } //whether to select new triggers during the search if( options::incrementTriggers() ){ @@ -156,6 +165,7 @@ InstStrategyAutoGenTriggers::InstStrategyAutoGenTriggers( QuantifiersEngine* qe } void InstStrategyAutoGenTriggers::processResetInstantiationRound( Theory::Effort effort ){ + Trace("inst-alg-debug") << "reset auto-gen triggers" << std::endl; //reset triggers for( unsigned r=0; r<2; r++ ){ for( std::map< Node, std::map< Trigger*, bool > >::iterator it = d_auto_gen_trigger[r].begin(); it != d_auto_gen_trigger[r].end(); ++it ){ @@ -166,6 +176,7 @@ void InstStrategyAutoGenTriggers::processResetInstantiationRound( Theory::Effort } } d_processed_trigger.clear(); + Trace("inst-alg-debug") << "done reset auto-gen triggers" << std::endl; } int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e ){ @@ -220,11 +231,13 @@ int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e ) if( r==1 ){ d_quantEngine->d_statistics.d_multi_trigger_instantiations += numInst; } - //d_quantEngine->d_hasInstantiated[f] = true; + if( d_quantEngine->inConflict() ){ + break; + } } } } - if( hasInst && options::multiTriggerPriority() ){ + if( d_quantEngine->inConflict() || ( hasInst && options::multiTriggerPriority() ) ){ break; } } @@ -237,67 +250,102 @@ int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e ) } void InstStrategyAutoGenTriggers::generateTriggers( Node f ){ - Trace("auto-gen-trigger-debug") << "Generate triggers for " << f << std::endl; + Trace("auto-gen-trigger-debug") << "Generate triggers for " << f << ", #var=" << f[0].getNumChildren() << "..." << 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(); bool ntrivTriggers = options::relationalTriggers(); std::vector< Node > patTermsF; + std::map< Node, inst::TriggerTermInfo > tinfo; //well-defined function: can assume LHS is only trigger if( options::quantFunWellDefined() ){ Node hd = TermDb::getFunDefHead( f ); if( !hd.isNull() ){ hd = d_quantEngine->getTermDatabase()->getInstConstantNode( hd, f ); patTermsF.push_back( hd ); + tinfo[hd].init( f, hd ); } } //otherwise, use algorithm for collecting pattern terms if( patTermsF.empty() ){ Node bd = d_quantEngine->getTermDatabase()->getInstConstantBody( f ); - Trigger::collectPatTerms( d_quantEngine, f, bd, patTermsF, d_tr_strategy, d_user_no_gen[f], true ); - Trace("auto-gen-trigger-debug") << "Collected pat terms for " << bd << ", no-patterns : " << d_user_no_gen[f].size() << std::endl; - Trace("auto-gen-trigger-debug") << " "; - for( int i=0; i<(int)patTermsF.size(); i++ ){ - Trace("auto-gen-trigger-debug") << patTermsF[i] << " "; - } - Trace("auto-gen-trigger-debug") << std::endl; + Trigger::collectPatTerms( f, bd, patTermsF, d_tr_strategy, d_user_no_gen[f], tinfo, true ); if( ntrivTriggers ){ sortTriggers st; std::sort( patTermsF.begin(), patTermsF.end(), st ); } + if( Trace.isOn("auto-gen-trigger-debug") ){ + Trace("auto-gen-trigger-debug") << "Collected pat terms for " << bd << ", no-patterns : " << d_user_no_gen[f].size() << std::endl; + for( unsigned i=0; i<patTermsF.size(); i++ ){ + Assert( tinfo.find( patTermsF[i] )!=tinfo.end() ); + Trace("auto-gen-trigger-debug") << " " << patTermsF[i]; + Trace("auto-gen-trigger-debug") << " info[" << tinfo[patTermsF[i]].d_reqPol << ", " << tinfo[patTermsF[i]].d_reqPolEq << ", " << tinfo[patTermsF[i]].d_fv.size() << "]" << std::endl; + } + Trace("auto-gen-trigger-debug") << std::endl; + } } - //sort into single/multi triggers - std::map< Node, std::vector< Node > > varContains; + //sort into single/multi triggers, calculate which terms should not be considered std::map< Node, bool > vcMap; std::map< Node, bool > rmPatTermsF; + int last_weight = -1; for( unsigned i=0; i<patTermsF.size(); i++ ){ - d_quantEngine->getTermDatabase()->getVarContainsNode( f, patTermsF[i], varContains[ patTermsF[i] ] ); + Assert( patTermsF[i].getKind()!=NOT ); bool newVar = false; - for( unsigned j=0; j<varContains[ patTermsF[i] ].size(); j++ ){ - if( vcMap.find( varContains[ patTermsF[i] ][j] )==vcMap.end() ){ - vcMap[varContains[ patTermsF[i] ][j]] = true; + for( unsigned j=0; j<tinfo[ patTermsF[i] ].d_fv.size(); j++ ){ + if( vcMap.find( tinfo[ patTermsF[i] ].d_fv[j] )==vcMap.end() ){ + vcMap[tinfo[ patTermsF[i] ].d_fv[j]] = true; newVar = true; } } - if( ntrivTriggers && !newVar && !Trigger::isAtomicTrigger( patTermsF[i] ) ){ - Trace("auto-gen-trigger-debug") << "Exclude expendible non-trivial trigger : " << patTermsF[i] << std::endl; + int curr_w = Trigger::getTriggerWeight( patTermsF[i] ); + if( ntrivTriggers && !newVar && last_weight!=-1 && curr_w>last_weight ){ + Trace("auto-gen-trigger-debug") << "...exclude expendible non-trivial trigger : " << patTermsF[i] << std::endl; rmPatTermsF[patTermsF[i]] = true; + }else{ + last_weight = curr_w; } } - for( std::map< Node, std::vector< Node > >::iterator it = varContains.begin(); it != varContains.end(); ++it ){ - if( rmPatTermsF.find( it->first )==rmPatTermsF.end() ){ - if( it->second.size()==f[0].getNumChildren() && ( options::pureThTriggers() || !Trigger::isPureTheoryTrigger( it->first ) ) ){ - d_patTerms[0][f].push_back( it->first ); - d_is_single_trigger[ it->first ] = true; + for( unsigned i=0; i<patTermsF.size(); i++ ){ + Node pat = patTermsF[i]; + if( rmPatTermsF.find( pat )==rmPatTermsF.end() ){ + Trace("auto-gen-trigger-debug") << "...processing pattern " << pat << std::endl; + //process the pattern: if it has a required polarity, consider it + Assert( tinfo.find( pat )!=tinfo.end() ); + int rpol = tinfo[pat].d_reqPol; + Node rpoleq = tinfo[pat].d_reqPolEq; + unsigned num_fv = tinfo[pat].d_fv.size(); + Trace("auto-gen-trigger-debug") << "...required polarity for " << pat << " is " << rpol << ", eq=" << rpoleq << std::endl; + if( rpol!=0 ){ + if( Trigger::isRelationalTrigger( pat ) ){ + pat = rpol==-1 ? pat.negate() : pat; + }else{ + Assert( Trigger::isAtomicTrigger( pat ) ); + if( pat.getType().isBoolean() && rpoleq.isNull() ){ + pat = NodeManager::currentNM()->mkNode( IFF, pat, NodeManager::currentNM()->mkConst( rpol==-1 ) ).negate(); + }else{ + Assert( !rpoleq.isNull() ); + if( rpol==-1 ){ + //all equivalence classes except rpoleq + pat = NodeManager::currentNM()->mkNode( EQUAL, pat, rpoleq ).negate(); + }else if( rpol==1 ){ + //all equivalence classes that are not disequal to rpoleq TODO + } + } + } + Trace("auto-gen-trigger-debug") << "...got : " << pat << std::endl; }else{ - d_patTerms[1][f].push_back( it->first ); - d_is_single_trigger[ it->first ] = false; + if( Trigger::isRelationalTrigger( pat ) ){ + //consider both polarities + addPatternToPool( f, pat.negate(), num_fv ); + } } + addPatternToPool( f, pat, num_fv ); } } + //tinfo not used below this point d_made_multi_trigger[f] = false; - Trace("auto-gen-trigger") << "Single triggers for " << f << " : " << std::endl; + Trace("auto-gen-trigger") << "Single trigger pool for " << f << " : " << std::endl; for( unsigned i=0; i<d_patTerms[0][f].size(); i++ ){ Trace("auto-gen-trigger") << " " << d_patTerms[0][f][i] << std::endl; } @@ -327,7 +375,7 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){ //sort based on # occurrences (this will cause Trigger to select rarer symbols) std::sort( patTerms.begin(), patTerms.end(), sqfs ); Debug("relevant-trigger") << "Terms based on relevance: " << std::endl; - for( int i=0; i<(int)patTerms.size(); i++ ){ + for( unsigned i=0; i<patTerms.size(); i++ ){ Debug("relevant-trigger") << " " << patTerms[i] << " ("; Debug("relevant-trigger") << d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( patTerms[i].getOperator() ) << ")" << std::endl; } @@ -336,7 +384,7 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){ int matchOption = 0; Trigger* tr = NULL; if( d_is_single_trigger[ patTerms[0] ] ){ - tr = Trigger::mkTrigger( d_quantEngine, f, patTerms[0], matchOption, false, Trigger::TR_RETURN_NULL, options::smartTriggers() ); + tr = Trigger::mkTrigger( d_quantEngine, f, patTerms[0], matchOption, false, Trigger::TR_RETURN_NULL ); d_single_trigger_gen[ patTerms[0] ] = true; }else{ //only generate multi trigger if option set, or if no single triggers exist @@ -354,7 +402,7 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){ d_made_multi_trigger[f] = true; } //will possibly want to get an old trigger - tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, matchOption, false, Trigger::TR_GET_OLD, options::smartTriggers() ); + tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, matchOption, false, Trigger::TR_GET_OLD ); } if( tr ){ unsigned tindex; @@ -390,7 +438,7 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){ if( !options::relevantTriggers() || d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( patTerms[index].getOperator() )<=nqfs_curr ){ d_single_trigger_gen[ patTerms[index] ] = true; - Trigger* tr2 = Trigger::mkTrigger( d_quantEngine, f, patTerms[index], matchOption, false, Trigger::TR_RETURN_NULL, options::smartTriggers() ); + Trigger* tr2 = Trigger::mkTrigger( d_quantEngine, f, patTerms[index], matchOption, false, Trigger::TR_RETURN_NULL ); if( tr2 ){ //Notice() << "Add additional trigger " << patTerms[index] << std::endl; tr2->resetInstantiationRound(); @@ -409,6 +457,16 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){ } } +void InstStrategyAutoGenTriggers::addPatternToPool( Node q, Node pat, unsigned num_fv ) { + if( num_fv==q[0].getNumChildren() && ( options::pureThTriggers() || !Trigger::isPureTheoryTrigger( pat ) ) ){ + d_patTerms[0][q].push_back( pat ); + d_is_single_trigger[ pat ] = true; + }else{ + d_patTerms[1][q].push_back( pat ); + d_is_single_trigger[ pat ] = false; + } +} + bool InstStrategyAutoGenTriggers::hasUserPatterns( Node q ) { if( q.getNumChildren()==3 ){ std::map< Node, bool >::iterator it = d_hasUserPatterns.find( q ); @@ -462,7 +520,7 @@ bool InstStrategyLocalTheoryExt::isLocalTheoryExt( Node f ) { } Trace("local-t-ext") << std::endl; int matchOption = 0; - Trigger * tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, matchOption, true, Trigger::TR_GET_OLD, options::smartTriggers() ); + Trigger * tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, matchOption, true, Trigger::TR_GET_OLD ); d_lte_trigger[f] = tr; }else{ Trace("local-t-ext") << "No local theory extensions trigger for " << f << "." << std::endl; @@ -515,12 +573,15 @@ void FullSaturation::check( Theory::Effort e, unsigned quant_e ) { Trace("fs-engine") << "---Full Saturation Round, effort = " << e << "---" << std::endl; } int addedLemmas = 0; - for( int i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ - Node q = d_quantEngine->getModel()->getAssertedQuantifier( i ); + for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ + Node q = d_quantEngine->getModel()->getAssertedQuantifier( i, true ); if( d_quantEngine->hasOwnership( q, this ) && d_quantEngine->getModel()->isQuantifierActive( q ) ){ if( process( q, fullEffort ) ){ //added lemma addedLemmas++; + if( d_quantEngine->inConflict() ){ + break; + } } } } @@ -538,18 +599,6 @@ bool FullSaturation::process( Node f, bool fullEffort ){ unsigned rstart = options::fullSaturateQuantRd() ? 0 : 1; unsigned rend = fullEffort ? 1 : rstart; for( unsigned r=rstart; r<=rend; r++ ){ - /* - //complete guess - if( d_guessed.find( f )==d_guessed.end() ){ - Trace("inst-alg") << "-> Guess instantiate " << f << "..." << std::endl; - d_guessed[f] = true; - InstMatch m( f ); - if( d_quantEngine->addInstantiation( f, m ) ){ - ++(d_quantEngine->d_statistics.d_instantiations_guess); - return true; - } - } - */ if( rd || r>0 ){ if( r==0 ){ Trace("inst-alg") << "-> Relevant domain instantiate " << f << "..." << std::endl; @@ -566,7 +615,7 @@ bool FullSaturation::process( Node f, bool fullEffort ){ if( r==0 ){ ts = rd->getRDomain( f, i )->d_terms.size(); }else{ - ts = d_quantEngine->getTermDatabase()->d_type_map[f[0][i].getType()].size(); + ts = d_quantEngine->getTermDatabase()->getNumTypeGroundTerms( f[0][i].getType() ); } max_zero.push_back( fullEffort && ts==0 ); ts = ( fullEffort && ts==0 ) ? 1 : ts; @@ -582,6 +631,11 @@ bool FullSaturation::process( Node f, bool fullEffort ){ } } if( !has_zero ){ + std::vector< TypeNode > ftypes; + for( unsigned i=0; i<f[0].getNumChildren(); i++ ){ + ftypes.push_back( f[0][i].getType() ); + } + Trace("inst-alg-rd") << "Will do " << final_max_i << " stages of instantiation." << std::endl; unsigned max_i = 0; bool success; @@ -599,7 +653,7 @@ bool FullSaturation::process( Node f, bool fullEffort ){ if( options::cbqi() && r==1 && !max_zero[index] ){ //skip inst constant nodes while( nv<maxs[index] && nv<=max_i && - quantifiers::TermDb::hasInstConstAttr( d_quantEngine->getTermDatabase()->d_type_map[f[0][index].getType()][nv] ) ){ + quantifiers::TermDb::hasInstConstAttr( d_quantEngine->getTermDatabase()->getTypeGroundTerm( ftypes[index], nv ) ) ){ nv++; } } @@ -625,13 +679,16 @@ bool FullSaturation::process( Node f, bool fullEffort ){ if( max_zero[i] ){ //no terms available, will report incomplete instantiation terms.push_back( Node::null() ); + Trace("inst-alg-rd") << " null" << std::endl; }else if( r==0 ){ terms.push_back( rd->getRDomain( f, i )->d_terms[childIndex[i]] ); + Trace("inst-alg-rd") << " " << rd->getRDomain( f, i )->d_terms[childIndex[i]] << std::endl; }else{ - terms.push_back( d_quantEngine->getTermDatabase()->d_type_map[f[0][i].getType()][childIndex[i]] ); + terms.push_back( d_quantEngine->getTermDatabase()->getTypeGroundTerm( ftypes[i], childIndex[i] ) ); + Trace("inst-alg-rd") << " " << d_quantEngine->getTermDatabase()->getTypeGroundTerm( ftypes[i], childIndex[i] ) << std::endl; } } - if( d_quantEngine->addInstantiation( f, terms, false ) ){ + if( d_quantEngine->addInstantiation( f, terms ) ){ Trace("inst-alg-rd") << "Success!" << std::endl; ++(d_quantEngine->d_statistics.d_instantiations_guess); return true; diff --git a/src/theory/quantifiers/inst_strategy_e_matching.h b/src/theory/quantifiers/inst_strategy_e_matching.h index 4e7afad5d..028f24b27 100644 --- a/src/theory/quantifiers/inst_strategy_e_matching.h +++ b/src/theory/quantifiers/inst_strategy_e_matching.h @@ -1,13 +1,13 @@ /********************* */ /*! \file inst_strategy_e_matching.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Morgan Deters, Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief E matching instantiation strategies **/ @@ -23,6 +23,7 @@ #include "theory/quantifiers/trigger.h" #include "theory/quantifiers_engine.h" #include "util/statistics_registry.h" +#include "options/quantifiers_options.h" namespace CVC4 { namespace theory { @@ -64,7 +65,7 @@ public: }; private: /** trigger generation strategy */ - int d_tr_strategy; + TriggerSelMode d_tr_strategy; /** regeneration */ bool d_regenerate; int d_regenerate_frequency; @@ -73,6 +74,8 @@ private: std::map< Node, int > d_counter; /** single, multi triggers for each quantifier */ std::map< Node, std::vector< Node > > d_patTerms[2]; + std::map< Node, std::map< Node, bool > > d_patReqPol; + /** information about triggers */ std::map< Node, bool > d_is_single_trigger; std::map< Node, bool > d_single_trigger_gen; std::map< Node, bool > d_made_multi_trigger; @@ -86,6 +89,7 @@ private: int process( Node q, Theory::Effort effort, int e ); /** generate triggers */ void generateTriggers( Node q ); + void addPatternToPool( Node q, Node pat, unsigned num_fv ); //bool addTrigger( inst::Trigger * tr, Node f, unsigned r ); /** has user patterns */ bool hasUserPatterns( Node q ); diff --git a/src/theory/quantifiers/instantiation_engine.cpp b/src/theory/quantifiers/instantiation_engine.cpp index 88a67e3c8..955dc5d86 100644 --- a/src/theory/quantifiers/instantiation_engine.cpp +++ b/src/theory/quantifiers/instantiation_engine.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file instantiation_engine.cpp ** \verbatim - ** Original author: Morgan Deters - ** Major contributors: Andrew Reynolds - ** Minor contributors (to current version): Tim King + ** Top contributors (to current version): + ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Implementation of instantiation engine class **/ @@ -60,7 +60,7 @@ void InstantiationEngine::presolve() { } } -bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){ +void InstantiationEngine::doInstantiationRound( Theory::Effort effort ){ unsigned lastWaiting = d_quantEngine->getNumLemmasWaiting(); //iterate over an internal effort level e int e = 0; @@ -83,8 +83,10 @@ bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){ InstStrategy* is = d_instStrategies[j]; Trace("inst-engine-debug") << "Do " << is->identify() << " " << e_use << std::endl; int quantStatus = is->process( q, effort, e_use ); - Trace("inst-engine-debug") << " -> status is " << quantStatus << std::endl; - if( quantStatus==InstStrategy::STATUS_UNFINISHED ){ + Trace("inst-engine-debug") << " -> status is " << quantStatus << ", conflict=" << d_quantEngine->inConflict() << std::endl; + if( d_quantEngine->inConflict() ){ + return; + }else if( quantStatus==InstStrategy::STATUS_UNFINISHED ){ finished = false; } } @@ -96,13 +98,6 @@ bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){ } e++; } - //Notice() << "All instantiators finished, # added lemmas = " << (int)d_lemmas_waiting.size() << std::endl; - if( !d_quantEngine->hasAddedLemma() ){ - return false; - }else{ - Trace("inst-engine") << "Added lemmas = " << (int)(d_quantEngine->getNumLemmasWaiting()-lastWaiting) << std::endl; - return true; - } } bool InstantiationEngine::needsCheck( Theory::Effort e ){ @@ -128,8 +123,8 @@ void InstantiationEngine::check( Theory::Effort e, unsigned quant_e ){ //collect all active quantified formulas belonging to this bool quantActive = false; d_quants.clear(); - for( int i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ - Node q = d_quantEngine->getModel()->getAssertedQuantifier( i ); + for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ + Node q = d_quantEngine->getModel()->getAssertedQuantifier( i, true ); if( d_quantEngine->hasOwnership( q, this ) && d_quantEngine->getModel()->isQuantifierActive( q ) ){ quantActive = true; d_quants.push_back( q ); @@ -138,8 +133,18 @@ void InstantiationEngine::check( Theory::Effort e, unsigned quant_e ){ Trace("inst-engine-debug") << "InstEngine: check: # asserted quantifiers " << d_quants.size() << "/"; Trace("inst-engine-debug") << d_quantEngine->getModel()->getNumAssertedQuantifiers() << " " << quantActive << std::endl; if( quantActive ){ - bool addedLemmas = doInstantiationRound( e ); - Trace("inst-engine-debug") << "Add lemmas = " << addedLemmas << std::endl; + unsigned lastWaiting = d_quantEngine->getNumLemmasWaiting(); + doInstantiationRound( e ); + if( d_quantEngine->inConflict() ){ + Assert( d_quantEngine->getNumLemmasWaiting()>lastWaiting ); + Trace("inst-engine") << "Conflict = " << d_quantEngine->getNumLemmasWaiting() << " / " << d_quantEngine->getNumLemmasAddedThisRound(); + if( lastWaiting>0 ){ + Trace("inst-engine") << " (prev " << lastWaiting << ")"; + } + Trace("inst-engine") << std::endl; + }else if( d_quantEngine->hasAddedLemma() ){ + Trace("inst-engine") << "Added lemmas = " << (d_quantEngine->getNumLemmasWaiting()-lastWaiting) << std::endl; + } }else{ d_quants.clear(); } @@ -165,6 +170,22 @@ bool InstantiationEngine::isIncomplete( Node q ) { return true; } +void InstantiationEngine::preRegisterQuantifier( Node q ) { + if( options::strictTriggers() && q.getNumChildren()==3 ){ + //if strict triggers, take ownership of this quantified formula + bool hasPat = false; + for( unsigned i=0; i<q[2].getNumChildren(); i++ ){ + if( q[2][i].getKind()==INST_PATTERN || q[2][i].getKind()==INST_NO_PATTERN ){ + hasPat = true; + break; + } + } + if( hasPat ){ + d_quantEngine->setOwner( q, this, 1 ); + } + } +} + void InstantiationEngine::registerQuantifier( Node f ){ if( d_quantEngine->hasOwnership( f, this ) ){ //for( unsigned i=0; i<d_instStrategies.size(); ++i ){ diff --git a/src/theory/quantifiers/instantiation_engine.h b/src/theory/quantifiers/instantiation_engine.h index bfa610369..d2b3740a1 100644 --- a/src/theory/quantifiers/instantiation_engine.h +++ b/src/theory/quantifiers/instantiation_engine.h @@ -1,13 +1,13 @@ /********************* */ /*! \file instantiation_engine.h ** \verbatim - ** Original author: Morgan Deters - ** Major contributors: Andrew Reynolds - ** Minor contributors (to current version): Tim King + ** Top contributors (to current version): + ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Instantiation Engine classes **/ @@ -70,7 +70,7 @@ private: /** is the engine incomplete for this quantifier */ bool isIncomplete( Node q ); /** do instantiation round */ - bool doInstantiationRound( Theory::Effort effort ); + void doInstantiationRound( Theory::Effort effort ); public: InstantiationEngine( QuantifiersEngine* qe ); ~InstantiationEngine(); @@ -79,6 +79,7 @@ public: void reset_round( Theory::Effort e ); void check( Theory::Effort e, unsigned quant_e ); bool checkComplete(); + void preRegisterQuantifier( Node q ); void registerQuantifier( Node q ); Node explain(TNode n){ return Node::null(); } /** add user pattern */ diff --git a/src/theory/quantifiers/local_theory_ext.cpp b/src/theory/quantifiers/local_theory_ext.cpp index 794032c87..ada28c084 100644 --- a/src/theory/quantifiers/local_theory_ext.cpp +++ b/src/theory/quantifiers/local_theory_ext.cpp @@ -1,13 +1,13 @@ /********************* */ -/*! \file quant_util.cpp +/*! \file local_theory_ext.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Implementation of local theory ext utilities **/ @@ -31,69 +31,69 @@ QuantifiersModule( qe ), d_wasInvoked( false ), d_needsCheck( false ){ } /** add quantifier */ -bool LtePartialInst::addQuantifier( Node q ) { - if( d_do_inst.find( q )!=d_do_inst.end() ){ - if( d_do_inst[q] ){ - d_lte_asserts.push_back( q ); - return true; +void LtePartialInst::preRegisterQuantifier( Node q ) { + if( !q.getAttribute(LtePartialInstAttribute()) ){ + if( d_do_inst.find( q )!=d_do_inst.end() ){ + if( d_do_inst[q] ){ + d_lte_asserts.push_back( q ); + d_quantEngine->setOwner( q, this ); + } }else{ - return false; - } - }else{ - d_vars[q].clear(); - d_pat_var_order[q].clear(); - //check if this quantified formula is eligible for partial instantiation - std::map< Node, bool > vars; - for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ - vars[q[0][i]] = false; - } - getEligibleInstVars( q[1], vars ); - - //instantiate only if we would force ground instances - std::map< Node, int > var_order; - bool doInst = true; - for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ - if( vars[q[0][i]] ){ - d_vars[q].push_back( q[0][i] ); - var_order[q[0][i]] = i; - }else{ - Trace("lte-partial-inst-debug") << "...do not consider, variable " << q[0][i] << " was not found in correct position in body." << std::endl; - doInst = false; - break; + d_vars[q].clear(); + d_pat_var_order[q].clear(); + //check if this quantified formula is eligible for partial instantiation + std::map< Node, bool > vars; + for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ + vars[q[0][i]] = false; } - } - if( doInst ){ - //also needs patterns - if( q.getNumChildren()==3 && q[2].getNumChildren()==1 ){ - for( unsigned i=0; i<q[2][0].getNumChildren(); i++ ){ - Node pat = q[2][0][i]; - if( pat.getKind()==APPLY_UF ){ - for( unsigned j=0; j<pat.getNumChildren(); j++ ){ - if( !addVariableToPatternList( pat[j], d_pat_var_order[q], var_order ) ){ - doInst = false; + getEligibleInstVars( q[1], vars ); + + //instantiate only if we would force ground instances + std::map< Node, int > var_order; + bool doInst = true; + for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ + if( vars[q[0][i]] ){ + d_vars[q].push_back( q[0][i] ); + var_order[q[0][i]] = i; + }else{ + Trace("lte-partial-inst-debug") << "...do not consider, variable " << q[0][i] << " was not found in correct position in body." << std::endl; + doInst = false; + break; + } + } + if( doInst ){ + //also needs patterns + if( q.getNumChildren()==3 && q[2].getNumChildren()==1 ){ + for( unsigned i=0; i<q[2][0].getNumChildren(); i++ ){ + Node pat = q[2][0][i]; + if( pat.getKind()==APPLY_UF ){ + for( unsigned j=0; j<pat.getNumChildren(); j++ ){ + if( !addVariableToPatternList( pat[j], d_pat_var_order[q], var_order ) ){ + doInst = false; + } } + }else if( !addVariableToPatternList( pat, d_pat_var_order[q], var_order ) ){ + doInst = false; + } + if( !doInst ){ + Trace("lte-partial-inst-debug") << "...do not consider, cannot resolve pattern : " << pat << std::endl; + break; } - }else if( !addVariableToPatternList( pat, d_pat_var_order[q], var_order ) ){ - doInst = false; - } - if( !doInst ){ - Trace("lte-partial-inst-debug") << "...do not consider, cannot resolve pattern : " << pat << std::endl; - break; } + }else{ + Trace("lte-partial-inst-debug") << "...do not consider (must have exactly one pattern)." << std::endl; } - }else{ - Trace("lte-partial-inst-debug") << "...do not consider (must have exactly one pattern)." << std::endl; + } + + + Trace("lte-partial-inst") << "LTE: ...will " << ( doInst ? "" : "not ") << "instantiate " << q << std::endl; + d_do_inst[q] = doInst; + if( doInst ){ + d_lte_asserts.push_back( q ); + d_needsCheck = true; + d_quantEngine->setOwner( q, this ); } } - - - Trace("lte-partial-inst") << "LTE: ...will " << ( doInst ? "" : "not ") << "instantiate " << q << std::endl; - d_do_inst[q] = doInst; - if( doInst ){ - d_lte_asserts.push_back( q ); - d_needsCheck = true; - } - return doInst; } } @@ -188,7 +188,6 @@ void LtePartialInst::getInstantiations( std::vector< Node >& lemmas ) { Assert( !conj.empty() ); lemmas.push_back( NodeManager::currentNM()->mkNode( OR, q.negate(), conj.size()==1 ? conj[0] : NodeManager::currentNM()->mkNode( AND, conj ) ) ); d_wasInvoked = true; - d_quantEngine->getModel()->markQuantifierReduced( q ); } } } diff --git a/src/theory/quantifiers/local_theory_ext.h b/src/theory/quantifiers/local_theory_ext.h index 6e2ee34af..94abf3c90 100644 --- a/src/theory/quantifiers/local_theory_ext.h +++ b/src/theory/quantifiers/local_theory_ext.h @@ -1,13 +1,13 @@ /********************* */ /*! \file local_theory_ext.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief local theory extensions util **/ @@ -55,8 +55,8 @@ private: bool addVariableToPatternList( Node v, std::vector< int >& pat_var_order, std::map< Node, int >& var_order ); public: LtePartialInst( QuantifiersEngine * qe, context::Context* c ); - /** add quantifier : special form of registration */ - bool addQuantifier( Node q ); + /** determine whether this quantified formula will be reduced */ + void preRegisterQuantifier( Node q ); /** was invoked */ bool wasInvoked() { return d_wasInvoked; } diff --git a/src/theory/quantifiers/macros.cpp b/src/theory/quantifiers/macros.cpp index a5e3dada8..582599680 100644 --- a/src/theory/quantifiers/macros.cpp +++ b/src/theory/quantifiers/macros.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file macros.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): Kshitij Bansal + ** Top contributors (to current version): + ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Sort inference module ** @@ -39,9 +39,15 @@ bool QuantifierMacros::simplify( std::vector< Node >& assertions, bool doRewrite d_ground_macros = (r==0); Trace("macros") << "Find macros, ground=" << d_ground_macros << "..." << std::endl; //first, collect macro definitions - for( int i=0; i<(int)assertions.size(); i++ ){ + std::vector< Node > macro_assertions; + for( unsigned i=0; i<assertions.size(); i++ ){ Trace("macros-debug") << " process assertion " << assertions[i] << std::endl; if( processAssertion( assertions[i] ) ){ + PROOF( + if( std::find( macro_assertions.begin(), macro_assertions.end(), assertions[i] )==macro_assertions.end() ){ + macro_assertions.push_back( assertions[i] ); + } + ); //process this assertion again i--; } @@ -56,7 +62,17 @@ bool QuantifierMacros::simplify( std::vector< Node >& assertions, bool doRewrite if( curr!=assertions[i] ){ curr = Rewriter::rewrite( curr ); Trace("macros-rewrite") << "Rewrite " << assertions[i] << " to " << curr << std::endl; - PROOF( ProofManager::currentPM()->addDependence(curr, assertions[i]); ); + //for now, it is dependent upon all assertions involving macros, this is an over-approximation. + //a more fine-grained unsat core computation would require caching dependencies for each subterm of the formula, + // which is expensive. + PROOF( + ProofManager::currentPM()->addDependence(curr, assertions[i]); + for( unsigned j=0; j<macro_assertions.size(); j++ ){ + if( macro_assertions[j]!=assertions[i] ){ + ProofManager::currentPM()->addDependence(curr,macro_assertions[j]); + } + } + ); assertions[i] = curr; retVal = true; } @@ -68,7 +84,7 @@ bool QuantifierMacros::simplify( std::vector< Node >& assertions, bool doRewrite } } if( Trace.isOn("macros-warn") ){ - for( int i=0; i<(int)assertions.size(); i++ ){ + for( unsigned i=0; i<assertions.size(); i++ ){ debugMacroDefinition( assertions[i], assertions[i] ); } } @@ -137,7 +153,7 @@ bool QuantifierMacros::isGroundUfTerm( Node f, Node n ) { d_qe->getTermDatabase()->getVarContainsNode( f, icn, var ); Trace("macros-debug2") << "Get trigger variables for " << icn << std::endl; std::vector< Node > trigger_var; - inst::Trigger::getTriggerVariables( d_qe, icn, f, trigger_var ); + inst::Trigger::getTriggerVariables( icn, f, trigger_var ); Trace("macros-debug2") << "Done." << std::endl; //only if all variables are also trigger variables return trigger_var.size()>=var.size(); @@ -145,18 +161,24 @@ bool QuantifierMacros::isGroundUfTerm( Node f, Node n ) { bool QuantifierMacros::isBoundVarApplyUf( Node n ) { Assert( n.getKind()==APPLY_UF ); - TypeNode tn = n.getOperator().getType(); + TypeNode tno = n.getOperator().getType(); + std::map< Node, bool > vars; for( unsigned i=0; i<n.getNumChildren(); i++ ){ if( n[i].getKind()!=BOUND_VARIABLE ){ return false; } - if( n[i].getType()!=tn[i] ){ + if( n[i].getType()!=tno[i] ){ return false; } - for( unsigned j=0; j<i; j++ ){ - if( n[j]==n[i] ){ - return false; - } + if( !tno[i].isSort() && !tno[i].isReal() && ( !tno[i].isDatatype() || tno[i].isParametricDatatype() ) && + !tno[i].isBitVector() && !tno[i].isString() && !tno[i].isFloatingPoint() ){ + //only non-parametric types are supported + return false; + } + if( vars.find( n[i] )==vars.end() ){ + vars[n[i]] = true; + }else{ + return false; } } return true; @@ -388,13 +410,33 @@ Node QuantifierMacros::simplify( Node n ){ Node op = n.getOperator(); std::map< Node, Node >::iterator it = d_macro_defs.find( op ); if( it!=d_macro_defs.end() && !it->second.isNull() ){ - //do substitution if necessary - ret = it->second; - std::map< Node, std::vector< Node > >::iterator itb = d_macro_basis.find( op ); - if( itb!=d_macro_basis.end() ){ - ret = ret.substitute( itb->second.begin(), itb->second.end(), children.begin(), children.end() ); + //only apply if children are subtypes of arguments + bool success = true; + std::vector< Node > cond; + TypeNode tno = op.getType(); + for( unsigned i=0; i<children.size(); i++ ){ + if( !TermDb::getEnsureTypeCondition( children[i], tno[i], cond ) ){ + //if this does fail, we are incomplete, since we are eliminating quantified formula corresponding to op, + // and not ensuring it applies to n when its types are correct. + //however, this should never fail: we never process types for which we cannot constuct conditions that ensure correct types, e.g. (is-int t). + Assert( false ); + success = false; + break; + } + } + if( success ){ + //do substitution if necessary + ret = it->second; + std::map< Node, std::vector< Node > >::iterator itb = d_macro_basis.find( op ); + if( itb!=d_macro_basis.end() ){ + ret = ret.substitute( itb->second.begin(), itb->second.end(), children.begin(), children.end() ); + } + if( !cond.empty() ){ + Node cc = cond.size()==1 ? cond[0] : NodeManager::currentNM()->mkNode( kind::AND, cond ); + ret = NodeManager::currentNM()->mkNode( kind::ITE, cc, ret, n ); + } + retSet = true; } - retSet = true; } } if( !retSet && childChanged ){ diff --git a/src/theory/quantifiers/macros.h b/src/theory/quantifiers/macros.h index 06e2d652a..39ec2f0a1 100644 --- a/src/theory/quantifiers/macros.h +++ b/src/theory/quantifiers/macros.h @@ -1,13 +1,13 @@ /********************* */ /*! \file macros.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Morgan Deters, Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Pre-process step for detecting quantifier macro definitions **/ diff --git a/src/theory/quantifiers/model_builder.cpp b/src/theory/quantifiers/model_builder.cpp index 95b674cca..3ae36b1d4 100644 --- a/src/theory/quantifiers/model_builder.cpp +++ b/src/theory/quantifiers/model_builder.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file model_builder.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): Kshitij Bansal, Morgan Deters + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Implementation of model builder class **/ @@ -50,14 +50,14 @@ bool QModelBuilder::optUseModel() { void QModelBuilder::debugModel( FirstOrderModel* fm ){ //debug the model: cycle through all instantiations for all quantifiers, report ones that are not true - if( Trace.isOn("quant-model-warn") ){ - Trace("quant-model-warn") << "Testing quantifier instantiations..." << std::endl; + if( Trace.isOn("quant-check-model") ){ + Trace("quant-check-model") << "Testing quantifier instantiations..." << std::endl; int tests = 0; int bad = 0; - for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){ + for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){ Node f = fm->getAssertedQuantifier( i ); std::vector< Node > vars; - for( int j=0; j<(int)f[0].getNumChildren(); j++ ){ + for( unsigned j=0; j<f[0].getNumChildren(); j++ ){ vars.push_back( f[0][j] ); } RepSetIterator riter( d_qe, &(fm->d_rep_set) ); @@ -65,26 +65,26 @@ void QModelBuilder::debugModel( FirstOrderModel* fm ){ while( !riter.isFinished() ){ tests++; std::vector< Node > terms; - for( int i=0; i<riter.getNumTerms(); i++ ){ - terms.push_back( riter.getTerm( i ) ); + for( int k=0; k<riter.getNumTerms(); k++ ){ + terms.push_back( riter.getTerm( k ) ); } Node n = d_qe->getInstantiation( f, vars, terms ); Node val = fm->getValue( n ); if( val!=fm->d_true ){ - Trace("quant-model-warn") << "******* Instantiation " << n << " for " << std::endl; - Trace("quant-model-warn") << " " << f << std::endl; - Trace("quant-model-warn") << " Evaluates to " << val << std::endl; + Trace("quant-check-model") << "******* Instantiation " << n << " for " << std::endl; + Trace("quant-check-model") << " " << f << std::endl; + Trace("quant-check-model") << " Evaluates to " << val << std::endl; bad++; } riter.increment(); } - Trace("quant-model-warn") << "Tested " << tests << " instantiations"; + Trace("quant-check-model") << "Tested " << tests << " instantiations"; if( bad>0 ){ - Trace("quant-model-warn") << ", " << bad << " failed" << std::endl; + Trace("quant-check-model") << ", " << bad << " failed" << std::endl; } - Trace("quant-model-warn") << "." << std::endl; + Trace("quant-check-model") << "." << std::endl; }else{ - Trace("quant-model-warn") << "Warning: Could not test quantifier " << f << std::endl; + Trace("quant-check-model") << "Warning: Could not test quantifier " << f << std::endl; } } } @@ -149,17 +149,21 @@ void QModelBuilderIG::processBuildModel( TheoryModel* m, bool fullModel ) { if( optUseModel() ){ Trace("model-engine-debug") << "Initializing " << fm->getNumAssertedQuantifiers() << " quantifiers..." << std::endl; //check if any quantifiers are un-initialized - for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){ + for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){ Node f = fm->getAssertedQuantifier( i ); if( isQuantifierActive( f ) ){ int lems = initializeQuantifier( f, f ); d_statistics.d_init_inst_gen_lemmas += lems; d_addedLemmas += lems; + if( d_qe->inConflict() ){ + break; + } } } if( d_addedLemmas>0 ){ Trace("model-engine") << "Initialize, Added Lemmas = " << d_addedLemmas << std::endl; }else{ + Assert( !d_qe->inConflict() ); //initialize model fm->initialize(); //analyze the functions @@ -169,7 +173,7 @@ void QModelBuilderIG::processBuildModel( TheoryModel* m, bool fullModel ) { Trace("model-engine-debug") << "Analyzing quantifiers..." << std::endl; d_quant_sat.clear(); d_uf_prefs.clear(); - for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){ + for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){ Node f = fm->getAssertedQuantifier( i ); if( isQuantifierActive( f ) ){ analyzeQuantifier( fm, f ); @@ -186,7 +190,7 @@ void QModelBuilderIG::processBuildModel( TheoryModel* m, bool fullModel ) { d_numQuantNoSelForm = 0; //now, see if we know that any exceptions via InstGen exist Trace("model-engine-debug") << "Perform InstGen techniques for quantifiers..." << std::endl; - for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){ + for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){ Node f = fm->getAssertedQuantifier( i ); if( isQuantifierActive( f ) ){ int lems = doInstGen( fm, f ); @@ -202,7 +206,7 @@ void QModelBuilderIG::processBuildModel( TheoryModel* m, bool fullModel ) { }else{ d_numQuantNoSelForm++; } - if( options::fmfInstGenOneQuantPerRound() && lems>0 ){ + if( d_qe->inConflict() || ( options::fmfInstGenOneQuantPerRound() && lems>0 ) ){ break; } }else if( d_quant_sat.find( f )!=d_quant_sat.end() ){ @@ -276,7 +280,7 @@ int QModelBuilderIG::initializeQuantifier( Node f, Node fp ){ //try to add it Trace("inst-fmf-init") << "Init: try to add match " << d_quant_basis_match[f] << std::endl; //add model basis instantiation - if( d_qe->addInstantiation( fp, d_quant_basis_match[f], false ) ){ + if( d_qe->addInstantiation( fp, d_quant_basis_match[f] ) ){ d_quant_basis_match_added[f] = true; return 1; }else{ @@ -426,8 +430,11 @@ bool QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, i } Debug("fmf-model-eval") << "* Add instantiation " << m << std::endl; //add as instantiation - if( d_qe->addInstantiation( f, m ) ){ + if( d_qe->addInstantiation( f, m, true ) ){ d_addedLemmas++; + if( d_qe->inConflict() ){ + break; + } //if the instantiation is show to be false, and we wish to skip multiple instantiations at once if( eval==-1 ){ riter.increment2( depIndex ); @@ -660,7 +667,7 @@ int QModelBuilderDefault::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, 0, true, inst::Trigger::TR_MAKE_NEW, options::smartTriggers() ); + inst::Trigger* tr = inst::Trigger::mkTrigger( d_qe, f, tr_terms, 0, true, inst::Trigger::TR_MAKE_NEW ); //Notice() << "Trigger = " << (*tr) << std::endl; tr->resetInstantiationRound(); tr->reset( Node::null() ); diff --git a/src/theory/quantifiers/model_builder.h b/src/theory/quantifiers/model_builder.h index b45aa0ff0..906673903 100644 --- a/src/theory/quantifiers/model_builder.h +++ b/src/theory/quantifiers/model_builder.h @@ -1,13 +1,13 @@ /********************* */ /*! \file model_builder.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Model Builder class **/ diff --git a/src/theory/quantifiers/model_engine.cpp b/src/theory/quantifiers/model_engine.cpp index 4b173c833..0bbca88eb 100644 --- a/src/theory/quantifiers/model_engine.cpp +++ b/src/theory/quantifiers/model_engine.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file model_engine.cpp ** \verbatim - ** Original author: Morgan Deters - ** Major contributors: Andrew Reynolds - ** Minor contributors (to current version): Francois Bobot + ** Top contributors (to current version): + ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Implementation of model engine class **/ @@ -62,6 +62,7 @@ void ModelEngine::reset_round( Theory::Effort e ) { void ModelEngine::check( Theory::Effort e, unsigned quant_e ){ if( quant_e==QuantifiersEngine::QEFFORT_MODEL ){ + Assert( !d_quantEngine->inConflict() ); int addedLemmas = 0; FirstOrderModel* fm = d_quantEngine->getModel(); @@ -82,8 +83,10 @@ void ModelEngine::check( Theory::Effort e, unsigned quant_e ){ Trace("model-engine-debug") << "Check model..." << std::endl; d_incomplete_check = false; //print debug - Trace("fmf-model-complete") << std::endl; - debugPrint("fmf-model-complete"); + if( Trace.isOn("fmf-model-complete") ){ + Trace("fmf-model-complete") << std::endl; + debugPrint("fmf-model-complete"); + } //successfully built an acceptable model, now check it addedLemmas += checkModel(); }else{ @@ -98,10 +101,10 @@ void ModelEngine::check( Theory::Effort e, unsigned quant_e ){ if( addedLemmas==0 ){ Trace("model-engine-debug") << "No lemmas added, incomplete = " << d_incomplete_check << std::endl; //CVC4 will answer SAT or unknown - Trace("fmf-consistent") << std::endl; - debugPrint("fmf-consistent"); - }else{ - //otherwise, the search will continue + if( Trace.isOn("fmf-consistent") ){ + Trace("fmf-consistent") << std::endl; + debugPrint("fmf-consistent"); + } } } } @@ -178,49 +181,51 @@ int ModelEngine::checkModel(){ d_addedLemmas = 0; d_totalLemmas = 0; //for statistics - for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){ - Node f = fm->getAssertedQuantifier( i ); - int totalInst = 1; - for( size_t i=0; i<f[0].getNumChildren(); i++ ){ - TypeNode tn = f[0][i].getType(); - if( fm->d_rep_set.hasType( tn ) ){ - totalInst = totalInst * (int)fm->d_rep_set.d_type_reps[ tn ].size(); + if( Trace.isOn("model-engine") ){ + for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){ + Node f = fm->getAssertedQuantifier( i ); + int totalInst = 1; + for( unsigned j=0; j<f[0].getNumChildren(); j++ ){ + TypeNode tn = f[0][j].getType(); + if( fm->d_rep_set.hasType( tn ) ){ + totalInst = totalInst * (int)fm->d_rep_set.d_type_reps[ tn ].size(); + } } + d_totalLemmas += totalInst; } - d_totalLemmas += totalInst; } Trace("model-engine-debug") << "Do exhaustive instantiation..." << std::endl; // FMC uses two sub-effort levels int e_max = options::mbqiMode()==MBQI_FMC || options::mbqiMode()==MBQI_FMC_INTERVAL ? 2 : ( options::mbqiMode()==MBQI_TRUST ? 0 : 1 ); for( int e=0; e<e_max; e++) { - if (d_addedLemmas==0) { - for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){ - Node f = fm->getAssertedQuantifier( i ); - Trace("fmf-exh-inst") << "-> Exhaustive instantiate " << f << ", effort = " << e << "..." << std::endl; - //determine if we should check this quantifier - if( considerQuantifiedFormula( f ) ){ - exhaustiveInstantiate( f, e ); - if( Trace.isOn("model-engine-warn") ){ - if( d_addedLemmas>10000 ){ - Debug("fmf-exit") << std::endl; - debugPrint("fmf-exit"); - exit( 0 ); - } - } - if( optOneQuantPerRound() && d_addedLemmas>0 ){ - break; - } - }else{ - Trace("fmf-exh-inst") << "-> Inactive : " << f << std::endl; + for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){ + Node f = fm->getAssertedQuantifier( i, true ); + Trace("fmf-exh-inst") << "-> Exhaustive instantiate " << f << ", effort = " << e << "..." << std::endl; + //determine if we should check this quantifier + if( considerQuantifiedFormula( f ) ){ + exhaustiveInstantiate( f, e ); + if( d_quantEngine->inConflict() || ( optOneQuantPerRound() && d_addedLemmas>0 ) ){ + break; } + }else{ + Trace("fmf-exh-inst") << "-> Inactive : " << f << std::endl; } } + if( d_addedLemmas>0 ){ + break; + }else{ + Assert( !d_quantEngine->inConflict() ); + } } //print debug information - Trace("model-engine") << "Added Lemmas = " << d_addedLemmas << " / " << d_triedLemmas << " / "; - Trace("model-engine") << d_totalLemmas << std::endl; + if( d_quantEngine->inConflict() ){ + Trace("model-engine") << "Conflict = " << d_quantEngine->getNumLemmasWaiting() << " / " << d_quantEngine->getNumLemmasAddedThisRound() << std::endl; + }else{ + Trace("model-engine") << "Added Lemmas = " << d_addedLemmas << " / " << d_triedLemmas << " / "; + Trace("model-engine") << d_totalLemmas << std::endl; + } return d_addedLemmas; } @@ -266,15 +271,17 @@ void ModelEngine::exhaustiveInstantiate( Node f, int effort ){ d_incomplete_check = d_incomplete_check || mb->d_incomplete_check; d_statistics.d_mbqi_inst_lemmas += mb->d_addedLemmas; }else{ - Trace("fmf-exh-inst-debug") << " Instantiation Constants: "; - for( size_t i=0; i<f[0].getNumChildren(); i++ ){ - Trace("fmf-exh-inst-debug") << d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i ) << " "; + if( Trace.isOn("fmf-exh-inst-debug") ){ + Trace("fmf-exh-inst-debug") << " Instantiation Constants: "; + for( size_t i=0; i<f[0].getNumChildren(); i++ ){ + Trace("fmf-exh-inst-debug") << d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i ) << " "; + } + Trace("fmf-exh-inst-debug") << std::endl; } - Trace("fmf-exh-inst-debug") << std::endl; //create a rep set iterator and iterate over the (relevant) domain of the quantifier RepSetIterator riter( d_quantEngine, &(d_quantEngine->getModel()->d_rep_set) ); if( riter.setQuantifier( f ) ){ - Trace("fmf-exh-inst") << "...exhaustive instantiation incomplete=" << riter.d_incomplete << "..." << std::endl; + Trace("fmf-exh-inst") << "...exhaustive instantiation set, incomplete=" << riter.d_incomplete << "..." << std::endl; if( !riter.d_incomplete ){ int triedLemmas = 0; int addedLemmas = 0; @@ -287,8 +294,11 @@ void ModelEngine::exhaustiveInstantiate( Node f, int effort ){ Debug("fmf-model-eval") << "* Add instantiation " << m << std::endl; triedLemmas++; //add as instantiation - if( d_quantEngine->addInstantiation( f, m ) ){ + if( d_quantEngine->addInstantiation( f, m, true ) ){ addedLemmas++; + if( d_quantEngine->inConflict() ){ + break; + } }else{ Debug("fmf-model-eval") << "* Failed Add instantiation " << m << std::endl; } @@ -299,6 +309,7 @@ void ModelEngine::exhaustiveInstantiate( Node f, int effort ){ d_statistics.d_exh_inst_lemmas += addedLemmas; } }else{ + Trace("fmf-exh-inst") << "...exhaustive instantiation failed to set, incomplete=" << riter.d_incomplete << "..." << std::endl; Assert( riter.d_incomplete ); } //if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round @@ -308,15 +319,15 @@ void ModelEngine::exhaustiveInstantiate( Node f, int effort ){ void ModelEngine::debugPrint( const char* c ){ Trace( c ) << "Quantifiers: " << std::endl; - for( int i=0; i<(int)d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ - Node f = d_quantEngine->getModel()->getAssertedQuantifier( i ); + for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ + Node q = d_quantEngine->getModel()->getAssertedQuantifier( i ); Trace( c ) << " "; - if( !d_quantEngine->getModelBuilder()->isQuantifierActive( f ) ){ + if( !d_quantEngine->getModelBuilder()->isQuantifierActive( q ) ){ Trace( c ) << "*Inactive* "; }else{ Trace( c ) << " "; } - Trace( c ) << f << std::endl; + Trace( c ) << q << std::endl; } //d_quantEngine->getModel()->debugPrint( c ); } diff --git a/src/theory/quantifiers/model_engine.h b/src/theory/quantifiers/model_engine.h index 1fb4255b2..12f18aa08 100644 --- a/src/theory/quantifiers/model_engine.h +++ b/src/theory/quantifiers/model_engine.h @@ -1,13 +1,13 @@ /********************* */ /*! \file model_engine.h ** \verbatim - ** Original author: Morgan Deters - ** Major contributors: Andrew Reynolds - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Morgan Deters, Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Model Engine class **/ diff --git a/src/theory/quantifiers/quant_conflict_find.cpp b/src/theory/quantifiers/quant_conflict_find.cpp index a890276f7..ca87a607d 100644 --- a/src/theory/quantifiers/quant_conflict_find.cpp +++ b/src/theory/quantifiers/quant_conflict_find.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file quant_conflict_find.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Clark Barrett, Tim King, Andrew Reynolds ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief quant conflict find class ** @@ -22,19 +22,32 @@ #include "theory/quantifiers/quant_util.h" #include "theory/quantifiers/term_database.h" #include "theory/quantifiers/trigger.h" +#include "theory/quantifiers/first_order_model.h" #include "theory/theory_engine.h" -using namespace CVC4; using namespace CVC4::kind; -using namespace CVC4::theory; -using namespace CVC4::theory::quantifiers; using namespace std; namespace CVC4 { +namespace theory { +namespace quantifiers { +QuantInfo::QuantInfo() + : d_mg( NULL ) +{} + +QuantInfo::~QuantInfo() { + delete d_mg; + for(std::map< int, MatchGen * >::iterator i = d_var_mg.begin(), + iend=d_var_mg.end(); i != iend; ++i) { + MatchGen* currentMatchGenerator = (*i).second; + delete currentMatchGenerator; + } + d_var_mg.clear(); +} -void QuantInfo::initialize( Node q, Node qn ) { +void QuantInfo::initialize( QuantConflictFind * p, Node q, Node qn ) { d_q = q; for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ d_match.push_back( TNode::null() ); @@ -95,6 +108,59 @@ void QuantInfo::initialize( Node q, Node qn ) { Trace("qcf-invalid") << "QCF invalid : body of formula cannot be processed." << std::endl; } Trace("qcf-qregister-summary") << "QCF register : " << ( d_mg->isValid() ? "VALID " : "INVALID" ) << " : " << q << std::endl; + + if( d_mg->isValid() ){ + //optimization : record variable argument positions for terms that must be matched + std::vector< TNode > vars; + //TODO: revisit this, makes QCF faster, but misses conflicts due to caring about paths that may not be relevant (starExec jobs 14136/14137) + //if( options::qcfSkipRd() ){ + // for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){ + // vars.push_back( d_vars[j] ); + // } + //} + //get all variables that are always relevant + std::map< TNode, bool > visited; + getPropagateVars( vars, q[1], false, visited ); + for( unsigned j=0; j<vars.size(); j++ ){ + Node v = vars[j]; + TNode f = p->getTermDatabase()->getMatchOperator( v ); + if( !f.isNull() ){ + Trace("qcf-opt") << "Record variable argument positions in " << v << ", op=" << f << "..." << std::endl; + for( unsigned k=0; k<v.getNumChildren(); k++ ){ + Node n = v[k]; + std::map< TNode, int >::iterator itv = d_var_num.find( n ); + if( itv!=d_var_num.end() ){ + Trace("qcf-opt") << " arg " << k << " is var #" << itv->second << std::endl; + if( std::find( d_var_rel_dom[itv->second][f].begin(), d_var_rel_dom[itv->second][f].end(), k )==d_var_rel_dom[itv->second][f].end() ){ + d_var_rel_dom[itv->second][f].push_back( k ); + } + } + } + } + } + } +} + +void QuantInfo::getPropagateVars( std::vector< TNode >& vars, TNode n, bool pol, std::map< TNode, bool >& visited ){ + std::map< TNode, bool >::iterator itv = visited.find( n ); + if( itv==visited.end() ){ + visited[n] = true; + bool rec = true; + bool newPol = pol; + if( d_var_num.find( n )!=d_var_num.end() ){ + Assert( std::find( vars.begin(), vars.end(), n )==vars.end() ); + vars.push_back( n ); + }else if( MatchGen::isHandledBoolConnective( n ) ){ + Assert( n.getKind()!=IMPLIES ); + QuantPhaseReq::getEntailPolarity( n, 0, true, pol, rec, newPol ); + } + Trace("qcf-opt-debug") << "getPropagateVars " << n << ", pol = " << pol << ", rec = " << rec << std::endl; + if( rec ){ + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + getPropagateVars( vars, n[i], pol, visited ); + } + } + } } void QuantInfo::registerNode( Node n, bool hasPol, bool pol, bool beneathQuant ) { @@ -315,7 +381,7 @@ int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, int vn, boo return 1; }else{ //std::map< int, TNode >::iterator itm = d_match.find( v ); - + bool isGroundRep = false; if( vn!=-1 ){ Debug("qcf-match-debug") << " ...Variable bound to variable" << std::endl; //std::map< int, TNode >::iterator itmn = d_match.find( vn ); @@ -361,13 +427,14 @@ int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, int vn, boo }else{ Debug("qcf-match-debug") << " ...Variable bound to ground" << std::endl; if( d_match[v].isNull() ){ + //isGroundRep = true; ?? }else{ //compare ground values Debug("qcf-match-debug") << " -> Ground value, compare " << d_match[v] << " "<< n << std::endl; return p->areMatchEqual( d_match[v], n ) ? 0 : -1; } } - if( setMatch( p, v, n ) ){ + if( setMatch( p, v, n, isGroundRep ) ){ Debug("qcf-match-debug") << " -> success" << std::endl; return 1; }else{ @@ -433,8 +500,23 @@ bool QuantInfo::isConstrainedVar( int v ) { } } -bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n ) { +bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n, bool isGroundRep ) { if( getCurrentCanBeEqual( p, v, n ) ){ + if( isGroundRep ){ + //fail if n does not exist in the relevant domain of each of the argument positions + std::map< int, std::map< TNode, std::vector< unsigned > > >::iterator it = d_var_rel_dom.find( v ); + if( it!=d_var_rel_dom.end() ){ + for( std::map< TNode, std::vector< unsigned > >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ + for( unsigned j=0; j<it2->second.size(); j++ ){ + Debug("qcf-match-debug2") << n << " in relevant domain " << it2->first << "." << it2->second[j] << "?" << std::endl; + if( !p->getTermDatabase()->inRelevantDomain( it2->first, it2->second[j], n ) ){ + Debug("qcf-match-debug") << " -> fail, since " << n << " is not in relevant domain of " << it2->first << "." << it2->second[j] << std::endl; + return false; + } + } + } + } + } Debug("qcf-match-debug") << "-- bind : " << v << " -> " << n << ", checked " << d_curr_var_deq[v].size() << " disequalities" << std::endl; d_match[v] = n; return true; @@ -477,7 +559,22 @@ bool QuantInfo::entailmentTest( QuantConflictFind * p, Node lit, bool chEnt ) { Trace("qcf-tconstraint-debug") << "...constraint " << lit << " is disentailed (rewrites to false)." << std::endl; return false; }else if( rew!=p->d_true ){ - //if checking for conflicts, we must be sure that the constraint is entailed + //if checking for conflicts, we must be sure that the (negation of) constraint is (not) entailed + if( !chEnt ){ + rew = Rewriter::rewrite( rew.negate() ); + } + //check if it is entailed + Trace("qcf-tconstraint-debug") << "Check entailment of " << rew << "..." << std::endl; + std::pair<bool, Node> et = p->getQuantifiersEngine()->getTheoryEngine()->entailmentCheck(THEORY_OF_TYPE_BASED, rew ); + ++(p->d_statistics.d_entailment_checks); + Trace("qcf-tconstraint-debug") << "ET result : " << et.first << " " << et.second << std::endl; + if( !et.first ){ + Trace("qcf-tconstraint-debug") << "...cannot show entailment of " << rew << "." << std::endl; + return !chEnt; + }else{ + return chEnt; + } +/* if( chEnt ){ //check if it is entailed Trace("qcf-tconstraint-debug") << "Check entailment of " << rew << "..." << std::endl; @@ -494,6 +591,7 @@ bool QuantInfo::entailmentTest( QuantConflictFind * p, Node lit, bool chEnt ) { Trace("qcf-tconstraint-debug") << "...does not need to be entailed." << std::endl; return true; } +*/ }else{ Trace("qcf-tconstraint-debug") << "...rewrites to true." << std::endl; return true; @@ -538,7 +636,7 @@ bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assign if( !z.isNull() ){ Trace("qcf-tconstraint-debug") << "...set " << d_vars[vn] << " = " << z << std::endl; assigned.push_back( vn ); - if( !setMatch( p, vn, z ) ){ + if( !setMatch( p, vn, z, false ) ){ success = false; break; } @@ -580,7 +678,7 @@ bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assign if( !sum.isNull() ){ assigned.push_back( slv_v ); Trace("qcf-tconstraint-debug") << "...set " << d_vars[slv_v] << " = " << sum << std::endl; - if( !setMatch( p, slv_v, sum ) ){ + if( !setMatch( p, slv_v, sum, false ) ){ success = false; } p->d_tempCache.push_back( sum ); @@ -666,7 +764,7 @@ bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assign int currIndex = d_una_eqc_count[d_una_index]; d_una_eqc_count[d_una_index]++; Trace("qcf-check-unassign") << d_unassigned[d_una_index] << "->" << p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] << std::endl; - if( setMatch( p, d_unassigned[d_una_index], p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] ) ){ + if( setMatch( p, d_unassigned[d_una_index], p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex], true ) ){ d_match_term[d_unassigned[d_una_index]] = TNode::null(); Trace("qcf-check-unassign") << "Succeeded match " << d_una_index << std::endl; d_una_index++; @@ -801,6 +899,7 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar ) if( isVar ){ Assert( qi->d_var_num.find( n )!=qi->d_var_num.end() ); if( n.getKind()==ITE ){ + /* d_type = typ_ite_var; d_type_not = false; d_n = n; @@ -817,15 +916,16 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar ) } } }else{ +*/ d_type = typ_invalid; - } + //} }else{ d_type = isHandledUfTerm( n ) ? typ_var : typ_tsym; d_qni_var_num[0] = qi->getVarNum( n ); d_qni_size++; d_type_not = false; d_n = n; - //Node f = getOperator( n ); + //Node f = getMatchOperator( n ); for( unsigned j=0; j<d_n.getNumChildren(); j++ ){ Node nn = d_n[j]; Trace("qcf-qregister-debug") << " " << d_qni_size; @@ -1031,16 +1131,27 @@ void MatchGen::reset_round( QuantConflictFind * p ) { d_qni_gterm_rep[it->first] = p->getRepresentative( it->second ); } if( d_type==typ_ground ){ - int e = p->evaluate( d_n ); - if( e==1 ){ - d_ground_eval[0] = p->d_true; - }else if( e==-1 ){ - d_ground_eval[0] = p->d_false; + //int e = p->evaluate( d_n ); + //if( e==1 ){ + // d_ground_eval[0] = p->d_true; + //}else if( e==-1 ){ + // d_ground_eval[0] = p->d_false; + //} + //modified + for( unsigned i=0; i<2; i++ ){ + if( p->getTermDatabase()->isEntailed( d_n, i==0 ) ){ + d_ground_eval[0] = i==0 ? p->d_true : p->d_false; + } } }else if( d_type==typ_eq ){ for( unsigned i=0; i<d_n.getNumChildren(); i++ ){ if( !d_n[i].hasBoundVar() ){ - d_ground_eval[i] = p->evaluateTerm( d_n[i] ); + TNode t = p->getTermDatabase()->getEntailedTerm( d_n[i] ); + if( t.isNull() ){ + d_ground_eval[i] = d_n[i]; + }else{ + d_ground_eval[i] = t; + } } } } @@ -1073,14 +1184,18 @@ void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) { int vn = qi->getCurrentRepVar( qi->getVarNum( n ) ); if( vn==-1 ){ //evaluate the value, see if it is compatible - int e = p->evaluate( n ); - if( ( e==1 && d_tgt ) || ( e==0 && !d_tgt ) ){ + //int e = p->evaluate( n ); + //if( ( e==1 && d_tgt ) || ( e==0 && !d_tgt ) ){ + // d_child_counter = 0; + //} + //modified + if( p->getTermDatabase()->isEntailed( n, d_tgt ) ){ d_child_counter = 0; } }else{ //unassigned, set match to true/false d_qni_bound[0] = vn; - qi->setMatch( p, vn, d_tgt ? p->d_true : p->d_false ); + qi->setMatch( p, vn, d_tgt ? p->d_true : p->d_false, false ); d_child_counter = 0; } if( d_child_counter==0 ){ @@ -1088,7 +1203,7 @@ void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) { } }else if( d_type==typ_var ){ Assert( isHandledUfTerm( d_n ) ); - Node f = getOperator( p, d_n ); + Node f = getMatchOperator( p, d_n ); Debug("qcf-match-debug") << " reset: Var will match operators of " << f << std::endl; TermArgTrie * qni = p->getTermDatabase()->getTermArgTrie( Node::null(), f ); if( qni!=NULL ){ @@ -1242,12 +1357,12 @@ bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) { Debug("qcf-match-debug") << "..." << std::endl; while( ( success && d_binding_it!=d_qni_bound.end() ) || doFail ){ - std::map< int, MatchGen * >::iterator itm; + QuantInfo::VarMgMap::const_iterator itm; if( !doFail ){ Debug("qcf-match-debug") << " check variable " << d_binding_it->second << std::endl; - itm = qi->d_var_mg.find( d_binding_it->second ); + itm = qi->var_mg_find( d_binding_it->second ); } - if( doFail || ( d_binding_it->first!=0 && itm!=qi->d_var_mg.end() ) ){ + if( doFail || ( d_binding_it->first!=0 && itm != qi->var_mg_end() ) ){ Debug("qcf-match-debug") << " we had bound variable " << d_binding_it->second << ", reset = " << doReset << std::endl; if( doReset ){ itm->second->reset( p, true, qi ); @@ -1261,7 +1376,9 @@ bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) { --d_binding_it; Debug("qcf-match-debug") << " decrement..." << std::endl; } - }while( success && ( d_binding_it->first==0 || qi->d_var_mg.find( d_binding_it->second )==qi->d_var_mg.end() ) ); + }while( success && + ( d_binding_it->first==0 || + (!qi->containsVarMg(d_binding_it->second)))); doReset = false; doFail = false; }else{ @@ -1318,17 +1435,6 @@ bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) { d_qni_bound_cons.clear(); } } - /* - if( d_type==typ_var && p->d_effort==QuantConflictFind::effort_mc && !d_matched_basis ){ - d_matched_basis = true; - Node f = getOperator( d_n ); - TNode mbo = p->getTermDatabase()->getModelBasisOpTerm( f ); - if( qi->setMatch( p, d_qni_var_num[0], mbo ) ){ - success = true; - d_qni_bound[0] = d_qni_var_num[0]; - } - } - */ } Debug("qcf-match") << " ...finished matching for " << d_n << ", success = " << success << std::endl; d_wasSet = success; @@ -1548,7 +1654,7 @@ bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) { if( it != d_qn[index]->d_data.end() ) { d_qni.push_back( it ); //set the match - if( it->first.getType().isComparableTo( qi->d_var_types[repVar] ) && qi->setMatch( p, d_qni_bound[index], it->first ) ){ + if( it->first.getType().isComparableTo( qi->d_var_types[repVar] ) && qi->setMatch( p, d_qni_bound[index], it->first, true ) ){ Debug("qcf-match-debug") << " Binding variable" << std::endl; if( d_qn.size()<d_qni_size ){ d_qn.push_back( &it->second ); @@ -1593,7 +1699,7 @@ bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) { d_qni[index]++; if( d_qni[index]!=d_qn[index]->d_data.end() ){ success = true; - if( qi->setMatch( p, itb->second, d_qni[index]->first ) ){ + if( qi->setMatch( p, itb->second, d_qni[index]->first, true ) ){ Debug("qcf-match-debug") << " Bind next variable" << std::endl; if( d_qn.size()<d_qni_size ){ d_qn.push_back( &d_qni[index]->second ); @@ -1679,12 +1785,14 @@ bool MatchGen::isHandledBoolConnective( TNode n ) { bool MatchGen::isHandledUfTerm( TNode n ) { //return n.getKind()==APPLY_UF || n.getKind()==STORE || n.getKind()==SELECT || // n.getKind()==APPLY_CONSTRUCTOR || n.getKind()==APPLY_SELECTOR_TOTAL || n.getKind()==APPLY_TESTER; + //TODO : treat APPLY_TESTER as a T-constraint instead of matching (currently leads to overabundance of instantiations) + //return inst::Trigger::isAtomicTriggerKind( n.getKind() ) && ( !options::qcfTConstraint() || n.getKind()!=APPLY_TESTER ); return inst::Trigger::isAtomicTriggerKind( n.getKind() ); } -Node MatchGen::getOperator( QuantConflictFind * p, Node n ) { +Node MatchGen::getMatchOperator( QuantConflictFind * p, Node n ) { if( isHandledUfTerm( n ) ){ - return p->getTermDatabase()->getOperator( n ); + return p->getTermDatabase()->getMatchOperator( n ); }else{ return Node::null(); } @@ -1707,8 +1815,7 @@ bool MatchGen::isHandled( TNode n ) { QuantConflictFind::QuantConflictFind( QuantifiersEngine * qe, context::Context* c ) : QuantifiersModule( qe ), -d_conflict( c, false ), -d_qassert( c ) { +d_conflict( c, false ) { d_fid_count = 0; d_true = NodeManager::currentNM()->mkConst<bool>(true); d_false = NodeManager::currentNM()->mkConst<bool>(false); @@ -1733,7 +1840,7 @@ void QuantConflictFind::registerQuantifier( Node q ) { Trace("qcf-qregister") << " : " << q << std::endl; //make QcfNode structure Trace("qcf-qregister") << "- Get relevant equality/disequality pairs, calculate flattening..." << std::endl; - d_qinfo[q].initialize( q, q[1] ); + d_qinfo[q].initialize( this, q, q[1] ); //debug print Trace("qcf-qregister") << "- Flattened structure is :" << std::endl; @@ -1748,96 +1855,16 @@ void QuantConflictFind::registerQuantifier( Node q ) { Trace("qcf-qregister") << std::endl; } } - + Trace("qcf-qregister") << "Done registering quantifier." << std::endl; } } -int QuantConflictFind::evaluate( Node n, bool pref, bool hasPref ) { - int ret = 0; - if( n.getKind()==EQUAL ){ - Node n1 = evaluateTerm( n[0] ); - Node n2 = evaluateTerm( n[1] ); - Debug("qcf-eval") << "Evaluate : Normalize " << n << " to " << n1 << " = " << n2 << std::endl; - if( areEqual( n1, n2 ) ){ - ret = 1; - }else if( areDisequal( n1, n2 ) ){ - ret = -1; - } - //else if( d_effort>QuantConflictFind::effort_conflict ){ - // ret = -1; - //} - }else if( MatchGen::isHandledUfTerm( n ) ){ //predicate - Node nn = evaluateTerm( n ); - Debug("qcf-eval") << "Evaluate : Normalize " << nn << " to " << n << std::endl; - if( areEqual( nn, d_true ) ){ - ret = 1; - }else if( areEqual( nn, d_false ) ){ - ret = -1; - } - //else if( d_effort>QuantConflictFind::effort_conflict ){ - // ret = -1; - //} - }else if( n.getKind()==NOT ){ - return -evaluate( n[0] ); - }else if( n.getKind()==ITE ){ - int cev1 = evaluate( n[0] ); - int cevc[2] = { 0, 0 }; - for( unsigned i=0; i<2; i++ ){ - if( ( i==0 && cev1!=-1 ) || ( i==1 && cev1!=1 ) ){ - cevc[i] = evaluate( n[i+1] ); - if( cev1!=0 ){ - ret = cevc[i]; - break; - }else if( cevc[i]==0 ){ - break; - } - } - } - if( ret==0 && cevc[0]!=0 && cevc[0]==cevc[1] ){ - ret = cevc[0]; - } - }else if( n.getKind()==IFF ){ - int cev1 = evaluate( n[0] ); - if( cev1!=0 ){ - int cev2 = evaluate( n[1] ); - if( cev2!=0 ){ - ret = cev1==cev2 ? 1 : -1; - } - } - - }else{ - int ssval = 0; - if( n.getKind()==OR ){ - ssval = 1; - }else if( n.getKind()==AND ){ - ssval = -1; - } - bool isUnk = false; - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - int cev = evaluate( n[i] ); - if( cev==ssval ){ - ret = ssval; - break; - }else if( cev==0 ){ - isUnk = true; - } - } - if( ret==0 && !isUnk ){ - ret = -ssval; - } - } - Debug("qcf-eval") << "Evaluate " << n << " to " << ret << std::endl; - return ret; -} - short QuantConflictFind::getMaxQcfEffort() { if( options::qcfMode()==QCF_CONFLICT_ONLY ){ return effort_conflict; - }else if( options::qcfMode()==QCF_PROP_EQ ){ + }else if( options::qcfMode()==QCF_PROP_EQ || options::qcfMode()==QCF_PARTIAL ){ return effort_prop_eq; - }else if( options::qcfMode()==QCF_MC ){ - return effort_mc; }else{ return 0; } @@ -1862,48 +1889,13 @@ bool QuantConflictFind::areMatchDisequal( TNode n1, TNode n2 ) { //-------------------------------------------------- handling assertions / eqc void QuantConflictFind::assertNode( Node q ) { + /* if( d_quantEngine->hasOwnership( q, this ) ){ Trace("qcf-proc") << "QCF : assertQuantifier : "; debugPrintQuant("qcf-proc", q); Trace("qcf-proc") << std::endl; - d_qassert.push_back( q ); - //set the eqRegistries that this depends on to true - //for( std::map< EqRegistry *, bool >::iterator it = d_qinfo[q].d_rel_eqr.begin(); it != d_qinfo[q].d_rel_eqr.end(); ++it ){ - // it->first->d_active.set( true ); - //} } -} - -Node QuantConflictFind::evaluateTerm( Node n ) { - if( MatchGen::isHandledUfTerm( n ) ){ - Node f = MatchGen::getOperator( this, n ); - Node nn; - if( getEqualityEngine()->hasTerm( n ) ){ - nn = getTermDatabase()->existsTerm( f, n ); - }else{ - std::vector< TNode > args; - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - Node c = evaluateTerm( n[i] ); - args.push_back( c ); - } - nn = getTermDatabase()->d_func_map_trie[f].existsTerm( args ); - } - if( !nn.isNull() ){ - Debug("qcf-eval") << "GT: Term " << nn << " for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl; - return getRepresentative( nn ); - }else{ - Debug("qcf-eval") << "GT: No term for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl; - return n; - } - }else if( n.getKind()==ITE ){ - int v = evaluate( n[0], false, false ); - if( v==1 ){ - return evaluateTerm( n[1] ); - }else if( v==-1 ){ - return evaluateTerm( n[2] ); - } - } - return getRepresentative( n ); + */ } /** new node */ @@ -1965,28 +1957,12 @@ void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) { //determine order for quantified formulas std::vector< Node > qorder; - std::map< Node, bool > qassert; - //mark which are asserted - for( unsigned i=0; i<d_qassert.size(); i++ ){ - qassert[d_qassert[i]] = true; - } - //add which ones are specified in the order - for( unsigned i=0; i<d_quant_order.size(); i++ ){ - Node n = d_quant_order[i]; - if( std::find( qorder.begin(), qorder.end(), n )==qorder.end() && qassert.find( n )!=qassert.end() ){ - qorder.push_back( n ); - } - } - d_quant_order.clear(); - d_quant_order.insert( d_quant_order.begin(), qorder.begin(), qorder.end() ); - //add remaining - for( unsigned i=0; i<d_qassert.size(); i++ ){ - Node n = d_qassert[i]; - if( std::find( qorder.begin(), qorder.end(), n )==qorder.end() ){ - qorder.push_back( n ); + for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ + Node q = d_quantEngine->getModel()->getAssertedQuantifier( i, true ); + if( d_quantEngine->hasOwnership( q, this ) ){ + qorder.push_back( q ); } } - if( Trace.isOn("qcf-debug") ){ Trace("qcf-debug") << std::endl; debugPrint("qcf-debug"); @@ -2002,7 +1978,7 @@ void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) { QuantInfo * qi = &d_qinfo[q]; Assert( d_qinfo.find( q )!=d_qinfo.end() ); - if( qi->d_mg->isValid() ){ + if( qi->matchGeneratorIsValid() ){ Trace("qcf-check") << "Check quantified formula "; debugPrintQuant("qcf-check", q); Trace("qcf-check") << " : " << q << "..." << std::endl; @@ -2011,7 +1987,7 @@ void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) { qi->reset_round( this ); //try to make a matches making the body false Trace("qcf-check-debug") << "Get next match..." << std::endl; - while( qi->d_mg->getNextMatch( this, qi ) ){ + while( qi->getNextMatch( this ) ){ Trace("qcf-inst") << "*** Produced match at effort " << e << " : " << std::endl; qi->debugPrintMatch("qcf-inst"); Trace("qcf-inst") << std::endl; @@ -2021,22 +1997,21 @@ void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) { std::vector< Node > terms; qi->getMatch( terms ); if( !qi->isTConstraintSpurious( this, terms ) ){ + //for debugging if( Debug.isOn("qcf-check-inst") ){ - //if( e==effort_conflict ){ Node inst = d_quantEngine->getInstantiation( q, terms ); Debug("qcf-check-inst") << "Check instantiation " << inst << "..." << std::endl; - Assert( evaluate( inst )!=1 ); - Assert( evaluate( inst )==-1 || e>effort_conflict ); - //} + Assert( !getTermDatabase()->isEntailed( inst, true ) ); + Assert( getTermDatabase()->isEntailed( inst, false ) || e>effort_conflict ); } - if( d_quantEngine->addInstantiation( q, terms, false ) ){ + if( d_quantEngine->addInstantiation( q, terms ) ){ Trace("qcf-check") << " ... Added instantiation" << std::endl; Trace("qcf-inst") << "*** Was from effort " << e << " : " << std::endl; qi->debugPrintMatch("qcf-inst"); Trace("qcf-inst") << std::endl; ++addedLemmas; if( e==effort_conflict ){ - d_quant_order.insert( d_quant_order.begin(), q ); + d_quantEngine->markRelevant( q ); ++(d_statistics.d_conflict_inst); if( options::qcfAllConflict() ){ isConflict = true; @@ -2045,11 +2020,14 @@ void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) { } break; }else if( e==effort_prop_eq ){ + d_quantEngine->markRelevant( q ); ++(d_statistics.d_prop_inst); } }else{ Trace("qcf-inst") << " ... Failed to add instantiation" << std::endl; - //Assert( false ); + //this should only happen if the algorithm generates the same propagating instance twice this round + //in this case, break to avoid exponential behavior + break; } } //clean up assigned @@ -2062,6 +2040,7 @@ void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) { Trace("qcf-inst") << " ... Spurious instantiation (match is inconsistent)" << std::endl; } } + Trace("qcf-check") << "Done, conflict = " << d_conflict << std::endl; if( d_conflict ){ break; } @@ -2099,60 +2078,24 @@ void QuantConflictFind::computeRelevantEqr() { //d_uf_terms.clear(); //d_eqc_uf_terms.clear(); d_eqcs.clear(); - d_model_basis.clear(); //d_arg_reps.clear(); //double clSet = 0; //if( Trace.isOn("qcf-opt") ){ // clSet = double(clock())/double(CLOCKS_PER_SEC); //} - //long nTermst = 0; - //long nTerms = 0; - //long nEqc = 0; - - //which nodes are irrelevant for disequality matches - std::map< TNode, bool > irrelevant_dnode; //now, store matches eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() ); while( !eqcs_i.isFinished() ){ - //nEqc++; Node r = (*eqcs_i); if( getTermDatabase()->hasTermCurrent( r ) ){ TypeNode rtn = r.getType(); - if( options::qcfMode()==QCF_MC ){ - std::map< TypeNode, std::vector< TNode > >::iterator itt = d_eqcs.find( rtn ); - if( itt==d_eqcs.end() ){ - Node mb = getTermDatabase()->getModelBasisTerm( rtn ); - if( !getEqualityEngine()->hasTerm( mb ) ){ - Trace("qcf-warn") << "WARNING: Model basis term does not exist!" << std::endl; - Assert( false ); - } - Node mbr = getRepresentative( mb ); - if( mbr!=r ){ - d_eqcs[rtn].push_back( mbr ); - } - d_eqcs[rtn].push_back( r ); - d_model_basis[rtn] = mb; - }else{ - itt->second.push_back( r ); - } - }else{ - if( !options::cbqi() || !TermDb::hasInstConstAttr( r ) ){ - d_eqcs[rtn].push_back( r ); - } + if( !options::cbqi() || !TermDb::hasInstConstAttr( r ) ){ + d_eqcs[rtn].push_back( r ); } } ++eqcs_i; } - /* - if( Trace.isOn("qcf-opt") ){ - double clSet2 = double(clock())/double(CLOCKS_PER_SEC); - Trace("qcf-opt") << "Compute rel eqc : " << std::endl; - Trace("qcf-opt") << " " << nEqc << " equivalence classes. " << std::endl; - Trace("qcf-opt") << " " << nTerms << " / " << nTermst << " terms." << std::endl; - Trace("qcf-opt") << " Time : " << (clSet2-clSet) << std::endl; - } - */ } } @@ -2179,21 +2122,6 @@ void QuantConflictFind::debugPrint( const char * c ) { ++eqc_i; } Trace(c) << (pr ? " " : "" ) << "}" << std::endl; - /* - EqcInfo * eqcn = getEqcInfo( n, false ); - if( eqcn ){ - Trace(c) << " DEQ : {"; - pr = false; - for( NodeBoolMap::iterator it = eqcn->d_diseq.begin(); it != eqcn->d_diseq.end(); ++it ){ - if( (*it).second ){ - Trace(c) << (pr ? "," : "" ) << " " << (*it).first; - pr = true; - } - } - Trace(c) << (pr ? " " : "" ) << "}" << std::endl; - } - //} - */ ++eqcs_i; } } @@ -2255,5 +2183,6 @@ TNode QuantConflictFind::getZero( Kind k ) { } } - -} +} /* namespace CVC4::theory::quantifiers */ +} /* namespace CVC4::theory */ +} /* namespace CVC4 */ diff --git a/src/theory/quantifiers/quant_conflict_find.h b/src/theory/quantifiers/quant_conflict_find.h index 11299b532..8b42b0916 100644 --- a/src/theory/quantifiers/quant_conflict_find.h +++ b/src/theory/quantifiers/quant_conflict_find.h @@ -1,13 +1,13 @@ /********************* */ /*! \file quant_conflict_find.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Clark Barrett, Tim King, Andrew Reynolds ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief quantifiers conflict find class **/ @@ -98,7 +98,7 @@ public: // is this term treated as UF application? static bool isHandledBoolConnective( TNode n ); static bool isHandledUfTerm( TNode n ); - static Node getOperator( QuantConflictFind * p, Node n ); + static Node getMatchOperator( QuantConflictFind * p, Node n ); //can this node be handled by the algorithm static bool isHandled( TNode n ); }; @@ -114,9 +114,12 @@ private: //for completing match int d_unassigned_nvar; int d_una_index; std::vector< int > d_una_eqc_count; + //optimization: track which arguments variables appear under UF terms in + std::map< int, std::map< TNode, std::vector< unsigned > > > d_var_rel_dom; + void getPropagateVars( std::vector< TNode >& vars, TNode n, bool pol, std::map< TNode, bool >& visited ); public: - QuantInfo() : d_mg( NULL ) {} - ~QuantInfo() { delete d_mg; } + QuantInfo(); + ~QuantInfo(); std::vector< TNode > d_vars; std::vector< TypeNode > d_var_types; std::map< TNode, int > d_var_num; @@ -128,13 +131,25 @@ public: int getNumVars() { return (int)d_vars.size(); } TNode getVar( int i ) { return d_vars[i]; } + typedef std::map< int, MatchGen * > VarMgMap; + private: MatchGen * d_mg; + VarMgMap d_var_mg; + public: + VarMgMap::const_iterator var_mg_find(int i) const { return d_var_mg.find(i); } + VarMgMap::const_iterator var_mg_end() const { return d_var_mg.end(); } + bool containsVarMg(int i) const { return var_mg_find(i) != var_mg_end(); } + + bool matchGeneratorIsValid() const { return d_mg->isValid(); } + bool getNextMatch( QuantConflictFind * p ) { + return d_mg->getNextMatch(p, this); + } + Node d_q; - std::map< int, MatchGen * > d_var_mg; void reset_round( QuantConflictFind * p ); public: //initialize - void initialize( Node q, Node qn ); + void initialize( QuantConflictFind * p, Node q, Node qn ); //current constraints std::vector< TNode > d_match; std::vector< TNode > d_match_term; @@ -146,7 +161,7 @@ public: bool getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq = false ); int addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity ); int addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove ); - bool setMatch( QuantConflictFind * p, int v, TNode n ); + bool setMatch( QuantConflictFind * p, int v, TNode n, bool isGroundRep ); bool isMatchSpurious( QuantConflictFind * p ); bool isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms ); bool entailmentTest( QuantConflictFind * p, Node lit, bool chEnt = true ); @@ -166,7 +181,6 @@ class QuantConflictFind : public QuantifiersModule typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap; private: context::CDO< bool > d_conflict; - std::vector< Node > d_quant_order; std::map< Kind, Node > d_zero; //for storing nodes created during t-constraint solving (prevents memory leaks) std::vector< Node > d_tempCache; @@ -180,21 +194,14 @@ public: //for ground terms Node d_false; TNode getZero( Kind k ); private: - Node evaluateTerm( Node n ); - int evaluate( Node n, bool pref = false, bool hasPref = false ); -private: - //currently asserted quantifiers - NodeList d_qassert; std::map< Node, QuantInfo > d_qinfo; private: //for equivalence classes // type -> list(eqc) std::map< TypeNode, std::vector< TNode > > d_eqcs; - std::map< TypeNode, Node > d_model_basis; public: enum { effort_conflict, effort_prop_eq, - effort_mc, }; short d_effort; void setEffort( int e ) { d_effort = e; } @@ -248,8 +255,8 @@ public: std::string identify() const { return "QcfEngine"; } }; -} -} -} +} /* namespace CVC4::theory::quantifiers */ +} /* namespace CVC4::theory */ +} /* namespace CVC4 */ #endif diff --git a/src/theory/quantifiers/quant_equality_engine.cpp b/src/theory/quantifiers/quant_equality_engine.cpp index 54a931196..3f89a799c 100644 --- a/src/theory/quantifiers/quant_equality_engine.cpp +++ b/src/theory/quantifiers/quant_equality_engine.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file quant_equality_engine.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** Congruence closure with free variables **/ @@ -32,6 +32,7 @@ d_conflict(c, false), d_quant_red(c), d_quant_unproc(c){ d_uequalityEngine.addFunctionKind( kind::APPLY_UF ); + d_intType = NodeManager::currentNM()->integerType(); } void QuantEqualityEngine::conflict(TNode t1, TNode t2) { @@ -86,56 +87,130 @@ void QuantEqualityEngine::registerQuantifier( Node q ) { void QuantEqualityEngine::assertNode( Node n ) { Assert( n.getKind()==FORALL ); Trace("qee-debug") << "QEE assert : " << n << std::endl; - Node lit = n[1].getKind()==NOT ? n[1][0] : n[1]; - bool pol = n[1].getKind()!=NOT; - if( lit.getKind()==APPLY_UF || lit.getKind()==EQUAL ){ - lit = getTermDatabase()->getCanonicalTerm( lit ); - Trace("qee-debug") << "Canonical : " << lit << ", pol = " << pol << std::endl; - Node t1 = lit.getKind()==APPLY_UF ? lit : lit[0]; + if( !d_conflict ){ + Node lit = n[1].getKind()==NOT ? n[1][0] : n[1]; + bool pol = n[1].getKind()!=NOT; + bool success = true; + Node t1; Node t2; - if( lit.getKind()==APPLY_UF ){ - t2 = pol ? getTermDatabase()->d_true : getTermDatabase()->d_false; - pol = true; + if( lit.getKind()==APPLY_UF || lit.getKind()==EQUAL || lit.getKind()==IFF ){ + lit = getTermDatabase()->getCanonicalTerm( lit ); + Trace("qee-debug") << "Canonical : " << lit << ", pol = " << pol << std::endl; + if( lit.getKind()==APPLY_UF ){ + t1 = getFunctionAppForPredicateApp( lit ); + t2 = pol ? getTermDatabase()->d_one : getTermDatabase()->d_zero; + pol = true; + lit = NodeManager::currentNM()->mkNode( EQUAL, t1, t2 ); + }else if( lit.getKind()==EQUAL ){ + t1 = lit[0]; + t2 = lit[1]; + }else if( lit.getKind()==IFF ){ + if( lit[0].getKind()==NOT ){ + t1 = lit[0][0]; + pol = !pol; + }else{ + t1 = lit[0]; + } + if( lit[1].getKind()==NOT ){ + t2 = lit[1][0]; + pol = !pol; + }else{ + t2 = lit[1]; + } + if( t1.getKind()==APPLY_UF && t2.getKind()==APPLY_UF ){ + t1 = getFunctionAppForPredicateApp( t1 ); + t2 = getFunctionAppForPredicateApp( t2 ); + lit = NodeManager::currentNM()->mkNode( EQUAL, t1, t2 ); + }else{ + success = false; + } + } }else{ - t2 = lit[1]; - } - bool alreadyHolds = false; - if( pol && areUnivEqual( t1, t2 ) ){ - alreadyHolds = true; - }else if( !pol && areUnivDisequal( t1, t2 ) ){ - alreadyHolds = true; + success = false; } + if( success ){ + bool alreadyHolds = false; + if( pol && areUnivEqualInternal( t1, t2 ) ){ + alreadyHolds = true; + }else if( !pol && areUnivDisequalInternal( t1, t2 ) ){ + alreadyHolds = true; + } - if( alreadyHolds ){ - d_quant_red.push_back( n ); - Trace("qee-debug") << "...add to redundant" << std::endl; - }else{ - Trace("qee-debug") << "...assert" << std::endl; - Trace("qee-assert") << "QEE : assert : " << lit << ", pol = " << pol << ", kind = " << lit.getKind() << std::endl; - if( lit.getKind()==APPLY_UF ){ - d_uequalityEngine.assertPredicate(lit, pol, n); + if( alreadyHolds ){ + d_quant_red.push_back( n ); + Trace("qee-debug") << "...add to redundant" << std::endl; }else{ - d_uequalityEngine.assertEquality(lit, pol, n); + Trace("qee-debug") << "...assert" << std::endl; + Trace("qee-assert") << "QEE : assert : " << lit << ", pol = " << pol << ", kind = " << lit.getKind() << std::endl; + if( lit.getKind()==APPLY_UF ){ + d_uequalityEngine.assertPredicate(lit, pol, n); + }else{ + d_uequalityEngine.assertEquality(lit, pol, n); + } } + }else{ + d_quant_unproc[n] = true; + Trace("qee-debug") << "...add to unprocessed (" << lit.getKind() << ")" << std::endl; } - }else{ - d_quant_unproc[n] = true; - Trace("qee-debug") << "...add to unprocessed (" << lit.getKind() << ")" << std::endl; } } -bool QuantEqualityEngine::areUnivDisequal( TNode n1, TNode n2 ) { +bool QuantEqualityEngine::areUnivDisequalInternal( TNode n1, TNode n2 ) { return n1!=n2 && d_uequalityEngine.hasTerm( n1 ) && d_uequalityEngine.hasTerm( n2 ) && d_uequalityEngine.areDisequal( n1, n2, false ); } -bool QuantEqualityEngine::areUnivEqual( TNode n1, TNode n2 ) { +bool QuantEqualityEngine::areUnivEqualInternal( TNode n1, TNode n2 ) { return n1==n2 || ( d_uequalityEngine.hasTerm( n1 ) && d_uequalityEngine.hasTerm( n2 ) && d_uequalityEngine.areEqual( n1, n2 ) ); } -TNode QuantEqualityEngine::getUnivRepresentative( TNode n ) { +TNode QuantEqualityEngine::getUnivRepresentativeInternal( TNode n ) { if( d_uequalityEngine.hasTerm( n ) ){ return d_uequalityEngine.getRepresentative( n ); }else{ return n; } -}
\ No newline at end of file +} +bool QuantEqualityEngine::areUnivDisequal( TNode n1, TNode n2 ) { + //TODO: must convert to internal representation + return areUnivDisequalInternal( n1, n2 ); +} + +bool QuantEqualityEngine::areUnivEqual( TNode n1, TNode n2 ) { + //TODO: must convert to internal representation + return areUnivEqualInternal( n1, n2 ); +} + +TNode QuantEqualityEngine::getUnivRepresentative( TNode n ) { + //TODO: must convert to internal representation + return getUnivRepresentativeInternal( n ); +} + +Node QuantEqualityEngine::getFunctionForPredicate( Node f ) { + std::map< Node, Node >::iterator it = d_pred_to_func.find( f ); + if( it==d_pred_to_func.end() ){ + std::vector< TypeNode > argTypes; + TypeNode tn = f.getType(); + for( unsigned i=0; i<(tn.getNumChildren()-1); i++ ){ + argTypes.push_back( tn[i] ); + } + TypeNode ftn = NodeManager::currentNM()->mkFunctionType( argTypes, d_intType ); + std::stringstream ss; + ss << "ee_" << f; + Node op = NodeManager::currentNM()->mkSkolem( ss.str(), ftn, "op created for internal ee" ); + d_pred_to_func[f] = op; + return op; + }else{ + return it->second; + } +} + +Node QuantEqualityEngine::getFunctionAppForPredicateApp( Node n ) { + Assert( n.getKind()==APPLY_UF ); + std::vector< Node > children; + children.push_back( getFunctionForPredicate( n.getOperator() ) ); + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + children.push_back( n[i] ); + } + return NodeManager::currentNM()->mkNode( APPLY_UF, children ); +} + diff --git a/src/theory/quantifiers/quant_equality_engine.h b/src/theory/quantifiers/quant_equality_engine.h index 35a328147..26654de4d 100644 --- a/src/theory/quantifiers/quant_equality_engine.h +++ b/src/theory/quantifiers/quant_equality_engine.h @@ -1,13 +1,13 @@ /********************* */ /*! \file quant_equality_engine.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Congruence closure with free variables **/ @@ -56,12 +56,21 @@ private: context::CDList<Node> d_quant_red; /** unprocessed quantifiers in current context */ NodeBoolMap d_quant_unproc; + // map predicates to functions over int + TypeNode d_intType; + std::map< Node, Node > d_pred_to_func; + Node getFunctionForPredicate( Node f ); + Node getFunctionAppForPredicateApp( Node n ); private: void conflict(TNode t1, TNode t2); void eqNotifyNewClass(TNode t); void eqNotifyPreMerge(TNode t1, TNode t2); void eqNotifyPostMerge(TNode t1, TNode t2); void eqNotifyDisequal(TNode t1, TNode t2, TNode reason); + //queries + bool areUnivDisequalInternal( TNode n1, TNode n2 ); + bool areUnivEqualInternal( TNode n1, TNode n2 ); + TNode getUnivRepresentativeInternal( TNode n ); public: QuantEqualityEngine( QuantifiersEngine * qe, context::Context* c ); virtual ~QuantEqualityEngine() throw (){} diff --git a/src/theory/quantifiers/quant_split.cpp b/src/theory/quantifiers/quant_split.cpp new file mode 100644 index 000000000..9fb943e5e --- /dev/null +++ b/src/theory/quantifiers/quant_split.cpp @@ -0,0 +1,134 @@ +/********************* */ +/*! \file quant_split.cpp + ** \verbatim + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim + ** + ** \brief Implementation of dynamic quantifiers splitting + **/ + +#include "theory/quantifiers/quant_split.h" +#include "theory/quantifiers/term_database.h" +#include "theory/quantifiers_engine.h" +#include "theory/quantifiers/first_order_model.h" +#include "options/quantifiers_options.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::quantifiers; + + +QuantDSplit::QuantDSplit( QuantifiersEngine * qe, context::Context* c ) : +QuantifiersModule( qe ), d_added_split( qe->getUserContext() ){ + +} + +/** pre register quantifier */ +void QuantDSplit::preRegisterQuantifier( Node q ) { + int max_index = -1; + int max_score = -1; + if( q.getNumChildren()==3 ){ + return; + } + Trace("quant-dsplit-debug") << "Check split quantified formula : " << q << std::endl; + for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ + TypeNode tn = q[0][i].getType(); + if( tn.isDatatype() ){ + const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype(); + if( dt.isRecursiveSingleton() ){ + Trace("quant-dsplit-debug") << "Datatype " << dt.getName() << " is recursive singleton." << std::endl; + }else{ + int score = -1; + if( options::quantDynamicSplit()==quantifiers::QUANT_DSPLIT_MODE_AGG ){ + score = dt.isUFinite() ? 1 : -1; + }else if( options::quantDynamicSplit()==quantifiers::QUANT_DSPLIT_MODE_DEFAULT ){ + score = dt.isUFinite() ? 1 : -1; + } + Trace("quant-dsplit-debug") << "Datatype " << dt.getName() << " is score " << score << " (" << dt.isUFinite() << " " << dt.isFinite() << ")" << std::endl; + if( score>max_score ){ + max_index = i; + max_score = score; + } + } + } + } + + if( max_index!=-1 ){ + Trace("quant-dsplit-debug") << "Will split at index " << max_index << "." << std::endl; + d_quant_to_reduce[q] = max_index; + d_quantEngine->setOwner( q, this ); + } +} + +/* whether this module needs to check this round */ +bool QuantDSplit::needsCheck( Theory::Effort e ) { + return e>=Theory::EFFORT_FULL && !d_quant_to_reduce.empty(); +} + +/* Call during quantifier engine's check */ +void QuantDSplit::check( Theory::Effort e, unsigned quant_e ) { + //add lemmas ASAP (they are a reduction) + if( quant_e==QuantifiersEngine::QEFFORT_CONFLICT ){ + std::vector< Node > lemmas; + for(std::map< Node, int >::iterator it = d_quant_to_reduce.begin(); it != d_quant_to_reduce.end(); ++it) { + Node q = it->first; + if( d_added_split.find( q )==d_added_split.end() ){ + d_added_split.insert( q ); + std::vector< Node > bvs; + for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ + if( (int)i!=it->second ){ + bvs.push_back( q[0][i] ); + } + } + std::vector< Node > disj; + disj.push_back( q.negate() ); + TNode svar = q[0][it->second]; + TypeNode tn = svar.getType(); + if( tn.isDatatype() ){ + std::vector< Node > cons; + const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype(); + for( unsigned j=0; j<dt.getNumConstructors(); j++ ){ + std::vector< Node > vars; + for( unsigned k=0; k<dt[j].getNumArgs(); k++ ){ + TypeNode tns = TypeNode::fromType( dt[j][k].getRangeType() ); + Node v = NodeManager::currentNM()->mkBoundVar( tns ); + vars.push_back( v ); + } + std::vector< Node > bvs_cmb; + bvs_cmb.insert( bvs_cmb.end(), bvs.begin(), bvs.end() ); + bvs_cmb.insert( bvs_cmb.end(), vars.begin(), vars.end() ); + vars.insert( vars.begin(), Node::fromExpr( dt[j].getConstructor() ) ); + Node c = NodeManager::currentNM()->mkNode( kind::APPLY_CONSTRUCTOR, vars ); + TNode ct = c; + Node body = q[1].substitute( svar, ct ); + if( !bvs_cmb.empty() ){ + body = NodeManager::currentNM()->mkNode( kind::FORALL, NodeManager::currentNM()->mkNode( kind::BOUND_VAR_LIST, bvs_cmb ), body ); + } + cons.push_back( body ); + } + Node conc = cons.size()==1 ? cons[0] : NodeManager::currentNM()->mkNode( kind::AND, cons ); + disj.push_back( conc ); + }else{ + Assert( false ); + } + lemmas.push_back( disj.size()==1 ? disj[0] : NodeManager::currentNM()->mkNode( kind::OR, disj ) ); + } + } + + //add lemmas to quantifiers engine + for( unsigned i=0; i<lemmas.size(); i++ ){ + Trace("quant-dsplit") << "QuantDSplit lemma : " << lemmas[i] << std::endl; + d_quantEngine->addLemma( lemmas[i], false ); + } + d_quant_to_reduce.clear(); + } +} + diff --git a/src/theory/quantifiers/quant_split.h b/src/theory/quantifiers/quant_split.h new file mode 100644 index 000000000..d36824998 --- /dev/null +++ b/src/theory/quantifiers/quant_split.h @@ -0,0 +1,54 @@ +/********************* */ +/*! \file quant_split.h + ** \verbatim + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim + ** + ** \brief dynamic quantifiers splitting + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY__QUANT_SPLIT_H +#define __CVC4__THEORY__QUANT_SPLIT_H + +#include "theory/quantifiers_engine.h" +#include "context/cdo.h" + +namespace CVC4 { +namespace theory { +namespace quantifiers { + +class QuantDSplit : public QuantifiersModule { + typedef context::CDHashSet<Node, NodeHashFunction> NodeSet; +private: + /** list of relevant quantifiers asserted in the current context */ + std::map< Node, int > d_quant_to_reduce; + /** whether we have instantiated quantified formulas */ + NodeSet d_added_split; +public: + QuantDSplit( QuantifiersEngine * qe, context::Context* c ); + /** determine whether this quantified formula will be reduced */ + void preRegisterQuantifier( Node q ); + + /* whether this module needs to check this round */ + bool needsCheck( Theory::Effort e ); + /* Call during quantifier engine's check */ + void check( Theory::Effort e, unsigned quant_e ); + /* Called for new quantifiers */ + void registerQuantifier( Node q ) {} + void assertNode( Node n ) {} + /** Identify this module (for debugging, dynamic configuration, etc..) */ + std::string identify() const { return "QuantDSplit"; } +}; + +} +} +} + +#endif diff --git a/src/theory/quantifiers/quant_util.cpp b/src/theory/quantifiers/quant_util.cpp index bf91f74c6..3b7787a20 100644 --- a/src/theory/quantifiers/quant_util.cpp +++ b/src/theory/quantifiers/quant_util.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file quant_util.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Implementation of quantifier utilities **/ @@ -23,6 +23,38 @@ using namespace CVC4::kind; using namespace CVC4::context; using namespace CVC4::theory; + +unsigned QuantifiersModule::needsModel( Theory::Effort e ) { + return QuantifiersEngine::QEFFORT_NONE; +} + +eq::EqualityEngine * QuantifiersModule::getEqualityEngine() { + return d_quantEngine->getMasterEqualityEngine(); +} + +bool QuantifiersModule::areEqual( TNode n1, TNode n2 ) { + eq::EqualityEngine * ee = getEqualityEngine(); + return n1==n2 || ( ee->hasTerm( n1 ) && ee->hasTerm( n2 ) && ee->areEqual( n1, n2 ) ); +} + +bool QuantifiersModule::areDisequal( TNode n1, TNode n2 ) { + eq::EqualityEngine * ee = getEqualityEngine(); + return n1!=n2 && ee->hasTerm( n1 ) && ee->hasTerm( n2 ) && ee->areDisequal( n1, n2, false ); +} + +TNode QuantifiersModule::getRepresentative( TNode n ) { + eq::EqualityEngine * ee = getEqualityEngine(); + if( ee->hasTerm( n ) ){ + return ee->getRepresentative( n ); + }else{ + return n; + } +} + +quantifiers::TermDb * QuantifiersModule::getTermDatabase() { + return d_quantEngine->getTermDatabase(); +} + bool QuantArith::getMonomial( Node n, Node& c, Node& v ){ if( n.getKind()==MULT && n.getNumChildren()==2 && n[0].isConst() ){ c = n[0]; @@ -33,8 +65,13 @@ bool QuantArith::getMonomial( Node n, Node& c, Node& v ){ } } bool QuantArith::getMonomial( Node n, std::map< Node, Node >& msum ) { - if ( n.getKind()==MULT ){ - if( n.getNumChildren()==2 && msum.find(n[1])==msum.end() && n[0].isConst() ){ + if( n.isConst() ){ + if( msum.find(Node::null())==msum.end() ){ + msum[Node::null()] = n; + return true; + } + }else if( n.getKind()==MULT && n.getNumChildren()==2 && n[0].isConst() ){ + if( msum.find(n[1])==msum.end() ){ msum[n[1]] = n[0]; return true; } @@ -63,10 +100,7 @@ bool QuantArith::getMonomialSum( Node n, std::map< Node, Node >& msum ) { bool QuantArith::getMonomialSumLit( Node lit, std::map< Node, Node >& msum ) { if( lit.getKind()==GEQ || lit.getKind()==EQUAL ){ if( getMonomialSum( lit[0], msum ) ){ - if( lit[1].isConst() ){ - if( !lit[1].getConst<Rational>().isZero() ){ - msum[Node::null()] = negate( lit[1] ); - } + if( lit[1].isConst() && lit[1].getConst<Rational>().isZero() ){ return true; }else{ //subtract the other side @@ -90,7 +124,29 @@ bool QuantArith::getMonomialSumLit( Node lit, std::map< Node, Node >& msum ) { return false; } -int QuantArith::isolate( Node v, std::map< Node, Node >& msum, Node & veq, Kind k, bool doCoeff ) { +Node QuantArith::mkNode( std::map< Node, Node >& msum ) { + std::vector< Node > children; + for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){ + Node m; + if( !it->first.isNull() ){ + if( !it->second.isNull() ){ + m = NodeManager::currentNM()->mkNode( MULT, it->second, it->first ); + }else{ + m = it->first; + } + }else{ + Assert( !it->second.isNull() ); + m = it->second; + } + children.push_back(m); + } + return children.size()>1 ? NodeManager::currentNM()->mkNode( PLUS, children ) : (children.size()==1 ? children[0] : NodeManager::currentNM()->mkConst( Rational(0) )); +} + +// given (msum <k> 0), solve (veq_c * v <k> val) or (val <k> veq_c * v), where: +// veq_c is either null (meaning 1), or positive. +// return value 1: veq_c*v is RHS, -1: veq_c*v is LHS, 0: failed. +int QuantArith::isolate( Node v, std::map< Node, Node >& msum, Node & veq_c, Node & val, Kind k ) { std::map< Node, Node >::iterator itv = msum.find( v ); if( itv!=msum.end() ){ std::vector< Node > children; @@ -111,46 +167,42 @@ int QuantArith::isolate( Node v, std::map< Node, Node >& msum, Node & veq, Kind children.push_back(m); } } - veq = children.size()>1 ? NodeManager::currentNM()->mkNode( PLUS, children ) : + val = children.size()>1 ? NodeManager::currentNM()->mkNode( PLUS, children ) : (children.size()==1 ? children[0] : NodeManager::currentNM()->mkConst( Rational(0) )); - Node vc = v; if( !r.isOne() && !r.isNegativeOne() ){ - if( vc.getType().isInteger() ){ - if( doCoeff ){ - vc = NodeManager::currentNM()->mkNode( MULT, NodeManager::currentNM()->mkConst( r.abs() ), vc ); - }else{ - return 0; - } + if( v.getType().isInteger() ){ + veq_c = NodeManager::currentNM()->mkConst( r.abs() ); }else{ - veq = NodeManager::currentNM()->mkNode( MULT, veq, NodeManager::currentNM()->mkConst( Rational(1) / r.abs() ) ); + val = NodeManager::currentNM()->mkNode( MULT, val, NodeManager::currentNM()->mkConst( Rational(1) / r.abs() ) ); } } if( r.sgn()==1 ){ - veq = negate(veq); + val = negate(val); + }else{ + val = Rewriter::rewrite( val ); } - veq = Rewriter::rewrite( veq ); - bool inOrder = r.sgn()==1 || k==EQUAL; - veq = NodeManager::currentNM()->mkNode( k, inOrder ? vc : veq, inOrder ? veq : vc ); - return inOrder ? 1 : -1; + return ( r.sgn()==1 || k==EQUAL ) ? 1 : -1; } } return 0; } -int QuantArith::isolate( Node v, std::map< Node, Node >& msum, Node & veq_c, Node & val, Kind k ) { - Node vatom; - //isolate pv in the inequality - int ires = isolate( v, msum, vatom, k, true ); +int QuantArith::isolate( Node v, std::map< Node, Node >& msum, Node & veq, Kind k, bool doCoeff ) { + Node veq_c; + Node val; + //isolate v in the (in)equality + int ires = isolate( v, msum, veq_c, val, k ); if( ires!=0 ){ - val = vatom[ ires==1 ? 1 : 0 ]; - Node pvm = vatom[ ires==1 ? 0 : 1 ]; - //get monomial - if( pvm!=v ){ - Node veq_v; - if( QuantArith::getMonomial( pvm, veq_c, veq_v ) ){ - Assert( veq_v==v ); + Node vc = v; + if( !veq_c.isNull() ){ + if( doCoeff ){ + vc = NodeManager::currentNM()->mkNode( MULT, veq_c, vc ); + }else{ + return 0; } } + bool inOrder = ires==1; + veq = NodeManager::currentNM()->mkNode( k, inOrder ? vc : val, inOrder ? val : vc ); } return ires; } @@ -164,7 +216,7 @@ Node QuantArith::solveEqualityFor( Node lit, Node v ) { return lit[1-r]; } } - if( tn.isInteger() || tn.isReal() ){ + if( tn.isReal() ){ if( quantifiers::TermDb::containsTerm( lit, v ) ){ std::map< Node, Node > msum; if( QuantArith::getMonomialSumLit( lit, msum ) ){ @@ -357,3 +409,20 @@ void QuantPhaseReq::getPolarity( Node n, int child, bool hasPol, bool pol, bool& newPol = pol; } } + +void QuantPhaseReq::getEntailPolarity( Node n, int child, bool hasPol, bool pol, bool& newHasPol, bool& newPol ) { + if( n.getKind()==AND || n.getKind()==OR ){ + newHasPol = hasPol && pol==( n.getKind()==AND ); + newPol = pol; + }else if( n.getKind()==IMPLIES ){ + newHasPol = hasPol && !pol; + newPol = child==0 ? !pol : pol; + }else if( n.getKind()==NOT ){ + newHasPol = hasPol; + newPol = !pol; + }else{ + newHasPol = false; + newPol = pol; + } +} + diff --git a/src/theory/quantifiers/quant_util.h b/src/theory/quantifiers/quant_util.h index 566a09923..79cdae437 100644 --- a/src/theory/quantifiers/quant_util.h +++ b/src/theory/quantifiers/quant_util.h @@ -1,13 +1,13 @@ /********************* */ /*! \file quant_util.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Morgan Deters, Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief quantifier util **/ @@ -29,6 +29,58 @@ namespace theory { class QuantifiersEngine; +namespace quantifiers { + class TermDb; +} + +class QuantifiersModule { +protected: + QuantifiersEngine* d_quantEngine; +public: + QuantifiersModule( QuantifiersEngine* qe ) : d_quantEngine( qe ){} + virtual ~QuantifiersModule(){} + //get quantifiers engine + QuantifiersEngine* getQuantifiersEngine() { return d_quantEngine; } + /** presolve */ + virtual void presolve() {} + /* whether this module needs to check this round */ + virtual bool needsCheck( Theory::Effort e ) { return e>=Theory::EFFORT_LAST_CALL; } + /* whether this module needs a model built */ + virtual unsigned needsModel( Theory::Effort e ); + /* reset at a round */ + virtual void reset_round( Theory::Effort e ){} + /* Call during quantifier engine's check */ + virtual void check( Theory::Effort e, unsigned quant_e ) = 0; + /* check was complete (e.g. no lemmas implies a model) */ + virtual bool checkComplete() { return true; } + /* Called for new quantified formulas */ + virtual void preRegisterQuantifier( Node q ) { } + /* Called for new quantifiers after owners are finalized */ + virtual void registerQuantifier( Node q ) = 0; + virtual void assertNode( Node n ) {} + virtual void propagate( Theory::Effort level ){} + virtual Node getNextDecisionRequest() { return TNode::null(); } + /** Identify this module (for debugging, dynamic configuration, etc..) */ + virtual std::string identify() const = 0; +public: + eq::EqualityEngine * getEqualityEngine(); + bool areDisequal( TNode n1, TNode n2 ); + bool areEqual( TNode n1, TNode n2 ); + TNode getRepresentative( TNode n ); + quantifiers::TermDb * getTermDatabase(); +};/* class QuantifiersModule */ + +class QuantifiersUtil { +public: + QuantifiersUtil(){} + virtual ~QuantifiersUtil(){} + /* reset at a round */ + virtual bool reset( Theory::Effort e ) = 0; + /** Identify this module (for debugging, dynamic configuration, etc..) */ + virtual std::string identify() const = 0; +}; + + class QuantArith { public: @@ -36,9 +88,10 @@ public: static bool getMonomial( Node n, std::map< Node, Node >& msum ); static bool getMonomialSum( Node n, std::map< Node, Node >& msum ); static bool getMonomialSumLit( Node lit, std::map< Node, Node >& msum ); + static Node mkNode( std::map< Node, Node >& msum ); //return 1 : solved on LHS, return -1 : solved on RHS, return 0: failed - static int isolate( Node v, std::map< Node, Node >& msum, Node & veq, Kind k, bool doCoeff = false ); static int isolate( Node v, std::map< Node, Node >& msum, Node & veq_c, Node & val, Kind k ); + static int isolate( Node v, std::map< Node, Node >& msum, Node & veq, Kind k, bool doCoeff = false ); static Node solveEqualityFor( Node lit, Node v ); static Node negate( Node t ); static Node offset( Node t, int i ); @@ -92,15 +145,16 @@ public: std::map< Node, Node > d_phase_reqs_equality_term; static void getPolarity( Node n, int child, bool hasPol, bool pol, bool& newHasPol, bool& newPol ); + static void getEntailPolarity( Node n, int child, bool hasPol, bool pol, bool& newHasPol, bool& newPol ); }; -class EqualityQuery { +class EqualityQuery : public QuantifiersUtil{ public: EqualityQuery(){} virtual ~EqualityQuery(){}; - /** reset */ - virtual void reset() = 0; + /** extends engine */ + virtual bool extendsEngine() { return false; } /** contains term */ virtual bool hasTerm( Node a ) = 0; /** get the representative of the equivalence class of a */ @@ -113,6 +167,8 @@ public: virtual eq::EqualityEngine* getEngine() = 0; /** get the equivalence class of a */ virtual void getEquivalenceClass( Node a, std::vector< Node >& eqc ) = 0; + /** get the term that exists in EE that is congruent to f with args (f is returned by TermDb::getMatchOperator(...) */ + virtual TNode getCongruentTerm( Node f, std::vector< TNode >& args ) = 0; };/* class EqualityQuery */ diff --git a/src/theory/quantifiers/quantifiers_attributes.cpp b/src/theory/quantifiers/quantifiers_attributes.cpp index 8c6b30124..b797f4ce9 100644 --- a/src/theory/quantifiers/quantifiers_attributes.cpp +++ b/src/theory/quantifiers/quantifiers_attributes.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file quantifiers_attributes.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Implementation of QuantifiersAttributes class **/ @@ -24,7 +24,7 @@ using namespace CVC4::context; using namespace CVC4::theory; using namespace CVC4::theory::quantifiers; -void QuantifiersAttributes::setUserAttribute( const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value ){ +void QuantifiersAttributes::setUserAttribute( const std::string& attr, Node n, std::vector< Node >& node_values, std::string str_value ){ Trace("quant-attr-debug") << "Set " << attr << " " << n << std::endl; if( attr=="axiom" ){ Trace("quant-attr-debug") << "Set axiom " << n << std::endl; @@ -58,5 +58,13 @@ void QuantifiersAttributes::setUserAttribute( const std::string& attr, Node n, s Trace("quant-attr-debug") << "Set rewrite rule priority " << n << " to " << lvl << std::endl; RrPriorityAttribute rrpa; n.setAttribute( rrpa, lvl ); + }else if( attr=="quant-elim" ){ + Trace("quant-attr-debug") << "Set quantifier elimination " << n << std::endl; + QuantElimAttribute qea; + n.setAttribute( qea, true ); + }else if( attr=="quant-elim-partial" ){ + Trace("quant-attr-debug") << "Set partial quantifier elimination " << n << std::endl; + QuantElimPartialAttribute qepa; + n.setAttribute( qepa, true ); } } diff --git a/src/theory/quantifiers/quantifiers_attributes.h b/src/theory/quantifiers/quantifiers_attributes.h index bad58eef8..53cef796a 100644 --- a/src/theory/quantifiers/quantifiers_attributes.h +++ b/src/theory/quantifiers/quantifiers_attributes.h @@ -1,13 +1,13 @@ /********************* */ /*! \file quantifiers_attributes.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Morgan Deters, Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Attributes for the theory quantifiers ** @@ -36,7 +36,7 @@ struct QuantifiersAttributes * This function will apply a custom set of attributes to all top-level universal * quantifiers contained in n */ - static void setUserAttribute( const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value ); + static void setUserAttribute( const std::string& attr, Node n, std::vector< Node >& node_values, std::string str_value ); }; diff --git a/src/theory/quantifiers/quantifiers_rewriter.cpp b/src/theory/quantifiers/quantifiers_rewriter.cpp index afe8cd598..5aae4d640 100644 --- a/src/theory/quantifiers/quantifiers_rewriter.cpp +++ b/src/theory/quantifiers/quantifiers_rewriter.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file quantifiers_rewriter.cpp ** \verbatim - ** Original author: Morgan Deters - ** Major contributors: Andrew Reynolds - ** Minor contributors (to current version): Tim King + ** Top contributors (to current version): + ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Implementation of QuantifiersRewriter class **/ @@ -229,52 +229,48 @@ RewriteResponse QuantifiersRewriter::preRewrite(TNode in) { RewriteResponse QuantifiersRewriter::postRewrite(TNode in) { Trace("quantifiers-rewrite-debug") << "post-rewriting " << in << std::endl; - if( !options::quantRewriteRules() || !TermDb::isRewriteRule( in ) ){ - RewriteStatus status = REWRITE_DONE; - Node ret = in; - //get the arguments - std::vector< Node > args; - for( int i=0; i<(int)in[0].getNumChildren(); i++ ){ - args.push_back( in[0][i] ); - } - //get the instantiation pattern list - Node ipl; + RewriteStatus status = REWRITE_DONE; + Node ret = in; + int rew_op = -1; + //get the body + if( in.getKind()==EXISTS ){ + std::vector< Node > children; + children.push_back( in[0] ); + children.push_back( in[1].negate() ); if( in.getNumChildren()==3 ){ - ipl = in[2]; - } - //get the body - if( in.getKind()==EXISTS ){ - std::vector< Node > children; - children.push_back( in[0] ); - children.push_back( in[1].negate() ); - if( in.getNumChildren()==3 ){ - children.push_back( in[2] ); - } - ret = NodeManager::currentNM()->mkNode( FORALL, children ); - ret = ret.negate(); - status = REWRITE_AGAIN_FULL; + children.push_back( in[2] ); + } + ret = NodeManager::currentNM()->mkNode( FORALL, children ); + ret = ret.negate(); + status = REWRITE_AGAIN_FULL; + }else if( in.getKind()==FORALL ){ + if( in[1].isConst() ){ + return RewriteResponse( status, in[1] ); }else{ - for( int op=0; op<COMPUTE_LAST; op++ ){ - //TODO : compute isNested (necessary?) - bool isNested = false; - if( doOperation( in, isNested, op ) ){ - ret = computeOperation( in, isNested, op ); - if( ret!=in ){ - status = REWRITE_AGAIN_FULL; - break; + //compute attributes + QAttributes qa; + TermDb::computeQuantAttributes( in, qa ); + if( !qa.isRewriteRule() ){ + for( int op=0; op<COMPUTE_LAST; op++ ){ + if( doOperation( in, op, qa ) ){ + ret = computeOperation( in, op, qa ); + if( ret!=in ){ + rew_op = op; + status = REWRITE_AGAIN_FULL; + break; + } } } } } - //print if changed - if( in!=ret ){ - Trace("quantifiers-rewrite") << "*** rewrite " << in << std::endl; - Trace("quantifiers-rewrite") << " to " << std::endl; - Trace("quantifiers-rewrite") << ret << std::endl; - } - return RewriteResponse( status, ret ); } - return RewriteResponse(REWRITE_DONE, in); + //print if changed + if( in!=ret ){ + Trace("quantifiers-rewrite") << "*** rewrite (op=" << rew_op << ") " << in << std::endl; + Trace("quantifiers-rewrite") << " to " << std::endl; + Trace("quantifiers-rewrite") << ret << std::endl; + } + return RewriteResponse( status, ret ); } Node QuantifiersRewriter::computeElimSymbols( Node body ) { @@ -315,6 +311,10 @@ Node QuantifiersRewriter::computeElimSymbols( Node body ) { } childrenChanged = childrenChanged || c!=body[i]; } + //if( body.getKind()==ITE && isLiteral( body[0] ) ){ + // ret = NodeManager::currentNM()->mkNode( AND, NodeManager::currentNM()->mkNode( OR, body[0].negate(), body[1] ), + // NodeManager::currentNM()->mkNode( OR, body[0], body[2] ) ); + //} if( childrenChanged ){ return ( children.size()==1 && k!=NOT ) ? children[0] : NodeManager::currentNM()->mkNode( k, children ); }else{ @@ -330,7 +330,7 @@ Node QuantifiersRewriter::computeNNF( Node body ){ }else if( isLiteral( body[0] ) ){ return body; }else{ - std::vector< Node > children; + std::vector< Node > children; Kind k = body[0].getKind(); if( body[0].getKind()==OR || body[0].getKind()==AND ){ @@ -564,12 +564,23 @@ void setEntailedCond( Node n, bool pol, std::map< Node, bool >& currCond, std::v } } -Node QuantifiersRewriter::computeProcessTerms( Node body, std::vector< Node >& new_vars, std::vector< Node >& new_conds, Node q ){ +void removeEntailedCond( std::map< Node, bool >& currCond, std::vector< Node >& new_cond, std::map< Node, Node >& cache ) { + if( !new_cond.empty() ){ + for( unsigned j=0; j<new_cond.size(); j++ ){ + currCond.erase( new_cond[j] ); + } + new_cond.clear(); + cache.clear(); + } +} + +Node QuantifiersRewriter::computeProcessTerms( Node body, std::vector< Node >& new_vars, std::vector< Node >& new_conds, Node q, QAttributes& qa ){ std::map< Node, bool > curr_cond; std::map< Node, Node > cache; std::map< Node, Node > icache; - Node h = TermDb::getFunDefHead( q ); - if( !h.isNull() ){ + if( qa.isFunDef() ){ + Node h = TermDb::getFunDefHead( q ); + Assert( !h.isNull() ); // if it is a function definition, rewrite the body independently Node fbody = TermDb::getFunDefBody( q ); Assert( !body.isNull() ); @@ -591,96 +602,119 @@ Node QuantifiersRewriter::computeProcessTerms2( Node body, bool hasPol, bool pol ret = iti->second; Trace("quantifiers-rewrite-term-debug2") << "Return (cached) " << ret << " for " << body << std::endl; }else{ - bool firstTimeCD = true; + //only do context dependent processing up to depth 8 + bool doCD = nCurrCond<8; bool changed = false; std::vector< Node > children; - for( size_t i=0; i<body.getNumChildren(); i++ ){ - std::vector< Node > new_cond; + //set entailed conditions based on OR/AND + std::map< int, std::vector< Node > > new_cond_children; + if( doCD && ( body.getKind()==OR || body.getKind()==AND ) ){ + nCurrCond = nCurrCond + 1; bool conflict = false; - //only do context dependent processing up to depth 8 - if( nCurrCond<8 ){ - if( firstTimeCD ){ - firstTimeCD = false; - nCurrCond = nCurrCond + 1; - } - if( Trace.isOn("quantifiers-rewrite-term-debug") ){ - //if( ( body.getKind()==ITE && i>0 ) || ( hasPol && ( ( body.getKind()==OR && pol ) || (body.getKind()==AND && !pol ) ) ) ){ - if( ( body.getKind()==ITE && i>0 ) || body.getKind()==OR || body.getKind()==AND ){ - Trace("quantifiers-rewrite-term-debug") << "---rewrite " << body[i] << " under conditions:----" << std::endl; + bool use_pol = body.getKind()==AND; + for( unsigned j=0; j<body.getNumChildren(); j++ ){ + setEntailedCond( body[j], use_pol, currCond, new_cond_children[j], conflict ); + } + if( conflict ){ + Trace("quantifiers-rewrite-term-debug") << "-------conflict, return " << !use_pol << std::endl; + ret = NodeManager::currentNM()->mkConst( !use_pol ); + } + } + if( ret.isNull() ){ + for( size_t i=0; i<body.getNumChildren(); i++ ){ + + //set/update entailed conditions + std::vector< Node > new_cond; + bool conflict = false; + if( doCD ){ + if( Trace.isOn("quantifiers-rewrite-term-debug") ){ + if( ( body.getKind()==ITE && i>0 ) || body.getKind()==OR || body.getKind()==AND ){ + Trace("quantifiers-rewrite-term-debug") << "---rewrite " << body[i] << " under conditions:----" << std::endl; + } } - } - if( body.getKind()==ITE && i>0 ){ - setEntailedCond( children[0], i==1, currCond, new_cond, conflict ); - //should not conflict (entailment check failed) - Assert( !conflict ); - } - //if( hasPol && ( ( body.getKind()==OR && pol ) || ( body.getKind()==AND && !pol ) ) ){ - // bool use_pol = !pol; - if( body.getKind()==OR || body.getKind()==AND ){ - bool use_pol = body.getKind()==AND; - for( unsigned j=0; j<body.getNumChildren(); j++ ){ - if( j<i ){ - setEntailedCond( children[j], use_pol, currCond, new_cond, conflict ); - }else if( j>i ){ - setEntailedCond( body[j], use_pol, currCond, new_cond, conflict ); + if( body.getKind()==ITE && i>0 ){ + if( i==1 ){ + nCurrCond = nCurrCond + 1; } + setEntailedCond( children[0], i==1, currCond, new_cond, conflict ); + //should not conflict (entailment check failed) + Assert( !conflict ); } - if( conflict ){ - Trace("quantifiers-rewrite-term-debug") << "-------conflict, return " << !use_pol << std::endl; - ret = NodeManager::currentNM()->mkConst( !use_pol ); + if( body.getKind()==OR || body.getKind()==AND ){ + bool use_pol = body.getKind()==AND; + //remove the current condition + removeEntailedCond( currCond, new_cond_children[i], cache ); + if( i>0 ){ + //add the previous condition + setEntailedCond( children[i-1], use_pol, currCond, new_cond_children[i-1], conflict ); + } + if( conflict ){ + Trace("quantifiers-rewrite-term-debug") << "-------conflict, return " << !use_pol << std::endl; + ret = NodeManager::currentNM()->mkConst( !use_pol ); + } } - } - if( !new_cond.empty() ){ - cache.clear(); - } - if( Trace.isOn("quantifiers-rewrite-term-debug") ){ - //if( ( body.getKind()==ITE && i>0 ) || ( hasPol && ( ( body.getKind()==OR && pol ) || (body.getKind()==AND && !pol ) ) ) ){ - if( ( body.getKind()==ITE && i>0 ) || body.getKind()==OR || body.getKind()==AND ){ - Trace("quantifiers-rewrite-term-debug") << "-------" << std::endl; + if( !new_cond.empty() ){ + cache.clear(); + } + if( Trace.isOn("quantifiers-rewrite-term-debug") ){ + if( ( body.getKind()==ITE && i>0 ) || body.getKind()==OR || body.getKind()==AND ){ + Trace("quantifiers-rewrite-term-debug") << "-------" << std::endl; + } } } - } - if( !conflict ){ - bool newHasPol; - bool newPol; - QuantPhaseReq::getPolarity( body, i, hasPol, pol, newHasPol, newPol ); - Node nn = computeProcessTerms2( body[i], newHasPol, newPol, currCond, nCurrCond, cache, icache, new_vars, new_conds ); - if( body.getKind()==ITE && i==0 ){ - int res = getEntailedCond( nn, currCond ); - Trace("quantifiers-rewrite-term-debug") << "Condition for " << body << " is " << nn << ", entailment check=" << res << std::endl; - if( res==1 ){ - ret = computeProcessTerms2( body[1], hasPol, pol, currCond, nCurrCond, cache, icache, new_vars, new_conds ); - }else if( res==-1 ){ - ret = computeProcessTerms2( body[2], hasPol, pol, currCond, nCurrCond, cache, icache, new_vars, new_conds ); + + //do the recursive call on children + if( !conflict ){ + bool newHasPol; + bool newPol; + QuantPhaseReq::getPolarity( body, i, hasPol, pol, newHasPol, newPol ); + Node nn = computeProcessTerms2( body[i], newHasPol, newPol, currCond, nCurrCond, cache, icache, new_vars, new_conds ); + if( body.getKind()==ITE && i==0 ){ + int res = getEntailedCond( nn, currCond ); + Trace("quantifiers-rewrite-term-debug") << "Condition for " << body << " is " << nn << ", entailment check=" << res << std::endl; + if( res==1 ){ + ret = computeProcessTerms2( body[1], hasPol, pol, currCond, nCurrCond, cache, icache, new_vars, new_conds ); + }else if( res==-1 ){ + ret = computeProcessTerms2( body[2], hasPol, pol, currCond, nCurrCond, cache, icache, new_vars, new_conds ); + } } + children.push_back( nn ); + changed = changed || nn!=body[i]; + } + + //clean up entailed conditions + removeEntailedCond( currCond, new_cond, cache ); + + if( !ret.isNull() ){ + break; } - children.push_back( nn ); - changed = changed || nn!=body[i]; } - if( !new_cond.empty() ){ - for( unsigned j=0; j<new_cond.size(); j++ ){ - currCond.erase( new_cond[j] ); + + //make return value + if( ret.isNull() ){ + if( changed ){ + if( body.getMetaKind() == kind::metakind::PARAMETERIZED ){ + children.insert( children.begin(), body.getOperator() ); + } + ret = NodeManager::currentNM()->mkNode( body.getKind(), children ); + }else{ + ret = body; } - cache.clear(); - } - if( !ret.isNull() ){ - break; } } - if( ret.isNull() ){ - if( changed ){ - if( body.getMetaKind() == kind::metakind::PARAMETERIZED ){ - children.insert( children.begin(), body.getOperator() ); - } - ret = NodeManager::currentNM()->mkNode( body.getKind(), children ); - }else{ - ret = body; + + //clean up entailed conditions + if( body.getKind()==OR || body.getKind()==AND ){ + for( unsigned j=0; j<body.getNumChildren(); j++ ){ + removeEntailedCond( currCond, new_cond_children[j], cache ); } } + Trace("quantifiers-rewrite-term-debug2") << "Returning " << ret << " for " << body << std::endl; cache[body] = ret; } + //do context-independent rewriting iti = icache.find( ret ); if( iti!=icache.end() ){ return iti->second; @@ -710,46 +744,60 @@ Node QuantifiersRewriter::computeProcessTerms2( Node body, bool hasPol, bool pol } } } - }else if( ret.getKind()==INTS_DIVISION_TOTAL || ret.getKind()==INTS_MODULUS_TOTAL ){ - Node num = ret[0]; - Node den = ret[1]; - if(den.isConst()) { - const Rational& rat = den.getConst<Rational>(); - Assert(!num.isConst()); - if(rat != 0) { - Node intVar = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType()); - new_vars.push_back( intVar ); - Node cond; - if(rat > 0) { - cond = NodeManager::currentNM()->mkNode(kind::AND, - NodeManager::currentNM()->mkNode(kind::LEQ, NodeManager::currentNM()->mkNode(kind::MULT, den, intVar), num), - NodeManager::currentNM()->mkNode(kind::LT, num, - NodeManager::currentNM()->mkNode(kind::MULT, den, NodeManager::currentNM()->mkNode(kind::PLUS, intVar, NodeManager::currentNM()->mkConst(Rational(1)))))); - } else { - cond = NodeManager::currentNM()->mkNode(kind::AND, - NodeManager::currentNM()->mkNode(kind::LEQ, NodeManager::currentNM()->mkNode(kind::MULT, den, intVar), num), - NodeManager::currentNM()->mkNode(kind::LT, num, - NodeManager::currentNM()->mkNode(kind::MULT, den, NodeManager::currentNM()->mkNode(kind::PLUS, intVar, NodeManager::currentNM()->mkConst(Rational(-1)))))); - } - new_conds.push_back( cond.negate() ); - if( ret.getKind()==INTS_DIVISION_TOTAL ){ - ret = intVar; - }else{ - ret = NodeManager::currentNM()->mkNode(kind::MINUS, num, NodeManager::currentNM()->mkNode(kind::MULT, den, intVar)); + /* ITE lifting + if( ret.getKind()==ITE ){ + TypeNode ite_t = ret[1].getType(); + if( !ite_t.isBoolean() ){ + ite_t = TypeNode::leastCommonTypeNode( ite_t, ret[2].getType() ); + Node ite_v = NodeManager::currentNM()->mkBoundVar(ite_t); + new_vars.push_back( ite_v ); + Node cond = NodeManager::currentNM()->mkNode(kind::ITE, ret[0], ite_v.eqNode( ret[1] ), ite_v.eqNode( ret[2] ) ); + new_conds.push_back( cond.negate() ); + ret = ite_v; + } + */ + }else if( options::elimExtArithQuant() ){ + if( ret.getKind()==INTS_DIVISION_TOTAL || ret.getKind()==INTS_MODULUS_TOTAL ){ + Node num = ret[0]; + Node den = ret[1]; + if(den.isConst()) { + const Rational& rat = den.getConst<Rational>(); + Assert(!num.isConst()); + if(rat != 0) { + Node intVar = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType()); + new_vars.push_back( intVar ); + Node cond; + if(rat > 0) { + cond = NodeManager::currentNM()->mkNode(kind::AND, + NodeManager::currentNM()->mkNode(kind::LEQ, NodeManager::currentNM()->mkNode(kind::MULT, den, intVar), num), + NodeManager::currentNM()->mkNode(kind::LT, num, + NodeManager::currentNM()->mkNode(kind::MULT, den, NodeManager::currentNM()->mkNode(kind::PLUS, intVar, NodeManager::currentNM()->mkConst(Rational(1)))))); + } else { + cond = NodeManager::currentNM()->mkNode(kind::AND, + NodeManager::currentNM()->mkNode(kind::LEQ, NodeManager::currentNM()->mkNode(kind::MULT, den, intVar), num), + NodeManager::currentNM()->mkNode(kind::LT, num, + NodeManager::currentNM()->mkNode(kind::MULT, den, NodeManager::currentNM()->mkNode(kind::PLUS, intVar, NodeManager::currentNM()->mkConst(Rational(-1)))))); + } + new_conds.push_back( cond.negate() ); + if( ret.getKind()==INTS_DIVISION_TOTAL ){ + ret = intVar; + }else{ + ret = NodeManager::currentNM()->mkNode(kind::MINUS, num, NodeManager::currentNM()->mkNode(kind::MULT, den, intVar)); + } } } - } - }else if( ret.getKind()==TO_INTEGER || ret.getKind()==IS_INTEGER ){ - Node intVar = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType()); - new_vars.push_back( intVar ); - new_conds.push_back(NodeManager::currentNM()->mkNode(kind::AND, - NodeManager::currentNM()->mkNode(kind::LT, - NodeManager::currentNM()->mkNode(kind::MINUS, ret[0], NodeManager::currentNM()->mkConst(Rational(1))), intVar), - NodeManager::currentNM()->mkNode(kind::LEQ, intVar, ret[0])).negate()); - if( ret.getKind()==TO_INTEGER ){ - ret = intVar; - }else{ - ret = ret[0].eqNode( intVar ); + }else if( ret.getKind()==TO_INTEGER || ret.getKind()==IS_INTEGER ){ + Node intVar = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType()); + new_vars.push_back( intVar ); + new_conds.push_back(NodeManager::currentNM()->mkNode(kind::AND, + NodeManager::currentNM()->mkNode(kind::LT, + NodeManager::currentNM()->mkNode(kind::MINUS, ret[0], NodeManager::currentNM()->mkConst(Rational(1))), intVar), + NodeManager::currentNM()->mkNode(kind::LEQ, intVar, ret[0])).negate()); + if( ret.getKind()==TO_INTEGER ){ + ret = intVar; + }else{ + ret = ret[0].eqNode( intVar ); + } } } icache[prev] = ret; @@ -782,7 +830,7 @@ bool QuantifiersRewriter::isConditionalVariableElim( Node n, int pol ){ return false; } -Node QuantifiersRewriter::computeCondSplit( Node body, Node ipl ){ +Node QuantifiersRewriter::computeCondSplit( Node body, QAttributes& qa ){ if( options::iteDtTesterSplitQuant() && body.getKind()==ITE ){ Trace("quantifiers-rewrite-ite-debug") << "DTT split : " << body << std::endl; std::map< Node, Node > pcons; @@ -799,7 +847,8 @@ Node QuantifiersRewriter::computeCondSplit( Node body, Node ipl ){ } } if( options::condVarSplitQuant() ){ - if( body.getKind()==ITE || ( body.getKind()==IFF && options::condVarSplitQuantAgg() && !TermDb::isFunDefAnnotation( ipl ) ) ){ + if( body.getKind()==ITE || ( body.getKind()==IFF && options::condVarSplitQuantAgg() ) ){ + Assert( !qa.isFunDef() ); Trace("quantifiers-rewrite-debug") << "Conditional var elim split " << body << "?" << std::endl; bool do_split = false; unsigned index_max = body.getKind()==ITE ? 0 : 1; @@ -932,8 +981,7 @@ bool QuantifiersRewriter::computeVariableElimLit( Node lit, bool pol, std::vecto newChildren.push_back( Node::fromExpr( c.getConstructor() ) ); std::vector< Node > newVars; for( unsigned j=0; j<c.getNumArgs(); j++ ){ - TypeNode tn = TypeNode::fromType( c[j].getSelector().getType() ); - tn = tn[1]; + TypeNode tn = TypeNode::fromType( c[j].getRangeType() ); Node v = NodeManager::currentNM()->mkBoundVar( tn ); newChildren.push_back( v ); newVars.push_back( v ); @@ -957,7 +1005,7 @@ bool QuantifiersRewriter::computeVariableElimLit( Node lit, bool pol, std::vecto return false; } -Node QuantifiersRewriter::computeVarElimination2( Node body, std::vector< Node >& args, Node& ipl, std::map< Node, std::vector< int > >& var_parent ){ +Node QuantifiersRewriter::computeVarElimination2( Node body, std::vector< Node >& args, QAttributes& qa, std::map< Node, std::vector< int > >& var_parent ){ Trace("var-elim-quant-debug") << "Compute var elimination for " << body << std::endl; QuantPhaseReq qpr( body ); std::vector< Node > vars; @@ -977,15 +1025,15 @@ Node QuantifiersRewriter::computeVarElimination2( Node body, std::vector< Node > //remake with eliminated nodes body = body.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); body = Rewriter::rewrite( body ); - if( !ipl.isNull() ){ - ipl = ipl.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); + if( !qa.d_ipl.isNull() ){ + qa.d_ipl = qa.d_ipl.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); } Trace("var-elim-quant") << "Return " << body << std::endl; } return body; } -Node QuantifiersRewriter::computeVarElimination( Node body, std::vector< Node >& args, Node& ipl ){ +Node QuantifiersRewriter::computeVarElimination( Node body, std::vector< Node >& args, QAttributes& qa ){ //the parent id's for each variable, if using purifyQuant std::map< Node, std::vector< int > > var_parent; if( options::purifyQuant() ){ @@ -995,7 +1043,7 @@ Node QuantifiersRewriter::computeVarElimination( Node body, std::vector< Node >& Node prev; do{ prev = body; - body = computeVarElimination2( body, args, ipl, var_parent ); + body = computeVarElimination2( body, args, qa, var_parent ); }while( prev!=body && !args.empty() ); } return body; @@ -1290,13 +1338,13 @@ Node QuantifiersRewriter::computeSplit( Node f, std::vector< Node >& args, Node return f; } -Node QuantifiersRewriter::mkForAll( std::vector< Node >& args, Node body, Node ipl ){ +Node QuantifiersRewriter::mkForAll( std::vector< Node >& args, Node body, QAttributes& qa ){ std::vector< Node > activeArgs; //if cegqi is on, may be synthesis conjecture, in which case we want to keep all variables - if( options::ceGuidedInst() && TermDb::isSygusConjectureAnnotation( ipl ) ){ + if( options::ceGuidedInst() && qa.d_sygus ){ activeArgs.insert( activeArgs.end(), args.begin(), args.end() ); }else{ - computeArgVec2( args, activeArgs, body, ipl ); + computeArgVec2( args, activeArgs, body, qa.d_ipl ); } if( activeArgs.empty() ){ return body; @@ -1304,14 +1352,14 @@ Node QuantifiersRewriter::mkForAll( std::vector< Node >& args, Node body, Node i std::vector< Node > children; children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, activeArgs ) ); children.push_back( body ); - if( !ipl.isNull() ){ - children.push_back( ipl ); + if( !qa.d_ipl.isNull() ){ + children.push_back( qa.d_ipl ); } return NodeManager::currentNM()->mkNode( kind::FORALL, children ); } } -Node QuantifiersRewriter::computeMiniscoping( Node f, std::vector< Node >& args, Node body, Node ipl ){ +Node QuantifiersRewriter::computeMiniscoping( Node f, std::vector< Node >& args, Node body, QAttributes& qa ){ if( body.getKind()==FORALL ){ //combine arguments std::vector< Node > newArgs; @@ -1319,26 +1367,26 @@ Node QuantifiersRewriter::computeMiniscoping( Node f, std::vector< Node >& args, newArgs.push_back( body[0][i] ); } newArgs.insert( newArgs.end(), args.begin(), args.end() ); - return mkForAll( newArgs, body[ 1 ], ipl ); + return mkForAll( newArgs, body[ 1 ], qa ); }else{ if( body.getKind()==NOT ){ //push not downwards if( body[0].getKind()==NOT ){ - return computeMiniscoping( f, args, body[0][0], ipl ); + return computeMiniscoping( f, args, body[0][0], qa ); }else if( body[0].getKind()==AND ){ if( options::miniscopeQuantFreeVar() ){ NodeBuilder<> t(kind::OR); for( int i=0; i<(int)body[0].getNumChildren(); i++ ){ t << ( body[0][i].getKind()==NOT ? body[0][i][0] : body[0][i].notNode() ); } - return computeMiniscoping( f, args, t.constructNode(), ipl ); + return computeMiniscoping( f, args, t.constructNode(), qa ); } }else if( body[0].getKind()==OR ){ if( options::miniscopeQuant() ){ NodeBuilder<> t(kind::AND); for( int i=0; i<(int)body[0].getNumChildren(); i++ ){ Node trm = body[0][i].negate(); - t << computeMiniscoping( f, args, trm, ipl ); + t << computeMiniscoping( f, args, trm, qa ); } return t.constructNode(); } @@ -1348,7 +1396,7 @@ Node QuantifiersRewriter::computeMiniscoping( Node f, std::vector< Node >& args, //break apart NodeBuilder<> t(kind::AND); for( unsigned i=0; i<body.getNumChildren(); i++ ){ - t << computeMiniscoping( f, args, body[i], ipl ); + t << computeMiniscoping( f, args, body[i], qa ); } Node retVal = t; return retVal; @@ -1376,7 +1424,7 @@ Node QuantifiersRewriter::computeMiniscoping( Node f, std::vector< Node >& args, return body_split; }else if( body_split.getNumChildren()>0 ){ newBody = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb; - body_split << mkForAll( args, newBody, ipl ); + body_split << mkForAll( args, newBody, qa ); return body_split.getNumChildren()==1 ? body_split.getChild( 0 ) : body_split; } } @@ -1385,7 +1433,7 @@ Node QuantifiersRewriter::computeMiniscoping( Node f, std::vector< Node >& args, //if( body==f[1] ){ // return f; //}else{ - return mkForAll( args, body, ipl ); + return mkForAll( args, body, qa ); //} } @@ -1491,101 +1539,96 @@ Node QuantifiersRewriter::computeAggressiveMiniscoping( std::vector< Node >& arg return n; } } - return mkForAll( args, body, Node::null() ); + QAttributes qa; + return mkForAll( args, body, qa ); } -bool QuantifiersRewriter::doOperation( Node f, bool isNested, int computeOption ){ +bool QuantifiersRewriter::doOperation( Node q, int computeOption, QAttributes& qa ){ + bool is_strict_trigger = qa.d_hasPattern && options::userPatternsQuant()==USER_PAT_MODE_TRUST; + bool is_std = !qa.d_sygus && !qa.d_quant_elim && !qa.isFunDef() && !is_strict_trigger; if( computeOption==COMPUTE_ELIM_SYMBOLS ){ return true; }else if( computeOption==COMPUTE_MINISCOPING ){ - return true; + return is_std; }else if( computeOption==COMPUTE_AGGRESSIVE_MINISCOPING ){ - return options::aggressiveMiniscopeQuant(); + return options::aggressiveMiniscopeQuant() && is_std; }else if( computeOption==COMPUTE_NNF ){ - return options::nnfQuant(); + return true; }else if( computeOption==COMPUTE_PROCESS_TERMS ){ return true; //return options::iteLiftQuant()!=ITE_LIFT_QUANT_MODE_NONE || options::iteCondVarSplitQuant(); }else if( computeOption==COMPUTE_COND_SPLIT ){ - return options::iteDtTesterSplitQuant() || options::condVarSplitQuant(); + return ( options::iteDtTesterSplitQuant() || options::condVarSplitQuant() ) && !is_strict_trigger; }else if( computeOption==COMPUTE_PRENEX ){ - return options::prenexQuant()!=PRENEX_NONE && !options::aggressiveMiniscopeQuant(); + return options::prenexQuant()!=PRENEX_NONE && !options::aggressiveMiniscopeQuant() && is_std; }else if( computeOption==COMPUTE_VAR_ELIMINATION ){ - return options::varElimQuant() || options::dtVarExpandQuant() || options::purifyQuant(); + return ( options::varElimQuant() || options::dtVarExpandQuant() || options::purifyQuant() ) && is_std; //}else if( computeOption==COMPUTE_CNF ){ // return options::cnfQuant(); }else if( computeOption==COMPUTE_PURIFY_EXPAND ){ - return options::purifyQuant(); + return options::purifyQuant() && is_std; }else{ return false; } } //general method for computing various rewrites -Node QuantifiersRewriter::computeOperation( Node f, bool isNested, int computeOption ){ - if( f.getKind()==FORALL ){ - Trace("quantifiers-rewrite-debug") << "Compute operation " << computeOption << " on " << f << ", nested = " << isNested << std::endl; - std::vector< Node > args; - for( unsigned i=0; i<f[0].getNumChildren(); i++ ){ - args.push_back( f[0][i] ); - } - Node n = f[1]; - Node ipl; - if( f.getNumChildren()==3 ){ - ipl = f[2]; - } - if( computeOption==COMPUTE_ELIM_SYMBOLS ){ - n = computeElimSymbols( n ); - }else if( computeOption==COMPUTE_MINISCOPING ){ - //return directly - return computeMiniscoping( f, args, n, ipl ); - }else if( computeOption==COMPUTE_AGGRESSIVE_MINISCOPING ){ - return computeAggressiveMiniscoping( args, n ); - }else if( computeOption==COMPUTE_NNF ){ - n = computeNNF( n ); - }else if( computeOption==COMPUTE_PROCESS_TERMS ){ - std::vector< Node > new_conds; - n = computeProcessTerms( n, args, new_conds, f ); - if( !new_conds.empty() ){ - new_conds.push_back( n ); - n = NodeManager::currentNM()->mkNode( OR, new_conds ); - } - }else if( computeOption==COMPUTE_COND_SPLIT ){ - n = computeCondSplit( n, ipl ); - }else if( computeOption==COMPUTE_PRENEX ){ - n = computePrenex( n, args, true ); - }else if( computeOption==COMPUTE_VAR_ELIMINATION ){ - n = computeVarElimination( n, args, ipl ); - //}else if( computeOption==COMPUTE_CNF ){ - //n = computeCNF( n, args, defs, false ); - //ipl = Node::null(); - }else if( computeOption==COMPUTE_PURIFY_EXPAND ){ - std::vector< Node > conj; - computePurifyExpand( n, conj, args, ipl ); - if( !conj.empty() ){ - return conj.size()==1 ? conj[0] : NodeManager::currentNM()->mkNode( AND, conj ); - }else{ - return f; - } +Node QuantifiersRewriter::computeOperation( Node f, int computeOption, QAttributes& qa ){ + Trace("quantifiers-rewrite-debug") << "Compute operation " << computeOption << " on " << f << std::endl; + std::vector< Node > args; + for( unsigned i=0; i<f[0].getNumChildren(); i++ ){ + args.push_back( f[0][i] ); + } + Node n = f[1]; + if( computeOption==COMPUTE_ELIM_SYMBOLS ){ + n = computeElimSymbols( n ); + }else if( computeOption==COMPUTE_MINISCOPING ){ + //return directly + return computeMiniscoping( f, args, n, qa ); + }else if( computeOption==COMPUTE_AGGRESSIVE_MINISCOPING ){ + return computeAggressiveMiniscoping( args, n ); + }else if( computeOption==COMPUTE_NNF ){ + n = computeNNF( n ); + }else if( computeOption==COMPUTE_PROCESS_TERMS ){ + std::vector< Node > new_conds; + n = computeProcessTerms( n, args, new_conds, f, qa ); + if( !new_conds.empty() ){ + new_conds.push_back( n ); + n = NodeManager::currentNM()->mkNode( OR, new_conds ); } - Trace("quantifiers-rewrite-debug") << "Compute Operation: return " << n << ", " << args.size() << std::endl; - if( f[1]==n && args.size()==f[0].getNumChildren() ){ + }else if( computeOption==COMPUTE_COND_SPLIT ){ + n = computeCondSplit( n, qa ); + }else if( computeOption==COMPUTE_PRENEX ){ + n = computePrenex( n, args, true ); + }else if( computeOption==COMPUTE_VAR_ELIMINATION ){ + n = computeVarElimination( n, args, qa ); + //}else if( computeOption==COMPUTE_CNF ){ + //n = computeCNF( n, args, defs, false ); + //ipl = Node::null(); + }else if( computeOption==COMPUTE_PURIFY_EXPAND ){ + std::vector< Node > conj; + computePurifyExpand( n, conj, args, qa ); + if( !conj.empty() ){ + return conj.size()==1 ? conj[0] : NodeManager::currentNM()->mkNode( AND, conj ); + }else{ return f; + } + } + Trace("quantifiers-rewrite-debug") << "Compute Operation: return " << n << ", " << args.size() << std::endl; + if( f[1]==n && args.size()==f[0].getNumChildren() ){ + return f; + }else{ + if( args.empty() ){ + return n; }else{ - if( args.empty() ){ - return n; - }else{ - std::vector< Node > children; - children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, args ) ); - children.push_back( n ); - if( !ipl.isNull() ){ - children.push_back( ipl ); - } - return NodeManager::currentNM()->mkNode(kind::FORALL, children ); + std::vector< Node > children; + children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, args ) ); + children.push_back( n ); + if( !qa.d_ipl.isNull() && args.size()==f[0].getNumChildren() ){ + children.push_back( qa.d_ipl ); } + return NodeManager::currentNM()->mkNode(kind::FORALL, children ); } - }else{ - return f; } } @@ -1754,31 +1797,29 @@ Node QuantifiersRewriter::preSkolemizeQuantifiers( Node n, bool polarity, std::v //check if it contains a quantifier as a subterm //if so, we will write this node if( containsQuantifiers( n ) ){ - if( n.getType().isBoolean() ){ - if( n.getKind()==kind::ITE || n.getKind()==kind::IFF || n.getKind()==kind::XOR || n.getKind()==kind::IMPLIES ){ - if( options::preSkolemQuantAgg() ){ - Node nn; - //must remove structure - if( n.getKind()==kind::ITE ){ - nn = NodeManager::currentNM()->mkNode( kind::AND, - NodeManager::currentNM()->mkNode( kind::OR, n[0].notNode(), n[1] ), - NodeManager::currentNM()->mkNode( kind::OR, n[0], n[2] ) ); - }else if( n.getKind()==kind::IFF || n.getKind()==kind::XOR ){ - nn = NodeManager::currentNM()->mkNode( kind::AND, - NodeManager::currentNM()->mkNode( kind::OR, n[0].notNode(), n.getKind()==kind::XOR ? n[1].notNode() : n[1] ), - NodeManager::currentNM()->mkNode( kind::OR, n[0], n.getKind()==kind::XOR ? n[1] : n[1].notNode() ) ); - }else if( n.getKind()==kind::IMPLIES ){ - nn = NodeManager::currentNM()->mkNode( kind::OR, n[0].notNode(), n[1] ); - } - return preSkolemizeQuantifiers( nn, polarity, fvTypes, fvs ); - } - }else if( n.getKind()==kind::AND || n.getKind()==kind::OR ){ - vector< Node > children; - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - children.push_back( preSkolemizeQuantifiers( n[i], polarity, fvTypes, fvs ) ); + if( ( n.getKind()==kind::ITE && n.getType().isBoolean() ) || n.getKind()==kind::IFF ){ + if( options::preSkolemQuantAgg() ){ + Node nn; + //must remove structure + if( n.getKind()==kind::ITE ){ + nn = NodeManager::currentNM()->mkNode( kind::AND, + NodeManager::currentNM()->mkNode( kind::OR, n[0].notNode(), n[1] ), + NodeManager::currentNM()->mkNode( kind::OR, n[0], n[2] ) ); + }else if( n.getKind()==kind::IFF || n.getKind()==kind::XOR ){ + nn = NodeManager::currentNM()->mkNode( kind::AND, + NodeManager::currentNM()->mkNode( kind::OR, n[0].notNode(), n.getKind()==kind::XOR ? n[1].notNode() : n[1] ), + NodeManager::currentNM()->mkNode( kind::OR, n[0], n.getKind()==kind::XOR ? n[1] : n[1].notNode() ) ); + }else if( n.getKind()==kind::IMPLIES ){ + nn = NodeManager::currentNM()->mkNode( kind::OR, n[0].notNode(), n[1] ); } - return NodeManager::currentNM()->mkNode( n.getKind(), children ); + return preSkolemizeQuantifiers( nn, polarity, fvTypes, fvs ); } + }else if( n.getKind()==kind::AND || n.getKind()==kind::OR ){ + vector< Node > children; + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + children.push_back( preSkolemizeQuantifiers( n[i], polarity, fvTypes, fvs ) ); + } + return NodeManager::currentNM()->mkNode( n.getKind(), children ); } } } @@ -1786,15 +1827,20 @@ Node QuantifiersRewriter::preSkolemizeQuantifiers( Node n, bool polarity, std::v } Node QuantifiersRewriter::preprocess( Node n, bool isInst ) { + Node prev = n; if( options::preSkolemQuant() ){ if( !isInst || !options::preSkolemQuantNested() ){ - //apply pre-skolemization to existential quantifiers Trace("quantifiers-preprocess-debug") << "Pre-skolemize " << n << "..." << std::endl; + //apply pre-skolemization to existential quantifiers std::vector< TypeNode > fvTypes; std::vector< TNode > fvs; - n = quantifiers::QuantifiersRewriter::preSkolemizeQuantifiers( n, true, fvTypes, fvs ); + n = quantifiers::QuantifiersRewriter::preSkolemizeQuantifiers( prev, true, fvTypes, fvs ); } } + if( n!=prev ){ + Trace("quantifiers-preprocess") << "Preprocess " << prev<< std::endl; + Trace("quantifiers-preprocess") << "..returned " << n << std::endl; + } return n; } @@ -1886,7 +1932,7 @@ Node QuantifiersRewriter::computePurify( Node body, std::vector< Node >& args, s } } -void QuantifiersRewriter::computePurifyExpand( Node body, std::vector< Node >& conj, std::vector< Node >& args, Node ipl ) { +void QuantifiersRewriter::computePurifyExpand( Node body, std::vector< Node >& conj, std::vector< Node >& args, QAttributes& qa ) { if( body.getKind()==OR ){ Trace("quantifiers-rewrite-purify-exp") << "Purify expansion : " << body << std::endl; std::map< int, std::vector< Node > > disj; diff --git a/src/theory/quantifiers/quantifiers_rewriter.h b/src/theory/quantifiers/quantifiers_rewriter.h index 47997f9a7..2071d1793 100644 --- a/src/theory/quantifiers/quantifiers_rewriter.h +++ b/src/theory/quantifiers/quantifiers_rewriter.h @@ -1,13 +1,13 @@ /********************* */ /*! \file quantifiers_rewriter.h ** \verbatim - ** Original author: Morgan Deters - ** Major contributors: Andrew Reynolds - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Morgan Deters, Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Rewriter for the theory of inductive quantifiers ** @@ -26,6 +26,8 @@ namespace CVC4 { namespace theory { namespace quantifiers { +class QAttributes; + class QuantifiersRewriter { private: static int getPurifyIdLit2( Node n, std::map< Node, int >& visited ); @@ -37,7 +39,7 @@ public: static int getPurifyIdLit( Node n ); private: static void addNodeToOrBuilder( Node n, NodeBuilder<>& t ); - static Node mkForAll( std::vector< Node >& args, Node body, Node ipl ); + static Node mkForAll( std::vector< Node >& args, Node body, QAttributes& qa ); static void computeArgs( std::vector< Node >& args, std::map< Node, bool >& activeMap, Node n, std::map< Node, bool >& visited ); static void computeArgVec( std::vector< Node >& args, std::vector< Node >& activeArgs, Node n ); static void computeArgVec2( std::vector< Node >& args, std::vector< Node >& activeArgs, Node n, Node ipl ); @@ -52,21 +54,21 @@ private: std::map< Node, std::vector< int > >& var_parent ); static Node computePurify2( Node body, std::vector< Node >& args, std::map< Node, Node >& visited, std::map< Node, Node >& var_to_term, std::map< Node, std::vector< int > >& var_parent, int parentId ); - static Node computeVarElimination2( Node body, std::vector< Node >& args, Node& ipl, std::map< Node, std::vector< int > >& var_parent ); + static Node computeVarElimination2( Node body, std::vector< Node >& args, QAttributes& qa, std::map< Node, std::vector< int > >& var_parent ); private: static Node computeElimSymbols( Node body ); - static Node computeMiniscoping( Node f, std::vector< Node >& args, Node body, Node ipl ); + static Node computeMiniscoping( Node f, std::vector< Node >& args, Node body, QAttributes& qa ); static Node computeAggressiveMiniscoping( std::vector< Node >& args, Node body ); static Node computeNNF( Node body ); //cache is dependent upon currCond, icache is not, new_conds are negated conditions - static Node computeProcessTerms( Node body, std::vector< Node >& new_vars, std::vector< Node >& new_conds, Node q ); - static Node computeCondSplit( Node body, Node ipl ); + static Node computeProcessTerms( Node body, std::vector< Node >& new_vars, std::vector< Node >& new_conds, Node q, QAttributes& qa ); + static Node computeCondSplit( Node body, QAttributes& qa ); static Node computeCNF( Node body, std::vector< Node >& args, NodeBuilder<>& defs, bool forcePred ); static Node computePrenex( Node body, std::vector< Node >& args, bool pol ); static Node computeSplit( Node f, std::vector< Node >& args, Node body ); - static Node computeVarElimination( Node body, std::vector< Node >& args, Node& ipl ); + static Node computeVarElimination( Node body, std::vector< Node >& args, QAttributes& qa ); static Node computePurify( Node body, std::vector< Node >& args, std::map< Node, std::vector< int > >& var_parent ); - static void computePurifyExpand( Node body, std::vector< Node >& conj, std::vector< Node >& args, Node ipl ); + static void computePurifyExpand( Node body, std::vector< Node >& conj, std::vector< Node >& args, QAttributes& qa ); private: enum{ COMPUTE_ELIM_SYMBOLS = 0, @@ -82,7 +84,7 @@ private: //COMPUTE_CNF, COMPUTE_LAST }; - static Node computeOperation( Node f, bool isNested, int computeOption ); + static Node computeOperation( Node f, int computeOption, QAttributes& qa ); public: static RewriteResponse preRewrite(TNode in); static RewriteResponse postRewrite(TNode in); @@ -90,7 +92,7 @@ public: static inline void shutdown() {} private: /** options */ - static bool doOperation( Node f, bool isNested, int computeOption ); + static bool doOperation( Node f, int computeOption, QAttributes& qa ); private: static Node preSkolemizeQuantifiers(Node n, bool polarity, std::vector< TypeNode >& fvTypes, std::vector<TNode>& fvs); public: diff --git a/src/theory/quantifiers/relevant_domain.cpp b/src/theory/quantifiers/relevant_domain.cpp index 88793358e..b353fce2f 100644 --- a/src/theory/quantifiers/relevant_domain.cpp +++ b/src/theory/quantifiers/relevant_domain.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file relevant_domain.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Implementation of relevant domain class **/ @@ -82,8 +82,9 @@ RelevantDomain::RDomain * RelevantDomain::getRDomain( Node n, int i, bool getPar return getParent ? d_rel_doms[n][i]->getParent() : d_rel_doms[n][i]; } -void RelevantDomain::reset(){ +bool RelevantDomain::reset( Theory::Effort e ) { d_is_computed = false; + return true; } void RelevantDomain::compute(){ @@ -94,7 +95,7 @@ void RelevantDomain::compute(){ it2->second->reset(); } } - for( int i=0; i<d_model->getNumAssertedQuantifiers(); i++ ){ + for( unsigned i=0; i<d_model->getNumAssertedQuantifiers(); i++ ){ Node q = d_model->getAssertedQuantifier( i ); Node icf = d_qe->getTermDatabase()->getInstConstantBody( q ); Trace("rel-dom-debug") << "compute relevant domain for " << icf << std::endl; @@ -140,7 +141,7 @@ void RelevantDomain::compute(){ } void RelevantDomain::computeRelevantDomain( Node q, Node n, bool hasPol, bool pol ) { - Node op = d_qe->getTermDatabase()->getOperator( n ); + Node op = d_qe->getTermDatabase()->getMatchOperator( n ); for( unsigned i=0; i<n.getNumChildren(); i++ ){ if( !op.isNull() ){ RDomain * rf = getRDomain( op, i ); diff --git a/src/theory/quantifiers/relevant_domain.h b/src/theory/quantifiers/relevant_domain.h index 3ce285bc8..2b90520fd 100644 --- a/src/theory/quantifiers/relevant_domain.h +++ b/src/theory/quantifiers/relevant_domain.h @@ -1,13 +1,13 @@ /********************* */ /*! \file relevant_domain.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Morgan Deters, Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief relevant domain class **/ @@ -23,7 +23,7 @@ namespace CVC4 { namespace theory { namespace quantifiers { -class RelevantDomain +class RelevantDomain : public QuantifiersUtil { private: class RDomain @@ -62,7 +62,10 @@ private: public: RelevantDomain( QuantifiersEngine* qe, FirstOrderModel* m ); virtual ~RelevantDomain(){} - void reset(); + /* reset */ + bool reset( Theory::Effort e ); + /** identify */ + std::string identify() const { return "RelevantDomain"; } //compute the relevant domain void compute(); diff --git a/src/theory/quantifiers/rewrite_engine.cpp b/src/theory/quantifiers/rewrite_engine.cpp index 4c8050239..5365dbcfa 100644 --- a/src/theory/quantifiers/rewrite_engine.cpp +++ b/src/theory/quantifiers/rewrite_engine.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file rewrite_engine.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Rewrite engine module ** @@ -68,7 +68,7 @@ bool RewriteEngine::needsCheck( Theory::Effort e ){ void RewriteEngine::check( Theory::Effort e, unsigned quant_e ) { if( quant_e==QuantifiersEngine::QEFFORT_STANDARD ){ - //if( e==Theory::EFFORT_FULL ){ + Assert( !d_quantEngine->inConflict() ); Trace("rewrite-engine") << "---Rewrite Engine Round, effort = " << e << "---" << std::endl; //if( e==Theory::EFFORT_LAST_CALL ){ // if( !d_quantEngine->getModel()->isModelSet() ){ @@ -95,7 +95,7 @@ void RewriteEngine::check( Theory::Effort e, unsigned quant_e ) { //per priority level int index = 0; bool success = true; - while( success && index<(int)d_priority_order.size() ) { + while( !d_quantEngine->inConflict() && success && index<(int)d_priority_order.size() ) { addedLemmas += checkRewriteRule( d_priority_order[index], e ); index++; if( index<(int)d_priority_order.size() ){ @@ -104,11 +104,6 @@ void RewriteEngine::check( Theory::Effort e, unsigned quant_e ) { } Trace("rewrite-engine") << "Finished rewrite engine, added " << addedLemmas << " lemmas." << std::endl; - if (addedLemmas==0) { - - }else{ - //otherwise, the search will continue - } } } @@ -124,12 +119,13 @@ int RewriteEngine::checkRewriteRule( Node f, Theory::Effort e ) { std::map< Node, QuantInfo >::iterator it = d_qinfo.find( f ); if( it!=d_qinfo.end() ){ QuantInfo * qi = &it->second; - if( qi->d_mg->isValid() ){ + if( qi->matchGeneratorIsValid() ){ Node rr = TermDb::getRewriteRule( f ); Trace("rewrite-engine-inst-debug") << " Reset round..." << std::endl; qi->reset_round( qcf ); Trace("rewrite-engine-inst-debug") << " Get matches..." << std::endl; - while( qi->d_mg->getNextMatch( qcf, qi ) && ( addedLemmas==0 || !options::rrOneInstPerRound() ) ){ + while( !d_quantEngine->inConflict() && qi->getNextMatch( qcf ) && + ( addedLemmas==0 || !options::rrOneInstPerRound() ) ){ Trace("rewrite-engine-inst-debug") << " Got match to complete..." << std::endl; qi->debugPrintMatch( "rewrite-engine-inst-debug" ); std::vector< int > assigned; @@ -137,7 +133,7 @@ int RewriteEngine::checkRewriteRule( Node f, Theory::Effort e ) { bool doContinue = false; bool success = true; int tempAddedLemmas = 0; - while( tempAddedLemmas==0 && success && ( addedLemmas==0 || !options::rrOneInstPerRound() ) ){ + while( !d_quantEngine->inConflict() && tempAddedLemmas==0 && success && ( addedLemmas==0 || !options::rrOneInstPerRound() ) ){ success = qi->completeMatch( qcf, assigned, doContinue ); doContinue = true; if( success ){ @@ -158,7 +154,7 @@ int RewriteEngine::checkRewriteRule( Node f, Theory::Effort e ) { if( inst.size()>f[0].getNumChildren() ){ inst.resize( f[0].getNumChildren() ); } - if( d_quantEngine->addInstantiation( f, inst, false ) ){ + if( d_quantEngine->addInstantiation( f, inst ) ){ addedLemmas++; tempAddedLemmas++; /* @@ -289,7 +285,7 @@ void RewriteEngine::registerQuantifier( Node f ) { //make the quantified formula d_qinfo_n[f] = NodeManager::currentNM()->mkNode( FORALL, qcfn_c ); Trace("rr-register") << " qcf formula is : " << d_qinfo_n[f] << std::endl; - d_qinfo[f].initialize( d_qinfo_n[f], d_qinfo_n[f][1] ); + d_qinfo[f].initialize( qcf, d_qinfo_n[f], d_qinfo_n[f][1] ); } } } diff --git a/src/theory/quantifiers/rewrite_engine.h b/src/theory/quantifiers/rewrite_engine.h index 6ad76c541..424530696 100644 --- a/src/theory/quantifiers/rewrite_engine.h +++ b/src/theory/quantifiers/rewrite_engine.h @@ -1,13 +1,13 @@ /********************* */ /*! \file rewrite_engine.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Morgan Deters, Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** [[ Add lengthier description here ]] ** \todo document this file diff --git a/src/theory/quantifiers/symmetry_breaking.cpp b/src/theory/quantifiers/symmetry_breaking.cpp index 4c8e24d08..2a2b13583 100644 --- a/src/theory/quantifiers/symmetry_breaking.cpp +++ b/src/theory/quantifiers/symmetry_breaking.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file symmetry_breaking.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): Morgan Deters + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King, Morgan Deters ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief symmetry breaking module ** diff --git a/src/theory/quantifiers/symmetry_breaking.h b/src/theory/quantifiers/symmetry_breaking.h index 43e5ec765..38fea4f45 100644 --- a/src/theory/quantifiers/symmetry_breaking.h +++ b/src/theory/quantifiers/symmetry_breaking.h @@ -1,13 +1,13 @@ /********************* */ /*! \file symmetry_breaking.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): Morgan Deters + ** Top contributors (to current version): + ** Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Pre-process step for first-order reasoning **/ diff --git a/src/theory/quantifiers/term_database.cpp b/src/theory/quantifiers/term_database.cpp index 560f68810..8b09d8e5d 100644 --- a/src/theory/quantifiers/term_database.cpp +++ b/src/theory/quantifiers/term_database.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file term_database.cpp ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Francois Bobot - ** Minor contributors (to current version): Kshitij Bansal, Morgan Deters + ** Top contributors (to current version): + ** Andrew Reynolds, Francois Bobot, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Implementation of term databse class **/ @@ -59,23 +59,27 @@ TNode TermArgTrie::existsTerm( std::vector< TNode >& reps, int argIndex ) { } bool TermArgTrie::addTerm( TNode n, std::vector< TNode >& reps, int argIndex ){ + return addOrGetTerm( n, reps, argIndex )==n; +} + +TNode TermArgTrie::addOrGetTerm( TNode n, std::vector< TNode >& reps, int argIndex ) { if( argIndex==(int)reps.size() ){ if( d_data.empty() ){ //store n in d_data (this should be interpretted as the "data" and not as a reference to a child) d_data[n].clear(); - return true; + return n; }else{ - return false; + return d_data.begin()->first; } }else{ - return d_data[reps[argIndex]].addTerm( n, reps, argIndex+1 ); + return d_data[reps[argIndex]].addOrGetTerm( n, reps, argIndex+1 ); } } void TermArgTrie::debugPrint( const char * c, Node n, unsigned depth ) { for( std::map< TNode, TermArgTrie >::iterator it = d_data.begin(); it != d_data.end(); ++it ){ - for( unsigned i=0; i<depth; i++ ){ Debug(c) << " "; } - Debug(c) << it->first << std::endl; + for( unsigned i=0; i<depth; i++ ){ Trace(c) << " "; } + Trace(c) << it->first << std::endl; it->second.debugPrint( c, n, depth+1 ); } } @@ -107,10 +111,25 @@ Node TermDb::getGroundTerm( Node f, unsigned i ) { return d_op_map[f][i]; } -Node TermDb::getOperator( Node n ) { - //return n.getOperator(); +unsigned TermDb::getNumTypeGroundTerms( TypeNode tn ) { + std::map< TypeNode, std::vector< Node > >::iterator it = d_type_map.find( tn ); + if( it!=d_type_map.end() ){ + return it->second.size(); + }else{ + return 0; + } +} + +Node TermDb::getTypeGroundTerm( TypeNode tn, unsigned i ) { + Assert( i<d_type_map[tn].size() ); + return d_type_map[tn][i]; +} + +Node TermDb::getMatchOperator( Node n ) { Kind k = n.getKind(); - if( k==SELECT || k==STORE || k==UNION || k==INTERSECTION || k==SUBSET || k==SETMINUS || k==MEMBER || k==SINGLETON ){ + //datatype operators may be parametric, always assume they are + if( k==SELECT || k==STORE || k==UNION || k==INTERSECTION || k==SUBSET || k==SETMINUS || k==MEMBER || k==SINGLETON || + k==APPLY_SELECTOR_TOTAL || k==APPLY_TESTER ){ //since it is parametric, use a particular one as op TypeNode tn = n[0].getType(); Node op = n.getOperator(); @@ -144,7 +163,7 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant, bool wi //if this is an atomic trigger, consider adding it if( inst::Trigger::isAtomicTrigger( n ) ){ Trace("term-db") << "register term in db " << n << std::endl; - Node op = getOperator( n ); + Node op = getMatchOperator( n ); d_op_map[op].push_back( n ); added.insert( n ); @@ -201,116 +220,192 @@ void TermDb::computeUfEqcTerms( TNode f ) { } } -TNode TermDb::evaluateTerm( TNode n, std::map< TNode, TNode >& subs, bool subsRep ) { - Trace("term-db-eval") << "evaluate term : " << n << std::endl; - eq::EqualityEngine * ee = d_quantEngine->getTheoryEngine()->getMasterEqualityEngine(); - if( ee->hasTerm( n ) ){ - Trace("term-db-eval") << "...exists in ee, return rep " << std::endl; - return ee->getRepresentative( n ); - }else if( n.getKind()==BOUND_VARIABLE ){ - Assert( subs.find( n )!=subs.end() ); - Trace("term-db-eval") << "...substitution is : " << subs[n] << std::endl; - if( subsRep ){ - Assert( ee->hasTerm( subs[n] ) ); - Assert( ee->getRepresentative( subs[n] )==subs[n] ); - return subs[n]; +bool TermDb::inRelevantDomain( TNode f, unsigned i, TNode r ) { + Assert( d_quantEngine->getTheoryEngine()->getMasterEqualityEngine()->getRepresentative( r )==r ); + std::map< Node, std::map< unsigned, std::vector< Node > > >::iterator it = d_func_map_rel_dom.find( f ); + if( it != d_func_map_rel_dom.end() ){ + std::map< unsigned, std::vector< Node > >::iterator it2 = it->second.find( i ); + if( it2!=it->second.end() ){ + return std::find( it2->second.begin(), it2->second.end(), r )!=it2->second.end(); }else{ - return evaluateTerm( subs[n], subs, subsRep ); + return false; } }else{ - if( n.hasOperator() ){ - TNode f = getOperator( n ); - if( !f.isNull() ){ - std::vector< TNode > args; - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - TNode c = evaluateTerm( n[i], subs, subsRep ); - if( c.isNull() ){ - return TNode::null(); + return false; + } +} + +//return a term n' equivalent to n +// maximal subterms of n' are representatives in the equality engine qy +Node TermDb::evaluateTerm2( TNode n, std::map< TNode, Node >& visited, EqualityQuery * qy ) { + std::map< TNode, Node >::iterator itv = visited.find( n ); + if( itv != visited.end() ){ + return itv->second; + } + Trace("term-db-eval") << "evaluate term : " << n << std::endl; + Node ret; + if( n.getKind()==BOUND_VARIABLE ){ + return n; + }else if( !qy->hasTerm( n ) ){ + //term is not known to be equal to a representative in equality engine, evaluate it + if( n.getKind()==FORALL ){ + ret = Node::null(); + }else if( n.hasOperator() ){ + TNode f = getMatchOperator( n ); + std::vector< TNode > args; + bool ret_set = false; + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + TNode c = evaluateTerm2( n[i], visited, qy ); + if( c.isNull() ){ + ret = Node::null(); + ret_set = true; + break; + }else if( c==d_true || c==d_false ){ + //short-circuiting + if( ( n.getKind()==kind::AND && c==d_false ) || ( n.getKind()==kind::OR && c==d_true ) ){ + ret = c; + ret_set = true; + break; + }else if( n.getKind()==kind::ITE && i==0 ){ + ret = evaluateTerm2( n[ c==d_true ? 1 : 2], visited, qy ); + ret_set = true; + break; } - Trace("term-db-eval") << "Got child : " << c << std::endl; - args.push_back( c ); } - Trace("term-db-eval") << "Get term from DB" << std::endl; - TNode nn = d_func_map_trie[f].existsTerm( args ); - Trace("term-db-eval") << "Got term " << nn << std::endl; - if( !nn.isNull() ){ - if( ee->hasTerm( nn ) ){ - Trace("term-db-eval") << "return rep " << std::endl; - return ee->getRepresentative( nn ); - }else{ - //Assert( false ); + Trace("term-db-eval") << " child " << i << " : " << c << std::endl; + args.push_back( c ); + } + if( !ret_set ){ + //if it is an indexed term, return the congruent term + if( !f.isNull() ){ + TNode nn = qy->getCongruentTerm( f, args ); + Trace("term-db-eval") << " got congruent term " << nn << " from DB for " << n << std::endl; + if( !nn.isNull() ){ + ret = qy->getRepresentative( nn ); + Trace("term-db-eval") << "return rep" << std::endl; + ret_set = true; + Assert( !ret.isNull() ); } } + if( !ret_set ){ + Trace("term-db-eval") << "return rewrite" << std::endl; + //a theory symbol or a new UF term + if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){ + args.insert( args.begin(), n.getOperator() ); + } + ret = NodeManager::currentNM()->mkNode( n.getKind(), args ); + ret = Rewriter::rewrite( ret ); + } } } - return TNode::null(); + }else{ + Trace("term-db-eval") << "...exists in ee, return rep" << std::endl; + ret = qy->getRepresentative( n ); } + Trace("term-db-eval") << "evaluated term : " << n << ", got : " << ret << std::endl; + visited[n] = ret; + return ret; } -TNode TermDb::evaluateTerm( TNode n ) { - eq::EqualityEngine * ee = d_quantEngine->getTheoryEngine()->getMasterEqualityEngine(); - if( ee->hasTerm( n ) ){ - return ee->getRepresentative( n ); - }else if( n.getKind()!=BOUND_VARIABLE ){ + +TNode TermDb::getEntailedTerm2( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool hasSubs, EqualityQuery * qy ) { + Assert( !qy->extendsEngine() ); + Trace("term-db-entail") << "get entailed term : " << n << std::endl; + if( qy->getEngine()->hasTerm( n ) ){ + Trace("term-db-entail") << "...exists in ee, return rep " << std::endl; + return n; + }else if( n.getKind()==BOUND_VARIABLE ){ + if( hasSubs ){ + Assert( subs.find( n )!=subs.end() ); + Trace("term-db-entail") << "...substitution is : " << subs[n] << std::endl; + if( subsRep ){ + Assert( qy->getEngine()->hasTerm( subs[n] ) ); + Assert( qy->getEngine()->getRepresentative( subs[n] )==subs[n] ); + return subs[n]; + }else{ + return getEntailedTerm2( subs[n], subs, subsRep, hasSubs, qy ); + } + } + }else if( n.getKind()==ITE ){ + for( unsigned i=0; i<2; i++ ){ + if( isEntailed2( n[0], subs, subsRep, hasSubs, i==0, qy ) ){ + return getEntailedTerm2( n[ i==0 ? 1 : 2 ], subs, subsRep, hasSubs, qy ); + } + } + }else{ if( n.hasOperator() ){ - TNode f = getOperator( n ); + TNode f = getMatchOperator( n ); if( !f.isNull() ){ std::vector< TNode > args; for( unsigned i=0; i<n.getNumChildren(); i++ ){ - TNode c = evaluateTerm( n[i] ); + TNode c = getEntailedTerm2( n[i], subs, subsRep, hasSubs, qy ); if( c.isNull() ){ return TNode::null(); } + c = qy->getEngine()->getRepresentative( c ); + Trace("term-db-entail") << " child " << i << " : " << c << std::endl; args.push_back( c ); } - TNode nn = d_func_map_trie[f].existsTerm( args ); - if( !nn.isNull() ){ - if( ee->hasTerm( nn ) ){ - return ee->getRepresentative( nn ); - }else{ - //Assert( false ); - } - } + TNode nn = qy->getCongruentTerm( f, args ); + Trace("term-db-entail") << " got congruent term " << nn << " for " << n << std::endl; + return nn; } } } return TNode::null(); } -bool TermDb::isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool pol ) { - Trace("term-db-eval") << "Check entailed : " << n << ", pol = " << pol << std::endl; +Node TermDb::evaluateTerm( TNode n, EqualityQuery * qy ) { + if( qy==NULL ){ + qy = d_quantEngine->getEqualityQuery(); + } + std::map< TNode, Node > visited; + return evaluateTerm2( n, visited, qy ); +} + +TNode TermDb::getEntailedTerm( TNode n, std::map< TNode, TNode >& subs, bool subsRep, EqualityQuery * qy ) { + if( qy==NULL ){ + qy = d_quantEngine->getEqualityQuery(); + } + return getEntailedTerm2( n, subs, subsRep, true, qy ); +} + +TNode TermDb::getEntailedTerm( TNode n, EqualityQuery * qy ) { + if( qy==NULL ){ + qy = d_quantEngine->getEqualityQuery(); + } + std::map< TNode, TNode > subs; + return getEntailedTerm2( n, subs, false, false, qy ); +} + +bool TermDb::isEntailed2( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool hasSubs, bool pol, EqualityQuery * qy ) { + Assert( !qy->extendsEngine() ); + Trace("term-db-entail") << "Check entailed : " << n << ", pol = " << pol << std::endl; Assert( n.getType().isBoolean() ); if( n.getKind()==EQUAL ){ - TNode n1 = evaluateTerm( n[0], subs, subsRep ); + TNode n1 = getEntailedTerm2( n[0], subs, subsRep, hasSubs, qy ); if( !n1.isNull() ){ - TNode n2 = evaluateTerm( n[1], subs, subsRep ); + TNode n2 = getEntailedTerm2( n[1], subs, subsRep, hasSubs, qy ); if( !n2.isNull() ){ - eq::EqualityEngine * ee = d_quantEngine->getTheoryEngine()->getMasterEqualityEngine(); - Assert( ee->hasTerm( n1 ) ); - Assert( ee->hasTerm( n2 ) ); - if( pol ){ - return n1==n2 || ee->areEqual( n1, n2 ); + if( n1==n2 ){ + return pol; }else{ - return n1!=n2 && ee->areDisequal( n1, n2, false ); + Assert( qy->getEngine()->hasTerm( n1 ) ); + Assert( qy->getEngine()->hasTerm( n2 ) ); + if( pol ){ + return qy->getEngine()->areEqual( n1, n2 ); + }else{ + return qy->getEngine()->areDisequal( n1, n2, false ); + } } } } - }else if( n.getKind()==APPLY_UF ){ - TNode n1 = evaluateTerm( n, subs, subsRep ); - if( !n1.isNull() ){ - eq::EqualityEngine * ee = d_quantEngine->getTheoryEngine()->getMasterEqualityEngine(); - Assert( ee->hasTerm( n1 ) ); - TNode n2 = pol ? d_true : d_false; - if( ee->hasTerm( n2 ) ){ - return ee->areEqual( n1, n2 ); - } - } }else if( n.getKind()==NOT ){ - return isEntailed( n[0], subs, subsRep, !pol ); + return isEntailed2( n[0], subs, subsRep, hasSubs, !pol, qy ); }else if( n.getKind()==OR || n.getKind()==AND ){ bool simPol = ( pol && n.getKind()==OR ) || ( !pol && n.getKind()==AND ); for( unsigned i=0; i<n.getNumChildren(); i++ ){ - if( isEntailed( n[i], subs, subsRep, pol ) ){ + if( isEntailed2( n[i], subs, subsRep, hasSubs, pol, qy ) ){ if( simPol ){ return true; } @@ -323,16 +418,45 @@ bool TermDb::isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep, return !simPol; }else if( n.getKind()==IFF || n.getKind()==ITE ){ for( unsigned i=0; i<2; i++ ){ - if( isEntailed( n[0], subs, subsRep, i==0 ) ){ + if( isEntailed2( n[0], subs, subsRep, hasSubs, i==0, qy ) ){ unsigned ch = ( n.getKind()==IFF || i==0 ) ? 1 : 2; bool reqPol = ( n.getKind()==ITE || i==0 ) ? pol : !pol; - return isEntailed( n[ch], subs, subsRep, reqPol ); + return isEntailed2( n[ch], subs, subsRep, hasSubs, reqPol, qy ); + } + } + }else if( n.getKind()==APPLY_UF ){ + TNode n1 = getEntailedTerm2( n, subs, subsRep, hasSubs, qy ); + if( !n1.isNull() ){ + Assert( qy->hasTerm( n1 ) ); + if( n1==d_true ){ + return pol; + }else if( n1==d_false ){ + return !pol; + }else{ + return qy->getEngine()->getRepresentative( n1 ) == ( pol ? d_true : d_false ); } } } return false; } +bool TermDb::isEntailed( TNode n, bool pol, EqualityQuery * qy ) { + if( qy==NULL ){ + Assert( d_consistent_ee ); + qy = d_quantEngine->getEqualityQuery(); + } + std::map< TNode, TNode > subs; + return isEntailed2( n, subs, false, false, pol, qy ); +} + +bool TermDb::isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool pol, EqualityQuery * qy ) { + if( qy==NULL ){ + Assert( d_consistent_ee ); + qy = d_quantEngine->getEqualityQuery(); + } + return isEntailed2( n, subs, subsRep, true, pol, qy ); +} + bool TermDb::hasTermCurrent( Node n, bool useMode ) { if( !useMode ){ return d_has_map.find( n )!=d_has_map.end(); @@ -431,7 +555,7 @@ void TermDb::presolve() { } } -void TermDb::reset( Theory::Effort effort ){ +bool TermDb::reset( Theory::Effort effort ){ int nonCongruentCount = 0; int congruentCount = 0; int alreadyCongruentCount = 0; @@ -440,6 +564,8 @@ void TermDb::reset( Theory::Effort effort ){ d_arg_reps.clear(); d_func_map_trie.clear(); d_func_map_eqc_trie.clear(); + d_func_map_rel_dom.clear(); + d_consistent_ee = true; eq::EqualityEngine* ee = d_quantEngine->getMasterEqualityEngine(); //compute has map @@ -480,7 +606,13 @@ void TermDb::reset( Theory::Effort effort ){ } } } - + //explicitly add inst closure terms to the equality engine to ensure only EE terms are indexed + for( std::hash_set< Node, NodeHashFunction >::iterator it = d_iclosure_processed.begin(); it !=d_iclosure_processed.end(); ++it ){ + Node n = *it; + if( !ee->hasTerm( n ) ){ + ee->addTerm( n ); + } + } //rebuild d_func/pred_map_trie for each operation, this will calculate all congruent terms for( std::map< Node, std::vector< Node > >::iterator it = d_op_map.begin(); it != d_op_map.end(); ++it ){ @@ -488,32 +620,58 @@ void TermDb::reset( Theory::Effort effort ){ Trace("term-db-debug") << "Adding terms for operator " << it->first << std::endl; for( unsigned i=0; i<it->second.size(); i++ ){ Node n = it->second[i]; - //to be added to term index, term must be relevant, and either exist in EE or be an inst closure term - if( hasTermCurrent( n ) && ( ee->hasTerm( n ) || d_iclosure_processed.find( n )!=d_iclosure_processed.end() ) ){ + //to be added to term index, term must be relevant, and exist in EE + if( hasTermCurrent( n ) && ee->hasTerm( n ) ){ if( !n.getAttribute(NoMatchAttribute()) ){ if( options::finiteModelFind() ){ computeModelBasisArgAttribute( n ); } computeArgReps( n ); - if( Trace.isOn("term-db-debug") ){ - Trace("term-db-debug") << "Adding term " << n << " with arg reps : "; - for( unsigned i=0; i<d_arg_reps[n].size(); i++ ){ - Trace("term-db-debug") << d_arg_reps[n] << " "; + Trace("term-db-debug") << "Adding term " << n << " with arg reps : "; + for( unsigned i=0; i<d_arg_reps[n].size(); i++ ){ + Trace("term-db-debug") << d_arg_reps[n][i] << " "; + if( std::find( d_func_map_rel_dom[it->first][i].begin(), + d_func_map_rel_dom[it->first][i].end(), d_arg_reps[n][i] ) == d_func_map_rel_dom[it->first][i].end() ){ + d_func_map_rel_dom[it->first][i].push_back( d_arg_reps[n][i] ); } - Trace("term-db-debug") << std::endl; } - - if( !d_func_map_trie[ it->first ].addTerm( n, d_arg_reps[n] ) ){ + Trace("term-db-debug") << std::endl; + if( ee->hasTerm( n ) ){ + Trace("term-db-debug") << " and value : " << ee->getRepresentative( n ) << std::endl; + } + Node at = d_func_map_trie[ it->first ].addOrGetTerm( n, d_arg_reps[n] ); + if( at!=n && ee->areEqual( at, n ) ){ NoMatchAttribute nma; n.setAttribute(nma,true); Trace("term-db-debug") << n << " is redundant." << std::endl; congruentCount++; }else{ + if( at!=n && ee->areDisequal( at, n, false ) ){ + std::vector< Node > lits; + lits.push_back( NodeManager::currentNM()->mkNode( at.getType().isBoolean() ? IFF : EQUAL, at, n ) ); + for( unsigned i=0; i<at.getNumChildren(); i++ ){ + if( at[i]!=n[i] ){ + lits.push_back( NodeManager::currentNM()->mkNode( at[i].getType().isBoolean() ? IFF : EQUAL, at[i], n[i] ).negate() ); + } + } + Node lem = lits.size()==1 ? lits[0] : NodeManager::currentNM()->mkNode( OR, lits ); + if( Trace.isOn("term-db-lemma") ){ + Trace("term-db-lemma") << "Disequal congruent terms : " << at << " " << n << "!!!!" << std::endl; + if( !d_quantEngine->getTheoryEngine()->needCheck() ){ + Trace("term-db-lemma") << " all theories passed with no lemmas." << std::endl; + } + Trace("term-db-lemma") << " add lemma : " << lem << std::endl; + } + d_quantEngine->addLemma( lem ); + d_consistent_ee = false; + return false; + } nonCongruentCount++; d_op_nonred_count[ it->first ]++; } }else{ + Trace("term-db-debug") << n << " is already redundant." << std::endl; congruentCount++; alreadyCongruentCount++; } @@ -526,15 +684,16 @@ void TermDb::reset( Theory::Effort effort ){ Trace("term-db-stats") << "TermDb: Reset" << std::endl; Trace("term-db-stats") << "Non-Congruent/Congruent/Non-Relevant = "; Trace("term-db-stats") << nonCongruentCount << " / " << congruentCount << " (" << alreadyCongruentCount << ") / " << nonRelevantCount << std::endl; - if( Debug.isOn("term-db") ){ - Debug("term-db") << "functions : " << std::endl; + if( Trace.isOn("term-db-index") ){ + Trace("term-db-index") << "functions : " << std::endl; for( std::map< Node, std::vector< Node > >::iterator it = d_op_map.begin(); it != d_op_map.end(); ++it ){ if( it->second.size()>0 ){ - Debug("term-db") << "- " << it->first << std::endl; - d_func_map_trie[ it->first ].debugPrint("term-db", it->second[0]); + Trace("term-db-index") << "- " << it->first << std::endl; + d_func_map_trie[ it->first ].debugPrint("term-db-index", it->second[0]); } } } + return true; } TermArgTrie * TermDb::getTermArgTrie( Node f ) { @@ -565,11 +724,15 @@ TermArgTrie * TermDb::getTermArgTrie( Node eqc, Node f ) { } } -TNode TermDb::existsTerm( Node f, Node n ) { +TNode TermDb::getCongruentTerm( Node f, Node n ) { computeArgReps( n ); return d_func_map_trie[f].existsTerm( d_arg_reps[n] ); } +TNode TermDb::getCongruentTerm( Node f, std::vector< TNode >& args ) { + return d_func_map_trie[f].existsTerm( args ); +} + Node TermDb::getModelBasisTerm( TypeNode tn, int i ){ if( d_model_basis_term.find( tn )==d_model_basis_term.end() ){ Node mbt; @@ -800,10 +963,10 @@ Node TermDb::getInstantiationConstant( Node q, int i ) const { } /** get number of instantiation constants for q */ -int TermDb::getNumInstantiationConstants( Node q ) const { +unsigned TermDb::getNumInstantiationConstants( Node q ) const { std::map< Node, std::vector< Node > >::const_iterator it = d_inst_constants.find( q ); if( it!=d_inst_constants.end() ){ - return (int)it->second.size(); + return it->second.size(); }else{ return 0; } @@ -853,14 +1016,29 @@ Node TermDb::getInstantiatedNode( Node n, Node q, std::vector< Node >& terms ) { } -void getSelfSel( const DatatypeConstructor& dc, Node n, TypeNode ntn, std::vector< Node >& selfSel ){ +void getSelfSel( const Datatype& dt, const DatatypeConstructor& dc, Node n, TypeNode ntn, std::vector< Node >& selfSel ){ + TypeNode tspec; + if( dt.isParametric() ){ + tspec = TypeNode::fromType( dc.getSpecializedConstructorType(n.getType().toType()) ); + Trace("sk-ind-debug") << "Specialized constructor type : " << tspec << std::endl; + Assert( tspec.getNumChildren()==dc.getNumArgs() ); + } + Trace("sk-ind-debug") << "Check self sel " << dc.getName() << " " << dt.getName() << std::endl; for( unsigned j=0; j<dc.getNumArgs(); j++ ){ - TypeNode tn = TypeNode::fromType( ((SelectorType)dc[j].getSelector().getType()).getRangeType() ); std::vector< Node > ssc; - if( tn==ntn ){ - ssc.push_back( n ); + if( dt.isParametric() ){ + Trace("sk-ind-debug") << "Compare " << tspec[j] << " " << ntn << std::endl; + if( tspec[j]==ntn ){ + ssc.push_back( n ); + } + }else{ + TypeNode tn = TypeNode::fromType( dc[j].getRangeType() ); + Trace("sk-ind-debug") << "Compare " << tn << " " << ntn << std::endl; + if( tn==ntn ){ + ssc.push_back( n ); + } } - /* TODO + /* TODO: more than weak structural induction else if( datatypes::DatatypesRewriter::isTypeDatatype( tn ) && std::find( visited.begin(), visited.end(), tn )==visited.end() ){ visited.push_back( tn ); const Datatype& dt = ((DatatypeType)(subs[0].getType()).toType()).getDatatype(); @@ -938,7 +1116,7 @@ Node TermDb::mkSkolemizedBody( Node f, Node n, std::vector< TypeNode >& argTypes std::vector< Node > disj; for( unsigned i=0; i<dt.getNumConstructors(); i++ ){ std::vector< Node > selfSel; - getSelfSel( dt[i], k, tn, selfSel ); + getSelfSel( dt, dt[i], k, tn, selfSel ); std::vector< Node > conj; conj.push_back( NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[i].getTester() ), k ).negate() ); for( unsigned j=0; j<selfSel.size(); j++ ){ @@ -1050,7 +1228,7 @@ bool TermDb::isClosedEnumerableType( TypeNode tn ) { const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype(); for( unsigned i=0; i<dt.getNumConstructors(); i++ ){ for( unsigned j=0; j<dt[i].getNumArgs(); j++ ){ - TypeNode ctn = TypeNode::fromType( ((SelectorType)dt[i][j].getSelector().getType()).getRangeType() ); + TypeNode ctn = TypeNode::fromType( dt[i][j].getRangeType() ); if( tn!=ctn && !isClosedEnumerableType( ctn ) ){ ret = false; break; @@ -1585,7 +1763,7 @@ bool TermDb::containsVtsInfinity( Node n, bool isFree ) { return containsTerms( n, t ); } -Node TermDb::mkNodeType( Node n, TypeNode tn ) { +Node TermDb::ensureType( Node n, TypeNode tn ) { TypeNode ntn = n.getType(); Assert( ntn.isComparableTo( tn ) ); if( ntn.isSubtypeOf( tn ) ){ @@ -1598,6 +1776,20 @@ Node TermDb::mkNodeType( Node n, TypeNode tn ) { } } +bool TermDb::getEnsureTypeCondition( Node n, TypeNode tn, std::vector< Node >& cond ) { + TypeNode ntn = n.getType(); + Assert( ntn.isComparableTo( tn ) ); + if( !ntn.isSubtypeOf( tn ) ){ + if( tn.isInteger() ){ + cond.push_back( NodeManager::currentNM()->mkNode( IS_INTEGER, n ) ); + return true; + } + return false; + }else{ + return true; + } +} + bool TermDb::containsTerm2( Node n, Node t, std::map< Node, bool >& visited ) { if( n==t ){ return true; @@ -1630,20 +1822,6 @@ bool TermDb::containsTerms2( Node n, std::vector< Node >& t, std::map< Node, boo return false; } -bool TermDb::containsUninterpretedConstant2( Node n, std::map< Node, bool >& visited ) { - if( n.getKind()==UNINTERPRETED_CONSTANT ){ - return true; - }else if( visited.find( n )==visited.end() ){ - visited[n] = true; - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - if( containsUninterpretedConstant2( n[i], visited ) ){ - return true; - } - } - } - return false; -} - bool TermDb::containsTerm( Node n, Node t ) { std::map< Node, bool > visited; return containsTerm2( n, t, visited ); @@ -1658,9 +1836,38 @@ bool TermDb::containsTerms( Node n, std::vector< Node >& t ) { } } +int TermDb::getTermDepth( Node n ) { + if (!n.hasAttribute(TermDepthAttribute()) ){ + int maxDepth = -1; + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + int depth = getTermDepth( n[i] ); + if( depth>maxDepth ){ + maxDepth = depth; + } + } + TermDepthAttribute tda; + n.setAttribute(tda,1+maxDepth); + } + return n.getAttribute(TermDepthAttribute()); +} + bool TermDb::containsUninterpretedConstant( Node n ) { - std::map< Node, bool > visited; - return containsUninterpretedConstant2( n, visited ); + if (!n.hasAttribute(ContainsUConstAttribute()) ){ + bool ret = false; + if( n.getKind()==UNINTERPRETED_CONSTANT ){ + ret = true; + }else{ + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + if( containsUninterpretedConstant( n[i] ) ){ + ret = true; + break; + } + } + } + ContainsUConstAttribute cuca; + n.setAttribute(cuca, ret ? 1 : 0); + } + return n.getAttribute(ContainsUConstAttribute())!=0; } Node TermDb::simpleNegate( Node n ){ @@ -1787,69 +1994,109 @@ bool TermDb::isSygusConjectureAnnotation( Node ipl ){ return false; } +bool TermDb::isQuantElimAnnotation( Node ipl ) { + if( !ipl.isNull() ){ + for( unsigned i=0; i<ipl.getNumChildren(); i++ ){ + if( ipl[i].getKind()==INST_ATTRIBUTE ){ + Node avar = ipl[i][0]; + if( avar.getAttribute(QuantElimAttribute()) ){ + return true; + } + } + } + } + return false; +} + void TermDb::computeAttributes( Node q ) { + computeQuantAttributes( q, d_qattr[q] ); + if( !d_qattr[q].d_rr.isNull() ){ + if( d_quantEngine->getRewriteEngine()==NULL ){ + Trace("quant-warn") << "WARNING : rewrite engine is null, and we have : " << q << std::endl; + } + //set rewrite engine as owner + d_quantEngine->setOwner( q, d_quantEngine->getRewriteEngine(), 2 ); + } + if( d_qattr[q].isFunDef() ){ + Node f = d_qattr[q].d_fundef_f; + if( d_fun_defs.find( f )!=d_fun_defs.end() ){ + Message() << "Cannot define function " << f << " more than once." << std::endl; + exit( 1 ); + } + d_fun_defs[f] = true; + d_quantEngine->setOwner( q, d_quantEngine->getFunDefEngine(), 2 ); + } + if( d_qattr[q].d_sygus ){ + if( d_quantEngine->getCegInstantiation()==NULL ){ + Trace("quant-warn") << "WARNING : ceg instantiation is null, and we have : " << q << std::endl; + } + d_quantEngine->setOwner( q, d_quantEngine->getCegInstantiation(), 2 ); + } + if( d_qattr[q].d_synthesis ){ + if( d_quantEngine->getCegInstantiation()==NULL ){ + Trace("quant-warn") << "WARNING : ceg instantiation is null, and we have : " << q << std::endl; + } + d_quantEngine->setOwner( q, d_quantEngine->getCegInstantiation(), 2 ); + } +} + +void TermDb::computeQuantAttributes( Node q, QAttributes& qa ){ Trace("quant-attr-debug") << "Compute attributes for " << q << std::endl; if( q.getNumChildren()==3 ){ + qa.d_ipl = q[2]; for( unsigned i=0; i<q[2].getNumChildren(); i++ ){ Trace("quant-attr-debug") << "Check : " << q[2][i] << " " << q[2][i].getKind() << std::endl; - if( q[2][i].getKind()==INST_ATTRIBUTE ){ + if( q[2][i].getKind()==INST_PATTERN || q[2][i].getKind()==INST_NO_PATTERN ){ + qa.d_hasPattern = true; + }else if( q[2][i].getKind()==INST_ATTRIBUTE ){ Node avar = q[2][i][0]; if( avar.getAttribute(AxiomAttribute()) ){ Trace("quant-attr") << "Attribute : axiom : " << q << std::endl; - d_qattr_axiom[q] = true; + qa.d_axiom = true; } if( avar.getAttribute(ConjectureAttribute()) ){ Trace("quant-attr") << "Attribute : conjecture : " << q << std::endl; - d_qattr_conjecture[q] = true; + qa.d_conjecture = true; } if( avar.getAttribute(FunDefAttribute()) ){ Trace("quant-attr") << "Attribute : function definition : " << q << std::endl; - d_qattr_fundef[q] = true; //get operator directly from pattern - Node f = q[2][i][0].getOperator(); - if( d_fun_defs.find( f )!=d_fun_defs.end() ){ - Message() << "Cannot define function " << f << " more than once." << std::endl; - exit( 0 ); - } - d_fun_defs[f] = true; - d_quantEngine->setOwner( q, d_quantEngine->getFunDefEngine() ); + qa.d_fundef_f = q[2][i][0].getOperator(); } if( avar.getAttribute(SygusAttribute()) ){ //not necessarily nested existential //Assert( q[1].getKind()==NOT ); //Assert( q[1][0].getKind()==FORALL ); - Trace("quant-attr") << "Attribute : sygus : " << q << std::endl; - d_qattr_sygus[q] = true; - if( d_quantEngine->getCegInstantiation()==NULL ){ - Trace("quant-warn") << "WARNING : ceg instantiation is null, and we have : " << q << std::endl; - } - d_quantEngine->setOwner( q, d_quantEngine->getCegInstantiation() ); + qa.d_sygus = true; } if( avar.getAttribute(SynthesisAttribute()) ){ Trace("quant-attr") << "Attribute : synthesis : " << q << std::endl; - d_qattr_synthesis[q] = true; - if( d_quantEngine->getCegInstantiation()==NULL ){ - Trace("quant-warn") << "WARNING : ceg instantiation is null, and we have : " << q << std::endl; - } - d_quantEngine->setOwner( q, d_quantEngine->getCegInstantiation() ); + qa.d_synthesis = true; } if( avar.hasAttribute(QuantInstLevelAttribute()) ){ - d_qattr_qinstLevel[q] = avar.getAttribute(QuantInstLevelAttribute()); - Trace("quant-attr") << "Attribute : quant inst level " << d_qattr_qinstLevel[q] << " : " << q << std::endl; + qa.d_qinstLevel = avar.getAttribute(QuantInstLevelAttribute()); + Trace("quant-attr") << "Attribute : quant inst level " << qa.d_qinstLevel << " : " << q << std::endl; } if( avar.hasAttribute(RrPriorityAttribute()) ){ - d_qattr_rr_priority[q] = avar.getAttribute(RrPriorityAttribute()); - Trace("quant-attr") << "Attribute : rr priority " << d_qattr_rr_priority[q] << " : " << q << std::endl; + qa.d_rr_priority = avar.getAttribute(RrPriorityAttribute()); + Trace("quant-attr") << "Attribute : rr priority " << qa.d_rr_priority << " : " << q << std::endl; + } + if( avar.getAttribute(QuantElimAttribute()) ){ + Trace("quant-attr") << "Attribute : quantifier elimination : " << q << std::endl; + qa.d_quant_elim = true; + //don't set owner, should happen naturally + } + if( avar.getAttribute(QuantElimPartialAttribute()) ){ + Trace("quant-attr") << "Attribute : quantifier elimination partial : " << q << std::endl; + qa.d_quant_elim = true; + qa.d_quant_elim_partial = true; + //don't set owner, should happen naturally } if( avar.getKind()==REWRITE_RULE ){ Trace("quant-attr") << "Attribute : rewrite rule : " << q << std::endl; Assert( i==0 ); - if( d_quantEngine->getRewriteEngine()==NULL ){ - Trace("quant-warn") << "WARNING : rewrite engine is null, and we have : " << q << std::endl; - } - //set rewrite engine as owner - d_quantEngine->setOwner( q, d_quantEngine->getRewriteEngine() ); + qa.d_rr = avar; } } } @@ -1857,69 +2104,85 @@ void TermDb::computeAttributes( Node q ) { } bool TermDb::isQAttrConjecture( Node q ) { - std::map< Node, bool >::iterator it = d_qattr_conjecture.find( q ); - if( it==d_qattr_conjecture.end() ){ + std::map< Node, QAttributes >::iterator it = d_qattr.find( q ); + if( it==d_qattr.end() ){ return false; }else{ - return it->second; + return it->second.d_conjecture; } } bool TermDb::isQAttrAxiom( Node q ) { - std::map< Node, bool >::iterator it = d_qattr_axiom.find( q ); - if( it==d_qattr_axiom.end() ){ + std::map< Node, QAttributes >::iterator it = d_qattr.find( q ); + if( it==d_qattr.end() ){ return false; }else{ - return it->second; + return it->second.d_axiom; } } bool TermDb::isQAttrFunDef( Node q ) { - std::map< Node, bool >::iterator it = d_qattr_fundef.find( q ); - if( it==d_qattr_fundef.end() ){ + std::map< Node, QAttributes >::iterator it = d_qattr.find( q ); + if( it==d_qattr.end() ){ return false; }else{ - return it->second; + return it->second.isFunDef(); } } bool TermDb::isQAttrSygus( Node q ) { - std::map< Node, bool >::iterator it = d_qattr_sygus.find( q ); - if( it==d_qattr_sygus.end() ){ + std::map< Node, QAttributes >::iterator it = d_qattr.find( q ); + if( it==d_qattr.end() ){ return false; }else{ - return it->second; + return it->second.d_sygus; } } bool TermDb::isQAttrSynthesis( Node q ) { - std::map< Node, bool >::iterator it = d_qattr_synthesis.find( q ); - if( it==d_qattr_synthesis.end() ){ + std::map< Node, QAttributes >::iterator it = d_qattr.find( q ); + if( it==d_qattr.end() ){ return false; }else{ - return it->second; + return it->second.d_synthesis; } } int TermDb::getQAttrQuantInstLevel( Node q ) { - std::map< Node, int >::iterator it = d_qattr_qinstLevel.find( q ); - if( it==d_qattr_qinstLevel.end() ){ + std::map< Node, QAttributes >::iterator it = d_qattr.find( q ); + if( it==d_qattr.end() ){ return -1; }else{ - return it->second; + return it->second.d_qinstLevel; } } int TermDb::getQAttrRewriteRulePriority( Node q ) { - std::map< Node, int >::iterator it = d_qattr_rr_priority.find( q ); - if( it==d_qattr_rr_priority.end() ){ + std::map< Node, QAttributes >::iterator it = d_qattr.find( q ); + if( it==d_qattr.end() ){ return -1; }else{ - return it->second; + return it->second.d_rr_priority; } } +bool TermDb::isQAttrQuantElim( Node q ) { + std::map< Node, QAttributes >::iterator it = d_qattr.find( q ); + if( it==d_qattr.end() ){ + return false; + }else{ + return it->second.d_quant_elim; + } +} +bool TermDb::isQAttrQuantElimPartial( Node q ) { + std::map< Node, QAttributes >::iterator it = d_qattr.find( q ); + if( it==d_qattr.end() ){ + return false; + }else{ + return it->second.d_quant_elim_partial; + } +} TermDbSygus::TermDbSygus(){ d_true = NodeManager::currentNM()->mkConst( true ); diff --git a/src/theory/quantifiers/term_database.h b/src/theory/quantifiers/term_database.h index 0c4e94517..a62b343a2 100644 --- a/src/theory/quantifiers/term_database.h +++ b/src/theory/quantifiers/term_database.h @@ -1,13 +1,13 @@ /********************* */ /*! \file term_database.h ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: Morgan Deters - ** Minor contributors (to current version): Tim King + ** Top contributors (to current version): + ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief term database class **/ @@ -20,6 +20,7 @@ #include "expr/attribute.h" #include "theory/theory.h" #include "theory/type_enumerator.h" +#include "theory/quantifiers/quant_util.h" #include <map> @@ -68,6 +69,12 @@ typedef expr::Attribute<InstLevelAttributeId, uint64_t> InstLevelAttribute; struct InstVarNumAttributeId {}; typedef expr::Attribute<InstVarNumAttributeId, uint64_t> InstVarNumAttribute; +struct TermDepthAttributeId {}; +typedef expr::Attribute<TermDepthAttributeId, uint64_t> TermDepthAttribute; + +struct ContainsUConstAttributeId {}; +typedef expr::Attribute<ContainsUConstAttributeId, uint64_t> ContainsUConstAttribute; + struct ModelBasisAttributeId {}; typedef expr::Attribute<ModelBasisAttributeId, bool> ModelBasisAttribute; //for APPLY_UF terms, 1 : term has direct child with model basis attribute, @@ -99,6 +106,14 @@ typedef expr::Attribute<SygusProxyAttributeId, Node> SygusProxyAttribute; struct AbsTypeFunDefAttributeId {}; typedef expr::Attribute<AbsTypeFunDefAttributeId, bool> AbsTypeFunDefAttribute; +/** Attribute true for quantifiers that we are doing quantifier elimination on */ +struct QuantElimAttributeId {}; +typedef expr::Attribute< QuantElimAttributeId, bool > QuantElimAttribute; + +/** Attribute true for quantifiers that we are doing partial quantifier elimination on */ +struct QuantElimPartialAttributeId {}; +typedef expr::Attribute< QuantElimPartialAttributeId, bool > QuantElimPartialAttribute; + class QuantifiersEngine; namespace inst{ @@ -112,23 +127,57 @@ public: /** the data */ std::map< TNode, TermArgTrie > d_data; public: + bool hasNodeData() { return !d_data.empty(); } + TNode getNodeData() { return d_data.begin()->first; } TNode existsTerm( std::vector< TNode >& reps, int argIndex = 0 ); + TNode addOrGetTerm( TNode n, std::vector< TNode >& reps, int argIndex = 0 ); bool addTerm( TNode n, std::vector< TNode >& reps, int argIndex = 0 ); void debugPrint( const char * c, Node n, unsigned depth = 0 ); void clear() { d_data.clear(); } };/* class TermArgTrie */ +class QAttributes{ +public: + QAttributes() : d_hasPattern(false), d_conjecture(false), d_axiom(false), d_sygus(false), + d_synthesis(false), d_rr_priority(-1), d_qinstLevel(-1), d_quant_elim(false), d_quant_elim_partial(false){} + ~QAttributes(){} + bool d_hasPattern; + Node d_rr; + bool d_conjecture; + bool d_axiom; + Node d_fundef_f; + bool d_sygus; + bool d_synthesis; + int d_rr_priority; + int d_qinstLevel; + bool d_quant_elim; + bool d_quant_elim_partial; + Node d_ipl; + bool isRewriteRule() { return !d_rr.isNull(); } + bool isFunDef() { return !d_fundef_f.isNull(); } +}; + namespace fmcheck { class FullModelChecker; } class TermDbSygus; +class QuantConflictFind; +class RelevantDomain; +class ConjectureGenerator; +class TermGenerator; +class TermGenEnv; -class TermDb { +class TermDb : public QuantifiersUtil { friend class ::CVC4::theory::QuantifiersEngine; + //TODO: eliminate most of these friend class ::CVC4::theory::inst::Trigger; friend class ::CVC4::theory::quantifiers::fmcheck::FullModelChecker; + friend class ::CVC4::theory::quantifiers::QuantConflictFind; + friend class ::CVC4::theory::quantifiers::RelevantDomain; + friend class ::CVC4::theory::quantifiers::ConjectureGenerator; + friend class ::CVC4::theory::quantifiers::TermGenEnv; typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap; private: /** reference to the quantifiers engine */ @@ -139,8 +188,8 @@ private: std::hash_set< Node, NodeHashFunction > d_iclosure_processed; /** select op map */ std::map< Node, std::map< TypeNode, Node > > d_par_op_map; - /** set has term */ - void setHasTerm( Node n ); + /** whether master equality engine is UF-inconsistent */ + bool d_consistent_ee; public: TermDb( context::Context* c, context::UserContext* u, QuantifiersEngine* qe ); ~TermDb(){} @@ -150,13 +199,19 @@ public: /** constants */ Node d_zero; Node d_one; - +public: + /** presolve (called once per user check-sat) */ + void presolve(); + /** reset (calculate which terms are active) */ + bool reset( Theory::Effort effort ); + /** identify */ + std::string identify() const { return "TermDb"; } +private: /** map from operators to ground terms for that operator */ std::map< Node, std::vector< Node > > d_op_map; /** map from type nodes to terms of that type */ std::map< TypeNode, std::vector< Node > > d_type_map; - /** count number of non-redundant ground terms per operator */ std::map< Node, int > d_op_nonred_count; /**mapping from UF terms to representatives of their arguments */ @@ -164,41 +219,53 @@ public: /** map from operators to trie */ std::map< Node, TermArgTrie > d_func_map_trie; std::map< Node, TermArgTrie > d_func_map_eqc_trie; + /** mapping from operators to their representative relevant domains */ + std::map< Node, std::map< unsigned, std::vector< Node > > > d_func_map_rel_dom; /** has map */ std::map< Node, bool > d_has_map; /** map from reps to a term in eqc in d_has_map */ - std::map< Node, Node > d_term_elig_eqc; - + std::map< Node, Node > d_term_elig_eqc; + /** set has term */ + void setHasTerm( Node n ); + /** evaluate term */ + Node evaluateTerm2( TNode n, std::map< TNode, Node >& visited, EqualityQuery * qy ); + TNode getEntailedTerm2( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool hasSubs, EqualityQuery * qy ); + bool isEntailed2( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool hasSubs, bool pol, EqualityQuery * qy ); public: /** ground terms for operator */ unsigned getNumGroundTerms( Node f ); /** get ground term for operator */ Node getGroundTerm( Node f, unsigned i ); + /** get num type terms */ + unsigned getNumTypeGroundTerms( TypeNode tn ); + /** get type ground term */ + Node getTypeGroundTerm( TypeNode tn, unsigned i ); /** add a term to the database */ void addTerm( Node n, std::set< Node >& added, bool withinQuant = false, bool withinInstClosure = false ); - /** presolve (called once per user check-sat) */ - void presolve(); - /** reset (calculate which terms are active) */ - void reset( Theory::Effort effort ); - /** get operator*/ - Node getOperator( Node n ); + /** get match operator */ + Node getMatchOperator( Node n ); /** get term arg index */ TermArgTrie * getTermArgTrie( Node f ); TermArgTrie * getTermArgTrie( Node eqc, Node f ); /** exists term */ - TNode existsTerm( Node f, Node n ); + TNode getCongruentTerm( Node f, Node n ); + TNode getCongruentTerm( Node f, std::vector< TNode >& args ); /** compute arg reps */ void computeArgReps( TNode n ); /** compute uf eqc terms */ void computeUfEqcTerms( TNode f ); + /** in relevant domain */ + bool inRelevantDomain( TNode f, unsigned i, TNode r ); /** evaluate a term under a substitution. Return representative in EE if possible. * subsRep is whether subs contains only representatives */ - TNode evaluateTerm( TNode n, std::map< TNode, TNode >& subs, bool subsRep ); - /** same as above, but without substitution */ - TNode evaluateTerm( TNode n ); + Node evaluateTerm( TNode n, EqualityQuery * qy = NULL ); + /** get entailed term, does not construct new terms, less aggressive */ + TNode getEntailedTerm( TNode n, EqualityQuery * qy = NULL ); + TNode getEntailedTerm( TNode n, std::map< TNode, TNode >& subs, bool subsRep, EqualityQuery * qy = NULL ); /** is entailed (incomplete check) */ - bool isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool pol ); + bool isEntailed( TNode n, bool pol, EqualityQuery * qy = NULL ); + bool isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool pol, EqualityQuery * qy = NULL ); /** has term */ bool hasTermCurrent( Node n, bool useMode = true ); /** is term eligble for instantiation? */ @@ -248,7 +315,7 @@ public: /** get the i^th instantiation constant of q */ Node getInstantiationConstant( Node q, int i ) const; /** get number of instantiation constants for q */ - int getNumInstantiationConstants( Node q ) const; + unsigned getNumInstantiationConstants( Node q ) const; /** get the ce body q[e/x] */ Node getInstConstantBody( Node q ); /** get counterexample literal (for cbqi) */ @@ -318,26 +385,26 @@ public: //for triggers private: /** helper function for compute var contains */ - void computeVarContains2( Node n, std::vector< Node >& varContains, std::map< Node, bool >& visited ); + static void computeVarContains2( Node n, std::vector< Node >& varContains, std::map< Node, bool >& visited ); /** triggers for each operator */ std::map< Node, std::vector< inst::Trigger* > > d_op_triggers; /** helper for is instance of */ - bool isUnifiableInstanceOf( Node n1, Node n2, std::map< Node, Node >& subs ); + static bool isUnifiableInstanceOf( Node n1, Node n2, std::map< Node, Node >& subs ); /** -1: n1 is an instance of n2, 1: n1 is an instance of n2 */ - int isInstanceOf2( Node n1, Node n2, std::vector< Node >& varContains1, std::vector< Node >& varContains2 ); + static int isInstanceOf2( Node n1, Node n2, std::vector< Node >& varContains1, std::vector< Node >& varContains2 ); public: /** compute var contains */ - void computeVarContains( Node n, std::vector< Node >& varContains ); + static void computeVarContains( Node n, std::vector< Node >& varContains ); /** get var contains for each of the patterns in pats */ - void getVarContains( Node f, std::vector< Node >& pats, std::map< Node, std::vector< Node > >& varContains ); + static void getVarContains( Node f, std::vector< Node >& pats, std::map< Node, std::vector< Node > >& varContains ); /** get var contains for node n */ - void getVarContainsNode( Node f, Node n, std::vector< Node >& varContains ); - /** register trigger (for eager quantifier instantiation) */ - void registerTrigger( inst::Trigger* tr, Node op ); + static void getVarContainsNode( Node f, Node n, std::vector< Node >& varContains ); /** -1: n1 is an instance of n2, 1: n1 is an instance of n2 */ - int isInstanceOf( Node n1, Node n2 ); + static int isInstanceOf( Node n1, Node n2 ); /** filter all nodes that have instances */ - void filterInstances( std::vector< Node >& nodes ); + static void filterInstances( std::vector< Node >& nodes ); + /** register trigger (for eager quantifier instantiation) */ + void registerTrigger( inst::Trigger* tr, Node op ); //for term ordering private: @@ -390,14 +457,14 @@ public: bool containsVtsTerm( std::vector< Node >& n, bool isFree = false ); /** simple check for contains term */ bool containsVtsInfinity( Node n, bool isFree = false ); - /** make type */ - static Node mkNodeType( Node n, TypeNode tn ); - + /** ensure type */ + static Node ensureType( Node n, TypeNode tn ); + /** get ensure type condition */ + static bool getEnsureTypeCondition( Node n, TypeNode tn, std::vector< Node >& cond ); private: //helper for contains term static bool containsTerm2( Node n, Node t, std::map< Node, bool >& visited ); static bool containsTerms2( Node n, std::vector< Node >& t, std::map< Node, bool >& visited ); - static bool containsUninterpretedConstant2( Node n, std::map< Node, bool >& visited ); //general utilities public: /** simple check for whether n contains t as subterm */ @@ -406,6 +473,8 @@ public: static bool containsTerms( Node n, std::vector< Node >& t ); /** contains uninterpreted constant */ static bool containsUninterpretedConstant( Node n ); + /** get the term depth of n */ + static int getTermDepth( Node n ); /** simple negate */ static Node simpleNegate( Node n ); /** is assoc */ @@ -440,15 +509,11 @@ public: //general queries concerning quantified formulas wrt modules static Node getFunDefHead( Node q ); /** get fun def body */ static Node getFunDefBody( Node q ); + /** is quant elim annotation */ + static bool isQuantElimAnnotation( Node ipl ); //attributes private: - std::map< Node, bool > d_qattr_conjecture; - std::map< Node, bool > d_qattr_axiom; - std::map< Node, bool > d_qattr_fundef; - std::map< Node, bool > d_qattr_sygus; - std::map< Node, bool > d_qattr_synthesis; - std::map< Node, int > d_qattr_rr_priority; - std::map< Node, int > d_qattr_qinstLevel; + std::map< Node, QAttributes > d_qattr; //record attributes void computeAttributes( Node q ); public: @@ -466,7 +531,12 @@ public: int getQAttrQuantInstLevel( Node q ); /** get rewrite rule priority */ int getQAttrRewriteRulePriority( Node q ); - + /** is quant elim */ + bool isQAttrQuantElim( Node q ); + /** is quant elim partial */ + bool isQAttrQuantElimPartial( Node q ); + /** compute quantifier attributes */ + static void computeQuantAttributes( Node q, QAttributes& qa ); };/* class TermDb */ class TermDbSygus { diff --git a/src/theory/quantifiers/theory_quantifiers.cpp b/src/theory/quantifiers/theory_quantifiers.cpp index 86fc057ea..efe40aaa8 100644 --- a/src/theory/quantifiers/theory_quantifiers.cpp +++ b/src/theory/quantifiers/theory_quantifiers.cpp @@ -1,13 +1,13 @@ /********************* */ /*! \file theory_quantifiers.cpp ** \verbatim - ** Original author: Morgan Deters - ** Major contributors: Andrew Reynolds - ** Minor contributors (to current version): Dejan Jovanovic + ** Top contributors (to current version): + ** Morgan Deters, Andrew Reynolds, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Implementation of the theory of quantifiers ** @@ -47,6 +47,8 @@ TheoryQuantifiers::TheoryQuantifiers(Context* c, context::UserContext* u, Output out.handleUserAttribute( "synthesis", this ); out.handleUserAttribute( "quant-inst-max-level", this ); out.handleUserAttribute( "rr-priority", this ); + out.handleUserAttribute( "quant-elim", this ); + out.handleUserAttribute( "quant-elim-partial", this ); } TheoryQuantifiers::~TheoryQuantifiers() { diff --git a/src/theory/quantifiers/theory_quantifiers.h b/src/theory/quantifiers/theory_quantifiers.h index 6335349b1..6775e0536 100644 --- a/src/theory/quantifiers/theory_quantifiers.h +++ b/src/theory/quantifiers/theory_quantifiers.h @@ -1,13 +1,13 @@ /********************* */ /*! \file theory_quantifiers.h ** \verbatim - ** Original author: Morgan Deters - ** Major contributors: none - ** Minor contributors (to current version): Francois Bobot, Dejan Jovanovic, Andrew Reynolds + ** Top contributors (to current version): + ** Morgan Deters, Tim King, Andrew Reynolds ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Theory of quantifiers. ** diff --git a/src/theory/quantifiers/theory_quantifiers_type_rules.h b/src/theory/quantifiers/theory_quantifiers_type_rules.h index 1fb8ddaf9..6ba57afb4 100644 --- a/src/theory/quantifiers/theory_quantifiers_type_rules.h +++ b/src/theory/quantifiers/theory_quantifiers_type_rules.h @@ -1,13 +1,13 @@ /********************* */ /*! \file theory_quantifiers_type_rules.h ** \verbatim - ** Original author: Morgan Deters - ** Major contributors: Andrew Reynolds - ** Minor contributors (to current version): none + ** Top contributors (to current version): + ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Theory of quantifiers ** diff --git a/src/theory/quantifiers/trigger.cpp b/src/theory/quantifiers/trigger.cpp index 9aee18317..38635b37b 100644 --- a/src/theory/quantifiers/trigger.cpp +++ b/src/theory/quantifiers/trigger.cpp @@ -1,60 +1,67 @@ /********************* */ /*! \file trigger.cpp ** \verbatim - ** Original author: Morgan Deters - ** Major contributors: Andrew Reynolds - ** Minor contributors (to current version): Francois Bobot, Kshitij Bansal + ** Top contributors (to current version): + ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief Implementation of trigger class **/ #include "theory/quantifiers/trigger.h" - -#include "options/quantifiers_options.h" #include "theory/quantifiers/candidate_generator.h" #include "theory/quantifiers/inst_match_generator.h" #include "theory/quantifiers/term_database.h" #include "theory/quantifiers_engine.h" #include "theory/theory_engine.h" #include "theory/uf/equality_engine.h" +#include "util/hash.h" + using namespace std; -using namespace CVC4; using namespace CVC4::kind; using namespace CVC4::context; -using namespace CVC4::theory; -using namespace CVC4::theory::inst; + +namespace CVC4 { +namespace theory { +namespace inst { + +void TriggerTermInfo::init( Node q, Node n, int reqPol, Node reqPolEq ){ + if( d_fv.empty() ){ + quantifiers::TermDb::getVarContainsNode( q, n, d_fv ); + } + if( d_reqPol==0 ){ + d_reqPol = reqPol; + d_reqPolEq = reqPolEq; + }else{ + //determined a ground (dis)equality must hold or else q is a tautology? + } +} /** trigger class constructor */ -Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool smartTriggers ) : -d_quantEngine( qe ), d_f( f ){ +Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption ) + : 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++ ){ + for( unsigned i=0; i<d_nodes.size(); i++ ){ Trace("trigger") << " " << d_nodes[i] << std::endl; } - Trace("trigger-debug") << ", smart triggers = " << smartTriggers; - Trace("trigger") << 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 = InstMatchGenerator::mkInstMatchGenerator( f, d_nodes[0], qe ); - d_mg->setActiveAdd(true); - } + if( d_nodes.size()==1 ){ + if( isSimpleTrigger( d_nodes[0] ) ){ + d_mg = new InstMatchGeneratorSimple( f, d_nodes[0] ); }else{ - d_mg = new InstMatchGeneratorMulti( f, d_nodes, qe ); - //d_mg = InstMatchGenerator::mkInstMatchGenerator( d_nodes, qe ); - //d_mg->setActiveAdd(); + d_mg = InstMatchGenerator::mkInstMatchGenerator( f, d_nodes[0], qe ); + d_mg->setActiveAdd(true); } }else{ - d_mg = InstMatchGenerator::mkInstMatchGenerator( f, d_nodes, qe ); - d_mg->setActiveAdd(true); + d_mg = new InstMatchGeneratorMulti( f, d_nodes, qe ); + //d_mg = InstMatchGenerator::mkInstMatchGenerator( d_nodes, qe ); + //d_mg->setActiveAdd(); } if( d_nodes.size()==1 ){ if( isSimpleTrigger( d_nodes[0] ) ){ @@ -63,23 +70,26 @@ d_quantEngine( qe ), d_f( f ){ ++(qe->d_statistics.d_simple_triggers); } }else{ - Trace("multi-trigger") << "Multi-trigger "; - debugPrint("multi-trigger"); - Trace("multi-trigger") << " for " << f << std::endl; - //Notice() << "Multi-trigger for " << f << " : " << std::endl; - //Notice() << " " << (*this) << std::endl; + Trace("multi-trigger") << "Trigger for " << f << ": " << std::endl; + for( unsigned i=0; i<d_nodes.size(); i++ ){ + Trace("multi-trigger") << " " << d_nodes[i] << std::endl; + } ++(qe->d_statistics.d_multi_triggers); } //Notice() << "Trigger : " << (*this) << " for " << f << std::endl; if( options::eagerInstQuant() ){ for( int i=0; i<(int)d_nodes.size(); i++ ){ - Node op = qe->getTermDatabase()->getOperator( d_nodes[i] ); + Node op = qe->getTermDatabase()->getMatchOperator( d_nodes[i] ); qe->getTermDatabase()->registerTrigger( this, op ); } } Trace("trigger-debug") << "Finished making trigger." << std::endl; } +Trigger::~Trigger() { + if(d_mg != NULL) { delete d_mg; } +} + void Trigger::resetInstantiationRound(){ d_mg->resetInstantiationRound( d_quantEngine ); } @@ -114,8 +124,7 @@ int Trigger::addInstantiations( InstMatch& baseMatch ){ return addedLemmas; } -Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool keepAll, int trOption, - bool smartTriggers ){ +Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool keepAll, int trOption ){ std::vector< Node > trNodes; if( !keepAll ){ //only take nodes that contribute variables to the trigger when added @@ -125,7 +134,7 @@ Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& std::map< Node, std::vector< Node > > patterns; size_t varCount = 0; std::map< Node, std::vector< Node > > varContains; - qe->getTermDatabase()->getVarContains( f, temp, varContains ); + quantifiers::TermDb::getVarContains( f, temp, varContains ); for( unsigned i=0; i<temp.size(); i++ ){ bool foundVar = false; for( unsigned j=0; j<varContains[ temp[i] ].size(); j++ ){ @@ -202,21 +211,21 @@ Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& } } } - Trigger* t = new Trigger( qe, f, trNodes, matchOption, smartTriggers ); + Trigger* t = new Trigger( qe, f, trNodes, matchOption ); qe->getTriggerDatabase()->addTrigger( trNodes, t ); return t; } -Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, Node n, int matchOption, bool keepAll, int trOption, bool smartTriggers ){ +Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, Node n, int matchOption, bool keepAll, int trOption ){ std::vector< Node > nodes; nodes.push_back( n ); - return mkTrigger( qe, f, nodes, matchOption, keepAll, trOption, smartTriggers ); + return mkTrigger( qe, f, nodes, matchOption, keepAll, trOption ); } bool Trigger::isUsable( Node n, Node q ){ if( quantifiers::TermDb::getInstConstAttr(n)==q ){ if( isAtomicTrigger( n ) ){ - for( int i=0; i<(int)n.getNumChildren(); i++ ){ + for( unsigned i=0; i<n.getNumChildren(); i++ ){ if( !isUsable( n[i], q ) ){ return false; } @@ -241,67 +250,91 @@ bool Trigger::isUsable( Node n, Node q ){ } } -Node Trigger::getIsUsableTrigger( Node n, Node f, bool pol, bool hasPol ) { +Node Trigger::getIsUsableEq( Node q, Node n ) { + Assert( isRelationalTrigger( n ) ); + for( unsigned i=0; i<2; i++) { + if( isUsableEqTerms( q, n[i], n[1-i] ) ){ + if( i==1 && ( n.getKind()==EQUAL || n.getKind()==IFF ) && !quantifiers::TermDb::hasInstConstAttr(n[0]) ){ + return NodeManager::currentNM()->mkNode( n.getKind(), n[1], n[0] ); + }else{ + return n; + } + } + } + return Node::null(); +} + +bool Trigger::isUsableEqTerms( Node q, Node n1, Node n2 ) { + if( n1.getKind()==INST_CONSTANT ){ + if( options::relationalTriggers() ){ + if( !quantifiers::TermDb::hasInstConstAttr(n2) ){ + return true; + }else if( n2.getKind()==INST_CONSTANT ){ + return true; + } + } + }else if( isAtomicTrigger( n1 ) && isUsable( n1, q ) ){ + if( options::relationalTriggers() && n2.getKind()==INST_CONSTANT && !quantifiers::TermDb::containsTerm( n1, n2 ) ){ + return true; + }else if( !quantifiers::TermDb::hasInstConstAttr(n2) ){ + return true; + } + } + return false; +} + +Node Trigger::getIsUsableTrigger( Node n, Node q ) { + bool pol = true; Trace("trigger-debug") << "Is " << n << " a usable trigger?" << std::endl; if( n.getKind()==NOT ){ pol = !pol; n = n[0]; } - if( options::relationalTriggers() ){ - if( n.getKind()==EQUAL || n.getKind()==IFF || n.getKind()==GEQ ){ - Node rtr; - bool do_negate = hasPol && pol; - bool is_arith = n[0].getType().isReal(); - for( unsigned i=0; i<2; i++) { - if( n[1-i].getKind()==INST_CONSTANT ){ - if( isUsableTrigger( n[i], f ) && !quantifiers::TermDb::containsTerm( n[i], n[1-i] ) && ( !do_negate || is_arith ) ){ - rtr = n; - break; - } - if( n[i].getKind()==INST_CONSTANT && ( !hasPol || pol ) ){ - do_negate = true; - rtr = n; - break; + if( n.getKind()==INST_CONSTANT ){ + return pol ? n : NodeManager::currentNM()->mkNode( IFF, n, NodeManager::currentNM()->mkConst( true ) ).notNode(); + }else if( isRelationalTrigger( n ) ){ + Node rtr = getIsUsableEq( q, n ); + if( rtr.isNull() && n[0].getType().isReal() ){ + //try to solve relation + std::map< Node, Node > m; + if( QuantArith::getMonomialSumLit(n, m) ){ + for( std::map< Node, Node >::iterator it = m.begin(); it!=m.end(); ++it ){ + bool trySolve = false; + if( !it->first.isNull() ){ + if( it->first.getKind()==INST_CONSTANT ){ + trySolve = options::relationalTriggers(); + }else if( isUsableTrigger( it->first, q ) ){ + trySolve = true; + } } - } - } - if( is_arith ){ - //try to rearrange? - std::map< Node, Node > m; - if( QuantArith::getMonomialSumLit(n, m) ){ - for( std::map< Node, Node >::iterator it = m.begin(); it!=m.end(); ++it ){ - if( !it->first.isNull() && it->first.getKind()==INST_CONSTANT ){ - Node veq; - if( QuantArith::isolate( it->first, m, veq, n.getKind() )!=0 ){ - int vti = veq[0]==it->first ? 1 : 0; - if( isUsableTrigger( veq[vti], f ) && !quantifiers::TermDb::containsTerm( veq[vti], veq[1-vti] ) ){ - rtr = veq; - } - } + if( trySolve ){ + Trace("trigger-debug") << "Try to solve for " << it->first << std::endl; + Node veq; + if( QuantArith::isolate( it->first, m, veq, n.getKind() )!=0 ){ + rtr = getIsUsableEq( q, veq ); } + //either all solves will succeed or all solves will fail + break; } } } - if( !rtr.isNull() ){ - Trace("relational-trigger") << "Relational trigger : " << std::endl; - Trace("relational-trigger") << " " << rtr << " (from " << n << ")" << std::endl; - Trace("relational-trigger") << " in quantifier " << f << std::endl; - if( hasPol ){ - Trace("relational-trigger") << " polarity : " << pol << std::endl; - } - Node rtr2 = do_negate ? rtr.negate() : rtr; - Trace("relational-trigger") << " return : " << rtr2 << std::endl; - return rtr2; - } } - } - bool usable = quantifiers::TermDb::getInstConstAttr(n)==f && isAtomicTrigger( n ) && isUsable( n, f ); - Trace("trigger-debug") << n << " usable : " << (quantifiers::TermDb::getInstConstAttr(n)==f) << " " << isAtomicTrigger( n ) << " " << isUsable( n, f ) << std::endl; - if( usable ){ - return n; + if( !rtr.isNull() ){ + Trace("relational-trigger") << "Relational trigger : " << std::endl; + Trace("relational-trigger") << " " << rtr << " (from " << n << ")" << std::endl; + Trace("relational-trigger") << " in quantifier " << q << std::endl; + Node rtr2 = pol ? rtr : rtr.negate(); + Trace("relational-trigger") << " return : " << rtr2 << std::endl; + return rtr2; + } }else{ - return Node::null(); + bool usable = quantifiers::TermDb::getInstConstAttr(n)==q && isAtomicTrigger( n ) && isUsable( n, q ); + Trace("trigger-debug") << n << " usable : " << (quantifiers::TermDb::getInstConstAttr(n)==q) << " " << isAtomicTrigger( n ) << " " << isUsable( n, q ) << std::endl; + if( usable ){ + return pol ? n : NodeManager::currentNM()->mkNode( IFF, n, NodeManager::currentNM()->mkConst( true ) ).notNode(); + } } + return Node::null(); } bool Trigger::isUsableTrigger( Node n, Node q ){ @@ -321,19 +354,33 @@ bool Trigger::isAtomicTriggerKind( Kind k ) { k==UNION || k==INTERSECTION || k==SUBSET || k==SETMINUS || k==MEMBER || k==SINGLETON; } +bool Trigger::isRelationalTrigger( Node n ) { + return isRelationalTriggerKind( n.getKind() ); +} + +bool Trigger::isRelationalTriggerKind( Kind k ) { + return k==EQUAL || k==IFF || k==GEQ; +} + bool Trigger::isCbqiKind( Kind k ) { return quantifiers::TermDb::isBoolConnective( k ) || k==PLUS || k==GEQ || k==EQUAL || k==MULT || k==APPLY_CONSTRUCTOR || k==APPLY_SELECTOR_TOTAL || k==APPLY_TESTER; } bool Trigger::isSimpleTrigger( Node n ){ - if( isAtomicTrigger( n ) ){ - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - if( n[i].getKind()!=INST_CONSTANT && quantifiers::TermDb::hasInstConstAttr(n[i]) ){ + Node t = n.getKind()==NOT ? n[0] : n; + if( n.getKind()==IFF || n.getKind()==EQUAL ){ + if( !quantifiers::TermDb::hasInstConstAttr( n[1] ) ){ + t = n[0]; + } + } + if( isAtomicTrigger( t ) ){ + for( unsigned i=0; i<t.getNumChildren(); i++ ){ + if( t[i].getKind()!=INST_CONSTANT && quantifiers::TermDb::hasInstConstAttr(t[i]) ){ return false; } } - if( options::purifyDtTriggers() && n.getKind()==APPLY_SELECTOR_TOTAL ){ + if( options::purifyDtTriggers() && t.getKind()==APPLY_SELECTOR_TOTAL ){ return false; } return true; @@ -342,69 +389,101 @@ bool Trigger::isSimpleTrigger( Node n ){ } } - -bool Trigger::collectPatTerms2( Node f, Node n, std::map< Node, bool >& patMap, int tstrt, std::vector< Node >& exclude, bool pol, bool hasPol ){ - if( patMap.find( n )==patMap.end() ){ - patMap[ n ] = false; - if( tstrt==TS_MIN_TRIGGER ){ - if( n.getKind()==FORALL ){ - return false; - }else{ - bool retVal = false; - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - bool newHasPol, newPol; - QuantPhaseReq::getPolarity( n, i, hasPol, pol, newHasPol, newPol ); - if( collectPatTerms2( f, n[i], patMap, tstrt, exclude, newPol, newHasPol ) ){ - retVal = true; +//store triggers in reqPol, indicating their polarity (if any) they must appear to falsify the quantified formula +bool Trigger::collectPatTerms2( Node q, Node n, std::map< Node, Node >& visited, std::map< Node, TriggerTermInfo >& tinfo, + quantifiers::TriggerSelMode tstrt, std::vector< Node >& exclude, std::vector< Node >& added, + bool pol, bool hasPol, bool epol, bool hasEPol ){ + std::map< Node, Node >::iterator itv = visited.find( n ); + if( itv==visited.end() ){ + visited[ n ] = Node::null(); + Trace("auto-gen-trigger-debug2") << "Collect pat terms " << n << " " << pol << " " << hasPol << " " << epol << " " << hasEPol << std::endl; + bool retVal = false; + if( n.getKind()!=FORALL && n.getKind()!=INST_CONSTANT ){ + bool rec = true; + Node nu; + bool nu_single = false; + if( n.getKind()!=NOT && std::find( exclude.begin(), exclude.end(), n )==exclude.end() ){ + nu = getIsUsableTrigger( n, q ); + if( !nu.isNull() ){ + Assert( nu.getKind()!=NOT ); + Trace("auto-gen-trigger-debug2") << "...found usable trigger : " << nu << std::endl; + Node reqEq; + if( nu.getKind()==IFF || nu.getKind()==EQUAL ){ + if( isAtomicTrigger( nu[0] ) && !quantifiers::TermDb::hasInstConstAttr(nu[1]) ){ + if( hasPol ){ + reqEq = nu[1]; + } + nu = nu[0]; + } } - } - if( retVal ){ - return true; - }else{ - Node nu; - if( std::find( exclude.begin(), exclude.end(), n )==exclude.end() ){ - nu = getIsUsableTrigger( n, f, pol, hasPol ); + Assert( reqEq.isNull() || !quantifiers::TermDb::hasInstConstAttr( reqEq ) ); + Assert( isUsableTrigger( nu, q ) ); + //do not add if already excluded + bool add = true; + if( n!=nu ){ + std::map< Node, Node >::iterator itvu = visited.find( nu ); + if( itvu!=visited.end() && itvu->second.isNull() ){ + add = false; + } } - if( !nu.isNull() ){ - patMap[ nu ] = true; - return true; - }else{ - return false; + if( add ){ + Trace("auto-gen-trigger-debug2") << "...add usable trigger : " << nu << std::endl; + visited[ nu ] = nu; + tinfo[ nu ].init( q, nu, hasEPol ? ( epol ? 1 : -1 ) : 0, reqEq ); + nu_single = tinfo[ nu ].d_fv.size()==q[0].getNumChildren(); + retVal = true; + if( tstrt==quantifiers::TRIGGER_SEL_MAX || ( tstrt==quantifiers::TRIGGER_SEL_MIN_SINGLE_MAX && !nu_single ) ){ + rec = false; + } } } } - }else{ - bool retVal = false; - Node nu; - if( std::find( exclude.begin(), exclude.end(), n )==exclude.end() ){ - nu = getIsUsableTrigger( n, f, pol, hasPol ); - } - if( !nu.isNull() ){ - patMap[ nu ] = true; - if( tstrt==TS_MAX_TRIGGER ){ - return true; - }else{ - retVal = true; - } - } - if( n.getKind()!=FORALL ){ - for( unsigned i=0; i<n.getNumChildren(); i++ ){ + if( rec ){ + Node nrec = nu.isNull() ? n : nu; + std::vector< Node > added2; + for( unsigned i=0; i<nrec.getNumChildren(); i++ ){ bool newHasPol, newPol; - QuantPhaseReq::getPolarity( n, i, hasPol, pol, newHasPol, newPol ); - if( collectPatTerms2( f, n[i], patMap, tstrt, exclude, newPol, newHasPol ) ){ + bool newHasEPol, newEPol; + QuantPhaseReq::getPolarity( nrec, i, hasPol, pol, newHasPol, newPol ); + QuantPhaseReq::getEntailPolarity( nrec, i, hasEPol, epol, newHasEPol, newEPol ); + if( collectPatTerms2( q, nrec[i], visited, tinfo, tstrt, exclude, added2, newPol, newHasPol, newEPol, newHasEPol ) ){ retVal = true; } } + if( !nu.isNull() ){ + bool rm_nu = false; + //discard if we added a subterm as a trigger with all variables that nu has + for( unsigned i=0; i<added2.size(); i++ ){ + Assert( tinfo.find( added2[i] )!=tinfo.end() ); + if( added2[i]!=nu ){ + if( tinfo[ nu ].d_fv.size()==tinfo[ added2[i] ].d_fv.size() ){ + rm_nu = true; + } + added.push_back( added2[i] ); + }else{ + Assert( false ); + } + } + if( rm_nu && ( tstrt==quantifiers::TRIGGER_SEL_MIN || ( tstrt==quantifiers::TRIGGER_SEL_MIN_SINGLE_ALL && nu_single ) ) ){ + visited[nu] = Node::null(); + tinfo.erase( nu ); + }else{ + added.push_back( nu ); + } + } } - return retVal; } + return retVal; }else{ - return patMap[ n ]; + if( itv->second.isNull() ){ + return false; + }else{ + added.push_back( itv->second ); + return true; + } } } - - bool Trigger::isBooleanTermTrigger( Node n ) { if( n.getKind()==ITE ){ //check for boolean term converted to ITE @@ -434,6 +513,23 @@ bool Trigger::isPureTheoryTrigger( Node n ) { } } +int Trigger::getTriggerWeight( Node n ) { + if( isAtomicTrigger( n ) ){ + return 0; + }else{ + if( options::relationalTriggers() ){ + if( isRelationalTrigger( n ) ){ + for( unsigned i=0; i<2; i++ ){ + if( n[i].getKind()==INST_CONSTANT && !quantifiers::TermDb::hasInstConstAttr( n[1-i] ) ){ + return 0; + } + } + } + } + return 1; + } +} + bool Trigger::isLocalTheoryExt( Node n, std::vector< Node >& vars, std::vector< Node >& patTerms ) { if( !n.getType().isBoolean() && n.getKind()==APPLY_UF ){ if( std::find( patTerms.begin(), patTerms.end(), n )==patTerms.end() ){ @@ -466,42 +562,51 @@ bool Trigger::isLocalTheoryExt( Node n, std::vector< Node >& vars, std::vector< return true; } -void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, std::vector< Node >& exclude, bool filterInst ){ - std::map< Node, bool > patMap; +void Trigger::collectPatTerms( Node q, Node n, std::vector< Node >& patTerms, quantifiers::TriggerSelMode tstrt, std::vector< Node >& exclude, + std::map< Node, TriggerTermInfo >& tinfo, bool filterInst ){ + std::map< Node, Node > visited; if( filterInst ){ //immediately do not consider any term t for which another term is an instance of t std::vector< Node > patTerms2; - collectPatTerms( qe, f, n, patTerms2, TS_ALL, exclude, false ); + std::map< Node, TriggerTermInfo > tinfo2; + collectPatTerms( q, n, patTerms2, quantifiers::TRIGGER_SEL_ALL, exclude, tinfo2, false ); std::vector< Node > temp; temp.insert( temp.begin(), patTerms2.begin(), patTerms2.end() ); - qe->getTermDatabase()->filterInstances( temp ); + quantifiers::TermDb::filterInstances( temp ); if( temp.size()!=patTerms2.size() ){ Trace("trigger-filter-instance") << "Filtered an instance: " << std::endl; Trace("trigger-filter-instance") << "Old: "; - for( int i=0; i<(int)patTerms2.size(); i++ ){ + for( unsigned i=0; i<patTerms2.size(); i++ ){ Trace("trigger-filter-instance") << patTerms2[i] << " "; } Trace("trigger-filter-instance") << std::endl << "New: "; - for( int i=0; i<(int)temp.size(); i++ ){ + for( unsigned i=0; i<temp.size(); i++ ){ Trace("trigger-filter-instance") << temp[i] << " "; } Trace("trigger-filter-instance") << std::endl; } - if( tstrt==TS_ALL ){ - patTerms.insert( patTerms.begin(), temp.begin(), temp.end() ); + if( tstrt==quantifiers::TRIGGER_SEL_ALL ){ + for( unsigned i=0; i<temp.size(); i++ ){ + //copy information + tinfo[temp[i]].d_fv.insert( tinfo[temp[i]].d_fv.end(), tinfo2[temp[i]].d_fv.begin(), tinfo2[temp[i]].d_fv.end() ); + tinfo[temp[i]].d_reqPol = tinfo2[temp[i]].d_reqPol; + tinfo[temp[i]].d_reqPolEq = tinfo2[temp[i]].d_reqPolEq; + patTerms.push_back( temp[i] ); + } return; }else{ //do not consider terms that have instances - for( int i=0; i<(int)patTerms2.size(); i++ ){ + for( unsigned i=0; i<patTerms2.size(); i++ ){ if( std::find( temp.begin(), temp.end(), patTerms2[i] )==temp.end() ){ - patMap[ patTerms2[i] ] = false; + visited[ patTerms2[i] ] = Node::null(); } } } } - collectPatTerms2( f, n, patMap, tstrt, exclude, true, true ); - for( std::map< Node, bool >::iterator it = patMap.begin(); it != patMap.end(); ++it ){ - if( it->second ){ + std::vector< Node > added; + collectPatTerms2( q, n, visited, tinfo, tstrt, exclude, added, true, true, false, true ); + for( std::map< Node, TriggerTermInfo >::iterator it = tinfo.begin(); it != tinfo.end(); ++it ){ + if( !visited[it->first].isNull() ){ patTerms.push_back( it->first ); } } @@ -582,14 +687,15 @@ Node Trigger::getInversion( Node n, Node x ) { return Node::null(); } -void Trigger::getTriggerVariables( QuantifiersEngine* qe, Node icn, Node f, std::vector< Node >& t_vars ) { +void Trigger::getTriggerVariables( Node icn, Node q, std::vector< Node >& t_vars ) { std::vector< Node > patTerms; + std::map< Node, TriggerTermInfo > tinfo; //collect all patterns from icn std::vector< Node > exclude; - collectPatTerms( qe, f, icn, patTerms, TS_ALL, exclude ); + collectPatTerms( q, icn, patTerms, quantifiers::TRIGGER_SEL_ALL, exclude, tinfo ); //collect all variables from all patterns in patTerms, add to t_vars for( unsigned i=0; i<patTerms.size(); i++ ){ - qe->getTermDatabase()->getVarContainsNode( f, patTerms[i], t_vars ); + quantifiers::TermDb::getVarContainsNode( q, patTerms[i], t_vars ); } } @@ -621,7 +727,7 @@ InstMatchGenerator* Trigger::getInstMatchGenerator( Node q, Node n ) { Trigger* TriggerTrie::getTrigger2( std::vector< Node >& nodes ){ if( nodes.empty() ){ - return d_tr; + return d_tr.empty() ? NULL : d_tr[0]; }else{ Node n = nodes.back(); nodes.pop_back(); @@ -635,7 +741,7 @@ Trigger* TriggerTrie::getTrigger2( std::vector< Node >& nodes ){ void TriggerTrie::addTrigger2( std::vector< Node >& nodes, Trigger* t ){ if( nodes.empty() ){ - d_tr = t; + d_tr.push_back( t ); }else{ Node n = nodes.back(); nodes.pop_back(); @@ -645,3 +751,24 @@ void TriggerTrie::addTrigger2( std::vector< Node >& nodes, Trigger* t ){ d_children[n]->addTrigger2( nodes, t ); } } + + +TriggerTrie::TriggerTrie() +{} + +TriggerTrie::~TriggerTrie() { + for(std::map< TNode, TriggerTrie* >::iterator i = d_children.begin(), iend = d_children.end(); + i != iend; ++i) { + TriggerTrie* current = (*i).second; + delete current; + } + d_children.clear(); + + for( unsigned i=0; i<d_tr.size(); i++ ){ + delete d_tr[i]; + } +} + +}/* CVC4::theory::inst namespace */ +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ diff --git a/src/theory/quantifiers/trigger.h b/src/theory/quantifiers/trigger.h index 11962008e..41f2a1c38 100644 --- a/src/theory/quantifiers/trigger.h +++ b/src/theory/quantifiers/trigger.h @@ -1,13 +1,13 @@ /********************* */ /*! \file trigger.h ** \verbatim - ** Original author: Morgan Deters - ** Major contributors: Andrew Reynolds - ** Minor contributors (to current version): Francois Bobot + ** Top contributors (to current version): + ** Tim King, Morgan Deters, Andrew Reynolds ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim + ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS + ** in the top-level source directory) and their institutional affiliations. + ** All rights reserved. See the file COPYING in the top-level source + ** directory for licensing information.\endverbatim ** ** \brief trigger class **/ @@ -17,11 +17,13 @@ #ifndef __CVC4__THEORY__QUANTIFIERS__TRIGGER_H #define __CVC4__THEORY__QUANTIFIERS__TRIGGER_H -#include "theory/quantifiers/inst_match.h" -#include "expr/node.h" -#include "util/hash.h" #include <map> +#include "expr/node.h" +#include "theory/quantifiers/inst_match.h" +#include "options/quantifiers_options.h" + +// Forward declarations for defining the Trigger and TriggerTrie. namespace CVC4 { namespace theory { @@ -31,29 +33,37 @@ namespace inst { class IMGenerator; class InstMatchGenerator; +}/* CVC4::theory::inst namespace */ +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ -//a collect of nodes representing a trigger -class Trigger { -private: - /** the quantifiers engine */ - QuantifiersEngine* d_quantEngine; - /** the quantifier this trigger is for */ - Node d_f; - /** match generators */ - IMGenerator* d_mg; -private: - /** trigger constructor */ - Trigger( QuantifiersEngine* ie, Node f, std::vector< Node >& nodes, int matchOption = 0, bool smartTriggers = false ); -public: - ~Trigger(){} -public: - std::vector< Node > d_nodes; + +namespace CVC4 { +namespace theory { +namespace inst { + +class TriggerTermInfo { public: + TriggerTermInfo() : d_reqPol(0){} + ~TriggerTermInfo(){} + std::vector< Node > d_fv; + int d_reqPol; + Node d_reqPolEq; + void init( Node q, Node n, int reqPol = 0, Node reqPolEq = Node::null() ); +}; + +/** A collect of nodes representing a trigger. */ +class Trigger { + public: + ~Trigger(); + IMGenerator* getGenerator() { return d_mg; } -public: - /** reset instantiation round (call this whenever equivalence classes have changed) */ + + /** reset instantiation round (call this whenever equivalence + * classes have changed) */ void resetInstantiationRound(); - /** reset, eqc is the equivalence class to search in (search in any if eqc=null) */ + /** 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( Node f, InstMatch& m ); @@ -66,7 +76,7 @@ public: int addTerm( Node t ); /** return whether this is a multi-trigger */ bool isMultiTrigger() { return d_nodes.size()>1; } -public: + /** add all available instantiations exhaustively, in any equivalence class if limitInst>0, limitInst is the max # of instantiations to try */ int addInstantiations( InstMatch& baseMatch ); @@ -74,51 +84,46 @@ public: ie : quantifier engine; f : forall something .... nodes : (multi-)trigger - matchOption : which policy to use for creating matches (one of InstMatchGenerator::MATCH_GEN_* ) + matchOption : which policy to use for creating matches + (one of InstMatchGenerator::MATCH_GEN_* ) keepAll: don't remove unneeded patterns; - trOption : policy for dealing with triggers that already existed (see below) + trOption : policy for dealing with triggers that already existed + (see below) */ enum{ TR_MAKE_NEW, //make new trigger even if it already may exist TR_GET_OLD, //return a previous trigger if it had already been created TR_RETURN_NULL //return null if a duplicate is found }; - static Trigger* mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, - int matchOption = 0, bool keepAll = true, int trOption = TR_MAKE_NEW, - bool smartTriggers = false ); + static Trigger* mkTrigger( QuantifiersEngine* qe, Node f, + std::vector< Node >& nodes, int matchOption = 0, + bool keepAll = true, int trOption = TR_MAKE_NEW ); static Trigger* mkTrigger( QuantifiersEngine* qe, Node f, Node n, - int matchOption = 0, bool keepAll = true, int trOption = TR_MAKE_NEW, - bool smartTriggers = false ); -private: - /** is subterm of trigger usable */ - static bool isUsable( Node n, Node q ); - static Node getIsUsableTrigger( Node n, Node f, bool pol = true, bool hasPol = false ); - /** collect all APPLY_UF pattern terms for f in n */ - static bool collectPatTerms2( Node f, Node n, std::map< Node, bool >& patMap, int tstrt, std::vector< Node >& exclude, bool pol, bool hasPol ); -public: - //different strategies for choosing trigger terms - enum { - TS_MAX_TRIGGER = 0, - TS_MIN_TRIGGER, - TS_ALL, - }; - static void collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, std::vector< Node >& exclude, bool filterInst = false ); -public: + int matchOption = 0, bool keepAll = true, + int trOption = TR_MAKE_NEW ); + static void collectPatTerms( Node q, Node n, std::vector< Node >& patTerms, quantifiers::TriggerSelMode tstrt, + std::vector< Node >& exclude, std::map< Node, TriggerTermInfo >& tinfo, + bool filterInst = false ); /** is usable trigger */ static bool isUsableTrigger( Node n, Node q ); + static Node getIsUsableTrigger( Node n, Node q ); static bool isAtomicTrigger( Node n ); static bool isAtomicTriggerKind( Kind k ); + static bool isRelationalTrigger( Node n ); + static bool isRelationalTriggerKind( Kind k ); static bool isCbqiKind( Kind k ); static bool isSimpleTrigger( Node n ); static bool isBooleanTermTrigger( Node n ); static bool isPureTheoryTrigger( Node n ); - static bool isLocalTheoryExt( Node n, std::vector< Node >& vars, std::vector< Node >& patTerms ); + static int getTriggerWeight( Node n ); + static bool isLocalTheoryExt( Node n, std::vector< Node >& vars, + std::vector< Node >& patTerms ); /** return data structure for producing matches for this trigger. */ static InstMatchGenerator* getInstMatchGenerator( Node q, Node n ); static Node getInversionVariable( Node n ); static Node getInversion( Node n, Node x ); /** get all variables that E-matching can possibly handle */ - static void getTriggerVariables( QuantifiersEngine* qe, Node icn, Node f, std::vector< Node >& t_vars ); + static void getTriggerVariables( Node icn, Node f, std::vector< Node >& t_vars ); void debugPrint( const char * c ) { Trace(c) << "TRIGGER( "; @@ -128,17 +133,35 @@ public: } Trace(c) << " )"; } -}; +private: + /** trigger constructor */ + Trigger( QuantifiersEngine* ie, Node f, std::vector< Node >& nodes, int matchOption = 0 ); + + /** is subterm of trigger usable */ + static bool isUsable( Node n, Node q ); + static Node getIsUsableEq( Node q, Node eq ); + static bool isUsableEqTerms( Node q, Node n1, Node n2 ); + /** collect all APPLY_UF pattern terms for f in n */ + static bool collectPatTerms2( Node q, Node n, std::map< Node, Node >& visited, std::map< Node, TriggerTermInfo >& tinfo, + quantifiers::TriggerSelMode tstrt, std::vector< Node >& exclude, std::vector< Node >& added, + bool pol, bool hasPol, bool epol, bool hasEPol ); + + std::vector< Node > d_nodes; + + /** the quantifiers engine */ + QuantifiersEngine* d_quantEngine; + /** the quantifier this trigger is for */ + Node d_f; + /** match generators */ + IMGenerator* d_mg; +}; /* class Trigger */ /** a trie of triggers */ class TriggerTrie { -private: - inst::Trigger* getTrigger2( std::vector< Node >& nodes ); - void addTrigger2( std::vector< Node >& nodes, inst::Trigger* t ); public: - TriggerTrie() : d_tr( NULL ){} - inst::Trigger* d_tr; - std::map< TNode, TriggerTrie* > d_children; + TriggerTrie(); + ~TriggerTrie(); + inst::Trigger* getTrigger( std::vector< Node >& nodes ){ std::vector< Node > temp; temp.insert( temp.begin(), nodes.begin(), nodes.end() ); @@ -151,7 +174,13 @@ public: std::sort( temp.begin(), temp.end() ); return addTrigger2( temp, t ); } -};/* class inst::Trigger::Trigger */ +private: + inst::Trigger* getTrigger2( std::vector< Node >& nodes ); + void addTrigger2( std::vector< Node >& nodes, inst::Trigger* t ); + + std::vector< inst::Trigger* > d_tr; + std::map< TNode, TriggerTrie* > d_children; +};/* class inst::Trigger::TriggerTrie */ }/* CVC4::theory::inst namespace */ }/* CVC4::theory namespace */ |