From: Morgan Deters Date: Mon, 4 Feb 2013 22:30:18 +0000 (-0500) Subject: fixed files with DOS newlines; fixed contrib/ scripts to use git X-Git-Tag: cvc5-1.0.0~7428 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=aed7130284c04f7ada79db1ed3d4a8ddb08d3543;p=cvc5.git fixed files with DOS newlines; fixed contrib/ scripts to use git --- diff --git a/contrib/get-authors b/contrib/get-authors index ef6abff8e..118ca4466 100755 --- a/contrib/get-authors +++ b/contrib/get-authors @@ -2,13 +2,15 @@ # # get-authors # Morgan Deters for CVC4 -# Copyright (c) 2009, 2010, 2011 The CVC4 Project +# Copyright (c) 2009-2013 The CVC4 Project # # usage: get-authors [ files... ] # -# This script uses svn to get the original author +# This script uses git to get the original author # +gituser="`git config user.name` <`git config user.email`>" + while [ $# -gt 0 ]; do f=$1 shift @@ -16,8 +18,8 @@ while [ $# -gt 0 ]; do major_contributors= minor_contributors= total_lines=`wc -l "$f" | awk '{print$1}'` - original_author=`svn log -q --incremental "$f" | tail -1 | awk '{print$3}'` - svn blame "$f" | awk '{print$2}' | sort | uniq -c | sort -n | + original_author=`git log --pretty="format:%aN <%aE>" "$f" | tail -1` + git blame --incremental "$f" | gawk '/^[0-9a-f]+ [0-9]+ [0-9]+ [0-9]+$/ {nl=$4;} /^author / {$1=""; author=$0;} /^author-mail / {mail=$2} /^filename / {while(nl--) {print author,mail}}' | sed "s,Not Committed Yet ,$gituser," | sort | uniq -c | sort -n | ( while read lines author; do pct=$((100*$lines/$total_lines)) if [ "$author" != "$original_author" ]; then diff --git a/contrib/update-copyright.pl b/contrib/update-copyright.pl index 8ac920bbf..4811a4bbe 100755 --- a/contrib/update-copyright.pl +++ b/contrib/update-copyright.pl @@ -2,7 +2,7 @@ # # update-copyright.pl # Morgan Deters for CVC4 -# Copyright (c) 2009-2012 The CVC4 Project +# Copyright (c) 2009-2013 The CVC4 Project # # usage: update-copyright [-m] [files/directories...] # update-copyright [-h | --help] @@ -16,15 +16,17 @@ # the CVC4 source tree, that means src/ in the CVC4 source tree. # # If -m is specified as the first argument, all files and directories -# are scanned, but only ones modifed in the current working directory -# are modified (i.e., those that have status M in "svn status"). +# are scanned, but only ones modified in the index or working tree +# are modified (i.e., those that have at least one status M in +# "git status -s"). # # It ignores any file/directory not starting with [a-zA-Z] -# (so, this includes . and .., vi swaps, .svn meta-info, +# (so, this includes . and .., vi swaps, .git meta-info, # .deps, etc.) # # It ignores any file not ending with one of: # .c .cc .cpp .C .h .hh .hpp .H .y .yy .ypp .Y .l .ll .lpp .L .g +# [ or those with ".in" also suffixed, e.g., .cpp.in ] # (so, this includes emacs ~-backups, CVS detritus, etc.) # # It ignores any directory matching $excluded_directories @@ -37,17 +39,17 @@ my $excluded_paths = '^(src/parser/antlr_input_imports.cpp|src/bindings/compat/. # Years of copyright for the template. E.g., the string # "1985, 1987, 1992, 1997, 2008" or "2006-2009" or whatever. -my $years = '2009-2012'; +my $years = '2009-2013'; my $standard_template = <= 0 && $ARGV[0] eq '-h' || $ARGV[0] eq '--help') { exit; } -# whether we ONLY process files with svn status "M" +# whether we ONLY process files with git status "M" my $modonly = 0; if($#ARGV >= 0 && $ARGV[0] eq '-m') { @@ -87,11 +89,12 @@ if($#ARGV == -1) { print <= 0) { sub handleFile { my ($srcdir, $file) = @_; - return if !($file =~ /\.(c|cc|cpp|C|h|hh|hpp|H|y|yy|ypp|Y|l|ll|lpp|L|g|java)$/); + return if !($file =~ /\.(c|cc|cpp|C|h|hh|hpp|H|y|yy|ypp|Y|l|ll|lpp|L|g|java)(\.in)?$/); return if ($srcdir.'/'.$file) =~ /$excluded_paths/; - return if $modonly &&`svn status "$srcdir/$file" 2>/dev/null` !~ /^M/; + return if $modonly && `git status -s "$srcdir/$file" 2>/dev/null` !~ /^(M|.M)/; print "$srcdir/$file..."; my $infile = $srcdir.'/'.$file; my $outfile = $srcdir.'/#'.$file.'.tmp'; diff --git a/src/theory/arrays/theory_arrays_model.h b/src/theory/arrays/theory_arrays_model.h index 8dfc7fc4a..c82c7635d 100644 --- a/src/theory/arrays/theory_arrays_model.h +++ b/src/theory/arrays/theory_arrays_model.h @@ -1,58 +1,58 @@ /********************* */ /*! \file theory_arrays_model.h ** \verbatim - ** Original author: ajreynol - ** Major contributors: none + ** Original author: Andrew Reynolds + ** Major contributors: Morgan Deters ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** - ** \brief MODEL for theory of arrays - **/ - - -#include "cvc4_private.h" - -#ifndef __CVC4__THEORY_ARRAYS_MODEL_H -#define __CVC4__THEORY_ARRAYS_MODEL_H - -#include "theory/quantifiers_engine.h" - -namespace CVC4 { -namespace theory { - -class TheoryModel; - -namespace arrays { - -class ArrayModel{ -protected: - /** the array this model is for */ - Node d_arr; -public: - ArrayModel(){} - ArrayModel( Node arr, TheoryModel* m ); - ~ArrayModel() {} -public: - /** pre-defined values */ - std::map< Node, Node > d_values; - /** base array */ - Node d_base_arr; - /** get value, return arguments that the value depends on */ - Node getValue( TheoryModel* m, Node i ); - /** set value */ - void setValue( TheoryModel* m, Node i, Node e ); - /** set default */ - void setDefaultArray( Node arr ); -public: - /** get array value */ - Node getArrayValue(); -};/* class ArrayModel */ - -} -} -} - + ** \brief MODEL for theory of arrays + **/ + + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY_ARRAYS_MODEL_H +#define __CVC4__THEORY_ARRAYS_MODEL_H + +#include "theory/quantifiers_engine.h" + +namespace CVC4 { +namespace theory { + +class TheoryModel; + +namespace arrays { + +class ArrayModel{ +protected: + /** the array this model is for */ + Node d_arr; +public: + ArrayModel(){} + ArrayModel( Node arr, TheoryModel* m ); + ~ArrayModel() {} +public: + /** pre-defined values */ + std::map< Node, Node > d_values; + /** base array */ + Node d_base_arr; + /** get value, return arguments that the value depends on */ + Node getValue( TheoryModel* m, Node i ); + /** set value */ + void setValue( TheoryModel* m, Node i, Node e ); + /** set default */ + void setDefaultArray( Node arr ); +public: + /** get array value */ + Node getArrayValue(); +};/* class ArrayModel */ + +} +} +} + #endif \ No newline at end of file diff --git a/src/theory/quantifiers/inst_gen.cpp b/src/theory/quantifiers/inst_gen.cpp old mode 100755 new mode 100644 index d3bd6ad03..dea371e9c --- a/src/theory/quantifiers/inst_gen.cpp +++ b/src/theory/quantifiers/inst_gen.cpp @@ -1,298 +1,296 @@ -/********************* */ -/*! \file inst_gen.cpp - ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief Implementation of inst gen classes - **/ - -#include "theory/quantifiers/inst_gen.h" -#include "theory/quantifiers/model_engine.h" -#include "theory/quantifiers/model_builder.h" -#include "theory/quantifiers/first_order_model.h" - -//#define CHILD_USE_CONSIDER - -using namespace std; -using namespace CVC4; -using namespace CVC4::kind; -using namespace CVC4::context; -using namespace CVC4::theory; -using namespace CVC4::theory::quantifiers; - - - -InstGenProcess::InstGenProcess( Node n ) : d_node( n ){ - Assert( n.hasAttribute(InstConstantAttribute()) ); - int count = 0; - for( size_t i=0; iexistsInstantiation( f, m, true ) ){ - //make sure no duplicates are produced - if( d_inst_trie[val].addInstMatch( qe, f, m, true ) ){ - d_match_values.push_back( val ); - d_matches.push_back( InstMatch( &m ) ); - qe->getModelEngine()->getModelBuilder()->d_instGenMatches++; - } - } -} - -void InstGenProcess::calculateMatches( QuantifiersEngine* qe, Node f, std::vector< Node >& considerVal, bool useConsider ){ - Trace("inst-gen-cm") << "* Calculate matches " << d_node << std::endl; - //whether we are doing a product or sum or matches - bool doProduct = true; - //get the model - FirstOrderModel* fm = qe->getModel(); - - //calculate terms we will consider - std::vector< Node > considerTerms; - std::vector< std::vector< Node > > newConsiderVal; - std::vector< bool > newUseConsider; - std::map< Node, InstMatch > considerTermsMatch[2]; - std::map< Node, bool > considerTermsSuccess[2]; - newConsiderVal.resize( d_children.size() ); - newUseConsider.resize( d_children.size(), useConsider ); - if( d_node.getKind()==APPLY_UF ){ - Node op = d_node.getOperator(); - if( useConsider ){ -#ifndef CHILD_USE_CONSIDER - for( size_t i=0; igetEqualityQuery()->getEngine()->getRepresentative( considerVal[i] ), - qe->getEqualityQuery()->getEngine() ); - while( !eqc.isFinished() ){ - Node en = (*eqc); - if( en.getKind()==APPLY_UF && en.getOperator()==op ){ - considerTerms.push_back( en ); - } - ++eqc; - } - } - }else{ - considerTerms.insert( considerTerms.begin(), fm->d_uf_terms[op].begin(), fm->d_uf_terms[op].end() ); - } - //for each term we consider, calculate a current match - for( size_t i=0; igetModelEngine()->getModelBuilder()->isTermSelected( n ); - bool hadSuccess CVC4_UNUSED = false; - for( int t=(isSelected ? 0 : 1); t<2; t++ ){ - if( t==0 || !n.getAttribute(NoMatchAttribute()) ){ - considerTermsMatch[t][n] = InstMatch(); - considerTermsSuccess[t][n] = true; - for( size_t j=0; jgetEqualityQuery(), d_node[j], n[j] ) ){ - Trace("inst-gen-cm") << "fail match: " << n[j] << " is not equal to "; - Trace("inst-gen-cm") << considerTermsMatch[t][n].getValue( d_node[j] ) << std::endl; - considerTermsSuccess[t][n] = false; - break; - } - }else if( !qe->getEqualityQuery()->areEqual( d_node[j], n[j] ) ){ - Trace("inst-gen-cm") << "fail arg: " << n[j] << " is not equal to " << d_node[j] << std::endl; - considerTermsSuccess[t][n] = false; - break; - } - } - } - } - //if successful, store it - if( considerTermsSuccess[t][n] ){ -#ifdef CHILD_USE_CONSIDER - if( !hadSuccess ){ - hadSuccess = true; - for( size_t k=0; kgetModel()->getRepresentative( n[childIndex] ); - if( std::find( newConsiderVal[k].begin(), newConsiderVal[k].end(), r )==newConsiderVal[k].end() ){ - newConsiderVal[k].push_back( r ); - //check if we now need to consider the entire domain - TypeNode tn = r.getType(); - if( qe->getModel()->d_rep_set.hasType( tn ) ){ - if( (int)newConsiderVal[k].size()>=qe->getModel()->d_rep_set.getNumRepresentatives( tn ) ){ - newConsiderVal[k].clear(); - newUseConsider[k] = false; - } - } - } - }else{ - //matching against selected term, will need to consider all values - newConsiderVal[k].clear(); - newUseConsider[k] = false; - } - } - } - } -#endif - } - } - } - } - }else{ - //the interpretted case - if( d_node.getType().isBoolean() ){ - if( useConsider ){ - //if( considerVal.size()!=1 ) { std::cout << "consider val = " << considerVal.size() << std::endl; } - Assert( considerVal.size()==1 ); - bool reqPol = considerVal[0]==fm->d_true; - Node ncv = considerVal[0]; - if( d_node.getKind()==NOT ){ - ncv = reqPol ? fm->d_false : fm->d_true; - } - if( d_node.getKind()==NOT || d_node.getKind()==AND || d_node.getKind()==OR ){ - for( size_t i=0; igetModelEngine()->getModelBuilder()->isTermSelected( n ); - for( int t=(isSelected ? 0 : 1); t<2; t++ ){ - //do not consider ground case if it is already congruent to another ground term - if( t==0 || !n.getAttribute(NoMatchAttribute()) ){ - Trace("inst-gen-cm") << "calculate for " << n << ", selected = " << (t==0) << std::endl; - if( considerTermsSuccess[t][n] ){ - //try to find unifier for d_node = n - calculateMatchesUninterpreted( qe, f, considerTermsMatch[t][n], n, 0, t==0 ); - } - } - } - } - }else{ - //if this is an interpreted function - if( doProduct ){ - //combining children matches - InstMatch curr; - std::vector< Node > terms; - calculateMatchesInterpreted( qe, f, curr, terms, 0 ); - }else{ - //summing children matches - Assert( considerVal.size()==1 ); - for( int i=0; i<(int)d_children.size(); i++ ){ - for( int j=0; j<(int)d_children[ i ].getNumMatches(); j++ ){ - InstMatch m; - if( d_children[ i ].getMatch( qe->getEqualityQuery(), j, m ) ){ - addMatchValue( qe, f, considerVal[0], m ); - } - } - } - } - } - Trace("inst-gen-cm") << "done calculate matches" << std::endl; - //can clear information used for finding duplicates - d_inst_trie.clear(); -} - -bool InstGenProcess::getMatch( EqualityQuery* q, int i, InstMatch& m ){ - //FIXME: is this correct? (query may not be accurate) - return m.merge( q, d_matches[i] ); -} - -void InstGenProcess::calculateMatchesUninterpreted( QuantifiersEngine* qe, Node f, InstMatch& curr, Node n, int childIndex, bool isSelected ){ - if( childIndex==(int)d_children.size() ){ - Node val = qe->getModel()->getRepresentative( n ); //FIXME: is this correct? - Trace("inst-gen-cm") << " - u-match : " << val << std::endl; - Trace("inst-gen-cm") << " : " << curr << std::endl; - addMatchValue( qe, f, val, curr ); - }else{ - Trace("inst-gen-cm") << "Consider child index = " << childIndex << ", against ground term argument " << d_children_index[childIndex] << " ... " << n[d_children_index[childIndex]] << std::endl; - bool sel = ( isSelected && n[d_children_index[childIndex]].getAttribute(ModelBasisAttribute()) ); - for( int i=0; i<(int)d_children[ childIndex ].getNumMatches(); i++ ){ - //FIXME: is this correct? - if( sel || qe->getEqualityQuery()->areEqual( d_children[ childIndex ].getMatchValue( i ), n[d_children_index[childIndex]] ) ){ - InstMatch next( &curr ); - if( d_children[ childIndex ].getMatch( qe->getEqualityQuery(), i, next ) ){ - calculateMatchesUninterpreted( qe, f, next, n, childIndex+1, isSelected ); - }else{ - Trace("inst-gen-cm") << curr << " not equal to " << d_children[ childIndex ].d_matches[i] << std::endl; - Trace("inst-gen-cm") << childIndex << " match " << i << " not equal subs." << std::endl; - } - }else{ - Trace("inst-gen-cm") << childIndex << " match " << i << " not equal value." << std::endl; - } - } - } -} - -void InstGenProcess::calculateMatchesInterpreted( QuantifiersEngine* qe, Node f, InstMatch& curr, std::vector< Node >& terms, int argIndex ){ - FirstOrderModel* fm = qe->getModel(); - if( argIndex==(int)d_node.getNumChildren() ){ - Node val; - if( d_node.getNumChildren()==0 ){ - val = d_node; - }else if( d_node.getKind()==EQUAL ){ - val = qe->getEqualityQuery()->areEqual( terms[0], terms[1] ) ? fm->d_true : fm->d_false; - }else{ - val = NodeManager::currentNM()->mkNode( d_node.getKind(), terms ); - val = Rewriter::rewrite( val ); - } - Trace("inst-gen-cm") << " - i-match : " << d_node << std::endl; - Trace("inst-gen-cm") << " : " << val << std::endl; - Trace("inst-gen-cm") << " : " << curr << std::endl; - addMatchValue( qe, f, val, curr ); - }else{ - if( d_children_map.find( argIndex )==d_children_map.end() ){ - terms.push_back( fm->getRepresentative( d_node[argIndex] ) ); - calculateMatchesInterpreted( qe, f, curr, terms, argIndex+1 ); - terms.pop_back(); - }else{ - for( int i=0; i<(int)d_children[ d_children_map[argIndex] ].getNumMatches(); i++ ){ - InstMatch next( &curr ); - if( d_children[ d_children_map[argIndex] ].getMatch( qe->getEqualityQuery(), i, next ) ){ - terms.push_back( d_children[ d_children_map[argIndex] ].getMatchValue( i ) ); - calculateMatchesInterpreted( qe, f, next, terms, argIndex+1 ); - terms.pop_back(); - } - } - } - } -} +/********************* */ +/*! \file inst_gen.cpp + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: Morgan Deters + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Implementation of inst gen classes + **/ + +#include "theory/quantifiers/inst_gen.h" +#include "theory/quantifiers/model_engine.h" +#include "theory/quantifiers/model_builder.h" +#include "theory/quantifiers/first_order_model.h" + +//#define CHILD_USE_CONSIDER + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::quantifiers; + + + +InstGenProcess::InstGenProcess( Node n ) : d_node( n ){ + Assert( n.hasAttribute(InstConstantAttribute()) ); + int count = 0; + for( size_t i=0; iexistsInstantiation( f, m, true ) ){ + //make sure no duplicates are produced + if( d_inst_trie[val].addInstMatch( qe, f, m, true ) ){ + d_match_values.push_back( val ); + d_matches.push_back( InstMatch( &m ) ); + qe->getModelEngine()->getModelBuilder()->d_instGenMatches++; + } + } +} + +void InstGenProcess::calculateMatches( QuantifiersEngine* qe, Node f, std::vector< Node >& considerVal, bool useConsider ){ + Trace("inst-gen-cm") << "* Calculate matches " << d_node << std::endl; + //whether we are doing a product or sum or matches + bool doProduct = true; + //get the model + FirstOrderModel* fm = qe->getModel(); + + //calculate terms we will consider + std::vector< Node > considerTerms; + std::vector< std::vector< Node > > newConsiderVal; + std::vector< bool > newUseConsider; + std::map< Node, InstMatch > considerTermsMatch[2]; + std::map< Node, bool > considerTermsSuccess[2]; + newConsiderVal.resize( d_children.size() ); + newUseConsider.resize( d_children.size(), useConsider ); + if( d_node.getKind()==APPLY_UF ){ + Node op = d_node.getOperator(); + if( useConsider ){ +#ifndef CHILD_USE_CONSIDER + for( size_t i=0; igetEqualityQuery()->getEngine()->getRepresentative( considerVal[i] ), + qe->getEqualityQuery()->getEngine() ); + while( !eqc.isFinished() ){ + Node en = (*eqc); + if( en.getKind()==APPLY_UF && en.getOperator()==op ){ + considerTerms.push_back( en ); + } + ++eqc; + } + } + }else{ + considerTerms.insert( considerTerms.begin(), fm->d_uf_terms[op].begin(), fm->d_uf_terms[op].end() ); + } + //for each term we consider, calculate a current match + for( size_t i=0; igetModelEngine()->getModelBuilder()->isTermSelected( n ); + bool hadSuccess CVC4_UNUSED = false; + for( int t=(isSelected ? 0 : 1); t<2; t++ ){ + if( t==0 || !n.getAttribute(NoMatchAttribute()) ){ + considerTermsMatch[t][n] = InstMatch(); + considerTermsSuccess[t][n] = true; + for( size_t j=0; jgetEqualityQuery(), d_node[j], n[j] ) ){ + Trace("inst-gen-cm") << "fail match: " << n[j] << " is not equal to "; + Trace("inst-gen-cm") << considerTermsMatch[t][n].getValue( d_node[j] ) << std::endl; + considerTermsSuccess[t][n] = false; + break; + } + }else if( !qe->getEqualityQuery()->areEqual( d_node[j], n[j] ) ){ + Trace("inst-gen-cm") << "fail arg: " << n[j] << " is not equal to " << d_node[j] << std::endl; + considerTermsSuccess[t][n] = false; + break; + } + } + } + } + //if successful, store it + if( considerTermsSuccess[t][n] ){ +#ifdef CHILD_USE_CONSIDER + if( !hadSuccess ){ + hadSuccess = true; + for( size_t k=0; kgetModel()->getRepresentative( n[childIndex] ); + if( std::find( newConsiderVal[k].begin(), newConsiderVal[k].end(), r )==newConsiderVal[k].end() ){ + newConsiderVal[k].push_back( r ); + //check if we now need to consider the entire domain + TypeNode tn = r.getType(); + if( qe->getModel()->d_rep_set.hasType( tn ) ){ + if( (int)newConsiderVal[k].size()>=qe->getModel()->d_rep_set.getNumRepresentatives( tn ) ){ + newConsiderVal[k].clear(); + newUseConsider[k] = false; + } + } + } + }else{ + //matching against selected term, will need to consider all values + newConsiderVal[k].clear(); + newUseConsider[k] = false; + } + } + } + } +#endif + } + } + } + } + }else{ + //the interpretted case + if( d_node.getType().isBoolean() ){ + if( useConsider ){ + //if( considerVal.size()!=1 ) { std::cout << "consider val = " << considerVal.size() << std::endl; } + Assert( considerVal.size()==1 ); + bool reqPol = considerVal[0]==fm->d_true; + Node ncv = considerVal[0]; + if( d_node.getKind()==NOT ){ + ncv = reqPol ? fm->d_false : fm->d_true; + } + if( d_node.getKind()==NOT || d_node.getKind()==AND || d_node.getKind()==OR ){ + for( size_t i=0; igetModelEngine()->getModelBuilder()->isTermSelected( n ); + for( int t=(isSelected ? 0 : 1); t<2; t++ ){ + //do not consider ground case if it is already congruent to another ground term + if( t==0 || !n.getAttribute(NoMatchAttribute()) ){ + Trace("inst-gen-cm") << "calculate for " << n << ", selected = " << (t==0) << std::endl; + if( considerTermsSuccess[t][n] ){ + //try to find unifier for d_node = n + calculateMatchesUninterpreted( qe, f, considerTermsMatch[t][n], n, 0, t==0 ); + } + } + } + } + }else{ + //if this is an interpreted function + if( doProduct ){ + //combining children matches + InstMatch curr; + std::vector< Node > terms; + calculateMatchesInterpreted( qe, f, curr, terms, 0 ); + }else{ + //summing children matches + Assert( considerVal.size()==1 ); + for( int i=0; i<(int)d_children.size(); i++ ){ + for( int j=0; j<(int)d_children[ i ].getNumMatches(); j++ ){ + InstMatch m; + if( d_children[ i ].getMatch( qe->getEqualityQuery(), j, m ) ){ + addMatchValue( qe, f, considerVal[0], m ); + } + } + } + } + } + Trace("inst-gen-cm") << "done calculate matches" << std::endl; + //can clear information used for finding duplicates + d_inst_trie.clear(); +} + +bool InstGenProcess::getMatch( EqualityQuery* q, int i, InstMatch& m ){ + //FIXME: is this correct? (query may not be accurate) + return m.merge( q, d_matches[i] ); +} + +void InstGenProcess::calculateMatchesUninterpreted( QuantifiersEngine* qe, Node f, InstMatch& curr, Node n, int childIndex, bool isSelected ){ + if( childIndex==(int)d_children.size() ){ + Node val = qe->getModel()->getRepresentative( n ); //FIXME: is this correct? + Trace("inst-gen-cm") << " - u-match : " << val << std::endl; + Trace("inst-gen-cm") << " : " << curr << std::endl; + addMatchValue( qe, f, val, curr ); + }else{ + Trace("inst-gen-cm") << "Consider child index = " << childIndex << ", against ground term argument " << d_children_index[childIndex] << " ... " << n[d_children_index[childIndex]] << std::endl; + bool sel = ( isSelected && n[d_children_index[childIndex]].getAttribute(ModelBasisAttribute()) ); + for( int i=0; i<(int)d_children[ childIndex ].getNumMatches(); i++ ){ + //FIXME: is this correct? + if( sel || qe->getEqualityQuery()->areEqual( d_children[ childIndex ].getMatchValue( i ), n[d_children_index[childIndex]] ) ){ + InstMatch next( &curr ); + if( d_children[ childIndex ].getMatch( qe->getEqualityQuery(), i, next ) ){ + calculateMatchesUninterpreted( qe, f, next, n, childIndex+1, isSelected ); + }else{ + Trace("inst-gen-cm") << curr << " not equal to " << d_children[ childIndex ].d_matches[i] << std::endl; + Trace("inst-gen-cm") << childIndex << " match " << i << " not equal subs." << std::endl; + } + }else{ + Trace("inst-gen-cm") << childIndex << " match " << i << " not equal value." << std::endl; + } + } + } +} + +void InstGenProcess::calculateMatchesInterpreted( QuantifiersEngine* qe, Node f, InstMatch& curr, std::vector< Node >& terms, int argIndex ){ + FirstOrderModel* fm = qe->getModel(); + if( argIndex==(int)d_node.getNumChildren() ){ + Node val; + if( d_node.getNumChildren()==0 ){ + val = d_node; + }else if( d_node.getKind()==EQUAL ){ + val = qe->getEqualityQuery()->areEqual( terms[0], terms[1] ) ? fm->d_true : fm->d_false; + }else{ + val = NodeManager::currentNM()->mkNode( d_node.getKind(), terms ); + val = Rewriter::rewrite( val ); + } + Trace("inst-gen-cm") << " - i-match : " << d_node << std::endl; + Trace("inst-gen-cm") << " : " << val << std::endl; + Trace("inst-gen-cm") << " : " << curr << std::endl; + addMatchValue( qe, f, val, curr ); + }else{ + if( d_children_map.find( argIndex )==d_children_map.end() ){ + terms.push_back( fm->getRepresentative( d_node[argIndex] ) ); + calculateMatchesInterpreted( qe, f, curr, terms, argIndex+1 ); + terms.pop_back(); + }else{ + for( int i=0; i<(int)d_children[ d_children_map[argIndex] ].getNumMatches(); i++ ){ + InstMatch next( &curr ); + if( d_children[ d_children_map[argIndex] ].getMatch( qe->getEqualityQuery(), i, next ) ){ + terms.push_back( d_children[ d_children_map[argIndex] ].getMatchValue( i ) ); + calculateMatchesInterpreted( qe, f, next, terms, argIndex+1 ); + terms.pop_back(); + } + } + } + } +} diff --git a/src/theory/quantifiers/inst_gen.h b/src/theory/quantifiers/inst_gen.h old mode 100755 new mode 100644 index f6e6a372e..94922df18 --- a/src/theory/quantifiers/inst_gen.h +++ b/src/theory/quantifiers/inst_gen.h @@ -1,61 +1,59 @@ -/********************* */ -/*! \file inst_gen.h - ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief Inst Gen classes - **/ - -#include "cvc4_private.h" - -#ifndef __CVC4__THEORY__QUANTIFIERS__INST_GEN_H -#define __CVC4__THEORY__QUANTIFIERS__INST_GEN_H - -#include "theory/quantifiers_engine.h" -#include "theory/quantifiers/inst_match.h" - -namespace CVC4 { -namespace theory { -namespace quantifiers { - -class InstGenProcess -{ -private: - //the node we are processing - Node d_node; - //the sub children for this node - std::vector< InstGenProcess > d_children; - std::vector< int > d_children_index; - std::map< int, int > d_children_map; - //the matches we have produced - std::vector< InstMatch > d_matches; - std::vector< Node > d_match_values; - //add match value - std::map< Node, inst::InstMatchTrie > d_inst_trie; - void addMatchValue( QuantifiersEngine* qe, Node f, Node val, InstMatch& m ); -private: - void calculateMatchesUninterpreted( QuantifiersEngine* qe, Node f, InstMatch& curr, Node n, int childIndex, bool isSelected ); - void calculateMatchesInterpreted( QuantifiersEngine* qe, Node f, InstMatch& curr, std::vector< Node >& terms, int argIndex ); -public: - InstGenProcess( Node n ); - virtual ~InstGenProcess(){} - - void calculateMatches( QuantifiersEngine* qe, Node f, std::vector< Node >& considerVal, bool useConsider ); - int getNumMatches() { return d_matches.size(); } - bool getMatch( EqualityQuery* q, int i, InstMatch& m ); - Node getMatchValue( int i ) { return d_match_values[i]; } -}; - -} -} -} - -#endif +/********************* */ +/*! \file inst_gen.h + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: Morgan Deters + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Inst Gen classes + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY__QUANTIFIERS__INST_GEN_H +#define __CVC4__THEORY__QUANTIFIERS__INST_GEN_H + +#include "theory/quantifiers_engine.h" +#include "theory/quantifiers/inst_match.h" + +namespace CVC4 { +namespace theory { +namespace quantifiers { + +class InstGenProcess +{ +private: + //the node we are processing + Node d_node; + //the sub children for this node + std::vector< InstGenProcess > d_children; + std::vector< int > d_children_index; + std::map< int, int > d_children_map; + //the matches we have produced + std::vector< InstMatch > d_matches; + std::vector< Node > d_match_values; + //add match value + std::map< Node, inst::InstMatchTrie > d_inst_trie; + void addMatchValue( QuantifiersEngine* qe, Node f, Node val, InstMatch& m ); +private: + void calculateMatchesUninterpreted( QuantifiersEngine* qe, Node f, InstMatch& curr, Node n, int childIndex, bool isSelected ); + void calculateMatchesInterpreted( QuantifiersEngine* qe, Node f, InstMatch& curr, std::vector< Node >& terms, int argIndex ); +public: + InstGenProcess( Node n ); + virtual ~InstGenProcess(){} + + void calculateMatches( QuantifiersEngine* qe, Node f, std::vector< Node >& considerVal, bool useConsider ); + int getNumMatches() { return d_matches.size(); } + bool getMatch( EqualityQuery* q, int i, InstMatch& m ); + Node getMatchValue( int i ) { return d_match_values[i]; } +}; + +} +} +} + +#endif diff --git a/src/theory/quantifiers/inst_match_generator.cpp b/src/theory/quantifiers/inst_match_generator.cpp old mode 100755 new mode 100644 index 7dc0058cf..e5922e77f --- a/src/theory/quantifiers/inst_match_generator.cpp +++ b/src/theory/quantifiers/inst_match_generator.cpp @@ -1,684 +1,685 @@ -/********************* */ -/*! \file inst_match_generator.cpp -** \verbatim -** Original author: ajreynol -** Major contributors: bobot -** Minor contributors (to current version): barrett, mdeters -** This file is part of the CVC4 prototype. -** Copyright (c) 2009-2012 New York University and The University of Iowa -** See the file COPYING in the top-level source directory for licensing -** information.\endverbatim -** -** \brief Implementation of inst match generator class -**/ - -#include "theory/quantifiers/inst_match_generator.h" -#include "theory/quantifiers/trigger.h" -#include "theory/quantifiers/term_database.h" -#include "theory/quantifiers/candidate_generator.h" -#include "theory/quantifiers_engine.h" - -using namespace std; -using namespace CVC4; -using namespace CVC4::kind; -using namespace CVC4::context; -using namespace CVC4::theory; - -namespace CVC4 { -namespace theory { -namespace inst { - - -InstMatchGenerator::InstMatchGenerator( Node pat, QuantifiersEngine* qe, int matchPolicy ) : d_matchPolicy( matchPolicy ){ - initializePattern( pat, qe ); -} - -InstMatchGenerator::InstMatchGenerator( std::vector< Node >& pats, QuantifiersEngine* qe, int matchPolicy ) : d_matchPolicy( matchPolicy ){ - if( pats.size()==1 ){ - initializePattern( pats[0], qe ); - }else{ - initializePatterns( pats, qe ); - } -} - -void InstMatchGenerator::setActiveAdd(){ - d_active_add = true; - if( !d_children.empty() ){ - d_children[d_children.size()-1]->setActiveAdd(); - } -} - -void InstMatchGenerator::initializePatterns( std::vector< Node >& pats, QuantifiersEngine* qe ){ - int childMatchPolicy = d_matchPolicy==MATCH_GEN_EFFICIENT_E_MATCH ? 0 : d_matchPolicy; - for( int i=0; i<(int)pats.size(); i++ ){ - d_children.push_back( new InstMatchGenerator( pats[i], qe, childMatchPolicy ) ); - } - d_pattern = Node::null(); - d_match_pattern = Node::null(); - d_cg = NULL; -} - -void InstMatchGenerator::initializePattern( Node pat, QuantifiersEngine* qe ){ - d_active_add = false; - Debug("inst-match-gen") << "Pattern term is " << pat << std::endl; - Assert( pat.hasAttribute(InstConstantAttribute()) ); - d_pattern = pat; - d_match_pattern = pat; - if( d_match_pattern.getKind()==NOT ){ - //we want to add the children of the NOT - d_match_pattern = d_pattern[0]; - } - if( d_match_pattern.getKind()==IFF || d_match_pattern.getKind()==EQUAL ){ - if( !d_match_pattern[0].hasAttribute(InstConstantAttribute()) ){ - Assert( d_match_pattern[1].hasAttribute(InstConstantAttribute()) ); - //swap sides - d_pattern = NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), d_match_pattern[1], d_match_pattern[0] ); - d_pattern = pat.getKind()==NOT ? d_pattern.notNode() : d_pattern; - if( pat.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching - d_match_pattern = d_match_pattern[1]; - }else{ - d_match_pattern = d_pattern[0][0]; - } - }else if( !d_match_pattern[1].hasAttribute(InstConstantAttribute()) ){ - Assert( d_match_pattern[0].hasAttribute(InstConstantAttribute()) ); - if( pat.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching - d_match_pattern = d_match_pattern[0]; - } - } - } - int childMatchPolicy = MATCH_GEN_DEFAULT; - for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){ - if( d_match_pattern[i].hasAttribute(InstConstantAttribute()) ){ - if( d_match_pattern[i].getKind()!=INST_CONSTANT ){ - d_children.push_back( new InstMatchGenerator( d_match_pattern[i], qe, childMatchPolicy ) ); - d_children_index.push_back( i ); - } - } - } - - Debug("inst-match-gen") << "Pattern is " << d_pattern << ", match pattern is " << d_match_pattern << std::endl; - - //create candidate generator - if( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF ){ - Assert( d_matchPolicy==MATCH_GEN_DEFAULT ); - //we will be producing candidates via literal matching heuristics - if( d_pattern.getKind()!=NOT ){ - //candidates will be all equalities - d_cg = new inst::CandidateGeneratorQELitEq( qe, d_match_pattern ); - }else{ - //candidates will be all disequalities - d_cg = new inst::CandidateGeneratorQELitDeq( qe, d_match_pattern ); - } - }else if( d_pattern.getKind()==EQUAL || d_pattern.getKind()==IFF || d_pattern.getKind()==NOT ){ - Assert( d_matchPolicy==MATCH_GEN_DEFAULT ); - if( d_pattern.getKind()==NOT ){ - Unimplemented("Disequal generator unimplemented"); - }else{ - Assert( Trigger::isAtomicTrigger( d_match_pattern ) ); - //we are matching only in a particular equivalence class - d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern.getOperator() ); - //store the equivalence class that we will call d_cg->reset( ... ) on - d_eq_class = d_pattern[1]; - } - }else if( Trigger::isAtomicTrigger( d_match_pattern ) ){ - //if( d_matchPolicy==MATCH_GEN_EFFICIENT_E_MATCH ){ - //Warning() << "Currently efficient e matching is not taken into account for quantifiers: " << d_pattern << std::endl; - //} - //we will be scanning lists trying to find d_match_pattern.getOperator() - d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern.getOperator() ); - }else{ - d_cg = new CandidateGeneratorQueue; - if( !Trigger::getPatternArithmetic( d_match_pattern.getAttribute(InstConstantAttribute()), d_match_pattern, d_arith_coeffs ) ){ - Debug("inst-match-gen") << "(?) Unknown matching pattern is " << d_match_pattern << std::endl; - //Warning() << "(?) Unknown matching pattern is " << d_match_pattern << std::endl; - d_matchPolicy = MATCH_GEN_INTERNAL_ERROR; - }else{ - Debug("matching-arith") << "Generated arithmetic pattern for " << d_match_pattern << ": " << std::endl; - for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ - Debug("matching-arith") << " " << it->first << " -> " << it->second << std::endl; - } - //we will treat this as match gen internal arithmetic - d_matchPolicy = MATCH_GEN_INTERNAL_ARITHMETIC; - } - } -} - -/** get match (not modulo equality) */ -bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngine* qe ){ - Debug("matching") << "Matching " << t << " against pattern " << d_match_pattern << " (" - << m << ")" << ", " << d_children.size() << std::endl; - Assert( !d_match_pattern.isNull() ); - if( qe->d_optMatchIgnoreModelBasis && t.getAttribute(ModelBasisAttribute()) ){ - return true; - }else if( d_matchPolicy==MATCH_GEN_INTERNAL_ARITHMETIC ){ - return getMatchArithmetic( t, m, qe ); - }else if( d_matchPolicy==MATCH_GEN_INTERNAL_ERROR ){ - return false; - }else{ - EqualityQuery* q = qe->getEqualityQuery(); - //add m to partial match vector - std::vector< InstMatch > partial; - partial.push_back( InstMatch( &m ) ); - //if t is null - Assert( !t.isNull() ); - Assert( !t.hasAttribute(InstConstantAttribute()) ); - Assert( t.getKind()==d_match_pattern.getKind() ); - 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 - for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){ - if( d_match_pattern[i].hasAttribute(InstConstantAttribute()) ){ - if( d_match_pattern[i].getKind()==INST_CONSTANT ){ - if( !partial[0].setMatch( q, d_match_pattern[i], t[i] ) ){ - //match is in conflict - Debug("matching-debug") << "Match in conflict " << t[i] << " and " - << d_match_pattern[i] << " because " - << partial[0].get(d_match_pattern[i]) - << std::endl; - Debug("matching-fail") << "Match fail: " << partial[0].get(d_match_pattern[i]) << " and " << t[i] << std::endl; - return false; - } - } - }else{ - if( !q->areEqual( d_match_pattern[i], t[i] ) ){ - Debug("matching-fail") << "Match fail arg: " << d_match_pattern[i] << " and " << t[i] << std::endl; - //ground arguments are not equal - return false; - } - } - } - //now, fit children into match - //we will be requesting candidates for matching terms for each child - std::vector< Node > reps; - for( int i=0; i<(int)d_children.size(); i++ ){ - Node rep = q->getRepresentative( t[ d_children_index[i] ] ); - reps.push_back( rep ); - d_children[i]->d_cg->reset( rep ); - } - - //combine child matches - int index = 0; - while( index>=0 && index<(int)d_children.size() ){ - partial.push_back( InstMatch( &partial[index] ) ); - if( d_children[index]->getNextMatch2( f, partial[index+1], qe ) ){ - index++; - }else{ - d_children[index]->d_cg->reset( reps[index] ); - partial.pop_back(); - if( !partial.empty() ){ - partial.pop_back(); - } - index--; - } - } - if( index>=0 ){ - if( d_children.empty() && d_active_add ){ - Trace("active-add") << "Active Adding instantiation " << partial.back() << std::endl; - bool succ = qe->addInstantiation( f, partial.back() ); - Trace("active-add") << "Success = " << succ << std::endl; - return succ; - }else{ - m = partial.back(); - return true; - } - }else{ - return false; - } - } -} - -bool InstMatchGenerator::getNextMatch2( Node f, InstMatch& m, QuantifiersEngine* qe, bool saveMatched ){ - bool success = false; - Node t; - do{ - //get the next candidate term t - t = d_cg->getNextCandidate(); - //if t not null, try to fit it into match m - if( !t.isNull() && t.getType()==d_match_pattern.getType() ){ - success = getMatch( f, t, m, qe ); - } - }while( !success && !t.isNull() ); - if (saveMatched) m.d_matched = t; - return success; -} - -bool InstMatchGenerator::getMatchArithmetic( Node t, InstMatch& m, QuantifiersEngine* qe ){ - Debug("matching-arith") << "Matching " << t << " " << d_match_pattern << std::endl; - if( !d_arith_coeffs.empty() ){ - NodeBuilder<> tb(kind::PLUS); - Node ic = Node::null(); - for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ - Debug("matching-arith") << it->first << " -> " << it->second << std::endl; - if( !it->first.isNull() ){ - if( m.find( it->first )==m.end() ){ - //see if we can choose this to set - if( ic.isNull() && ( it->second.isNull() || !it->first.getType().isInteger() ) ){ - ic = it->first; - } - }else{ - Debug("matching-arith") << "already set " << m.get( it->first ) << std::endl; - Node tm = m.get( it->first ); - if( !it->second.isNull() ){ - tm = NodeManager::currentNM()->mkNode( MULT, it->second, tm ); - } - tb << tm; - } - }else{ - tb << it->second; - } - } - if( !ic.isNull() ){ - Node tm; - if( tb.getNumChildren()==0 ){ - tm = t; - }else{ - tm = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb; - tm = NodeManager::currentNM()->mkNode( MINUS, t, tm ); - } - if( !d_arith_coeffs[ ic ].isNull() ){ - Assert( !ic.getType().isInteger() ); - Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_arith_coeffs[ ic ].getConst() ); - tm = NodeManager::currentNM()->mkNode( MULT, coeff, tm ); - } - m.set( ic, Rewriter::rewrite( tm )); - //set the rest to zeros - for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ - if( !it->first.isNull() ){ - if( m.find( it->first )==m.end() ){ - m.set( it->first, NodeManager::currentNM()->mkConst( Rational(0) ) ); - } - } - } - Debug("matching-arith") << "Setting " << ic << " to " << tm << std::endl; - return true; - }else{ - return false; - } - }else{ - return false; - } -} - - -/** reset instantiation round */ -void InstMatchGenerator::resetInstantiationRound( QuantifiersEngine* qe ){ - if( d_match_pattern.isNull() ){ - for( int i=0; i<(int)d_children.size(); i++ ){ - d_children[i]->resetInstantiationRound( qe ); - } - }else{ - if( d_cg ){ - d_cg->resetInstantiationRound(); - } - } -} - -void InstMatchGenerator::reset( Node eqc, QuantifiersEngine* qe ){ - if( d_match_pattern.isNull() ){ - for( int i=0; i<(int)d_children.size(); i++ ){ - d_children[i]->reset( eqc, qe ); - } - d_partial.clear(); - }else{ - if( !d_eq_class.isNull() ){ - //we have a specific equivalence class in mind - //we are producing matches for f(E) ~ t, where E is a non-ground vector of terms, and t is a ground term - //just look in equivalence class of the RHS - d_cg->reset( d_eq_class ); - }else{ - d_cg->reset( eqc ); - } - } -} - -bool InstMatchGenerator::getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ){ - m.d_matched = Node::null(); - if( d_match_pattern.isNull() ){ - int index = (int)d_partial.size(); - while( index>=0 && index<(int)d_children.size() ){ - if( index>0 ){ - d_partial.push_back( InstMatch( &d_partial[index-1] ) ); - }else{ - d_partial.push_back( InstMatch() ); - } - if( d_children[index]->getNextMatch( f, d_partial[index], qe ) ){ - index++; - }else{ - d_children[index]->reset( Node::null(), qe ); - d_partial.pop_back(); - if( !d_partial.empty() ){ - d_partial.pop_back(); - } - index--; - } - } - if( index>=0 ){ - m = d_partial.back(); - d_partial.pop_back(); - return true; - }else{ - return false; - } - }else{ - bool res = getNextMatch2( f, m, qe, true ); - Assert(!res || !m.d_matched.isNull()); - return res; - } -} - - - -int InstMatchGenerator::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ){ - //now, try to add instantiation for each match produced - int addedLemmas = 0; - InstMatch m; - while( getNextMatch( f, m, qe ) ){ - //if( d_active_add ){ - // std::cout << "should not add at top level." << std::endl; - //} - if( !d_active_add ){ - //m.makeInternal( d_quantEngine->getEqualityQuery() ); - m.add( baseMatch ); - if( qe->addInstantiation( f, m ) ){ - addedLemmas++; - if( qe->d_optInstLimitActive && qe->d_optInstLimit<=0 ){ - return addedLemmas; - } - } - m.clear(); - } - } - //return number of lemmas added - return addedLemmas; -} - -int InstMatchGenerator::addTerm( Node f, Node t, QuantifiersEngine* qe ){ - Assert( options::eagerInstQuant() ); - if( !d_match_pattern.isNull() ){ - InstMatch m; - if( getMatch( f, t, m, qe ) ){ - if( qe->addInstantiation( f, m ) ){ - return 1; - } - } - }else{ - for( int i=0; i<(int)d_children.size(); i++ ){ - d_children[i]->addTerm( f, t, qe ); - } - } - return 0; -} - -/** constructors */ -InstMatchGeneratorMulti::InstMatchGeneratorMulti( Node f, std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption ) : -d_f( f ){ - Debug("smart-multi-trigger") << "Making smart multi-trigger for " << f << std::endl; - std::map< Node, std::vector< Node > > var_contains; - qe->getTermDatabase()->getVarContains( f, pats, var_contains ); - //convert to indicies - for( std::map< Node, std::vector< Node > >::iterator it = var_contains.begin(); it != var_contains.end(); ++it ){ - Debug("smart-multi-trigger") << "Pattern " << it->first << " contains: "; - for( int i=0; i<(int)it->second.size(); i++ ){ - Debug("smart-multi-trigger") << it->second[i] << " "; - int index = it->second[i].getAttribute(InstVarNumAttribute()); - d_var_contains[ it->first ].push_back( index ); - d_var_to_node[ index ].push_back( it->first ); - } - Debug("smart-multi-trigger") << std::endl; - } - for( int i=0; i<(int)pats.size(); i++ ){ - Node n = pats[i]; - //make the match generator - d_children.push_back( new InstMatchGenerator( n, qe, matchOption ) ); - //compute unique/shared variables - std::vector< int > unique_vars; - std::map< int, bool > shared_vars; - int numSharedVars = 0; - for( int j=0; j<(int)d_var_contains[n].size(); j++ ){ - if( d_var_to_node[ d_var_contains[n][j] ].size()==1 ){ - Debug("smart-multi-trigger") << "Var " << d_var_contains[n][j] << " is unique to " << pats[i] << std::endl; - unique_vars.push_back( d_var_contains[n][j] ); - }else{ - shared_vars[ d_var_contains[n][j] ] = true; - numSharedVars++; - } - } - //we use the latest shared variables, then unique variables - std::vector< int > vars; - int index = i==0 ? (int)(pats.size()-1) : (i-1); - while( numSharedVars>0 && index!=i ){ - for( std::map< int, bool >::iterator it = shared_vars.begin(); it != shared_vars.end(); ++it ){ - if( it->second ){ - if( std::find( d_var_contains[ pats[index] ].begin(), d_var_contains[ pats[index] ].end(), it->first )!= - d_var_contains[ pats[index] ].end() ){ - vars.push_back( it->first ); - shared_vars[ it->first ] = false; - numSharedVars--; - } - } - } - index = index==0 ? (int)(pats.size()-1) : (index-1); - } - vars.insert( vars.end(), unique_vars.begin(), unique_vars.end() ); - Debug("smart-multi-trigger") << " Index[" << i << "]: "; - for( int i=0; i<(int)vars.size(); i++ ){ - Debug("smart-multi-trigger") << vars[i] << " "; - } - Debug("smart-multi-trigger") << std::endl; - //make ordered inst match trie - InstMatchTrie::ImtIndexOrder* imtio = new InstMatchTrie::ImtIndexOrder; - imtio->d_order.insert( imtio->d_order.begin(), vars.begin(), vars.end() ); - d_children_trie.push_back( InstMatchTrieOrdered( imtio ) ); - } - -} - -/** 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++ ){ - 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++ ){ - d_children[i]->reset( eqc, qe ); - } -} - -int InstMatchGeneratorMulti::addInstantiations( Node f, 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++ ){ - Debug("smart-multi-trigger") << "Calculate matches " << i << std::endl; - std::vector< InstMatch > newMatches; - InstMatch m; - while( d_children[i]->getNextMatch( f, m, qe ) ){ - m.makeRepresentative( qe ); - newMatches.push_back( InstMatch( &m ) ); - m.clear(); - } - for( int j=0; j<(int)newMatches.size(); j++ ){ - processNewMatch( qe, newMatches[j], i, addedLemmas ); - } - } - return addedLemmas; -} - -void InstMatchGeneratorMulti::processNewMatch( QuantifiersEngine* qe, InstMatch& m, int fromChildIndex, int& addedLemmas ){ - //see if these produce new matches - d_children_trie[fromChildIndex].addInstMatch( qe, d_f, m, true ); - //possibly only do the following if we know that new matches will be produced? - //the issue is that instantiations are filtered in quantifiers engine, and so there is no guarentee that - // we can safely skip the following lines, even when we have already produced this match. - Debug("smart-multi-trigger") << "Child " << fromChildIndex << " produced match " << m << std::endl; - //process new instantiations - int childIndex = (fromChildIndex+1)%(int)d_children.size(); - std::vector< IndexedTrie > unique_var_tries; - processNewInstantiations( qe, m, addedLemmas, d_children_trie[childIndex].getTrie(), - unique_var_tries, 0, childIndex, fromChildIndex, true ); -} - -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 ){ - if( childIndex==endChildIndex ){ - //now, process unique variables - processNewInstantiations2( qe, m, addedLemmas, unique_var_tries, 0 ); - }else if( trieIndex<(int)d_children_trie[childIndex].getOrdering()->d_order.size() ){ - int curr_index = d_children_trie[childIndex].getOrdering()->d_order[trieIndex]; - Node curr_ic = qe->getTermDatabase()->getInstantiationConstant( d_f, curr_index ); - if( m.find( curr_ic )==m.end() ){ - //if( d_var_to_node[ curr_index ].size()==1 ){ //FIXME - // //unique variable(s), defer calculation - // unique_var_tries.push_back( IndexedTrie( std::pair< int, int >( childIndex, trieIndex ), tr ) ); - // int newChildIndex = (childIndex+1)%(int)d_children.size(); - // processNewInstantiations( qe, m, d_children_trie[newChildIndex].getTrie(), unique_var_tries, - // 0, newChildIndex, endChildIndex, modEq ); - //}else{ - //shared and non-set variable, add to InstMatch - for( std::map< Node, InstMatchTrie >::iterator it = tr->d_data.begin(); it != tr->d_data.end(); ++it ){ - InstMatch mn( &m ); - mn.set( curr_ic, it->first); - processNewInstantiations( qe, mn, addedLemmas, &(it->second), unique_var_tries, - trieIndex+1, childIndex, endChildIndex, modEq ); - } - //} - }else{ - //shared and set variable, try to merge - Node n = m.get( curr_ic ); - std::map< Node, InstMatchTrie >::iterator it = tr->d_data.find( n ); - if( it!=tr->d_data.end() ){ - processNewInstantiations( qe, m, addedLemmas, &(it->second), unique_var_tries, - trieIndex+1, childIndex, endChildIndex, modEq ); - } - if( modEq ){ - //check modulo equality for other possible instantiations - if( qe->getEqualityQuery()->getEngine()->hasTerm( n ) ){ - eq::EqClassIterator eqc( qe->getEqualityQuery()->getEngine()->getRepresentative( n ), - qe->getEqualityQuery()->getEngine() ); - while( !eqc.isFinished() ){ - Node en = (*eqc); - if( en!=n ){ - std::map< Node, InstMatchTrie >::iterator itc = tr->d_data.find( en ); - if( itc!=tr->d_data.end() ){ - processNewInstantiations( qe, m, addedLemmas, &(itc->second), unique_var_tries, - trieIndex+1, childIndex, endChildIndex, modEq ); - } - } - ++eqc; - } - } - } - } - }else{ - int newChildIndex = (childIndex+1)%(int)d_children.size(); - processNewInstantiations( qe, m, addedLemmas, d_children_trie[newChildIndex].getTrie(), unique_var_tries, - 0, newChildIndex, endChildIndex, modEq ); - } -} - -void InstMatchGeneratorMulti::processNewInstantiations2( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, - std::vector< IndexedTrie >& unique_var_tries, - int uvtIndex, InstMatchTrie* tr, int trieIndex ){ - if( uvtIndex<(int)unique_var_tries.size() ){ - int childIndex = unique_var_tries[uvtIndex].first.first; - if( !tr ){ - tr = unique_var_tries[uvtIndex].second; - trieIndex = unique_var_tries[uvtIndex].first.second; - } - if( trieIndex<(int)d_children_trie[childIndex].getOrdering()->d_order.size() ){ - int curr_index = d_children_trie[childIndex].getOrdering()->d_order[trieIndex]; - Node curr_ic = qe->getTermDatabase()->getInstantiationConstant( d_f, curr_index ); - //unique non-set variable, add to InstMatch - for( std::map< Node, InstMatchTrie >::iterator it = tr->d_data.begin(); it != tr->d_data.end(); ++it ){ - InstMatch mn( &m ); - mn.set( curr_ic, it->first); - processNewInstantiations2( qe, mn, addedLemmas, unique_var_tries, uvtIndex, &(it->second), trieIndex+1 ); - } - }else{ - processNewInstantiations2( qe, m, addedLemmas, unique_var_tries, uvtIndex+1 ); - } - }else{ - //m is an instantiation - if( qe->addInstantiation( d_f, m ) ){ - addedLemmas++; - Debug("smart-multi-trigger") << "-> Produced instantiation " << m << std::endl; - } - } -} - -int InstMatchGeneratorMulti::addTerm( Node f, Node t, QuantifiersEngine* qe ){ - Assert( options::eagerInstQuant() ); - int addedLemmas = 0; - for( int i=0; i<(int)d_children.size(); i++ ){ - if( ((InstMatchGenerator*)d_children[i])->d_match_pattern.getOperator()==t.getOperator() ){ - InstMatch m; - //if it produces a match, then process it with the rest - if( ((InstMatchGenerator*)d_children[i])->getMatch( f, t, m, qe ) ){ - processNewMatch( qe, m, i, addedLemmas ); - } - } - } - return addedLemmas; -} - -int InstMatchGeneratorSimple::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ){ - InstMatch m; - m.add( baseMatch ); - int addedLemmas = 0; - if( d_match_pattern.getType()==NodeManager::currentNM()->booleanType() ){ - for( int i=0; i<2; i++ ){ - addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_pred_map_trie[i][ d_match_pattern.getOperator() ]) ); - } - }else{ - addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_func_map_trie[ d_match_pattern.getOperator() ]) ); - } - return addedLemmas; -} - -void InstMatchGeneratorSimple::addInstantiations( InstMatch& m, QuantifiersEngine* qe, int& addedLemmas, int argIndex, quantifiers::TermArgTrie* tat ){ - if( argIndex==(int)d_match_pattern.getNumChildren() ){ - //m is an instantiation - if( qe->addInstantiation( d_f, m ) ){ - addedLemmas++; - Debug("simple-multi-trigger") << "-> Produced instantiation " << m << std::endl; - } - }else{ - if( d_match_pattern[argIndex].getKind()==INST_CONSTANT ){ - Node ic = d_match_pattern[argIndex]; - for( std::map< Node, quantifiers::TermArgTrie >::iterator it = tat->d_data.begin(); it != tat->d_data.end(); ++it ){ - Node t = it->first; - if( ( m.get( ic ).isNull() || m.get( ic )==t ) && ic.getType()==t.getType() ){ - Node prev = m.get( ic ); - m.set( ic, t); - addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) ); - m.set( ic, prev); - } - } - }else{ - Node r = qe->getEqualityQuery()->getRepresentative( d_match_pattern[argIndex] ); - std::map< Node, quantifiers::TermArgTrie >::iterator it = tat->d_data.find( r ); - if( it!=tat->d_data.end() ){ - addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) ); - } - } - } -} - -int InstMatchGeneratorSimple::addTerm( Node f, Node t, QuantifiersEngine* qe ){ - Assert( options::eagerInstQuant() ); - InstMatch m; - for( int i=0; i<(int)t.getNumChildren(); i++ ){ - if( d_match_pattern[i].getKind()==INST_CONSTANT ){ - m.set(d_match_pattern[i], t[i]); - }else if( !qe->getEqualityQuery()->areEqual( d_match_pattern[i], t[i] ) ){ - return 0; - } - } - return qe->addInstantiation( f, m ) ? 1 : 0; -} - -}/* CVC4::theory::inst namespace */ -}/* CVC4::theory namespace */ -}/* CVC4 namespace */ +/********************* */ +/*! \file inst_match_generator.cpp + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: Morgan Deters + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** [[ Add lengthier description here ]] + ** \todo document this file +**/ + +#include "theory/quantifiers/inst_match_generator.h" +#include "theory/quantifiers/trigger.h" +#include "theory/quantifiers/term_database.h" +#include "theory/quantifiers/candidate_generator.h" +#include "theory/quantifiers_engine.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; + +namespace CVC4 { +namespace theory { +namespace inst { + + +InstMatchGenerator::InstMatchGenerator( Node pat, QuantifiersEngine* qe, int matchPolicy ) : d_matchPolicy( matchPolicy ){ + initializePattern( pat, qe ); +} + +InstMatchGenerator::InstMatchGenerator( std::vector< Node >& pats, QuantifiersEngine* qe, int matchPolicy ) : d_matchPolicy( matchPolicy ){ + if( pats.size()==1 ){ + initializePattern( pats[0], qe ); + }else{ + initializePatterns( pats, qe ); + } +} + +void InstMatchGenerator::setActiveAdd(){ + d_active_add = true; + if( !d_children.empty() ){ + d_children[d_children.size()-1]->setActiveAdd(); + } +} + +void InstMatchGenerator::initializePatterns( std::vector< Node >& pats, QuantifiersEngine* qe ){ + int childMatchPolicy = d_matchPolicy==MATCH_GEN_EFFICIENT_E_MATCH ? 0 : d_matchPolicy; + for( int i=0; i<(int)pats.size(); i++ ){ + d_children.push_back( new InstMatchGenerator( pats[i], qe, childMatchPolicy ) ); + } + d_pattern = Node::null(); + d_match_pattern = Node::null(); + d_cg = NULL; +} + +void InstMatchGenerator::initializePattern( Node pat, QuantifiersEngine* qe ){ + d_active_add = false; + Debug("inst-match-gen") << "Pattern term is " << pat << std::endl; + Assert( pat.hasAttribute(InstConstantAttribute()) ); + d_pattern = pat; + d_match_pattern = pat; + if( d_match_pattern.getKind()==NOT ){ + //we want to add the children of the NOT + d_match_pattern = d_pattern[0]; + } + if( d_match_pattern.getKind()==IFF || d_match_pattern.getKind()==EQUAL ){ + if( !d_match_pattern[0].hasAttribute(InstConstantAttribute()) ){ + Assert( d_match_pattern[1].hasAttribute(InstConstantAttribute()) ); + //swap sides + d_pattern = NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), d_match_pattern[1], d_match_pattern[0] ); + d_pattern = pat.getKind()==NOT ? d_pattern.notNode() : d_pattern; + if( pat.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching + d_match_pattern = d_match_pattern[1]; + }else{ + d_match_pattern = d_pattern[0][0]; + } + }else if( !d_match_pattern[1].hasAttribute(InstConstantAttribute()) ){ + Assert( d_match_pattern[0].hasAttribute(InstConstantAttribute()) ); + if( pat.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching + d_match_pattern = d_match_pattern[0]; + } + } + } + int childMatchPolicy = MATCH_GEN_DEFAULT; + for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){ + if( d_match_pattern[i].hasAttribute(InstConstantAttribute()) ){ + if( d_match_pattern[i].getKind()!=INST_CONSTANT ){ + d_children.push_back( new InstMatchGenerator( d_match_pattern[i], qe, childMatchPolicy ) ); + d_children_index.push_back( i ); + } + } + } + + Debug("inst-match-gen") << "Pattern is " << d_pattern << ", match pattern is " << d_match_pattern << std::endl; + + //create candidate generator + if( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF ){ + Assert( d_matchPolicy==MATCH_GEN_DEFAULT ); + //we will be producing candidates via literal matching heuristics + if( d_pattern.getKind()!=NOT ){ + //candidates will be all equalities + d_cg = new inst::CandidateGeneratorQELitEq( qe, d_match_pattern ); + }else{ + //candidates will be all disequalities + d_cg = new inst::CandidateGeneratorQELitDeq( qe, d_match_pattern ); + } + }else if( d_pattern.getKind()==EQUAL || d_pattern.getKind()==IFF || d_pattern.getKind()==NOT ){ + Assert( d_matchPolicy==MATCH_GEN_DEFAULT ); + if( d_pattern.getKind()==NOT ){ + Unimplemented("Disequal generator unimplemented"); + }else{ + Assert( Trigger::isAtomicTrigger( d_match_pattern ) ); + //we are matching only in a particular equivalence class + d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern.getOperator() ); + //store the equivalence class that we will call d_cg->reset( ... ) on + d_eq_class = d_pattern[1]; + } + }else if( Trigger::isAtomicTrigger( d_match_pattern ) ){ + //if( d_matchPolicy==MATCH_GEN_EFFICIENT_E_MATCH ){ + //Warning() << "Currently efficient e matching is not taken into account for quantifiers: " << d_pattern << std::endl; + //} + //we will be scanning lists trying to find d_match_pattern.getOperator() + d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern.getOperator() ); + }else{ + d_cg = new CandidateGeneratorQueue; + if( !Trigger::getPatternArithmetic( d_match_pattern.getAttribute(InstConstantAttribute()), d_match_pattern, d_arith_coeffs ) ){ + Debug("inst-match-gen") << "(?) Unknown matching pattern is " << d_match_pattern << std::endl; + //Warning() << "(?) Unknown matching pattern is " << d_match_pattern << std::endl; + d_matchPolicy = MATCH_GEN_INTERNAL_ERROR; + }else{ + Debug("matching-arith") << "Generated arithmetic pattern for " << d_match_pattern << ": " << std::endl; + for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ + Debug("matching-arith") << " " << it->first << " -> " << it->second << std::endl; + } + //we will treat this as match gen internal arithmetic + d_matchPolicy = MATCH_GEN_INTERNAL_ARITHMETIC; + } + } +} + +/** get match (not modulo equality) */ +bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngine* qe ){ + Debug("matching") << "Matching " << t << " against pattern " << d_match_pattern << " (" + << m << ")" << ", " << d_children.size() << std::endl; + Assert( !d_match_pattern.isNull() ); + if( qe->d_optMatchIgnoreModelBasis && t.getAttribute(ModelBasisAttribute()) ){ + return true; + }else if( d_matchPolicy==MATCH_GEN_INTERNAL_ARITHMETIC ){ + return getMatchArithmetic( t, m, qe ); + }else if( d_matchPolicy==MATCH_GEN_INTERNAL_ERROR ){ + return false; + }else{ + EqualityQuery* q = qe->getEqualityQuery(); + //add m to partial match vector + std::vector< InstMatch > partial; + partial.push_back( InstMatch( &m ) ); + //if t is null + Assert( !t.isNull() ); + Assert( !t.hasAttribute(InstConstantAttribute()) ); + Assert( t.getKind()==d_match_pattern.getKind() ); + 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 + for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){ + if( d_match_pattern[i].hasAttribute(InstConstantAttribute()) ){ + if( d_match_pattern[i].getKind()==INST_CONSTANT ){ + if( !partial[0].setMatch( q, d_match_pattern[i], t[i] ) ){ + //match is in conflict + Debug("matching-debug") << "Match in conflict " << t[i] << " and " + << d_match_pattern[i] << " because " + << partial[0].get(d_match_pattern[i]) + << std::endl; + Debug("matching-fail") << "Match fail: " << partial[0].get(d_match_pattern[i]) << " and " << t[i] << std::endl; + return false; + } + } + }else{ + if( !q->areEqual( d_match_pattern[i], t[i] ) ){ + Debug("matching-fail") << "Match fail arg: " << d_match_pattern[i] << " and " << t[i] << std::endl; + //ground arguments are not equal + return false; + } + } + } + //now, fit children into match + //we will be requesting candidates for matching terms for each child + std::vector< Node > reps; + for( int i=0; i<(int)d_children.size(); i++ ){ + Node rep = q->getRepresentative( t[ d_children_index[i] ] ); + reps.push_back( rep ); + d_children[i]->d_cg->reset( rep ); + } + + //combine child matches + int index = 0; + while( index>=0 && index<(int)d_children.size() ){ + partial.push_back( InstMatch( &partial[index] ) ); + if( d_children[index]->getNextMatch2( f, partial[index+1], qe ) ){ + index++; + }else{ + d_children[index]->d_cg->reset( reps[index] ); + partial.pop_back(); + if( !partial.empty() ){ + partial.pop_back(); + } + index--; + } + } + if( index>=0 ){ + if( d_children.empty() && d_active_add ){ + Trace("active-add") << "Active Adding instantiation " << partial.back() << std::endl; + bool succ = qe->addInstantiation( f, partial.back() ); + Trace("active-add") << "Success = " << succ << std::endl; + return succ; + }else{ + m = partial.back(); + return true; + } + }else{ + return false; + } + } +} + +bool InstMatchGenerator::getNextMatch2( Node f, InstMatch& m, QuantifiersEngine* qe, bool saveMatched ){ + bool success = false; + Node t; + do{ + //get the next candidate term t + t = d_cg->getNextCandidate(); + //if t not null, try to fit it into match m + if( !t.isNull() && t.getType()==d_match_pattern.getType() ){ + success = getMatch( f, t, m, qe ); + } + }while( !success && !t.isNull() ); + if (saveMatched) m.d_matched = t; + return success; +} + +bool InstMatchGenerator::getMatchArithmetic( Node t, InstMatch& m, QuantifiersEngine* qe ){ + Debug("matching-arith") << "Matching " << t << " " << d_match_pattern << std::endl; + if( !d_arith_coeffs.empty() ){ + NodeBuilder<> tb(kind::PLUS); + Node ic = Node::null(); + for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ + Debug("matching-arith") << it->first << " -> " << it->second << std::endl; + if( !it->first.isNull() ){ + if( m.find( it->first )==m.end() ){ + //see if we can choose this to set + if( ic.isNull() && ( it->second.isNull() || !it->first.getType().isInteger() ) ){ + ic = it->first; + } + }else{ + Debug("matching-arith") << "already set " << m.get( it->first ) << std::endl; + Node tm = m.get( it->first ); + if( !it->second.isNull() ){ + tm = NodeManager::currentNM()->mkNode( MULT, it->second, tm ); + } + tb << tm; + } + }else{ + tb << it->second; + } + } + if( !ic.isNull() ){ + Node tm; + if( tb.getNumChildren()==0 ){ + tm = t; + }else{ + tm = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb; + tm = NodeManager::currentNM()->mkNode( MINUS, t, tm ); + } + if( !d_arith_coeffs[ ic ].isNull() ){ + Assert( !ic.getType().isInteger() ); + Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_arith_coeffs[ ic ].getConst() ); + tm = NodeManager::currentNM()->mkNode( MULT, coeff, tm ); + } + m.set( ic, Rewriter::rewrite( tm )); + //set the rest to zeros + for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ + if( !it->first.isNull() ){ + if( m.find( it->first )==m.end() ){ + m.set( it->first, NodeManager::currentNM()->mkConst( Rational(0) ) ); + } + } + } + Debug("matching-arith") << "Setting " << ic << " to " << tm << std::endl; + return true; + }else{ + return false; + } + }else{ + return false; + } +} + + +/** reset instantiation round */ +void InstMatchGenerator::resetInstantiationRound( QuantifiersEngine* qe ){ + if( d_match_pattern.isNull() ){ + for( int i=0; i<(int)d_children.size(); i++ ){ + d_children[i]->resetInstantiationRound( qe ); + } + }else{ + if( d_cg ){ + d_cg->resetInstantiationRound(); + } + } +} + +void InstMatchGenerator::reset( Node eqc, QuantifiersEngine* qe ){ + if( d_match_pattern.isNull() ){ + for( int i=0; i<(int)d_children.size(); i++ ){ + d_children[i]->reset( eqc, qe ); + } + d_partial.clear(); + }else{ + if( !d_eq_class.isNull() ){ + //we have a specific equivalence class in mind + //we are producing matches for f(E) ~ t, where E is a non-ground vector of terms, and t is a ground term + //just look in equivalence class of the RHS + d_cg->reset( d_eq_class ); + }else{ + d_cg->reset( eqc ); + } + } +} + +bool InstMatchGenerator::getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ){ + m.d_matched = Node::null(); + if( d_match_pattern.isNull() ){ + int index = (int)d_partial.size(); + while( index>=0 && index<(int)d_children.size() ){ + if( index>0 ){ + d_partial.push_back( InstMatch( &d_partial[index-1] ) ); + }else{ + d_partial.push_back( InstMatch() ); + } + if( d_children[index]->getNextMatch( f, d_partial[index], qe ) ){ + index++; + }else{ + d_children[index]->reset( Node::null(), qe ); + d_partial.pop_back(); + if( !d_partial.empty() ){ + d_partial.pop_back(); + } + index--; + } + } + if( index>=0 ){ + m = d_partial.back(); + d_partial.pop_back(); + return true; + }else{ + return false; + } + }else{ + bool res = getNextMatch2( f, m, qe, true ); + Assert(!res || !m.d_matched.isNull()); + return res; + } +} + + + +int InstMatchGenerator::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ){ + //now, try to add instantiation for each match produced + int addedLemmas = 0; + InstMatch m; + while( getNextMatch( f, m, qe ) ){ + //if( d_active_add ){ + // std::cout << "should not add at top level." << std::endl; + //} + if( !d_active_add ){ + //m.makeInternal( d_quantEngine->getEqualityQuery() ); + m.add( baseMatch ); + if( qe->addInstantiation( f, m ) ){ + addedLemmas++; + if( qe->d_optInstLimitActive && qe->d_optInstLimit<=0 ){ + return addedLemmas; + } + } + m.clear(); + } + } + //return number of lemmas added + return addedLemmas; +} + +int InstMatchGenerator::addTerm( Node f, Node t, QuantifiersEngine* qe ){ + Assert( options::eagerInstQuant() ); + if( !d_match_pattern.isNull() ){ + InstMatch m; + if( getMatch( f, t, m, qe ) ){ + if( qe->addInstantiation( f, m ) ){ + return 1; + } + } + }else{ + for( int i=0; i<(int)d_children.size(); i++ ){ + d_children[i]->addTerm( f, t, qe ); + } + } + return 0; +} + +/** constructors */ +InstMatchGeneratorMulti::InstMatchGeneratorMulti( Node f, std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption ) : +d_f( f ){ + Debug("smart-multi-trigger") << "Making smart multi-trigger for " << f << std::endl; + std::map< Node, std::vector< Node > > var_contains; + qe->getTermDatabase()->getVarContains( f, pats, var_contains ); + //convert to indicies + for( std::map< Node, std::vector< Node > >::iterator it = var_contains.begin(); it != var_contains.end(); ++it ){ + Debug("smart-multi-trigger") << "Pattern " << it->first << " contains: "; + for( int i=0; i<(int)it->second.size(); i++ ){ + Debug("smart-multi-trigger") << it->second[i] << " "; + int index = it->second[i].getAttribute(InstVarNumAttribute()); + d_var_contains[ it->first ].push_back( index ); + d_var_to_node[ index ].push_back( it->first ); + } + Debug("smart-multi-trigger") << std::endl; + } + for( int i=0; i<(int)pats.size(); i++ ){ + Node n = pats[i]; + //make the match generator + d_children.push_back( new InstMatchGenerator( n, qe, matchOption ) ); + //compute unique/shared variables + std::vector< int > unique_vars; + std::map< int, bool > shared_vars; + int numSharedVars = 0; + for( int j=0; j<(int)d_var_contains[n].size(); j++ ){ + if( d_var_to_node[ d_var_contains[n][j] ].size()==1 ){ + Debug("smart-multi-trigger") << "Var " << d_var_contains[n][j] << " is unique to " << pats[i] << std::endl; + unique_vars.push_back( d_var_contains[n][j] ); + }else{ + shared_vars[ d_var_contains[n][j] ] = true; + numSharedVars++; + } + } + //we use the latest shared variables, then unique variables + std::vector< int > vars; + int index = i==0 ? (int)(pats.size()-1) : (i-1); + while( numSharedVars>0 && index!=i ){ + for( std::map< int, bool >::iterator it = shared_vars.begin(); it != shared_vars.end(); ++it ){ + if( it->second ){ + if( std::find( d_var_contains[ pats[index] ].begin(), d_var_contains[ pats[index] ].end(), it->first )!= + d_var_contains[ pats[index] ].end() ){ + vars.push_back( it->first ); + shared_vars[ it->first ] = false; + numSharedVars--; + } + } + } + index = index==0 ? (int)(pats.size()-1) : (index-1); + } + vars.insert( vars.end(), unique_vars.begin(), unique_vars.end() ); + Debug("smart-multi-trigger") << " Index[" << i << "]: "; + for( int i=0; i<(int)vars.size(); i++ ){ + Debug("smart-multi-trigger") << vars[i] << " "; + } + Debug("smart-multi-trigger") << std::endl; + //make ordered inst match trie + InstMatchTrie::ImtIndexOrder* imtio = new InstMatchTrie::ImtIndexOrder; + imtio->d_order.insert( imtio->d_order.begin(), vars.begin(), vars.end() ); + d_children_trie.push_back( InstMatchTrieOrdered( imtio ) ); + } + +} + +/** 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++ ){ + 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++ ){ + d_children[i]->reset( eqc, qe ); + } +} + +int InstMatchGeneratorMulti::addInstantiations( Node f, 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++ ){ + Debug("smart-multi-trigger") << "Calculate matches " << i << std::endl; + std::vector< InstMatch > newMatches; + InstMatch m; + while( d_children[i]->getNextMatch( f, m, qe ) ){ + m.makeRepresentative( qe ); + newMatches.push_back( InstMatch( &m ) ); + m.clear(); + } + for( int j=0; j<(int)newMatches.size(); j++ ){ + processNewMatch( qe, newMatches[j], i, addedLemmas ); + } + } + return addedLemmas; +} + +void InstMatchGeneratorMulti::processNewMatch( QuantifiersEngine* qe, InstMatch& m, int fromChildIndex, int& addedLemmas ){ + //see if these produce new matches + d_children_trie[fromChildIndex].addInstMatch( qe, d_f, m, true ); + //possibly only do the following if we know that new matches will be produced? + //the issue is that instantiations are filtered in quantifiers engine, and so there is no guarentee that + // we can safely skip the following lines, even when we have already produced this match. + Debug("smart-multi-trigger") << "Child " << fromChildIndex << " produced match " << m << std::endl; + //process new instantiations + int childIndex = (fromChildIndex+1)%(int)d_children.size(); + std::vector< IndexedTrie > unique_var_tries; + processNewInstantiations( qe, m, addedLemmas, d_children_trie[childIndex].getTrie(), + unique_var_tries, 0, childIndex, fromChildIndex, true ); +} + +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 ){ + if( childIndex==endChildIndex ){ + //now, process unique variables + processNewInstantiations2( qe, m, addedLemmas, unique_var_tries, 0 ); + }else if( trieIndex<(int)d_children_trie[childIndex].getOrdering()->d_order.size() ){ + int curr_index = d_children_trie[childIndex].getOrdering()->d_order[trieIndex]; + Node curr_ic = qe->getTermDatabase()->getInstantiationConstant( d_f, curr_index ); + if( m.find( curr_ic )==m.end() ){ + //if( d_var_to_node[ curr_index ].size()==1 ){ //FIXME + // //unique variable(s), defer calculation + // unique_var_tries.push_back( IndexedTrie( std::pair< int, int >( childIndex, trieIndex ), tr ) ); + // int newChildIndex = (childIndex+1)%(int)d_children.size(); + // processNewInstantiations( qe, m, d_children_trie[newChildIndex].getTrie(), unique_var_tries, + // 0, newChildIndex, endChildIndex, modEq ); + //}else{ + //shared and non-set variable, add to InstMatch + for( std::map< Node, InstMatchTrie >::iterator it = tr->d_data.begin(); it != tr->d_data.end(); ++it ){ + InstMatch mn( &m ); + mn.set( curr_ic, it->first); + processNewInstantiations( qe, mn, addedLemmas, &(it->second), unique_var_tries, + trieIndex+1, childIndex, endChildIndex, modEq ); + } + //} + }else{ + //shared and set variable, try to merge + Node n = m.get( curr_ic ); + std::map< Node, InstMatchTrie >::iterator it = tr->d_data.find( n ); + if( it!=tr->d_data.end() ){ + processNewInstantiations( qe, m, addedLemmas, &(it->second), unique_var_tries, + trieIndex+1, childIndex, endChildIndex, modEq ); + } + if( modEq ){ + //check modulo equality for other possible instantiations + if( qe->getEqualityQuery()->getEngine()->hasTerm( n ) ){ + eq::EqClassIterator eqc( qe->getEqualityQuery()->getEngine()->getRepresentative( n ), + qe->getEqualityQuery()->getEngine() ); + while( !eqc.isFinished() ){ + Node en = (*eqc); + if( en!=n ){ + std::map< Node, InstMatchTrie >::iterator itc = tr->d_data.find( en ); + if( itc!=tr->d_data.end() ){ + processNewInstantiations( qe, m, addedLemmas, &(itc->second), unique_var_tries, + trieIndex+1, childIndex, endChildIndex, modEq ); + } + } + ++eqc; + } + } + } + } + }else{ + int newChildIndex = (childIndex+1)%(int)d_children.size(); + processNewInstantiations( qe, m, addedLemmas, d_children_trie[newChildIndex].getTrie(), unique_var_tries, + 0, newChildIndex, endChildIndex, modEq ); + } +} + +void InstMatchGeneratorMulti::processNewInstantiations2( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, + std::vector< IndexedTrie >& unique_var_tries, + int uvtIndex, InstMatchTrie* tr, int trieIndex ){ + if( uvtIndex<(int)unique_var_tries.size() ){ + int childIndex = unique_var_tries[uvtIndex].first.first; + if( !tr ){ + tr = unique_var_tries[uvtIndex].second; + trieIndex = unique_var_tries[uvtIndex].first.second; + } + if( trieIndex<(int)d_children_trie[childIndex].getOrdering()->d_order.size() ){ + int curr_index = d_children_trie[childIndex].getOrdering()->d_order[trieIndex]; + Node curr_ic = qe->getTermDatabase()->getInstantiationConstant( d_f, curr_index ); + //unique non-set variable, add to InstMatch + for( std::map< Node, InstMatchTrie >::iterator it = tr->d_data.begin(); it != tr->d_data.end(); ++it ){ + InstMatch mn( &m ); + mn.set( curr_ic, it->first); + processNewInstantiations2( qe, mn, addedLemmas, unique_var_tries, uvtIndex, &(it->second), trieIndex+1 ); + } + }else{ + processNewInstantiations2( qe, m, addedLemmas, unique_var_tries, uvtIndex+1 ); + } + }else{ + //m is an instantiation + if( qe->addInstantiation( d_f, m ) ){ + addedLemmas++; + Debug("smart-multi-trigger") << "-> Produced instantiation " << m << std::endl; + } + } +} + +int InstMatchGeneratorMulti::addTerm( Node f, Node t, QuantifiersEngine* qe ){ + Assert( options::eagerInstQuant() ); + int addedLemmas = 0; + for( int i=0; i<(int)d_children.size(); i++ ){ + if( ((InstMatchGenerator*)d_children[i])->d_match_pattern.getOperator()==t.getOperator() ){ + InstMatch m; + //if it produces a match, then process it with the rest + if( ((InstMatchGenerator*)d_children[i])->getMatch( f, t, m, qe ) ){ + processNewMatch( qe, m, i, addedLemmas ); + } + } + } + return addedLemmas; +} + +int InstMatchGeneratorSimple::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ){ + InstMatch m; + m.add( baseMatch ); + int addedLemmas = 0; + if( d_match_pattern.getType()==NodeManager::currentNM()->booleanType() ){ + for( int i=0; i<2; i++ ){ + addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_pred_map_trie[i][ d_match_pattern.getOperator() ]) ); + } + }else{ + addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_func_map_trie[ d_match_pattern.getOperator() ]) ); + } + return addedLemmas; +} + +void InstMatchGeneratorSimple::addInstantiations( InstMatch& m, QuantifiersEngine* qe, int& addedLemmas, int argIndex, quantifiers::TermArgTrie* tat ){ + if( argIndex==(int)d_match_pattern.getNumChildren() ){ + //m is an instantiation + if( qe->addInstantiation( d_f, m ) ){ + addedLemmas++; + Debug("simple-multi-trigger") << "-> Produced instantiation " << m << std::endl; + } + }else{ + if( d_match_pattern[argIndex].getKind()==INST_CONSTANT ){ + Node ic = d_match_pattern[argIndex]; + for( std::map< Node, quantifiers::TermArgTrie >::iterator it = tat->d_data.begin(); it != tat->d_data.end(); ++it ){ + Node t = it->first; + if( ( m.get( ic ).isNull() || m.get( ic )==t ) && ic.getType()==t.getType() ){ + Node prev = m.get( ic ); + m.set( ic, t); + addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) ); + m.set( ic, prev); + } + } + }else{ + Node r = qe->getEqualityQuery()->getRepresentative( d_match_pattern[argIndex] ); + std::map< Node, quantifiers::TermArgTrie >::iterator it = tat->d_data.find( r ); + if( it!=tat->d_data.end() ){ + addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) ); + } + } + } +} + +int InstMatchGeneratorSimple::addTerm( Node f, Node t, QuantifiersEngine* qe ){ + Assert( options::eagerInstQuant() ); + InstMatch m; + for( int i=0; i<(int)t.getNumChildren(); i++ ){ + if( d_match_pattern[i].getKind()==INST_CONSTANT ){ + m.set(d_match_pattern[i], t[i]); + }else if( !qe->getEqualityQuery()->areEqual( d_match_pattern[i], t[i] ) ){ + return 0; + } + } + return qe->addInstantiation( f, m ) ? 1 : 0; +} + +}/* CVC4::theory::inst namespace */ +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ diff --git a/src/theory/quantifiers/inst_match_generator.h b/src/theory/quantifiers/inst_match_generator.h old mode 100755 new mode 100644 index a544f605a..602e71ca7 --- a/src/theory/quantifiers/inst_match_generator.h +++ b/src/theory/quantifiers/inst_match_generator.h @@ -1,197 +1,197 @@ -/********************* */ -/*! \file inst_match_generator.h - ** \verbatim - ** Original author: ajreynol - ** Major contributors: bobot - ** Minor contributors (to current version): mdeters - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief inst match generator class - **/ - -#include "cvc4_private.h" - -#ifndef __CVC4__THEORY__QUANTIFIERS__INST_MATCH_GENERATOR_H -#define __CVC4__THEORY__QUANTIFIERS__INST_MATCH_GENERATOR_H - -#include "theory/quantifiers/inst_match.h" -#include - -namespace CVC4 { -namespace theory { - -class QuantifiersEngine; -namespace quantifiers{ - class TermArgTrie; -} - -namespace inst { - -/** base class for producing InstMatch objects */ -class IMGenerator { -public: - /** reset instantiation round (call this at beginning of instantiation round) */ - virtual void resetInstantiationRound( QuantifiersEngine* qe ) = 0; - /** reset, eqc is the equivalence class to search in (any if eqc=null) */ - virtual void reset( Node eqc, QuantifiersEngine* qe ) = 0; - /** get the next match. must call reset( eqc ) before this function. */ - virtual bool getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ) = 0; - /** add instantiations directly */ - virtual int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ) = 0; - /** add ground term t, called when t is added to term db */ - virtual int addTerm( Node f, Node t, QuantifiersEngine* qe ) = 0; - /** set active add */ - virtual void setActiveAdd() {} -};/* class IMGenerator */ - -class CandidateGenerator; - -class InstMatchGenerator : public IMGenerator { -private: - /** candidate generator */ - CandidateGenerator* d_cg; - /** policy to use for matching */ - int d_matchPolicy; - /** children generators */ - std::vector< InstMatchGenerator* > d_children; - std::vector< int > d_children_index; - /** partial vector */ - std::vector< InstMatch > d_partial; - /** eq class */ - Node d_eq_class; - /** for arithmetic matching */ - std::map< Node, Node > d_arith_coeffs; - /** initialize pattern */ - void initializePatterns( std::vector< Node >& pats, QuantifiersEngine* qe ); - void initializePattern( Node pat, QuantifiersEngine* qe ); -public: - enum { - //options for producing matches - MATCH_GEN_DEFAULT = 0, - MATCH_GEN_EFFICIENT_E_MATCH, //generate matches via Efficient E-matching for SMT solvers - //others (internally used) - MATCH_GEN_INTERNAL_ARITHMETIC, - MATCH_GEN_INTERNAL_ERROR, - }; -private: - /** get the next match. must call d_cg->reset( ... ) before using. - only valid for use where !d_match_pattern.isNull(). - */ - bool getNextMatch2( Node f, InstMatch& m, QuantifiersEngine* qe, bool saveMatched = false ); - /** for arithmetic */ - bool getMatchArithmetic( Node t, InstMatch& m, QuantifiersEngine* qe ); -public: - /** get the match against ground term or formula t. - d_match_pattern and t should have the same shape. - only valid for use where !d_match_pattern.isNull(). - */ - bool getMatch( Node f, Node t, InstMatch& m, QuantifiersEngine* qe ); - - /** constructors */ - InstMatchGenerator( Node pat, QuantifiersEngine* qe, int matchOption = 0 ); - InstMatchGenerator( std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption = 0 ); - /** destructor */ - ~InstMatchGenerator(){} - /** The pattern we are producing matches for. - If null, this is a multi trigger that is merging matches from d_children. - */ - Node d_pattern; - /** match pattern */ - Node d_match_pattern; -public: - /** reset instantiation round (call this whenever equivalence classes have changed) */ - void resetInstantiationRound( QuantifiersEngine* qe ); - /** reset, eqc is the equivalence class to search in (any if eqc=null) */ - void reset( Node eqc, QuantifiersEngine* qe ); - /** get the next match. must call reset( eqc ) before this function. */ - bool getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ); - /** add instantiations */ - int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ); - /** add ground term t */ - int addTerm( Node f, Node t, QuantifiersEngine* qe ); - - bool d_active_add; - void setActiveAdd(); -};/* class InstMatchGenerator */ - -/** smart multi-trigger implementation */ -class InstMatchGeneratorMulti : public IMGenerator { -private: - /** indexed trie */ - typedef std::pair< std::pair< int, int >, InstMatchTrie* > IndexedTrie; - /** process new match */ - void processNewMatch( QuantifiersEngine* qe, InstMatch& m, int fromChildIndex, int& addedLemmas ); - /** process new instantiations */ - void processNewInstantiations( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, InstMatchTrie* tr, - std::vector< IndexedTrie >& unique_var_tries, - int trieIndex, int childIndex, int endChildIndex, bool modEq ); - /** process new instantiations 2 */ - void processNewInstantiations2( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, - std::vector< IndexedTrie >& unique_var_tries, - int uvtIndex, InstMatchTrie* tr = NULL, int trieIndex = 0 ); -private: - /** var contains (variable indices) for each pattern node */ - std::map< Node, std::vector< int > > d_var_contains; - /** variable indices contained to pattern nodes */ - std::map< int, std::vector< Node > > d_var_to_node; - /** quantifier to use */ - Node d_f; - /** policy to use for matching */ - int d_matchPolicy; - /** children generators */ - std::vector< InstMatchGenerator* > d_children; - /** inst match tries for each child */ - std::vector< InstMatchTrieOrdered > d_children_trie; - /** calculate matches */ - void calculateMatches( QuantifiersEngine* qe ); -public: - /** constructors */ - InstMatchGeneratorMulti( Node f, std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption = 0 ); - /** destructor */ - ~InstMatchGeneratorMulti(){} - /** reset instantiation round (call this whenever equivalence classes have changed) */ - void resetInstantiationRound( QuantifiersEngine* qe ); - /** reset, eqc is the equivalence class to search in (any if eqc=null) */ - void reset( Node eqc, QuantifiersEngine* qe ); - /** get the next match. must call reset( eqc ) before this function. (not implemented) */ - bool getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ) { return false; } - /** add instantiations */ - int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ); - /** add ground term t */ - int addTerm( Node f, Node t, QuantifiersEngine* qe ); -};/* class InstMatchGeneratorMulti */ - -/** smart (single)-trigger implementation */ -class InstMatchGeneratorSimple : public IMGenerator { -private: - /** quantifier for match term */ - Node d_f; - /** match term */ - Node d_match_pattern; - /** add instantiations */ - void addInstantiations( InstMatch& m, QuantifiersEngine* qe, int& addedLemmas, int argIndex, quantifiers::TermArgTrie* tat ); -public: - /** constructors */ - InstMatchGeneratorSimple( Node f, Node pat ) : d_f( f ), d_match_pattern( pat ){} - /** destructor */ - ~InstMatchGeneratorSimple(){} - /** reset instantiation round (call this whenever equivalence classes have changed) */ - void resetInstantiationRound( QuantifiersEngine* qe ) {} - /** reset, eqc is the equivalence class to search in (any if eqc=null) */ - void reset( Node eqc, QuantifiersEngine* qe ) {} - /** get the next match. must call reset( eqc ) before this function. (not implemented) */ - bool getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ) { return false; } - /** add instantiations */ - int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ); - /** add ground term t, possibly add instantiations */ - int addTerm( Node f, Node t, QuantifiersEngine* qe ); -};/* class InstMatchGeneratorSimple */ - -} -} -} - -#endif +/********************* */ +/*! \file inst_match_generator.h + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: Morgan Deters + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief inst match generator class + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY__QUANTIFIERS__INST_MATCH_GENERATOR_H +#define __CVC4__THEORY__QUANTIFIERS__INST_MATCH_GENERATOR_H + +#include "theory/quantifiers/inst_match.h" +#include + +namespace CVC4 { +namespace theory { + +class QuantifiersEngine; +namespace quantifiers{ + class TermArgTrie; +} + +namespace inst { + +/** base class for producing InstMatch objects */ +class IMGenerator { +public: + /** reset instantiation round (call this at beginning of instantiation round) */ + virtual void resetInstantiationRound( QuantifiersEngine* qe ) = 0; + /** reset, eqc is the equivalence class to search in (any if eqc=null) */ + virtual void reset( Node eqc, QuantifiersEngine* qe ) = 0; + /** get the next match. must call reset( eqc ) before this function. */ + virtual bool getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ) = 0; + /** add instantiations directly */ + virtual int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ) = 0; + /** add ground term t, called when t is added to term db */ + virtual int addTerm( Node f, Node t, QuantifiersEngine* qe ) = 0; + /** set active add */ + virtual void setActiveAdd() {} +};/* class IMGenerator */ + +class CandidateGenerator; + +class InstMatchGenerator : public IMGenerator { +private: + /** candidate generator */ + CandidateGenerator* d_cg; + /** policy to use for matching */ + int d_matchPolicy; + /** children generators */ + std::vector< InstMatchGenerator* > d_children; + std::vector< int > d_children_index; + /** partial vector */ + std::vector< InstMatch > d_partial; + /** eq class */ + Node d_eq_class; + /** for arithmetic matching */ + std::map< Node, Node > d_arith_coeffs; + /** initialize pattern */ + void initializePatterns( std::vector< Node >& pats, QuantifiersEngine* qe ); + void initializePattern( Node pat, QuantifiersEngine* qe ); +public: + enum { + //options for producing matches + MATCH_GEN_DEFAULT = 0, + MATCH_GEN_EFFICIENT_E_MATCH, //generate matches via Efficient E-matching for SMT solvers + //others (internally used) + MATCH_GEN_INTERNAL_ARITHMETIC, + MATCH_GEN_INTERNAL_ERROR, + }; +private: + /** get the next match. must call d_cg->reset( ... ) before using. + only valid for use where !d_match_pattern.isNull(). + */ + bool getNextMatch2( Node f, InstMatch& m, QuantifiersEngine* qe, bool saveMatched = false ); + /** for arithmetic */ + bool getMatchArithmetic( Node t, InstMatch& m, QuantifiersEngine* qe ); +public: + /** get the match against ground term or formula t. + d_match_pattern and t should have the same shape. + only valid for use where !d_match_pattern.isNull(). + */ + bool getMatch( Node f, Node t, InstMatch& m, QuantifiersEngine* qe ); + + /** constructors */ + InstMatchGenerator( Node pat, QuantifiersEngine* qe, int matchOption = 0 ); + InstMatchGenerator( std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption = 0 ); + /** destructor */ + ~InstMatchGenerator(){} + /** The pattern we are producing matches for. + If null, this is a multi trigger that is merging matches from d_children. + */ + Node d_pattern; + /** match pattern */ + Node d_match_pattern; +public: + /** reset instantiation round (call this whenever equivalence classes have changed) */ + void resetInstantiationRound( QuantifiersEngine* qe ); + /** reset, eqc is the equivalence class to search in (any if eqc=null) */ + void reset( Node eqc, QuantifiersEngine* qe ); + /** get the next match. must call reset( eqc ) before this function. */ + bool getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ); + /** add instantiations */ + int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ); + /** add ground term t */ + int addTerm( Node f, Node t, QuantifiersEngine* qe ); + + bool d_active_add; + void setActiveAdd(); +};/* class InstMatchGenerator */ + +/** smart multi-trigger implementation */ +class InstMatchGeneratorMulti : public IMGenerator { +private: + /** indexed trie */ + typedef std::pair< std::pair< int, int >, InstMatchTrie* > IndexedTrie; + /** process new match */ + void processNewMatch( QuantifiersEngine* qe, InstMatch& m, int fromChildIndex, int& addedLemmas ); + /** process new instantiations */ + void processNewInstantiations( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, InstMatchTrie* tr, + std::vector< IndexedTrie >& unique_var_tries, + int trieIndex, int childIndex, int endChildIndex, bool modEq ); + /** process new instantiations 2 */ + void processNewInstantiations2( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, + std::vector< IndexedTrie >& unique_var_tries, + int uvtIndex, InstMatchTrie* tr = NULL, int trieIndex = 0 ); +private: + /** var contains (variable indices) for each pattern node */ + std::map< Node, std::vector< int > > d_var_contains; + /** variable indices contained to pattern nodes */ + std::map< int, std::vector< Node > > d_var_to_node; + /** quantifier to use */ + Node d_f; + /** policy to use for matching */ + int d_matchPolicy; + /** children generators */ + std::vector< InstMatchGenerator* > d_children; + /** inst match tries for each child */ + std::vector< InstMatchTrieOrdered > d_children_trie; + /** calculate matches */ + void calculateMatches( QuantifiersEngine* qe ); +public: + /** constructors */ + InstMatchGeneratorMulti( Node f, std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption = 0 ); + /** destructor */ + ~InstMatchGeneratorMulti(){} + /** reset instantiation round (call this whenever equivalence classes have changed) */ + void resetInstantiationRound( QuantifiersEngine* qe ); + /** reset, eqc is the equivalence class to search in (any if eqc=null) */ + void reset( Node eqc, QuantifiersEngine* qe ); + /** get the next match. must call reset( eqc ) before this function. (not implemented) */ + bool getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ) { return false; } + /** add instantiations */ + int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ); + /** add ground term t */ + int addTerm( Node f, Node t, QuantifiersEngine* qe ); +};/* class InstMatchGeneratorMulti */ + +/** smart (single)-trigger implementation */ +class InstMatchGeneratorSimple : public IMGenerator { +private: + /** quantifier for match term */ + Node d_f; + /** match term */ + Node d_match_pattern; + /** add instantiations */ + void addInstantiations( InstMatch& m, QuantifiersEngine* qe, int& addedLemmas, int argIndex, quantifiers::TermArgTrie* tat ); +public: + /** constructors */ + InstMatchGeneratorSimple( Node f, Node pat ) : d_f( f ), d_match_pattern( pat ){} + /** destructor */ + ~InstMatchGeneratorSimple(){} + /** reset instantiation round (call this whenever equivalence classes have changed) */ + void resetInstantiationRound( QuantifiersEngine* qe ) {} + /** reset, eqc is the equivalence class to search in (any if eqc=null) */ + void reset( Node eqc, QuantifiersEngine* qe ) {} + /** get the next match. must call reset( eqc ) before this function. (not implemented) */ + bool getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ) { return false; } + /** add instantiations */ + int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ); + /** add ground term t, possibly add instantiations */ + int addTerm( Node f, Node t, QuantifiersEngine* qe ); +};/* class InstMatchGeneratorSimple */ + +} +} +} + +#endif diff --git a/src/theory/quantifiers/inst_strategy_cbqi.cpp b/src/theory/quantifiers/inst_strategy_cbqi.cpp old mode 100755 new mode 100644 index ddf763b73..b12fed619 --- a/src/theory/quantifiers/inst_strategy_cbqi.cpp +++ b/src/theory/quantifiers/inst_strategy_cbqi.cpp @@ -1,405 +1,405 @@ -/********************* */ -/*! \file inst_strategy_cbqi.cpp - ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): bobot, mdeters - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief Implementation of cbqi instantiation strategies - **/ - -#include "theory/quantifiers/inst_strategy_cbqi.h" -#include "theory/arith/theory_arith.h" -#include "theory/theory_engine.h" -#include "theory/quantifiers/options.h" -#include "theory/quantifiers/term_database.h" - -using namespace std; -using namespace CVC4; -using namespace CVC4::kind; -using namespace CVC4::context; -using namespace CVC4::theory; -using namespace CVC4::theory::quantifiers; -using namespace CVC4::theory::arith; -using namespace CVC4::theory::datatypes; - -#define ARITH_INSTANTIATOR_USE_MINUS_DELTA - -InstStrategySimplex::InstStrategySimplex( TheoryArith* th, QuantifiersEngine* ie ) : - InstStrategy( ie ), d_th( th ), d_counter( 0 ){ - d_negOne = NodeManager::currentNM()->mkConst( Rational(-1) ); -} - -bool InstStrategySimplex::calculateShouldProcess( Node f ){ - //DO_THIS - return false; -} - -void InstStrategySimplex::processResetInstantiationRound( Theory::Effort effort ){ - Debug("quant-arith") << "Setting up simplex for instantiator... " << std::endl; - d_instRows.clear(); - d_tableaux_term.clear(); - d_tableaux.clear(); - d_ceTableaux.clear(); - //search for instantiation rows in simplex tableaux - ArithVarNodeMap& avnm = d_th->d_arithvarNodeMap; - ArithVarNodeMap::var_iterator vi, vend; - for(vi = avnm.var_begin(), vend = avnm.var_end(); vi != vend; ++vi ){ - ArithVar x = *vi; - if( d_th->d_partialModel.hasEitherBound( x ) ){ - Node n = avnm.asNode(x); - Node f; - NodeBuilder<> t(kind::PLUS); - if( n.getKind()==PLUS ){ - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - addTermToRow( x, n[i], f, t ); - } - }else{ - addTermToRow( x, n, f, t ); - } - if( f!=Node::null() ){ - d_instRows[f].push_back( x ); - //this theory has constraints from f - Debug("quant-arith") << "Has constraints from " << f << std::endl; - //set that we should process it - d_quantActive[ f ] = true; - //set tableaux term - if( t.getNumChildren()==0 ){ - d_tableaux_term[x] = NodeManager::currentNM()->mkConst( Rational(0) ); - }else if( t.getNumChildren()==1 ){ - d_tableaux_term[x] = t.getChild( 0 ); - }else{ - d_tableaux_term[x] = t; - } - } - } - } - //print debug - debugPrint( "quant-arith-debug" ); - d_counter++; -} - -int InstStrategySimplex::process( Node f, Theory::Effort effort, int e ){ - if( e<2 ){ - return STATUS_UNFINISHED; - }else if( e==2 ){ - //Notice() << f << std::endl; - //Notice() << "Num inst rows = " << d_th->d_instRows[f].size() << std::endl; - //Notice() << "Num inst constants = " << d_quantEngine->getNumInstantiationConstants( f ) << std::endl; - Debug("quant-arith-simplex") << "InstStrategySimplex check " << f << ", rows = " << d_instRows[f].size() << std::endl; - for( int j=0; j<(int)d_instRows[f].size(); j++ ){ - ArithVar x = d_instRows[f][j]; - if( !d_ceTableaux[x].empty() ){ - Debug("quant-arith-simplex") << "Check row " << x << std::endl; - //instantiation row will be A*e + B*t = beta, - // where e is a vector of terms , and t is vector of ground terms. - // Say one term in A*e is coeff*e_i, where e_i is an instantiation constant - // We will construct the term ( beta - B*t)/coeff to use for e_i. - InstMatch m; - //By default, choose the first instantiation constant to be e_i. - Node var = d_ceTableaux[x].begin()->first; - if( var.getType().isInteger() ){ - std::map< Node, Node >::iterator it = d_ceTableaux[x].begin(); - //try to find coefficent that is +/- 1 - while( !var.isNull() && !d_ceTableaux[x][var].isNull() && d_ceTableaux[x][var]!=d_negOne ){ - ++it; - if( it==d_ceTableaux[x].end() ){ - var = Node::null(); - }else{ - var = it->first; - } - } - //otherwise, try one that divides all ground term coefficients? DO_THIS - } - if( !var.isNull() ){ - Debug("quant-arith-simplex") << "Instantiate with var " << var << std::endl; - doInstantiation( f, d_tableaux_term[x], x, m, var ); - }else{ - Debug("quant-arith-simplex") << "Could not find var." << std::endl; - } - ////choose a new variable based on alternation strategy - //int index = d_counter%(int)d_th->d_ceTableaux[x].size(); - //Node var; - //for( std::map< Node, Node >::iterator it = d_th->d_ceTableaux[x].begin(); it != d_th->d_ceTableaux[x].end(); ++it ){ - // if( index==0 ){ - // var = it->first; - // break; - // } - // index--; - //} - //d_th->doInstantiation( f, d_th->d_tableaux_term[x], x, &m, var ); - } - } - } - return STATUS_UNKNOWN; -} - - -void InstStrategySimplex::addTermToRow( ArithVar x, Node n, Node& f, NodeBuilder<>& t ){ - if( n.getKind()==MULT ){ - if( n[1].hasAttribute(InstConstantAttribute()) ){ - f = n[1].getAttribute(InstConstantAttribute()); - if( n[1].getKind()==INST_CONSTANT ){ - d_ceTableaux[x][ n[1] ] = n[0]; - }else{ - d_tableaux_ce_term[x][ n[1] ] = n[0]; - } - }else{ - d_tableaux[x][ n[1] ] = n[0]; - t << n; - } - }else{ - if( n.hasAttribute(InstConstantAttribute()) ){ - f = n.getAttribute(InstConstantAttribute()); - if( n.getKind()==INST_CONSTANT ){ - d_ceTableaux[x][ n ] = Node::null(); - }else{ - d_tableaux_ce_term[x][ n ] = NodeManager::currentNM()->mkConst( Rational(1) ); - } - }else{ - d_tableaux[x][ n ] = NodeManager::currentNM()->mkConst( Rational(1) ); - t << n; - } - } -} - -void InstStrategySimplex::debugPrint( const char* c ){ - const ArithVarNodeMap& avnm = d_th->d_arithvarNodeMap; - ArithVarNodeMap::var_iterator vi, vend; - for(vi = avnm.var_begin(), vend = avnm.var_end(); vi != vend; ++vi ){ - ArithVar x = *vi; - Node n = avnm.asNode(x); - //if( ((TheoryArith*)getTheory())->d_partialModel.hasEitherBound( x ) ){ - Debug(c) << x << " : " << n << ", bounds = "; - if( d_th->d_partialModel.hasLowerBound( x ) ){ - Debug(c) << d_th->d_partialModel.getLowerBound( x ); - }else{ - Debug(c) << "-infty"; - } - Debug(c) << " <= "; - Debug(c) << d_th->d_partialModel.getAssignment( x ); - Debug(c) << " <= "; - if( d_th->d_partialModel.hasUpperBound( x ) ){ - Debug(c) << d_th->d_partialModel.getUpperBound( x ); - }else{ - Debug(c) << "+infty"; - } - Debug(c) << std::endl; - //Debug(c) << " Term = " << d_tableaux_term[x] << std::endl; - //Debug(c) << " "; - //for( std::map< Node, Node >::iterator it2 = d_tableaux[x].begin(); it2 != d_tableaux[x].end(); ++it2 ){ - // Debug(c) << "( " << it2->first << ", " << it2->second << " ) "; - //} - //for( std::map< Node, Node >::iterator it2 = d_ceTableaux[x].begin(); it2 != d_ceTableaux[x].end(); ++it2 ){ - // Debug(c) << "(CE)( " << it2->first << ", " << it2->second << " ) "; - //} - //for( std::map< Node, Node >::iterator it2 = d_tableaux_ce_term[x].begin(); it2 != d_tableaux_ce_term[x].end(); ++it2 ){ - // Debug(c) << "(CE-term)( " << it2->first << ", " << it2->second << " ) "; - //} - //Debug(c) << std::endl; - //} - } - Debug(c) << std::endl; - - for( int q=0; qgetNumQuantifiers(); q++ ){ - Node f = d_quantEngine->getQuantifier( q ); - Debug(c) << f << std::endl; - Debug(c) << " Inst constants: "; - for( int i=0; i<(int)d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); i++ ){ - if( i>0 ){ - Debug( c ) << ", "; - } - Debug( c ) << d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i ); - } - Debug(c) << std::endl; - Debug(c) << " Instantiation rows: "; - for( int i=0; i<(int)d_instRows[f].size(); i++ ){ - if( i>0 ){ - Debug(c) << ", "; - } - Debug(c) << d_instRows[f][i]; - } - Debug(c) << std::endl; - } -} - -//say instantiation row x for quantifier f is coeff*var + A*t[e] + term = beta, -// where var is an instantiation constant from f, -// t[e] is a vector of terms containing instantiation constants from f, -// and term is a ground term (c1*t1 + ... + cn*tn). -// We construct the term ( beta - term )/coeff to use as an instantiation for var. -bool InstStrategySimplex::doInstantiation( Node f, Node term, ArithVar x, InstMatch& m, Node var ){ - //first try +delta - if( doInstantiation2( f, term, x, m, var ) ){ - ++(d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_cbqi_arith); - return true; - }else{ -#ifdef ARITH_INSTANTIATOR_USE_MINUS_DELTA - //otherwise try -delta - if( doInstantiation2( f, term, x, m, var, true ) ){ - ++(d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_cbqi_arith_minus); - return true; - }else{ - return false; - } -#else - return false; -#endif - } -} - -bool InstStrategySimplex::doInstantiation2( Node f, Node term, ArithVar x, InstMatch& m, Node var, bool minus_delta ){ - // make term ( beta - term )/coeff - Node beta = getTableauxValue( x, minus_delta ); - Node instVal = NodeManager::currentNM()->mkNode( MINUS, beta, term ); - if( !d_ceTableaux[x][var].isNull() ){ - if( var.getType().isInteger() ){ - Assert( d_ceTableaux[x][var]==NodeManager::currentNM()->mkConst( Rational(-1) ) ); - instVal = NodeManager::currentNM()->mkNode( MULT, d_ceTableaux[x][var], instVal ); - }else{ - Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_ceTableaux[x][var].getConst() ); - instVal = NodeManager::currentNM()->mkNode( MULT, coeff, instVal ); - } - } - instVal = Rewriter::rewrite( instVal ); - //use as instantiation value for var - m.set(var, instVal); - Debug("quant-arith") << "Add instantiation " << m << std::endl; - return d_quantEngine->addInstantiation( f, m ); -} - -Node InstStrategySimplex::getTableauxValue( Node n, bool minus_delta ){ - if( d_th->d_arithvarNodeMap.hasArithVar(n) ){ - ArithVar v = d_th->d_arithvarNodeMap.asArithVar( n ); - return getTableauxValue( v, minus_delta ); - }else{ - return NodeManager::currentNM()->mkConst( Rational(0) ); - } -} - -Node InstStrategySimplex::getTableauxValue( ArithVar v, bool minus_delta ){ - const Rational& delta = d_th->d_partialModel.getDelta(); - DeltaRational drv = d_th->d_partialModel.getAssignment( v ); - Rational qmodel = drv.substituteDelta( minus_delta ? -delta : delta ); - return mkRationalNode(qmodel); -} - - -InstStrategyDatatypesValue::InstStrategyDatatypesValue( TheoryDatatypes* th, QuantifiersEngine* qe ) : - InstStrategy( qe ), d_th( th ){ - -} - -bool InstStrategyDatatypesValue::calculateShouldProcess( Node f ){ - //DO_THIS - return false; -} - -void InstStrategyDatatypesValue::processResetInstantiationRound( Theory::Effort effort ){ - -} - -int InstStrategyDatatypesValue::process( Node f, Theory::Effort effort, int e ){ - Debug("quant-datatypes") << "Datatypes: Try to solve (" << e << ") for " << f << "... " << std::endl; - if( e<2 ){ - return InstStrategy::STATUS_UNFINISHED; - }else if( e==2 ){ - InstMatch m; - for( int j = 0; j<(int)d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); j++ ){ - Node i = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, j ); - if( i.getType().isDatatype() ){ - Node n = getValueFor( i ); - Debug("quant-datatypes-debug") << "Value for " << i << " is " << n << std::endl; - m.set(i,n); - } - } - //d_quantEngine->addInstantiation( f, m ); - } - return InstStrategy::STATUS_UNKNOWN; -} - -Node InstStrategyDatatypesValue::getValueFor( Node n ){ - //simply get the ground value for n in the current model, if it exists, - // or return an arbitrary ground term otherwise - if( !n.hasAttribute(InstConstantAttribute()) ){ - return n; - }else{ - return n; - } - /* FIXME - - Debug("quant-datatypes-debug") << "get value for " << n << std::endl; - if( !n.hasAttribute(InstConstantAttribute()) ){ - return n; - }else{ - Assert( n.getType().isDatatype() ); - //check if in equivalence class with ground term - Node rep = getRepresentative( n ); - Debug("quant-datatypes-debug") << "Rep is " << rep << std::endl; - if( !rep.hasAttribute(InstConstantAttribute()) ){ - return rep; - }else{ - if( !n.getType().isDatatype() ){ - return n.getType().mkGroundTerm(); - }else{ - if( n.getKind()==APPLY_CONSTRUCTOR ){ - std::vector< Node > children; - children.push_back( n.getOperator() ); - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - children.push_back( getValueFor( n[i] ) ); - } - return NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children ); - }else{ - const Datatype& dt = ((DatatypeType)(n.getType()).toType()).getDatatype(); - TheoryDatatypes::EqLists* labels = &((TheoryDatatypes*)d_th)->d_labels; - //otherwise, use which constructor the inst constant is current chosen to be - if( labels->find( n )!=labels->end() ){ - TheoryDatatypes::EqList* lbl = (*labels->find( n )).second; - int tIndex = -1; - if( !lbl->empty() && (*lbl)[ lbl->size()-1 ].getKind()==APPLY_TESTER ){ - Debug("quant-datatypes-debug") << n << " tester is " << (*lbl)[ lbl->size()-1 ] << std::endl; - tIndex = Datatype::indexOf((*lbl)[ lbl->size()-1 ].getOperator().toExpr()); - }else{ - Debug("quant-datatypes-debug") << "find possible tester choice" << std::endl; - //must find a possible choice - vector< bool > possibleCons; - possibleCons.resize( dt.getNumConstructors(), true ); - for( TheoryDatatypes::EqList::const_iterator j = lbl->begin(); j != lbl->end(); j++ ) { - Node leqn = (*j); - possibleCons[ Datatype::indexOf( leqn[0].getOperator().toExpr() ) ] = false; - } - for( unsigned int j=0; j children; - children.push_back( cons ); - for( int i=0; i<(int)dt[ tIndex ].getNumArgs(); i++ ) { - Node sn = NodeManager::currentNM()->mkNode( APPLY_SELECTOR, Node::fromExpr( dt[tIndex][i].getSelector() ), n ); - if( n.hasAttribute(InstConstantAttribute()) ){ - InstConstantAttribute ica; - sn.setAttribute(ica,n.getAttribute(InstConstantAttribute()) ); - } - Node snn = getValueFor( sn ); - children.push_back( snn ); - } - return NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children ); - }else{ - return n.getType().mkGroundTerm(); - } - } - } - } - } - */ -} +/********************* */ +/*! \file inst_strategy_cbqi.cpp + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: Morgan Deters + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Implementation of cbqi instantiation strategies + **/ + +#include "theory/quantifiers/inst_strategy_cbqi.h" +#include "theory/arith/theory_arith.h" +#include "theory/theory_engine.h" +#include "theory/quantifiers/options.h" +#include "theory/quantifiers/term_database.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::quantifiers; +using namespace CVC4::theory::arith; +using namespace CVC4::theory::datatypes; + +#define ARITH_INSTANTIATOR_USE_MINUS_DELTA + +InstStrategySimplex::InstStrategySimplex( TheoryArith* th, QuantifiersEngine* ie ) : + InstStrategy( ie ), d_th( th ), d_counter( 0 ){ + d_negOne = NodeManager::currentNM()->mkConst( Rational(-1) ); +} + +bool InstStrategySimplex::calculateShouldProcess( Node f ){ + //DO_THIS + return false; +} + +void InstStrategySimplex::processResetInstantiationRound( Theory::Effort effort ){ + Debug("quant-arith") << "Setting up simplex for instantiator... " << std::endl; + d_instRows.clear(); + d_tableaux_term.clear(); + d_tableaux.clear(); + d_ceTableaux.clear(); + //search for instantiation rows in simplex tableaux + ArithVarNodeMap& avnm = d_th->d_arithvarNodeMap; + ArithVarNodeMap::var_iterator vi, vend; + for(vi = avnm.var_begin(), vend = avnm.var_end(); vi != vend; ++vi ){ + ArithVar x = *vi; + if( d_th->d_partialModel.hasEitherBound( x ) ){ + Node n = avnm.asNode(x); + Node f; + NodeBuilder<> t(kind::PLUS); + if( n.getKind()==PLUS ){ + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + addTermToRow( x, n[i], f, t ); + } + }else{ + addTermToRow( x, n, f, t ); + } + if( f!=Node::null() ){ + d_instRows[f].push_back( x ); + //this theory has constraints from f + Debug("quant-arith") << "Has constraints from " << f << std::endl; + //set that we should process it + d_quantActive[ f ] = true; + //set tableaux term + if( t.getNumChildren()==0 ){ + d_tableaux_term[x] = NodeManager::currentNM()->mkConst( Rational(0) ); + }else if( t.getNumChildren()==1 ){ + d_tableaux_term[x] = t.getChild( 0 ); + }else{ + d_tableaux_term[x] = t; + } + } + } + } + //print debug + debugPrint( "quant-arith-debug" ); + d_counter++; +} + +int InstStrategySimplex::process( Node f, Theory::Effort effort, int e ){ + if( e<2 ){ + return STATUS_UNFINISHED; + }else if( e==2 ){ + //Notice() << f << std::endl; + //Notice() << "Num inst rows = " << d_th->d_instRows[f].size() << std::endl; + //Notice() << "Num inst constants = " << d_quantEngine->getNumInstantiationConstants( f ) << std::endl; + Debug("quant-arith-simplex") << "InstStrategySimplex check " << f << ", rows = " << d_instRows[f].size() << std::endl; + for( int j=0; j<(int)d_instRows[f].size(); j++ ){ + ArithVar x = d_instRows[f][j]; + if( !d_ceTableaux[x].empty() ){ + Debug("quant-arith-simplex") << "Check row " << x << std::endl; + //instantiation row will be A*e + B*t = beta, + // where e is a vector of terms , and t is vector of ground terms. + // Say one term in A*e is coeff*e_i, where e_i is an instantiation constant + // We will construct the term ( beta - B*t)/coeff to use for e_i. + InstMatch m; + //By default, choose the first instantiation constant to be e_i. + Node var = d_ceTableaux[x].begin()->first; + if( var.getType().isInteger() ){ + std::map< Node, Node >::iterator it = d_ceTableaux[x].begin(); + //try to find coefficent that is +/- 1 + while( !var.isNull() && !d_ceTableaux[x][var].isNull() && d_ceTableaux[x][var]!=d_negOne ){ + ++it; + if( it==d_ceTableaux[x].end() ){ + var = Node::null(); + }else{ + var = it->first; + } + } + //otherwise, try one that divides all ground term coefficients? DO_THIS + } + if( !var.isNull() ){ + Debug("quant-arith-simplex") << "Instantiate with var " << var << std::endl; + doInstantiation( f, d_tableaux_term[x], x, m, var ); + }else{ + Debug("quant-arith-simplex") << "Could not find var." << std::endl; + } + ////choose a new variable based on alternation strategy + //int index = d_counter%(int)d_th->d_ceTableaux[x].size(); + //Node var; + //for( std::map< Node, Node >::iterator it = d_th->d_ceTableaux[x].begin(); it != d_th->d_ceTableaux[x].end(); ++it ){ + // if( index==0 ){ + // var = it->first; + // break; + // } + // index--; + //} + //d_th->doInstantiation( f, d_th->d_tableaux_term[x], x, &m, var ); + } + } + } + return STATUS_UNKNOWN; +} + + +void InstStrategySimplex::addTermToRow( ArithVar x, Node n, Node& f, NodeBuilder<>& t ){ + if( n.getKind()==MULT ){ + if( n[1].hasAttribute(InstConstantAttribute()) ){ + f = n[1].getAttribute(InstConstantAttribute()); + if( n[1].getKind()==INST_CONSTANT ){ + d_ceTableaux[x][ n[1] ] = n[0]; + }else{ + d_tableaux_ce_term[x][ n[1] ] = n[0]; + } + }else{ + d_tableaux[x][ n[1] ] = n[0]; + t << n; + } + }else{ + if( n.hasAttribute(InstConstantAttribute()) ){ + f = n.getAttribute(InstConstantAttribute()); + if( n.getKind()==INST_CONSTANT ){ + d_ceTableaux[x][ n ] = Node::null(); + }else{ + d_tableaux_ce_term[x][ n ] = NodeManager::currentNM()->mkConst( Rational(1) ); + } + }else{ + d_tableaux[x][ n ] = NodeManager::currentNM()->mkConst( Rational(1) ); + t << n; + } + } +} + +void InstStrategySimplex::debugPrint( const char* c ){ + const ArithVarNodeMap& avnm = d_th->d_arithvarNodeMap; + ArithVarNodeMap::var_iterator vi, vend; + for(vi = avnm.var_begin(), vend = avnm.var_end(); vi != vend; ++vi ){ + ArithVar x = *vi; + Node n = avnm.asNode(x); + //if( ((TheoryArith*)getTheory())->d_partialModel.hasEitherBound( x ) ){ + Debug(c) << x << " : " << n << ", bounds = "; + if( d_th->d_partialModel.hasLowerBound( x ) ){ + Debug(c) << d_th->d_partialModel.getLowerBound( x ); + }else{ + Debug(c) << "-infty"; + } + Debug(c) << " <= "; + Debug(c) << d_th->d_partialModel.getAssignment( x ); + Debug(c) << " <= "; + if( d_th->d_partialModel.hasUpperBound( x ) ){ + Debug(c) << d_th->d_partialModel.getUpperBound( x ); + }else{ + Debug(c) << "+infty"; + } + Debug(c) << std::endl; + //Debug(c) << " Term = " << d_tableaux_term[x] << std::endl; + //Debug(c) << " "; + //for( std::map< Node, Node >::iterator it2 = d_tableaux[x].begin(); it2 != d_tableaux[x].end(); ++it2 ){ + // Debug(c) << "( " << it2->first << ", " << it2->second << " ) "; + //} + //for( std::map< Node, Node >::iterator it2 = d_ceTableaux[x].begin(); it2 != d_ceTableaux[x].end(); ++it2 ){ + // Debug(c) << "(CE)( " << it2->first << ", " << it2->second << " ) "; + //} + //for( std::map< Node, Node >::iterator it2 = d_tableaux_ce_term[x].begin(); it2 != d_tableaux_ce_term[x].end(); ++it2 ){ + // Debug(c) << "(CE-term)( " << it2->first << ", " << it2->second << " ) "; + //} + //Debug(c) << std::endl; + //} + } + Debug(c) << std::endl; + + for( int q=0; qgetNumQuantifiers(); q++ ){ + Node f = d_quantEngine->getQuantifier( q ); + Debug(c) << f << std::endl; + Debug(c) << " Inst constants: "; + for( int i=0; i<(int)d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); i++ ){ + if( i>0 ){ + Debug( c ) << ", "; + } + Debug( c ) << d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i ); + } + Debug(c) << std::endl; + Debug(c) << " Instantiation rows: "; + for( int i=0; i<(int)d_instRows[f].size(); i++ ){ + if( i>0 ){ + Debug(c) << ", "; + } + Debug(c) << d_instRows[f][i]; + } + Debug(c) << std::endl; + } +} + +//say instantiation row x for quantifier f is coeff*var + A*t[e] + term = beta, +// where var is an instantiation constant from f, +// t[e] is a vector of terms containing instantiation constants from f, +// and term is a ground term (c1*t1 + ... + cn*tn). +// We construct the term ( beta - term )/coeff to use as an instantiation for var. +bool InstStrategySimplex::doInstantiation( Node f, Node term, ArithVar x, InstMatch& m, Node var ){ + //first try +delta + if( doInstantiation2( f, term, x, m, var ) ){ + ++(d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_cbqi_arith); + return true; + }else{ +#ifdef ARITH_INSTANTIATOR_USE_MINUS_DELTA + //otherwise try -delta + if( doInstantiation2( f, term, x, m, var, true ) ){ + ++(d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_cbqi_arith_minus); + return true; + }else{ + return false; + } +#else + return false; +#endif + } +} + +bool InstStrategySimplex::doInstantiation2( Node f, Node term, ArithVar x, InstMatch& m, Node var, bool minus_delta ){ + // make term ( beta - term )/coeff + Node beta = getTableauxValue( x, minus_delta ); + Node instVal = NodeManager::currentNM()->mkNode( MINUS, beta, term ); + if( !d_ceTableaux[x][var].isNull() ){ + if( var.getType().isInteger() ){ + Assert( d_ceTableaux[x][var]==NodeManager::currentNM()->mkConst( Rational(-1) ) ); + instVal = NodeManager::currentNM()->mkNode( MULT, d_ceTableaux[x][var], instVal ); + }else{ + Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_ceTableaux[x][var].getConst() ); + instVal = NodeManager::currentNM()->mkNode( MULT, coeff, instVal ); + } + } + instVal = Rewriter::rewrite( instVal ); + //use as instantiation value for var + m.set(var, instVal); + Debug("quant-arith") << "Add instantiation " << m << std::endl; + return d_quantEngine->addInstantiation( f, m ); +} + +Node InstStrategySimplex::getTableauxValue( Node n, bool minus_delta ){ + if( d_th->d_arithvarNodeMap.hasArithVar(n) ){ + ArithVar v = d_th->d_arithvarNodeMap.asArithVar( n ); + return getTableauxValue( v, minus_delta ); + }else{ + return NodeManager::currentNM()->mkConst( Rational(0) ); + } +} + +Node InstStrategySimplex::getTableauxValue( ArithVar v, bool minus_delta ){ + const Rational& delta = d_th->d_partialModel.getDelta(); + DeltaRational drv = d_th->d_partialModel.getAssignment( v ); + Rational qmodel = drv.substituteDelta( minus_delta ? -delta : delta ); + return mkRationalNode(qmodel); +} + + +InstStrategyDatatypesValue::InstStrategyDatatypesValue( TheoryDatatypes* th, QuantifiersEngine* qe ) : + InstStrategy( qe ), d_th( th ){ + +} + +bool InstStrategyDatatypesValue::calculateShouldProcess( Node f ){ + //DO_THIS + return false; +} + +void InstStrategyDatatypesValue::processResetInstantiationRound( Theory::Effort effort ){ + +} + +int InstStrategyDatatypesValue::process( Node f, Theory::Effort effort, int e ){ + Debug("quant-datatypes") << "Datatypes: Try to solve (" << e << ") for " << f << "... " << std::endl; + if( e<2 ){ + return InstStrategy::STATUS_UNFINISHED; + }else if( e==2 ){ + InstMatch m; + for( int j = 0; j<(int)d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); j++ ){ + Node i = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, j ); + if( i.getType().isDatatype() ){ + Node n = getValueFor( i ); + Debug("quant-datatypes-debug") << "Value for " << i << " is " << n << std::endl; + m.set(i,n); + } + } + //d_quantEngine->addInstantiation( f, m ); + } + return InstStrategy::STATUS_UNKNOWN; +} + +Node InstStrategyDatatypesValue::getValueFor( Node n ){ + //simply get the ground value for n in the current model, if it exists, + // or return an arbitrary ground term otherwise + if( !n.hasAttribute(InstConstantAttribute()) ){ + return n; + }else{ + return n; + } + /* FIXME + + Debug("quant-datatypes-debug") << "get value for " << n << std::endl; + if( !n.hasAttribute(InstConstantAttribute()) ){ + return n; + }else{ + Assert( n.getType().isDatatype() ); + //check if in equivalence class with ground term + Node rep = getRepresentative( n ); + Debug("quant-datatypes-debug") << "Rep is " << rep << std::endl; + if( !rep.hasAttribute(InstConstantAttribute()) ){ + return rep; + }else{ + if( !n.getType().isDatatype() ){ + return n.getType().mkGroundTerm(); + }else{ + if( n.getKind()==APPLY_CONSTRUCTOR ){ + std::vector< Node > children; + children.push_back( n.getOperator() ); + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + children.push_back( getValueFor( n[i] ) ); + } + return NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children ); + }else{ + const Datatype& dt = ((DatatypeType)(n.getType()).toType()).getDatatype(); + TheoryDatatypes::EqLists* labels = &((TheoryDatatypes*)d_th)->d_labels; + //otherwise, use which constructor the inst constant is current chosen to be + if( labels->find( n )!=labels->end() ){ + TheoryDatatypes::EqList* lbl = (*labels->find( n )).second; + int tIndex = -1; + if( !lbl->empty() && (*lbl)[ lbl->size()-1 ].getKind()==APPLY_TESTER ){ + Debug("quant-datatypes-debug") << n << " tester is " << (*lbl)[ lbl->size()-1 ] << std::endl; + tIndex = Datatype::indexOf((*lbl)[ lbl->size()-1 ].getOperator().toExpr()); + }else{ + Debug("quant-datatypes-debug") << "find possible tester choice" << std::endl; + //must find a possible choice + vector< bool > possibleCons; + possibleCons.resize( dt.getNumConstructors(), true ); + for( TheoryDatatypes::EqList::const_iterator j = lbl->begin(); j != lbl->end(); j++ ) { + Node leqn = (*j); + possibleCons[ Datatype::indexOf( leqn[0].getOperator().toExpr() ) ] = false; + } + for( unsigned int j=0; j children; + children.push_back( cons ); + for( int i=0; i<(int)dt[ tIndex ].getNumArgs(); i++ ) { + Node sn = NodeManager::currentNM()->mkNode( APPLY_SELECTOR, Node::fromExpr( dt[tIndex][i].getSelector() ), n ); + if( n.hasAttribute(InstConstantAttribute()) ){ + InstConstantAttribute ica; + sn.setAttribute(ica,n.getAttribute(InstConstantAttribute()) ); + } + Node snn = getValueFor( sn ); + children.push_back( snn ); + } + return NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children ); + }else{ + return n.getType().mkGroundTerm(); + } + } + } + } + } + */ +} diff --git a/src/theory/quantifiers/inst_strategy_cbqi.h b/src/theory/quantifiers/inst_strategy_cbqi.h old mode 100755 new mode 100644 index 3ee423fe7..de548ab14 --- a/src/theory/quantifiers/inst_strategy_cbqi.h +++ b/src/theory/quantifiers/inst_strategy_cbqi.h @@ -1,110 +1,110 @@ -/********************* */ -/*! \file inst_strategy_cbqi.h - ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): mdeters - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief instantiator_arith_instantiator - **/ - - -#include "cvc4_private.h" - -#ifndef __CVC4__INST_STRATEGT_CBQI_H -#define __CVC4__INST_STRATEGT_CBQI_H - -#include "theory/quantifiers/instantiation_engine.h" -#include "theory/arith/arithvar_node_map.h" - -#include "util/statistics_registry.h" - -namespace CVC4 { -namespace theory { - -namespace arith { - class TheoryArith; -} - -namespace datatypes { - class TheoryDatatypes; -} - -namespace quantifiers { - - -class InstStrategySimplex : public InstStrategy{ -protected: - /** calculate if we should process this quantifier */ - bool calculateShouldProcess( Node f ); -private: - /** reference to theory arithmetic */ - arith::TheoryArith* d_th; - /** delta */ - std::map< TypeNode, Node > d_deltas; - /** for each quantifier, simplex rows */ - std::map< Node, std::vector< arith::ArithVar > > d_instRows; - /** tableaux */ - std::map< arith::ArithVar, Node > d_tableaux_term; - std::map< arith::ArithVar, std::map< Node, Node > > d_tableaux_ce_term; - std::map< arith::ArithVar, std::map< Node, Node > > d_tableaux; - /** ce tableaux */ - std::map< arith::ArithVar, std::map< Node, Node > > d_ceTableaux; - /** get value */ - Node getTableauxValue( Node n, bool minus_delta = false ); - Node getTableauxValue( arith::ArithVar v, bool minus_delta = false ); - /** do instantiation */ - bool doInstantiation( Node f, Node term, arith::ArithVar x, InstMatch& m, Node var ); - bool doInstantiation2( Node f, Node term, arith::ArithVar x, InstMatch& m, Node var, bool minus_delta = false ); - /** add term to row */ - void addTermToRow( arith::ArithVar x, Node n, Node& f, NodeBuilder<>& t ); - /** print debug */ - void debugPrint( const char* c ); -private: - /** */ - int d_counter; - /** negative one */ - Node d_negOne; - /** process functions */ - void processResetInstantiationRound( Theory::Effort effort ); - int process( Node f, Theory::Effort effort, int e ); -public: - InstStrategySimplex( arith::TheoryArith* th, QuantifiersEngine* ie ); - ~InstStrategySimplex(){} - /** identify */ - std::string identify() const { return std::string("Simplex"); } -}; - - -class InstStrategyDatatypesValue : public InstStrategy -{ -protected: - /** calculate if we should process this quantifier */ - bool calculateShouldProcess( Node f ); -private: - /** reference to theory datatypes */ - datatypes::TheoryDatatypes* d_th; - /** get value function */ - Node getValueFor( Node n ); -public: - //constructor - InstStrategyDatatypesValue( datatypes::TheoryDatatypes* th, QuantifiersEngine* qe ); - ~InstStrategyDatatypesValue(){} - /** reset instantiation */ - void processResetInstantiationRound( Theory::Effort effort ); - /** process method, returns a status */ - int process( Node f, Theory::Effort effort, int e ); - /** identify */ - std::string identify() const { return std::string("InstStrategyDatatypesValue"); } - -};/* class InstStrategy */ - -} -} -} - +/********************* */ +/*! \file inst_strategy_cbqi.h + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: Morgan Deters + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief instantiator_arith_instantiator + **/ + + +#include "cvc4_private.h" + +#ifndef __CVC4__INST_STRATEGT_CBQI_H +#define __CVC4__INST_STRATEGT_CBQI_H + +#include "theory/quantifiers/instantiation_engine.h" +#include "theory/arith/arithvar_node_map.h" + +#include "util/statistics_registry.h" + +namespace CVC4 { +namespace theory { + +namespace arith { + class TheoryArith; +} + +namespace datatypes { + class TheoryDatatypes; +} + +namespace quantifiers { + + +class InstStrategySimplex : public InstStrategy{ +protected: + /** calculate if we should process this quantifier */ + bool calculateShouldProcess( Node f ); +private: + /** reference to theory arithmetic */ + arith::TheoryArith* d_th; + /** delta */ + std::map< TypeNode, Node > d_deltas; + /** for each quantifier, simplex rows */ + std::map< Node, std::vector< arith::ArithVar > > d_instRows; + /** tableaux */ + std::map< arith::ArithVar, Node > d_tableaux_term; + std::map< arith::ArithVar, std::map< Node, Node > > d_tableaux_ce_term; + std::map< arith::ArithVar, std::map< Node, Node > > d_tableaux; + /** ce tableaux */ + std::map< arith::ArithVar, std::map< Node, Node > > d_ceTableaux; + /** get value */ + Node getTableauxValue( Node n, bool minus_delta = false ); + Node getTableauxValue( arith::ArithVar v, bool minus_delta = false ); + /** do instantiation */ + bool doInstantiation( Node f, Node term, arith::ArithVar x, InstMatch& m, Node var ); + bool doInstantiation2( Node f, Node term, arith::ArithVar x, InstMatch& m, Node var, bool minus_delta = false ); + /** add term to row */ + void addTermToRow( arith::ArithVar x, Node n, Node& f, NodeBuilder<>& t ); + /** print debug */ + void debugPrint( const char* c ); +private: + /** */ + int d_counter; + /** negative one */ + Node d_negOne; + /** process functions */ + void processResetInstantiationRound( Theory::Effort effort ); + int process( Node f, Theory::Effort effort, int e ); +public: + InstStrategySimplex( arith::TheoryArith* th, QuantifiersEngine* ie ); + ~InstStrategySimplex(){} + /** identify */ + std::string identify() const { return std::string("Simplex"); } +}; + + +class InstStrategyDatatypesValue : public InstStrategy +{ +protected: + /** calculate if we should process this quantifier */ + bool calculateShouldProcess( Node f ); +private: + /** reference to theory datatypes */ + datatypes::TheoryDatatypes* d_th; + /** get value function */ + Node getValueFor( Node n ); +public: + //constructor + InstStrategyDatatypesValue( datatypes::TheoryDatatypes* th, QuantifiersEngine* qe ); + ~InstStrategyDatatypesValue(){} + /** reset instantiation */ + void processResetInstantiationRound( Theory::Effort effort ); + /** process method, returns a status */ + int process( Node f, Theory::Effort effort, int e ); + /** identify */ + std::string identify() const { return std::string("InstStrategyDatatypesValue"); } + +};/* class InstStrategy */ + +} +} +} + #endif \ No newline at end of file diff --git a/src/theory/quantifiers/inst_strategy_e_matching.cpp b/src/theory/quantifiers/inst_strategy_e_matching.cpp old mode 100755 new mode 100644 index 91cd2829c..3f5cc7666 --- a/src/theory/quantifiers/inst_strategy_e_matching.cpp +++ b/src/theory/quantifiers/inst_strategy_e_matching.cpp @@ -1,375 +1,375 @@ -/********************* */ -/*! \file inst_strategy_e_matching.cpp - ** \verbatim - ** Original author: ajreynol - ** Major contributors: mdeters - ** Minor contributors (to current version): bobot - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa - ** 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 "theory/theory_engine.h" -#include "theory/quantifiers/options.h" -#include "theory/quantifiers/term_database.h" -#include "theory/quantifiers/inst_match_generator.h" - -using namespace std; -using namespace CVC4; -using namespace CVC4::kind; -using namespace CVC4::context; -using namespace CVC4::theory; -using namespace CVC4::theory::inst; -using namespace CVC4::theory::quantifiers; - -//#define MULTI_TRIGGER_FULL_EFFORT_HALF -#define MULTI_MULTI_TRIGGERS - -struct sortQuantifiersForSymbol { - QuantifiersEngine* d_qe; - bool operator() (Node i, Node j) { - int nqfsi = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( i.getOperator() ); - int nqfsj = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( j.getOperator() ); - if( nqfsinqfsj ){ - return false; - }else{ - return false; - } - } -}; - -void InstStrategyUserPatterns::processResetInstantiationRound( Theory::Effort effort ){ - //reset triggers - for( std::map< Node, std::vector< Trigger* > >::iterator it = d_user_gen.begin(); it != d_user_gen.end(); ++it ){ - for( int i=0; i<(int)it->second.size(); i++ ){ - it->second[i]->resetInstantiationRound(); - it->second[i]->reset( Node::null() ); - } - } -} - -int InstStrategyUserPatterns::process( Node f, Theory::Effort effort, int e ){ - if( e==0 ){ - return STATUS_UNFINISHED; - }else if( e==1 ){ - d_counter[f]++; - Debug("quant-uf-strategy") << "Try user-provided patterns..." << std::endl; - //Notice() << "Try user-provided patterns..." << std::endl; - for( int i=0; i<(int)d_user_gen[f].size(); i++ ){ - bool processTrigger = true; - if( processTrigger ){ - //if( d_user_gen[f][i]->isMultiTrigger() ) - Trace("process-trigger") << " Process (user) " << (*d_user_gen[f][i]) << "..." << std::endl; - InstMatch baseMatch; - int numInst = d_user_gen[f][i]->addInstantiations( baseMatch ); - //if( d_user_gen[f][i]->isMultiTrigger() ) - Trace("process-trigger") << " Done, numInst = " << numInst << "." << std::endl; - d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_user_patterns += numInst; - if( d_user_gen[f][i]->isMultiTrigger() ){ - d_quantEngine->d_statistics.d_multi_trigger_instantiations += numInst; - } - //d_quantEngine->d_hasInstantiated[f] = true; - } - } - Debug("quant-uf-strategy") << "done." << std::endl; - //Notice() << "done" << std::endl; - } - return STATUS_UNKNOWN; -} - -void InstStrategyUserPatterns::addUserPattern( Node f, Node pat ){ - //add to generators - std::vector< Node > nodes; - for( int i=0; i<(int)pat.getNumChildren(); i++ ){ - nodes.push_back( pat[i] ); - } - if( Trigger::isUsableTrigger( nodes, f ) ){ - //extend to literal matching - d_quantEngine->getPhaseReqTerms( f, nodes ); - //check match option - int matchOption = options::efficientEMatching() ? InstMatchGenerator::MATCH_GEN_EFFICIENT_E_MATCH : 0; - d_user_gen[f].push_back( Trigger::mkTrigger( d_quantEngine, f, nodes, matchOption, true, Trigger::TR_MAKE_NEW, - options::smartTriggers() ) ); - } -} -/* -InstStrategyUserPatterns::Statistics::Statistics(): - d_instantiations("InstStrategyUserPatterns::Instantiations", 0) -{ - StatisticsRegistry::registerStat(&d_instantiations); -} - -InstStrategyUserPatterns::Statistics::~Statistics(){ - StatisticsRegistry::unregisterStat(&d_instantiations); -} -*/ - -void InstStrategyAutoGenTriggers::processResetInstantiationRound( Theory::Effort effort ){ - //reset triggers - for( std::map< Node, std::map< Trigger*, bool > >::iterator it = d_auto_gen_trigger.begin(); it != d_auto_gen_trigger.end(); ++it ){ - for( std::map< Trigger*, bool >::iterator itt = it->second.begin(); itt != it->second.end(); ++itt ){ - itt->first->resetInstantiationRound(); - itt->first->reset( Node::null() ); - } - } - d_processed_trigger.clear(); -} - -int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e ){ - int peffort = f.getNumChildren()==3 ? 2 : 1; - //int peffort = f.getNumChildren()==3 ? 2 : 1; - //int peffort = 1; - if( e::iterator itt = d_auto_gen_trigger[f].begin(); itt != d_auto_gen_trigger[f].end(); ++itt ){ - Trigger* tr = itt->first; - if( tr ){ - bool processTrigger = itt->second; - if( processTrigger && d_processed_trigger[f].find( tr )==d_processed_trigger[f].end() ){ - d_processed_trigger[f][tr] = true; - //if( tr->isMultiTrigger() ) - Trace("process-trigger") << " Process " << (*tr) << "..." << std::endl; - InstMatch baseMatch; - int numInst = tr->addInstantiations( baseMatch ); - //if( tr->isMultiTrigger() ) - Trace("process-trigger") << " Done, numInst = " << numInst << "." << std::endl; - if( d_tr_strategy==Trigger::TS_MIN_TRIGGER ){ - d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_auto_gen_min += numInst; - }else{ - d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_auto_gen += numInst; - } - if( tr->isMultiTrigger() ){ - d_quantEngine->d_statistics.d_multi_trigger_instantiations += numInst; - } - //d_quantEngine->d_hasInstantiated[f] = true; - } - } - } - Debug("quant-uf-strategy") << "done." << std::endl; - //Notice() << "done" << std::endl; - return status; - } -} - -void InstStrategyAutoGenTriggers::generateTriggers( Node f, Theory::Effort effort, int e, int & status ){ - Trace("auto-gen-trigger-debug") << "Generate trigger for " << f << std::endl; - if( d_patTerms[0].find( f )==d_patTerms[0].end() ){ - //determine all possible pattern terms based on trigger term selection strategy d_tr_strategy - d_patTerms[0][f].clear(); - d_patTerms[1][f].clear(); - std::vector< Node > patTermsF; - Trigger::collectPatTerms( d_quantEngine, f, d_quantEngine->getTermDatabase()->getInstConstantBody( f ), patTermsF, d_tr_strategy, true ); - Trace("auto-gen-trigger") << "Collected pat terms for " << d_quantEngine->getTermDatabase()->getInstConstantBody( f ) << std::endl; - Trace("auto-gen-trigger") << " "; - for( int i=0; i<(int)patTermsF.size(); i++ ){ - Trace("auto-gen-trigger") << patTermsF[i] << " "; - } - Trace("auto-gen-trigger") << std::endl; - //extend to literal matching (if applicable) - d_quantEngine->getPhaseReqTerms( f, patTermsF ); - //sort into single/multi triggers - std::map< Node, std::vector< Node > > varContains; - d_quantEngine->getTermDatabase()->getVarContains( f, patTermsF, varContains ); - for( std::map< Node, std::vector< Node > >::iterator it = varContains.begin(); it != varContains.end(); ++it ){ - if( it->second.size()==f[0].getNumChildren() ){ - d_patTerms[0][f].push_back( it->first ); - d_is_single_trigger[ it->first ] = true; - }else{ - d_patTerms[1][f].push_back( it->first ); - d_is_single_trigger[ it->first ] = false; - } - } - d_made_multi_trigger[f] = false; - Trace("auto-gen-trigger") << "Single triggers for " << f << " : " << std::endl; - Trace("auto-gen-trigger") << " "; - for( int i=0; i<(int)d_patTerms[0][f].size(); i++ ){ - Trace("auto-gen-trigger") << d_patTerms[0][f][i] << " "; - } - Trace("auto-gen-trigger") << std::endl; - Trace("auto-gen-trigger") << "Multi-trigger term pool for " << f << " : " << std::endl; - Trace("auto-gen-trigger") << " "; - for( int i=0; i<(int)d_patTerms[1][f].size(); i++ ){ - Trace("auto-gen-trigger") << d_patTerms[1][f][i] << " "; - } - Trace("auto-gen-trigger") << std::endl; - } - - //populate candidate pattern term vector for the current trigger - std::vector< Node > patTerms; - //try to add single triggers first - for( int i=0; i<(int)d_patTerms[0][f].size(); i++ ){ - if( !d_single_trigger_gen[d_patTerms[0][f][i]] ){ - patTerms.push_back( d_patTerms[0][f][i] ); - } - } - //if no single triggers exist, add multi trigger terms - if( patTerms.empty() ){ - patTerms.insert( patTerms.begin(), d_patTerms[1][f].begin(), d_patTerms[1][f].end() ); - } - - if( !patTerms.empty() ){ - Trace("auto-gen-trigger") << "Generate trigger for " << f << std::endl; - //sort terms based on relevance - if( d_rlv_strategy==RELEVANCE_DEFAULT ){ - sortQuantifiersForSymbol sqfs; - sqfs.d_qe = d_quantEngine; - //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++ ){ - Debug("relevant-trigger") << " " << patTerms[i] << " ("; - Debug("relevant-trigger") << d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( patTerms[i].getOperator() ) << ")" << std::endl; - } - //Notice() << "Terms based on relevance: " << std::endl; - //for( int i=0; i<(int)patTerms.size(); i++ ){ - // Notice() << " " << patTerms[i] << " ("; - // Notice() << d_quantEngine->getNumQuantifiersForSymbol( patTerms[i].getOperator() ) << ")" << std::endl; - //} - } - //now, generate the trigger... - int matchOption = options::efficientEMatching() ? InstMatchGenerator::MATCH_GEN_EFFICIENT_E_MATCH : 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() ); - d_single_trigger_gen[ patTerms[0] ] = true; - }else{ - //only generate multi trigger if effort level > 5, or if no single triggers exist - if( !d_patTerms[0][f].empty() ){ - if( e<=5 ){ - status = STATUS_UNFINISHED; - return; - }else{ - Trace("multi-trigger-debug") << "Resort to choosing multi-triggers..." << std::endl; - } - } - //if we are re-generating triggers, shuffle based on some method - if( d_made_multi_trigger[f] ){ -#ifndef MULTI_MULTI_TRIGGERS - return; -#endif - std::random_shuffle( patTerms.begin(), patTerms.end() ); //shuffle randomly - }else{ - 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() ); - } - if( tr ){ - if( tr->isMultiTrigger() ){ - //disable all other multi triggers - for( std::map< Trigger*, bool >::iterator it = d_auto_gen_trigger[f].begin(); it != d_auto_gen_trigger[f].end(); ++it ){ - if( it->first->isMultiTrigger() ){ - d_auto_gen_trigger[f][ it->first ] = false; - } - } - } - //making it during an instantiation round, so must reset - if( d_auto_gen_trigger[f].find( tr )==d_auto_gen_trigger[f].end() ){ - tr->resetInstantiationRound(); - tr->reset( Node::null() ); - } - d_auto_gen_trigger[f][tr] = true; - //if we are generating additional triggers... - if( d_generate_additional && d_is_single_trigger[ patTerms[0] ] ){ - int index = 0; - if( index<(int)patTerms.size() ){ - //Notice() << "check add additional" << std::endl; - //check if similar patterns exist, and if so, add them additionally - int nqfs_curr = d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( patTerms[0].getOperator() ); - index++; - bool success = true; - while( success && index<(int)patTerms.size() && d_is_single_trigger[ patTerms[index] ] ){ - success = false; - if( 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() ); - if( tr2 ){ - //Notice() << "Add additional trigger " << patTerms[index] << std::endl; - tr2->resetInstantiationRound(); - tr2->reset( Node::null() ); - d_auto_gen_trigger[f][tr2] = true; - } - success = true; - } - index++; - } - //Notice() << "done check add additional" << std::endl; - } - } - } - } -} -/* -InstStrategyAutoGenTriggers::Statistics::Statistics(): - d_instantiations("InstStrategyAutoGenTriggers::Instantiations", 0), - d_instantiations_min("InstStrategyAutoGenTriggers::Instantiations_min", 0) -{ - StatisticsRegistry::registerStat(&d_instantiations); - StatisticsRegistry::registerStat(&d_instantiations_min); -} - -InstStrategyAutoGenTriggers::Statistics::~Statistics(){ - StatisticsRegistry::unregisterStat(&d_instantiations); - StatisticsRegistry::unregisterStat(&d_instantiations_min); -} -*/ - -void InstStrategyFreeVariable::processResetInstantiationRound( Theory::Effort effort ){ -} - -int InstStrategyFreeVariable::process( Node f, Theory::Effort effort, int e ){ - if( e<5 ){ - return STATUS_UNFINISHED; - }else{ - if( d_guessed.find( f )==d_guessed.end() ){ - d_guessed[f] = true; - Debug("quant-uf-alg") << "Add guessed instantiation" << std::endl; - InstMatch m; - if( d_quantEngine->addInstantiation( f, m ) ){ - ++(d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_guess); - //d_quantEngine->d_hasInstantiated[f] = true; - } - } - return STATUS_UNKNOWN; - } -} -/* -InstStrategyFreeVariable::Statistics::Statistics(): - d_instantiations("InstStrategyGuess::Instantiations", 0) -{ - StatisticsRegistry::registerStat(&d_instantiations); -} - -InstStrategyFreeVariable::Statistics::~Statistics(){ - StatisticsRegistry::unregisterStat(&d_instantiations); -} -*/ +/********************* */ +/*! \file inst_strategy_e_matching.cpp + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: Morgan Deters + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Implementation of e matching instantiation strategies + **/ + +#include "theory/quantifiers/inst_strategy_e_matching.h" + +#include "theory/theory_engine.h" +#include "theory/quantifiers/options.h" +#include "theory/quantifiers/term_database.h" +#include "theory/quantifiers/inst_match_generator.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::inst; +using namespace CVC4::theory::quantifiers; + +//#define MULTI_TRIGGER_FULL_EFFORT_HALF +#define MULTI_MULTI_TRIGGERS + +struct sortQuantifiersForSymbol { + QuantifiersEngine* d_qe; + bool operator() (Node i, Node j) { + int nqfsi = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( i.getOperator() ); + int nqfsj = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( j.getOperator() ); + if( nqfsinqfsj ){ + return false; + }else{ + return false; + } + } +}; + +void InstStrategyUserPatterns::processResetInstantiationRound( Theory::Effort effort ){ + //reset triggers + for( std::map< Node, std::vector< Trigger* > >::iterator it = d_user_gen.begin(); it != d_user_gen.end(); ++it ){ + for( int i=0; i<(int)it->second.size(); i++ ){ + it->second[i]->resetInstantiationRound(); + it->second[i]->reset( Node::null() ); + } + } +} + +int InstStrategyUserPatterns::process( Node f, Theory::Effort effort, int e ){ + if( e==0 ){ + return STATUS_UNFINISHED; + }else if( e==1 ){ + d_counter[f]++; + Debug("quant-uf-strategy") << "Try user-provided patterns..." << std::endl; + //Notice() << "Try user-provided patterns..." << std::endl; + for( int i=0; i<(int)d_user_gen[f].size(); i++ ){ + bool processTrigger = true; + if( processTrigger ){ + //if( d_user_gen[f][i]->isMultiTrigger() ) + Trace("process-trigger") << " Process (user) " << (*d_user_gen[f][i]) << "..." << std::endl; + InstMatch baseMatch; + int numInst = d_user_gen[f][i]->addInstantiations( baseMatch ); + //if( d_user_gen[f][i]->isMultiTrigger() ) + Trace("process-trigger") << " Done, numInst = " << numInst << "." << std::endl; + d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_user_patterns += numInst; + if( d_user_gen[f][i]->isMultiTrigger() ){ + d_quantEngine->d_statistics.d_multi_trigger_instantiations += numInst; + } + //d_quantEngine->d_hasInstantiated[f] = true; + } + } + Debug("quant-uf-strategy") << "done." << std::endl; + //Notice() << "done" << std::endl; + } + return STATUS_UNKNOWN; +} + +void InstStrategyUserPatterns::addUserPattern( Node f, Node pat ){ + //add to generators + std::vector< Node > nodes; + for( int i=0; i<(int)pat.getNumChildren(); i++ ){ + nodes.push_back( pat[i] ); + } + if( Trigger::isUsableTrigger( nodes, f ) ){ + //extend to literal matching + d_quantEngine->getPhaseReqTerms( f, nodes ); + //check match option + int matchOption = options::efficientEMatching() ? InstMatchGenerator::MATCH_GEN_EFFICIENT_E_MATCH : 0; + d_user_gen[f].push_back( Trigger::mkTrigger( d_quantEngine, f, nodes, matchOption, true, Trigger::TR_MAKE_NEW, + options::smartTriggers() ) ); + } +} +/* +InstStrategyUserPatterns::Statistics::Statistics(): + d_instantiations("InstStrategyUserPatterns::Instantiations", 0) +{ + StatisticsRegistry::registerStat(&d_instantiations); +} + +InstStrategyUserPatterns::Statistics::~Statistics(){ + StatisticsRegistry::unregisterStat(&d_instantiations); +} +*/ + +void InstStrategyAutoGenTriggers::processResetInstantiationRound( Theory::Effort effort ){ + //reset triggers + for( std::map< Node, std::map< Trigger*, bool > >::iterator it = d_auto_gen_trigger.begin(); it != d_auto_gen_trigger.end(); ++it ){ + for( std::map< Trigger*, bool >::iterator itt = it->second.begin(); itt != it->second.end(); ++itt ){ + itt->first->resetInstantiationRound(); + itt->first->reset( Node::null() ); + } + } + d_processed_trigger.clear(); +} + +int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e ){ + int peffort = f.getNumChildren()==3 ? 2 : 1; + //int peffort = f.getNumChildren()==3 ? 2 : 1; + //int peffort = 1; + if( e::iterator itt = d_auto_gen_trigger[f].begin(); itt != d_auto_gen_trigger[f].end(); ++itt ){ + Trigger* tr = itt->first; + if( tr ){ + bool processTrigger = itt->second; + if( processTrigger && d_processed_trigger[f].find( tr )==d_processed_trigger[f].end() ){ + d_processed_trigger[f][tr] = true; + //if( tr->isMultiTrigger() ) + Trace("process-trigger") << " Process " << (*tr) << "..." << std::endl; + InstMatch baseMatch; + int numInst = tr->addInstantiations( baseMatch ); + //if( tr->isMultiTrigger() ) + Trace("process-trigger") << " Done, numInst = " << numInst << "." << std::endl; + if( d_tr_strategy==Trigger::TS_MIN_TRIGGER ){ + d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_auto_gen_min += numInst; + }else{ + d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_auto_gen += numInst; + } + if( tr->isMultiTrigger() ){ + d_quantEngine->d_statistics.d_multi_trigger_instantiations += numInst; + } + //d_quantEngine->d_hasInstantiated[f] = true; + } + } + } + Debug("quant-uf-strategy") << "done." << std::endl; + //Notice() << "done" << std::endl; + return status; + } +} + +void InstStrategyAutoGenTriggers::generateTriggers( Node f, Theory::Effort effort, int e, int & status ){ + Trace("auto-gen-trigger-debug") << "Generate trigger for " << f << std::endl; + if( d_patTerms[0].find( f )==d_patTerms[0].end() ){ + //determine all possible pattern terms based on trigger term selection strategy d_tr_strategy + d_patTerms[0][f].clear(); + d_patTerms[1][f].clear(); + std::vector< Node > patTermsF; + Trigger::collectPatTerms( d_quantEngine, f, d_quantEngine->getTermDatabase()->getInstConstantBody( f ), patTermsF, d_tr_strategy, true ); + Trace("auto-gen-trigger") << "Collected pat terms for " << d_quantEngine->getTermDatabase()->getInstConstantBody( f ) << std::endl; + Trace("auto-gen-trigger") << " "; + for( int i=0; i<(int)patTermsF.size(); i++ ){ + Trace("auto-gen-trigger") << patTermsF[i] << " "; + } + Trace("auto-gen-trigger") << std::endl; + //extend to literal matching (if applicable) + d_quantEngine->getPhaseReqTerms( f, patTermsF ); + //sort into single/multi triggers + std::map< Node, std::vector< Node > > varContains; + d_quantEngine->getTermDatabase()->getVarContains( f, patTermsF, varContains ); + for( std::map< Node, std::vector< Node > >::iterator it = varContains.begin(); it != varContains.end(); ++it ){ + if( it->second.size()==f[0].getNumChildren() ){ + d_patTerms[0][f].push_back( it->first ); + d_is_single_trigger[ it->first ] = true; + }else{ + d_patTerms[1][f].push_back( it->first ); + d_is_single_trigger[ it->first ] = false; + } + } + d_made_multi_trigger[f] = false; + Trace("auto-gen-trigger") << "Single triggers for " << f << " : " << std::endl; + Trace("auto-gen-trigger") << " "; + for( int i=0; i<(int)d_patTerms[0][f].size(); i++ ){ + Trace("auto-gen-trigger") << d_patTerms[0][f][i] << " "; + } + Trace("auto-gen-trigger") << std::endl; + Trace("auto-gen-trigger") << "Multi-trigger term pool for " << f << " : " << std::endl; + Trace("auto-gen-trigger") << " "; + for( int i=0; i<(int)d_patTerms[1][f].size(); i++ ){ + Trace("auto-gen-trigger") << d_patTerms[1][f][i] << " "; + } + Trace("auto-gen-trigger") << std::endl; + } + + //populate candidate pattern term vector for the current trigger + std::vector< Node > patTerms; + //try to add single triggers first + for( int i=0; i<(int)d_patTerms[0][f].size(); i++ ){ + if( !d_single_trigger_gen[d_patTerms[0][f][i]] ){ + patTerms.push_back( d_patTerms[0][f][i] ); + } + } + //if no single triggers exist, add multi trigger terms + if( patTerms.empty() ){ + patTerms.insert( patTerms.begin(), d_patTerms[1][f].begin(), d_patTerms[1][f].end() ); + } + + if( !patTerms.empty() ){ + Trace("auto-gen-trigger") << "Generate trigger for " << f << std::endl; + //sort terms based on relevance + if( d_rlv_strategy==RELEVANCE_DEFAULT ){ + sortQuantifiersForSymbol sqfs; + sqfs.d_qe = d_quantEngine; + //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++ ){ + Debug("relevant-trigger") << " " << patTerms[i] << " ("; + Debug("relevant-trigger") << d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( patTerms[i].getOperator() ) << ")" << std::endl; + } + //Notice() << "Terms based on relevance: " << std::endl; + //for( int i=0; i<(int)patTerms.size(); i++ ){ + // Notice() << " " << patTerms[i] << " ("; + // Notice() << d_quantEngine->getNumQuantifiersForSymbol( patTerms[i].getOperator() ) << ")" << std::endl; + //} + } + //now, generate the trigger... + int matchOption = options::efficientEMatching() ? InstMatchGenerator::MATCH_GEN_EFFICIENT_E_MATCH : 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() ); + d_single_trigger_gen[ patTerms[0] ] = true; + }else{ + //only generate multi trigger if effort level > 5, or if no single triggers exist + if( !d_patTerms[0][f].empty() ){ + if( e<=5 ){ + status = STATUS_UNFINISHED; + return; + }else{ + Trace("multi-trigger-debug") << "Resort to choosing multi-triggers..." << std::endl; + } + } + //if we are re-generating triggers, shuffle based on some method + if( d_made_multi_trigger[f] ){ +#ifndef MULTI_MULTI_TRIGGERS + return; +#endif + std::random_shuffle( patTerms.begin(), patTerms.end() ); //shuffle randomly + }else{ + 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() ); + } + if( tr ){ + if( tr->isMultiTrigger() ){ + //disable all other multi triggers + for( std::map< Trigger*, bool >::iterator it = d_auto_gen_trigger[f].begin(); it != d_auto_gen_trigger[f].end(); ++it ){ + if( it->first->isMultiTrigger() ){ + d_auto_gen_trigger[f][ it->first ] = false; + } + } + } + //making it during an instantiation round, so must reset + if( d_auto_gen_trigger[f].find( tr )==d_auto_gen_trigger[f].end() ){ + tr->resetInstantiationRound(); + tr->reset( Node::null() ); + } + d_auto_gen_trigger[f][tr] = true; + //if we are generating additional triggers... + if( d_generate_additional && d_is_single_trigger[ patTerms[0] ] ){ + int index = 0; + if( index<(int)patTerms.size() ){ + //Notice() << "check add additional" << std::endl; + //check if similar patterns exist, and if so, add them additionally + int nqfs_curr = d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( patTerms[0].getOperator() ); + index++; + bool success = true; + while( success && index<(int)patTerms.size() && d_is_single_trigger[ patTerms[index] ] ){ + success = false; + if( 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() ); + if( tr2 ){ + //Notice() << "Add additional trigger " << patTerms[index] << std::endl; + tr2->resetInstantiationRound(); + tr2->reset( Node::null() ); + d_auto_gen_trigger[f][tr2] = true; + } + success = true; + } + index++; + } + //Notice() << "done check add additional" << std::endl; + } + } + } + } +} +/* +InstStrategyAutoGenTriggers::Statistics::Statistics(): + d_instantiations("InstStrategyAutoGenTriggers::Instantiations", 0), + d_instantiations_min("InstStrategyAutoGenTriggers::Instantiations_min", 0) +{ + StatisticsRegistry::registerStat(&d_instantiations); + StatisticsRegistry::registerStat(&d_instantiations_min); +} + +InstStrategyAutoGenTriggers::Statistics::~Statistics(){ + StatisticsRegistry::unregisterStat(&d_instantiations); + StatisticsRegistry::unregisterStat(&d_instantiations_min); +} +*/ + +void InstStrategyFreeVariable::processResetInstantiationRound( Theory::Effort effort ){ +} + +int InstStrategyFreeVariable::process( Node f, Theory::Effort effort, int e ){ + if( e<5 ){ + return STATUS_UNFINISHED; + }else{ + if( d_guessed.find( f )==d_guessed.end() ){ + d_guessed[f] = true; + Debug("quant-uf-alg") << "Add guessed instantiation" << std::endl; + InstMatch m; + if( d_quantEngine->addInstantiation( f, m ) ){ + ++(d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_guess); + //d_quantEngine->d_hasInstantiated[f] = true; + } + } + return STATUS_UNKNOWN; + } +} +/* +InstStrategyFreeVariable::Statistics::Statistics(): + d_instantiations("InstStrategyGuess::Instantiations", 0) +{ + StatisticsRegistry::registerStat(&d_instantiations); +} + +InstStrategyFreeVariable::Statistics::~Statistics(){ + StatisticsRegistry::unregisterStat(&d_instantiations); +} +*/ diff --git a/src/theory/quantifiers/inst_strategy_e_matching.h b/src/theory/quantifiers/inst_strategy_e_matching.h old mode 100755 new mode 100644 index fa4094634..13d443c6a --- a/src/theory/quantifiers/inst_strategy_e_matching.h +++ b/src/theory/quantifiers/inst_strategy_e_matching.h @@ -1,137 +1,137 @@ -/********************* */ -/*! \file inst_strategy_e_matching.h - ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): bobot, mdeters - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief E matching instantiation strategies - **/ - -#include "cvc4_private.h" - -#ifndef __CVC4__INST_STRATEGY_E_MATCHING_H -#define __CVC4__INST_STRATEGY_E_MATCHING_H - -#include "theory/quantifiers_engine.h" -#include "theory/quantifiers/trigger.h" - -#include "context/context.h" -#include "context/context_mm.h" - -#include "util/statistics_registry.h" -#include "theory/quantifiers/instantiation_engine.h" - -namespace CVC4 { -namespace theory { -namespace quantifiers { - -//instantiation strategies - -class InstStrategyUserPatterns : public InstStrategy{ -private: - /** explicitly provided patterns */ - std::map< Node, std::vector< inst::Trigger* > > d_user_gen; - /** counter for quantifiers */ - std::map< Node, int > d_counter; - /** process functions */ - void processResetInstantiationRound( Theory::Effort effort ); - int process( Node f, Theory::Effort effort, int e ); -public: - InstStrategyUserPatterns( QuantifiersEngine* ie ) : - InstStrategy( ie ){} - ~InstStrategyUserPatterns(){} -public: - /** add pattern */ - void addUserPattern( Node f, Node pat ); - /** get num patterns */ - int getNumUserGenerators( Node f ) { return (int)d_user_gen[f].size(); } - /** get user pattern */ - inst::Trigger* getUserGenerator( Node f, int i ) { return d_user_gen[f][ i ]; } - /** identify */ - std::string identify() const { return std::string("UserPatterns"); } -};/* class InstStrategyUserPatterns */ - -class InstStrategyAutoGenTriggers : public InstStrategy{ -public: - enum { - RELEVANCE_NONE, - RELEVANCE_DEFAULT, - }; -private: - /** trigger generation strategy */ - int d_tr_strategy; - /** relevance strategy */ - int d_rlv_strategy; - /** regeneration */ - bool d_regenerate; - int d_regenerate_frequency; - /** generate additional triggers */ - bool d_generate_additional; - /** triggers for each quantifier */ - std::map< Node, std::map< inst::Trigger*, bool > > d_auto_gen_trigger; - std::map< Node, int > d_counter; - /** single, multi triggers for each quantifier */ - std::map< Node, std::vector< Node > > d_patTerms[2]; - std::map< Node, bool > d_is_single_trigger; - std::map< Node, bool > d_single_trigger_gen; - std::map< Node, bool > d_made_multi_trigger; - //processed trigger this round - std::map< Node, std::map< inst::Trigger*, bool > > d_processed_trigger; -private: - /** process functions */ - void processResetInstantiationRound( Theory::Effort effort ); - int process( Node f, Theory::Effort effort, int e ); - /** generate triggers */ - void generateTriggers( Node f, Theory::Effort effort, int e, int & status ); -public: - /** tstrt is the type of triggers to use (maximum depth, minimum depth, or all) - rstrt is the relevance setting for trigger (use only relevant triggers vs. use all) - rgfr is the frequency at which triggers are generated */ - InstStrategyAutoGenTriggers( QuantifiersEngine* qe, int tstrt, int rstrt, int rgfr = -1 ) : - InstStrategy( qe ), d_tr_strategy( tstrt ), d_rlv_strategy( rstrt ), d_generate_additional( false ){ - setRegenerateFrequency( rgfr ); - } - ~InstStrategyAutoGenTriggers(){} -public: - /** get auto-generated trigger */ - inst::Trigger* getAutoGenTrigger( Node f ); - /** identify */ - std::string identify() const { return std::string("AutoGenTriggers"); } - /** set regenerate frequency, if fr<0, turn off regenerate */ - void setRegenerateFrequency( int fr ){ - if( fr<0 ){ - d_regenerate = false; - }else{ - d_regenerate_frequency = fr; - d_regenerate = true; - } - } - /** set generate additional */ - void setGenerateAdditional( bool val ) { d_generate_additional = val; } -};/* class InstStrategyAutoGenTriggers */ - -class InstStrategyFreeVariable : public InstStrategy{ -private: - /** guessed instantiations */ - std::map< Node, bool > d_guessed; - /** process functions */ - void processResetInstantiationRound( Theory::Effort effort ); - int process( Node f, Theory::Effort effort, int e ); -public: - InstStrategyFreeVariable( QuantifiersEngine* qe ) : - InstStrategy( qe ){} - ~InstStrategyFreeVariable(){} - /** identify */ - std::string identify() const { return std::string("FreeVariable"); } -};/* class InstStrategyFreeVariable */ - -} -}/* CVC4::theory namespace */ -}/* CVC4 namespace */ - -#endif +/********************* */ +/*! \file inst_strategy_e_matching.h + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: Morgan Deters + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief E matching instantiation strategies + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__INST_STRATEGY_E_MATCHING_H +#define __CVC4__INST_STRATEGY_E_MATCHING_H + +#include "theory/quantifiers_engine.h" +#include "theory/quantifiers/trigger.h" + +#include "context/context.h" +#include "context/context_mm.h" + +#include "util/statistics_registry.h" +#include "theory/quantifiers/instantiation_engine.h" + +namespace CVC4 { +namespace theory { +namespace quantifiers { + +//instantiation strategies + +class InstStrategyUserPatterns : public InstStrategy{ +private: + /** explicitly provided patterns */ + std::map< Node, std::vector< inst::Trigger* > > d_user_gen; + /** counter for quantifiers */ + std::map< Node, int > d_counter; + /** process functions */ + void processResetInstantiationRound( Theory::Effort effort ); + int process( Node f, Theory::Effort effort, int e ); +public: + InstStrategyUserPatterns( QuantifiersEngine* ie ) : + InstStrategy( ie ){} + ~InstStrategyUserPatterns(){} +public: + /** add pattern */ + void addUserPattern( Node f, Node pat ); + /** get num patterns */ + int getNumUserGenerators( Node f ) { return (int)d_user_gen[f].size(); } + /** get user pattern */ + inst::Trigger* getUserGenerator( Node f, int i ) { return d_user_gen[f][ i ]; } + /** identify */ + std::string identify() const { return std::string("UserPatterns"); } +};/* class InstStrategyUserPatterns */ + +class InstStrategyAutoGenTriggers : public InstStrategy{ +public: + enum { + RELEVANCE_NONE, + RELEVANCE_DEFAULT, + }; +private: + /** trigger generation strategy */ + int d_tr_strategy; + /** relevance strategy */ + int d_rlv_strategy; + /** regeneration */ + bool d_regenerate; + int d_regenerate_frequency; + /** generate additional triggers */ + bool d_generate_additional; + /** triggers for each quantifier */ + std::map< Node, std::map< inst::Trigger*, bool > > d_auto_gen_trigger; + std::map< Node, int > d_counter; + /** single, multi triggers for each quantifier */ + std::map< Node, std::vector< Node > > d_patTerms[2]; + std::map< Node, bool > d_is_single_trigger; + std::map< Node, bool > d_single_trigger_gen; + std::map< Node, bool > d_made_multi_trigger; + //processed trigger this round + std::map< Node, std::map< inst::Trigger*, bool > > d_processed_trigger; +private: + /** process functions */ + void processResetInstantiationRound( Theory::Effort effort ); + int process( Node f, Theory::Effort effort, int e ); + /** generate triggers */ + void generateTriggers( Node f, Theory::Effort effort, int e, int & status ); +public: + /** tstrt is the type of triggers to use (maximum depth, minimum depth, or all) + rstrt is the relevance setting for trigger (use only relevant triggers vs. use all) + rgfr is the frequency at which triggers are generated */ + InstStrategyAutoGenTriggers( QuantifiersEngine* qe, int tstrt, int rstrt, int rgfr = -1 ) : + InstStrategy( qe ), d_tr_strategy( tstrt ), d_rlv_strategy( rstrt ), d_generate_additional( false ){ + setRegenerateFrequency( rgfr ); + } + ~InstStrategyAutoGenTriggers(){} +public: + /** get auto-generated trigger */ + inst::Trigger* getAutoGenTrigger( Node f ); + /** identify */ + std::string identify() const { return std::string("AutoGenTriggers"); } + /** set regenerate frequency, if fr<0, turn off regenerate */ + void setRegenerateFrequency( int fr ){ + if( fr<0 ){ + d_regenerate = false; + }else{ + d_regenerate_frequency = fr; + d_regenerate = true; + } + } + /** set generate additional */ + void setGenerateAdditional( bool val ) { d_generate_additional = val; } +};/* class InstStrategyAutoGenTriggers */ + +class InstStrategyFreeVariable : public InstStrategy{ +private: + /** guessed instantiations */ + std::map< Node, bool > d_guessed; + /** process functions */ + void processResetInstantiationRound( Theory::Effort effort ); + int process( Node f, Theory::Effort effort, int e ); +public: + InstStrategyFreeVariable( QuantifiersEngine* qe ) : + InstStrategy( qe ){} + ~InstStrategyFreeVariable(){} + /** identify */ + std::string identify() const { return std::string("FreeVariable"); } +};/* class InstStrategyFreeVariable */ + +} +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ + +#endif diff --git a/src/theory/quantifiers/macros.cpp b/src/theory/quantifiers/macros.cpp old mode 100755 new mode 100644 index c116b73f5..9f08764a9 --- a/src/theory/quantifiers/macros.cpp +++ b/src/theory/quantifiers/macros.cpp @@ -1,375 +1,375 @@ -/********************* */ -/*! \file macros.cpp - ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief Sort inference module - ** - ** This class implements quantifiers macro definitions. - **/ - -#include - -#include "theory/quantifiers/macros.h" -#include "theory/rewriter.h" - -using namespace CVC4; -using namespace std; -using namespace CVC4::theory; -using namespace CVC4::theory::quantifiers; -using namespace CVC4::kind; -using namespace CVC4::context; - -bool QuantifierMacros::simplify( std::vector< Node >& assertions, bool doRewrite ){ - //first, collect macro definitions - for( size_t i=0; i args; - for( size_t j=0; j > >::iterator it = d_macro_def_cases.begin(); - it != d_macro_def_cases.end(); ++it ){ - //create ite based on case definitions - Node val; - for( size_t i=0; isecond.size(); ++i ){ - if( it->second[i].first.isNull() ){ - Assert( i==0 ); - val = it->second[i].second; - }else{ - //if value is null, must generate it - if( val.isNull() ){ - std::stringstream ss; - ss << "mdo_" << it->first << "_$$"; - Node op = NodeManager::currentNM()->mkSkolem( ss.str(), it->first.getType(), "op created during macro definitions" ); - //will be defined in terms of fresh operator - std::vector< Node > children; - children.push_back( op ); - children.insert( children.end(), d_macro_basis[ it->first ].begin(), d_macro_basis[ it->first ].end() ); - val = NodeManager::currentNM()->mkNode( APPLY_UF, children ); - } - val = NodeManager::currentNM()->mkNode( ITE, it->second[i].first, it->second[i].second, val ); - } - } - d_macro_defs[ it->first ] = val; - Trace("macros-def") << "* " << val << " is a macro for " << it->first << std::endl; - } - //now simplify bodies - for( std::map< Node, Node >::iterator it = d_macro_defs.begin(); it != d_macro_defs.end(); ++it ){ - d_macro_defs[ it->first ] = Rewriter::rewrite( simplify( it->second ) ); - } - bool retVal = false; - if( doRewrite && !d_macro_defs.empty() ){ - //now, rewrite based on macro definitions - for( size_t i=0; i& candidates ){ - if( n.getKind()==APPLY_UF ){ - candidates.push_back( n ); - }else if( n.getKind()==PLUS ){ - for( size_t i=0; i plus_children; - //find monomial with n - for( size_t j=0; jmkConst( Rational(1) ); - }else if( lit[1][j].getKind()==MULT && lit[1][j][1]==n ){ - Assert( coeff.isNull() ); - Assert( lit[1][j][0].isConst() ); - coeff = lit[1][j][0]; - }else{ - plus_children.push_back( lit[1][j] ); - } - } - if( !coeff.isNull() ){ - term = NodeManager::currentNM()->mkNode( PLUS, plus_children ); - term = NodeManager::currentNM()->mkNode( MINUS, lit[0], term ); - } - } - if( !coeff.isNull() ){ - coeff = NodeManager::currentNM()->mkConst( Rational(1) / coeff.getConst() ); - term = NodeManager::currentNM()->mkNode( MULT, coeff, term ); - term = Rewriter::rewrite( term ); - return term; - } - } - } - Trace("macros-debug") << "Cannot find for " << lit << " " << n << std::endl; - return Node::null(); -} - -bool QuantifierMacros::isConsistentDefinition( Node op, Node cond, Node def ){ - if( d_macro_def_cases[op].empty() || ( cond.isNull() && !d_macro_def_cases[op][0].first.isNull() ) ){ - return true; - }else{ - return false; - } -} - -bool QuantifierMacros::getFreeVariables( Node n, std::vector< Node >& v_quant, std::vector< Node >& vars, bool retOnly ){ - if( std::find( v_quant.begin(), v_quant.end(), n )!=v_quant.end() ){ - if( std::find( vars.begin(), vars.end(), n )==vars.end() ){ - if( retOnly ){ - return true; - }else{ - vars.push_back( n ); - } - } - } - for( size_t i=0; i& v_quant, std::map< Node, Node >& solved, - std::vector< Node >& vars, std::vector< Node >& subs, bool reqComplete ){ - bool success = true; - for( size_t a=0; a& args, Node f ){ - if( n.getKind()==NOT ){ - process( n[0], !pol, args, f ); - }else if( n.getKind()==AND || n.getKind()==OR || n.getKind()==IMPLIES ){ - //bool favorPol = (n.getKind()==AND)==pol; - //conditional? - }else if( n.getKind()==ITE ){ - //can not do anything - }else{ - //literal case - if( isMacroLiteral( n, pol ) ){ - std::vector< Node > candidates; - for( size_t i=0; i fvs; - getFreeVariables( m, args, fvs, false ); - //get definition and condition - Node n_def = solveInEquality( m, n ); //definition for the macro - //definition must exist and not contain any free variables apart from fvs - if( !n_def.isNull() && !getFreeVariables( n_def, args, fvs, true ) ){ - Node n_cond; //condition when this definition holds - //conditional must not contain any free variables apart from fvs - if( n_cond.isNull() || !getFreeVariables( n_cond, args, fvs, true ) ){ - Trace("macros") << m << " is possible macro in " << f << std::endl; - //now we must rewrite candidates[i] to a term of form g( x1, ..., xn ) where - // x1 ... xn are distinct variables - if( d_macro_basis[op].empty() ){ - for( size_t a=0; amkSkolem( ss.str(), m[a].getType(), "created during macro definition recognition" ); - d_macro_basis[op].push_back( v ); - } - } - std::vector< Node > eq; - for( size_t a=0; a solved; - //solve obvious cases first - for( size_t a=0; a vars; - std::vector< Node > subs; - getSubstitution( fvs, solved, vars, subs, false ); - for( size_t a=0; a conds; - if( !n_cond.isNull() ){ - //must apply substitution obtained from solving system of equations to original condition - n_cond = n_cond.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); - conds.push_back( n_cond ); - } - for( size_t a=0; amkNode( eq[a].getType().isBoolean() ? IFF : EQUAL, d_macro_basis[op][a], eq[a] ) ); - } - } - //build the condition - if( !conds.empty() ){ - n_cond = conds.size()==1 ? conds[0] : NodeManager::currentNM()->mkNode( AND, conds ); - } - //apply the substitution to the - n_def = n_def.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); - //now see if definition is consistent with others - if( isConsistentDefinition( op, n_cond, n_def ) ){ - //must clear if it is a base definition - if( n_cond.isNull() ){ - d_macro_def_cases[ op ].clear(); - } - d_macro_def_cases[ op ].push_back( std::pair< Node, Node >( n_cond, n_def ) ); - } - } - } - } - } - } - } - } -} - -Node QuantifierMacros::simplify( Node n ){ - Trace("macros-debug") << "simplify " << n << std::endl; - std::vector< Node > children; - bool childChanged = false; - for( size_t i=0; imkNode( n.getKind(), children ); - }else{ - return n; - } -} +/********************* */ +/*! \file macros.cpp + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: Morgan Deters + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Sort inference module + ** + ** This class implements quantifiers macro definitions. + **/ + +#include + +#include "theory/quantifiers/macros.h" +#include "theory/rewriter.h" + +using namespace CVC4; +using namespace std; +using namespace CVC4::theory; +using namespace CVC4::theory::quantifiers; +using namespace CVC4::kind; +using namespace CVC4::context; + +bool QuantifierMacros::simplify( std::vector< Node >& assertions, bool doRewrite ){ + //first, collect macro definitions + for( size_t i=0; i args; + for( size_t j=0; j > >::iterator it = d_macro_def_cases.begin(); + it != d_macro_def_cases.end(); ++it ){ + //create ite based on case definitions + Node val; + for( size_t i=0; isecond.size(); ++i ){ + if( it->second[i].first.isNull() ){ + Assert( i==0 ); + val = it->second[i].second; + }else{ + //if value is null, must generate it + if( val.isNull() ){ + std::stringstream ss; + ss << "mdo_" << it->first << "_$$"; + Node op = NodeManager::currentNM()->mkSkolem( ss.str(), it->first.getType(), "op created during macro definitions" ); + //will be defined in terms of fresh operator + std::vector< Node > children; + children.push_back( op ); + children.insert( children.end(), d_macro_basis[ it->first ].begin(), d_macro_basis[ it->first ].end() ); + val = NodeManager::currentNM()->mkNode( APPLY_UF, children ); + } + val = NodeManager::currentNM()->mkNode( ITE, it->second[i].first, it->second[i].second, val ); + } + } + d_macro_defs[ it->first ] = val; + Trace("macros-def") << "* " << val << " is a macro for " << it->first << std::endl; + } + //now simplify bodies + for( std::map< Node, Node >::iterator it = d_macro_defs.begin(); it != d_macro_defs.end(); ++it ){ + d_macro_defs[ it->first ] = Rewriter::rewrite( simplify( it->second ) ); + } + bool retVal = false; + if( doRewrite && !d_macro_defs.empty() ){ + //now, rewrite based on macro definitions + for( size_t i=0; i& candidates ){ + if( n.getKind()==APPLY_UF ){ + candidates.push_back( n ); + }else if( n.getKind()==PLUS ){ + for( size_t i=0; i plus_children; + //find monomial with n + for( size_t j=0; jmkConst( Rational(1) ); + }else if( lit[1][j].getKind()==MULT && lit[1][j][1]==n ){ + Assert( coeff.isNull() ); + Assert( lit[1][j][0].isConst() ); + coeff = lit[1][j][0]; + }else{ + plus_children.push_back( lit[1][j] ); + } + } + if( !coeff.isNull() ){ + term = NodeManager::currentNM()->mkNode( PLUS, plus_children ); + term = NodeManager::currentNM()->mkNode( MINUS, lit[0], term ); + } + } + if( !coeff.isNull() ){ + coeff = NodeManager::currentNM()->mkConst( Rational(1) / coeff.getConst() ); + term = NodeManager::currentNM()->mkNode( MULT, coeff, term ); + term = Rewriter::rewrite( term ); + return term; + } + } + } + Trace("macros-debug") << "Cannot find for " << lit << " " << n << std::endl; + return Node::null(); +} + +bool QuantifierMacros::isConsistentDefinition( Node op, Node cond, Node def ){ + if( d_macro_def_cases[op].empty() || ( cond.isNull() && !d_macro_def_cases[op][0].first.isNull() ) ){ + return true; + }else{ + return false; + } +} + +bool QuantifierMacros::getFreeVariables( Node n, std::vector< Node >& v_quant, std::vector< Node >& vars, bool retOnly ){ + if( std::find( v_quant.begin(), v_quant.end(), n )!=v_quant.end() ){ + if( std::find( vars.begin(), vars.end(), n )==vars.end() ){ + if( retOnly ){ + return true; + }else{ + vars.push_back( n ); + } + } + } + for( size_t i=0; i& v_quant, std::map< Node, Node >& solved, + std::vector< Node >& vars, std::vector< Node >& subs, bool reqComplete ){ + bool success = true; + for( size_t a=0; a& args, Node f ){ + if( n.getKind()==NOT ){ + process( n[0], !pol, args, f ); + }else if( n.getKind()==AND || n.getKind()==OR || n.getKind()==IMPLIES ){ + //bool favorPol = (n.getKind()==AND)==pol; + //conditional? + }else if( n.getKind()==ITE ){ + //can not do anything + }else{ + //literal case + if( isMacroLiteral( n, pol ) ){ + std::vector< Node > candidates; + for( size_t i=0; i fvs; + getFreeVariables( m, args, fvs, false ); + //get definition and condition + Node n_def = solveInEquality( m, n ); //definition for the macro + //definition must exist and not contain any free variables apart from fvs + if( !n_def.isNull() && !getFreeVariables( n_def, args, fvs, true ) ){ + Node n_cond; //condition when this definition holds + //conditional must not contain any free variables apart from fvs + if( n_cond.isNull() || !getFreeVariables( n_cond, args, fvs, true ) ){ + Trace("macros") << m << " is possible macro in " << f << std::endl; + //now we must rewrite candidates[i] to a term of form g( x1, ..., xn ) where + // x1 ... xn are distinct variables + if( d_macro_basis[op].empty() ){ + for( size_t a=0; amkSkolem( ss.str(), m[a].getType(), "created during macro definition recognition" ); + d_macro_basis[op].push_back( v ); + } + } + std::vector< Node > eq; + for( size_t a=0; a solved; + //solve obvious cases first + for( size_t a=0; a vars; + std::vector< Node > subs; + getSubstitution( fvs, solved, vars, subs, false ); + for( size_t a=0; a conds; + if( !n_cond.isNull() ){ + //must apply substitution obtained from solving system of equations to original condition + n_cond = n_cond.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); + conds.push_back( n_cond ); + } + for( size_t a=0; amkNode( eq[a].getType().isBoolean() ? IFF : EQUAL, d_macro_basis[op][a], eq[a] ) ); + } + } + //build the condition + if( !conds.empty() ){ + n_cond = conds.size()==1 ? conds[0] : NodeManager::currentNM()->mkNode( AND, conds ); + } + //apply the substitution to the + n_def = n_def.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); + //now see if definition is consistent with others + if( isConsistentDefinition( op, n_cond, n_def ) ){ + //must clear if it is a base definition + if( n_cond.isNull() ){ + d_macro_def_cases[ op ].clear(); + } + d_macro_def_cases[ op ].push_back( std::pair< Node, Node >( n_cond, n_def ) ); + } + } + } + } + } + } + } + } +} + +Node QuantifierMacros::simplify( Node n ){ + Trace("macros-debug") << "simplify " << n << std::endl; + std::vector< Node > children; + bool childChanged = false; + for( size_t i=0; imkNode( n.getKind(), children ); + }else{ + return n; + } +} diff --git a/src/theory/quantifiers/macros.h b/src/theory/quantifiers/macros.h old mode 100755 new mode 100644 index b1fbb3e68..140f02966 --- a/src/theory/quantifiers/macros.h +++ b/src/theory/quantifiers/macros.h @@ -1,62 +1,62 @@ -/********************* */ -/*! \file macros.h - ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief Pre-process step for detecting quantifier macro definitions - **/ - -#include "cvc4_private.h" - -#ifndef __CVC4__QUANTIFIERS_MACROS_H -#define __CVC4__QUANTIFIERS_MACROS_H - -#include -#include -#include -#include -#include "expr/node.h" -#include "expr/type_node.h" - -namespace CVC4 { -namespace theory { -namespace quantifiers { - -class QuantifierMacros{ -private: - void process( Node n, bool pol, std::vector< Node >& args, Node f ); - bool contains( Node n, Node n_s ); - bool containsBadOp( Node n, Node n_op ); - bool isMacroLiteral( Node n, bool pol ); - void getMacroCandidates( Node n, std::vector< Node >& candidates ); - Node solveInEquality( Node n, Node lit ); - bool isConsistentDefinition( Node op, Node cond, Node def ); - bool getFreeVariables( Node n, std::vector< Node >& v_quant, std::vector< Node >& vars, bool retOnly ); - bool getSubstitution( std::vector< Node >& v_quant, std::map< Node, Node >& solved, - std::vector< Node >& vars, std::vector< Node >& subs, bool reqComplete ); - //map from operators to macro basis terms - std::map< Node, std::vector< Node > > d_macro_basis; - //map from operators to map from conditions to definition cases - std::map< Node, std::vector< std::pair< Node, Node > > > d_macro_def_cases; - //map from operators to macro definition - std::map< Node, Node > d_macro_defs; -private: - Node simplify( Node n ); -public: - QuantifierMacros(){} - ~QuantifierMacros(){} - - bool simplify( std::vector< Node >& assertions, bool doRewrite = false ); -}; - -} -} -} - -#endif +/********************* */ +/*! \file macros.h + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: Morgan Deters + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Pre-process step for detecting quantifier macro definitions + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__QUANTIFIERS_MACROS_H +#define __CVC4__QUANTIFIERS_MACROS_H + +#include +#include +#include +#include +#include "expr/node.h" +#include "expr/type_node.h" + +namespace CVC4 { +namespace theory { +namespace quantifiers { + +class QuantifierMacros{ +private: + void process( Node n, bool pol, std::vector< Node >& args, Node f ); + bool contains( Node n, Node n_s ); + bool containsBadOp( Node n, Node n_op ); + bool isMacroLiteral( Node n, bool pol ); + void getMacroCandidates( Node n, std::vector< Node >& candidates ); + Node solveInEquality( Node n, Node lit ); + bool isConsistentDefinition( Node op, Node cond, Node def ); + bool getFreeVariables( Node n, std::vector< Node >& v_quant, std::vector< Node >& vars, bool retOnly ); + bool getSubstitution( std::vector< Node >& v_quant, std::map< Node, Node >& solved, + std::vector< Node >& vars, std::vector< Node >& subs, bool reqComplete ); + //map from operators to macro basis terms + std::map< Node, std::vector< Node > > d_macro_basis; + //map from operators to map from conditions to definition cases + std::map< Node, std::vector< std::pair< Node, Node > > > d_macro_def_cases; + //map from operators to macro definition + std::map< Node, Node > d_macro_defs; +private: + Node simplify( Node n ); +public: + QuantifierMacros(){} + ~QuantifierMacros(){} + + bool simplify( std::vector< Node >& assertions, bool doRewrite = false ); +}; + +} +} +} + +#endif diff --git a/src/theory/quantifiers/quant_util.cpp b/src/theory/quantifiers/quant_util.cpp old mode 100755 new mode 100644 index d1b0e0fea..9e4a2a14a --- a/src/theory/quantifiers/quant_util.cpp +++ b/src/theory/quantifiers/quant_util.cpp @@ -1,145 +1,145 @@ -/********************* */ -/*! \file quant_util.cpp - ** \verbatim - ** Original author: ajreynol - ** Major contributors: bobot, mdeters - ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief Implementation of quantifier utilities - **/ - -#include "theory/quantifiers/quant_util.h" -#include "theory/quantifiers/inst_match.h" -#include "theory/quantifiers/term_database.h" - -using namespace std; -using namespace CVC4; -using namespace CVC4::kind; -using namespace CVC4::context; -using namespace CVC4::theory; - -void QuantRelevance::registerQuantifier( Node f ){ - //compute symbols in f - std::vector< Node > syms; - computeSymbols( f[1], syms ); - d_syms[f].insert( d_syms[f].begin(), syms.begin(), syms.end() ); - //set initial relevance - int minRelevance = -1; - for( int i=0; i<(int)syms.size(); i++ ){ - d_syms_quants[ syms[i] ].push_back( f ); - int r = getRelevance( syms[i] ); - if( r!=-1 && ( minRelevance==-1 || r& syms ){ - if( n.getKind()==APPLY_UF ){ - Node op = n.getOperator(); - if( std::find( syms.begin(), syms.end(), op )==syms.end() ){ - syms.push_back( op ); - } - } - if( n.getKind()!=FORALL ){ - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - computeSymbols( n[i], syms ); - } - } -} - -/** set relevance */ -void QuantRelevance::setRelevance( Node s, int r ){ - if( d_computeRel ){ - int rOld = getRelevance( s ); - if( rOld==-1 || r phaseReqs2; - computePhaseReqs( n, false, phaseReqs2 ); - for( std::map< Node, int >::iterator it = phaseReqs2.begin(); it != phaseReqs2.end(); ++it ){ - if( it->second==1 ){ - d_phase_reqs[ it->first ] = true; - }else if( it->second==-1 ){ - d_phase_reqs[ it->first ] = false; - } - } - Debug("inst-engine-phase-req") << "Phase requirements for " << n << ":" << std::endl; - //now, compute if any patterns are equality required - if( computeEq ){ - for( std::map< Node, bool >::iterator it = d_phase_reqs.begin(); it != d_phase_reqs.end(); ++it ){ - Debug("inst-engine-phase-req") << " " << it->first << " -> " << it->second << std::endl; - if( it->first.getKind()==EQUAL ){ - if( it->first[0].hasAttribute(InstConstantAttribute()) ){ - if( !it->first[1].hasAttribute(InstConstantAttribute()) ){ - d_phase_reqs_equality_term[ it->first[0] ] = it->first[1]; - d_phase_reqs_equality[ it->first[0] ] = it->second; - Debug("inst-engine-phase-req") << " " << it->first[0] << ( it->second ? " == " : " != " ) << it->first[1] << std::endl; - } - }else if( it->first[1].hasAttribute(InstConstantAttribute()) ){ - d_phase_reqs_equality_term[ it->first[1] ] = it->first[0]; - d_phase_reqs_equality[ it->first[1] ] = it->second; - Debug("inst-engine-phase-req") << " " << it->first[1] << ( it->second ? " == " : " != " ) << it->first[0] << std::endl; - } - } - } - } -} - -void QuantPhaseReq::computePhaseReqs( Node n, bool polarity, std::map< Node, int >& phaseReqs ){ - bool newReqPol = false; - bool newPolarity; - if( n.getKind()==NOT ){ - newReqPol = true; - newPolarity = !polarity; - }else if( n.getKind()==OR || n.getKind()==IMPLIES ){ - if( !polarity ){ - newReqPol = true; - newPolarity = false; - } - }else if( n.getKind()==AND ){ - if( polarity ){ - newReqPol = true; - newPolarity = true; - } - }else{ - int val = polarity ? 1 : -1; - if( phaseReqs.find( n )==phaseReqs.end() ){ - phaseReqs[n] = val; - }else if( val!=phaseReqs[n] ){ - phaseReqs[n] = 0; - } - } - if( newReqPol ){ - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - if( n.getKind()==IMPLIES && i==0 ){ - computePhaseReqs( n[i], !newPolarity, phaseReqs ); - }else{ - computePhaseReqs( n[i], newPolarity, phaseReqs ); - } - } - } -} +/********************* */ +/*! \file quant_util.cpp + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: Morgan Deters + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Implementation of quantifier utilities + **/ + +#include "theory/quantifiers/quant_util.h" +#include "theory/quantifiers/inst_match.h" +#include "theory/quantifiers/term_database.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; + +void QuantRelevance::registerQuantifier( Node f ){ + //compute symbols in f + std::vector< Node > syms; + computeSymbols( f[1], syms ); + d_syms[f].insert( d_syms[f].begin(), syms.begin(), syms.end() ); + //set initial relevance + int minRelevance = -1; + for( int i=0; i<(int)syms.size(); i++ ){ + d_syms_quants[ syms[i] ].push_back( f ); + int r = getRelevance( syms[i] ); + if( r!=-1 && ( minRelevance==-1 || r& syms ){ + if( n.getKind()==APPLY_UF ){ + Node op = n.getOperator(); + if( std::find( syms.begin(), syms.end(), op )==syms.end() ){ + syms.push_back( op ); + } + } + if( n.getKind()!=FORALL ){ + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + computeSymbols( n[i], syms ); + } + } +} + +/** set relevance */ +void QuantRelevance::setRelevance( Node s, int r ){ + if( d_computeRel ){ + int rOld = getRelevance( s ); + if( rOld==-1 || r phaseReqs2; + computePhaseReqs( n, false, phaseReqs2 ); + for( std::map< Node, int >::iterator it = phaseReqs2.begin(); it != phaseReqs2.end(); ++it ){ + if( it->second==1 ){ + d_phase_reqs[ it->first ] = true; + }else if( it->second==-1 ){ + d_phase_reqs[ it->first ] = false; + } + } + Debug("inst-engine-phase-req") << "Phase requirements for " << n << ":" << std::endl; + //now, compute if any patterns are equality required + if( computeEq ){ + for( std::map< Node, bool >::iterator it = d_phase_reqs.begin(); it != d_phase_reqs.end(); ++it ){ + Debug("inst-engine-phase-req") << " " << it->first << " -> " << it->second << std::endl; + if( it->first.getKind()==EQUAL ){ + if( it->first[0].hasAttribute(InstConstantAttribute()) ){ + if( !it->first[1].hasAttribute(InstConstantAttribute()) ){ + d_phase_reqs_equality_term[ it->first[0] ] = it->first[1]; + d_phase_reqs_equality[ it->first[0] ] = it->second; + Debug("inst-engine-phase-req") << " " << it->first[0] << ( it->second ? " == " : " != " ) << it->first[1] << std::endl; + } + }else if( it->first[1].hasAttribute(InstConstantAttribute()) ){ + d_phase_reqs_equality_term[ it->first[1] ] = it->first[0]; + d_phase_reqs_equality[ it->first[1] ] = it->second; + Debug("inst-engine-phase-req") << " " << it->first[1] << ( it->second ? " == " : " != " ) << it->first[0] << std::endl; + } + } + } + } +} + +void QuantPhaseReq::computePhaseReqs( Node n, bool polarity, std::map< Node, int >& phaseReqs ){ + bool newReqPol = false; + bool newPolarity; + if( n.getKind()==NOT ){ + newReqPol = true; + newPolarity = !polarity; + }else if( n.getKind()==OR || n.getKind()==IMPLIES ){ + if( !polarity ){ + newReqPol = true; + newPolarity = false; + } + }else if( n.getKind()==AND ){ + if( polarity ){ + newReqPol = true; + newPolarity = true; + } + }else{ + int val = polarity ? 1 : -1; + if( phaseReqs.find( n )==phaseReqs.end() ){ + phaseReqs[n] = val; + }else if( val!=phaseReqs[n] ){ + phaseReqs[n] = 0; + } + } + if( newReqPol ){ + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + if( n.getKind()==IMPLIES && i==0 ){ + computePhaseReqs( n[i], !newPolarity, phaseReqs ); + }else{ + computePhaseReqs( n[i], newPolarity, phaseReqs ); + } + } + } +} diff --git a/src/theory/quantifiers/quant_util.h b/src/theory/quantifiers/quant_util.h old mode 100755 new mode 100644 index bb6855c47..85602dbab --- a/src/theory/quantifiers/quant_util.h +++ b/src/theory/quantifiers/quant_util.h @@ -1,99 +1,99 @@ -/********************* */ -/*! \file quant_util.h - ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): mdeters, bobot - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief quantifier util - **/ - -#include "cvc4_private.h" - -#ifndef __CVC4__THEORY__QUANT_UTIL_H -#define __CVC4__THEORY__QUANT_UTIL_H - -#include "theory/theory.h" -#include "theory/uf/equality_engine.h" - -#include -#include -#include - -namespace CVC4 { -namespace theory { - - -class QuantRelevance -{ -private: - /** for computing relavance */ - bool d_computeRel; - /** map from quantifiers to symbols they contain */ - std::map< Node, std::vector< Node > > d_syms; - /** map from symbols to quantifiers */ - std::map< Node, std::vector< Node > > d_syms_quants; - /** relevance for quantifiers and symbols */ - std::map< Node, int > d_relevance; - /** compute symbols */ - void computeSymbols( Node n, std::vector< Node >& syms ); -public: - QuantRelevance( bool cr ) : d_computeRel( cr ){} - ~QuantRelevance(){} - /** register quantifier */ - void registerQuantifier( Node f ); - /** set relevance */ - void setRelevance( Node s, int r ); - /** get relevance */ - int getRelevance( Node s ) { return d_relevance.find( s )==d_relevance.end() ? -1 : d_relevance[s]; } - /** get number of quantifiers for symbol s */ - int getNumQuantifiersForSymbol( Node s ) { return (int)d_syms_quants[s].size(); } -}; - -class QuantPhaseReq -{ -private: - /** helper functions compute phase requirements */ - void computePhaseReqs( Node n, bool polarity, std::map< Node, int >& phaseReqs ); -public: - QuantPhaseReq( Node n, bool computeEq = false ); - ~QuantPhaseReq(){} - /** is phase required */ - bool isPhaseReq( Node lit ) { return d_phase_reqs.find( lit )!=d_phase_reqs.end(); } - /** get phase requirement */ - bool getPhaseReq( Node lit ) { return d_phase_reqs.find( lit )==d_phase_reqs.end() ? false : d_phase_reqs[ lit ]; } - /** phase requirements for each quantifier for each instantiation literal */ - std::map< Node, bool > d_phase_reqs; - std::map< Node, bool > d_phase_reqs_equality; - std::map< Node, Node > d_phase_reqs_equality_term; -}; - - -class EqualityQuery { -public: - EqualityQuery(){} - virtual ~EqualityQuery(){}; - /** reset */ - virtual void reset() = 0; - /** contains term */ - virtual bool hasTerm( Node a ) = 0; - /** get the representative of the equivalence class of a */ - virtual Node getRepresentative( Node a ) = 0; - /** returns true if a and b are equal in the current context */ - virtual bool areEqual( Node a, Node b ) = 0; - /** returns true is a and b are disequal in the current context */ - virtual bool areDisequal( Node a, Node b ) = 0; - /** get the equality engine associated with this query */ - virtual eq::EqualityEngine* getEngine() = 0; - /** get the equivalence class of a */ - virtual void getEquivalenceClass( Node a, std::vector< Node >& eqc ) = 0; -};/* class EqualityQuery */ - -} -} - -#endif +/********************* */ +/*! \file quant_util.h + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: Morgan Deters + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief quantifier util + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY__QUANT_UTIL_H +#define __CVC4__THEORY__QUANT_UTIL_H + +#include "theory/theory.h" +#include "theory/uf/equality_engine.h" + +#include +#include +#include + +namespace CVC4 { +namespace theory { + + +class QuantRelevance +{ +private: + /** for computing relavance */ + bool d_computeRel; + /** map from quantifiers to symbols they contain */ + std::map< Node, std::vector< Node > > d_syms; + /** map from symbols to quantifiers */ + std::map< Node, std::vector< Node > > d_syms_quants; + /** relevance for quantifiers and symbols */ + std::map< Node, int > d_relevance; + /** compute symbols */ + void computeSymbols( Node n, std::vector< Node >& syms ); +public: + QuantRelevance( bool cr ) : d_computeRel( cr ){} + ~QuantRelevance(){} + /** register quantifier */ + void registerQuantifier( Node f ); + /** set relevance */ + void setRelevance( Node s, int r ); + /** get relevance */ + int getRelevance( Node s ) { return d_relevance.find( s )==d_relevance.end() ? -1 : d_relevance[s]; } + /** get number of quantifiers for symbol s */ + int getNumQuantifiersForSymbol( Node s ) { return (int)d_syms_quants[s].size(); } +}; + +class QuantPhaseReq +{ +private: + /** helper functions compute phase requirements */ + void computePhaseReqs( Node n, bool polarity, std::map< Node, int >& phaseReqs ); +public: + QuantPhaseReq( Node n, bool computeEq = false ); + ~QuantPhaseReq(){} + /** is phase required */ + bool isPhaseReq( Node lit ) { return d_phase_reqs.find( lit )!=d_phase_reqs.end(); } + /** get phase requirement */ + bool getPhaseReq( Node lit ) { return d_phase_reqs.find( lit )==d_phase_reqs.end() ? false : d_phase_reqs[ lit ]; } + /** phase requirements for each quantifier for each instantiation literal */ + std::map< Node, bool > d_phase_reqs; + std::map< Node, bool > d_phase_reqs_equality; + std::map< Node, Node > d_phase_reqs_equality_term; +}; + + +class EqualityQuery { +public: + EqualityQuery(){} + virtual ~EqualityQuery(){}; + /** reset */ + virtual void reset() = 0; + /** contains term */ + virtual bool hasTerm( Node a ) = 0; + /** get the representative of the equivalence class of a */ + virtual Node getRepresentative( Node a ) = 0; + /** returns true if a and b are equal in the current context */ + virtual bool areEqual( Node a, Node b ) = 0; + /** returns true is a and b are disequal in the current context */ + virtual bool areDisequal( Node a, Node b ) = 0; + /** get the equality engine associated with this query */ + virtual eq::EqualityEngine* getEngine() = 0; + /** get the equivalence class of a */ + virtual void getEquivalenceClass( Node a, std::vector< Node >& eqc ) = 0; +};/* class EqualityQuery */ + +} +} + +#endif diff --git a/src/theory/quantifiers/quantifiers_attributes.cpp b/src/theory/quantifiers/quantifiers_attributes.cpp index 2f6dc47db..b00fe45f4 100644 --- a/src/theory/quantifiers/quantifiers_attributes.cpp +++ b/src/theory/quantifiers/quantifiers_attributes.cpp @@ -1,41 +1,41 @@ /********************* */ /*! \file quantifiers_attributes.cpp ** \verbatim - ** Original author: ajreynol - ** Major contributors: none + ** Original author: Andrew Reynolds + ** Major contributors: Morgan Deters ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** - ** \brief Implementation of QuantifiersAttributes class - **/ - -#include "theory/quantifiers/quantifiers_attributes.h" -#include "theory/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; - -void QuantifiersAttributes::setUserAttribute( const std::string& attr, Node n ){ - if( n.getKind()==FORALL ){ - if( attr=="axiom" ){ - Trace("quant-attr") << "Set axiom " << n << std::endl; - AxiomAttribute aa; - n.setAttribute( aa, true ); - }else if( attr=="conjecture" ){ - Trace("quant-attr") << "Set conjecture " << n << std::endl; - ConjectureAttribute ca; - n.setAttribute( ca, true ); - } - }else{ - for( size_t i=0; i + ** Major contributors: Morgan Deters ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** - ** \brief Attributes for the theory quantifiers - ** - ** Attributes for the theory quantifiers. - **/ - -#include "cvc4_private.h" - -#ifndef __CVC4__THEORY__QUANTIFIERS__QUANTIFIERS_REWRITER_H -#define __CVC4__THEORY__QUANTIFIERS__QUANTIFIERS_REWRITER_H - -#include "theory/rewriter.h" -#include "theory/quantifiers_engine.h" - -namespace CVC4 { -namespace theory { -namespace quantifiers { - -/** Attribute true for quantifiers that are axioms */ -struct AxiomAttributeId {}; -typedef expr::Attribute< AxiomAttributeId, bool > AxiomAttribute; - -/** Attribute true for quantifiers that are conjecture */ -struct ConjectureAttributeId {}; -typedef expr::Attribute< ConjectureAttributeId, bool > ConjectureAttribute; - -struct QuantifiersAttributes -{ - /** set user attribute - * 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 ); -}; - - -} -} -} - -#endif + ** \brief Attributes for the theory quantifiers + ** + ** Attributes for the theory quantifiers. + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY__QUANTIFIERS__QUANTIFIERS_REWRITER_H +#define __CVC4__THEORY__QUANTIFIERS__QUANTIFIERS_REWRITER_H + +#include "theory/rewriter.h" +#include "theory/quantifiers_engine.h" + +namespace CVC4 { +namespace theory { +namespace quantifiers { + +/** Attribute true for quantifiers that are axioms */ +struct AxiomAttributeId {}; +typedef expr::Attribute< AxiomAttributeId, bool > AxiomAttribute; + +/** Attribute true for quantifiers that are conjecture */ +struct ConjectureAttributeId {}; +typedef expr::Attribute< ConjectureAttributeId, bool > ConjectureAttribute; + +struct QuantifiersAttributes +{ + /** set user attribute + * 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 ); +}; + + +} +} +} + +#endif diff --git a/src/theory/rep_set.cpp b/src/theory/rep_set.cpp index b50878e70..4ae7f2d0c 100644 --- a/src/theory/rep_set.cpp +++ b/src/theory/rep_set.cpp @@ -1,231 +1,231 @@ /********************* */ /*! \file rep_set.cpp ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): mdeters - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** Original author: Andrew Reynolds + ** Major contributors: Morgan Deters + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** - ** \brief Implementation of representative set - **/ - -#include "theory/rep_set.h" -#include "theory/type_enumerator.h" - -using namespace std; -using namespace CVC4; -using namespace CVC4::kind; -using namespace CVC4::context; -using namespace CVC4::theory; - -void RepSet::clear(){ - d_type_reps.clear(); - d_type_complete.clear(); - d_tmap.clear(); -} - -int RepSet::getNumRepresentatives( TypeNode tn ) const{ - std::map< TypeNode, std::vector< Node > >::const_iterator it = d_type_reps.find( tn ); - if( it!=d_type_reps.end() ){ - return (int)it->second.size(); - }else{ - return 0; - } -} - -void RepSet::add( Node n ){ - TypeNode t = n.getType(); - d_tmap[ n ] = (int)d_type_reps[t].size(); - d_type_reps[t].push_back( n ); -} - -int RepSet::getIndexFor( Node n ) const { - std::map< Node, int >::const_iterator it = d_tmap.find( n ); - if( it!=d_tmap.end() ){ - return it->second; - }else{ - return -1; - } -} - -void RepSet::complete( TypeNode t ){ - if( d_type_complete.find( t )==d_type_complete.end() ){ - d_type_complete[t] = true; - TypeEnumerator te(t); - while( !te.isFinished() ){ - Node n = *te; - if( std::find( d_type_reps[t].begin(), d_type_reps[t].end(), n )==d_type_reps[t].end() ){ - add( n ); - } - ++te; - } - for( size_t i=0; i >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){ - out << it->first << " : " << std::endl; - for( int i=0; i<(int)it->second.size(); i++ ){ - out << " " << i << ": " << it->second[i] << std::endl; - } - } -#else - for( std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){ - if( !it->first.isFunction() && !it->first.isPredicate() ){ - out << "(" << it->first << " " << it->second.size(); - out << " ("; - for( int i=0; i<(int)it->second.size(); i++ ){ - if( i>0 ){ out << " "; } - out << it->second[i]; - } - out << ")"; - out << ")" << std::endl; - } - } -#endif -} - - -RepSetIterator::RepSetIterator( RepSet* rs ) : d_rep_set( rs ){ - d_incomplete = false; - -} - -bool RepSetIterator::setQuantifier( Node f ){ - Assert( d_types.empty() ); - //store indicies - for( size_t i=0; ihasType( tn ) ){ - Node var = NodeManager::currentNM()->mkSkolem( "repSet_$$", tn, "is a variable created by the RepSetIterator" ); - Trace("mkVar") << "RepSetIterator:: Make variable " << var << " : " << tn << std::endl; - d_rep_set->add( var ); - } - }else if( tn.isInteger() || tn.isReal() ){ - Trace("fmf-incomplete") << "Incomplete because of infinite type " << tn << std::endl; - d_incomplete = true; - }else if( tn.isDatatype() ){ - const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype(); - //if finite, then complete all values of the domain - if( dt.isFinite() ){ - d_rep_set->complete( tn ); - //d_incomplete = true; - }else{ - Trace("fmf-incomplete") << "Incomplete because of infinite datatype " << tn << std::endl; - d_incomplete = true; - } - }else{ - Trace("fmf-incomplete") << "Incomplete because of unknown type " << tn << std::endl; - d_incomplete = true; - } - if( d_rep_set->hasType( tn ) ){ - for( size_t j=0; jd_type_reps[tn].size(); j++ ){ - d_domain[i].push_back( j ); - } - }else{ - return false; - } - } - return true; -} - -void RepSetIterator::setIndexOrder( std::vector< int >& indexOrder ){ - d_index_order.clear(); - d_index_order.insert( d_index_order.begin(), indexOrder.begin(), indexOrder.end() ); - //make the d_var_order mapping - for( int i=0; i<(int)d_index_order.size(); i++ ){ - d_var_order[d_index_order[i]] = i; - } -} - -void RepSetIterator::setDomain( std::vector< RepDomain >& domain ){ - d_domain.clear(); - d_domain.insert( d_domain.begin(), domain.begin(), domain.end() ); - //we are done if a domain is empty - for( int i=0; i<(int)d_domain.size(); i++ ){ - if( d_domain[i].empty() ){ - d_index.clear(); - } - } -} - -void RepSetIterator::increment2( int counter ){ - Assert( !isFinished() ); -#ifdef DISABLE_EVAL_SKIP_MULTIPLE - counter = (int)d_index.size()-1; -#endif - //increment d_index - while( counter>=0 && d_index[counter]==(int)(d_domain[counter].size()-1) ){ - counter--; - } - if( counter==-1 ){ - d_index.clear(); - }else{ - for( int i=(int)d_index.size()-1; i>counter; i-- ){ - d_index[i] = 0; - } - d_index[counter]++; - } -} - -void RepSetIterator::increment(){ - if( !isFinished() ){ - increment2( (int)d_index.size()-1 ); - } -} - -bool RepSetIterator::isFinished(){ - return d_index.empty(); -} - -Node RepSetIterator::getTerm( int i ){ - TypeNode tn = d_types[d_index_order[i]]; - Assert( d_rep_set->d_type_reps.find( tn )!=d_rep_set->d_type_reps.end() ); - int index = d_index_order[i]; - return d_rep_set->d_type_reps[tn][d_domain[index][d_index[index]]]; -} - -void RepSetIterator::debugPrint( const char* c ){ - for( int i=0; i<(int)d_index.size(); i++ ){ - Debug( c ) << i << " : " << d_index[i] << " : " << getTerm( i ) << std::endl; - } -} - -void RepSetIterator::debugPrintSmall( const char* c ){ - Debug( c ) << "RI: "; - for( int i=0; i<(int)d_index.size(); i++ ){ - Debug( c ) << d_index[i] << ": " << getTerm( i ) << " "; - } - Debug( c ) << std::endl; -} + ** \brief Implementation of representative set + **/ + +#include "theory/rep_set.h" +#include "theory/type_enumerator.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; + +void RepSet::clear(){ + d_type_reps.clear(); + d_type_complete.clear(); + d_tmap.clear(); +} + +int RepSet::getNumRepresentatives( TypeNode tn ) const{ + std::map< TypeNode, std::vector< Node > >::const_iterator it = d_type_reps.find( tn ); + if( it!=d_type_reps.end() ){ + return (int)it->second.size(); + }else{ + return 0; + } +} + +void RepSet::add( Node n ){ + TypeNode t = n.getType(); + d_tmap[ n ] = (int)d_type_reps[t].size(); + d_type_reps[t].push_back( n ); +} + +int RepSet::getIndexFor( Node n ) const { + std::map< Node, int >::const_iterator it = d_tmap.find( n ); + if( it!=d_tmap.end() ){ + return it->second; + }else{ + return -1; + } +} + +void RepSet::complete( TypeNode t ){ + if( d_type_complete.find( t )==d_type_complete.end() ){ + d_type_complete[t] = true; + TypeEnumerator te(t); + while( !te.isFinished() ){ + Node n = *te; + if( std::find( d_type_reps[t].begin(), d_type_reps[t].end(), n )==d_type_reps[t].end() ){ + add( n ); + } + ++te; + } + for( size_t i=0; i >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){ + out << it->first << " : " << std::endl; + for( int i=0; i<(int)it->second.size(); i++ ){ + out << " " << i << ": " << it->second[i] << std::endl; + } + } +#else + for( std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){ + if( !it->first.isFunction() && !it->first.isPredicate() ){ + out << "(" << it->first << " " << it->second.size(); + out << " ("; + for( int i=0; i<(int)it->second.size(); i++ ){ + if( i>0 ){ out << " "; } + out << it->second[i]; + } + out << ")"; + out << ")" << std::endl; + } + } +#endif +} + + +RepSetIterator::RepSetIterator( RepSet* rs ) : d_rep_set( rs ){ + d_incomplete = false; + +} + +bool RepSetIterator::setQuantifier( Node f ){ + Assert( d_types.empty() ); + //store indicies + for( size_t i=0; ihasType( tn ) ){ + Node var = NodeManager::currentNM()->mkSkolem( "repSet_$$", tn, "is a variable created by the RepSetIterator" ); + Trace("mkVar") << "RepSetIterator:: Make variable " << var << " : " << tn << std::endl; + d_rep_set->add( var ); + } + }else if( tn.isInteger() || tn.isReal() ){ + Trace("fmf-incomplete") << "Incomplete because of infinite type " << tn << std::endl; + d_incomplete = true; + }else if( tn.isDatatype() ){ + const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype(); + //if finite, then complete all values of the domain + if( dt.isFinite() ){ + d_rep_set->complete( tn ); + //d_incomplete = true; + }else{ + Trace("fmf-incomplete") << "Incomplete because of infinite datatype " << tn << std::endl; + d_incomplete = true; + } + }else{ + Trace("fmf-incomplete") << "Incomplete because of unknown type " << tn << std::endl; + d_incomplete = true; + } + if( d_rep_set->hasType( tn ) ){ + for( size_t j=0; jd_type_reps[tn].size(); j++ ){ + d_domain[i].push_back( j ); + } + }else{ + return false; + } + } + return true; +} + +void RepSetIterator::setIndexOrder( std::vector< int >& indexOrder ){ + d_index_order.clear(); + d_index_order.insert( d_index_order.begin(), indexOrder.begin(), indexOrder.end() ); + //make the d_var_order mapping + for( int i=0; i<(int)d_index_order.size(); i++ ){ + d_var_order[d_index_order[i]] = i; + } +} + +void RepSetIterator::setDomain( std::vector< RepDomain >& domain ){ + d_domain.clear(); + d_domain.insert( d_domain.begin(), domain.begin(), domain.end() ); + //we are done if a domain is empty + for( int i=0; i<(int)d_domain.size(); i++ ){ + if( d_domain[i].empty() ){ + d_index.clear(); + } + } +} + +void RepSetIterator::increment2( int counter ){ + Assert( !isFinished() ); +#ifdef DISABLE_EVAL_SKIP_MULTIPLE + counter = (int)d_index.size()-1; +#endif + //increment d_index + while( counter>=0 && d_index[counter]==(int)(d_domain[counter].size()-1) ){ + counter--; + } + if( counter==-1 ){ + d_index.clear(); + }else{ + for( int i=(int)d_index.size()-1; i>counter; i-- ){ + d_index[i] = 0; + } + d_index[counter]++; + } +} + +void RepSetIterator::increment(){ + if( !isFinished() ){ + increment2( (int)d_index.size()-1 ); + } +} + +bool RepSetIterator::isFinished(){ + return d_index.empty(); +} + +Node RepSetIterator::getTerm( int i ){ + TypeNode tn = d_types[d_index_order[i]]; + Assert( d_rep_set->d_type_reps.find( tn )!=d_rep_set->d_type_reps.end() ); + int index = d_index_order[i]; + return d_rep_set->d_type_reps[tn][d_domain[index][d_index[index]]]; +} + +void RepSetIterator::debugPrint( const char* c ){ + for( int i=0; i<(int)d_index.size(); i++ ){ + Debug( c ) << i << " : " << d_index[i] << " : " << getTerm( i ) << std::endl; + } +} + +void RepSetIterator::debugPrintSmall( const char* c ){ + Debug( c ) << "RI: "; + for( int i=0; i<(int)d_index.size(); i++ ){ + Debug( c ) << d_index[i] << ": " << getTerm( i ) << " "; + } + Debug( c ) << std::endl; +} diff --git a/src/theory/rep_set.h b/src/theory/rep_set.h index 61b2ebf9f..dc31f2d5f 100644 --- a/src/theory/rep_set.h +++ b/src/theory/rep_set.h @@ -1,112 +1,112 @@ /********************* */ /*! \file rep_set.h ** \verbatim - ** Original author: ajreynol - ** Major contributors: none + ** Original author: Andrew Reynolds + ** Major contributors: Morgan Deters ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** - ** \brief Representative set class and utilities - **/ - -#include "cvc4_private.h" - -#ifndef __CVC4__REP_SET_H -#define __CVC4__REP_SET_H - -#include "expr/node.h" -#include - -namespace CVC4 { -namespace theory { - -/** this class stores a representative set */ -class RepSet { -public: - RepSet(){} - ~RepSet(){} - std::map< TypeNode, std::vector< Node > > d_type_reps; - std::map< TypeNode, bool > d_type_complete; - std::map< Node, int > d_tmap; - /** clear the set */ - void clear(); - /** has type */ - bool hasType( TypeNode tn ) const { return d_type_reps.find( tn )!=d_type_reps.end(); } - /** get cardinality for type */ - int getNumRepresentatives( TypeNode tn ) const; - /** add representative for type */ - void add( Node n ); - /** returns index in d_type_reps for node n */ - int getIndexFor( Node n ) const; - /** complete all values */ - void complete( TypeNode t ); - /** debug print */ - void toStream(std::ostream& out); -}; - -//representative domain -typedef std::vector< int > RepDomain; - -/** this class iterates over a RepSet */ -class RepSetIterator { -private: - //initialize function - bool initialize(); -public: - RepSetIterator( RepSet* rs ); - ~RepSetIterator(){} - //set that this iterator will be iterating over instantiations for a quantifier - bool setQuantifier( Node f ); - //set that this iterator will be iterating over the domain of a function - bool setFunctionDomain( Node op ); -public: - //pointer to model - RepSet* d_rep_set; - //index we are considering - std::vector< int > d_index; - //types we are considering - std::vector< TypeNode > d_types; - //domain we are considering - std::vector< RepDomain > d_domain; - //are we only considering a strict subset of the domain of the quantifier? - bool d_incomplete; - //ordering for variables we are indexing over - // for example, given reps = { a, b } and quantifier forall( x, y, z ) P( x, y, z ) with d_index_order = { 2, 0, 1 }, - // then we consider instantiations in this order: - // a/x a/y a/z - // a/x b/y a/z - // b/x a/y a/z - // b/x b/y a/z - // ... - std::vector< int > d_index_order; - //variables to index they are considered at - // for example, if d_index_order = { 2, 0, 1 } - // then d_var_order = { 0 -> 1, 1 -> 2, 2 -> 0 } - std::map< int, int > d_var_order; -public: - /** set index order */ - void setIndexOrder( std::vector< int >& indexOrder ); - /** set domain */ - void setDomain( std::vector< RepDomain >& domain ); - /** increment the iterator at index=counter */ - void increment2( int counter ); - /** increment the iterator */ - void increment(); - /** is the iterator finished? */ - bool isFinished(); - /** get the i_th term we are considering */ - Node getTerm( int i ); - /** get the number of terms we are considering */ - int getNumTerms() { return (int)d_index_order.size(); } - /** debug print */ - void debugPrint( const char* c ); - void debugPrintSmall( const char* c ); -}; - -} -} - + ** \brief Representative set class and utilities + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__REP_SET_H +#define __CVC4__REP_SET_H + +#include "expr/node.h" +#include + +namespace CVC4 { +namespace theory { + +/** this class stores a representative set */ +class RepSet { +public: + RepSet(){} + ~RepSet(){} + std::map< TypeNode, std::vector< Node > > d_type_reps; + std::map< TypeNode, bool > d_type_complete; + std::map< Node, int > d_tmap; + /** clear the set */ + void clear(); + /** has type */ + bool hasType( TypeNode tn ) const { return d_type_reps.find( tn )!=d_type_reps.end(); } + /** get cardinality for type */ + int getNumRepresentatives( TypeNode tn ) const; + /** add representative for type */ + void add( Node n ); + /** returns index in d_type_reps for node n */ + int getIndexFor( Node n ) const; + /** complete all values */ + void complete( TypeNode t ); + /** debug print */ + void toStream(std::ostream& out); +}; + +//representative domain +typedef std::vector< int > RepDomain; + +/** this class iterates over a RepSet */ +class RepSetIterator { +private: + //initialize function + bool initialize(); +public: + RepSetIterator( RepSet* rs ); + ~RepSetIterator(){} + //set that this iterator will be iterating over instantiations for a quantifier + bool setQuantifier( Node f ); + //set that this iterator will be iterating over the domain of a function + bool setFunctionDomain( Node op ); +public: + //pointer to model + RepSet* d_rep_set; + //index we are considering + std::vector< int > d_index; + //types we are considering + std::vector< TypeNode > d_types; + //domain we are considering + std::vector< RepDomain > d_domain; + //are we only considering a strict subset of the domain of the quantifier? + bool d_incomplete; + //ordering for variables we are indexing over + // for example, given reps = { a, b } and quantifier forall( x, y, z ) P( x, y, z ) with d_index_order = { 2, 0, 1 }, + // then we consider instantiations in this order: + // a/x a/y a/z + // a/x b/y a/z + // b/x a/y a/z + // b/x b/y a/z + // ... + std::vector< int > d_index_order; + //variables to index they are considered at + // for example, if d_index_order = { 2, 0, 1 } + // then d_var_order = { 0 -> 1, 1 -> 2, 2 -> 0 } + std::map< int, int > d_var_order; +public: + /** set index order */ + void setIndexOrder( std::vector< int >& indexOrder ); + /** set domain */ + void setDomain( std::vector< RepDomain >& domain ); + /** increment the iterator at index=counter */ + void increment2( int counter ); + /** increment the iterator */ + void increment(); + /** is the iterator finished? */ + bool isFinished(); + /** get the i_th term we are considering */ + Node getTerm( int i ); + /** get the number of terms we are considering */ + int getNumTerms() { return (int)d_index_order.size(); } + /** debug print */ + void debugPrint( const char* c ); + void debugPrintSmall( const char* c ); +}; + +} +} + #endif \ No newline at end of file diff --git a/src/theory/rewriterules/efficient_e_matching.cpp b/src/theory/rewriterules/efficient_e_matching.cpp old mode 100755 new mode 100644 index 2f39d8098..5ed34d46c --- a/src/theory/rewriterules/efficient_e_matching.cpp +++ b/src/theory/rewriterules/efficient_e_matching.cpp @@ -1,686 +1,686 @@ -/********************* */ -/*! \file efficient_e_matching.cpp - ** \verbatim - ** Original author: ajreynol - ** Major contributors: bobot - ** Minor contributors (to current version): mdeters - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief Implementation of theory uf instantiator class - **/ - -#include "theory/rewriterules/efficient_e_matching.h" -#include "theory/rewriterules/rr_candidate_generator.h" -#include "theory/quantifiers/candidate_generator.h" -#include "theory/quantifiers/options.h" -#include "theory/rewriterules/options.h" -#include "theory/quantifiers/term_database.h" - -#include "theory/theory_engine.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 { - -inline std::ostream& operator<<(std::ostream& out, const EfficientEMatcher::Ips& ips) { - return out; -}; - -EqClassInfo::EqClassInfo( context::Context* c ) : d_funs( c ), d_pfuns( c ), d_disequal( c ){ - -} - -//set member -void EqClassInfo::setMember( Node n, quantifiers::TermDb* db ){ - if( n.hasOperator() ){ - d_funs.insertAtContextLevelZero(n.getOperator(),true); - } - //add parent functions - for( std::hash_map< Node, std::hash_map< int, std::vector< Node > >, NodeHashFunction >::iterator it = db->d_parents[n].begin(); - it != db->d_parents[n].end(); ++it ){ - //TODO Is it true to do it at level 0? That depend when SetMember is called - // At worst it is a good overapproximation - d_pfuns.insertAtContextLevelZero( it->first, true); - } -} - -//get has function -bool EqClassInfo::hasFunction( Node op ){ - return d_funs.find( op )!=d_funs.end(); -} - -bool EqClassInfo::hasParent( Node op ){ - return d_pfuns.find( op )!=d_pfuns.end(); -} - -//merge with another eq class info -void EqClassInfo::merge( EqClassInfo* eci ){ - for( BoolMap::iterator it = eci->d_funs.begin(); it != eci->d_funs.end(); it++ ) { - d_funs[ (*it).first ] = true; - } - for( BoolMap::iterator it = eci->d_pfuns.begin(); it != eci->d_pfuns.end(); it++ ) { - d_pfuns[ (*it).first ] = true; - } -} - -inline void outputEqClassInfo( const char* c, const EqClassInfo* eci){ - Debug(c) << " funs:"; - for( EqClassInfo::BoolMap::iterator it = eci->d_funs.begin(); it != eci->d_funs.end(); it++ ) { - Debug(c) << (*it).first << ","; - } - Debug(c) << std::endl << "pfuns:"; - for( EqClassInfo::BoolMap::iterator it = eci->d_pfuns.begin(); it != eci->d_pfuns.end(); it++ ) { - Debug(c) << (*it).first << ","; - } - Debug(c) << std::endl; -} - - - -EfficientEMatcher::EfficientEMatcher( CVC4::theory::QuantifiersEngine* qe ) : d_quantEngine( qe ) -{ - -} - -eq::EqualityEngine* EfficientEMatcher::getEqualityEngine(){ - //return ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getEqualityEngine(); - return d_quantEngine->getMasterEqualityEngine(); -} - -/** new node */ -void EfficientEMatcher::newEqClass( TNode n ){ - -} - -void EfficientEMatcher::newTerms(SetNode& s){ - static NoMatchAttribute rewrittenNodeAttribute; - /* op -> nodes (if the set is empty, the op is not interesting) */ - std::hash_map< TNode, SetNode, TNodeHashFunction > h; - /* types -> nodes (if the set is empty, the type is not interesting) */ - std::hash_map< TypeNode, SetNode, TypeNodeHashFunction > tyh; - for(SetNode::iterator i=s.begin(), end=s.end(); i != end; ++i){ - if (i->getAttribute(rewrittenNodeAttribute)) continue; /* skip it */ - if( !d_cand_gens.empty() ){ - // op - TNode op = i->getOperator(); - std::hash_map< TNode, SetNode, TNodeHashFunction >::iterator - is = h.find(op); - if(is == h.end()){ - std::pair::iterator,bool> - p = h.insert(make_pair(op,SetNode())); - is = p.first; - if(d_cand_gens.find(op) != d_cand_gens.end()){ - is->second.insert(*i); - } /* else we have inserted an empty set */ - }else if(!is->second.empty()){ - is->second.insert(*i); - } - } - if( !d_cand_gen_types.empty() ){ - //type - TypeNode ty = i->getType(); - std::hash_map< TypeNode, SetNode, TypeNodeHashFunction >::iterator - is = tyh.find(ty); - if(is == tyh.end()){ - std::pair::iterator,bool> - p = tyh.insert(make_pair(ty,SetNode())); - is = p.first; - if(d_cand_gen_types.find(ty) != d_cand_gen_types.end()){ - is->second.insert(*i); - } /* else we have inserted an empty set */ - }else if(!is->second.empty()){ - is->second.insert(*i); - } - } - } - //op - for(std::hash_map< TNode, SetNode, TNodeHashFunction >::iterator i=h.begin(), end=h.end(); - i != end; ++i){ - //new term, add n to candidate generators - if(i->second.empty()) continue; - std::map< Node, NodeNewTermDispatcher >::iterator - inpc = d_cand_gens.find(i->first); - //we know that this op exists - Assert(inpc != d_cand_gens.end()); - inpc->second.send(i->second); - } - //type - for(std::hash_map< TypeNode, SetNode, TypeNodeHashFunction >::iterator i=tyh.begin(), end=tyh.end(); - i != end; ++i){ - //new term, add n to candidate generators - if(i->second.empty()) continue; - std::map< TypeNode, NodeNewTermDispatcher >::iterator - inpc = d_cand_gen_types.find(i->first); - //we know that this op exists - Assert(inpc != d_cand_gen_types.end()); - inpc->second.send(i->second); - } - -} - - -/** merge */ -void EfficientEMatcher::merge( TNode a, TNode b ){ - if( options::efficientEMatching() ){ - //merge eqc_ops of b into a - EqClassInfo* eci_a = getOrCreateEquivalenceClassInfo( a ); - EqClassInfo* eci_b = getOrCreateEquivalenceClassInfo( b ); - - if( a.getKind()!=IFF && a.getKind()!=EQUAL && b.getKind()!=IFF && b.getKind()!=EQUAL ){ - Debug("efficient-e-match") << "Merging " << a << " with " << b << std::endl; - - //determine new candidates for instantiation - computeCandidatesPcPairs( a, eci_a, b, eci_b ); - computeCandidatesPcPairs( b, eci_b, a, eci_a ); - computeCandidatesPpPairs( a, eci_a, b, eci_b ); - computeCandidatesPpPairs( b, eci_b, a, eci_a ); - } - computeCandidatesConstants( a, eci_a, b, eci_b); - computeCandidatesConstants( b, eci_b, a, eci_a); - - eci_a->merge( eci_b ); - } -} - -/** assert terms are disequal */ -void EfficientEMatcher::assertDisequal( TNode a, TNode b, TNode reason ){ - -} - -EqClassInfo* EfficientEMatcher::getEquivalenceClassInfo( Node n ) { - return d_eqc_ops.find( n )==d_eqc_ops.end() ? NULL : d_eqc_ops[n]; -} -EqClassInfo* EfficientEMatcher::getOrCreateEquivalenceClassInfo( Node n ){ - Assert( n==getEqualityEngine()->getRepresentative( n ) ); - if( d_eqc_ops.find( n )==d_eqc_ops.end() ){ - EqClassInfo* eci = new EqClassInfo( d_quantEngine->getSatContext() ); - eci->setMember( n, d_quantEngine->getTermDatabase() ); - d_eqc_ops[n] = eci; - } - return d_eqc_ops[n]; -} - -void EfficientEMatcher::computeCandidatesPcPairs( Node a, EqClassInfo* eci_a, Node b, EqClassInfo* eci_b ){ - Debug("efficient-e-match") << "Compute candidates for pc pairs..." << std::endl; - Debug("efficient-e-match") << " Eq class = ["; - outputEqClass( "efficient-e-match", a); - Debug("efficient-e-match") << "]" << std::endl; - outputEqClassInfo("efficient-e-match",eci_a); - for( EqClassInfo::BoolMap::iterator it = eci_a->d_funs.begin(); it != eci_a->d_funs.end(); it++ ) { - //the child function: a member of eq_class( a ) has top symbol g, in other words g is in funs( a ) - Node g = (*it).first; - Debug("efficient-e-match") << " Checking application " << g << std::endl; - //look at all parent/child pairs - for( std::map< Node, std::vector< std::pair< NodePcDispatcher*, Ips > > >::iterator itf = d_pc_pairs[g].begin(); - itf != d_pc_pairs[g].end(); ++itf ){ - //f/g is a parent/child pair - Node f = itf->first; - if( eci_b->hasParent( f ) ){ - //DO_THIS: determine if f in pfuns( b ), only do the follow if so - Debug("efficient-e-match") << " Checking parent application " << f << std::endl; - //scan through the list of inverted path strings/candidate generators - for( std::vector< std::pair< NodePcDispatcher*, Ips > >::iterator cit = itf->second.begin(); - cit != itf->second.end(); ++cit ){ -#ifdef CVC4_DEBUG - Debug("efficient-e-match") << " Checking pattern " << cit->first->pat << std::endl; -#endif - Debug("efficient-e-match") << " Check inverted path string for pattern "; - outputIps( "efficient-e-match", cit->second ); - Debug("efficient-e-match") << std::endl; - - //collect all new relevant terms - SetNode terms; - terms.insert( b ); - collectTermsIps( cit->second, terms ); - if( terms.empty() ) continue; - Debug("efficient-e-match") << " -> Added terms (" << terms.size() << "): "; - for( SetNode::const_iterator t=terms.begin(), end=terms.end(); - t!=end; ++t ){ - Debug("efficient-e-match") << (*t) << " "; - } - Debug("efficient-e-match") << std::endl; - //add them as candidates to the candidate generator - cit->first->send(terms); - } - } - } - } -} - -void EfficientEMatcher::computeCandidatesPpPairs( Node a, EqClassInfo* eci_a, Node b, EqClassInfo* eci_b ){ - Debug("efficient-e-match") << "Compute candidates for pp pairs..." << std::endl; - for( std::map< Node, std::map< Node, std::vector< triple< NodePpDispatcher*, Ips, Ips > > > >::iterator it = d_pp_pairs.begin(); - it != d_pp_pairs.end(); ++it ){ - Node f = it->first; - if( eci_a->hasParent( f ) ){ - Debug("efficient-e-match") << " Checking parent application " << f << std::endl; - for( std::map< Node, std::vector< triple > >::iterator it2 = it->second.begin(); - it2 != it->second.end(); ++it2 ){ - Node g = it2->first; - if( eci_b->hasParent( g ) ){ - Debug("efficient-e-match") << " Checking parent application " << g << std::endl; - //if f in pfuns( a ) and g is in pfuns( b ), only do the follow if so - for( std::vector< triple > ::iterator cit = it2->second.begin(); - cit != it2->second.end(); ++cit ){ -#ifdef CVC4_DEBUG - Debug("efficient-e-match") << " Checking pattern " << cit->first->pat1 << " and " << cit->first->pat2 << std::endl; -#endif - Debug("efficient-e-match") << " Check inverted path string "; - outputIps( "efficient-e-match", cit->second ); - SetNode a_terms; - a_terms.insert( a ); - collectTermsIps( cit->second, a_terms ); - if( a_terms.empty() ) continue; - Debug("efficient-e-match") << " And check inverted path string "; - outputIps( "efficient-e-match", cit->third ); - SetNode b_terms; - b_terms.insert( b ); - collectTermsIps( cit->third, b_terms ); - if( b_terms.empty() ) continue; - //Start debug - Debug("efficient-e-match") << " -> Possibly Added termsA (" << a_terms.size() << "): "; - for( SetNode::const_iterator t=a_terms.begin(), end=a_terms.end(); - t!=end; ++t ){ - Debug("efficient-e-match") << (*t) << " "; - } - Debug("efficient-e-match") << std::endl; - Debug("efficient-e-match") << " -> Possibly Added termsB (" << b_terms.size() << "): "; - for( SetNode::const_iterator t=b_terms.begin(), end=b_terms.end(); - t!=end; ++t ){ - Debug("efficient-e-match") << (*t) << " "; - } - Debug("efficient-e-match") << std::endl; - //End debug - - cit->first->send(a_terms,b_terms); - } - } - } - } - } -} - - -void EfficientEMatcher::computeCandidatesConstants( Node a, EqClassInfo* eci_a, Node b, EqClassInfo* eci_b ){ - Debug("efficient-e-match") << "Compute candidates constants for cc pairs..." << std::endl; - Debug("efficient-e-match") << " Eq class = ["; - outputEqClass( "efficient-e-match", a); - Debug("efficient-e-match") << "]" << std::endl; - outputEqClassInfo("efficient-e-match",eci_a); - for( std::map< Node, std::map< Node, NodePcDispatcher* > >::iterator - it = d_cc_pairs.begin(), end = d_cc_pairs.end(); - it != end; ++it ) { - Debug("efficient-e-match") << " Checking application " << it->first << std::endl; - if( !eci_b->hasFunction(it->first) ) continue; - for( std::map< Node, NodePcDispatcher* >::iterator - itc = it->second.begin(), end = it->second.end(); - itc != end; ++itc ) { - //The constant - Debug("efficient-e-match") << " Checking constant " << a << std::endl; - if(getEqualityEngine()->getRepresentative(itc->first) != a) continue; - SetNode s; - eq::EqClassIterator eqc_iter( b, getEqualityEngine() ); - while( !eqc_iter.isFinished() ){ - Debug("efficient-e-match-debug") << "> look at " << (*eqc_iter) - << std::endl; - if( (*eqc_iter).hasOperator() && (*eqc_iter).getOperator() == it->first ) s.insert(*eqc_iter); - eqc_iter++; - } - - if( s.empty() ) continue; - Debug("efficient-e-match") << " -> Added terms (" << s.size() << "): "; - for( SetNode::const_iterator t=s.begin(), end=s.end(); - t!=end; ++t ){ - Debug("efficient-e-match") << (*t) << " "; - } - Debug("efficient-e-match") << std::endl; - itc->second->send(s); - } - } -} - -void EfficientEMatcher::collectTermsIps( Ips& ips, SetNode & terms ){ - Assert( ips.size() > 0); - return collectTermsIps( ips, terms, ips.size() - 1); -} - -void EfficientEMatcher::collectTermsIps( Ips& ips, SetNode& terms, int index ){ - if( !terms.empty() ){ - Debug("efficient-e-match-debug") << "> Process " << index << std::endl; - Node f = ips[index].first; - int arg = ips[index].second; - - //for each term in terms, determine if any term (modulo equality) has parent "f" from position "arg" - bool addRep = ( index!=0 ); // We want to keep the top symbol for the last - SetNode newTerms; - for( SetNode::const_iterator t=terms.begin(), end=terms.end(); - t!=end; ++t ){ - collectParentsTermsIps( *t, f, arg, newTerms, addRep ); - } - terms.swap(newTerms); - - Debug("efficient-e-match-debug") << "> Terms are now: "; - for( SetNode::const_iterator t=terms.begin(), end=terms.end(); - t!=end; ++t ){ - Debug("efficient-e-match-debug") << *t << " "; - } - Debug("efficient-e-match-debug") << std::endl; - - if(index!=0) collectTermsIps( ips, terms, index-1 ); - } -} - -bool EfficientEMatcher::collectParentsTermsIps( Node n, Node f, int arg, SetNode & terms, bool addRep, bool modEq ){ //modEq default true - bool addedTerm = false; - - if( modEq && getEqualityEngine()->hasTerm( n )){ - Assert( getEqualityEngine()->getRepresentative( n )==n ); - //collect modulo equality - //DO_THIS: this should (if necessary) compute a current set of (f, arg) parents for n and cache it - eq::EqClassIterator eqc_iter( n, getEqualityEngine() ); - while( !eqc_iter.isFinished() ){ - Debug("efficient-e-match-debug") << "> look at " << (*eqc_iter) - << std::endl; - if( collectParentsTermsIps( (*eqc_iter), f, arg, terms, addRep, false ) ){ - //if only one argument, we know we can stop (since all others added will be congruent) - if( f.getType().getNumChildren()==2 ){ - return true; - } - addedTerm = true; - } - eqc_iter++; - } - }else{ - quantifiers::TermDb* db = d_quantEngine->getTermDatabase(); - //see if parent f exists from argument arg - const std::vector & parents = db->getParents(n,f,arg); - for( size_t i=0; igetRepresentative( t ); - terms.insert(t); - addedTerm = true; - } - } - return addedTerm; -} - -void EfficientEMatcher::registerPatternElementPairs2( Node pat, Ips& ips, PpIpsMap & pp_ips_map, NodePcDispatcher* npc ){ - Assert( pat.hasOperator() ); - //add information for possible pp-pair - ips.push_back( std::pair< Node, int >( pat.getOperator(), 0 ) ); //0 is just a dumb value - - for( int i=0; i<(int)pat.getNumChildren(); i++ ){ - if( pat[i].getKind()==INST_CONSTANT ){ - ips.back().second = i; - pp_ips_map[ pat[i] ].push_back( make_pair( pat.getOperator(), Ips( ips ) ) ); - } - } - - for( int i=0; i<(int)pat.getNumChildren(); i++ ){ - if( pat[i].getKind()==APPLY_UF ){ - ips.back().second = i; - registerPatternElementPairs2( pat[i], ips, pp_ips_map, npc ); - Debug("pattern-element-opt") << "Found pc-pair ( " << pat.getOperator() << ", " << pat[i].getOperator() << " )" << std::endl; - Debug("pattern-element-opt") << " Path = "; - outputIps( "pattern-element-opt", ips ); - Debug("pattern-element-opt") << std::endl; - //pat.getOperator() and pat[i].getOperator() are a pc-pair - d_pc_pairs[ pat[i].getOperator() ][ pat.getOperator() ] - .push_back( make_pair(npc,Ips(ips)) ); - } - } - ips.pop_back(); -} - -void EfficientEMatcher::registerPatternElementPairs( Node pat, PpIpsMap & pp_ips_map, - NodePcDispatcher* npc, - NodePpDispatcher* npp){ - Ips ips; - registerPatternElementPairs2( pat, ips, pp_ips_map, npc ); - for( PpIpsMap::iterator it = pp_ips_map.begin(); it != pp_ips_map.end(); ++it ){ - // for each variable construct all the pp-pair - for( size_t j=0; jsecond.size(); j++ ){ - for( size_t k=j+1; ksecond.size(); k++ ){ - //found a pp-pair - Debug("pattern-element-opt") << "Found pp-pair ( " << it->second[j].first << ", " << it->second[k].first << " )" << std::endl; - Debug("pattern-element-opt") << " Paths = "; - outputIps( "pattern-element-opt", it->second[j].second ); - Debug("pattern-element-opt") << " and "; - outputIps( "pattern-element-opt", it->second[k].second ); - Debug("pattern-element-opt") << std::endl; - d_pp_pairs[ it->second[j].first ][ it->second[k].first ] - .push_back( make_triple( npp, it->second[j].second, it->second[k].second )); - } - } - } -}; - -void findPpSite(Node pat, EfficientEMatcher::Ips& ips, EfficientEMatcher::PpIpsMap & pp_ips_map){ - Assert( pat.getKind()==APPLY_UF ); - //add information for possible pp-pair - - ips.push_back( make_pair( pat.getOperator(), 0) ); - for( size_t i=0; i & pats){ - hash_map npps; - for( PpIpsMap::iterator it = pp_ips_map.begin(); it != pp_ips_map.end(); ++it ){ - MultiPpIpsMap::iterator mit = multi_pp_ips_map.find(it->first); - if(mit == multi_pp_ips_map.end()) continue; - // for each variable construct all the pp-pair - // j the last pattern treated - for( std::vector< std::pair< Node, Ips > >::iterator j=it->second.begin(), jend = it->second.end() ; - j != jend; ++j){ - // k one of the previous one - for( std::vector< triple< size_t, Node, Ips > >::iterator k=mit->second.begin(), kend = mit->second.end() ; - k != kend; ++k){ - //found a pp-pair - Debug("pattern-element-opt") << "Found multi-pp-pair ( " << j->first - << ", " << k->second << " in "<< k->first - << " )" << std::endl; - Debug("pattern-element-opt") << " Paths = "; - outputIps( "pattern-element-opt", j->second ); - Debug("pattern-element-opt") << " and "; - outputIps( "pattern-element-opt", k->third ); - Debug("pattern-element-opt") << std::endl; - NodePpDispatcher* dispatcher; - hash_map::iterator inpp = npps.find(k->first); - if( inpp != npps.end() ) dispatcher = inpp->second; - else{ - dispatcher = new NodePpDispatcher(); -#ifdef CVC4_DEBUG - dispatcher->pat1 = pats[index2]; - dispatcher->pat2 = pats[k->first]; -#endif - dispatcher->addPpDispatcher(&eh,index2,k->first); - }; - d_pp_pairs[ j->first ][ k->second ].push_back( make_triple( dispatcher, j->second, k->third )); - } - } - } - - /** Put pp_ips_map to multi_pp_ips_map */ - for( PpIpsMap::iterator it = pp_ips_map.begin(); it != pp_ips_map.end(); ++it ){ - for( std::vector< std::pair< Node, Ips > >::iterator j=it->second.begin(), jend = it->second.end() ; - j != jend; ++j){ - multi_pp_ips_map[it->first].push_back(make_triple(index2, j->first, j->second)); - } - } - -} - - -void EfficientEMatcher::registerEfficientHandler( EfficientHandler& handler, - const std::vector< Node > & pats ){ - Assert(pats.size() > 0); - - MultiPpIpsMap multi_pp_ips_map; - PpIpsMap pp_ips_map; - //In a multi-pattern Pattern that is only a variable are specials, - //if the variable appears in another pattern, it can be discarded. - //Otherwise new term of this term can be candidate. So we stock them - //here before adding them. - std::vector< size_t > patVars; - - Debug("pattern-element-opt") << "Register patterns" << pats << std::endl; - for(size_t i = 0; i < pats.size(); ++i){ - if( pats[i].getKind() == kind::INST_CONSTANT){ - patVars.push_back(i); - continue; - } - //to complete - if( pats[i].getKind() == kind::NOT && pats[i][0].getKind() == kind::EQUAL){ - Node cst = NodeManager::currentNM()->mkConst(false); - TNode op = pats[i][0].getOperator(); - if(d_cc_pairs[op][cst] == NULL){ - d_cc_pairs[op][cst] = new NodePcDispatcher(); - } - d_cc_pairs[op][cst]->addPcDispatcher(&handler,i); - continue; - } - //end to complete - Debug("pattern-element-opt") << " Register candidate generator..." << pats[i] << std::endl; - /* Has the pattern already been seen */ - if( d_pat_cand_gens.find( pats[i] )==d_pat_cand_gens.end() ){ - NodePcDispatcher* npc = new NodePcDispatcher(); - NodePpDispatcher* npp = new NodePpDispatcher(); -#ifdef CVC4_DEBUG - npc->pat = pats[i]; - npp->pat1 = pats[i]; - npp->pat2 = pats[i]; -#endif - d_pat_cand_gens[pats[i]] = make_pair(npc,npp); - registerPatternElementPairs( pats[i], pp_ips_map, npc, npp ); - }else{ - Ips ips; - findPpSite(pats[i],ips,pp_ips_map); - } - //Has the top operator already been seen */ - TNode op = pats[i].getOperator(); - d_pat_cand_gens[pats[i]].first->addPcDispatcher(&handler,i); - d_pat_cand_gens[pats[i]].second->addPpDispatcher(&handler,i,i); - d_cand_gens[op].addNewTermDispatcher(&handler,i); - - combineMultiPpIpsMap(pp_ips_map,multi_pp_ips_map,handler,i,pats); - - pp_ips_map.clear(); - } - - for(size_t i = 0; i < patVars.size(); ++i){ - TNode var = pats[patVars[i]]; - Assert( var.getKind() == kind::INST_CONSTANT ); - if( multi_pp_ips_map.find(var) != multi_pp_ips_map.end() ){ - //The variable appear in another pattern, skip it - continue; - }; - d_cand_gen_types[var.getType()].addNewTermDispatcher(&handler,patVars[i]); - } - - //take all terms from the uf term db and add to candidate generator - if( pats[0].getKind() == kind::INST_CONSTANT ){ - TypeNode ty = pats[0].getType(); - rrinst::CandidateGenerator* cg = new GenericCandidateGeneratorClasses(d_quantEngine); - cg->reset(Node::null()); - TNode c; - SetNode ele; - while( !(c = cg->getNextCandidate()).isNull() ){ - if( c.getType() == ty ) ele.insert(c); - } - if( !ele.empty() ){ - // for(std::vector::iterator i = db->d_op_map[op].begin(), end = db->d_op_map[op].end(); i != end; ++i){ - // if(CandidateGenerator::isLegalCandidate(*i)) ele.insert(*i); - // } - if(Debug.isOn("efficient-e-match-stats")){ - Debug("efficient-e-match-stats") << "pattern " << pats << " initialized with " << ele.size() << " terms"<< std::endl; - } - handler.addMonoCandidate(ele, 0); - } - - } else if( pats[0].getKind() == kind::NOT && pats[0][0].getKind() == kind::EQUAL){ - Node cst = NodeManager::currentNM()->mkConst(false); - TNode op = pats[0][0].getOperator(); - cst = getEqualityEngine()->getRepresentative(cst); - SetNode ele; - eq::EqClassIterator eqc_iter( cst, getEqualityEngine() ); - while( !eqc_iter.isFinished() ){ - Debug("efficient-e-match-debug") << "> look at " << (*eqc_iter) - << std::endl; - if( (*eqc_iter).hasOperator() && (*eqc_iter).getOperator() == op ) ele.insert(*eqc_iter); - eqc_iter++; - } - if( !ele.empty() ){ - if(Debug.isOn("efficient-e-match-stats")){ - Debug("efficient-e-match-stats") << "pattern " << pats << " initialized with " << ele.size() << " terms"<< std::endl; - } - handler.addMonoCandidate(ele, 0); - } - - } else { - Node op = pats[0].getOperator(); - TermDb* db = d_quantEngine->getTermDatabase(); - if(db->d_op_map[op].begin() != db->d_op_map[op].end()){ - SetNode ele; - // for(std::vector::iterator i = db->d_op_map[op].begin(), end = db->d_op_map[op].end(); i != end; ++i){ - // if(CandidateGenerator::isLegalCandidate(*i)) ele.insert(*i); - // } - ele.insert(db->d_op_map[op].begin(), db->d_op_map[op].end()); - if(Debug.isOn("efficient-e-match-stats")){ - Debug("efficient-e-match-stats") << "pattern " << pats << " initialized with " << ele.size() << " terms"<< std::endl; - } - handler.addMonoCandidate(ele, 0); - } - } - Debug("efficient-e-match") << "Done." << std::endl; -} - -void EfficientEMatcher::outputEqClass( const char* c, Node n ){ - if( getEqualityEngine()->hasTerm( n ) ){ - eq::EqClassIterator eqc_iter( getEqualityEngine()->getRepresentative( n ), - getEqualityEngine() ); - bool firstTime = true; - while( !eqc_iter.isFinished() ){ - if( !firstTime ){ Debug(c) << ", "; } - Debug(c) << (*eqc_iter); - firstTime = false; - eqc_iter++; - } - }else{ - Debug(c) << n; - } -} - -void EfficientEMatcher::outputIps( const char* c, Ips& ips ){ - for( int i=0; i<(int)ips.size(); i++ ){ - if( i>0 ){ Debug( c ) << "."; } - Debug( c ) << ips[i].first << "." << ips[i].second; - } -} - - -} /* namespace theory */ -} /* namespace cvc4 */ +/********************* */ +/*! \file efficient_e_matching.cpp + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: Morgan Deters + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Implementation of theory uf instantiator class + **/ + +#include "theory/rewriterules/efficient_e_matching.h" +#include "theory/rewriterules/rr_candidate_generator.h" +#include "theory/quantifiers/candidate_generator.h" +#include "theory/quantifiers/options.h" +#include "theory/rewriterules/options.h" +#include "theory/quantifiers/term_database.h" + +#include "theory/theory_engine.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 { + +inline std::ostream& operator<<(std::ostream& out, const EfficientEMatcher::Ips& ips) { + return out; +}; + +EqClassInfo::EqClassInfo( context::Context* c ) : d_funs( c ), d_pfuns( c ), d_disequal( c ){ + +} + +//set member +void EqClassInfo::setMember( Node n, quantifiers::TermDb* db ){ + if( n.hasOperator() ){ + d_funs.insertAtContextLevelZero(n.getOperator(),true); + } + //add parent functions + for( std::hash_map< Node, std::hash_map< int, std::vector< Node > >, NodeHashFunction >::iterator it = db->d_parents[n].begin(); + it != db->d_parents[n].end(); ++it ){ + //TODO Is it true to do it at level 0? That depend when SetMember is called + // At worst it is a good overapproximation + d_pfuns.insertAtContextLevelZero( it->first, true); + } +} + +//get has function +bool EqClassInfo::hasFunction( Node op ){ + return d_funs.find( op )!=d_funs.end(); +} + +bool EqClassInfo::hasParent( Node op ){ + return d_pfuns.find( op )!=d_pfuns.end(); +} + +//merge with another eq class info +void EqClassInfo::merge( EqClassInfo* eci ){ + for( BoolMap::iterator it = eci->d_funs.begin(); it != eci->d_funs.end(); it++ ) { + d_funs[ (*it).first ] = true; + } + for( BoolMap::iterator it = eci->d_pfuns.begin(); it != eci->d_pfuns.end(); it++ ) { + d_pfuns[ (*it).first ] = true; + } +} + +inline void outputEqClassInfo( const char* c, const EqClassInfo* eci){ + Debug(c) << " funs:"; + for( EqClassInfo::BoolMap::iterator it = eci->d_funs.begin(); it != eci->d_funs.end(); it++ ) { + Debug(c) << (*it).first << ","; + } + Debug(c) << std::endl << "pfuns:"; + for( EqClassInfo::BoolMap::iterator it = eci->d_pfuns.begin(); it != eci->d_pfuns.end(); it++ ) { + Debug(c) << (*it).first << ","; + } + Debug(c) << std::endl; +} + + + +EfficientEMatcher::EfficientEMatcher( CVC4::theory::QuantifiersEngine* qe ) : d_quantEngine( qe ) +{ + +} + +eq::EqualityEngine* EfficientEMatcher::getEqualityEngine(){ + //return ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getEqualityEngine(); + return d_quantEngine->getMasterEqualityEngine(); +} + +/** new node */ +void EfficientEMatcher::newEqClass( TNode n ){ + +} + +void EfficientEMatcher::newTerms(SetNode& s){ + static NoMatchAttribute rewrittenNodeAttribute; + /* op -> nodes (if the set is empty, the op is not interesting) */ + std::hash_map< TNode, SetNode, TNodeHashFunction > h; + /* types -> nodes (if the set is empty, the type is not interesting) */ + std::hash_map< TypeNode, SetNode, TypeNodeHashFunction > tyh; + for(SetNode::iterator i=s.begin(), end=s.end(); i != end; ++i){ + if (i->getAttribute(rewrittenNodeAttribute)) continue; /* skip it */ + if( !d_cand_gens.empty() ){ + // op + TNode op = i->getOperator(); + std::hash_map< TNode, SetNode, TNodeHashFunction >::iterator + is = h.find(op); + if(is == h.end()){ + std::pair::iterator,bool> + p = h.insert(make_pair(op,SetNode())); + is = p.first; + if(d_cand_gens.find(op) != d_cand_gens.end()){ + is->second.insert(*i); + } /* else we have inserted an empty set */ + }else if(!is->second.empty()){ + is->second.insert(*i); + } + } + if( !d_cand_gen_types.empty() ){ + //type + TypeNode ty = i->getType(); + std::hash_map< TypeNode, SetNode, TypeNodeHashFunction >::iterator + is = tyh.find(ty); + if(is == tyh.end()){ + std::pair::iterator,bool> + p = tyh.insert(make_pair(ty,SetNode())); + is = p.first; + if(d_cand_gen_types.find(ty) != d_cand_gen_types.end()){ + is->second.insert(*i); + } /* else we have inserted an empty set */ + }else if(!is->second.empty()){ + is->second.insert(*i); + } + } + } + //op + for(std::hash_map< TNode, SetNode, TNodeHashFunction >::iterator i=h.begin(), end=h.end(); + i != end; ++i){ + //new term, add n to candidate generators + if(i->second.empty()) continue; + std::map< Node, NodeNewTermDispatcher >::iterator + inpc = d_cand_gens.find(i->first); + //we know that this op exists + Assert(inpc != d_cand_gens.end()); + inpc->second.send(i->second); + } + //type + for(std::hash_map< TypeNode, SetNode, TypeNodeHashFunction >::iterator i=tyh.begin(), end=tyh.end(); + i != end; ++i){ + //new term, add n to candidate generators + if(i->second.empty()) continue; + std::map< TypeNode, NodeNewTermDispatcher >::iterator + inpc = d_cand_gen_types.find(i->first); + //we know that this op exists + Assert(inpc != d_cand_gen_types.end()); + inpc->second.send(i->second); + } + +} + + +/** merge */ +void EfficientEMatcher::merge( TNode a, TNode b ){ + if( options::efficientEMatching() ){ + //merge eqc_ops of b into a + EqClassInfo* eci_a = getOrCreateEquivalenceClassInfo( a ); + EqClassInfo* eci_b = getOrCreateEquivalenceClassInfo( b ); + + if( a.getKind()!=IFF && a.getKind()!=EQUAL && b.getKind()!=IFF && b.getKind()!=EQUAL ){ + Debug("efficient-e-match") << "Merging " << a << " with " << b << std::endl; + + //determine new candidates for instantiation + computeCandidatesPcPairs( a, eci_a, b, eci_b ); + computeCandidatesPcPairs( b, eci_b, a, eci_a ); + computeCandidatesPpPairs( a, eci_a, b, eci_b ); + computeCandidatesPpPairs( b, eci_b, a, eci_a ); + } + computeCandidatesConstants( a, eci_a, b, eci_b); + computeCandidatesConstants( b, eci_b, a, eci_a); + + eci_a->merge( eci_b ); + } +} + +/** assert terms are disequal */ +void EfficientEMatcher::assertDisequal( TNode a, TNode b, TNode reason ){ + +} + +EqClassInfo* EfficientEMatcher::getEquivalenceClassInfo( Node n ) { + return d_eqc_ops.find( n )==d_eqc_ops.end() ? NULL : d_eqc_ops[n]; +} +EqClassInfo* EfficientEMatcher::getOrCreateEquivalenceClassInfo( Node n ){ + Assert( n==getEqualityEngine()->getRepresentative( n ) ); + if( d_eqc_ops.find( n )==d_eqc_ops.end() ){ + EqClassInfo* eci = new EqClassInfo( d_quantEngine->getSatContext() ); + eci->setMember( n, d_quantEngine->getTermDatabase() ); + d_eqc_ops[n] = eci; + } + return d_eqc_ops[n]; +} + +void EfficientEMatcher::computeCandidatesPcPairs( Node a, EqClassInfo* eci_a, Node b, EqClassInfo* eci_b ){ + Debug("efficient-e-match") << "Compute candidates for pc pairs..." << std::endl; + Debug("efficient-e-match") << " Eq class = ["; + outputEqClass( "efficient-e-match", a); + Debug("efficient-e-match") << "]" << std::endl; + outputEqClassInfo("efficient-e-match",eci_a); + for( EqClassInfo::BoolMap::iterator it = eci_a->d_funs.begin(); it != eci_a->d_funs.end(); it++ ) { + //the child function: a member of eq_class( a ) has top symbol g, in other words g is in funs( a ) + Node g = (*it).first; + Debug("efficient-e-match") << " Checking application " << g << std::endl; + //look at all parent/child pairs + for( std::map< Node, std::vector< std::pair< NodePcDispatcher*, Ips > > >::iterator itf = d_pc_pairs[g].begin(); + itf != d_pc_pairs[g].end(); ++itf ){ + //f/g is a parent/child pair + Node f = itf->first; + if( eci_b->hasParent( f ) ){ + //DO_THIS: determine if f in pfuns( b ), only do the follow if so + Debug("efficient-e-match") << " Checking parent application " << f << std::endl; + //scan through the list of inverted path strings/candidate generators + for( std::vector< std::pair< NodePcDispatcher*, Ips > >::iterator cit = itf->second.begin(); + cit != itf->second.end(); ++cit ){ +#ifdef CVC4_DEBUG + Debug("efficient-e-match") << " Checking pattern " << cit->first->pat << std::endl; +#endif + Debug("efficient-e-match") << " Check inverted path string for pattern "; + outputIps( "efficient-e-match", cit->second ); + Debug("efficient-e-match") << std::endl; + + //collect all new relevant terms + SetNode terms; + terms.insert( b ); + collectTermsIps( cit->second, terms ); + if( terms.empty() ) continue; + Debug("efficient-e-match") << " -> Added terms (" << terms.size() << "): "; + for( SetNode::const_iterator t=terms.begin(), end=terms.end(); + t!=end; ++t ){ + Debug("efficient-e-match") << (*t) << " "; + } + Debug("efficient-e-match") << std::endl; + //add them as candidates to the candidate generator + cit->first->send(terms); + } + } + } + } +} + +void EfficientEMatcher::computeCandidatesPpPairs( Node a, EqClassInfo* eci_a, Node b, EqClassInfo* eci_b ){ + Debug("efficient-e-match") << "Compute candidates for pp pairs..." << std::endl; + for( std::map< Node, std::map< Node, std::vector< triple< NodePpDispatcher*, Ips, Ips > > > >::iterator it = d_pp_pairs.begin(); + it != d_pp_pairs.end(); ++it ){ + Node f = it->first; + if( eci_a->hasParent( f ) ){ + Debug("efficient-e-match") << " Checking parent application " << f << std::endl; + for( std::map< Node, std::vector< triple > >::iterator it2 = it->second.begin(); + it2 != it->second.end(); ++it2 ){ + Node g = it2->first; + if( eci_b->hasParent( g ) ){ + Debug("efficient-e-match") << " Checking parent application " << g << std::endl; + //if f in pfuns( a ) and g is in pfuns( b ), only do the follow if so + for( std::vector< triple > ::iterator cit = it2->second.begin(); + cit != it2->second.end(); ++cit ){ +#ifdef CVC4_DEBUG + Debug("efficient-e-match") << " Checking pattern " << cit->first->pat1 << " and " << cit->first->pat2 << std::endl; +#endif + Debug("efficient-e-match") << " Check inverted path string "; + outputIps( "efficient-e-match", cit->second ); + SetNode a_terms; + a_terms.insert( a ); + collectTermsIps( cit->second, a_terms ); + if( a_terms.empty() ) continue; + Debug("efficient-e-match") << " And check inverted path string "; + outputIps( "efficient-e-match", cit->third ); + SetNode b_terms; + b_terms.insert( b ); + collectTermsIps( cit->third, b_terms ); + if( b_terms.empty() ) continue; + //Start debug + Debug("efficient-e-match") << " -> Possibly Added termsA (" << a_terms.size() << "): "; + for( SetNode::const_iterator t=a_terms.begin(), end=a_terms.end(); + t!=end; ++t ){ + Debug("efficient-e-match") << (*t) << " "; + } + Debug("efficient-e-match") << std::endl; + Debug("efficient-e-match") << " -> Possibly Added termsB (" << b_terms.size() << "): "; + for( SetNode::const_iterator t=b_terms.begin(), end=b_terms.end(); + t!=end; ++t ){ + Debug("efficient-e-match") << (*t) << " "; + } + Debug("efficient-e-match") << std::endl; + //End debug + + cit->first->send(a_terms,b_terms); + } + } + } + } + } +} + + +void EfficientEMatcher::computeCandidatesConstants( Node a, EqClassInfo* eci_a, Node b, EqClassInfo* eci_b ){ + Debug("efficient-e-match") << "Compute candidates constants for cc pairs..." << std::endl; + Debug("efficient-e-match") << " Eq class = ["; + outputEqClass( "efficient-e-match", a); + Debug("efficient-e-match") << "]" << std::endl; + outputEqClassInfo("efficient-e-match",eci_a); + for( std::map< Node, std::map< Node, NodePcDispatcher* > >::iterator + it = d_cc_pairs.begin(), end = d_cc_pairs.end(); + it != end; ++it ) { + Debug("efficient-e-match") << " Checking application " << it->first << std::endl; + if( !eci_b->hasFunction(it->first) ) continue; + for( std::map< Node, NodePcDispatcher* >::iterator + itc = it->second.begin(), end = it->second.end(); + itc != end; ++itc ) { + //The constant + Debug("efficient-e-match") << " Checking constant " << a << std::endl; + if(getEqualityEngine()->getRepresentative(itc->first) != a) continue; + SetNode s; + eq::EqClassIterator eqc_iter( b, getEqualityEngine() ); + while( !eqc_iter.isFinished() ){ + Debug("efficient-e-match-debug") << "> look at " << (*eqc_iter) + << std::endl; + if( (*eqc_iter).hasOperator() && (*eqc_iter).getOperator() == it->first ) s.insert(*eqc_iter); + eqc_iter++; + } + + if( s.empty() ) continue; + Debug("efficient-e-match") << " -> Added terms (" << s.size() << "): "; + for( SetNode::const_iterator t=s.begin(), end=s.end(); + t!=end; ++t ){ + Debug("efficient-e-match") << (*t) << " "; + } + Debug("efficient-e-match") << std::endl; + itc->second->send(s); + } + } +} + +void EfficientEMatcher::collectTermsIps( Ips& ips, SetNode & terms ){ + Assert( ips.size() > 0); + return collectTermsIps( ips, terms, ips.size() - 1); +} + +void EfficientEMatcher::collectTermsIps( Ips& ips, SetNode& terms, int index ){ + if( !terms.empty() ){ + Debug("efficient-e-match-debug") << "> Process " << index << std::endl; + Node f = ips[index].first; + int arg = ips[index].second; + + //for each term in terms, determine if any term (modulo equality) has parent "f" from position "arg" + bool addRep = ( index!=0 ); // We want to keep the top symbol for the last + SetNode newTerms; + for( SetNode::const_iterator t=terms.begin(), end=terms.end(); + t!=end; ++t ){ + collectParentsTermsIps( *t, f, arg, newTerms, addRep ); + } + terms.swap(newTerms); + + Debug("efficient-e-match-debug") << "> Terms are now: "; + for( SetNode::const_iterator t=terms.begin(), end=terms.end(); + t!=end; ++t ){ + Debug("efficient-e-match-debug") << *t << " "; + } + Debug("efficient-e-match-debug") << std::endl; + + if(index!=0) collectTermsIps( ips, terms, index-1 ); + } +} + +bool EfficientEMatcher::collectParentsTermsIps( Node n, Node f, int arg, SetNode & terms, bool addRep, bool modEq ){ //modEq default true + bool addedTerm = false; + + if( modEq && getEqualityEngine()->hasTerm( n )){ + Assert( getEqualityEngine()->getRepresentative( n )==n ); + //collect modulo equality + //DO_THIS: this should (if necessary) compute a current set of (f, arg) parents for n and cache it + eq::EqClassIterator eqc_iter( n, getEqualityEngine() ); + while( !eqc_iter.isFinished() ){ + Debug("efficient-e-match-debug") << "> look at " << (*eqc_iter) + << std::endl; + if( collectParentsTermsIps( (*eqc_iter), f, arg, terms, addRep, false ) ){ + //if only one argument, we know we can stop (since all others added will be congruent) + if( f.getType().getNumChildren()==2 ){ + return true; + } + addedTerm = true; + } + eqc_iter++; + } + }else{ + quantifiers::TermDb* db = d_quantEngine->getTermDatabase(); + //see if parent f exists from argument arg + const std::vector & parents = db->getParents(n,f,arg); + for( size_t i=0; igetRepresentative( t ); + terms.insert(t); + addedTerm = true; + } + } + return addedTerm; +} + +void EfficientEMatcher::registerPatternElementPairs2( Node pat, Ips& ips, PpIpsMap & pp_ips_map, NodePcDispatcher* npc ){ + Assert( pat.hasOperator() ); + //add information for possible pp-pair + ips.push_back( std::pair< Node, int >( pat.getOperator(), 0 ) ); //0 is just a dumb value + + for( int i=0; i<(int)pat.getNumChildren(); i++ ){ + if( pat[i].getKind()==INST_CONSTANT ){ + ips.back().second = i; + pp_ips_map[ pat[i] ].push_back( make_pair( pat.getOperator(), Ips( ips ) ) ); + } + } + + for( int i=0; i<(int)pat.getNumChildren(); i++ ){ + if( pat[i].getKind()==APPLY_UF ){ + ips.back().second = i; + registerPatternElementPairs2( pat[i], ips, pp_ips_map, npc ); + Debug("pattern-element-opt") << "Found pc-pair ( " << pat.getOperator() << ", " << pat[i].getOperator() << " )" << std::endl; + Debug("pattern-element-opt") << " Path = "; + outputIps( "pattern-element-opt", ips ); + Debug("pattern-element-opt") << std::endl; + //pat.getOperator() and pat[i].getOperator() are a pc-pair + d_pc_pairs[ pat[i].getOperator() ][ pat.getOperator() ] + .push_back( make_pair(npc,Ips(ips)) ); + } + } + ips.pop_back(); +} + +void EfficientEMatcher::registerPatternElementPairs( Node pat, PpIpsMap & pp_ips_map, + NodePcDispatcher* npc, + NodePpDispatcher* npp){ + Ips ips; + registerPatternElementPairs2( pat, ips, pp_ips_map, npc ); + for( PpIpsMap::iterator it = pp_ips_map.begin(); it != pp_ips_map.end(); ++it ){ + // for each variable construct all the pp-pair + for( size_t j=0; jsecond.size(); j++ ){ + for( size_t k=j+1; ksecond.size(); k++ ){ + //found a pp-pair + Debug("pattern-element-opt") << "Found pp-pair ( " << it->second[j].first << ", " << it->second[k].first << " )" << std::endl; + Debug("pattern-element-opt") << " Paths = "; + outputIps( "pattern-element-opt", it->second[j].second ); + Debug("pattern-element-opt") << " and "; + outputIps( "pattern-element-opt", it->second[k].second ); + Debug("pattern-element-opt") << std::endl; + d_pp_pairs[ it->second[j].first ][ it->second[k].first ] + .push_back( make_triple( npp, it->second[j].second, it->second[k].second )); + } + } + } +}; + +void findPpSite(Node pat, EfficientEMatcher::Ips& ips, EfficientEMatcher::PpIpsMap & pp_ips_map){ + Assert( pat.getKind()==APPLY_UF ); + //add information for possible pp-pair + + ips.push_back( make_pair( pat.getOperator(), 0) ); + for( size_t i=0; i & pats){ + hash_map npps; + for( PpIpsMap::iterator it = pp_ips_map.begin(); it != pp_ips_map.end(); ++it ){ + MultiPpIpsMap::iterator mit = multi_pp_ips_map.find(it->first); + if(mit == multi_pp_ips_map.end()) continue; + // for each variable construct all the pp-pair + // j the last pattern treated + for( std::vector< std::pair< Node, Ips > >::iterator j=it->second.begin(), jend = it->second.end() ; + j != jend; ++j){ + // k one of the previous one + for( std::vector< triple< size_t, Node, Ips > >::iterator k=mit->second.begin(), kend = mit->second.end() ; + k != kend; ++k){ + //found a pp-pair + Debug("pattern-element-opt") << "Found multi-pp-pair ( " << j->first + << ", " << k->second << " in "<< k->first + << " )" << std::endl; + Debug("pattern-element-opt") << " Paths = "; + outputIps( "pattern-element-opt", j->second ); + Debug("pattern-element-opt") << " and "; + outputIps( "pattern-element-opt", k->third ); + Debug("pattern-element-opt") << std::endl; + NodePpDispatcher* dispatcher; + hash_map::iterator inpp = npps.find(k->first); + if( inpp != npps.end() ) dispatcher = inpp->second; + else{ + dispatcher = new NodePpDispatcher(); +#ifdef CVC4_DEBUG + dispatcher->pat1 = pats[index2]; + dispatcher->pat2 = pats[k->first]; +#endif + dispatcher->addPpDispatcher(&eh,index2,k->first); + }; + d_pp_pairs[ j->first ][ k->second ].push_back( make_triple( dispatcher, j->second, k->third )); + } + } + } + + /** Put pp_ips_map to multi_pp_ips_map */ + for( PpIpsMap::iterator it = pp_ips_map.begin(); it != pp_ips_map.end(); ++it ){ + for( std::vector< std::pair< Node, Ips > >::iterator j=it->second.begin(), jend = it->second.end() ; + j != jend; ++j){ + multi_pp_ips_map[it->first].push_back(make_triple(index2, j->first, j->second)); + } + } + +} + + +void EfficientEMatcher::registerEfficientHandler( EfficientHandler& handler, + const std::vector< Node > & pats ){ + Assert(pats.size() > 0); + + MultiPpIpsMap multi_pp_ips_map; + PpIpsMap pp_ips_map; + //In a multi-pattern Pattern that is only a variable are specials, + //if the variable appears in another pattern, it can be discarded. + //Otherwise new term of this term can be candidate. So we stock them + //here before adding them. + std::vector< size_t > patVars; + + Debug("pattern-element-opt") << "Register patterns" << pats << std::endl; + for(size_t i = 0; i < pats.size(); ++i){ + if( pats[i].getKind() == kind::INST_CONSTANT){ + patVars.push_back(i); + continue; + } + //to complete + if( pats[i].getKind() == kind::NOT && pats[i][0].getKind() == kind::EQUAL){ + Node cst = NodeManager::currentNM()->mkConst(false); + TNode op = pats[i][0].getOperator(); + if(d_cc_pairs[op][cst] == NULL){ + d_cc_pairs[op][cst] = new NodePcDispatcher(); + } + d_cc_pairs[op][cst]->addPcDispatcher(&handler,i); + continue; + } + //end to complete + Debug("pattern-element-opt") << " Register candidate generator..." << pats[i] << std::endl; + /* Has the pattern already been seen */ + if( d_pat_cand_gens.find( pats[i] )==d_pat_cand_gens.end() ){ + NodePcDispatcher* npc = new NodePcDispatcher(); + NodePpDispatcher* npp = new NodePpDispatcher(); +#ifdef CVC4_DEBUG + npc->pat = pats[i]; + npp->pat1 = pats[i]; + npp->pat2 = pats[i]; +#endif + d_pat_cand_gens[pats[i]] = make_pair(npc,npp); + registerPatternElementPairs( pats[i], pp_ips_map, npc, npp ); + }else{ + Ips ips; + findPpSite(pats[i],ips,pp_ips_map); + } + //Has the top operator already been seen */ + TNode op = pats[i].getOperator(); + d_pat_cand_gens[pats[i]].first->addPcDispatcher(&handler,i); + d_pat_cand_gens[pats[i]].second->addPpDispatcher(&handler,i,i); + d_cand_gens[op].addNewTermDispatcher(&handler,i); + + combineMultiPpIpsMap(pp_ips_map,multi_pp_ips_map,handler,i,pats); + + pp_ips_map.clear(); + } + + for(size_t i = 0; i < patVars.size(); ++i){ + TNode var = pats[patVars[i]]; + Assert( var.getKind() == kind::INST_CONSTANT ); + if( multi_pp_ips_map.find(var) != multi_pp_ips_map.end() ){ + //The variable appear in another pattern, skip it + continue; + }; + d_cand_gen_types[var.getType()].addNewTermDispatcher(&handler,patVars[i]); + } + + //take all terms from the uf term db and add to candidate generator + if( pats[0].getKind() == kind::INST_CONSTANT ){ + TypeNode ty = pats[0].getType(); + rrinst::CandidateGenerator* cg = new GenericCandidateGeneratorClasses(d_quantEngine); + cg->reset(Node::null()); + TNode c; + SetNode ele; + while( !(c = cg->getNextCandidate()).isNull() ){ + if( c.getType() == ty ) ele.insert(c); + } + if( !ele.empty() ){ + // for(std::vector::iterator i = db->d_op_map[op].begin(), end = db->d_op_map[op].end(); i != end; ++i){ + // if(CandidateGenerator::isLegalCandidate(*i)) ele.insert(*i); + // } + if(Debug.isOn("efficient-e-match-stats")){ + Debug("efficient-e-match-stats") << "pattern " << pats << " initialized with " << ele.size() << " terms"<< std::endl; + } + handler.addMonoCandidate(ele, 0); + } + + } else if( pats[0].getKind() == kind::NOT && pats[0][0].getKind() == kind::EQUAL){ + Node cst = NodeManager::currentNM()->mkConst(false); + TNode op = pats[0][0].getOperator(); + cst = getEqualityEngine()->getRepresentative(cst); + SetNode ele; + eq::EqClassIterator eqc_iter( cst, getEqualityEngine() ); + while( !eqc_iter.isFinished() ){ + Debug("efficient-e-match-debug") << "> look at " << (*eqc_iter) + << std::endl; + if( (*eqc_iter).hasOperator() && (*eqc_iter).getOperator() == op ) ele.insert(*eqc_iter); + eqc_iter++; + } + if( !ele.empty() ){ + if(Debug.isOn("efficient-e-match-stats")){ + Debug("efficient-e-match-stats") << "pattern " << pats << " initialized with " << ele.size() << " terms"<< std::endl; + } + handler.addMonoCandidate(ele, 0); + } + + } else { + Node op = pats[0].getOperator(); + TermDb* db = d_quantEngine->getTermDatabase(); + if(db->d_op_map[op].begin() != db->d_op_map[op].end()){ + SetNode ele; + // for(std::vector::iterator i = db->d_op_map[op].begin(), end = db->d_op_map[op].end(); i != end; ++i){ + // if(CandidateGenerator::isLegalCandidate(*i)) ele.insert(*i); + // } + ele.insert(db->d_op_map[op].begin(), db->d_op_map[op].end()); + if(Debug.isOn("efficient-e-match-stats")){ + Debug("efficient-e-match-stats") << "pattern " << pats << " initialized with " << ele.size() << " terms"<< std::endl; + } + handler.addMonoCandidate(ele, 0); + } + } + Debug("efficient-e-match") << "Done." << std::endl; +} + +void EfficientEMatcher::outputEqClass( const char* c, Node n ){ + if( getEqualityEngine()->hasTerm( n ) ){ + eq::EqClassIterator eqc_iter( getEqualityEngine()->getRepresentative( n ), + getEqualityEngine() ); + bool firstTime = true; + while( !eqc_iter.isFinished() ){ + if( !firstTime ){ Debug(c) << ", "; } + Debug(c) << (*eqc_iter); + firstTime = false; + eqc_iter++; + } + }else{ + Debug(c) << n; + } +} + +void EfficientEMatcher::outputIps( const char* c, Ips& ips ){ + for( int i=0; i<(int)ips.size(); i++ ){ + if( i>0 ){ Debug( c ) << "."; } + Debug( c ) << ips[i].first << "." << ips[i].second; + } +} + + +} /* namespace theory */ +} /* namespace cvc4 */ diff --git a/src/theory/rewriterules/efficient_e_matching.h b/src/theory/rewriterules/efficient_e_matching.h old mode 100755 new mode 100644 index 2f0a07184..11c6b783e --- a/src/theory/rewriterules/efficient_e_matching.h +++ b/src/theory/rewriterules/efficient_e_matching.h @@ -1,450 +1,450 @@ -/********************* */ -/*! \file efficient_e_matching.h - ** \verbatim - ** Original author: ajreynol - ** Major contributors: bobot - ** Minor contributors (to current version): mdeters - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief efficient e-matching - **/ - -#include "cvc4_private.h" - -#ifndef __CVC4__EFFICIENT_E_MATCHING_H -#define __CVC4__EFFICIENT_E_MATCHING_H - -#include "expr/node.h" -#include "context/context.h" -#include "context/context_mm.h" -#include "context/cdchunk_list.h" - -#include "util/statistics_registry.h" -#include "util/ntuple.h" -#include "context/cdqueue.h" -#include "context/cdo.h" - -#include "theory/uf/equality_engine.h" - -namespace CVC4 { -namespace theory { - -class QuantifiersEngine; - -namespace quantifiers{ - class TermDb; -} - -class EfficientEMatcher; -class HandlerPcDispatcher; -class HandlerPpDispatcher; - -typedef std::set SetNode; - -template -class CleanUpPointer{ -public: - inline void operator()(T** e){ - delete(*e); - }; -}; - -class EfficientHandler{ -public: - typedef std::pair< Node, size_t > MonoCandidate; - typedef std::pair< MonoCandidate, MonoCandidate > MultiCandidate; - typedef std::pair< SetNode, size_t > MonoCandidates; - typedef std::pair< MonoCandidates, MonoCandidates > MultiCandidates; -private: - /* Queue of candidates */ - typedef context::CDQueue< MonoCandidates *, CleanUpPointer > MonoCandidatesQueue; - typedef context::CDQueue< MultiCandidates *, CleanUpPointer > MultiCandidatesQueue; - MonoCandidatesQueue d_monoCandidates; - typedef SetNode::iterator SetNodeIter; - context::CDO d_si; - context::CDO d_mono_not_first; - - MonoCandidatesQueue d_monoCandidatesNewTerm; - context::CDO d_si_new_term; - context::CDO d_mono_not_first_new_term; - - - MultiCandidatesQueue d_multiCandidates; - context::CDO d_si1; - context::CDO d_si2; - context::CDO d_multi_not_first; - - - friend class EfficientEMatcher; - friend class HandlerPcDispatcher; - friend class HandlerPpDispatcher; - friend class HandlerNewTermDispatcher; -protected: - void addMonoCandidate(SetNode & s, size_t index){ - Assert(!s.empty()); - d_monoCandidates.push(new MonoCandidates(s,index)); - } - void addMonoCandidateNewTerm(SetNode & s, size_t index){ - Assert(!s.empty()); - d_monoCandidatesNewTerm.push(new MonoCandidates(s,index)); - } - void addMultiCandidate(SetNode & s1, size_t index1, SetNode & s2, size_t index2){ - Assert(!s1.empty() && !s2.empty()); - d_multiCandidates.push(new MultiCandidates(MonoCandidates(s1,index1), - MonoCandidates(s2,index2))); - } -public: - EfficientHandler(context::Context * c): - //false for d_mono_not_first beacause its the default constructor - d_monoCandidates(c), d_si(c), d_mono_not_first(c,false), - d_monoCandidatesNewTerm(c), d_si_new_term(c), - d_mono_not_first_new_term(c,false), - d_multiCandidates(c) , d_si1(c), d_si2(c), d_multi_not_first(c,false) {}; - - bool getNextMonoCandidate(MonoCandidate & candidate){ - if(d_monoCandidates.empty()) return false; - const MonoCandidates * front = d_monoCandidates.front(); - SetNodeIter si_tmp; - if(!d_mono_not_first){ - Assert(front->first.begin() != front->first.end()); - d_mono_not_first = true; - si_tmp=front->first.begin(); - }else{ - si_tmp = d_si; - ++si_tmp; - }; - if(si_tmp != front->first.end()){ - candidate.first = (*si_tmp); - candidate.second = front->second; - d_si = si_tmp; - Debug("efficienthandler") << "Mono produces " << candidate.first << " for " << candidate.second << std::endl; - return true; - }; - d_monoCandidates.pop(); - d_mono_not_first = false; - return getNextMonoCandidate(candidate); - }; - - bool getNextMonoCandidateNewTerm(MonoCandidate & candidate){ - if(d_monoCandidatesNewTerm.empty()) return false; - const MonoCandidates * front = d_monoCandidatesNewTerm.front(); - SetNodeIter si_tmp; - if(!d_mono_not_first_new_term){ - Assert(front->first.begin() != front->first.end()); - d_mono_not_first_new_term = true; - si_tmp=front->first.begin(); - }else{ - si_tmp = d_si_new_term; - ++si_tmp; - }; - if(si_tmp != front->first.end()){ - candidate.first = (*si_tmp); - candidate.second = front->second; - d_si_new_term = si_tmp; - Debug("efficienthandler") << "Mono produces " << candidate.first << " for " << candidate.second << std::endl; - return true; - }; - d_monoCandidatesNewTerm.pop(); - d_mono_not_first_new_term = false; - return getNextMonoCandidateNewTerm(candidate); - }; - - bool getNextMultiCandidate(MultiCandidate & candidate){ - if(d_multiCandidates.empty()) return false; - const MultiCandidates* front = d_multiCandidates.front(); - SetNodeIter si1_tmp; - SetNodeIter si2_tmp; - if(!d_multi_not_first){ - Assert(front->first.first.begin() != front->first.first.end()); - Assert(front->second.first.begin() != front->second.first.end()); - si1_tmp = front->first.first.begin(); - si2_tmp = front->second.first.begin(); - }else{ - si1_tmp = d_si1; - si2_tmp = d_si2; - ++si2_tmp; - }; - if(si2_tmp != front->second.first.end()){ - candidate.first.first = *si1_tmp; - candidate.first.second = front->first.second; - candidate.second.first = *si2_tmp; - candidate.second.second = front->second.second; - if(!d_multi_not_first){d_si1 = si1_tmp; d_multi_not_first = true; }; - d_si2 = si2_tmp; - Debug("efficienthandler") << "Multi1 produces " - << candidate.first.first << " for " - << candidate.first.second << " and " - << candidate.second.first << " for " - << candidate.second.second << " and " - << std::endl; - return true; - }; // end of the second set - si2_tmp = front->second.first.begin(); - ++si1_tmp; - if(si1_tmp != front->first.first.end()){ - candidate.first.first = *si1_tmp; - candidate.first.second = front->first.second; - candidate.second.first = *si2_tmp; - candidate.second.second = front->second.second; - d_si1 = si1_tmp; - d_si2 = si2_tmp; - Debug("efficienthandler") << "Multi2 produces " - << candidate.first.first << " for " - << candidate.first.second << " and " - << candidate.second.first << " for " - << candidate.second.second << " and " - << std::endl; - return true; - }; // end of the first set - d_multiCandidates.pop(); - d_multi_not_first = false; - return getNextMultiCandidate(candidate); - } -}; - -class PcDispatcher{ -public: - virtual ~PcDispatcher(){}; - /* Send the node to the dispatcher */ - virtual void send(SetNode & s) = 0; -}; - - -class HandlerPcDispatcher: public PcDispatcher{ - EfficientHandler* d_handler; - size_t d_index; -public: - HandlerPcDispatcher(EfficientHandler* handler, size_t index): - d_handler(handler), d_index(index) {}; - void send(SetNode & s){ - d_handler->addMonoCandidate(s,d_index); - } -}; - - -/** All the dispatcher that correspond to this node */ -class NodePcDispatcher: public PcDispatcher{ -#ifdef CVC4_DEBUG -public: - Node pat; -#endif/* CVC4_DEBUG*/ -private: - std::vector d_dis; -public: - void send(SetNode & s){ - Assert(!s.empty()); - for(std::vector::iterator i = d_dis.begin(), end = d_dis.end(); - i != end; ++i){ - (*i).send(s); - } - } - void addPcDispatcher(EfficientHandler* handler, size_t index){ - d_dis.push_back(HandlerPcDispatcher(handler,index)); - } -}; - - -class HandlerNewTermDispatcher: public PcDispatcher{ - EfficientHandler* d_handler; - size_t d_index; -public: - HandlerNewTermDispatcher(EfficientHandler* handler, size_t index): - d_handler(handler), d_index(index) {}; - void send(SetNode & s){ - d_handler->addMonoCandidateNewTerm(s,d_index); - } -}; - -/** All the dispatcher that correspond to this node */ -class NodeNewTermDispatcher: public PcDispatcher{ -#ifdef CVC4_DEBUG -public: - Node pat; -#endif/* CVC4_DEBUG*/ -private: - std::vector d_dis; -public: - void send(SetNode & s){ - Assert(!s.empty()); - for(std::vector::iterator i = d_dis.begin(), end = d_dis.end(); - i != end; ++i){ - (*i).send(s); - } - } - void addNewTermDispatcher(EfficientHandler* handler, size_t index){ - d_dis.push_back(HandlerNewTermDispatcher(handler,index)); - } -}; - -class PpDispatcher{ -public: - virtual ~PpDispatcher(){}; - /* Send the node to the dispatcher */ - virtual void send(SetNode & s1, SetNode & s2, SetNode & sinter) = 0; -}; - - -class HandlerPpDispatcher: public PpDispatcher{ - EfficientHandler* d_handler; - size_t d_index1; - size_t d_index2; -public: - HandlerPpDispatcher(EfficientHandler* handler, size_t index1, size_t index2): - d_handler(handler), d_index1(index1), d_index2(index2) {}; - void send(SetNode & s1, SetNode & s2, SetNode & sinter){ - if(d_index1 == d_index2){ - if(!sinter.empty()) - d_handler->addMonoCandidate(sinter,d_index1); - }else{ - d_handler->addMultiCandidate(s1,d_index1,s2,d_index2); - } - } -}; - - -/** All the dispatcher that correspond to this node */ -class NodePpDispatcher: public PpDispatcher{ -#ifdef CVC4_DEBUG -public: - Node pat1; - Node pat2; -#endif/* CVC4_DEBUG */ -private: - std::vector d_dis; - void send(SetNode & s1, SetNode & s2, SetNode & inter){ - for(std::vector::iterator i = d_dis.begin(), end = d_dis.end(); - i != end; ++i){ - (*i).send(s1,s2,inter); - } - } -public: - void send(SetNode & s1, SetNode & s2){ - // can be done in HandlerPpDispatcher lazily - Assert(!s1.empty() && !s2.empty()); - SetNode inter; - std::set_intersection( s1.begin(), s1.end(), s2.begin(), s2.end(), - std::inserter( inter, inter.begin() ) ); - send(s1,s2,inter); - } - void addPpDispatcher(EfficientHandler* handler, size_t index1, size_t index2){ - d_dis.push_back(HandlerPpDispatcher(handler,index1,index2)); - } -}; - -//equivalence class info -class EqClassInfo -{ -public: - typedef context::CDHashMap BoolMap; - typedef context::CDChunkList NodeList; -public: - //a list of operators that occur as top symbols in this equivalence class - // Efficient E-Matching for SMT Solvers: "funs" - BoolMap d_funs; - //a list of operators f for which a term of the form f( ... t ... ) exists - // Efficient E-Matching for SMT Solvers: "pfuns" - BoolMap d_pfuns; - //a list of equivalence classes that are disequal - BoolMap d_disequal; -public: - EqClassInfo( context::Context* c ); - ~EqClassInfo(){} - //set member - void setMember( Node n, quantifiers::TermDb* db ); - //has function "funs" - bool hasFunction( Node op ); - //has parent "pfuns" - bool hasParent( Node op ); - //merge with another eq class info - void merge( EqClassInfo* eci ); -}; - -class EfficientEMatcher{ -protected: - /** reference to the quantifiers engine */ - QuantifiersEngine* d_quantEngine; -public: - EfficientEMatcher(CVC4::theory::QuantifiersEngine* qe); - ~EfficientEMatcher() { - for(std::map< Node, std::pair >::iterator - i = d_pat_cand_gens.begin(), end = d_pat_cand_gens.end(); - i != end; i++){ - delete(i->second.first); - delete(i->second.second); - } - } - /** get equality engine we are using */ - eq::EqualityEngine* getEqualityEngine(); -private: - //information for each equivalence class - std::map< Node, EqClassInfo* > d_eqc_ops; -public: - /** new node */ - void newEqClass( TNode n ); - /** merge */ - void merge( TNode a, TNode b ); - /** assert terms are disequal */ - void assertDisequal( TNode a, TNode b, TNode reason ); - /** get equivalence class info */ - EqClassInfo* getEquivalenceClassInfo( Node n ); - EqClassInfo* getOrCreateEquivalenceClassInfo( Node n ); - typedef std::vector< std::pair< Node, int > > Ips; - typedef std::map< Node, std::vector< std::pair< Node, Ips > > > PpIpsMap; - typedef std::map< Node, std::vector< triple< size_t, Node, Ips > > > MultiPpIpsMap; -private: - /** Parent/Child Pairs (for efficient E-matching) - So, for example, if we have the pattern f( g( x ) ), then d_pc_pairs[g][f][f( g( x ) )] = { f.0 }. - */ - std::map< Node, std::map< Node, std::vector< std::pair< NodePcDispatcher*, Ips > > > > d_pc_pairs; - /** Parent/Parent Pairs (for efficient E-matching) */ - std::map< Node, std::map< Node, std::vector< triple< NodePpDispatcher*, Ips, Ips > > > > d_pp_pairs; - /** Constants/Child Pairs - So, for example, if we have the pattern f( x ) = c, then d_pc_pairs[f][c] = ..., pcdispatcher, ... - */ - //TODO constant in pattern can use the same thing just add an Ips - std::map< Node, std::map< Node, NodePcDispatcher* > > d_cc_pairs; - /** list of all candidate generators for each operator */ - std::map< Node, NodeNewTermDispatcher > d_cand_gens; - /** list of all candidate generators for each type */ - std::map< TypeNode, NodeNewTermDispatcher > d_cand_gen_types; - /** map from patterns to candidate generators */ - std::map< Node, std::pair > d_pat_cand_gens; - /** helper functions */ - void registerPatternElementPairs2( Node pat, Ips& ips, - PpIpsMap & pp_ips_map, NodePcDispatcher* npc); - void registerPatternElementPairs( Node pat, PpIpsMap & pp_ips_map, - NodePcDispatcher* npc, NodePpDispatcher* npp); - /** find the pp-pair between pattern inside multi-pattern*/ - void combineMultiPpIpsMap(PpIpsMap & pp_ips_map, MultiPpIpsMap & multi_pp_ips_map, - EfficientHandler& eh, size_t index2, - const std::vector & pats); //pats for debug - /** compute candidates for pc pairs */ - void computeCandidatesPcPairs( Node a, EqClassInfo*, Node b, EqClassInfo* ); - /** compute candidates for pp pairs */ - void computeCandidatesPpPairs( Node a, EqClassInfo*, Node b, EqClassInfo* ); - /** compute candidates for cc pairs */ - void computeCandidatesConstants( Node a, EqClassInfo*, Node b, EqClassInfo* ); - /** collect terms based on inverted path string */ - void collectTermsIps( Ips& ips, SetNode& terms, int index); - bool collectParentsTermsIps( Node n, Node f, int arg, SetNode& terms, bool addRep, bool modEq = true ); -public: - void collectTermsIps( Ips& ips, SetNode& terms); -public: - void registerEfficientHandler( EfficientHandler& eh, const std::vector & pat ); -public: - void newTerms(SetNode& s); -public: - /** output eq class */ - void outputEqClass( const char* c, Node n ); - /** output inverted path string */ - void outputIps( const char* c, Ips& ips ); -};/* class EfficientEMatcher */ - - -}/* CVC4::theory namespace */ -}/* CVC4 namespace */ - -#endif /* __CVC4__EFFICIENT_E_MATCHING_H */ +/********************* */ +/*! \file efficient_e_matching.h + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: Morgan Deters + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief efficient e-matching + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__EFFICIENT_E_MATCHING_H +#define __CVC4__EFFICIENT_E_MATCHING_H + +#include "expr/node.h" +#include "context/context.h" +#include "context/context_mm.h" +#include "context/cdchunk_list.h" + +#include "util/statistics_registry.h" +#include "util/ntuple.h" +#include "context/cdqueue.h" +#include "context/cdo.h" + +#include "theory/uf/equality_engine.h" + +namespace CVC4 { +namespace theory { + +class QuantifiersEngine; + +namespace quantifiers{ + class TermDb; +} + +class EfficientEMatcher; +class HandlerPcDispatcher; +class HandlerPpDispatcher; + +typedef std::set SetNode; + +template +class CleanUpPointer{ +public: + inline void operator()(T** e){ + delete(*e); + }; +}; + +class EfficientHandler{ +public: + typedef std::pair< Node, size_t > MonoCandidate; + typedef std::pair< MonoCandidate, MonoCandidate > MultiCandidate; + typedef std::pair< SetNode, size_t > MonoCandidates; + typedef std::pair< MonoCandidates, MonoCandidates > MultiCandidates; +private: + /* Queue of candidates */ + typedef context::CDQueue< MonoCandidates *, CleanUpPointer > MonoCandidatesQueue; + typedef context::CDQueue< MultiCandidates *, CleanUpPointer > MultiCandidatesQueue; + MonoCandidatesQueue d_monoCandidates; + typedef SetNode::iterator SetNodeIter; + context::CDO d_si; + context::CDO d_mono_not_first; + + MonoCandidatesQueue d_monoCandidatesNewTerm; + context::CDO d_si_new_term; + context::CDO d_mono_not_first_new_term; + + + MultiCandidatesQueue d_multiCandidates; + context::CDO d_si1; + context::CDO d_si2; + context::CDO d_multi_not_first; + + + friend class EfficientEMatcher; + friend class HandlerPcDispatcher; + friend class HandlerPpDispatcher; + friend class HandlerNewTermDispatcher; +protected: + void addMonoCandidate(SetNode & s, size_t index){ + Assert(!s.empty()); + d_monoCandidates.push(new MonoCandidates(s,index)); + } + void addMonoCandidateNewTerm(SetNode & s, size_t index){ + Assert(!s.empty()); + d_monoCandidatesNewTerm.push(new MonoCandidates(s,index)); + } + void addMultiCandidate(SetNode & s1, size_t index1, SetNode & s2, size_t index2){ + Assert(!s1.empty() && !s2.empty()); + d_multiCandidates.push(new MultiCandidates(MonoCandidates(s1,index1), + MonoCandidates(s2,index2))); + } +public: + EfficientHandler(context::Context * c): + //false for d_mono_not_first beacause its the default constructor + d_monoCandidates(c), d_si(c), d_mono_not_first(c,false), + d_monoCandidatesNewTerm(c), d_si_new_term(c), + d_mono_not_first_new_term(c,false), + d_multiCandidates(c) , d_si1(c), d_si2(c), d_multi_not_first(c,false) {}; + + bool getNextMonoCandidate(MonoCandidate & candidate){ + if(d_monoCandidates.empty()) return false; + const MonoCandidates * front = d_monoCandidates.front(); + SetNodeIter si_tmp; + if(!d_mono_not_first){ + Assert(front->first.begin() != front->first.end()); + d_mono_not_first = true; + si_tmp=front->first.begin(); + }else{ + si_tmp = d_si; + ++si_tmp; + }; + if(si_tmp != front->first.end()){ + candidate.first = (*si_tmp); + candidate.second = front->second; + d_si = si_tmp; + Debug("efficienthandler") << "Mono produces " << candidate.first << " for " << candidate.second << std::endl; + return true; + }; + d_monoCandidates.pop(); + d_mono_not_first = false; + return getNextMonoCandidate(candidate); + }; + + bool getNextMonoCandidateNewTerm(MonoCandidate & candidate){ + if(d_monoCandidatesNewTerm.empty()) return false; + const MonoCandidates * front = d_monoCandidatesNewTerm.front(); + SetNodeIter si_tmp; + if(!d_mono_not_first_new_term){ + Assert(front->first.begin() != front->first.end()); + d_mono_not_first_new_term = true; + si_tmp=front->first.begin(); + }else{ + si_tmp = d_si_new_term; + ++si_tmp; + }; + if(si_tmp != front->first.end()){ + candidate.first = (*si_tmp); + candidate.second = front->second; + d_si_new_term = si_tmp; + Debug("efficienthandler") << "Mono produces " << candidate.first << " for " << candidate.second << std::endl; + return true; + }; + d_monoCandidatesNewTerm.pop(); + d_mono_not_first_new_term = false; + return getNextMonoCandidateNewTerm(candidate); + }; + + bool getNextMultiCandidate(MultiCandidate & candidate){ + if(d_multiCandidates.empty()) return false; + const MultiCandidates* front = d_multiCandidates.front(); + SetNodeIter si1_tmp; + SetNodeIter si2_tmp; + if(!d_multi_not_first){ + Assert(front->first.first.begin() != front->first.first.end()); + Assert(front->second.first.begin() != front->second.first.end()); + si1_tmp = front->first.first.begin(); + si2_tmp = front->second.first.begin(); + }else{ + si1_tmp = d_si1; + si2_tmp = d_si2; + ++si2_tmp; + }; + if(si2_tmp != front->second.first.end()){ + candidate.first.first = *si1_tmp; + candidate.first.second = front->first.second; + candidate.second.first = *si2_tmp; + candidate.second.second = front->second.second; + if(!d_multi_not_first){d_si1 = si1_tmp; d_multi_not_first = true; }; + d_si2 = si2_tmp; + Debug("efficienthandler") << "Multi1 produces " + << candidate.first.first << " for " + << candidate.first.second << " and " + << candidate.second.first << " for " + << candidate.second.second << " and " + << std::endl; + return true; + }; // end of the second set + si2_tmp = front->second.first.begin(); + ++si1_tmp; + if(si1_tmp != front->first.first.end()){ + candidate.first.first = *si1_tmp; + candidate.first.second = front->first.second; + candidate.second.first = *si2_tmp; + candidate.second.second = front->second.second; + d_si1 = si1_tmp; + d_si2 = si2_tmp; + Debug("efficienthandler") << "Multi2 produces " + << candidate.first.first << " for " + << candidate.first.second << " and " + << candidate.second.first << " for " + << candidate.second.second << " and " + << std::endl; + return true; + }; // end of the first set + d_multiCandidates.pop(); + d_multi_not_first = false; + return getNextMultiCandidate(candidate); + } +}; + +class PcDispatcher{ +public: + virtual ~PcDispatcher(){}; + /* Send the node to the dispatcher */ + virtual void send(SetNode & s) = 0; +}; + + +class HandlerPcDispatcher: public PcDispatcher{ + EfficientHandler* d_handler; + size_t d_index; +public: + HandlerPcDispatcher(EfficientHandler* handler, size_t index): + d_handler(handler), d_index(index) {}; + void send(SetNode & s){ + d_handler->addMonoCandidate(s,d_index); + } +}; + + +/** All the dispatcher that correspond to this node */ +class NodePcDispatcher: public PcDispatcher{ +#ifdef CVC4_DEBUG +public: + Node pat; +#endif/* CVC4_DEBUG*/ +private: + std::vector d_dis; +public: + void send(SetNode & s){ + Assert(!s.empty()); + for(std::vector::iterator i = d_dis.begin(), end = d_dis.end(); + i != end; ++i){ + (*i).send(s); + } + } + void addPcDispatcher(EfficientHandler* handler, size_t index){ + d_dis.push_back(HandlerPcDispatcher(handler,index)); + } +}; + + +class HandlerNewTermDispatcher: public PcDispatcher{ + EfficientHandler* d_handler; + size_t d_index; +public: + HandlerNewTermDispatcher(EfficientHandler* handler, size_t index): + d_handler(handler), d_index(index) {}; + void send(SetNode & s){ + d_handler->addMonoCandidateNewTerm(s,d_index); + } +}; + +/** All the dispatcher that correspond to this node */ +class NodeNewTermDispatcher: public PcDispatcher{ +#ifdef CVC4_DEBUG +public: + Node pat; +#endif/* CVC4_DEBUG*/ +private: + std::vector d_dis; +public: + void send(SetNode & s){ + Assert(!s.empty()); + for(std::vector::iterator i = d_dis.begin(), end = d_dis.end(); + i != end; ++i){ + (*i).send(s); + } + } + void addNewTermDispatcher(EfficientHandler* handler, size_t index){ + d_dis.push_back(HandlerNewTermDispatcher(handler,index)); + } +}; + +class PpDispatcher{ +public: + virtual ~PpDispatcher(){}; + /* Send the node to the dispatcher */ + virtual void send(SetNode & s1, SetNode & s2, SetNode & sinter) = 0; +}; + + +class HandlerPpDispatcher: public PpDispatcher{ + EfficientHandler* d_handler; + size_t d_index1; + size_t d_index2; +public: + HandlerPpDispatcher(EfficientHandler* handler, size_t index1, size_t index2): + d_handler(handler), d_index1(index1), d_index2(index2) {}; + void send(SetNode & s1, SetNode & s2, SetNode & sinter){ + if(d_index1 == d_index2){ + if(!sinter.empty()) + d_handler->addMonoCandidate(sinter,d_index1); + }else{ + d_handler->addMultiCandidate(s1,d_index1,s2,d_index2); + } + } +}; + + +/** All the dispatcher that correspond to this node */ +class NodePpDispatcher: public PpDispatcher{ +#ifdef CVC4_DEBUG +public: + Node pat1; + Node pat2; +#endif/* CVC4_DEBUG */ +private: + std::vector d_dis; + void send(SetNode & s1, SetNode & s2, SetNode & inter){ + for(std::vector::iterator i = d_dis.begin(), end = d_dis.end(); + i != end; ++i){ + (*i).send(s1,s2,inter); + } + } +public: + void send(SetNode & s1, SetNode & s2){ + // can be done in HandlerPpDispatcher lazily + Assert(!s1.empty() && !s2.empty()); + SetNode inter; + std::set_intersection( s1.begin(), s1.end(), s2.begin(), s2.end(), + std::inserter( inter, inter.begin() ) ); + send(s1,s2,inter); + } + void addPpDispatcher(EfficientHandler* handler, size_t index1, size_t index2){ + d_dis.push_back(HandlerPpDispatcher(handler,index1,index2)); + } +}; + +//equivalence class info +class EqClassInfo +{ +public: + typedef context::CDHashMap BoolMap; + typedef context::CDChunkList NodeList; +public: + //a list of operators that occur as top symbols in this equivalence class + // Efficient E-Matching for SMT Solvers: "funs" + BoolMap d_funs; + //a list of operators f for which a term of the form f( ... t ... ) exists + // Efficient E-Matching for SMT Solvers: "pfuns" + BoolMap d_pfuns; + //a list of equivalence classes that are disequal + BoolMap d_disequal; +public: + EqClassInfo( context::Context* c ); + ~EqClassInfo(){} + //set member + void setMember( Node n, quantifiers::TermDb* db ); + //has function "funs" + bool hasFunction( Node op ); + //has parent "pfuns" + bool hasParent( Node op ); + //merge with another eq class info + void merge( EqClassInfo* eci ); +}; + +class EfficientEMatcher{ +protected: + /** reference to the quantifiers engine */ + QuantifiersEngine* d_quantEngine; +public: + EfficientEMatcher(CVC4::theory::QuantifiersEngine* qe); + ~EfficientEMatcher() { + for(std::map< Node, std::pair >::iterator + i = d_pat_cand_gens.begin(), end = d_pat_cand_gens.end(); + i != end; i++){ + delete(i->second.first); + delete(i->second.second); + } + } + /** get equality engine we are using */ + eq::EqualityEngine* getEqualityEngine(); +private: + //information for each equivalence class + std::map< Node, EqClassInfo* > d_eqc_ops; +public: + /** new node */ + void newEqClass( TNode n ); + /** merge */ + void merge( TNode a, TNode b ); + /** assert terms are disequal */ + void assertDisequal( TNode a, TNode b, TNode reason ); + /** get equivalence class info */ + EqClassInfo* getEquivalenceClassInfo( Node n ); + EqClassInfo* getOrCreateEquivalenceClassInfo( Node n ); + typedef std::vector< std::pair< Node, int > > Ips; + typedef std::map< Node, std::vector< std::pair< Node, Ips > > > PpIpsMap; + typedef std::map< Node, std::vector< triple< size_t, Node, Ips > > > MultiPpIpsMap; +private: + /** Parent/Child Pairs (for efficient E-matching) + So, for example, if we have the pattern f( g( x ) ), then d_pc_pairs[g][f][f( g( x ) )] = { f.0 }. + */ + std::map< Node, std::map< Node, std::vector< std::pair< NodePcDispatcher*, Ips > > > > d_pc_pairs; + /** Parent/Parent Pairs (for efficient E-matching) */ + std::map< Node, std::map< Node, std::vector< triple< NodePpDispatcher*, Ips, Ips > > > > d_pp_pairs; + /** Constants/Child Pairs + So, for example, if we have the pattern f( x ) = c, then d_pc_pairs[f][c] = ..., pcdispatcher, ... + */ + //TODO constant in pattern can use the same thing just add an Ips + std::map< Node, std::map< Node, NodePcDispatcher* > > d_cc_pairs; + /** list of all candidate generators for each operator */ + std::map< Node, NodeNewTermDispatcher > d_cand_gens; + /** list of all candidate generators for each type */ + std::map< TypeNode, NodeNewTermDispatcher > d_cand_gen_types; + /** map from patterns to candidate generators */ + std::map< Node, std::pair > d_pat_cand_gens; + /** helper functions */ + void registerPatternElementPairs2( Node pat, Ips& ips, + PpIpsMap & pp_ips_map, NodePcDispatcher* npc); + void registerPatternElementPairs( Node pat, PpIpsMap & pp_ips_map, + NodePcDispatcher* npc, NodePpDispatcher* npp); + /** find the pp-pair between pattern inside multi-pattern*/ + void combineMultiPpIpsMap(PpIpsMap & pp_ips_map, MultiPpIpsMap & multi_pp_ips_map, + EfficientHandler& eh, size_t index2, + const std::vector & pats); //pats for debug + /** compute candidates for pc pairs */ + void computeCandidatesPcPairs( Node a, EqClassInfo*, Node b, EqClassInfo* ); + /** compute candidates for pp pairs */ + void computeCandidatesPpPairs( Node a, EqClassInfo*, Node b, EqClassInfo* ); + /** compute candidates for cc pairs */ + void computeCandidatesConstants( Node a, EqClassInfo*, Node b, EqClassInfo* ); + /** collect terms based on inverted path string */ + void collectTermsIps( Ips& ips, SetNode& terms, int index); + bool collectParentsTermsIps( Node n, Node f, int arg, SetNode& terms, bool addRep, bool modEq = true ); +public: + void collectTermsIps( Ips& ips, SetNode& terms); +public: + void registerEfficientHandler( EfficientHandler& eh, const std::vector & pat ); +public: + void newTerms(SetNode& s); +public: + /** output eq class */ + void outputEqClass( const char* c, Node n ); + /** output inverted path string */ + void outputIps( const char* c, Ips& ips ); +};/* class EfficientEMatcher */ + + +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ + +#endif /* __CVC4__EFFICIENT_E_MATCHING_H */ diff --git a/src/util/sort_inference.cpp b/src/util/sort_inference.cpp old mode 100755 new mode 100644 index cab5dac42..0304a8e35 --- a/src/util/sort_inference.cpp +++ b/src/util/sort_inference.cpp @@ -1,428 +1,428 @@ -/********************* */ -/*! \file sort_inference.cpp - ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief Sort inference module - ** - ** This class implements sort inference, based on a simple algorithm: - ** First, we assume all functions and predicates have distinct uninterpreted types. - ** One pass is made through the input assertions, while a union-find data structure - ** maintains necessary information regarding constraints on these types. - **/ - -#include - -#include "util/sort_inference.h" - -using namespace CVC4; -using namespace std; - -namespace CVC4 { - - -void SortInference::printSort( const char* c, int t ){ - int rt = getRepresentative( t ); - if( d_type_types.find( rt )!=d_type_types.end() ){ - Trace(c) << d_type_types[rt]; - }else{ - Trace(c) << "s_" << rt; - } -} - -void SortInference::simplify( std::vector< Node >& assertions, bool doRewrite ){ - //process all assertions - for( unsigned i=0; i var_bound; - process( assertions[i], var_bound ); - } - //print debug - if( Trace.isOn("sort-inference") ){ - for( std::map< Node, int >::iterator it = d_op_return_types.begin(); it != d_op_return_types.end(); ++it ){ - Trace("sort-inference") << it->first << " : "; - if( !d_op_arg_types[ it->first ].empty() ){ - Trace("sort-inference") << "( "; - for( size_t i=0; ifirst ].size(); i++ ){ - printSort( "sort-inference", d_op_arg_types[ it->first ][i] ); - Trace("sort-inference") << " "; - } - Trace("sort-inference") << ") -> "; - } - printSort( "sort-inference", it->second ); - Trace("sort-inference") << std::endl; - } - for( std::map< Node, std::map< Node, int > >::iterator it = d_var_types.begin(); it != d_var_types.end(); ++it ){ - Trace("sort-inference") << "Quantified formula " << it->first << " : " << std::endl; - for( std::map< Node, int >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ - printSort( "sort-inference", it2->second ); - Trace("sort-inference") << std::endl; - } - Trace("sort-inference") << std::endl; - } - } - if( doRewrite ){ - //simplify all assertions by introducing new symbols wherever necessary (NOTE: this is unsound for quantifiers) - for( unsigned i=0; i var_bound; - assertions[i] = simplify( assertions[i], var_bound ); - Trace("sort-inference-rewrite") << " --> " << assertions[i] << std::endl; - } - //now, ensure constants are distinct - for( std::map< TypeNode, std::map< Node, Node > >::iterator it = d_const_map.begin(); it != d_const_map.end(); ++it ){ - std::vector< Node > consts; - for( std::map< Node, Node >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ - consts.push_back( it2->second ); - } - //add lemma enforcing introduced constants to be distinct? - } - } -} - -int SortInference::getRepresentative( int t ){ - std::map< int, int >::iterator it = d_type_union_find.find( t ); - if( it!=d_type_union_find.end() ){ - if( it->second==t ){ - return t; - }else{ - int rt = getRepresentative( it->second ); - d_type_union_find[t] = rt; - return rt; - } - }else{ - return t; - } -} - -void SortInference::setEqual( int t1, int t2 ){ - if( t1!=t2 ){ - int rt1 = getRepresentative( t1 ); - int rt2 = getRepresentative( t2 ); - if( rt1!=rt2 ){ - Trace("sort-inference-debug") << "Set equal : "; - printSort( "sort-inference-debug", rt1 ); - Trace("sort-inference-debug") << " "; - printSort( "sort-inference-debug", rt2 ); - Trace("sort-inference-debug") << std::endl; - //check if they must be a type - std::map< int, TypeNode >::iterator it1 = d_type_types.find( rt1 ); - std::map< int, TypeNode >::iterator it2 = d_type_types.find( rt2 ); - if( it2!=d_type_types.end() ){ - if( it1==d_type_types.end() ){ - //swap sides - int swap = rt1; - rt1 = rt2; - rt2 = swap; - }else{ - Assert( rt1==rt2 ); - } - } - /* - d_type_eq_class[rt1].insert( d_type_eq_class[rt1].end(), d_type_eq_class[rt2].begin(), d_type_eq_class[rt2].end() ); - d_type_eq_class[rt2].clear(); - Trace("sort-inference-debug") << "EqClass : { "; - for( int i=0; i<(int)d_type_eq_class[rt1].size(); i++ ){ - Trace("sort-inference-debug") << d_type_eq_class[rt1][i] << ", "; - } - Trace("sort-inference-debug") << "}" << std::endl; - */ - d_type_union_find[rt2] = rt1; - } - } -} - -int SortInference::getIdForType( TypeNode tn ){ - //register the return type - std::map< TypeNode, int >::iterator it = d_id_for_types.find( tn ); - if( it==d_id_for_types.end() ){ - int sc = sortCount; - d_type_types[ sortCount ] = tn; - d_id_for_types[ tn ] = sortCount; - sortCount++; - return sc; - }else{ - return it->second; - } -} - -int SortInference::process( Node n, std::map< Node, Node >& var_bound ){ - Trace("sort-inference-debug") << "Process " << n << std::endl; - //add to variable bindings - if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){ - for( size_t i=0; i children; - std::vector< int > child_types; - for( size_t i=0; i::iterator it = var_bound.find( n ); - if( it!=var_bound.end() ){ - Trace("sort-inference-debug") << n << " is a bound variable." << std::endl; - //the return type was specified while binding - retType = d_var_types[it->second][n]; - }else if( n.getKind() == kind::VARIABLE ){ - Trace("sort-inference-debug") << n << " is a variable." << std::endl; - if( d_op_return_types.find( n )==d_op_return_types.end() ){ - //assign arbitrary sort - d_op_return_types[n] = sortCount; - sortCount++; - //d_type_eq_class[sortCount].push_back( n ); - } - retType = d_op_return_types[n]; - }else if( n.isConst() ){ - Trace("sort-inference-debug") << n << " is a constant." << std::endl; - //can be any type we want - retType = sortCount; - sortCount++; - }else{ - Trace("sort-inference-debug") << n << " is a interpreted symbol." << std::endl; - //it is an interpretted term - for( size_t i=0; imkSort( ss.str() ); - } - d_id_for_types[ retType ] = rt; - d_type_types[ rt ] = retType; - return retType; - } -} - -TypeNode SortInference::getTypeForId( int t ){ - int rt = getRepresentative( t ); - if( d_type_types.find( rt )!=d_type_types.end() ){ - return d_type_types[rt]; - }else{ - return TypeNode::null(); - } -} - -Node SortInference::getNewSymbol( Node old, TypeNode tn ){ - if( tn==old.getType() ){ - return old; - }else if( old.isConst() ){ - //must make constant of type tn - if( d_const_map[tn].find( old )==d_const_map[tn].end() ){ - std::stringstream ss; - ss << "ic_" << tn << "_" << old; - d_const_map[tn][ old ] = NodeManager::currentNM()->mkSkolem( ss.str(), tn, "constant created during sort inference" ); //use mkConst??? - } - return d_const_map[tn][ old ]; - }else{ - std::stringstream ss; - ss << "i_$$_" << old; - return NodeManager::currentNM()->mkSkolem( ss.str(), tn, "created during sort inference" ); - } -} - -Node SortInference::simplify( Node n, std::map< Node, Node >& var_bound ){ - std::vector< Node > children; - if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){ - //recreate based on types of variables - std::vector< Node > new_children; - for( size_t i=0; imkNode( n[0].getKind(), new_children ) ); - } - - //process children - if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){ - children.push_back( n.getOperator() ); - } - for( size_t i=0; i=1; - } - if( processChild ){ - children.push_back( simplify( n[i], var_bound ) ); - } - } - - //remove from variable bindings - if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){ - //erase from variable bound - for( size_t i=0; imkNode( n.getKind(), children ); - }else if( n.getKind()==kind::EQUAL ){ - if( children[0].getType()!=children[1].getType() ){ - if( children[0].isConst() ){ - children[0] = getNewSymbol( children[0], children[1].getType() ); - }else if( children[1].isConst() ){ - children[1] = getNewSymbol( children[1], children[0].getType() ); - }else{ - Trace("sort-inference-warn") << "Sort inference created bad equality: " << children[0] << " = " << children[1] << std::endl; - Trace("sort-inference-warn") << " Types : " << children[0].getType() << " " << children[1].getType() << std::endl; - Assert( false ); - } - } - return NodeManager::currentNM()->mkNode( kind::APPLY_UF, children ); - }else if( n.getKind()==kind::APPLY_UF ){ - Node op = n.getOperator(); - if( d_symbol_map.find( op )==d_symbol_map.end() ){ - //make the new operator if necessary - bool opChanged = false; - std::vector< TypeNode > argTypes; - for( size_t i=0; imkFunctionType( argTypes, retType ); - d_symbol_map[op] = NodeManager::currentNM()->mkSkolem( ss.str(), typ, "op created during sort inference" ); - }else{ - d_symbol_map[op] = op; - } - } - children[0] = d_symbol_map[op]; - //make sure all children have been taken care of - for( size_t i=0; imkNode( kind::APPLY_UF, children ); - }else{ - std::map< Node, Node >::iterator it = var_bound.find( n ); - if( it!=var_bound.end() ){ - return it->second; - }else if( n.getKind() == kind::VARIABLE ){ - if( d_symbol_map.find( n )==d_symbol_map.end() ){ - TypeNode tn = getOrCreateTypeForId( d_op_return_types[n], n.getType() ); - d_symbol_map[n] = getNewSymbol( n, tn ); - } - return d_symbol_map[n]; - }else if( n.isConst() ){ - //just return n, we will fix at higher scope - return n; - }else{ - return NodeManager::currentNM()->mkNode( n.getKind(), children ); - } - } - -} -int SortInference::getSortId( Node n ) { - Node op = n.getKind()==kind::APPLY_UF ? n.getOperator() : n; - return getRepresentative( d_op_return_types[op] ); -} - -int SortInference::getSortId( Node f, Node v ) { - return getRepresentative( d_var_types[f][v] ); -} - -void SortInference::setSkolemVar( Node f, Node v, Node sk ){ - d_op_return_types[sk] = getSortId( f, v ); -} - +/********************* */ +/*! \file sort_inference.cpp + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: Morgan Deters + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Sort inference module + ** + ** This class implements sort inference, based on a simple algorithm: + ** First, we assume all functions and predicates have distinct uninterpreted types. + ** One pass is made through the input assertions, while a union-find data structure + ** maintains necessary information regarding constraints on these types. + **/ + +#include + +#include "util/sort_inference.h" + +using namespace CVC4; +using namespace std; + +namespace CVC4 { + + +void SortInference::printSort( const char* c, int t ){ + int rt = getRepresentative( t ); + if( d_type_types.find( rt )!=d_type_types.end() ){ + Trace(c) << d_type_types[rt]; + }else{ + Trace(c) << "s_" << rt; + } +} + +void SortInference::simplify( std::vector< Node >& assertions, bool doRewrite ){ + //process all assertions + for( unsigned i=0; i var_bound; + process( assertions[i], var_bound ); + } + //print debug + if( Trace.isOn("sort-inference") ){ + for( std::map< Node, int >::iterator it = d_op_return_types.begin(); it != d_op_return_types.end(); ++it ){ + Trace("sort-inference") << it->first << " : "; + if( !d_op_arg_types[ it->first ].empty() ){ + Trace("sort-inference") << "( "; + for( size_t i=0; ifirst ].size(); i++ ){ + printSort( "sort-inference", d_op_arg_types[ it->first ][i] ); + Trace("sort-inference") << " "; + } + Trace("sort-inference") << ") -> "; + } + printSort( "sort-inference", it->second ); + Trace("sort-inference") << std::endl; + } + for( std::map< Node, std::map< Node, int > >::iterator it = d_var_types.begin(); it != d_var_types.end(); ++it ){ + Trace("sort-inference") << "Quantified formula " << it->first << " : " << std::endl; + for( std::map< Node, int >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ + printSort( "sort-inference", it2->second ); + Trace("sort-inference") << std::endl; + } + Trace("sort-inference") << std::endl; + } + } + if( doRewrite ){ + //simplify all assertions by introducing new symbols wherever necessary (NOTE: this is unsound for quantifiers) + for( unsigned i=0; i var_bound; + assertions[i] = simplify( assertions[i], var_bound ); + Trace("sort-inference-rewrite") << " --> " << assertions[i] << std::endl; + } + //now, ensure constants are distinct + for( std::map< TypeNode, std::map< Node, Node > >::iterator it = d_const_map.begin(); it != d_const_map.end(); ++it ){ + std::vector< Node > consts; + for( std::map< Node, Node >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ + consts.push_back( it2->second ); + } + //add lemma enforcing introduced constants to be distinct? + } + } +} + +int SortInference::getRepresentative( int t ){ + std::map< int, int >::iterator it = d_type_union_find.find( t ); + if( it!=d_type_union_find.end() ){ + if( it->second==t ){ + return t; + }else{ + int rt = getRepresentative( it->second ); + d_type_union_find[t] = rt; + return rt; + } + }else{ + return t; + } +} + +void SortInference::setEqual( int t1, int t2 ){ + if( t1!=t2 ){ + int rt1 = getRepresentative( t1 ); + int rt2 = getRepresentative( t2 ); + if( rt1!=rt2 ){ + Trace("sort-inference-debug") << "Set equal : "; + printSort( "sort-inference-debug", rt1 ); + Trace("sort-inference-debug") << " "; + printSort( "sort-inference-debug", rt2 ); + Trace("sort-inference-debug") << std::endl; + //check if they must be a type + std::map< int, TypeNode >::iterator it1 = d_type_types.find( rt1 ); + std::map< int, TypeNode >::iterator it2 = d_type_types.find( rt2 ); + if( it2!=d_type_types.end() ){ + if( it1==d_type_types.end() ){ + //swap sides + int swap = rt1; + rt1 = rt2; + rt2 = swap; + }else{ + Assert( rt1==rt2 ); + } + } + /* + d_type_eq_class[rt1].insert( d_type_eq_class[rt1].end(), d_type_eq_class[rt2].begin(), d_type_eq_class[rt2].end() ); + d_type_eq_class[rt2].clear(); + Trace("sort-inference-debug") << "EqClass : { "; + for( int i=0; i<(int)d_type_eq_class[rt1].size(); i++ ){ + Trace("sort-inference-debug") << d_type_eq_class[rt1][i] << ", "; + } + Trace("sort-inference-debug") << "}" << std::endl; + */ + d_type_union_find[rt2] = rt1; + } + } +} + +int SortInference::getIdForType( TypeNode tn ){ + //register the return type + std::map< TypeNode, int >::iterator it = d_id_for_types.find( tn ); + if( it==d_id_for_types.end() ){ + int sc = sortCount; + d_type_types[ sortCount ] = tn; + d_id_for_types[ tn ] = sortCount; + sortCount++; + return sc; + }else{ + return it->second; + } +} + +int SortInference::process( Node n, std::map< Node, Node >& var_bound ){ + Trace("sort-inference-debug") << "Process " << n << std::endl; + //add to variable bindings + if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){ + for( size_t i=0; i children; + std::vector< int > child_types; + for( size_t i=0; i::iterator it = var_bound.find( n ); + if( it!=var_bound.end() ){ + Trace("sort-inference-debug") << n << " is a bound variable." << std::endl; + //the return type was specified while binding + retType = d_var_types[it->second][n]; + }else if( n.getKind() == kind::VARIABLE ){ + Trace("sort-inference-debug") << n << " is a variable." << std::endl; + if( d_op_return_types.find( n )==d_op_return_types.end() ){ + //assign arbitrary sort + d_op_return_types[n] = sortCount; + sortCount++; + //d_type_eq_class[sortCount].push_back( n ); + } + retType = d_op_return_types[n]; + }else if( n.isConst() ){ + Trace("sort-inference-debug") << n << " is a constant." << std::endl; + //can be any type we want + retType = sortCount; + sortCount++; + }else{ + Trace("sort-inference-debug") << n << " is a interpreted symbol." << std::endl; + //it is an interpretted term + for( size_t i=0; imkSort( ss.str() ); + } + d_id_for_types[ retType ] = rt; + d_type_types[ rt ] = retType; + return retType; + } +} + +TypeNode SortInference::getTypeForId( int t ){ + int rt = getRepresentative( t ); + if( d_type_types.find( rt )!=d_type_types.end() ){ + return d_type_types[rt]; + }else{ + return TypeNode::null(); + } +} + +Node SortInference::getNewSymbol( Node old, TypeNode tn ){ + if( tn==old.getType() ){ + return old; + }else if( old.isConst() ){ + //must make constant of type tn + if( d_const_map[tn].find( old )==d_const_map[tn].end() ){ + std::stringstream ss; + ss << "ic_" << tn << "_" << old; + d_const_map[tn][ old ] = NodeManager::currentNM()->mkSkolem( ss.str(), tn, "constant created during sort inference" ); //use mkConst??? + } + return d_const_map[tn][ old ]; + }else{ + std::stringstream ss; + ss << "i_$$_" << old; + return NodeManager::currentNM()->mkSkolem( ss.str(), tn, "created during sort inference" ); + } +} + +Node SortInference::simplify( Node n, std::map< Node, Node >& var_bound ){ + std::vector< Node > children; + if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){ + //recreate based on types of variables + std::vector< Node > new_children; + for( size_t i=0; imkNode( n[0].getKind(), new_children ) ); + } + + //process children + if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){ + children.push_back( n.getOperator() ); + } + for( size_t i=0; i=1; + } + if( processChild ){ + children.push_back( simplify( n[i], var_bound ) ); + } + } + + //remove from variable bindings + if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){ + //erase from variable bound + for( size_t i=0; imkNode( n.getKind(), children ); + }else if( n.getKind()==kind::EQUAL ){ + if( children[0].getType()!=children[1].getType() ){ + if( children[0].isConst() ){ + children[0] = getNewSymbol( children[0], children[1].getType() ); + }else if( children[1].isConst() ){ + children[1] = getNewSymbol( children[1], children[0].getType() ); + }else{ + Trace("sort-inference-warn") << "Sort inference created bad equality: " << children[0] << " = " << children[1] << std::endl; + Trace("sort-inference-warn") << " Types : " << children[0].getType() << " " << children[1].getType() << std::endl; + Assert( false ); + } + } + return NodeManager::currentNM()->mkNode( kind::APPLY_UF, children ); + }else if( n.getKind()==kind::APPLY_UF ){ + Node op = n.getOperator(); + if( d_symbol_map.find( op )==d_symbol_map.end() ){ + //make the new operator if necessary + bool opChanged = false; + std::vector< TypeNode > argTypes; + for( size_t i=0; imkFunctionType( argTypes, retType ); + d_symbol_map[op] = NodeManager::currentNM()->mkSkolem( ss.str(), typ, "op created during sort inference" ); + }else{ + d_symbol_map[op] = op; + } + } + children[0] = d_symbol_map[op]; + //make sure all children have been taken care of + for( size_t i=0; imkNode( kind::APPLY_UF, children ); + }else{ + std::map< Node, Node >::iterator it = var_bound.find( n ); + if( it!=var_bound.end() ){ + return it->second; + }else if( n.getKind() == kind::VARIABLE ){ + if( d_symbol_map.find( n )==d_symbol_map.end() ){ + TypeNode tn = getOrCreateTypeForId( d_op_return_types[n], n.getType() ); + d_symbol_map[n] = getNewSymbol( n, tn ); + } + return d_symbol_map[n]; + }else if( n.isConst() ){ + //just return n, we will fix at higher scope + return n; + }else{ + return NodeManager::currentNM()->mkNode( n.getKind(), children ); + } + } + +} +int SortInference::getSortId( Node n ) { + Node op = n.getKind()==kind::APPLY_UF ? n.getOperator() : n; + return getRepresentative( d_op_return_types[op] ); +} + +int SortInference::getSortId( Node f, Node v ) { + return getRepresentative( d_var_types[f][v] ); +} + +void SortInference::setSkolemVar( Node f, Node v, Node sk ){ + d_op_return_types[sk] = getSortId( f, v ); +} + } \ No newline at end of file diff --git a/src/util/sort_inference.h b/src/util/sort_inference.h old mode 100755 new mode 100644 index 1378a266c..0b1f96f85 --- a/src/util/sort_inference.h +++ b/src/util/sort_inference.h @@ -1,76 +1,76 @@ -/********************* */ -/*! \file sort_inference.h - ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief Pre-process step for performing sort inference - **/ - -#include "cvc4_private.h" - -#ifndef __CVC4__SORT_INFERENCE_H -#define __CVC4__SORT_INFERENCE_H - -#include -#include -#include -#include -#include "expr/node.h" -#include "expr/type_node.h" - -namespace CVC4 { - -class SortInference{ -private: - //for debugging - //std::map< int, std::vector< Node > > d_type_eq_class; -private: - int sortCount; - std::map< int, int > d_type_union_find; - std::map< int, TypeNode > d_type_types; - std::map< TypeNode, int > d_id_for_types; - //for apply uf operators - std::map< Node, int > d_op_return_types; - std::map< Node, std::vector< int > > d_op_arg_types; - //for bound variables - std::map< Node, std::map< Node, int > > d_var_types; - //get representative - int getRepresentative( int t ); - void setEqual( int t1, int t2 ); - int getIdForType( TypeNode tn ); - void printSort( const char* c, int t ); - //process - int process( Node n, std::map< Node, Node >& var_bound ); -private: - //mapping from old symbols to new symbols - std::map< Node, Node > d_symbol_map; - //mapping from constants to new symbols - std::map< TypeNode, std::map< Node, Node > > d_const_map; - //number of subtypes generated - std::map< TypeNode, int > d_subtype_count; - //helper functions for simplify - TypeNode getOrCreateTypeForId( int t, TypeNode pref ); - TypeNode getTypeForId( int t ); - Node getNewSymbol( Node old, TypeNode tn ); - //simplify - Node simplify( Node n, std::map< Node, Node >& var_bound ); -public: - SortInference() : sortCount( 0 ){} - ~SortInference(){} - - void simplify( std::vector< Node >& assertions, bool doRewrite = false ); - int getSortId( Node n ); - int getSortId( Node f, Node v ); - //set that sk is the skolem variable of v for quantifier f - void setSkolemVar( Node f, Node v, Node sk ); -}; - -} - -#endif +/********************* */ +/*! \file sort_inference.h + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: Morgan Deters + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2013 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Pre-process step for performing sort inference + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__SORT_INFERENCE_H +#define __CVC4__SORT_INFERENCE_H + +#include +#include +#include +#include +#include "expr/node.h" +#include "expr/type_node.h" + +namespace CVC4 { + +class SortInference{ +private: + //for debugging + //std::map< int, std::vector< Node > > d_type_eq_class; +private: + int sortCount; + std::map< int, int > d_type_union_find; + std::map< int, TypeNode > d_type_types; + std::map< TypeNode, int > d_id_for_types; + //for apply uf operators + std::map< Node, int > d_op_return_types; + std::map< Node, std::vector< int > > d_op_arg_types; + //for bound variables + std::map< Node, std::map< Node, int > > d_var_types; + //get representative + int getRepresentative( int t ); + void setEqual( int t1, int t2 ); + int getIdForType( TypeNode tn ); + void printSort( const char* c, int t ); + //process + int process( Node n, std::map< Node, Node >& var_bound ); +private: + //mapping from old symbols to new symbols + std::map< Node, Node > d_symbol_map; + //mapping from constants to new symbols + std::map< TypeNode, std::map< Node, Node > > d_const_map; + //number of subtypes generated + std::map< TypeNode, int > d_subtype_count; + //helper functions for simplify + TypeNode getOrCreateTypeForId( int t, TypeNode pref ); + TypeNode getTypeForId( int t ); + Node getNewSymbol( Node old, TypeNode tn ); + //simplify + Node simplify( Node n, std::map< Node, Node >& var_bound ); +public: + SortInference() : sortCount( 0 ){} + ~SortInference(){} + + void simplify( std::vector< Node >& assertions, bool doRewrite = false ); + int getSortId( Node n ); + int getSortId( Node f, Node v ); + //set that sk is the skolem variable of v for quantifier f + void setSkolemVar( Node f, Node v, Node sk ); +}; + +} + +#endif