diff options
-rwxr-xr-x | src/theory/quantifiers/ambqi_builder.cpp | 1872 | ||||
-rwxr-xr-x | src/theory/quantifiers/ambqi_builder.h | 204 | ||||
-rwxr-xr-x | src/theory/quantifiers/qinterval_builder.cpp | 2222 | ||||
-rwxr-xr-x | src/theory/quantifiers/qinterval_builder.h | 308 | ||||
-rwxr-xr-x | src/theory/quantifiers/quant_conflict_find.cpp | 5058 | ||||
-rwxr-xr-x | src/theory/quantifiers/quant_conflict_find.h | 594 | ||||
-rw-r--r-- | src/theory/strings/regexp_operation.cpp | 3038 | ||||
-rw-r--r-- | src/theory/strings/regexp_operation.h | 200 | ||||
-rw-r--r-- | src/util/regexp.cpp | 318 |
9 files changed, 6907 insertions, 6907 deletions
diff --git a/src/theory/quantifiers/ambqi_builder.cpp b/src/theory/quantifiers/ambqi_builder.cpp index e86a96a8f..374d161e9 100755 --- a/src/theory/quantifiers/ambqi_builder.cpp +++ b/src/theory/quantifiers/ambqi_builder.cpp @@ -1,936 +1,936 @@ -/********************* */
-/*! \file ambqi_builder.cpp
- ** \verbatim
- ** Original author: Andrew Reynolds
- ** Major contributors: none
- ** 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 abstract MBQI builder
- **/
-
-
-#include "theory/quantifiers/ambqi_builder.h"
-#include "theory/quantifiers/term_database.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 AbsDef::construct_func( FirstOrderModelAbs * m, std::vector< TNode >& fapps, unsigned depth ) {
- d_def.clear();
- Assert( !fapps.empty() );
- if( depth==fapps[0].getNumChildren() ){
- //if( fapps.size()>1 ){
- // for( unsigned i=0; i<fapps.size(); i++ ){
- // std::cout << "...." << fapps[i] << " -> " << m->getRepresentativeId( fapps[i] ) << std::endl;
- // }
- //}
- //get representative in model for this term
- d_value = m->getRepresentativeId( fapps[0] );
- Assert( d_value!=val_none );
- }else{
- TypeNode tn = fapps[0][depth].getType();
- std::map< unsigned, std::vector< TNode > > fapp_child;
-
- //partition based on evaluations of fapps[1][depth]....fapps[n][depth]
- for( unsigned i=0; i<fapps.size(); i++ ){
- unsigned r = m->getRepresentativeId( fapps[i][depth] );
- Assert( r < 32 );
- fapp_child[r].push_back( fapps[i] );
- }
-
- //do completion
- std::map< unsigned, unsigned > fapp_child_index;
- unsigned def = m->d_domain[ tn ];
- unsigned minSize = fapp_child.begin()->second.size();
- unsigned minSizeIndex = fapp_child.begin()->first;
- for( std::map< unsigned, std::vector< TNode > >::iterator it = fapp_child.begin(); it != fapp_child.end(); ++it ){
- fapp_child_index[it->first] = ( 1 << it->first );
- def = def & ~( 1 << it->first );
- if( it->second.size()<minSize ){
- minSize = it->second.size();
- minSizeIndex = it->first;
- }
- }
- fapp_child_index[minSizeIndex] |= def;
- d_default = fapp_child_index[minSizeIndex];
-
- //construct children
- for( std::map< unsigned, std::vector< TNode > >::iterator it = fapp_child.begin(); it != fapp_child.end(); ++it ){
- Trace("abs-model-debug") << "Construct " << it->first << " : " << fapp_child_index[it->first] << " : ";
- debugPrintUInt( "abs-model-debug", m->d_rep_set.d_type_reps[tn].size(), fapp_child_index[it->first] );
- Trace("abs-model-debug") << " : " << it->second.size() << " terms." << std::endl;
- d_def[fapp_child_index[it->first]].construct_func( m, it->second, depth+1 );
- }
- }
-}
-
-void AbsDef::simplify( FirstOrderModelAbs * m, TNode q, TNode n, unsigned depth ) {
- if( d_value==val_none && !d_def.empty() ){
- //process the default
- std::map< unsigned, AbsDef >::iterator defd = d_def.find( d_default );
- Assert( defd!=d_def.end() );
- unsigned newDef = d_default;
- std::vector< unsigned > to_erase;
- defd->second.simplify( m, q, n, depth+1 );
- int defVal = defd->second.d_value;
- bool isConstant = ( defVal!=val_none );
- //process each child
- for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
- if( it->first!=d_default ){
- it->second.simplify( m, q, n, depth+1 );
- if( it->second.d_value==defVal && it->second.d_value!=val_none ){
- newDef = newDef | it->first;
- to_erase.push_back( it->first );
- }else{
- isConstant = false;
- }
- }
- }
- if( !to_erase.empty() ){
- //erase old default
- int defVal = defd->second.d_value;
- d_def.erase( d_default );
- //set new default
- d_default = newDef;
- d_def[d_default].construct_def_entry( m, q, n, defVal, depth+1 );
- //erase redundant entries
- for( unsigned i=0; i<to_erase.size(); i++ ){
- d_def.erase( to_erase[i] );
- }
- }
- //if constant, propagate the value upwards
- if( isConstant ){
- d_value = defVal;
- }else{
- d_value = val_none;
- }
- }
-}
-
-void AbsDef::debugPrintUInt( const char * c, unsigned dSize, unsigned u ) const{
- for( unsigned i=0; i<dSize; i++ ){
- Trace(c) << ( ( u & ( 1 << i ) )!=0 ? "1" : "0");
- }
- //Trace(c) << "(";
- //for( unsigned i=0; i<32; i++ ){
- // Trace(c) << ( ( u & ( 1 << i ) )!=0 ? "1" : "0");
- //}
- //Trace(c) << ")";
-}
-
-void AbsDef::debugPrint( const char * c, FirstOrderModelAbs * m, TNode f, unsigned depth ) const{
- if( Trace.isOn(c) ){
- if( depth==f.getNumChildren() ){
- for( unsigned i=0; i<depth; i++ ){ Trace(c) << " ";}
- Trace(c) << "V[" << d_value << "]" << std::endl;
- }else{
- TypeNode tn = f[depth].getType();
- unsigned dSize = m->d_rep_set.getNumRepresentatives( tn );
- Assert( dSize<32 );
- for( std::map< unsigned, AbsDef >::const_iterator it = d_def.begin(); it != d_def.end(); ++it ){
- for( unsigned i=0; i<depth; i++ ){ Trace(c) << " ";}
- debugPrintUInt( c, dSize, it->first );
- if( it->first==d_default ){
- Trace(c) << "*";
- }
- if( it->second.d_value!=val_none ){
- Trace(c) << " -> V[" << it->second.d_value << "]";
- }
- Trace(c) << std::endl;
- it->second.debugPrint( c, m, f, depth+1 );
- }
- }
- }
-}
-
-bool AbsDef::addInstantiations( FirstOrderModelAbs * m, QuantifiersEngine * qe, TNode q, std::vector< Node >& terms, int& inst, unsigned depth ) {
- if( inst==0 || !options::fmfOneInstPerRound() ){
- if( d_value==1 ){
- //instantiations are all true : ignore this
- return true;
- }else{
- if( depth==q[0].getNumChildren() ){
- if( qe->addInstantiation( q, terms ) ){
- Trace("ambqi-inst-debug") << "-> Added instantiation." << std::endl;
- inst++;
- return true;
- }else{
- Trace("ambqi-inst-debug") << "-> Failed to add instantiation." << std::endl;
- //we are incomplete
- return false;
- }
- }else{
- bool osuccess = true;
- TypeNode tn = m->getVariable( q, depth ).getType();
- for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
- //get witness term
- unsigned index = 0;
- bool success;
- do {
- success = false;
- index = getId( it->first, index );
- if( index<32 ){
- Assert( index<m->d_rep_set.d_type_reps[tn].size() );
- terms[m->d_var_order[q][depth]] = m->d_rep_set.d_type_reps[tn][index];
- //terms[depth] = m->d_rep_set.d_type_reps[tn][index];
- if( !it->second.addInstantiations( m, qe, q, terms, inst, depth+1 ) && inst==0 ){
- //if we are incomplete, and have not yet added an instantiation, keep trying
- index++;
- Trace("ambqi-inst-debug") << "At depth " << depth << ", failed branch, no instantiations and incomplete, increment index : " << index << std::endl;
- }else{
- success = true;
- }
- }
- }while( !success && index<32 );
- //mark if we are incomplete
- osuccess = osuccess && success;
- }
- return osuccess;
- }
- }
- }else{
- return true;
- }
-}
-
-void AbsDef::construct_entry( std::vector< unsigned >& entry, std::vector< bool >& entry_def, int v, unsigned depth ) {
- if( depth==entry.size() ){
- d_value = v;
- }else{
- d_def[entry[depth]].construct_entry( entry, entry_def, v, depth+1 );
- if( entry_def[depth] ){
- d_default = entry[depth];
- }
- }
-}
-
-void AbsDef::get_defs( unsigned u, std::vector< AbsDef * >& defs ) {
- for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
- if( ( u & it->first )!=0 ){
- Assert( (u & it->first)==u );
- defs.push_back( &it->second );
- }
- }
-}
-
-void AbsDef::construct_normalize( FirstOrderModelAbs * m, TNode q, std::vector< AbsDef * >& defs, unsigned depth ) {
- if( depth==q[0].getNumChildren() ){
- Assert( defs.size()==1 );
- d_value = defs[0]->d_value;
- }else{
- TypeNode tn = m->getVariable( q, depth ).getType();
- unsigned def = m->d_domain[tn];
- for( unsigned i=0; i<defs.size(); i++ ){
- //process each simple child
- for( std::map< unsigned, AbsDef >::iterator itd = defs[i]->d_def.begin(); itd != defs[i]->d_def.end(); ++itd ){
- if( isSimple( itd->first ) && ( def & itd->first )!=0 ){
- def &= ~( itd->first );
- //process this value
- std::vector< AbsDef * > cdefs;
- for( unsigned j=0; j<defs.size(); j++ ){
- defs[j]->get_defs( itd->first, cdefs );
- }
- d_def[itd->first].construct_normalize( m, q, cdefs, depth+1 );
- if( def==0 ){
- d_default = itd->first;
- break;
- }
- }
- }
- if( def==0 ){
- break;
- }
- }
- if( def!=0 ){
- d_default = def;
- //process the default
- std::vector< AbsDef * > cdefs;
- for( unsigned j=0; j<defs.size(); j++ ){
- defs[j]->get_defs( d_default, cdefs );
- }
- d_def[d_default].construct_normalize( m, q, cdefs, depth+1 );
- }
- }
-}
-
-void AbsDef::construct_def_entry( FirstOrderModelAbs * m, TNode q, TNode n, int v, unsigned depth ) {
- d_value = v;
- if( depth<n.getNumChildren() ){
- TypeNode tn = q.isNull() ? n[depth].getType() : m->getVariable( q, depth ).getType();
- unsigned dom = m->d_domain[tn] ;
- d_def[dom].construct_def_entry( m, q, n, v, depth+1 );
- d_default = dom;
- }
-}
-
-void AbsDef::apply_ucompose( FirstOrderModelAbs * m, TNode q,
- std::vector< unsigned >& entry, std::vector< bool >& entry_def,
- std::vector< int >& terms, std::map< unsigned, int >& vchildren,
- AbsDef * a, unsigned depth ) {
- if( depth==terms.size() ){
- if( Trace.isOn("ambqi-check-debug2") ){
- Trace("ambqi-check-debug2") << "Add entry ( ";
- for( unsigned i=0; i<entry.size(); i++ ){
- unsigned dSize = m->d_rep_set.d_type_reps[m->getVariable( q, i ).getType()].size();
- debugPrintUInt( "ambqi-check-debug2", dSize, entry[i] );
- Trace("ambqi-check-debug2") << " ";
- }
- Trace("ambqi-check-debug2") << ")" << std::endl;
- }
- a->construct_entry( entry, entry_def, d_value );
- }else{
- unsigned id;
- if( terms[depth]==val_none ){
- //a variable
- std::map< unsigned, int >::iterator itv = vchildren.find( depth );
- Assert( itv!=vchildren.end() );
- unsigned prev_v = entry[itv->second];
- bool prev_vd = entry_def[itv->second];
- for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
- entry[itv->second] = it->first & prev_v;
- entry_def[itv->second] = ( it->first==d_default ) && prev_vd;
- if( entry[itv->second]!=0 ){
- it->second.apply_ucompose( m, q, entry, entry_def, terms, vchildren, a, depth+1 );
- }
- }
- entry[itv->second] = prev_v;
- entry_def[itv->second] = prev_vd;
- }else{
- id = (unsigned)terms[depth];
- Assert( id<32 );
- unsigned fid = 1 << id;
- std::map< unsigned, AbsDef >::iterator it = d_def.find( fid );
- if( it!=d_def.end() ){
- it->second.apply_ucompose( m, q, entry, entry_def, terms, vchildren, a, depth+1 );
- }else{
- d_def[d_default].apply_ucompose( m, q, entry, entry_def, terms, vchildren, a, depth+1 );
- }
- }
- }
-}
-
-void AbsDef::construct_var_eq( FirstOrderModelAbs * m, TNode q, unsigned v1, unsigned v2, int curr, int currv, unsigned depth ) {
- if( depth==q[0].getNumChildren() ){
- Assert( currv!=val_none );
- d_value = currv;
- }else{
- TypeNode tn = m->getVariable( q, depth ).getType();
- unsigned dom = m->d_domain[tn];
- int vindex = depth==v1 ? 0 : ( depth==v2 ? 1 : val_none );
- if( vindex==val_none ){
- d_def[dom].construct_var_eq( m, q, v1, v2, curr, currv, depth+1 );
- d_default = dom;
- }else{
- Assert( currv==val_none );
- if( curr==val_none ){
- unsigned numReps = m->d_rep_set.getNumRepresentatives( tn );
- Assert( numReps < 32 );
- for( unsigned i=0; i<numReps; i++ ){
- curr = 1 << i;
- d_def[curr].construct_var_eq( m, q, v1, v2, curr, currv, depth+1 );
- }
- d_default = curr;
- }else{
- d_def[curr].construct_var_eq( m, q, v1, v2, curr, 1, depth+1 );
- dom = dom & ~curr;
- d_def[dom].construct_var_eq( m, q, v1, v2, curr, 0, depth+1 );
- d_default = dom;
- }
- }
- }
-}
-
-void AbsDef::construct_var( FirstOrderModelAbs * m, TNode q, unsigned v, int currv, unsigned depth ) {
- if( depth==q[0].getNumChildren() ){
- Assert( currv!=val_none );
- d_value = currv;
- }else{
- TypeNode tn = m->getVariable( q, depth ).getType();
- if( v==depth ){
- unsigned numReps = m->d_rep_set.d_type_reps[tn].size();
- Assert( numReps>0 && numReps < 32 );
- for( unsigned i=0; i<numReps; i++ ){
- d_def[ 1 << i ].construct_var( m, q, v, i, depth+1 );
- }
- d_default = 1 << (numReps - 1);
- }else{
- unsigned dom = m->d_domain[tn];
- d_def[dom].construct_var( m, q, v, currv, depth+1 );
- d_default = dom;
- }
- }
-}
-
-void AbsDef::construct_compose( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f,
- std::map< unsigned, AbsDef * >& children,
- std::map< unsigned, int >& bchildren, std::map< unsigned, int >& vchildren,
- std::vector< unsigned >& entry, std::vector< bool >& entry_def ) {
- if( n.getKind()==OR || n.getKind()==AND ){
- // short circuiting
- for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){
- if( ( it->second->d_value==0 && n.getKind()==AND ) ||
- ( it->second->d_value==1 && n.getKind()==OR ) ){
- //std::cout << "Short circuit " << it->second->d_value << " " << entry.size() << "/" << q[0].getNumChildren() << std::endl;
- unsigned count = q[0].getNumChildren() - entry.size();
- for( unsigned i=0; i<count; i++ ){
- entry.push_back( m->d_domain[m->getVariable( q, entry.size() ).getType()] );
- entry_def.push_back( true );
- }
- construct_entry( entry, entry_def, it->second->d_value );
- for( unsigned i=0; i<count; i++ ){
- entry.pop_back();
- entry_def.pop_back();
- }
- return;
- }
- }
- }
- if( entry.size()==q[0].getNumChildren() ){
- if( f ){
- if( Trace.isOn("ambqi-check-debug2") ){
- for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << " "; }
- Trace("ambqi-check-debug2") << "Evaluate uninterpreted function entry..." << std::endl;
- }
- //we are composing with an uninterpreted function
- std::vector< int > values;
- values.resize( n.getNumChildren(), val_none );
- for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){
- values[it->first] = it->second->d_value;
- }
- for( std::map< unsigned, int >::iterator it = bchildren.begin(); it != bchildren.end(); ++it ){
- values[it->first] = it->second;
- }
- //look up value(s)
- f->apply_ucompose( m, q, entry, entry_def, values, vchildren, this );
- }else{
- bool incomplete = false;
- //we are composing with an interpreted function
- std::vector< TNode > values;
- values.resize( n.getNumChildren(), TNode::null() );
- for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){
- Trace("ambqi-check-debug2") << "composite : " << it->first << " : " << it->second->d_value;
- if( it->second->d_value>=0 ){
- if( it->second->d_value>=(int)m->d_rep_set.d_type_reps[n[it->first].getType()].size() ){
- std::cout << it->second->d_value << " " << n[it->first] << " " << n[it->first].getType() << " " << m->d_rep_set.d_type_reps[n[it->first].getType()].size() << std::endl;
- }
- Assert( it->second->d_value<(int)m->d_rep_set.d_type_reps[n[it->first].getType()].size() );
- values[it->first] = m->d_rep_set.d_type_reps[n[it->first].getType()][it->second->d_value];
- }else{
- incomplete = true;
- }
- Trace("ambqi-check-debug2") << " ->> " << values[it->first] << std::endl;
- }
- for( std::map< unsigned, int >::iterator it = bchildren.begin(); it != bchildren.end(); ++it ){
- Trace("ambqi-check-debug2") << " basic : " << it->first << " : " << it->second;
- if( it->second>=0 ){
- Assert( it->second<(int)m->d_rep_set.d_type_reps[n[it->first].getType()].size() );
- values[it->first] = m->d_rep_set.d_type_reps[n[it->first].getType()][it->second];
- }else{
- incomplete = true;
- }
- Trace("ambqi-check-debug2") << " ->> " << values[it->first] << std::endl;
- }
- Assert( vchildren.empty() );
- if( incomplete ){
- Trace("ajr-temp") << "Construct incomplete entry." << std::endl;
-
- //if a child is unknown, we must return unknown
- construct_entry( entry, entry_def, val_unk );
- }else{
- if( Trace.isOn("ambqi-check-debug2") ){
- for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << " "; }
- Trace("ambqi-check-debug2") << "Evaluate interpreted function entry ( ";
- for( unsigned i=0; i<values.size(); i++ ){
- Assert( !values[i].isNull() );
- Trace("ambqi-check-debug2") << values[i] << " ";
- }
- Trace("ambqi-check-debug2") << ")..." << std::endl;
- }
- //evaluate
- Node vv = NodeManager::currentNM()->mkNode( n.getKind(), values );
- vv = Rewriter::rewrite( vv );
- int v = m->getRepresentativeId( vv );
- construct_entry( entry, entry_def, v );
- }
- }
- }else{
- //take product of arguments
- TypeNode tn = m->getVariable( q, entry.size() ).getType();
- Assert( m->isValidType( tn ) );
- unsigned def = m->d_domain[tn];
- if( Trace.isOn("ambqi-check-debug2") ){
- for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << " "; }
- Trace("ambqi-check-debug2") << "Take product of arguments" << std::endl;
- }
- for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){
- Assert( it->second!=NULL );
- //process each child
- for( std::map< unsigned, AbsDef >::iterator itd = it->second->d_def.begin(); itd != it->second->d_def.end(); ++itd ){
- if( itd->first!=it->second->d_default && ( def & itd->first )!=0 ){
- def &= ~( itd->first );
- //process this value
- std::map< unsigned, AbsDef * > cchildren;
- for( std::map< unsigned, AbsDef * >::iterator it2 = children.begin(); it2 != children.end(); ++it2 ){
- Assert( it2->second!=NULL );
- std::map< unsigned, AbsDef >::iterator itdf = it2->second->d_def.find( itd->first );
- if( itdf!=it2->second->d_def.end() ){
- cchildren[it2->first] = &itdf->second;
- }else{
- Assert( it2->second->getDefault()!=NULL );
- cchildren[it2->first] = it2->second->getDefault();
- }
- }
- if( Trace.isOn("ambqi-check-debug2") ){
- for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << " "; }
- Trace("ambqi-check-debug2") << "...process : ";
- debugPrintUInt("ambqi-check-debug2", m->d_rep_set.d_type_reps[tn].size(), itd->first );
- Trace("ambqi-check-debug2") << " " << children.size() << " " << cchildren.size() << std::endl;
- }
- entry.push_back( itd->first );
- entry_def.push_back( def==0 );
- construct_compose( m, q, n, f, cchildren, bchildren, vchildren, entry, entry_def );
- entry_def.pop_back();
- entry.pop_back();
- if( def==0 ){
- break;
- }
- }
- }
- if( def==0 ){
- break;
- }
- }
- if( def!=0 ){
- if( Trace.isOn("ambqi-check-debug2") ){
- for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << " "; }
- Trace("ambqi-check-debug2") << "Make default argument" << std::endl;
- }
- std::map< unsigned, AbsDef * > cdchildren;
- for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){
- Assert( it->second->getDefault()!=NULL );
- cdchildren[it->first] = it->second->getDefault();
- }
- if( Trace.isOn("ambqi-check-debug2") ){
- for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << " "; }
- Trace("ambqi-check-debug2") << "...process default : ";
- debugPrintUInt("ambqi-check-debug2", m->d_rep_set.getNumRepresentatives( tn ), def );
- Trace("ambqi-check-debug2") << " " << children.size() << " " << cdchildren.size() << std::endl;
- }
- entry.push_back( def );
- entry_def.push_back( true );
- construct_compose( m, q, n, f, cdchildren, bchildren, vchildren, entry, entry_def );
- entry_def.pop_back();
- entry.pop_back();
- }
- }
-}
-
-bool AbsDef::construct( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f,
- std::map< unsigned, AbsDef * >& children,
- std::map< unsigned, int >& bchildren, std::map< unsigned, int >& vchildren,
- int varChCount ) {
- if( Trace.isOn("ambqi-check-debug3") ){
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- Trace("ambqi-check-debug3") << i << " : ";
- Trace("ambqi-check-debug3") << ((children.find( i )!=children.end()) ? "X" : ".");
- if( bchildren.find( i )!=bchildren.end() ){
- Trace("ambqi-check-debug3") << bchildren[i];
- }else{
- Trace("ambqi-check-debug3") << ".";
- }
- if( vchildren.find( i )!=vchildren.end() ){
- Trace("ambqi-check-debug3") << vchildren[i];
- }else{
- Trace("ambqi-check-debug3") << ".";
- }
- Trace("ambqi-check-debug3") << std::endl;
- }
- Trace("ambqi-check-debug3") << "varChCount : " << varChCount << std::endl;
- }
- if( varChCount==0 || f ){
- //short-circuit
- if( n.getKind()==AND || n.getKind()==OR ){
- for( std::map< unsigned, int >::iterator it = bchildren.begin(); it !=bchildren.end(); ++it ){
- if( ( it->second==0 && n.getKind()==AND ) ||
- ( it->second==1 && n.getKind()==OR ) ){
- construct_def_entry( m, q, q[0], it->second );
- return true;
- }
- }
- }
- Trace("ambqi-check-debug2") << "Construct compose..." << std::endl;
- std::vector< unsigned > entry;
- std::vector< bool > entry_def;
- if( f && varChCount>0 ){
- AbsDef unorm;
- unorm.construct_compose( m, q, n, f, children, bchildren, vchildren, entry, entry_def );
- //normalize
- std::vector< AbsDef* > defs;
- defs.push_back( &unorm );
- construct_normalize( m, q, defs );
- }else{
- construct_compose( m, q, n, f, children, bchildren, vchildren, entry, entry_def );
- }
- Assert( is_normalized() );
- //if( !is_normalized() ){
- // std::cout << "NON NORMALIZED DEFINITION" << std::endl;
- // exit( 10 );
- //}
- return true;
- }else if( varChCount==1 && n.getKind()==EQUAL ){
- Trace("ambqi-check-debug2") << "Expand variable child..." << std::endl;
- //expand the variable based on its finite domain
- AbsDef a;
- a.construct_var( m, q, vchildren.begin()->second, val_none );
- children[vchildren.begin()->first] = &a;
- vchildren.clear();
- std::vector< unsigned > entry;
- std::vector< bool > entry_def;
- Trace("ambqi-check-debug2") << "Construct compose with variable..." << std::endl;
- construct_compose( m, q, n, f, children, bchildren, vchildren, entry, entry_def );
- return true;
- }else if( varChCount==2 && n.getKind()==EQUAL ){
- Trace("ambqi-check-debug2") << "Construct variable equality..." << std::endl;
- //efficient expansion of the equality
- construct_var_eq( m, q, vchildren[0], vchildren[1], val_none, val_none );
- return true;
- }else{
- return false;
- }
-}
-
-void AbsDef::negate() {
- for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
- it->second.negate();
- }
- if( d_value==0 ){
- d_value = 1;
- }else if( d_value==1 ){
- d_value = 0;
- }
-}
-
-Node AbsDef::getFunctionValue( FirstOrderModelAbs * m, TNode op, std::vector< Node >& vars, unsigned depth ) {
- if( depth==vars.size() ){
- TypeNode tn = op.getType();
- if( tn.getNumChildren()>0 ){
- tn = tn[tn.getNumChildren() - 1];
- }
- if( d_value>=0 ){
- Assert( d_value<(int)m->d_rep_set.d_type_reps[tn].size() );
- if( tn.isBoolean() ){
- return NodeManager::currentNM()->mkConst( d_value==1 );
- }else{
- return m->d_rep_set.d_type_reps[tn][d_value];
- }
- }else{
- return Node::null();
- }
- }else{
- TypeNode tn = vars[depth].getType();
- Node curr;
- curr = d_def[d_default].getFunctionValue( m, op, vars, depth+1 );
- for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
- if( it->first!=d_default ){
- unsigned id = getId( it->first );
- Assert( id<m->d_rep_set.d_type_reps[tn].size() );
- TNode n = m->d_rep_set.d_type_reps[tn][id];
- Node fv = it->second.getFunctionValue( m, op, vars, depth+1 );
- if( !curr.isNull() && !fv.isNull() ){
- curr = NodeManager::currentNM()->mkNode( ITE, vars[depth].eqNode( n ), fv, curr );
- }else{
- curr = Node::null();
- }
- }
- }
- return curr;
- }
-}
-
-bool AbsDef::isSimple( unsigned n ) {
- return (n & (n - 1))==0;
-}
-
-unsigned AbsDef::getId( unsigned n, unsigned start, unsigned end ) {
- Assert( n!=0 );
- while( (n & ( 1 << start )) == 0 ){
- start++;
- if( start==end ){
- return start;
- }
- }
- return start;
-}
-
-Node AbsDef::evaluate( FirstOrderModelAbs * m, TypeNode retTyp, std::vector< Node >& args ) {
- std::vector< unsigned > iargs;
- for( unsigned i=0; i<args.size(); i++ ){
- unsigned v = 1 << m->getRepresentativeId( args[i] );
- iargs.push_back( v );
- }
- return evaluate( m, retTyp, iargs, 0 );
-}
-
-Node AbsDef::evaluate( FirstOrderModelAbs * m, TypeNode retTyp, std::vector< unsigned >& iargs, unsigned depth ) {
- if( d_value!=val_none ){
- if( d_value==val_unk ){
- return Node::null();
- }else{
- Assert( d_value>=0 && d_value<(int)m->d_rep_set.d_type_reps[retTyp].size() );
- return m->d_rep_set.d_type_reps[retTyp][d_value];
- }
- }else{
- std::map< unsigned, AbsDef >::iterator it = d_def.find( iargs[depth] );
- if( it==d_def.end() ){
- return d_def[d_default].evaluate( m, retTyp, iargs, depth+1 );
- }else{
- return it->second.evaluate( m, retTyp, iargs, depth+1 );
- }
- }
-}
-
-bool AbsDef::is_normalized() {
- for( std::map< unsigned, AbsDef >::iterator it1 = d_def.begin(); it1 != d_def.end(); ++it1 ){
- if( !it1->second.is_normalized() ){
- return false;
- }
- for( std::map< unsigned, AbsDef >::iterator it2 = d_def.begin(); it2 != d_def.end(); ++it2 ){
- if( it1->first!=it2->first && (( it1->first & it2->first )!=0) ){
- return false;
- }
- }
- }
- return true;
-}
-
-AbsMbqiBuilder::AbsMbqiBuilder( context::Context* c, QuantifiersEngine* qe ) :
-QModelBuilder( c, qe ){
- d_true = NodeManager::currentNM()->mkConst( true );
- d_false = NodeManager::currentNM()->mkConst( false );
-}
-
-
-//------------------------model construction----------------------------
-
-void AbsMbqiBuilder::processBuildModel(TheoryModel* m, bool fullModel) {
- Trace("ambqi-debug") << "process build model " << fullModel << std::endl;
- FirstOrderModel* f = (FirstOrderModel*)m;
- FirstOrderModelAbs* fm = f->asFirstOrderModelAbs();
- if( fullModel ){
- Trace("ambqi-model") << "Construct model representation..." << std::endl;
- //make function values
- for( std::map<Node, AbsDef * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) {
- if( it->first.getType().getNumChildren()>1 ){
- Trace("ambqi-model") << "Construct for " << it->first << "..." << std::endl;
- m->d_uf_models[ it->first ] = fm->getFunctionValue( it->first, "$x" );
- }
- }
- TheoryEngineModelBuilder::processBuildModel( m, fullModel );
- //mark that the model has been set
- fm->markModelSet();
- //debug the model
- debugModel( fm );
- }else{
- fm->initialize( d_considerAxioms );
- //process representatives
- fm->d_rep_id.clear();
- fm->d_domain.clear();
-
- //initialize boolean sort
- TypeNode b = d_true.getType();
- fm->d_rep_set.d_type_reps[b].clear();
- fm->d_rep_set.d_type_reps[b].push_back( d_false );
- fm->d_rep_set.d_type_reps[b].push_back( d_true );
- fm->d_rep_id[d_false] = 0;
- fm->d_rep_id[d_true] = 1;
-
- //initialize unintpreted sorts
- Trace("ambqi-model") << std::endl << "Making representatives..." << std::endl;
- for( std::map< TypeNode, std::vector< Node > >::iterator it = fm->d_rep_set.d_type_reps.begin();
- it != fm->d_rep_set.d_type_reps.end(); ++it ){
- if( it->first.isSort() ){
- Assert( !it->second.empty() );
- //set the domain
- fm->d_domain[it->first] = 0;
- Trace("ambqi-model") << "Representatives for " << it->first << " : " << std::endl;
- for( unsigned i=0; i<it->second.size(); i++ ){
- if( i<32 ){
- fm->d_domain[it->first] |= ( 1 << i );
- }
- Trace("ambqi-model") << i << " : " << it->second[i] << std::endl;
- fm->d_rep_id[it->second[i]] = i;
- }
- if( it->second.size()>=32 ){
- fm->d_domain.erase( it->first );
- }
- }
- }
-
- Trace("ambqi-model") << std::endl << "Making function definitions..." << std::endl;
- //construct the models for functions
- for( std::map<Node, AbsDef * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) {
- Node f = it->first;
- Trace("ambqi-model-debug") << "Building Model for " << f << std::endl;
- //reset the model
- it->second->clear();
- //get all (non-redundant) f-applications
- std::vector< TNode > fapps;
- Trace("ambqi-model-debug") << "Initial terms: " << std::endl;
- for( size_t i=0; i<fm->d_uf_terms[f].size(); i++ ){
- Node n = fm->d_uf_terms[f][i];
- if( !n.getAttribute(NoMatchAttribute()) ){
- Trace("ambqi-model-debug") << " " << n << " -> " << fm->getRepresentativeId( n ) << std::endl;
- fapps.push_back( n );
- }
- }
- if( fapps.empty() ){
- //choose arbitrary value
- Node mbt = d_qe->getTermDatabase()->getModelBasisOpTerm(f);
- Trace("ambqi-model-debug") << "Initial terms empty, add " << mbt << std::endl;
- fapps.push_back( mbt );
- }
- bool fValid = true;
- for( unsigned i=0; i<fapps[0].getNumChildren(); i++ ){
- if( fm->d_domain.find( fapps[0][i].getType() )==fm->d_domain.end() ){
- Trace("ambqi-model") << "Interpretation of " << f << " is not valid.";
- Trace("ambqi-model") << " (domain for " << fapps[0][i].getType() << " is too large)." << std::endl;
- fValid = false;
- break;
- }
- }
- fm->d_models_valid[f] = fValid;
- if( fValid ){
- //construct the ambqi model
- it->second->construct_func( fm, fapps );
- Trace("ambqi-model-debug") << "Interpretation of " << f << " : " << std::endl;
- it->second->debugPrint("ambqi-model-debug", fm, fapps[0] );
- Trace("ambqi-model-debug") << "Simplifying " << f << "..." << std::endl;
- it->second->simplify( fm, TNode::null(), fapps[0] );
- Trace("ambqi-model") << "(Simplified) interpretation of " << f << " : " << std::endl;
- it->second->debugPrint("ambqi-model", fm, fapps[0] );
-
-/*
- if( Debug.isOn("ambqi-model-debug") ){
- for( size_t i=0; i<fm->d_uf_terms[f].size(); i++ ){
- Node e = it->second->evaluate_n( fm, fm->d_uf_terms[f][i] );
- Debug("ambqi-model-debug") << fm->d_uf_terms[f][i] << " evaluates to " << e << std::endl;
- Assert( fm->areEqual( e, fm->d_uf_terms[f][i] ) );
- }
- }
-*/
- }
- }
- }
-}
-
-
-//--------------------model checking---------------------------------------
-
-//do exhaustive instantiation
-bool AbsMbqiBuilder::doExhaustiveInstantiation( FirstOrderModel * fm, Node q, int effort ) {
- Trace("ambqi-check") << "Exhaustive instantiation " << q << " " << effort << std::endl;
- if (effort==0) {
- FirstOrderModelAbs * fma = fm->asFirstOrderModelAbs();
- bool quantValid = true;
- for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
- if( !fma->isValidType( q[0][i].getType() ) ){
- quantValid = false;
- Trace("ambqi-inst") << "Interpretation of " << q << " is not valid because of type " << q[0][i].getType() << std::endl;
- break;
- }
- }
- if( quantValid ){
- Trace("ambqi-check") << "Compute interpretation..." << std::endl;
- AbsDef ad;
- doCheck( fma, q, ad, q[1] );
- //now process entries
- Trace("ambqi-inst-debug") << "...Current : " << d_addedLemmas << std::endl;
- Trace("ambqi-inst") << "Interpretation of " << q << " is : " << std::endl;
- ad.debugPrint( "ambqi-inst", fma, q[0] );
- Trace("ambqi-inst") << std::endl;
- Trace("ambqi-check") << "Add instantiations..." << std::endl;
- int lem = 0;
- quantValid = ad.addInstantiations( fma, d_qe, q, lem );
- Trace("ambqi-inst") << "...Added " << lem << " lemmas." << std::endl;
- if( lem>0 ){
- //if we were incomplete but added at least one lemma, we are ok
- quantValid = true;
- }
- d_addedLemmas += lem;
- Trace("ambqi-inst-debug") << "...Total : " << d_addedLemmas << std::endl;
- }
- return quantValid;
- }
- return true;
-}
-
-bool AbsMbqiBuilder::doCheck( FirstOrderModelAbs * m, TNode q, AbsDef & ad, TNode n ) {
- Assert( n.getKind()!=FORALL );
- if( n.getKind()==NOT && n[0].getKind()!=FORALL ){
- doCheck( m, q, ad, n[0] );
- ad.negate();
- return true;
- }else{
- std::map< unsigned, AbsDef > children;
- std::map< unsigned, int > bchildren;
- std::map< unsigned, int > vchildren;
- int varChCount = 0;
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- if( n[i].getKind()==FORALL ){
- bchildren[i] = AbsDef::val_unk;
- }else if( n[i].getKind() == BOUND_VARIABLE ){
- varChCount++;
- vchildren[i] = m->d_var_index[q][ m->getVariableId( q, n[i] ) ];
- //vchildren[i] = m->getVariableId( q, n[i] );
- }else if( m->hasTerm( n[i] ) ){
- bchildren[i] = m->getRepresentativeId( n[i] );
- }else{
- if( !doCheck( m, q, children[i], n[i] ) ){
- bchildren[i] = AbsDef::val_unk;
- children.erase( i );
- }
- }
- }
- //convert to pointers
- std::map< unsigned, AbsDef * > pchildren;
- for( std::map< unsigned, AbsDef >::iterator it = children.begin(); it != children.end(); ++it ){
- pchildren[it->first] = &it->second;
- }
- //construct the interpretation
- Trace("ambqi-check-debug") << "Compute Interpretation of " << n << " " << n.getKind() << std::endl;
- if( n.getKind() == APPLY_UF || n.getKind() == VARIABLE || n.getKind() == SKOLEM ){
- Node op;
- if( n.getKind() == APPLY_UF ){
- op = n.getOperator();
- }else{
- op = n;
- }
- //uninterpreted compose
- if( m->d_models_valid[op] ){
- ad.construct( m, q, n, m->d_models[op], pchildren, bchildren, vchildren, varChCount );
- }else{
- Trace("ambqi-check-debug") << "** Cannot produce interpretation for " << n << " (no function model)" << std::endl;
- return false;
- }
- }else if( !ad.construct( m, q, n, NULL, pchildren, bchildren, vchildren, varChCount ) ){
- Trace("ambqi-check-debug") << "** Cannot produce interpretation for " << n << " (variables are children of interpreted symbol)" << std::endl;
- return false;
- }
- Trace("ambqi-check-try") << "Interpretation for " << n << " is : " << std::endl;
- ad.debugPrint("ambqi-check-try", m, q[0] );
- ad.simplify( m, q, q[0] );
- Trace("ambqi-check-debug") << "(Simplified) Interpretation for " << n << " is : " << std::endl;
- ad.debugPrint("ambqi-check-debug", m, q[0] );
- Trace("ambqi-check-debug") << std::endl;
- return true;
- }
-}
+/********************* */ +/*! \file ambqi_builder.cpp + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: none + ** 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 abstract MBQI builder + **/ + + +#include "theory/quantifiers/ambqi_builder.h" +#include "theory/quantifiers/term_database.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 AbsDef::construct_func( FirstOrderModelAbs * m, std::vector< TNode >& fapps, unsigned depth ) { + d_def.clear(); + Assert( !fapps.empty() ); + if( depth==fapps[0].getNumChildren() ){ + //if( fapps.size()>1 ){ + // for( unsigned i=0; i<fapps.size(); i++ ){ + // std::cout << "...." << fapps[i] << " -> " << m->getRepresentativeId( fapps[i] ) << std::endl; + // } + //} + //get representative in model for this term + d_value = m->getRepresentativeId( fapps[0] ); + Assert( d_value!=val_none ); + }else{ + TypeNode tn = fapps[0][depth].getType(); + std::map< unsigned, std::vector< TNode > > fapp_child; + + //partition based on evaluations of fapps[1][depth]....fapps[n][depth] + for( unsigned i=0; i<fapps.size(); i++ ){ + unsigned r = m->getRepresentativeId( fapps[i][depth] ); + Assert( r < 32 ); + fapp_child[r].push_back( fapps[i] ); + } + + //do completion + std::map< unsigned, unsigned > fapp_child_index; + unsigned def = m->d_domain[ tn ]; + unsigned minSize = fapp_child.begin()->second.size(); + unsigned minSizeIndex = fapp_child.begin()->first; + for( std::map< unsigned, std::vector< TNode > >::iterator it = fapp_child.begin(); it != fapp_child.end(); ++it ){ + fapp_child_index[it->first] = ( 1 << it->first ); + def = def & ~( 1 << it->first ); + if( it->second.size()<minSize ){ + minSize = it->second.size(); + minSizeIndex = it->first; + } + } + fapp_child_index[minSizeIndex] |= def; + d_default = fapp_child_index[minSizeIndex]; + + //construct children + for( std::map< unsigned, std::vector< TNode > >::iterator it = fapp_child.begin(); it != fapp_child.end(); ++it ){ + Trace("abs-model-debug") << "Construct " << it->first << " : " << fapp_child_index[it->first] << " : "; + debugPrintUInt( "abs-model-debug", m->d_rep_set.d_type_reps[tn].size(), fapp_child_index[it->first] ); + Trace("abs-model-debug") << " : " << it->second.size() << " terms." << std::endl; + d_def[fapp_child_index[it->first]].construct_func( m, it->second, depth+1 ); + } + } +} + +void AbsDef::simplify( FirstOrderModelAbs * m, TNode q, TNode n, unsigned depth ) { + if( d_value==val_none && !d_def.empty() ){ + //process the default + std::map< unsigned, AbsDef >::iterator defd = d_def.find( d_default ); + Assert( defd!=d_def.end() ); + unsigned newDef = d_default; + std::vector< unsigned > to_erase; + defd->second.simplify( m, q, n, depth+1 ); + int defVal = defd->second.d_value; + bool isConstant = ( defVal!=val_none ); + //process each child + for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){ + if( it->first!=d_default ){ + it->second.simplify( m, q, n, depth+1 ); + if( it->second.d_value==defVal && it->second.d_value!=val_none ){ + newDef = newDef | it->first; + to_erase.push_back( it->first ); + }else{ + isConstant = false; + } + } + } + if( !to_erase.empty() ){ + //erase old default + int defVal = defd->second.d_value; + d_def.erase( d_default ); + //set new default + d_default = newDef; + d_def[d_default].construct_def_entry( m, q, n, defVal, depth+1 ); + //erase redundant entries + for( unsigned i=0; i<to_erase.size(); i++ ){ + d_def.erase( to_erase[i] ); + } + } + //if constant, propagate the value upwards + if( isConstant ){ + d_value = defVal; + }else{ + d_value = val_none; + } + } +} + +void AbsDef::debugPrintUInt( const char * c, unsigned dSize, unsigned u ) const{ + for( unsigned i=0; i<dSize; i++ ){ + Trace(c) << ( ( u & ( 1 << i ) )!=0 ? "1" : "0"); + } + //Trace(c) << "("; + //for( unsigned i=0; i<32; i++ ){ + // Trace(c) << ( ( u & ( 1 << i ) )!=0 ? "1" : "0"); + //} + //Trace(c) << ")"; +} + +void AbsDef::debugPrint( const char * c, FirstOrderModelAbs * m, TNode f, unsigned depth ) const{ + if( Trace.isOn(c) ){ + if( depth==f.getNumChildren() ){ + for( unsigned i=0; i<depth; i++ ){ Trace(c) << " ";} + Trace(c) << "V[" << d_value << "]" << std::endl; + }else{ + TypeNode tn = f[depth].getType(); + unsigned dSize = m->d_rep_set.getNumRepresentatives( tn ); + Assert( dSize<32 ); + for( std::map< unsigned, AbsDef >::const_iterator it = d_def.begin(); it != d_def.end(); ++it ){ + for( unsigned i=0; i<depth; i++ ){ Trace(c) << " ";} + debugPrintUInt( c, dSize, it->first ); + if( it->first==d_default ){ + Trace(c) << "*"; + } + if( it->second.d_value!=val_none ){ + Trace(c) << " -> V[" << it->second.d_value << "]"; + } + Trace(c) << std::endl; + it->second.debugPrint( c, m, f, depth+1 ); + } + } + } +} + +bool AbsDef::addInstantiations( FirstOrderModelAbs * m, QuantifiersEngine * qe, TNode q, std::vector< Node >& terms, int& inst, unsigned depth ) { + if( inst==0 || !options::fmfOneInstPerRound() ){ + if( d_value==1 ){ + //instantiations are all true : ignore this + return true; + }else{ + if( depth==q[0].getNumChildren() ){ + if( qe->addInstantiation( q, terms ) ){ + Trace("ambqi-inst-debug") << "-> Added instantiation." << std::endl; + inst++; + return true; + }else{ + Trace("ambqi-inst-debug") << "-> Failed to add instantiation." << std::endl; + //we are incomplete + return false; + } + }else{ + bool osuccess = true; + TypeNode tn = m->getVariable( q, depth ).getType(); + for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){ + //get witness term + unsigned index = 0; + bool success; + do { + success = false; + index = getId( it->first, index ); + if( index<32 ){ + Assert( index<m->d_rep_set.d_type_reps[tn].size() ); + terms[m->d_var_order[q][depth]] = m->d_rep_set.d_type_reps[tn][index]; + //terms[depth] = m->d_rep_set.d_type_reps[tn][index]; + if( !it->second.addInstantiations( m, qe, q, terms, inst, depth+1 ) && inst==0 ){ + //if we are incomplete, and have not yet added an instantiation, keep trying + index++; + Trace("ambqi-inst-debug") << "At depth " << depth << ", failed branch, no instantiations and incomplete, increment index : " << index << std::endl; + }else{ + success = true; + } + } + }while( !success && index<32 ); + //mark if we are incomplete + osuccess = osuccess && success; + } + return osuccess; + } + } + }else{ + return true; + } +} + +void AbsDef::construct_entry( std::vector< unsigned >& entry, std::vector< bool >& entry_def, int v, unsigned depth ) { + if( depth==entry.size() ){ + d_value = v; + }else{ + d_def[entry[depth]].construct_entry( entry, entry_def, v, depth+1 ); + if( entry_def[depth] ){ + d_default = entry[depth]; + } + } +} + +void AbsDef::get_defs( unsigned u, std::vector< AbsDef * >& defs ) { + for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){ + if( ( u & it->first )!=0 ){ + Assert( (u & it->first)==u ); + defs.push_back( &it->second ); + } + } +} + +void AbsDef::construct_normalize( FirstOrderModelAbs * m, TNode q, std::vector< AbsDef * >& defs, unsigned depth ) { + if( depth==q[0].getNumChildren() ){ + Assert( defs.size()==1 ); + d_value = defs[0]->d_value; + }else{ + TypeNode tn = m->getVariable( q, depth ).getType(); + unsigned def = m->d_domain[tn]; + for( unsigned i=0; i<defs.size(); i++ ){ + //process each simple child + for( std::map< unsigned, AbsDef >::iterator itd = defs[i]->d_def.begin(); itd != defs[i]->d_def.end(); ++itd ){ + if( isSimple( itd->first ) && ( def & itd->first )!=0 ){ + def &= ~( itd->first ); + //process this value + std::vector< AbsDef * > cdefs; + for( unsigned j=0; j<defs.size(); j++ ){ + defs[j]->get_defs( itd->first, cdefs ); + } + d_def[itd->first].construct_normalize( m, q, cdefs, depth+1 ); + if( def==0 ){ + d_default = itd->first; + break; + } + } + } + if( def==0 ){ + break; + } + } + if( def!=0 ){ + d_default = def; + //process the default + std::vector< AbsDef * > cdefs; + for( unsigned j=0; j<defs.size(); j++ ){ + defs[j]->get_defs( d_default, cdefs ); + } + d_def[d_default].construct_normalize( m, q, cdefs, depth+1 ); + } + } +} + +void AbsDef::construct_def_entry( FirstOrderModelAbs * m, TNode q, TNode n, int v, unsigned depth ) { + d_value = v; + if( depth<n.getNumChildren() ){ + TypeNode tn = q.isNull() ? n[depth].getType() : m->getVariable( q, depth ).getType(); + unsigned dom = m->d_domain[tn] ; + d_def[dom].construct_def_entry( m, q, n, v, depth+1 ); + d_default = dom; + } +} + +void AbsDef::apply_ucompose( FirstOrderModelAbs * m, TNode q, + std::vector< unsigned >& entry, std::vector< bool >& entry_def, + std::vector< int >& terms, std::map< unsigned, int >& vchildren, + AbsDef * a, unsigned depth ) { + if( depth==terms.size() ){ + if( Trace.isOn("ambqi-check-debug2") ){ + Trace("ambqi-check-debug2") << "Add entry ( "; + for( unsigned i=0; i<entry.size(); i++ ){ + unsigned dSize = m->d_rep_set.d_type_reps[m->getVariable( q, i ).getType()].size(); + debugPrintUInt( "ambqi-check-debug2", dSize, entry[i] ); + Trace("ambqi-check-debug2") << " "; + } + Trace("ambqi-check-debug2") << ")" << std::endl; + } + a->construct_entry( entry, entry_def, d_value ); + }else{ + unsigned id; + if( terms[depth]==val_none ){ + //a variable + std::map< unsigned, int >::iterator itv = vchildren.find( depth ); + Assert( itv!=vchildren.end() ); + unsigned prev_v = entry[itv->second]; + bool prev_vd = entry_def[itv->second]; + for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){ + entry[itv->second] = it->first & prev_v; + entry_def[itv->second] = ( it->first==d_default ) && prev_vd; + if( entry[itv->second]!=0 ){ + it->second.apply_ucompose( m, q, entry, entry_def, terms, vchildren, a, depth+1 ); + } + } + entry[itv->second] = prev_v; + entry_def[itv->second] = prev_vd; + }else{ + id = (unsigned)terms[depth]; + Assert( id<32 ); + unsigned fid = 1 << id; + std::map< unsigned, AbsDef >::iterator it = d_def.find( fid ); + if( it!=d_def.end() ){ + it->second.apply_ucompose( m, q, entry, entry_def, terms, vchildren, a, depth+1 ); + }else{ + d_def[d_default].apply_ucompose( m, q, entry, entry_def, terms, vchildren, a, depth+1 ); + } + } + } +} + +void AbsDef::construct_var_eq( FirstOrderModelAbs * m, TNode q, unsigned v1, unsigned v2, int curr, int currv, unsigned depth ) { + if( depth==q[0].getNumChildren() ){ + Assert( currv!=val_none ); + d_value = currv; + }else{ + TypeNode tn = m->getVariable( q, depth ).getType(); + unsigned dom = m->d_domain[tn]; + int vindex = depth==v1 ? 0 : ( depth==v2 ? 1 : val_none ); + if( vindex==val_none ){ + d_def[dom].construct_var_eq( m, q, v1, v2, curr, currv, depth+1 ); + d_default = dom; + }else{ + Assert( currv==val_none ); + if( curr==val_none ){ + unsigned numReps = m->d_rep_set.getNumRepresentatives( tn ); + Assert( numReps < 32 ); + for( unsigned i=0; i<numReps; i++ ){ + curr = 1 << i; + d_def[curr].construct_var_eq( m, q, v1, v2, curr, currv, depth+1 ); + } + d_default = curr; + }else{ + d_def[curr].construct_var_eq( m, q, v1, v2, curr, 1, depth+1 ); + dom = dom & ~curr; + d_def[dom].construct_var_eq( m, q, v1, v2, curr, 0, depth+1 ); + d_default = dom; + } + } + } +} + +void AbsDef::construct_var( FirstOrderModelAbs * m, TNode q, unsigned v, int currv, unsigned depth ) { + if( depth==q[0].getNumChildren() ){ + Assert( currv!=val_none ); + d_value = currv; + }else{ + TypeNode tn = m->getVariable( q, depth ).getType(); + if( v==depth ){ + unsigned numReps = m->d_rep_set.d_type_reps[tn].size(); + Assert( numReps>0 && numReps < 32 ); + for( unsigned i=0; i<numReps; i++ ){ + d_def[ 1 << i ].construct_var( m, q, v, i, depth+1 ); + } + d_default = 1 << (numReps - 1); + }else{ + unsigned dom = m->d_domain[tn]; + d_def[dom].construct_var( m, q, v, currv, depth+1 ); + d_default = dom; + } + } +} + +void AbsDef::construct_compose( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f, + std::map< unsigned, AbsDef * >& children, + std::map< unsigned, int >& bchildren, std::map< unsigned, int >& vchildren, + std::vector< unsigned >& entry, std::vector< bool >& entry_def ) { + if( n.getKind()==OR || n.getKind()==AND ){ + // short circuiting + for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){ + if( ( it->second->d_value==0 && n.getKind()==AND ) || + ( it->second->d_value==1 && n.getKind()==OR ) ){ + //std::cout << "Short circuit " << it->second->d_value << " " << entry.size() << "/" << q[0].getNumChildren() << std::endl; + unsigned count = q[0].getNumChildren() - entry.size(); + for( unsigned i=0; i<count; i++ ){ + entry.push_back( m->d_domain[m->getVariable( q, entry.size() ).getType()] ); + entry_def.push_back( true ); + } + construct_entry( entry, entry_def, it->second->d_value ); + for( unsigned i=0; i<count; i++ ){ + entry.pop_back(); + entry_def.pop_back(); + } + return; + } + } + } + if( entry.size()==q[0].getNumChildren() ){ + if( f ){ + if( Trace.isOn("ambqi-check-debug2") ){ + for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << " "; } + Trace("ambqi-check-debug2") << "Evaluate uninterpreted function entry..." << std::endl; + } + //we are composing with an uninterpreted function + std::vector< int > values; + values.resize( n.getNumChildren(), val_none ); + for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){ + values[it->first] = it->second->d_value; + } + for( std::map< unsigned, int >::iterator it = bchildren.begin(); it != bchildren.end(); ++it ){ + values[it->first] = it->second; + } + //look up value(s) + f->apply_ucompose( m, q, entry, entry_def, values, vchildren, this ); + }else{ + bool incomplete = false; + //we are composing with an interpreted function + std::vector< TNode > values; + values.resize( n.getNumChildren(), TNode::null() ); + for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){ + Trace("ambqi-check-debug2") << "composite : " << it->first << " : " << it->second->d_value; + if( it->second->d_value>=0 ){ + if( it->second->d_value>=(int)m->d_rep_set.d_type_reps[n[it->first].getType()].size() ){ + std::cout << it->second->d_value << " " << n[it->first] << " " << n[it->first].getType() << " " << m->d_rep_set.d_type_reps[n[it->first].getType()].size() << std::endl; + } + Assert( it->second->d_value<(int)m->d_rep_set.d_type_reps[n[it->first].getType()].size() ); + values[it->first] = m->d_rep_set.d_type_reps[n[it->first].getType()][it->second->d_value]; + }else{ + incomplete = true; + } + Trace("ambqi-check-debug2") << " ->> " << values[it->first] << std::endl; + } + for( std::map< unsigned, int >::iterator it = bchildren.begin(); it != bchildren.end(); ++it ){ + Trace("ambqi-check-debug2") << " basic : " << it->first << " : " << it->second; + if( it->second>=0 ){ + Assert( it->second<(int)m->d_rep_set.d_type_reps[n[it->first].getType()].size() ); + values[it->first] = m->d_rep_set.d_type_reps[n[it->first].getType()][it->second]; + }else{ + incomplete = true; + } + Trace("ambqi-check-debug2") << " ->> " << values[it->first] << std::endl; + } + Assert( vchildren.empty() ); + if( incomplete ){ + Trace("ajr-temp") << "Construct incomplete entry." << std::endl; + + //if a child is unknown, we must return unknown + construct_entry( entry, entry_def, val_unk ); + }else{ + if( Trace.isOn("ambqi-check-debug2") ){ + for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << " "; } + Trace("ambqi-check-debug2") << "Evaluate interpreted function entry ( "; + for( unsigned i=0; i<values.size(); i++ ){ + Assert( !values[i].isNull() ); + Trace("ambqi-check-debug2") << values[i] << " "; + } + Trace("ambqi-check-debug2") << ")..." << std::endl; + } + //evaluate + Node vv = NodeManager::currentNM()->mkNode( n.getKind(), values ); + vv = Rewriter::rewrite( vv ); + int v = m->getRepresentativeId( vv ); + construct_entry( entry, entry_def, v ); + } + } + }else{ + //take product of arguments + TypeNode tn = m->getVariable( q, entry.size() ).getType(); + Assert( m->isValidType( tn ) ); + unsigned def = m->d_domain[tn]; + if( Trace.isOn("ambqi-check-debug2") ){ + for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << " "; } + Trace("ambqi-check-debug2") << "Take product of arguments" << std::endl; + } + for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){ + Assert( it->second!=NULL ); + //process each child + for( std::map< unsigned, AbsDef >::iterator itd = it->second->d_def.begin(); itd != it->second->d_def.end(); ++itd ){ + if( itd->first!=it->second->d_default && ( def & itd->first )!=0 ){ + def &= ~( itd->first ); + //process this value + std::map< unsigned, AbsDef * > cchildren; + for( std::map< unsigned, AbsDef * >::iterator it2 = children.begin(); it2 != children.end(); ++it2 ){ + Assert( it2->second!=NULL ); + std::map< unsigned, AbsDef >::iterator itdf = it2->second->d_def.find( itd->first ); + if( itdf!=it2->second->d_def.end() ){ + cchildren[it2->first] = &itdf->second; + }else{ + Assert( it2->second->getDefault()!=NULL ); + cchildren[it2->first] = it2->second->getDefault(); + } + } + if( Trace.isOn("ambqi-check-debug2") ){ + for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << " "; } + Trace("ambqi-check-debug2") << "...process : "; + debugPrintUInt("ambqi-check-debug2", m->d_rep_set.d_type_reps[tn].size(), itd->first ); + Trace("ambqi-check-debug2") << " " << children.size() << " " << cchildren.size() << std::endl; + } + entry.push_back( itd->first ); + entry_def.push_back( def==0 ); + construct_compose( m, q, n, f, cchildren, bchildren, vchildren, entry, entry_def ); + entry_def.pop_back(); + entry.pop_back(); + if( def==0 ){ + break; + } + } + } + if( def==0 ){ + break; + } + } + if( def!=0 ){ + if( Trace.isOn("ambqi-check-debug2") ){ + for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << " "; } + Trace("ambqi-check-debug2") << "Make default argument" << std::endl; + } + std::map< unsigned, AbsDef * > cdchildren; + for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){ + Assert( it->second->getDefault()!=NULL ); + cdchildren[it->first] = it->second->getDefault(); + } + if( Trace.isOn("ambqi-check-debug2") ){ + for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << " "; } + Trace("ambqi-check-debug2") << "...process default : "; + debugPrintUInt("ambqi-check-debug2", m->d_rep_set.getNumRepresentatives( tn ), def ); + Trace("ambqi-check-debug2") << " " << children.size() << " " << cdchildren.size() << std::endl; + } + entry.push_back( def ); + entry_def.push_back( true ); + construct_compose( m, q, n, f, cdchildren, bchildren, vchildren, entry, entry_def ); + entry_def.pop_back(); + entry.pop_back(); + } + } +} + +bool AbsDef::construct( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f, + std::map< unsigned, AbsDef * >& children, + std::map< unsigned, int >& bchildren, std::map< unsigned, int >& vchildren, + int varChCount ) { + if( Trace.isOn("ambqi-check-debug3") ){ + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + Trace("ambqi-check-debug3") << i << " : "; + Trace("ambqi-check-debug3") << ((children.find( i )!=children.end()) ? "X" : "."); + if( bchildren.find( i )!=bchildren.end() ){ + Trace("ambqi-check-debug3") << bchildren[i]; + }else{ + Trace("ambqi-check-debug3") << "."; + } + if( vchildren.find( i )!=vchildren.end() ){ + Trace("ambqi-check-debug3") << vchildren[i]; + }else{ + Trace("ambqi-check-debug3") << "."; + } + Trace("ambqi-check-debug3") << std::endl; + } + Trace("ambqi-check-debug3") << "varChCount : " << varChCount << std::endl; + } + if( varChCount==0 || f ){ + //short-circuit + if( n.getKind()==AND || n.getKind()==OR ){ + for( std::map< unsigned, int >::iterator it = bchildren.begin(); it !=bchildren.end(); ++it ){ + if( ( it->second==0 && n.getKind()==AND ) || + ( it->second==1 && n.getKind()==OR ) ){ + construct_def_entry( m, q, q[0], it->second ); + return true; + } + } + } + Trace("ambqi-check-debug2") << "Construct compose..." << std::endl; + std::vector< unsigned > entry; + std::vector< bool > entry_def; + if( f && varChCount>0 ){ + AbsDef unorm; + unorm.construct_compose( m, q, n, f, children, bchildren, vchildren, entry, entry_def ); + //normalize + std::vector< AbsDef* > defs; + defs.push_back( &unorm ); + construct_normalize( m, q, defs ); + }else{ + construct_compose( m, q, n, f, children, bchildren, vchildren, entry, entry_def ); + } + Assert( is_normalized() ); + //if( !is_normalized() ){ + // std::cout << "NON NORMALIZED DEFINITION" << std::endl; + // exit( 10 ); + //} + return true; + }else if( varChCount==1 && n.getKind()==EQUAL ){ + Trace("ambqi-check-debug2") << "Expand variable child..." << std::endl; + //expand the variable based on its finite domain + AbsDef a; + a.construct_var( m, q, vchildren.begin()->second, val_none ); + children[vchildren.begin()->first] = &a; + vchildren.clear(); + std::vector< unsigned > entry; + std::vector< bool > entry_def; + Trace("ambqi-check-debug2") << "Construct compose with variable..." << std::endl; + construct_compose( m, q, n, f, children, bchildren, vchildren, entry, entry_def ); + return true; + }else if( varChCount==2 && n.getKind()==EQUAL ){ + Trace("ambqi-check-debug2") << "Construct variable equality..." << std::endl; + //efficient expansion of the equality + construct_var_eq( m, q, vchildren[0], vchildren[1], val_none, val_none ); + return true; + }else{ + return false; + } +} + +void AbsDef::negate() { + for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){ + it->second.negate(); + } + if( d_value==0 ){ + d_value = 1; + }else if( d_value==1 ){ + d_value = 0; + } +} + +Node AbsDef::getFunctionValue( FirstOrderModelAbs * m, TNode op, std::vector< Node >& vars, unsigned depth ) { + if( depth==vars.size() ){ + TypeNode tn = op.getType(); + if( tn.getNumChildren()>0 ){ + tn = tn[tn.getNumChildren() - 1]; + } + if( d_value>=0 ){ + Assert( d_value<(int)m->d_rep_set.d_type_reps[tn].size() ); + if( tn.isBoolean() ){ + return NodeManager::currentNM()->mkConst( d_value==1 ); + }else{ + return m->d_rep_set.d_type_reps[tn][d_value]; + } + }else{ + return Node::null(); + } + }else{ + TypeNode tn = vars[depth].getType(); + Node curr; + curr = d_def[d_default].getFunctionValue( m, op, vars, depth+1 ); + for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){ + if( it->first!=d_default ){ + unsigned id = getId( it->first ); + Assert( id<m->d_rep_set.d_type_reps[tn].size() ); + TNode n = m->d_rep_set.d_type_reps[tn][id]; + Node fv = it->second.getFunctionValue( m, op, vars, depth+1 ); + if( !curr.isNull() && !fv.isNull() ){ + curr = NodeManager::currentNM()->mkNode( ITE, vars[depth].eqNode( n ), fv, curr ); + }else{ + curr = Node::null(); + } + } + } + return curr; + } +} + +bool AbsDef::isSimple( unsigned n ) { + return (n & (n - 1))==0; +} + +unsigned AbsDef::getId( unsigned n, unsigned start, unsigned end ) { + Assert( n!=0 ); + while( (n & ( 1 << start )) == 0 ){ + start++; + if( start==end ){ + return start; + } + } + return start; +} + +Node AbsDef::evaluate( FirstOrderModelAbs * m, TypeNode retTyp, std::vector< Node >& args ) { + std::vector< unsigned > iargs; + for( unsigned i=0; i<args.size(); i++ ){ + unsigned v = 1 << m->getRepresentativeId( args[i] ); + iargs.push_back( v ); + } + return evaluate( m, retTyp, iargs, 0 ); +} + +Node AbsDef::evaluate( FirstOrderModelAbs * m, TypeNode retTyp, std::vector< unsigned >& iargs, unsigned depth ) { + if( d_value!=val_none ){ + if( d_value==val_unk ){ + return Node::null(); + }else{ + Assert( d_value>=0 && d_value<(int)m->d_rep_set.d_type_reps[retTyp].size() ); + return m->d_rep_set.d_type_reps[retTyp][d_value]; + } + }else{ + std::map< unsigned, AbsDef >::iterator it = d_def.find( iargs[depth] ); + if( it==d_def.end() ){ + return d_def[d_default].evaluate( m, retTyp, iargs, depth+1 ); + }else{ + return it->second.evaluate( m, retTyp, iargs, depth+1 ); + } + } +} + +bool AbsDef::is_normalized() { + for( std::map< unsigned, AbsDef >::iterator it1 = d_def.begin(); it1 != d_def.end(); ++it1 ){ + if( !it1->second.is_normalized() ){ + return false; + } + for( std::map< unsigned, AbsDef >::iterator it2 = d_def.begin(); it2 != d_def.end(); ++it2 ){ + if( it1->first!=it2->first && (( it1->first & it2->first )!=0) ){ + return false; + } + } + } + return true; +} + +AbsMbqiBuilder::AbsMbqiBuilder( context::Context* c, QuantifiersEngine* qe ) : +QModelBuilder( c, qe ){ + d_true = NodeManager::currentNM()->mkConst( true ); + d_false = NodeManager::currentNM()->mkConst( false ); +} + + +//------------------------model construction---------------------------- + +void AbsMbqiBuilder::processBuildModel(TheoryModel* m, bool fullModel) { + Trace("ambqi-debug") << "process build model " << fullModel << std::endl; + FirstOrderModel* f = (FirstOrderModel*)m; + FirstOrderModelAbs* fm = f->asFirstOrderModelAbs(); + if( fullModel ){ + Trace("ambqi-model") << "Construct model representation..." << std::endl; + //make function values + for( std::map<Node, AbsDef * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) { + if( it->first.getType().getNumChildren()>1 ){ + Trace("ambqi-model") << "Construct for " << it->first << "..." << std::endl; + m->d_uf_models[ it->first ] = fm->getFunctionValue( it->first, "$x" ); + } + } + TheoryEngineModelBuilder::processBuildModel( m, fullModel ); + //mark that the model has been set + fm->markModelSet(); + //debug the model + debugModel( fm ); + }else{ + fm->initialize( d_considerAxioms ); + //process representatives + fm->d_rep_id.clear(); + fm->d_domain.clear(); + + //initialize boolean sort + TypeNode b = d_true.getType(); + fm->d_rep_set.d_type_reps[b].clear(); + fm->d_rep_set.d_type_reps[b].push_back( d_false ); + fm->d_rep_set.d_type_reps[b].push_back( d_true ); + fm->d_rep_id[d_false] = 0; + fm->d_rep_id[d_true] = 1; + + //initialize unintpreted sorts + Trace("ambqi-model") << std::endl << "Making representatives..." << std::endl; + for( std::map< TypeNode, std::vector< Node > >::iterator it = fm->d_rep_set.d_type_reps.begin(); + it != fm->d_rep_set.d_type_reps.end(); ++it ){ + if( it->first.isSort() ){ + Assert( !it->second.empty() ); + //set the domain + fm->d_domain[it->first] = 0; + Trace("ambqi-model") << "Representatives for " << it->first << " : " << std::endl; + for( unsigned i=0; i<it->second.size(); i++ ){ + if( i<32 ){ + fm->d_domain[it->first] |= ( 1 << i ); + } + Trace("ambqi-model") << i << " : " << it->second[i] << std::endl; + fm->d_rep_id[it->second[i]] = i; + } + if( it->second.size()>=32 ){ + fm->d_domain.erase( it->first ); + } + } + } + + Trace("ambqi-model") << std::endl << "Making function definitions..." << std::endl; + //construct the models for functions + for( std::map<Node, AbsDef * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) { + Node f = it->first; + Trace("ambqi-model-debug") << "Building Model for " << f << std::endl; + //reset the model + it->second->clear(); + //get all (non-redundant) f-applications + std::vector< TNode > fapps; + Trace("ambqi-model-debug") << "Initial terms: " << std::endl; + for( size_t i=0; i<fm->d_uf_terms[f].size(); i++ ){ + Node n = fm->d_uf_terms[f][i]; + if( !n.getAttribute(NoMatchAttribute()) ){ + Trace("ambqi-model-debug") << " " << n << " -> " << fm->getRepresentativeId( n ) << std::endl; + fapps.push_back( n ); + } + } + if( fapps.empty() ){ + //choose arbitrary value + Node mbt = d_qe->getTermDatabase()->getModelBasisOpTerm(f); + Trace("ambqi-model-debug") << "Initial terms empty, add " << mbt << std::endl; + fapps.push_back( mbt ); + } + bool fValid = true; + for( unsigned i=0; i<fapps[0].getNumChildren(); i++ ){ + if( fm->d_domain.find( fapps[0][i].getType() )==fm->d_domain.end() ){ + Trace("ambqi-model") << "Interpretation of " << f << " is not valid."; + Trace("ambqi-model") << " (domain for " << fapps[0][i].getType() << " is too large)." << std::endl; + fValid = false; + break; + } + } + fm->d_models_valid[f] = fValid; + if( fValid ){ + //construct the ambqi model + it->second->construct_func( fm, fapps ); + Trace("ambqi-model-debug") << "Interpretation of " << f << " : " << std::endl; + it->second->debugPrint("ambqi-model-debug", fm, fapps[0] ); + Trace("ambqi-model-debug") << "Simplifying " << f << "..." << std::endl; + it->second->simplify( fm, TNode::null(), fapps[0] ); + Trace("ambqi-model") << "(Simplified) interpretation of " << f << " : " << std::endl; + it->second->debugPrint("ambqi-model", fm, fapps[0] ); + +/* + if( Debug.isOn("ambqi-model-debug") ){ + for( size_t i=0; i<fm->d_uf_terms[f].size(); i++ ){ + Node e = it->second->evaluate_n( fm, fm->d_uf_terms[f][i] ); + Debug("ambqi-model-debug") << fm->d_uf_terms[f][i] << " evaluates to " << e << std::endl; + Assert( fm->areEqual( e, fm->d_uf_terms[f][i] ) ); + } + } +*/ + } + } + } +} + + +//--------------------model checking--------------------------------------- + +//do exhaustive instantiation +bool AbsMbqiBuilder::doExhaustiveInstantiation( FirstOrderModel * fm, Node q, int effort ) { + Trace("ambqi-check") << "Exhaustive instantiation " << q << " " << effort << std::endl; + if (effort==0) { + FirstOrderModelAbs * fma = fm->asFirstOrderModelAbs(); + bool quantValid = true; + for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ + if( !fma->isValidType( q[0][i].getType() ) ){ + quantValid = false; + Trace("ambqi-inst") << "Interpretation of " << q << " is not valid because of type " << q[0][i].getType() << std::endl; + break; + } + } + if( quantValid ){ + Trace("ambqi-check") << "Compute interpretation..." << std::endl; + AbsDef ad; + doCheck( fma, q, ad, q[1] ); + //now process entries + Trace("ambqi-inst-debug") << "...Current : " << d_addedLemmas << std::endl; + Trace("ambqi-inst") << "Interpretation of " << q << " is : " << std::endl; + ad.debugPrint( "ambqi-inst", fma, q[0] ); + Trace("ambqi-inst") << std::endl; + Trace("ambqi-check") << "Add instantiations..." << std::endl; + int lem = 0; + quantValid = ad.addInstantiations( fma, d_qe, q, lem ); + Trace("ambqi-inst") << "...Added " << lem << " lemmas." << std::endl; + if( lem>0 ){ + //if we were incomplete but added at least one lemma, we are ok + quantValid = true; + } + d_addedLemmas += lem; + Trace("ambqi-inst-debug") << "...Total : " << d_addedLemmas << std::endl; + } + return quantValid; + } + return true; +} + +bool AbsMbqiBuilder::doCheck( FirstOrderModelAbs * m, TNode q, AbsDef & ad, TNode n ) { + Assert( n.getKind()!=FORALL ); + if( n.getKind()==NOT && n[0].getKind()!=FORALL ){ + doCheck( m, q, ad, n[0] ); + ad.negate(); + return true; + }else{ + std::map< unsigned, AbsDef > children; + std::map< unsigned, int > bchildren; + std::map< unsigned, int > vchildren; + int varChCount = 0; + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + if( n[i].getKind()==FORALL ){ + bchildren[i] = AbsDef::val_unk; + }else if( n[i].getKind() == BOUND_VARIABLE ){ + varChCount++; + vchildren[i] = m->d_var_index[q][ m->getVariableId( q, n[i] ) ]; + //vchildren[i] = m->getVariableId( q, n[i] ); + }else if( m->hasTerm( n[i] ) ){ + bchildren[i] = m->getRepresentativeId( n[i] ); + }else{ + if( !doCheck( m, q, children[i], n[i] ) ){ + bchildren[i] = AbsDef::val_unk; + children.erase( i ); + } + } + } + //convert to pointers + std::map< unsigned, AbsDef * > pchildren; + for( std::map< unsigned, AbsDef >::iterator it = children.begin(); it != children.end(); ++it ){ + pchildren[it->first] = &it->second; + } + //construct the interpretation + Trace("ambqi-check-debug") << "Compute Interpretation of " << n << " " << n.getKind() << std::endl; + if( n.getKind() == APPLY_UF || n.getKind() == VARIABLE || n.getKind() == SKOLEM ){ + Node op; + if( n.getKind() == APPLY_UF ){ + op = n.getOperator(); + }else{ + op = n; + } + //uninterpreted compose + if( m->d_models_valid[op] ){ + ad.construct( m, q, n, m->d_models[op], pchildren, bchildren, vchildren, varChCount ); + }else{ + Trace("ambqi-check-debug") << "** Cannot produce interpretation for " << n << " (no function model)" << std::endl; + return false; + } + }else if( !ad.construct( m, q, n, NULL, pchildren, bchildren, vchildren, varChCount ) ){ + Trace("ambqi-check-debug") << "** Cannot produce interpretation for " << n << " (variables are children of interpreted symbol)" << std::endl; + return false; + } + Trace("ambqi-check-try") << "Interpretation for " << n << " is : " << std::endl; + ad.debugPrint("ambqi-check-try", m, q[0] ); + ad.simplify( m, q, q[0] ); + Trace("ambqi-check-debug") << "(Simplified) Interpretation for " << n << " is : " << std::endl; + ad.debugPrint("ambqi-check-debug", m, q[0] ); + Trace("ambqi-check-debug") << std::endl; + return true; + } +} diff --git a/src/theory/quantifiers/ambqi_builder.h b/src/theory/quantifiers/ambqi_builder.h index 349073cb4..d586d9c8f 100755 --- a/src/theory/quantifiers/ambqi_builder.h +++ b/src/theory/quantifiers/ambqi_builder.h @@ -1,102 +1,102 @@ -/********************* */
-/*! \file ambqi_builder.h
- ** \verbatim
- ** Original author: Andrew Reynolds
- ** Major contributors: none
- ** 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 Abstract MBQI model builder class
- **/
-
-#include "cvc4_private.h"
-
-#ifndef ABSTRACT_MBQI_BUILDER
-#define ABSTRACT_MBQI_BUILDER
-
-#include "theory/quantifiers/model_builder.h"
-#include "theory/quantifiers/first_order_model.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-class FirstOrderModelAbs;
-
-//representiation of function and term interpretations
-class AbsDef
-{
-private:
- bool addInstantiations( FirstOrderModelAbs * m, QuantifiersEngine * qe, TNode q, std::vector< Node >& terms, int& inst, unsigned depth );
- void construct_compose( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f,
- std::map< unsigned, AbsDef * >& children,
- std::map< unsigned, int >& bchildren, std::map< unsigned, int >& vchildren,
- std::vector< unsigned >& entry, std::vector< bool >& entry_def );
- void construct_entry( std::vector< unsigned >& entry, std::vector< bool >& entry_def, int v, unsigned depth = 0 );
- void construct_def_entry( FirstOrderModelAbs * m, TNode q, TNode n, int v, unsigned depth = 0 );
- void apply_ucompose( FirstOrderModelAbs * m, TNode q,
- std::vector< unsigned >& entry, std::vector< bool >& entry_def, std::vector< int >& terms,
- std::map< unsigned, int >& vchildren, AbsDef * a, unsigned depth = 0 );
- void construct_var_eq( FirstOrderModelAbs * m, TNode q, unsigned v1, unsigned v2, int curr, int currv, unsigned depth = 0 );
- void construct_var( FirstOrderModelAbs * m, TNode q, unsigned v, int currv, unsigned depth = 0 );
- void get_defs( unsigned u, std::vector< AbsDef * >& defs );
- void construct_normalize( FirstOrderModelAbs * m, TNode q, std::vector< AbsDef * >& defs, unsigned depth = 0 );
-public:
- enum {
- val_none = -1,
- val_unk = -2,
- };
- AbsDef() : d_default( 0 ), d_value( -1 ){}
- std::map< unsigned, AbsDef > d_def;
- unsigned d_default;
- int d_value;
-
- void clear() { d_def.clear(); d_default = 0; d_value = -1; }
- AbsDef * getDefault() { return &d_def[d_default]; }
- void construct_func( FirstOrderModelAbs * m, std::vector< TNode >& fapps, unsigned depth = 0 );
- void debugPrintUInt( const char * c, unsigned dSize, unsigned u ) const;
- void debugPrint( const char * c, FirstOrderModelAbs * m, TNode f, unsigned depth = 0 ) const;
- void simplify( FirstOrderModelAbs * m, TNode q, TNode n, unsigned depth = 0 );
- int addInstantiations( FirstOrderModelAbs * m, QuantifiersEngine * qe, Node q, int& inst ){
- std::vector< Node > terms;
- terms.resize( q[0].getNumChildren() );
- return addInstantiations( m, qe, q, terms, inst, 0 );
- }
- bool construct( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f,
- std::map< unsigned, AbsDef * >& children,
- std::map< unsigned, int >& bchildren,
- std::map< unsigned, int >& vchildren,
- int varChCount );
- void negate();
- Node getFunctionValue( FirstOrderModelAbs * m, TNode op, std::vector< Node >& vars, unsigned depth = 0 );
- static bool isSimple( unsigned n );
- static unsigned getId( unsigned n, unsigned start=0, unsigned end=32 );
- Node evaluate( FirstOrderModelAbs * m, TypeNode retType, std::vector< Node >& args );
- Node evaluate( FirstOrderModelAbs * m, TypeNode retType, std::vector< unsigned >& iargs, unsigned depth = 0 );
- //for debugging
- bool is_normalized();
-};
-
-class AbsMbqiBuilder : public QModelBuilder
-{
- friend class AbsDef;
-private:
- Node d_true;
- Node d_false;
- bool doCheck( FirstOrderModelAbs * m, TNode q, AbsDef & ad, TNode n );
-public:
- AbsMbqiBuilder( context::Context* c, QuantifiersEngine* qe );
- //process build model
- void processBuildModel(TheoryModel* m, bool fullModel);
- //do exhaustive instantiation
- bool doExhaustiveInstantiation( FirstOrderModel * fm, Node q, int effort );
-};
-
-}
-}
-}
-
-#endif
+/********************* */ +/*! \file ambqi_builder.h + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: none + ** 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 Abstract MBQI model builder class + **/ + +#include "cvc4_private.h" + +#ifndef ABSTRACT_MBQI_BUILDER +#define ABSTRACT_MBQI_BUILDER + +#include "theory/quantifiers/model_builder.h" +#include "theory/quantifiers/first_order_model.h" + +namespace CVC4 { +namespace theory { +namespace quantifiers { + +class FirstOrderModelAbs; + +//representiation of function and term interpretations +class AbsDef +{ +private: + bool addInstantiations( FirstOrderModelAbs * m, QuantifiersEngine * qe, TNode q, std::vector< Node >& terms, int& inst, unsigned depth ); + void construct_compose( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f, + std::map< unsigned, AbsDef * >& children, + std::map< unsigned, int >& bchildren, std::map< unsigned, int >& vchildren, + std::vector< unsigned >& entry, std::vector< bool >& entry_def ); + void construct_entry( std::vector< unsigned >& entry, std::vector< bool >& entry_def, int v, unsigned depth = 0 ); + void construct_def_entry( FirstOrderModelAbs * m, TNode q, TNode n, int v, unsigned depth = 0 ); + void apply_ucompose( FirstOrderModelAbs * m, TNode q, + std::vector< unsigned >& entry, std::vector< bool >& entry_def, std::vector< int >& terms, + std::map< unsigned, int >& vchildren, AbsDef * a, unsigned depth = 0 ); + void construct_var_eq( FirstOrderModelAbs * m, TNode q, unsigned v1, unsigned v2, int curr, int currv, unsigned depth = 0 ); + void construct_var( FirstOrderModelAbs * m, TNode q, unsigned v, int currv, unsigned depth = 0 ); + void get_defs( unsigned u, std::vector< AbsDef * >& defs ); + void construct_normalize( FirstOrderModelAbs * m, TNode q, std::vector< AbsDef * >& defs, unsigned depth = 0 ); +public: + enum { + val_none = -1, + val_unk = -2, + }; + AbsDef() : d_default( 0 ), d_value( -1 ){} + std::map< unsigned, AbsDef > d_def; + unsigned d_default; + int d_value; + + void clear() { d_def.clear(); d_default = 0; d_value = -1; } + AbsDef * getDefault() { return &d_def[d_default]; } + void construct_func( FirstOrderModelAbs * m, std::vector< TNode >& fapps, unsigned depth = 0 ); + void debugPrintUInt( const char * c, unsigned dSize, unsigned u ) const; + void debugPrint( const char * c, FirstOrderModelAbs * m, TNode f, unsigned depth = 0 ) const; + void simplify( FirstOrderModelAbs * m, TNode q, TNode n, unsigned depth = 0 ); + int addInstantiations( FirstOrderModelAbs * m, QuantifiersEngine * qe, Node q, int& inst ){ + std::vector< Node > terms; + terms.resize( q[0].getNumChildren() ); + return addInstantiations( m, qe, q, terms, inst, 0 ); + } + bool construct( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f, + std::map< unsigned, AbsDef * >& children, + std::map< unsigned, int >& bchildren, + std::map< unsigned, int >& vchildren, + int varChCount ); + void negate(); + Node getFunctionValue( FirstOrderModelAbs * m, TNode op, std::vector< Node >& vars, unsigned depth = 0 ); + static bool isSimple( unsigned n ); + static unsigned getId( unsigned n, unsigned start=0, unsigned end=32 ); + Node evaluate( FirstOrderModelAbs * m, TypeNode retType, std::vector< Node >& args ); + Node evaluate( FirstOrderModelAbs * m, TypeNode retType, std::vector< unsigned >& iargs, unsigned depth = 0 ); + //for debugging + bool is_normalized(); +}; + +class AbsMbqiBuilder : public QModelBuilder +{ + friend class AbsDef; +private: + Node d_true; + Node d_false; + bool doCheck( FirstOrderModelAbs * m, TNode q, AbsDef & ad, TNode n ); +public: + AbsMbqiBuilder( context::Context* c, QuantifiersEngine* qe ); + //process build model + void processBuildModel(TheoryModel* m, bool fullModel); + //do exhaustive instantiation + bool doExhaustiveInstantiation( FirstOrderModel * fm, Node q, int effort ); +}; + +} +} +} + +#endif diff --git a/src/theory/quantifiers/qinterval_builder.cpp b/src/theory/quantifiers/qinterval_builder.cpp index 285834e96..bd8f23db6 100755 --- a/src/theory/quantifiers/qinterval_builder.cpp +++ b/src/theory/quantifiers/qinterval_builder.cpp @@ -1,1111 +1,1111 @@ -/********************* */
-/*! \file qinterval_builder.cpp
- ** \verbatim
- ** Original author: Andrew Reynolds
- ** Major contributors: none
- ** 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 qinterval builder
- **/
-
-
-#include "theory/quantifiers/qinterval_builder.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;
-
-//lower bound is exclusive
-//upper bound is inclusive
-
-struct QIntSort
-{
- FirstOrderModelQInt * m;
- bool operator() (Node i, Node j) {
- return m->isLessThan( i, j );
- }
-};
-
-void QIntDef::init_vec( FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u ) {
- for( unsigned i=0; i<m->getOrderedNumVars( q ); i++ ){
- l.push_back( Node::null() );
- u.push_back( m->getMaximum( m->getOrderedVarType( q, i ) ) );
- }
-}
-
-void QIntDef::debugPrint( const char * c, FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u )
-{
- Trace(c) << "( ";
- for( unsigned i=0; i<l.size(); i++ ){
- if( i>0 ) Trace(c) << ", ";
- //Trace(c) << l[i] << "..." << u[i];
- int lindex = l[i].isNull() ? 0 : m->getRepId( l[i] ) + 1;
- int uindex = m->getRepId( u[i] );
- Trace(c) << lindex << "..." << uindex;
- }
- Trace(c) << " )";
-}
-
-
-int QIntDef::getEvIndex( FirstOrderModelQInt * m, Node n, bool exc ) {
- if( n.isNull() ){
- Assert( exc );
- return 0;
- }else{
- int min = 0;
- int max = (int)(d_def_order.size()-1);
- while( min!=max ){
- int index = (min+max)/2;
- Assert( index>=0 && index<(int)d_def_order.size() );
- if( n==d_def_order[index] ){
- max = index;
- min = index;
- }else if( m->isLessThan( n, d_def_order[index] ) ){
- max = index;
- }else{
- min = index+1;
- }
- }
- if( n==d_def_order[min] && exc ){
- min++;
- }
- Assert( min>=0 && min<(int)d_def_order.size() );
- if( ( min!=0 && !m->isLessThan( d_def_order[min-1], n ) && ( !exc || d_def_order[min-1]!=n ) ) ||
- ( ( exc || d_def_order[min]!=n ) && !m->isLessThan( n, d_def_order[min] ) ) ){
- Debug("qint-error") << "ERR size : " << d_def_order.size() << ", exc : " << exc << std::endl;
- for( unsigned i=0; i<d_def_order.size(); i++ ){
- Debug("qint-error") << "ERR ch #" << i << " : " << d_def_order[i];
- Debug("qint-error") << " " << m->getRepId( d_def_order[i] ) << std::endl;
- }
- Debug("qint-error") << " : " << n << " " << min << " " << m->getRepId( n ) << std::endl;
- }
-
- Assert( min==0 || m->isLessThan( d_def_order[min-1], n ) || ( exc && d_def_order[min-1]==n ) );
- Assert( ( !exc && n==d_def_order[min] ) || m->isLessThan( n, d_def_order[min] ) );
- return min;
- }
-}
-
-void QIntDef::addEntry( FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u,
- Node v, unsigned depth ) {
- if( depth==0 ){
- Trace("qint-compose-debug") << "Add entry ";
- debugPrint( "qint-compose-debug", m, q, l, u );
- Trace("qint-compose-debug") << " -> " << v << "..." << std::endl;
- }
- //Assert( false );
- if( depth==u.size() ){
- Assert( d_def_order.empty() );
- Assert( v.isNull() || v.isConst() || ( v.getType().isSort() && m->getRepId( v )!=-1 ) );
- d_def_order.push_back( v );
- }else{
- /*
- if( !d_def_order.empty() &&
- ( l[depth].isNull() || m->isLessThan( l[depth], d_def_order[d_def_order.size()-1] ) ) ){
- int startEvIndex = getEvIndex( m, l[depth], true );
- int endEvIndex;
- if( m->isLessThan( u[depth], d_def_order[d_def_order.size()-1] ) ){
- endEvIndex = getEvIndex( m, u[depth] );
- }else{
- endEvIndex = d_def_order.size()-1;
- }
- Trace("qint-compose-debug2") << this << " adding for bounds " << l[depth] << "..." << u[depth] << std::endl;
- for( int i=startEvIndex; i<=endEvIndex; i++ ){
- Trace("qint-compose-debug2") << this << " add entry " << d_def_order[i] << std::endl;
- d_def[d_def_order[i]].addEntry( m, q, l, u, v, depth+1 );
- }
- }
- if( !d_def_order.empty() &&
- d_def.find(u[depth])==d_def.end() &&
- !m->isLessThan( d_def_order[d_def_order.size()-1], u[depth] ) ){
- Trace("qint-compose-debug2") << "Bad : depth : " << depth << std::endl;
- }
- Assert( d_def_order.empty() ||
- d_def.find(u[depth])!=d_def.end() ||
- m->isLessThan( d_def_order[d_def_order.size()-1], u[depth] ) );
-
- if( d_def_order.empty() || m->isLessThan( d_def_order[d_def_order.size()-1], u[depth] ) ){
- Trace("qint-compose-debug2") << this << " add entry new : " << u[depth] << std::endl;
- d_def_order.push_back( u[depth] );
- d_def[u[depth]].addEntry( m, q, l, u, v, depth+1 );
- }
- */
- //%%%%%%
- bool success = true;
- int nnum = m->getVarOrder( q )->getNextNum( depth );
- Node pl;
- Node pu;
- if( nnum!=-1 ){
- Trace("qint-compose-debug2") << "...adding entry #" << depth << " is #" << nnum << std::endl;
- //Assert( l[nnum].isNull() || l[nnum]==l[depth] || m->isLessThan( l[nnum], l[depth] ) );
- //Assert( u[nnum]==u[depth] || m->isLessThan( u[depth], u[nnum] ) );
- pl = l[nnum];
- pu = u[nnum];
- if( !m->doMeet( l[nnum], u[nnum], l[depth], u[depth], l[nnum], u[nnum] ) ){
- success = false;
- }
- }
- //%%%%%%
- if( success ){
- Node r = u[depth];
- if( d_def.find( r )!=d_def.end() ){
- d_def[r].addEntry( m, q, l, u, v, depth+1 );
- }else{
- if( !d_def_order.empty() &&
- !m->isLessThan( d_def_order[d_def_order.size()-1], u[depth] ) ){
- Trace("qint-compose-debug2") << "Bad : depth : " << depth << " ";
- Trace("qint-compose-debug2") << d_def_order[d_def_order.size()-1] << " " << u[depth] << std::endl;
- }
- Assert( d_def_order.empty() || m->isLessThan( d_def_order[d_def_order.size()-1], r ) );
- d_def_order.push_back( r );
- d_def[r].addEntry( m, q, l, u, v, depth+1 );
- }
- }
- if( nnum!=-1 ){
- l[nnum] = pl;
- u[nnum] = pu;
- }
- }
-}
-
-Node QIntDef::simplify_r( FirstOrderModelQInt * m, Node q, std::vector< Node >& il, std::vector< Node >& iu,
- unsigned depth ) {
- if( d_def.empty() ){
- if( d_def_order.size()!=0 ){
- Debug("qint-error") << "Simplify, size = " << d_def_order.size() << std::endl;
- }
- Assert( d_def_order.size()==1 );
- return d_def_order[0];
- }else{
- Assert( !d_def_order.empty() );
- std::vector< Node > newDefs;
- Node curr;
- for( unsigned i=0; i<d_def_order.size(); i++ ){
- Node n = d_def[d_def_order[i]].simplify_r( m, q, il, iu, depth+1 );
- if( i>0 ){
- if( n==curr && !n.isNull() ){
- d_def.erase( d_def_order[i-1] );
- }else{
- newDefs.push_back( d_def_order[i-1] );
- }
- }
- curr = n;
- }
- newDefs.push_back( d_def_order[d_def_order.size()-1] );
- d_def_order.clear();
- d_def_order.insert( d_def_order.end(), newDefs.begin(), newDefs.end() );
- return d_def_order.size()==1 ? curr : Node::null();
- }
-}
-
-Node QIntDef::simplify( FirstOrderModelQInt * m, Node q ) {
- std::vector< Node > l;
- std::vector< Node > u;
- if( !q.isNull() ){
- //init_vec( m, q, l, u );
- }
- return simplify_r( m, q, l, u, 0 );
-}
-
-bool QIntDef::isTotal_r( FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u,
- unsigned depth ) {
- if( d_def_order.empty() ){
- return false;
- }else if( d_def.empty() ){
- return true;
- }else{
- //get the current maximum
- Node mx;
- if( !q.isNull() ){
- int pnum = m->getVarOrder( q )->getPrevNum( depth );
- if( pnum!=-1 ){
- mx = u[pnum];
- }
- }
- if( mx.isNull() ){
- mx = m->getMaximum( d_def_order[d_def_order.size()-1].getType() );
- }
- //if not current maximum
- if( d_def_order[d_def_order.size()-1]!=mx ){
- return false;
- }else{
- Node pu = u[depth];
- for( unsigned i=0; i<d_def_order.size(); i++ ){
- u[depth] = d_def_order[i];
- if( !d_def[d_def_order[i]].isTotal_r( m, q, l, u, depth+1 ) ){
- return false;
- }
- }
- u[depth] = pu;
- return true;
- }
- }
-}
-
-bool QIntDef::isTotal( FirstOrderModelQInt * m, Node q ) {
- std::vector< Node > l;
- std::vector< Node > u;
- if( !q.isNull() ){
- init_vec( m, q, l, u );
- }
- return isTotal_r( m, q, l, u, 0 );
-}
-
-void QIntDef::construct_compose_r( FirstOrderModelQInt * m, Node q,
- std::vector< Node >& l, std::vector< Node >& u,
- Node n, QIntDef * f,
- std::vector< Node >& args,
- std::map< unsigned, QIntDef >& children,
- std::map< unsigned, Node >& bchildren,
- QIntVarNumIndex& vindex, unsigned depth ) {
- //check for short circuit
- if( !f ){
- if( !args.empty() ){
- if( ( n.getKind()==OR && args[args.size()-1]==m->d_true ) ||
- ( n.getKind()==AND && args[args.size()-1]==m->d_false ) ){
- addEntry( m, q, l, u, args[args.size()-1] );
- return;
- }
- }
- }
-
- for( unsigned i=0; i<depth; i++ ) { Trace("qint-compose") << " "; }
- Trace("qint-compose") << (f ? "U" : "I" ) << "C( ";
- for( unsigned i=0; i<l.size(); i++ ){
- if( i>0 ) Trace("qint-compose") << ", ";
- //Trace("qint-compose") << l[i] << "..." << u[i];
- int lindex = l[i].isNull() ? 0 : m->getRepId( l[i] ) + 1;
- int uindex = m->getRepId( u[i] );
- Trace( "qint-compose" ) << lindex << "..." << uindex;
- }
- Trace("qint-compose") << " )...";
-
- //finished?
- if( ( f && f->d_def.empty() ) || args.size()==n.getNumChildren() ){
- if( f ){
- Assert( f->d_def_order.size()==1 );
- Trace("qint-compose") << "UVALUE(" << f->d_def_order[0] << ")" << std::endl;
- addEntry( m, q, l, u, f->d_def_order[0] );
- }else{
- Node nn;
- bool nnSet = false;
- for( unsigned i=0; i<args.size(); i++ ){
- if( args[i].isNull() ){
- nnSet = true;
- break;
- }
- }
- if( !nnSet ){
- if( n.getKind()==EQUAL ){
- nn = NodeManager::currentNM()->mkConst( args[0]==args[1] );
- }else{
- //apply the operator to args
- nn = NodeManager::currentNM()->mkNode( n.getKind(), args );
- nn = Rewriter::rewrite( nn );
- }
- }
- Trace("qint-compose") << "IVALUE(" << nn << ")" << std::endl;
- addEntry( m, q, l, u, nn );
- Trace("qint-compose-debug2") << "...added entry." << std::endl;
- }
- }else{
- //if a non-simple child
- if( children.find( depth )!=children.end() ){
- //***************************
- Trace("qint-compose") << "compound child, recurse" << std::endl;
- std::vector< int > currIndex;
- std::vector< int > endIndex;
- std::vector< Node > prevL;
- std::vector< Node > prevU;
- std::vector< QIntDef * > visited;
- do{
- Assert( currIndex.size()==visited.size() );
-
- //populate the vectors
- while( visited.size()<m->getOrderedNumVars( q ) ){
- unsigned i = visited.size();
- QIntDef * qq = visited.empty() ? &children[depth] : visited[i-1]->getChild( currIndex[i-1] );
- visited.push_back( qq );
- Node qq_mx = qq->getMaximum();
- Trace("qint-compose-debug2") << "...Get ev indices " << i << " " << l[i] << " " << u[i] << std::endl;
- currIndex.push_back( qq->getEvIndex( m, l[i], true ) );
- Trace("qint-compose-debug2") << "...Done get curr index " << currIndex[currIndex.size()-1] << std::endl;
- if( m->isLessThan( qq_mx, u[i] ) ){
- endIndex.push_back( qq->getNumChildren()-1 );
- }else{
- endIndex.push_back( qq->getEvIndex( m, u[i] ) );
- }
- Trace("qint-compose-debug2") << "...Done get end index " << endIndex[endIndex.size()-1] << std::endl;
- prevL.push_back( l[i] );
- prevU.push_back( u[i] );
- if( !m->doMeet( prevL[i], prevU[i],
- qq->getLower( currIndex[i] ), qq->getUpper( currIndex[i] ), l[i], u[i] ) ){
- Assert( false );
- }
- }
- for( unsigned i=0; i<depth; i++ ) { Trace("qint-compose") << " "; }
- for( unsigned i=0; i<currIndex.size(); i++ ){
- Trace("qint-compose") << "[" << currIndex[i] << "/" << endIndex[i] << "]";
- }
- Trace("qint-compose") << std::endl;
- //consider the current
- int activeIndex = visited.size()-1;
- QIntDef * qa = visited.empty() ? &children[depth] : visited[activeIndex]->getChild( currIndex[activeIndex] );
- if( f ){
- int fIndex = f->getEvIndex( m, qa->getValue() );
- construct_compose_r( m, q, l, u, n, f->getChild( fIndex ), args, children, bchildren, vindex, depth+1 );
- }else{
- args.push_back( qa->getValue() );
- construct_compose_r( m, q, l, u, n, f, args, children, bchildren, vindex, depth+1 );
- args.pop_back();
- }
-
- //increment the index (if possible)
- while( activeIndex>=0 && currIndex[activeIndex]==endIndex[activeIndex] ){
- currIndex.pop_back();
- endIndex.pop_back();
- l[activeIndex] = prevL[activeIndex];
- u[activeIndex] = prevU[activeIndex];
- prevL.pop_back();
- prevU.pop_back();
- visited.pop_back();
- activeIndex--;
- }
- if( activeIndex>=0 ){
- for( unsigned i=0; i<depth; i++ ) { Trace("qint-compose") << " "; }
- Trace("qint-compose-debug") << "Increment at " << activeIndex << std::endl;
- currIndex[activeIndex]++;
- if( !m->doMeet( prevL[activeIndex], prevU[activeIndex],
- visited[activeIndex]->getLower( currIndex[activeIndex] ),
- visited[activeIndex]->getUpper( currIndex[activeIndex] ),
- l[activeIndex], u[activeIndex] ) ){
- Assert( false );
- }
- }
- }while( !visited.empty() );
- //***************************
- }else{
- Assert( bchildren.find( depth )!=bchildren.end() );
- Node v = bchildren[depth];
- if( f ){
- if( v.getKind()==BOUND_VARIABLE ){
- int vn = vindex.d_var_num[depth];
- Trace("qint-compose") << "variable #" << vn << ", recurse" << std::endl;
- //int vn = m->getOrderedVarOccurId( q, n, depth );
- Trace("qint-compose-debug") << "-process " << v << ", which is var #" << vn << std::endl;
- Node lprev = l[vn];
- Node uprev = u[vn];
- //restrict to last variable in order
- int pnum = m->getVarOrder( q )->getPrevNum( vn );
- if( pnum!=-1 ){
- Trace("qint-compose-debug") << "-restrict to var #" << pnum << " " << l[pnum] << " " << u[pnum] << std::endl;
- l[vn] = l[pnum];
- u[vn] = u[pnum];
- }
- int startIndex = f->getEvIndex( m, l[vn], true );
- int endIndex = f->getEvIndex( m, u[vn] );
- Trace("qint-compose-debug") << "--will process " << startIndex << " " << endIndex << std::endl;
- for( int i=startIndex; i<=endIndex; i++ ){
- if( m->doMeet( lprev, uprev, f->getLower( i ), f->getUpper( i ), l[vn], u[vn] ) ){
- construct_compose_r( m, q, l, u, n, f->getChild( i ), args, children, bchildren, vindex, depth+1 );
- }else{
- Assert( false );
- }
- }
- l[vn] = lprev;
- u[vn] = uprev;
- }else{
- Trace("qint-compose") << "value, recurse" << std::endl;
- //simple
- int ei = f->getEvIndex( m, v );
- construct_compose_r( m, q, l, u, n, f->getChild( ei ), args, children, bchildren, vindex, depth+1 );
- }
- }else{
- Trace("qint-compose") << "value, recurse" << std::endl;
- args.push_back( v );
- construct_compose_r( m, q, l, u, n, f, args, children, bchildren, vindex, depth+1 );
- args.pop_back();
- }
- }
- }
-}
-
-
-void QIntDef::construct_enum_r( FirstOrderModelQInt * m, Node q, unsigned vn, unsigned depth, Node v ) {
- if( depth==m->getOrderedNumVars( q ) ){
- Assert( !v.isNull() );
- d_def_order.push_back( v );
- }else{
- TypeNode tn = m->getOrderedVarType( q, depth );
- //int vnum = m->getVarOrder( q )->getVar( depth )==
- if( depth==vn ){
- for( unsigned i=0; i<m->d_rep_set.d_type_reps[tn].size(); i++ ){
- Node vv = m->d_rep_set.d_type_reps[tn][i];
- d_def_order.push_back( vv );
- d_def[vv].construct_enum_r( m, q, vn, depth+1, vv );
- }
- }else if( m->getVarOrder( q )->getVar( depth )==m->getVarOrder( q )->getVar( vn ) && depth>vn ){
- d_def_order.push_back( v );
- d_def[v].construct_enum_r( m, q, vn, depth+1, v );
- }else{
- Node mx = m->getMaximum( tn );
- d_def_order.push_back( mx );
- d_def[mx].construct_enum_r( m, q, vn, depth+1, v );
- }
- }
-}
-
-bool QIntDef::construct_enum( FirstOrderModelQInt * m, Node q, unsigned vn ) {
- TypeNode tn = m->getOrderedVarType( q, vn );
- if( tn.isSort() ){
- construct_enum_r( m, q, vn, 0, Node::null() );
- return true;
- }else{
- return false;
- }
-}
-
-bool QIntDef::construct_compose( FirstOrderModelQInt * m, Node q, Node n, QIntDef * f,
- std::map< unsigned, QIntDef >& children,
- std::map< unsigned, Node >& bchildren, int varChCount,
- QIntVarNumIndex& vindex ) {
- Trace("qint-compose") << "Do " << (f ? "uninterpreted" : "interpreted");
- Trace("qint-compose") << " compose, var count = " << varChCount << "..." << std::endl;
- std::vector< Node > l;
- std::vector< Node > u;
- init_vec( m, q, l, u );
- if( varChCount==0 || f ){
- //standard (no variable child) interpreted compose, or uninterpreted compose
- std::vector< Node > args;
- construct_compose_r( m, q, l, u, n, f, args, children, bchildren, vindex, 0 );
- }else{
- //special cases
- bool success = false;
- int varIndex = ( bchildren.find( 0 )!=bchildren.end() && bchildren[0].getKind()==BOUND_VARIABLE ) ? 0 : 1;
- if( varChCount>1 ){
- if( n.getKind()==EQUAL ){
- //make it an enumeration
- unsigned vn = vindex.d_var_num[0];
- if( children[0].construct_enum( m, q, vn ) ){
- bchildren.erase( 0 );
- varIndex = 1;
- success = true;
- }
- }
- }else{
- success = n.getKind()==EQUAL;
- }
- if( success ){
- int oIndex = varIndex==0 ? 1 : 0;
- Node v = bchildren[varIndex];
- unsigned vn = vindex.d_var_num[varIndex];
- if( children.find( oIndex )==children.end() ){
- Assert( bchildren.find( oIndex )!=bchildren.end() );
- Node at = bchildren[oIndex];
- Trace("qint-icompose") << "Basic child, " << at << " with var " << v << std::endl;
- Node prev = m->getPrev( bchildren[oIndex].getType(), bchildren[oIndex] );
- Node above = u[vn];
- if( !prev.isNull() ){
- u[vn] = prev;
- addEntry( m, q, l, u, NodeManager::currentNM()->mkConst( false ) );
- }
- l[vn] = prev;
- u[vn] = at;
- addEntry( m, q, l, u, NodeManager::currentNM()->mkConst( true ) );
- if( at!=above ){
- l[vn] = at;
- u[vn] = above;
- addEntry( m, q, l, u, NodeManager::currentNM()->mkConst( false ) );
- }
- }else{
- QIntDef * qid = &children[oIndex];
- qid->debugPrint("qint-icompose", m, q );
- Trace("qint-icompose") << " against variable..." << v << ", which is var #" << vn << std::endl;
-
- TypeNode tn = v.getType();
- QIntDefIter qdi( m, q, qid );
- while( !qdi.isFinished() ){
- std::vector< Node > us;
- qdi.getUppers( us );
- std::vector< Node > ls;
- qdi.getLowers( ls );
- qdi.debugPrint( "qint-icompose" );
-
- Node n_below = ls[vn];
- Node n_prev = m->getPrev( tn, qdi.getValue() );
- Node n_at = qdi.getValue();
- Node n_above = us[vn];
- Trace("qint-icompose") << n_below << " < " << n_prev << " < " << n_at << " < " << n_above << std::endl;
- if( n.getKind()==EQUAL ){
- bool atLtAbove = m->isLessThan( n_at, n_above );
- Node currL = n_below;
- if( n_at==n_above || atLtAbove ){
- //add for value (at-1)
- if( !n_prev.isNull() && ( n_below.isNull() || m->isLessThan( n_below, n_prev ) ) ){
- ls[vn] = currL;
- us[vn] = n_prev;
- currL = n_prev;
- Trace("qint-icompose") << "-add entry(-) at " << ls[vn] << "..." << us[vn] << std::endl;
- addEntry( m, q, ls, us, NodeManager::currentNM()->mkConst( false ) );
- }
- //add for value (at)
- if( ( n_below.isNull() || m->isLessThan( n_below, n_at ) ) && atLtAbove ){
- ls[vn] = currL;
- us[vn] = n_at;
- currL = n_at;
- Trace("qint-icompose") << "-add entry(=) at " << ls[vn] << "..." << us[vn] << std::endl;
- addEntry( m, q, ls, us, NodeManager::currentNM()->mkConst( true ) );
- }
- }
- ls[vn] = currL;
- us[vn] = n_above;
- Trace("qint-icompose") << "-add entry(+) at " << ls[vn] << "..." << us[vn] << std::endl;
- addEntry( m, q, ls, us, NodeManager::currentNM()->mkConst( n_at==n_above ) );
- }else{
- return false;
- }
- qdi.increment();
-
- Trace("qint-icompose-debug") << "Now : " << std::endl;
- debugPrint("qint-icompose-debug", m, q );
- Trace("qint-icompose-debug") << std::endl;
- }
- }
-
- Trace("qint-icompose") << "Result : " << std::endl;
- debugPrint("qint-icompose", m, q );
- Trace("qint-icompose") << std::endl;
-
- }else{
- return false;
- }
- }
- Trace("qint-compose") << "Done i-compose" << std::endl;
- return true;
-}
-
-
-void QIntDef::construct( FirstOrderModelQInt * m, std::vector< Node >& fapps, unsigned depth ) {
- d_def.clear();
- d_def_order.clear();
- Assert( !fapps.empty() );
- if( depth==fapps[0].getNumChildren() ){
- //get representative in model for this term
- Assert( fapps.size()>=1 );
- Node r = m->getUsedRepresentative( fapps[0] );
- d_def_order.push_back( r );
- }else{
- std::map< Node, std::vector< Node > > fapp_child;
- //partition based on evaluations of fapps[1][depth]....fapps[n][depth]
- for( unsigned i=0; i<fapps.size(); i++ ){
- Node r = m->getUsedRepresentative( fapps[i][depth] );
- fapp_child[r].push_back( fapps[i] );
- }
- //sort by QIntSort
- for( std::map< Node, std::vector< Node > >::iterator it = fapp_child.begin(); it != fapp_child.end(); ++it ){
- d_def_order.push_back( it->first );
- }
- QIntSort qis;
- qis.m = m;
- std::sort( d_def_order.begin(), d_def_order.end(), qis );
- //construct children
- for( unsigned i=0; i<d_def_order.size(); i++ ){
- Node n = d_def_order[i];
- if( i==d_def_order.size()-1 ){
- d_def_order[i] = m->getMaximum( d_def_order[i].getType() );
- }
- Debug("qint-model-debug2") << "Construct for " << n << ", terms = " << fapp_child[n].size() << std::endl;
- d_def[d_def_order[i]].construct( m, fapp_child[n], depth+1 );
- }
- }
-}
-
-Node QIntDef::getFunctionValue( FirstOrderModelQInt * m, std::vector< Node >& vars, unsigned depth ) {
- if( d_def.empty() ){
- Assert( d_def_order.size()==1 );
- //must convert to actual domain constant
- if( d_def_order[0].getType().isSort() ){
- return m->d_rep_set.d_type_reps[ d_def_order[0].getType() ][ m->getRepId( d_def_order[0] ) ];
- }else{
- return m->getUsedRepresentative( d_def_order[0] );
- }
- }else{
- TypeNode tn = vars[depth].getType();
- Node curr;
- int rep_id = m->d_rep_set.getNumRepresentatives( tn );
- for( int i=(int)(d_def_order.size()-1); i>=0; i-- ){
- int curr_rep_id = i==0 ? 0 : m->getRepId( d_def_order[i-1] )+1;
- Node ccurr = d_def[d_def_order[i]].getFunctionValue( m, vars, depth+1 );
- if( curr.isNull() ){
- curr = ccurr;
- }else{
- std::vector< Node > c;
- Assert( curr_rep_id<rep_id );
- for( int j=curr_rep_id; j<rep_id; j++ ){
- c.push_back( vars[depth].eqNode( m->d_rep_set.d_type_reps[tn][j] ) );
- }
- Node cond = c.size()==1 ? c[0] : NodeManager::currentNM()->mkNode( OR, c );
- curr = NodeManager::currentNM()->mkNode( ITE, cond, ccurr, curr );
- }
- rep_id = curr_rep_id;
- }
- return curr;
- }
-}
-
-Node QIntDef::evaluate_r( FirstOrderModelQInt * m, std::vector< Node >& reps, unsigned depth ) {
- if( depth==reps.size() ){
- Assert( d_def_order.size()==1 );
- return d_def_order[0];
- }else{
- if( d_def.find( reps[depth] )!=d_def.end() ){
- return d_def[reps[depth]].evaluate_r( m, reps, depth+1 );
- }else{
- int ei = getEvIndex( m, reps[depth] );
- return d_def[d_def_order[ei]].evaluate_r( m, reps, depth+1 );
- }
- }
-}
-Node QIntDef::evaluate_n_r( FirstOrderModelQInt * m, Node n, unsigned depth ) {
- if( depth==n.getNumChildren() ){
- Assert( d_def_order.size()==1 );
- return d_def_order[0];
- }else{
- Node r = m->getUsedRepresentative( n[depth] );
- if( d_def.find( r )!=d_def.end() ){
- return d_def[r].evaluate_n_r( m, n, depth+1 );
- }else{
- int ei = getEvIndex( m, r );
- return d_def[d_def_order[ei]].evaluate_n_r( m, n, depth+1 );
- }
- }
-}
-
-
-
-QIntDef * QIntDef::getChild( unsigned i ) {
- Assert( i<d_def_order.size() );
- Assert( d_def.find( d_def_order[i] )!=d_def.end() );
- return &d_def[ d_def_order[i] ];
-}
-
-void QIntDef::debugPrint( const char * c, FirstOrderModelQInt * m, Node q, int t ) {
- /*
- for( unsigned i=0; i<d_def_order.size(); i++ ){
- for( int j=0; j<t; j++ ) { Trace(c) << " "; }
- //Trace(c) << this << " ";
- Trace(c) << d_def_order[i] << " : " << std::endl;
- if( d_def.find( d_def_order[i] )!=d_def.end() ){
- d_def[d_def_order[i]].debugPrint( c, m, t+1 );
- }
- }
- */
- //if( t==0 ){
- QIntDefIter qdi( m, q, this );
- while( !qdi.isFinished() ){
- qdi.debugPrint( c, t );
- qdi.increment();
- }
- //}
-}
-
-
-QIntDefIter::QIntDefIter( FirstOrderModelQInt * m, Node q, QIntDef * qid ) : d_fm( m ), d_q( q ){
- resetIndex( qid );
-}
-
-void QIntDefIter::debugPrint( const char * c, int t ) {
- //Trace( c ) << getSize() << " " << d_index_visited.size() << " ";
- for( int j=0; j<t; j++ ) { Trace(c) << " "; }
- std::vector< Node > l;
- std::vector< Node > u;
- getLowers( l );
- getUppers( u );
- QIntDef::debugPrint( c, d_fm, d_q, l, u );
- Trace( c ) << " -> " << getValue() << std::endl;
-}
-
-void QIntDefIter::resetIndex( QIntDef * qid ){
- //std::cout << "check : " << qid << " " << qid->d_def_order.size() << " " << qid->d_def.size() << std::endl;
- if( !qid->d_def.empty() ){
- //std::cout << "add to visited " << qid << std::endl;
- d_index.push_back( 0 );
- d_index_visited.push_back( qid );
- resetIndex( qid->getChild( 0 ) );
- }
-}
-
-bool QIntDefIter::increment( int index ) {
- if( !isFinished() ){
- index = index==-1 ? (int)(d_index.size()-1) : index;
- while( (int)(d_index.size()-1)>index ){
- //std::cout << "remove from visit 1 " << std::endl;
- d_index.pop_back();
- d_index_visited.pop_back();
- }
- while( index>=0 && d_index[index]>=(int)(d_index_visited[index]->d_def_order.size()-1) ){
- //std::cout << "remove from visit " << d_index_visited[ d_index_visited.size()-1 ] << std::endl;
- d_index.pop_back();
- d_index_visited.pop_back();
- index--;
- }
- if( index>=0 ){
- //std::cout << "increment at index = " << index << std::endl;
- d_index[index]++;
- resetIndex( d_index_visited[index]->getChild( d_index[index] ) );
- return true;
- }else{
- d_index.clear();
- return false;
- }
- }else{
- return false;
- }
-}
-
-Node QIntDefIter::getLower( int index ) {
- if( d_index[index]==0 && !d_q.isNull() ){
- int pnum = d_fm->getVarOrder( d_q )->getPrevNum( index );
- if( pnum!=-1 ){
- return getLower( pnum );
- }
- }
- return d_index_visited[index]->getLower( d_index[index] );
-}
-
-Node QIntDefIter::getUpper( int index ) {
- return d_index_visited[index]->getUpper( d_index[index] );
-}
-
-void QIntDefIter::getLowers( std::vector< Node >& reps ) {
- for( unsigned i=0; i<getSize(); i++ ){
- bool added = false;
- if( d_index[i]==0 && !d_q.isNull() ){
- int pnum = d_fm->getVarOrder( d_q )->getPrevNum( i );
- if( pnum!=-1 ){
- added = true;
- reps.push_back( reps[pnum] );
- }
- }
- if( !added ){
- reps.push_back( getLower( i ) );
- }
- }
-}
-
-void QIntDefIter::getUppers( std::vector< Node >& reps ) {
- for( unsigned i=0; i<getSize(); i++ ){
- reps.push_back( getUpper( i ) );
- }
-}
-
-Node QIntDefIter::getValue() {
- return d_index_visited[ d_index_visited.size()-1 ]->getChild( d_index[d_index.size()-1] )->getValue();
-}
-
-
-//------------------------variable ordering----------------------------
-
-QuantVarOrder::QuantVarOrder( Node q ) : d_q( q ) {
- d_var_count = 0;
- initialize( q[1], 0, d_var_occur );
-}
-
-int QuantVarOrder::initialize( Node n, int minVarIndex, QIntVarNumIndex& vindex ) {
- if( n.getKind()!=FORALL ){
- //std::vector< Node > vars;
- //std::vector< int > args;
- int procVarOn = n.getKind()==APPLY_UF ? 0 : 1;
- for( int r=0; r<=procVarOn; r++ ){
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- if( n[i].getKind()==BOUND_VARIABLE && r==procVarOn ){
- int occ_index = -1;
- for( unsigned j=0; j<d_var_to_num[n[i]].size(); j++ ){
- if( d_var_to_num[n[i]][j]>=minVarIndex ){
- occ_index = d_var_to_num[n[i]][j];
- }
- }
- if( occ_index==-1 ){
- //need to assign new
- d_num_to_var[d_var_count] = n[i];
- if( !d_var_to_num[n[i]].empty() ){
- int v = d_var_to_num[n[i]][ d_var_to_num[n[i]].size()-1 ];
- d_num_to_prev_num[ d_var_count ] = v;
- d_num_to_next_num[ v ] = d_var_count;
- }
- d_var_num_index[ d_var_count ] = d_var_to_num[n[i]].size();
- d_var_to_num[n[i]].push_back( d_var_count );
- occ_index = d_var_count;
- d_var_count++;
- }
- vindex.d_var_num[i] = occ_index;
- minVarIndex = occ_index;
- }else if( r==0 ){
- minVarIndex = initialize( n[i], minVarIndex, vindex.d_var_index[i] );
- }
- }
- }
- }
- return minVarIndex;
-}
-
-bool QuantVarOrder::getInstantiation( FirstOrderModelQInt * m, std::vector< Node >& l, std::vector< Node >& u,
- std::vector< Node >& inst ) {
- Debug("qint-var-order-debug2") << "Get for " << d_q << " " << l.size() << " " << u.size() << std::endl;
- for( unsigned i=0; i<d_q[0].getNumChildren(); i++ ){
- Debug("qint-var-order-debug2") << "Get for " << d_q[0][i] << " " << d_var_to_num[d_q[0][i]].size() << std::endl;
- Node ll = Node::null();
- Node uu = m->getMaximum( d_q[0][i].getType() );
- for( unsigned j=0; j<d_var_to_num[d_q[0][i]].size(); j++ ){
- Debug("qint-var-order-debug2") << "Go " << j << std::endl;
- Node cl = ll;
- Node cu = uu;
- int index = d_var_to_num[d_q[0][i]][j];
- Debug("qint-var-order-debug2") << "Do meet for " << index << "..." << std::endl;
- Debug("qint-var-order-debug2") << l[index] << " " << u[index] << " " << cl << " " << cu << std::endl;
- if( !m->doMeet( l[index], u[index], cl, cu, ll, uu ) ){
- Debug("qint-var-order-debug2") << "FAILED" << std::endl;
- return false;
- }
- Debug("qint-var-order-debug2") << "Result : " << ll << " " << uu << std::endl;
- }
- Debug("qint-var-order-debug2") << "Got " << uu << std::endl;
- inst.push_back( uu );
- }
- return true;
-}
-
-void QuantVarOrder::debugPrint( const char * c ) {
- Trace( c ) << "Variable order for " << d_q << " is : " << std::endl;
- debugPrint( c, d_q[1], d_var_occur );
- Trace( c ) << std::endl;
- for( unsigned i=0; i<d_q[0].getNumChildren(); i++ ){
- Trace( c ) << d_q[0][i] << " : ";
- for( unsigned j=0; j<d_var_to_num[d_q[0][i]].size(); j++ ){
- Trace( c ) << d_var_to_num[d_q[0][i]][j] << " ";
- }
- Trace( c ) << std::endl;
- }
-}
-
-void QuantVarOrder::debugPrint( const char * c, Node n, QIntVarNumIndex& vindex ) {
- if( n.getKind()==FORALL ){
- Trace(c) << "NESTED_QUANT";
- }else{
- Trace(c) << n.getKind() << "(";
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- if( i>0 ) Trace( c ) << ",";
- Trace( c ) << " ";
- if( n[i].getKind()==BOUND_VARIABLE ){
- Trace(c) << "VAR[" << vindex.d_var_num[i] << "]";
- }else{
- debugPrint( c, n[i], vindex.d_var_index[i] );
- }
- if( i==n.getNumChildren()-1 ) Trace( c ) << " ";
- }
- Trace(c) << ")";
- }
-}
-
-QIntervalBuilder::QIntervalBuilder( context::Context* c, QuantifiersEngine* qe ) :
-QModelBuilder( c, qe ){
- d_true = NodeManager::currentNM()->mkConst( true );
-}
-
-
-//------------------------model construction----------------------------
-
-void QIntervalBuilder::processBuildModel(TheoryModel* m, bool fullModel) {
- Trace("fmf-qint-debug") << "process build model " << fullModel << std::endl;
- FirstOrderModel* f = (FirstOrderModel*)m;
- FirstOrderModelQInt* fm = f->asFirstOrderModelQInt();
- if( fullModel ){
- Trace("qint-model") << "Construct model representation..." << std::endl;
- //make function values
- for( std::map<Node, QIntDef * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) {
- if( it->first.getType().getNumChildren()>1 ){
- Trace("qint-model") << "Construct for " << it->first << "..." << std::endl;
- m->d_uf_models[ it->first ] = fm->getFunctionValue( it->first, "$x" );
- }
- }
- TheoryEngineModelBuilder::processBuildModel( m, fullModel );
- //mark that the model has been set
- fm->markModelSet();
- //debug the model
- debugModel( fm );
- }else{
- fm->initialize( d_considerAxioms );
- //process representatives
- fm->d_rep_id.clear();
- fm->d_max.clear();
- fm->d_min.clear();
- Trace("qint-model") << std::endl << "Making representatives..." << std::endl;
- for( std::map< TypeNode, std::vector< Node > >::iterator it = fm->d_rep_set.d_type_reps.begin();
- it != fm->d_rep_set.d_type_reps.end(); ++it ){
- if( it->first.isSort() ){
- if( it->second.empty() ){
- std::cout << "Empty rep for " << it->first << std::endl;
- exit(0);
- }
- Trace("qint-model") << "Representatives for " << it->first << " : " << std::endl;
- for( unsigned i=0; i<it->second.size(); i++ ){
- Trace("qint-model") << i << " : " << it->second[i] << std::endl;
- fm->d_rep_id[it->second[i]] = i;
- }
- fm->d_min[it->first] = it->second[0];
- fm->d_max[it->first] = it->second[it->second.size()-1];
- }else{
- //TODO: enumerate?
- }
- }
- Trace("qint-model") << std::endl << "Making function definitions..." << std::endl;
- //construct the models for functions
- for( std::map<Node, QIntDef * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) {
- Node f = it->first;
- Trace("qint-model-debug") << "Building Model for " << f << std::endl;
- //reset the model
- //get all (non-redundant) f-applications
- std::vector< Node > fapps;
- Trace("qint-model-debug") << "Initial terms: " << std::endl;
- for( size_t i=0; i<fm->d_uf_terms[f].size(); i++ ){
- Node n = fm->d_uf_terms[f][i];
- if( !n.getAttribute(NoMatchAttribute()) ){
- Trace("qint-model-debug") << " " << n << std::endl;
- fapps.push_back( n );
- }
- }
- if( fapps.empty() ){
- //choose arbitrary value
- Node mbt = d_qe->getTermDatabase()->getModelBasisOpTerm(f);
- Trace("qint-model-debug") << "Initial terms empty, add " << mbt << std::endl;
- fapps.push_back( mbt );
- }
- //construct the interval model
- it->second->construct( fm, fapps );
- Trace("qint-model-debug") << "Definition for " << f << " : " << std::endl;
- it->second->debugPrint("qint-model-debug", fm, Node::null() );
-
- it->second->simplify( fm, Node::null() );
- Trace("qint-model") << "(Simplified) definition for " << f << " : " << std::endl;
- it->second->debugPrint("qint-model", fm, Node::null() );
-
- if( Debug.isOn("qint-model-debug") ){
- for( size_t i=0; i<fm->d_uf_terms[f].size(); i++ ){
- Node e = it->second->evaluate_n( fm, fm->d_uf_terms[f][i] );
- Debug("qint-model-debug") << fm->d_uf_terms[f][i] << " evaluates to " << e << std::endl;
- Assert( fm->areEqual( e, fm->d_uf_terms[f][i] ) );
- }
- }
- }
- }
-}
-
-
-//--------------------model checking---------------------------------------
-
-//do exhaustive instantiation
-bool QIntervalBuilder::doExhaustiveInstantiation( FirstOrderModel * fm, Node q, int effort ) {
- Trace("qint-check") << "exhaustive instantiation " << q << " " << effort << std::endl;
- if (effort==0) {
-
- FirstOrderModelQInt * fmqint = fm->asFirstOrderModelQInt();
- QIntDef qid;
- doCheck( fmqint, q, qid, q[1], fmqint->d_var_order[q]->d_var_occur );
- //now process entries
- Trace("qint-inst") << "Interpretation for " << q << " is : " << std::endl;
- qid.debugPrint( "qint-inst", fmqint, q );
- Trace("qint-inst") << std::endl;
- Debug("qint-check-debug2") << "Make iterator..." << std::endl;
- QIntDefIter qdi( fmqint, q, &qid );
- while( !qdi.isFinished() ){
- if( qdi.getValue()!=d_true ){
- Debug("qint-check-debug2") << "Set up vectors..." << std::endl;
- std::vector< Node > l;
- std::vector< Node > u;
- std::vector< Node > inst;
- qdi.getLowers( l );
- qdi.getUppers( u );
- Debug("qint-check-debug2") << "Get instantiation..." << std::endl;
- if( fmqint->d_var_order[q]->getInstantiation( fmqint, l, u, inst ) ){
- Trace("qint-inst") << "** Instantiate with ";
- //just add the instance
- for( unsigned j=0; j<inst.size(); j++) {
- Trace("qint-inst") << inst[j] << " ";
- }
- Trace("qint-inst") << std::endl;
- d_triedLemmas++;
- if( d_qe->addInstantiation( q, inst ) ){
- Trace("qint-inst") << " ...added instantiation." << std::endl;
- d_addedLemmas++;
- }else{
- Trace("qint-inst") << " ...duplicate instantiation" << std::endl;
- //verify that instantiation is witness for current entry
- if( Debug.isOn("qint-check-debug2") ){
- Debug("qint-check-debug2") << "Check if : ";
- std::vector< Node > exp_inst;
- for( unsigned i=0; i<fmqint->getOrderedNumVars( q ); i++ ){
- int index = fmqint->getOrderedVarNumToVarNum( q, i );
- exp_inst.push_back( inst[ index ] );
- Debug("qint-check-debug2") << inst[index] << " ";
- }
- Debug("qint-check-debug2") << " evaluates to " << qdi.getValue() << std::endl;
- Assert( qid.evaluate( fmqint, exp_inst )==qdi.getValue() );
- }
- }
- }else{
- Trace("qint-inst") << "** Spurious instantiation." << std::endl;
- }
- }
- qdi.increment();
- }
- }
- return true;
-}
-
-bool QIntervalBuilder::doCheck( FirstOrderModelQInt * m, Node q, QIntDef & qid, Node n,
- QIntVarNumIndex& vindex ) {
- Assert( n.getKind()!=FORALL );
- std::map< unsigned, QIntDef > children;
- std::map< unsigned, Node > bchildren;
- int varChCount = 0;
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- if( n[i].getKind()==FORALL ){
- bchildren[i] = Node::null();
- }else if( n[i].getKind() == BOUND_VARIABLE ){
- varChCount++;
- bchildren[i] = n[i];
- }else if( m->hasTerm( n[i] ) ){
- bchildren[i] = m->getUsedRepresentative( n[i] );
- }else{
- if( !doCheck( m, q, children[i], n[i], vindex.d_var_index[i] ) ){
- bchildren[i] = Node::null();
- }
- }
- }
- Trace("qint-check-debug") << "Compute Interpretation of " << n << " " << n.getKind() << std::endl;
- if( n.getKind() == APPLY_UF || n.getKind() == VARIABLE || n.getKind() == SKOLEM ){
- Node op = n.getKind() == APPLY_UF ? n.getOperator() : n;
- //uninterpreted compose
- qid.construct_compose( m, q, n, m->d_models[op], children, bchildren, varChCount, vindex );
- }else if( !qid.construct_compose( m, q, n, NULL, children, bchildren, varChCount, vindex ) ){
- Trace("qint-check-debug") << "** Cannot produce definition for " << n << std::endl;
- return false;
- }
- Trace("qint-check-debug2") << "Definition for " << n << " is : " << std::endl;
- qid.debugPrint("qint-check-debug2", m, q);
- qid.simplify( m, q );
- Trace("qint-check-debug") << "(Simplified) Definition for " << n << " is : " << std::endl;
- qid.debugPrint("qint-check-debug", m, q);
- Trace("qint-check-debug") << std::endl;
- Assert( qid.isTotal( m, q ) );
- return true;
-}
+/********************* */ +/*! \file qinterval_builder.cpp + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: none + ** 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 qinterval builder + **/ + + +#include "theory/quantifiers/qinterval_builder.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; + +//lower bound is exclusive +//upper bound is inclusive + +struct QIntSort +{ + FirstOrderModelQInt * m; + bool operator() (Node i, Node j) { + return m->isLessThan( i, j ); + } +}; + +void QIntDef::init_vec( FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u ) { + for( unsigned i=0; i<m->getOrderedNumVars( q ); i++ ){ + l.push_back( Node::null() ); + u.push_back( m->getMaximum( m->getOrderedVarType( q, i ) ) ); + } +} + +void QIntDef::debugPrint( const char * c, FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u ) +{ + Trace(c) << "( "; + for( unsigned i=0; i<l.size(); i++ ){ + if( i>0 ) Trace(c) << ", "; + //Trace(c) << l[i] << "..." << u[i]; + int lindex = l[i].isNull() ? 0 : m->getRepId( l[i] ) + 1; + int uindex = m->getRepId( u[i] ); + Trace(c) << lindex << "..." << uindex; + } + Trace(c) << " )"; +} + + +int QIntDef::getEvIndex( FirstOrderModelQInt * m, Node n, bool exc ) { + if( n.isNull() ){ + Assert( exc ); + return 0; + }else{ + int min = 0; + int max = (int)(d_def_order.size()-1); + while( min!=max ){ + int index = (min+max)/2; + Assert( index>=0 && index<(int)d_def_order.size() ); + if( n==d_def_order[index] ){ + max = index; + min = index; + }else if( m->isLessThan( n, d_def_order[index] ) ){ + max = index; + }else{ + min = index+1; + } + } + if( n==d_def_order[min] && exc ){ + min++; + } + Assert( min>=0 && min<(int)d_def_order.size() ); + if( ( min!=0 && !m->isLessThan( d_def_order[min-1], n ) && ( !exc || d_def_order[min-1]!=n ) ) || + ( ( exc || d_def_order[min]!=n ) && !m->isLessThan( n, d_def_order[min] ) ) ){ + Debug("qint-error") << "ERR size : " << d_def_order.size() << ", exc : " << exc << std::endl; + for( unsigned i=0; i<d_def_order.size(); i++ ){ + Debug("qint-error") << "ERR ch #" << i << " : " << d_def_order[i]; + Debug("qint-error") << " " << m->getRepId( d_def_order[i] ) << std::endl; + } + Debug("qint-error") << " : " << n << " " << min << " " << m->getRepId( n ) << std::endl; + } + + Assert( min==0 || m->isLessThan( d_def_order[min-1], n ) || ( exc && d_def_order[min-1]==n ) ); + Assert( ( !exc && n==d_def_order[min] ) || m->isLessThan( n, d_def_order[min] ) ); + return min; + } +} + +void QIntDef::addEntry( FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u, + Node v, unsigned depth ) { + if( depth==0 ){ + Trace("qint-compose-debug") << "Add entry "; + debugPrint( "qint-compose-debug", m, q, l, u ); + Trace("qint-compose-debug") << " -> " << v << "..." << std::endl; + } + //Assert( false ); + if( depth==u.size() ){ + Assert( d_def_order.empty() ); + Assert( v.isNull() || v.isConst() || ( v.getType().isSort() && m->getRepId( v )!=-1 ) ); + d_def_order.push_back( v ); + }else{ + /* + if( !d_def_order.empty() && + ( l[depth].isNull() || m->isLessThan( l[depth], d_def_order[d_def_order.size()-1] ) ) ){ + int startEvIndex = getEvIndex( m, l[depth], true ); + int endEvIndex; + if( m->isLessThan( u[depth], d_def_order[d_def_order.size()-1] ) ){ + endEvIndex = getEvIndex( m, u[depth] ); + }else{ + endEvIndex = d_def_order.size()-1; + } + Trace("qint-compose-debug2") << this << " adding for bounds " << l[depth] << "..." << u[depth] << std::endl; + for( int i=startEvIndex; i<=endEvIndex; i++ ){ + Trace("qint-compose-debug2") << this << " add entry " << d_def_order[i] << std::endl; + d_def[d_def_order[i]].addEntry( m, q, l, u, v, depth+1 ); + } + } + if( !d_def_order.empty() && + d_def.find(u[depth])==d_def.end() && + !m->isLessThan( d_def_order[d_def_order.size()-1], u[depth] ) ){ + Trace("qint-compose-debug2") << "Bad : depth : " << depth << std::endl; + } + Assert( d_def_order.empty() || + d_def.find(u[depth])!=d_def.end() || + m->isLessThan( d_def_order[d_def_order.size()-1], u[depth] ) ); + + if( d_def_order.empty() || m->isLessThan( d_def_order[d_def_order.size()-1], u[depth] ) ){ + Trace("qint-compose-debug2") << this << " add entry new : " << u[depth] << std::endl; + d_def_order.push_back( u[depth] ); + d_def[u[depth]].addEntry( m, q, l, u, v, depth+1 ); + } + */ + //%%%%%% + bool success = true; + int nnum = m->getVarOrder( q )->getNextNum( depth ); + Node pl; + Node pu; + if( nnum!=-1 ){ + Trace("qint-compose-debug2") << "...adding entry #" << depth << " is #" << nnum << std::endl; + //Assert( l[nnum].isNull() || l[nnum]==l[depth] || m->isLessThan( l[nnum], l[depth] ) ); + //Assert( u[nnum]==u[depth] || m->isLessThan( u[depth], u[nnum] ) ); + pl = l[nnum]; + pu = u[nnum]; + if( !m->doMeet( l[nnum], u[nnum], l[depth], u[depth], l[nnum], u[nnum] ) ){ + success = false; + } + } + //%%%%%% + if( success ){ + Node r = u[depth]; + if( d_def.find( r )!=d_def.end() ){ + d_def[r].addEntry( m, q, l, u, v, depth+1 ); + }else{ + if( !d_def_order.empty() && + !m->isLessThan( d_def_order[d_def_order.size()-1], u[depth] ) ){ + Trace("qint-compose-debug2") << "Bad : depth : " << depth << " "; + Trace("qint-compose-debug2") << d_def_order[d_def_order.size()-1] << " " << u[depth] << std::endl; + } + Assert( d_def_order.empty() || m->isLessThan( d_def_order[d_def_order.size()-1], r ) ); + d_def_order.push_back( r ); + d_def[r].addEntry( m, q, l, u, v, depth+1 ); + } + } + if( nnum!=-1 ){ + l[nnum] = pl; + u[nnum] = pu; + } + } +} + +Node QIntDef::simplify_r( FirstOrderModelQInt * m, Node q, std::vector< Node >& il, std::vector< Node >& iu, + unsigned depth ) { + if( d_def.empty() ){ + if( d_def_order.size()!=0 ){ + Debug("qint-error") << "Simplify, size = " << d_def_order.size() << std::endl; + } + Assert( d_def_order.size()==1 ); + return d_def_order[0]; + }else{ + Assert( !d_def_order.empty() ); + std::vector< Node > newDefs; + Node curr; + for( unsigned i=0; i<d_def_order.size(); i++ ){ + Node n = d_def[d_def_order[i]].simplify_r( m, q, il, iu, depth+1 ); + if( i>0 ){ + if( n==curr && !n.isNull() ){ + d_def.erase( d_def_order[i-1] ); + }else{ + newDefs.push_back( d_def_order[i-1] ); + } + } + curr = n; + } + newDefs.push_back( d_def_order[d_def_order.size()-1] ); + d_def_order.clear(); + d_def_order.insert( d_def_order.end(), newDefs.begin(), newDefs.end() ); + return d_def_order.size()==1 ? curr : Node::null(); + } +} + +Node QIntDef::simplify( FirstOrderModelQInt * m, Node q ) { + std::vector< Node > l; + std::vector< Node > u; + if( !q.isNull() ){ + //init_vec( m, q, l, u ); + } + return simplify_r( m, q, l, u, 0 ); +} + +bool QIntDef::isTotal_r( FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u, + unsigned depth ) { + if( d_def_order.empty() ){ + return false; + }else if( d_def.empty() ){ + return true; + }else{ + //get the current maximum + Node mx; + if( !q.isNull() ){ + int pnum = m->getVarOrder( q )->getPrevNum( depth ); + if( pnum!=-1 ){ + mx = u[pnum]; + } + } + if( mx.isNull() ){ + mx = m->getMaximum( d_def_order[d_def_order.size()-1].getType() ); + } + //if not current maximum + if( d_def_order[d_def_order.size()-1]!=mx ){ + return false; + }else{ + Node pu = u[depth]; + for( unsigned i=0; i<d_def_order.size(); i++ ){ + u[depth] = d_def_order[i]; + if( !d_def[d_def_order[i]].isTotal_r( m, q, l, u, depth+1 ) ){ + return false; + } + } + u[depth] = pu; + return true; + } + } +} + +bool QIntDef::isTotal( FirstOrderModelQInt * m, Node q ) { + std::vector< Node > l; + std::vector< Node > u; + if( !q.isNull() ){ + init_vec( m, q, l, u ); + } + return isTotal_r( m, q, l, u, 0 ); +} + +void QIntDef::construct_compose_r( FirstOrderModelQInt * m, Node q, + std::vector< Node >& l, std::vector< Node >& u, + Node n, QIntDef * f, + std::vector< Node >& args, + std::map< unsigned, QIntDef >& children, + std::map< unsigned, Node >& bchildren, + QIntVarNumIndex& vindex, unsigned depth ) { + //check for short circuit + if( !f ){ + if( !args.empty() ){ + if( ( n.getKind()==OR && args[args.size()-1]==m->d_true ) || + ( n.getKind()==AND && args[args.size()-1]==m->d_false ) ){ + addEntry( m, q, l, u, args[args.size()-1] ); + return; + } + } + } + + for( unsigned i=0; i<depth; i++ ) { Trace("qint-compose") << " "; } + Trace("qint-compose") << (f ? "U" : "I" ) << "C( "; + for( unsigned i=0; i<l.size(); i++ ){ + if( i>0 ) Trace("qint-compose") << ", "; + //Trace("qint-compose") << l[i] << "..." << u[i]; + int lindex = l[i].isNull() ? 0 : m->getRepId( l[i] ) + 1; + int uindex = m->getRepId( u[i] ); + Trace( "qint-compose" ) << lindex << "..." << uindex; + } + Trace("qint-compose") << " )..."; + + //finished? + if( ( f && f->d_def.empty() ) || args.size()==n.getNumChildren() ){ + if( f ){ + Assert( f->d_def_order.size()==1 ); + Trace("qint-compose") << "UVALUE(" << f->d_def_order[0] << ")" << std::endl; + addEntry( m, q, l, u, f->d_def_order[0] ); + }else{ + Node nn; + bool nnSet = false; + for( unsigned i=0; i<args.size(); i++ ){ + if( args[i].isNull() ){ + nnSet = true; + break; + } + } + if( !nnSet ){ + if( n.getKind()==EQUAL ){ + nn = NodeManager::currentNM()->mkConst( args[0]==args[1] ); + }else{ + //apply the operator to args + nn = NodeManager::currentNM()->mkNode( n.getKind(), args ); + nn = Rewriter::rewrite( nn ); + } + } + Trace("qint-compose") << "IVALUE(" << nn << ")" << std::endl; + addEntry( m, q, l, u, nn ); + Trace("qint-compose-debug2") << "...added entry." << std::endl; + } + }else{ + //if a non-simple child + if( children.find( depth )!=children.end() ){ + //*************************** + Trace("qint-compose") << "compound child, recurse" << std::endl; + std::vector< int > currIndex; + std::vector< int > endIndex; + std::vector< Node > prevL; + std::vector< Node > prevU; + std::vector< QIntDef * > visited; + do{ + Assert( currIndex.size()==visited.size() ); + + //populate the vectors + while( visited.size()<m->getOrderedNumVars( q ) ){ + unsigned i = visited.size(); + QIntDef * qq = visited.empty() ? &children[depth] : visited[i-1]->getChild( currIndex[i-1] ); + visited.push_back( qq ); + Node qq_mx = qq->getMaximum(); + Trace("qint-compose-debug2") << "...Get ev indices " << i << " " << l[i] << " " << u[i] << std::endl; + currIndex.push_back( qq->getEvIndex( m, l[i], true ) ); + Trace("qint-compose-debug2") << "...Done get curr index " << currIndex[currIndex.size()-1] << std::endl; + if( m->isLessThan( qq_mx, u[i] ) ){ + endIndex.push_back( qq->getNumChildren()-1 ); + }else{ + endIndex.push_back( qq->getEvIndex( m, u[i] ) ); + } + Trace("qint-compose-debug2") << "...Done get end index " << endIndex[endIndex.size()-1] << std::endl; + prevL.push_back( l[i] ); + prevU.push_back( u[i] ); + if( !m->doMeet( prevL[i], prevU[i], + qq->getLower( currIndex[i] ), qq->getUpper( currIndex[i] ), l[i], u[i] ) ){ + Assert( false ); + } + } + for( unsigned i=0; i<depth; i++ ) { Trace("qint-compose") << " "; } + for( unsigned i=0; i<currIndex.size(); i++ ){ + Trace("qint-compose") << "[" << currIndex[i] << "/" << endIndex[i] << "]"; + } + Trace("qint-compose") << std::endl; + //consider the current + int activeIndex = visited.size()-1; + QIntDef * qa = visited.empty() ? &children[depth] : visited[activeIndex]->getChild( currIndex[activeIndex] ); + if( f ){ + int fIndex = f->getEvIndex( m, qa->getValue() ); + construct_compose_r( m, q, l, u, n, f->getChild( fIndex ), args, children, bchildren, vindex, depth+1 ); + }else{ + args.push_back( qa->getValue() ); + construct_compose_r( m, q, l, u, n, f, args, children, bchildren, vindex, depth+1 ); + args.pop_back(); + } + + //increment the index (if possible) + while( activeIndex>=0 && currIndex[activeIndex]==endIndex[activeIndex] ){ + currIndex.pop_back(); + endIndex.pop_back(); + l[activeIndex] = prevL[activeIndex]; + u[activeIndex] = prevU[activeIndex]; + prevL.pop_back(); + prevU.pop_back(); + visited.pop_back(); + activeIndex--; + } + if( activeIndex>=0 ){ + for( unsigned i=0; i<depth; i++ ) { Trace("qint-compose") << " "; } + Trace("qint-compose-debug") << "Increment at " << activeIndex << std::endl; + currIndex[activeIndex]++; + if( !m->doMeet( prevL[activeIndex], prevU[activeIndex], + visited[activeIndex]->getLower( currIndex[activeIndex] ), + visited[activeIndex]->getUpper( currIndex[activeIndex] ), + l[activeIndex], u[activeIndex] ) ){ + Assert( false ); + } + } + }while( !visited.empty() ); + //*************************** + }else{ + Assert( bchildren.find( depth )!=bchildren.end() ); + Node v = bchildren[depth]; + if( f ){ + if( v.getKind()==BOUND_VARIABLE ){ + int vn = vindex.d_var_num[depth]; + Trace("qint-compose") << "variable #" << vn << ", recurse" << std::endl; + //int vn = m->getOrderedVarOccurId( q, n, depth ); + Trace("qint-compose-debug") << "-process " << v << ", which is var #" << vn << std::endl; + Node lprev = l[vn]; + Node uprev = u[vn]; + //restrict to last variable in order + int pnum = m->getVarOrder( q )->getPrevNum( vn ); + if( pnum!=-1 ){ + Trace("qint-compose-debug") << "-restrict to var #" << pnum << " " << l[pnum] << " " << u[pnum] << std::endl; + l[vn] = l[pnum]; + u[vn] = u[pnum]; + } + int startIndex = f->getEvIndex( m, l[vn], true ); + int endIndex = f->getEvIndex( m, u[vn] ); + Trace("qint-compose-debug") << "--will process " << startIndex << " " << endIndex << std::endl; + for( int i=startIndex; i<=endIndex; i++ ){ + if( m->doMeet( lprev, uprev, f->getLower( i ), f->getUpper( i ), l[vn], u[vn] ) ){ + construct_compose_r( m, q, l, u, n, f->getChild( i ), args, children, bchildren, vindex, depth+1 ); + }else{ + Assert( false ); + } + } + l[vn] = lprev; + u[vn] = uprev; + }else{ + Trace("qint-compose") << "value, recurse" << std::endl; + //simple + int ei = f->getEvIndex( m, v ); + construct_compose_r( m, q, l, u, n, f->getChild( ei ), args, children, bchildren, vindex, depth+1 ); + } + }else{ + Trace("qint-compose") << "value, recurse" << std::endl; + args.push_back( v ); + construct_compose_r( m, q, l, u, n, f, args, children, bchildren, vindex, depth+1 ); + args.pop_back(); + } + } + } +} + + +void QIntDef::construct_enum_r( FirstOrderModelQInt * m, Node q, unsigned vn, unsigned depth, Node v ) { + if( depth==m->getOrderedNumVars( q ) ){ + Assert( !v.isNull() ); + d_def_order.push_back( v ); + }else{ + TypeNode tn = m->getOrderedVarType( q, depth ); + //int vnum = m->getVarOrder( q )->getVar( depth )== + if( depth==vn ){ + for( unsigned i=0; i<m->d_rep_set.d_type_reps[tn].size(); i++ ){ + Node vv = m->d_rep_set.d_type_reps[tn][i]; + d_def_order.push_back( vv ); + d_def[vv].construct_enum_r( m, q, vn, depth+1, vv ); + } + }else if( m->getVarOrder( q )->getVar( depth )==m->getVarOrder( q )->getVar( vn ) && depth>vn ){ + d_def_order.push_back( v ); + d_def[v].construct_enum_r( m, q, vn, depth+1, v ); + }else{ + Node mx = m->getMaximum( tn ); + d_def_order.push_back( mx ); + d_def[mx].construct_enum_r( m, q, vn, depth+1, v ); + } + } +} + +bool QIntDef::construct_enum( FirstOrderModelQInt * m, Node q, unsigned vn ) { + TypeNode tn = m->getOrderedVarType( q, vn ); + if( tn.isSort() ){ + construct_enum_r( m, q, vn, 0, Node::null() ); + return true; + }else{ + return false; + } +} + +bool QIntDef::construct_compose( FirstOrderModelQInt * m, Node q, Node n, QIntDef * f, + std::map< unsigned, QIntDef >& children, + std::map< unsigned, Node >& bchildren, int varChCount, + QIntVarNumIndex& vindex ) { + Trace("qint-compose") << "Do " << (f ? "uninterpreted" : "interpreted"); + Trace("qint-compose") << " compose, var count = " << varChCount << "..." << std::endl; + std::vector< Node > l; + std::vector< Node > u; + init_vec( m, q, l, u ); + if( varChCount==0 || f ){ + //standard (no variable child) interpreted compose, or uninterpreted compose + std::vector< Node > args; + construct_compose_r( m, q, l, u, n, f, args, children, bchildren, vindex, 0 ); + }else{ + //special cases + bool success = false; + int varIndex = ( bchildren.find( 0 )!=bchildren.end() && bchildren[0].getKind()==BOUND_VARIABLE ) ? 0 : 1; + if( varChCount>1 ){ + if( n.getKind()==EQUAL ){ + //make it an enumeration + unsigned vn = vindex.d_var_num[0]; + if( children[0].construct_enum( m, q, vn ) ){ + bchildren.erase( 0 ); + varIndex = 1; + success = true; + } + } + }else{ + success = n.getKind()==EQUAL; + } + if( success ){ + int oIndex = varIndex==0 ? 1 : 0; + Node v = bchildren[varIndex]; + unsigned vn = vindex.d_var_num[varIndex]; + if( children.find( oIndex )==children.end() ){ + Assert( bchildren.find( oIndex )!=bchildren.end() ); + Node at = bchildren[oIndex]; + Trace("qint-icompose") << "Basic child, " << at << " with var " << v << std::endl; + Node prev = m->getPrev( bchildren[oIndex].getType(), bchildren[oIndex] ); + Node above = u[vn]; + if( !prev.isNull() ){ + u[vn] = prev; + addEntry( m, q, l, u, NodeManager::currentNM()->mkConst( false ) ); + } + l[vn] = prev; + u[vn] = at; + addEntry( m, q, l, u, NodeManager::currentNM()->mkConst( true ) ); + if( at!=above ){ + l[vn] = at; + u[vn] = above; + addEntry( m, q, l, u, NodeManager::currentNM()->mkConst( false ) ); + } + }else{ + QIntDef * qid = &children[oIndex]; + qid->debugPrint("qint-icompose", m, q ); + Trace("qint-icompose") << " against variable..." << v << ", which is var #" << vn << std::endl; + + TypeNode tn = v.getType(); + QIntDefIter qdi( m, q, qid ); + while( !qdi.isFinished() ){ + std::vector< Node > us; + qdi.getUppers( us ); + std::vector< Node > ls; + qdi.getLowers( ls ); + qdi.debugPrint( "qint-icompose" ); + + Node n_below = ls[vn]; + Node n_prev = m->getPrev( tn, qdi.getValue() ); + Node n_at = qdi.getValue(); + Node n_above = us[vn]; + Trace("qint-icompose") << n_below << " < " << n_prev << " < " << n_at << " < " << n_above << std::endl; + if( n.getKind()==EQUAL ){ + bool atLtAbove = m->isLessThan( n_at, n_above ); + Node currL = n_below; + if( n_at==n_above || atLtAbove ){ + //add for value (at-1) + if( !n_prev.isNull() && ( n_below.isNull() || m->isLessThan( n_below, n_prev ) ) ){ + ls[vn] = currL; + us[vn] = n_prev; + currL = n_prev; + Trace("qint-icompose") << "-add entry(-) at " << ls[vn] << "..." << us[vn] << std::endl; + addEntry( m, q, ls, us, NodeManager::currentNM()->mkConst( false ) ); + } + //add for value (at) + if( ( n_below.isNull() || m->isLessThan( n_below, n_at ) ) && atLtAbove ){ + ls[vn] = currL; + us[vn] = n_at; + currL = n_at; + Trace("qint-icompose") << "-add entry(=) at " << ls[vn] << "..." << us[vn] << std::endl; + addEntry( m, q, ls, us, NodeManager::currentNM()->mkConst( true ) ); + } + } + ls[vn] = currL; + us[vn] = n_above; + Trace("qint-icompose") << "-add entry(+) at " << ls[vn] << "..." << us[vn] << std::endl; + addEntry( m, q, ls, us, NodeManager::currentNM()->mkConst( n_at==n_above ) ); + }else{ + return false; + } + qdi.increment(); + + Trace("qint-icompose-debug") << "Now : " << std::endl; + debugPrint("qint-icompose-debug", m, q ); + Trace("qint-icompose-debug") << std::endl; + } + } + + Trace("qint-icompose") << "Result : " << std::endl; + debugPrint("qint-icompose", m, q ); + Trace("qint-icompose") << std::endl; + + }else{ + return false; + } + } + Trace("qint-compose") << "Done i-compose" << std::endl; + return true; +} + + +void QIntDef::construct( FirstOrderModelQInt * m, std::vector< Node >& fapps, unsigned depth ) { + d_def.clear(); + d_def_order.clear(); + Assert( !fapps.empty() ); + if( depth==fapps[0].getNumChildren() ){ + //get representative in model for this term + Assert( fapps.size()>=1 ); + Node r = m->getUsedRepresentative( fapps[0] ); + d_def_order.push_back( r ); + }else{ + std::map< Node, std::vector< Node > > fapp_child; + //partition based on evaluations of fapps[1][depth]....fapps[n][depth] + for( unsigned i=0; i<fapps.size(); i++ ){ + Node r = m->getUsedRepresentative( fapps[i][depth] ); + fapp_child[r].push_back( fapps[i] ); + } + //sort by QIntSort + for( std::map< Node, std::vector< Node > >::iterator it = fapp_child.begin(); it != fapp_child.end(); ++it ){ + d_def_order.push_back( it->first ); + } + QIntSort qis; + qis.m = m; + std::sort( d_def_order.begin(), d_def_order.end(), qis ); + //construct children + for( unsigned i=0; i<d_def_order.size(); i++ ){ + Node n = d_def_order[i]; + if( i==d_def_order.size()-1 ){ + d_def_order[i] = m->getMaximum( d_def_order[i].getType() ); + } + Debug("qint-model-debug2") << "Construct for " << n << ", terms = " << fapp_child[n].size() << std::endl; + d_def[d_def_order[i]].construct( m, fapp_child[n], depth+1 ); + } + } +} + +Node QIntDef::getFunctionValue( FirstOrderModelQInt * m, std::vector< Node >& vars, unsigned depth ) { + if( d_def.empty() ){ + Assert( d_def_order.size()==1 ); + //must convert to actual domain constant + if( d_def_order[0].getType().isSort() ){ + return m->d_rep_set.d_type_reps[ d_def_order[0].getType() ][ m->getRepId( d_def_order[0] ) ]; + }else{ + return m->getUsedRepresentative( d_def_order[0] ); + } + }else{ + TypeNode tn = vars[depth].getType(); + Node curr; + int rep_id = m->d_rep_set.getNumRepresentatives( tn ); + for( int i=(int)(d_def_order.size()-1); i>=0; i-- ){ + int curr_rep_id = i==0 ? 0 : m->getRepId( d_def_order[i-1] )+1; + Node ccurr = d_def[d_def_order[i]].getFunctionValue( m, vars, depth+1 ); + if( curr.isNull() ){ + curr = ccurr; + }else{ + std::vector< Node > c; + Assert( curr_rep_id<rep_id ); + for( int j=curr_rep_id; j<rep_id; j++ ){ + c.push_back( vars[depth].eqNode( m->d_rep_set.d_type_reps[tn][j] ) ); + } + Node cond = c.size()==1 ? c[0] : NodeManager::currentNM()->mkNode( OR, c ); + curr = NodeManager::currentNM()->mkNode( ITE, cond, ccurr, curr ); + } + rep_id = curr_rep_id; + } + return curr; + } +} + +Node QIntDef::evaluate_r( FirstOrderModelQInt * m, std::vector< Node >& reps, unsigned depth ) { + if( depth==reps.size() ){ + Assert( d_def_order.size()==1 ); + return d_def_order[0]; + }else{ + if( d_def.find( reps[depth] )!=d_def.end() ){ + return d_def[reps[depth]].evaluate_r( m, reps, depth+1 ); + }else{ + int ei = getEvIndex( m, reps[depth] ); + return d_def[d_def_order[ei]].evaluate_r( m, reps, depth+1 ); + } + } +} +Node QIntDef::evaluate_n_r( FirstOrderModelQInt * m, Node n, unsigned depth ) { + if( depth==n.getNumChildren() ){ + Assert( d_def_order.size()==1 ); + return d_def_order[0]; + }else{ + Node r = m->getUsedRepresentative( n[depth] ); + if( d_def.find( r )!=d_def.end() ){ + return d_def[r].evaluate_n_r( m, n, depth+1 ); + }else{ + int ei = getEvIndex( m, r ); + return d_def[d_def_order[ei]].evaluate_n_r( m, n, depth+1 ); + } + } +} + + + +QIntDef * QIntDef::getChild( unsigned i ) { + Assert( i<d_def_order.size() ); + Assert( d_def.find( d_def_order[i] )!=d_def.end() ); + return &d_def[ d_def_order[i] ]; +} + +void QIntDef::debugPrint( const char * c, FirstOrderModelQInt * m, Node q, int t ) { + /* + for( unsigned i=0; i<d_def_order.size(); i++ ){ + for( int j=0; j<t; j++ ) { Trace(c) << " "; } + //Trace(c) << this << " "; + Trace(c) << d_def_order[i] << " : " << std::endl; + if( d_def.find( d_def_order[i] )!=d_def.end() ){ + d_def[d_def_order[i]].debugPrint( c, m, t+1 ); + } + } + */ + //if( t==0 ){ + QIntDefIter qdi( m, q, this ); + while( !qdi.isFinished() ){ + qdi.debugPrint( c, t ); + qdi.increment(); + } + //} +} + + +QIntDefIter::QIntDefIter( FirstOrderModelQInt * m, Node q, QIntDef * qid ) : d_fm( m ), d_q( q ){ + resetIndex( qid ); +} + +void QIntDefIter::debugPrint( const char * c, int t ) { + //Trace( c ) << getSize() << " " << d_index_visited.size() << " "; + for( int j=0; j<t; j++ ) { Trace(c) << " "; } + std::vector< Node > l; + std::vector< Node > u; + getLowers( l ); + getUppers( u ); + QIntDef::debugPrint( c, d_fm, d_q, l, u ); + Trace( c ) << " -> " << getValue() << std::endl; +} + +void QIntDefIter::resetIndex( QIntDef * qid ){ + //std::cout << "check : " << qid << " " << qid->d_def_order.size() << " " << qid->d_def.size() << std::endl; + if( !qid->d_def.empty() ){ + //std::cout << "add to visited " << qid << std::endl; + d_index.push_back( 0 ); + d_index_visited.push_back( qid ); + resetIndex( qid->getChild( 0 ) ); + } +} + +bool QIntDefIter::increment( int index ) { + if( !isFinished() ){ + index = index==-1 ? (int)(d_index.size()-1) : index; + while( (int)(d_index.size()-1)>index ){ + //std::cout << "remove from visit 1 " << std::endl; + d_index.pop_back(); + d_index_visited.pop_back(); + } + while( index>=0 && d_index[index]>=(int)(d_index_visited[index]->d_def_order.size()-1) ){ + //std::cout << "remove from visit " << d_index_visited[ d_index_visited.size()-1 ] << std::endl; + d_index.pop_back(); + d_index_visited.pop_back(); + index--; + } + if( index>=0 ){ + //std::cout << "increment at index = " << index << std::endl; + d_index[index]++; + resetIndex( d_index_visited[index]->getChild( d_index[index] ) ); + return true; + }else{ + d_index.clear(); + return false; + } + }else{ + return false; + } +} + +Node QIntDefIter::getLower( int index ) { + if( d_index[index]==0 && !d_q.isNull() ){ + int pnum = d_fm->getVarOrder( d_q )->getPrevNum( index ); + if( pnum!=-1 ){ + return getLower( pnum ); + } + } + return d_index_visited[index]->getLower( d_index[index] ); +} + +Node QIntDefIter::getUpper( int index ) { + return d_index_visited[index]->getUpper( d_index[index] ); +} + +void QIntDefIter::getLowers( std::vector< Node >& reps ) { + for( unsigned i=0; i<getSize(); i++ ){ + bool added = false; + if( d_index[i]==0 && !d_q.isNull() ){ + int pnum = d_fm->getVarOrder( d_q )->getPrevNum( i ); + if( pnum!=-1 ){ + added = true; + reps.push_back( reps[pnum] ); + } + } + if( !added ){ + reps.push_back( getLower( i ) ); + } + } +} + +void QIntDefIter::getUppers( std::vector< Node >& reps ) { + for( unsigned i=0; i<getSize(); i++ ){ + reps.push_back( getUpper( i ) ); + } +} + +Node QIntDefIter::getValue() { + return d_index_visited[ d_index_visited.size()-1 ]->getChild( d_index[d_index.size()-1] )->getValue(); +} + + +//------------------------variable ordering---------------------------- + +QuantVarOrder::QuantVarOrder( Node q ) : d_q( q ) { + d_var_count = 0; + initialize( q[1], 0, d_var_occur ); +} + +int QuantVarOrder::initialize( Node n, int minVarIndex, QIntVarNumIndex& vindex ) { + if( n.getKind()!=FORALL ){ + //std::vector< Node > vars; + //std::vector< int > args; + int procVarOn = n.getKind()==APPLY_UF ? 0 : 1; + for( int r=0; r<=procVarOn; r++ ){ + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + if( n[i].getKind()==BOUND_VARIABLE && r==procVarOn ){ + int occ_index = -1; + for( unsigned j=0; j<d_var_to_num[n[i]].size(); j++ ){ + if( d_var_to_num[n[i]][j]>=minVarIndex ){ + occ_index = d_var_to_num[n[i]][j]; + } + } + if( occ_index==-1 ){ + //need to assign new + d_num_to_var[d_var_count] = n[i]; + if( !d_var_to_num[n[i]].empty() ){ + int v = d_var_to_num[n[i]][ d_var_to_num[n[i]].size()-1 ]; + d_num_to_prev_num[ d_var_count ] = v; + d_num_to_next_num[ v ] = d_var_count; + } + d_var_num_index[ d_var_count ] = d_var_to_num[n[i]].size(); + d_var_to_num[n[i]].push_back( d_var_count ); + occ_index = d_var_count; + d_var_count++; + } + vindex.d_var_num[i] = occ_index; + minVarIndex = occ_index; + }else if( r==0 ){ + minVarIndex = initialize( n[i], minVarIndex, vindex.d_var_index[i] ); + } + } + } + } + return minVarIndex; +} + +bool QuantVarOrder::getInstantiation( FirstOrderModelQInt * m, std::vector< Node >& l, std::vector< Node >& u, + std::vector< Node >& inst ) { + Debug("qint-var-order-debug2") << "Get for " << d_q << " " << l.size() << " " << u.size() << std::endl; + for( unsigned i=0; i<d_q[0].getNumChildren(); i++ ){ + Debug("qint-var-order-debug2") << "Get for " << d_q[0][i] << " " << d_var_to_num[d_q[0][i]].size() << std::endl; + Node ll = Node::null(); + Node uu = m->getMaximum( d_q[0][i].getType() ); + for( unsigned j=0; j<d_var_to_num[d_q[0][i]].size(); j++ ){ + Debug("qint-var-order-debug2") << "Go " << j << std::endl; + Node cl = ll; + Node cu = uu; + int index = d_var_to_num[d_q[0][i]][j]; + Debug("qint-var-order-debug2") << "Do meet for " << index << "..." << std::endl; + Debug("qint-var-order-debug2") << l[index] << " " << u[index] << " " << cl << " " << cu << std::endl; + if( !m->doMeet( l[index], u[index], cl, cu, ll, uu ) ){ + Debug("qint-var-order-debug2") << "FAILED" << std::endl; + return false; + } + Debug("qint-var-order-debug2") << "Result : " << ll << " " << uu << std::endl; + } + Debug("qint-var-order-debug2") << "Got " << uu << std::endl; + inst.push_back( uu ); + } + return true; +} + +void QuantVarOrder::debugPrint( const char * c ) { + Trace( c ) << "Variable order for " << d_q << " is : " << std::endl; + debugPrint( c, d_q[1], d_var_occur ); + Trace( c ) << std::endl; + for( unsigned i=0; i<d_q[0].getNumChildren(); i++ ){ + Trace( c ) << d_q[0][i] << " : "; + for( unsigned j=0; j<d_var_to_num[d_q[0][i]].size(); j++ ){ + Trace( c ) << d_var_to_num[d_q[0][i]][j] << " "; + } + Trace( c ) << std::endl; + } +} + +void QuantVarOrder::debugPrint( const char * c, Node n, QIntVarNumIndex& vindex ) { + if( n.getKind()==FORALL ){ + Trace(c) << "NESTED_QUANT"; + }else{ + Trace(c) << n.getKind() << "("; + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + if( i>0 ) Trace( c ) << ","; + Trace( c ) << " "; + if( n[i].getKind()==BOUND_VARIABLE ){ + Trace(c) << "VAR[" << vindex.d_var_num[i] << "]"; + }else{ + debugPrint( c, n[i], vindex.d_var_index[i] ); + } + if( i==n.getNumChildren()-1 ) Trace( c ) << " "; + } + Trace(c) << ")"; + } +} + +QIntervalBuilder::QIntervalBuilder( context::Context* c, QuantifiersEngine* qe ) : +QModelBuilder( c, qe ){ + d_true = NodeManager::currentNM()->mkConst( true ); +} + + +//------------------------model construction---------------------------- + +void QIntervalBuilder::processBuildModel(TheoryModel* m, bool fullModel) { + Trace("fmf-qint-debug") << "process build model " << fullModel << std::endl; + FirstOrderModel* f = (FirstOrderModel*)m; + FirstOrderModelQInt* fm = f->asFirstOrderModelQInt(); + if( fullModel ){ + Trace("qint-model") << "Construct model representation..." << std::endl; + //make function values + for( std::map<Node, QIntDef * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) { + if( it->first.getType().getNumChildren()>1 ){ + Trace("qint-model") << "Construct for " << it->first << "..." << std::endl; + m->d_uf_models[ it->first ] = fm->getFunctionValue( it->first, "$x" ); + } + } + TheoryEngineModelBuilder::processBuildModel( m, fullModel ); + //mark that the model has been set + fm->markModelSet(); + //debug the model + debugModel( fm ); + }else{ + fm->initialize( d_considerAxioms ); + //process representatives + fm->d_rep_id.clear(); + fm->d_max.clear(); + fm->d_min.clear(); + Trace("qint-model") << std::endl << "Making representatives..." << std::endl; + for( std::map< TypeNode, std::vector< Node > >::iterator it = fm->d_rep_set.d_type_reps.begin(); + it != fm->d_rep_set.d_type_reps.end(); ++it ){ + if( it->first.isSort() ){ + if( it->second.empty() ){ + std::cout << "Empty rep for " << it->first << std::endl; + exit(0); + } + Trace("qint-model") << "Representatives for " << it->first << " : " << std::endl; + for( unsigned i=0; i<it->second.size(); i++ ){ + Trace("qint-model") << i << " : " << it->second[i] << std::endl; + fm->d_rep_id[it->second[i]] = i; + } + fm->d_min[it->first] = it->second[0]; + fm->d_max[it->first] = it->second[it->second.size()-1]; + }else{ + //TODO: enumerate? + } + } + Trace("qint-model") << std::endl << "Making function definitions..." << std::endl; + //construct the models for functions + for( std::map<Node, QIntDef * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) { + Node f = it->first; + Trace("qint-model-debug") << "Building Model for " << f << std::endl; + //reset the model + //get all (non-redundant) f-applications + std::vector< Node > fapps; + Trace("qint-model-debug") << "Initial terms: " << std::endl; + for( size_t i=0; i<fm->d_uf_terms[f].size(); i++ ){ + Node n = fm->d_uf_terms[f][i]; + if( !n.getAttribute(NoMatchAttribute()) ){ + Trace("qint-model-debug") << " " << n << std::endl; + fapps.push_back( n ); + } + } + if( fapps.empty() ){ + //choose arbitrary value + Node mbt = d_qe->getTermDatabase()->getModelBasisOpTerm(f); + Trace("qint-model-debug") << "Initial terms empty, add " << mbt << std::endl; + fapps.push_back( mbt ); + } + //construct the interval model + it->second->construct( fm, fapps ); + Trace("qint-model-debug") << "Definition for " << f << " : " << std::endl; + it->second->debugPrint("qint-model-debug", fm, Node::null() ); + + it->second->simplify( fm, Node::null() ); + Trace("qint-model") << "(Simplified) definition for " << f << " : " << std::endl; + it->second->debugPrint("qint-model", fm, Node::null() ); + + if( Debug.isOn("qint-model-debug") ){ + for( size_t i=0; i<fm->d_uf_terms[f].size(); i++ ){ + Node e = it->second->evaluate_n( fm, fm->d_uf_terms[f][i] ); + Debug("qint-model-debug") << fm->d_uf_terms[f][i] << " evaluates to " << e << std::endl; + Assert( fm->areEqual( e, fm->d_uf_terms[f][i] ) ); + } + } + } + } +} + + +//--------------------model checking--------------------------------------- + +//do exhaustive instantiation +bool QIntervalBuilder::doExhaustiveInstantiation( FirstOrderModel * fm, Node q, int effort ) { + Trace("qint-check") << "exhaustive instantiation " << q << " " << effort << std::endl; + if (effort==0) { + + FirstOrderModelQInt * fmqint = fm->asFirstOrderModelQInt(); + QIntDef qid; + doCheck( fmqint, q, qid, q[1], fmqint->d_var_order[q]->d_var_occur ); + //now process entries + Trace("qint-inst") << "Interpretation for " << q << " is : " << std::endl; + qid.debugPrint( "qint-inst", fmqint, q ); + Trace("qint-inst") << std::endl; + Debug("qint-check-debug2") << "Make iterator..." << std::endl; + QIntDefIter qdi( fmqint, q, &qid ); + while( !qdi.isFinished() ){ + if( qdi.getValue()!=d_true ){ + Debug("qint-check-debug2") << "Set up vectors..." << std::endl; + std::vector< Node > l; + std::vector< Node > u; + std::vector< Node > inst; + qdi.getLowers( l ); + qdi.getUppers( u ); + Debug("qint-check-debug2") << "Get instantiation..." << std::endl; + if( fmqint->d_var_order[q]->getInstantiation( fmqint, l, u, inst ) ){ + Trace("qint-inst") << "** Instantiate with "; + //just add the instance + for( unsigned j=0; j<inst.size(); j++) { + Trace("qint-inst") << inst[j] << " "; + } + Trace("qint-inst") << std::endl; + d_triedLemmas++; + if( d_qe->addInstantiation( q, inst ) ){ + Trace("qint-inst") << " ...added instantiation." << std::endl; + d_addedLemmas++; + }else{ + Trace("qint-inst") << " ...duplicate instantiation" << std::endl; + //verify that instantiation is witness for current entry + if( Debug.isOn("qint-check-debug2") ){ + Debug("qint-check-debug2") << "Check if : "; + std::vector< Node > exp_inst; + for( unsigned i=0; i<fmqint->getOrderedNumVars( q ); i++ ){ + int index = fmqint->getOrderedVarNumToVarNum( q, i ); + exp_inst.push_back( inst[ index ] ); + Debug("qint-check-debug2") << inst[index] << " "; + } + Debug("qint-check-debug2") << " evaluates to " << qdi.getValue() << std::endl; + Assert( qid.evaluate( fmqint, exp_inst )==qdi.getValue() ); + } + } + }else{ + Trace("qint-inst") << "** Spurious instantiation." << std::endl; + } + } + qdi.increment(); + } + } + return true; +} + +bool QIntervalBuilder::doCheck( FirstOrderModelQInt * m, Node q, QIntDef & qid, Node n, + QIntVarNumIndex& vindex ) { + Assert( n.getKind()!=FORALL ); + std::map< unsigned, QIntDef > children; + std::map< unsigned, Node > bchildren; + int varChCount = 0; + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + if( n[i].getKind()==FORALL ){ + bchildren[i] = Node::null(); + }else if( n[i].getKind() == BOUND_VARIABLE ){ + varChCount++; + bchildren[i] = n[i]; + }else if( m->hasTerm( n[i] ) ){ + bchildren[i] = m->getUsedRepresentative( n[i] ); + }else{ + if( !doCheck( m, q, children[i], n[i], vindex.d_var_index[i] ) ){ + bchildren[i] = Node::null(); + } + } + } + Trace("qint-check-debug") << "Compute Interpretation of " << n << " " << n.getKind() << std::endl; + if( n.getKind() == APPLY_UF || n.getKind() == VARIABLE || n.getKind() == SKOLEM ){ + Node op = n.getKind() == APPLY_UF ? n.getOperator() : n; + //uninterpreted compose + qid.construct_compose( m, q, n, m->d_models[op], children, bchildren, varChCount, vindex ); + }else if( !qid.construct_compose( m, q, n, NULL, children, bchildren, varChCount, vindex ) ){ + Trace("qint-check-debug") << "** Cannot produce definition for " << n << std::endl; + return false; + } + Trace("qint-check-debug2") << "Definition for " << n << " is : " << std::endl; + qid.debugPrint("qint-check-debug2", m, q); + qid.simplify( m, q ); + Trace("qint-check-debug") << "(Simplified) Definition for " << n << " is : " << std::endl; + qid.debugPrint("qint-check-debug", m, q); + Trace("qint-check-debug") << std::endl; + Assert( qid.isTotal( m, q ) ); + return true; +} diff --git a/src/theory/quantifiers/qinterval_builder.h b/src/theory/quantifiers/qinterval_builder.h index 8f48776cc..6ec17756c 100755 --- a/src/theory/quantifiers/qinterval_builder.h +++ b/src/theory/quantifiers/qinterval_builder.h @@ -1,155 +1,155 @@ -/********************* */
-/*! \file qinterval_builder.h
- ** \verbatim
- ** Original author: Andrew Reynolds
- ** Major contributors: none
- ** 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 qinterval model class
- **/
-
-#include "cvc4_private.h"
-
-#ifndef QINTERVAL_BUILDER
-#define QINTERVAL_BUILDER
-
-#include "theory/quantifiers/model_builder.h"
-#include "theory/quantifiers/first_order_model.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-class FirstOrderModelQInt;
-
-class QIntVarNumIndex
-{
-public:
- std::map< int, int > d_var_num;
- std::map< int, QIntVarNumIndex > d_var_index;
-};
-
-class QIntDef
-{
-private:
- Node evaluate_r( FirstOrderModelQInt * m, std::vector< Node >& reps, unsigned depth );
- Node evaluate_n_r( FirstOrderModelQInt * m, Node n, unsigned depth );
- void construct_compose_r( FirstOrderModelQInt * m, Node q,
- std::vector< Node >& l, std::vector< Node >& u, Node n, QIntDef * f,
- std::vector< Node >& args,
- std::map< unsigned, QIntDef >& children,
- std::map< unsigned, Node >& bchildren,
- QIntVarNumIndex& vindex,
- unsigned depth );
-
- void construct_enum_r( FirstOrderModelQInt * m, Node q, unsigned vn, unsigned depth, Node v );
- int getEvIndex( FirstOrderModelQInt * m, Node n, bool exc = false );
- void addEntry( FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u,
- Node v, unsigned depth = 0 );
- Node simplify_r( FirstOrderModelQInt * m, Node q, std::vector< Node >& il, std::vector< Node >& iu,
- unsigned depth );
- bool isTotal_r( FirstOrderModelQInt * m, Node q, std::vector< Node >& il, std::vector< Node >& iu,
- unsigned depth );
-public:
- QIntDef(){}
- std::map< Node, QIntDef > d_def;
- std::vector< Node > d_def_order;
-
- void construct( FirstOrderModelQInt * m, std::vector< Node >& fapps, unsigned depth = 0 );
- bool construct_compose( FirstOrderModelQInt * m, Node q, Node n, QIntDef * f,
- std::map< unsigned, QIntDef >& children,
- std::map< unsigned, Node >& bchildren, int varChCount,
- QIntVarNumIndex& vindex );
- bool construct_enum( FirstOrderModelQInt * m, Node q, unsigned vn );
-
- Node evaluate( FirstOrderModelQInt * m, std::vector< Node >& reps ) { return evaluate_r( m, reps, 0 ); }
- Node evaluate_n( FirstOrderModelQInt * m, Node n ) { return evaluate_n_r( m, n, 0 ); }
-
- void debugPrint( const char * c, FirstOrderModelQInt * m, Node q, int t = 0 );
- QIntDef * getChild( unsigned i );
- Node getValue() { return d_def_order[0]; }
- Node getLower( unsigned i ) { return i==0 ? Node::null() : d_def_order[i-1]; }
- Node getUpper( unsigned i ) { return d_def_order[i]; }
- Node getMaximum() { return d_def_order.empty() ? Node::null() : getUpper( d_def_order.size()-1 ); }
- int getNumChildren() { return d_def_order.size(); }
- bool isTotal( FirstOrderModelQInt * m, Node q );
-
- Node simplify( FirstOrderModelQInt * m, Node q );
- Node getFunctionValue( FirstOrderModelQInt * m, std::vector< Node >& vars, unsigned depth = 0 );
-
- static void init_vec( FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u );
- static void debugPrint( const char * c, FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u );
-};
-
-class QIntDefIter {
-private:
- FirstOrderModelQInt * d_fm;
- Node d_q;
- void resetIndex( QIntDef * qid );
-public:
- QIntDefIter( FirstOrderModelQInt * m, Node q, QIntDef * qid );
- void debugPrint( const char * c, int t = 0 );
- std::vector< QIntDef * > d_index_visited;
- std::vector< int > d_index;
- bool isFinished() { return d_index.empty(); }
- bool increment( int index = -1 );
- unsigned getSize() { return d_index.size(); }
- Node getLower( int index );
- Node getUpper( int index );
- void getLowers( std::vector< Node >& reps );
- void getUppers( std::vector< Node >& reps );
- Node getValue();
-};
-
-
-class QuantVarOrder
-{
-private:
- int initialize( Node n, int minVarIndex, QIntVarNumIndex& vindex );
- int d_var_count;
- Node d_q;
- void debugPrint( const char * c, Node n, QIntVarNumIndex& vindex );
-public:
- QuantVarOrder( Node q );
- std::map< int, Node > d_num_to_var;
- std::map< int, int > d_num_to_prev_num;
- std::map< int, int > d_num_to_next_num;
- std::map< Node, std::vector< int > > d_var_to_num;
- std::map< int, int > d_var_num_index;
- //std::map< Node, std::map< int, int > > d_var_occur;
- //int getVarNum( Node n, int arg ) { return d_var_occur[n][arg]; }
- unsigned getNumVars() { return d_var_count; }
- Node getVar( int i ) { return d_num_to_var[i]; }
- int getPrevNum( int i ) { return d_num_to_prev_num.find( i )!=d_num_to_prev_num.end() ? d_num_to_prev_num[i] : -1; }
- int getNextNum( int i ) { return d_num_to_next_num.find( i )!=d_num_to_next_num.end() ? d_num_to_next_num[i] : -1; }
- int getVarNumIndex( int i ) { return d_var_num_index[i]; }
- bool getInstantiation( FirstOrderModelQInt * m, std::vector< Node >& l, std::vector< Node >& u,
- std::vector< Node >& inst );
- void debugPrint( const char * c );
- QIntVarNumIndex d_var_occur;
-};
-
-class QIntervalBuilder : public QModelBuilder
-{
-private:
- Node d_true;
- bool doCheck( FirstOrderModelQInt * m, Node q, QIntDef & qid, Node n,
- QIntVarNumIndex& vindex );
-public:
- QIntervalBuilder( context::Context* c, QuantifiersEngine* qe );
- //process build model
- void processBuildModel(TheoryModel* m, bool fullModel);
- //do exhaustive instantiation
- bool doExhaustiveInstantiation( FirstOrderModel * fm, Node q, int effort );
-};
-
-
-}
-}
-}
-
+/********************* */ +/*! \file qinterval_builder.h + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: none + ** 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 qinterval model class + **/ + +#include "cvc4_private.h" + +#ifndef QINTERVAL_BUILDER +#define QINTERVAL_BUILDER + +#include "theory/quantifiers/model_builder.h" +#include "theory/quantifiers/first_order_model.h" + +namespace CVC4 { +namespace theory { +namespace quantifiers { + +class FirstOrderModelQInt; + +class QIntVarNumIndex +{ +public: + std::map< int, int > d_var_num; + std::map< int, QIntVarNumIndex > d_var_index; +}; + +class QIntDef +{ +private: + Node evaluate_r( FirstOrderModelQInt * m, std::vector< Node >& reps, unsigned depth ); + Node evaluate_n_r( FirstOrderModelQInt * m, Node n, unsigned depth ); + void construct_compose_r( FirstOrderModelQInt * m, Node q, + std::vector< Node >& l, std::vector< Node >& u, Node n, QIntDef * f, + std::vector< Node >& args, + std::map< unsigned, QIntDef >& children, + std::map< unsigned, Node >& bchildren, + QIntVarNumIndex& vindex, + unsigned depth ); + + void construct_enum_r( FirstOrderModelQInt * m, Node q, unsigned vn, unsigned depth, Node v ); + int getEvIndex( FirstOrderModelQInt * m, Node n, bool exc = false ); + void addEntry( FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u, + Node v, unsigned depth = 0 ); + Node simplify_r( FirstOrderModelQInt * m, Node q, std::vector< Node >& il, std::vector< Node >& iu, + unsigned depth ); + bool isTotal_r( FirstOrderModelQInt * m, Node q, std::vector< Node >& il, std::vector< Node >& iu, + unsigned depth ); +public: + QIntDef(){} + std::map< Node, QIntDef > d_def; + std::vector< Node > d_def_order; + + void construct( FirstOrderModelQInt * m, std::vector< Node >& fapps, unsigned depth = 0 ); + bool construct_compose( FirstOrderModelQInt * m, Node q, Node n, QIntDef * f, + std::map< unsigned, QIntDef >& children, + std::map< unsigned, Node >& bchildren, int varChCount, + QIntVarNumIndex& vindex ); + bool construct_enum( FirstOrderModelQInt * m, Node q, unsigned vn ); + + Node evaluate( FirstOrderModelQInt * m, std::vector< Node >& reps ) { return evaluate_r( m, reps, 0 ); } + Node evaluate_n( FirstOrderModelQInt * m, Node n ) { return evaluate_n_r( m, n, 0 ); } + + void debugPrint( const char * c, FirstOrderModelQInt * m, Node q, int t = 0 ); + QIntDef * getChild( unsigned i ); + Node getValue() { return d_def_order[0]; } + Node getLower( unsigned i ) { return i==0 ? Node::null() : d_def_order[i-1]; } + Node getUpper( unsigned i ) { return d_def_order[i]; } + Node getMaximum() { return d_def_order.empty() ? Node::null() : getUpper( d_def_order.size()-1 ); } + int getNumChildren() { return d_def_order.size(); } + bool isTotal( FirstOrderModelQInt * m, Node q ); + + Node simplify( FirstOrderModelQInt * m, Node q ); + Node getFunctionValue( FirstOrderModelQInt * m, std::vector< Node >& vars, unsigned depth = 0 ); + + static void init_vec( FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u ); + static void debugPrint( const char * c, FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u ); +}; + +class QIntDefIter { +private: + FirstOrderModelQInt * d_fm; + Node d_q; + void resetIndex( QIntDef * qid ); +public: + QIntDefIter( FirstOrderModelQInt * m, Node q, QIntDef * qid ); + void debugPrint( const char * c, int t = 0 ); + std::vector< QIntDef * > d_index_visited; + std::vector< int > d_index; + bool isFinished() { return d_index.empty(); } + bool increment( int index = -1 ); + unsigned getSize() { return d_index.size(); } + Node getLower( int index ); + Node getUpper( int index ); + void getLowers( std::vector< Node >& reps ); + void getUppers( std::vector< Node >& reps ); + Node getValue(); +}; + + +class QuantVarOrder +{ +private: + int initialize( Node n, int minVarIndex, QIntVarNumIndex& vindex ); + int d_var_count; + Node d_q; + void debugPrint( const char * c, Node n, QIntVarNumIndex& vindex ); +public: + QuantVarOrder( Node q ); + std::map< int, Node > d_num_to_var; + std::map< int, int > d_num_to_prev_num; + std::map< int, int > d_num_to_next_num; + std::map< Node, std::vector< int > > d_var_to_num; + std::map< int, int > d_var_num_index; + //std::map< Node, std::map< int, int > > d_var_occur; + //int getVarNum( Node n, int arg ) { return d_var_occur[n][arg]; } + unsigned getNumVars() { return d_var_count; } + Node getVar( int i ) { return d_num_to_var[i]; } + int getPrevNum( int i ) { return d_num_to_prev_num.find( i )!=d_num_to_prev_num.end() ? d_num_to_prev_num[i] : -1; } + int getNextNum( int i ) { return d_num_to_next_num.find( i )!=d_num_to_next_num.end() ? d_num_to_next_num[i] : -1; } + int getVarNumIndex( int i ) { return d_var_num_index[i]; } + bool getInstantiation( FirstOrderModelQInt * m, std::vector< Node >& l, std::vector< Node >& u, + std::vector< Node >& inst ); + void debugPrint( const char * c ); + QIntVarNumIndex d_var_occur; +}; + +class QIntervalBuilder : public QModelBuilder +{ +private: + Node d_true; + bool doCheck( FirstOrderModelQInt * m, Node q, QIntDef & qid, Node n, + QIntVarNumIndex& vindex ); +public: + QIntervalBuilder( context::Context* c, QuantifiersEngine* qe ); + //process build model + void processBuildModel(TheoryModel* m, bool fullModel); + //do exhaustive instantiation + bool doExhaustiveInstantiation( FirstOrderModel * fm, Node q, int effort ); +}; + + +} +} +} + #endif
\ No newline at end of file diff --git a/src/theory/quantifiers/quant_conflict_find.cpp b/src/theory/quantifiers/quant_conflict_find.cpp index 731b53dc4..8321f17ba 100755 --- a/src/theory/quantifiers/quant_conflict_find.cpp +++ b/src/theory/quantifiers/quant_conflict_find.cpp @@ -1,2529 +1,2529 @@ -/********************* */
-/*! \file quant_conflict_find.cpp
- ** \verbatim
- ** Original author: Andrew Reynolds
- ** Major contributors: none
- ** 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 quant conflict find class
- **
- **/
-
-#include <vector>
-
-#include "theory/quantifiers/quant_conflict_find.h"
-#include "theory/quantifiers/quant_util.h"
-#include "theory/theory_engine.h"
-#include "theory/quantifiers/options.h"
-#include "theory/quantifiers/term_database.h"
-#include "theory/quantifiers/trigger.h"
-
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::theory;
-using namespace CVC4::theory::quantifiers;
-using namespace std;
-
-namespace CVC4 {
-
-Node QcfNodeIndex::existsTerm( TNode n, std::vector< TNode >& reps, int index ) {
- if( index==(int)reps.size() ){
- if( d_children.empty() ){
- return Node::null();
- }else{
- return d_children.begin()->first;
- }
- }else{
- std::map< TNode, QcfNodeIndex >::iterator it = d_children.find( reps[index] );
- if( it==d_children.end() ){
- return Node::null();
- }else{
- return it->second.existsTerm( n, reps, index+1 );
- }
- }
-}
-
-Node QcfNodeIndex::addTerm( TNode n, std::vector< TNode >& reps, int index ) {
- if( index==(int)reps.size() ){
- if( d_children.empty() ){
- d_children[ n ].clear();
- return n;
- }else{
- return d_children.begin()->first;
- }
- }else{
- return d_children[reps[index]].addTerm( n, reps, index+1 );
- }
-}
-
-
-void QcfNodeIndex::debugPrint( const char * c, int t ) {
- for( std::map< TNode, QcfNodeIndex >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
- if( !it->first.isNull() ){
- for( int j=0; j<t; j++ ){ Trace(c) << " "; }
- Trace(c) << it->first << " : " << std::endl;
- it->second.debugPrint( c, t+1 );
- }
- }
-}
-
-
-void QuantInfo::initialize( Node q, Node qn ) {
- d_q = q;
- for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
- d_match.push_back( TNode::null() );
- d_match_term.push_back( TNode::null() );
- }
-
- //register the variables
- for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
- d_var_num[q[0][i]] = i;
- d_vars.push_back( q[0][i] );
- }
-
- registerNode( qn, true, true );
-
-
- Trace("qcf-qregister") << "- Make match gen structure..." << std::endl;
- d_mg = new MatchGen( this, qn );
-
- if( d_mg->isValid() ){
- /*
- for( unsigned j=0; j<q[0].getNumChildren(); j++ ){
- if( d_inMatchConstraint.find( q[0][j] )==d_inMatchConstraint.end() ){
- Trace("qcf-invalid") << "QCF invalid : variable " << q[0][j] << " does not exist in a matching constraint." << std::endl;
- d_mg->setInvalid();
- break;
- }
- }
- */
- if( d_mg->isValid() ){
- for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){
- if( d_vars[j].getKind()!=BOUND_VARIABLE ){
- d_var_mg[j] = NULL;
- bool is_tsym = false;
- if( !MatchGen::isHandledUfTerm( d_vars[j] ) && d_vars[j].getKind()!=ITE ){
- is_tsym = true;
- d_tsym_vars.push_back( j );
- }
- if( !is_tsym || options::qcfTConstraint() ){
- d_var_mg[j] = new MatchGen( this, d_vars[j], true );
- }
- if( !d_var_mg[j] || !d_var_mg[j]->isValid() ){
- Trace("qcf-invalid") << "QCF invalid : cannot match for " << d_vars[j] << std::endl;
- d_mg->setInvalid();
- break;
- }else{
- std::vector< int > bvars;
- d_var_mg[j]->determineVariableOrder( this, bvars );
- }
- }
- }
- if( d_mg->isValid() ){
- std::vector< int > bvars;
- d_mg->determineVariableOrder( this, bvars );
- }
- }
- }else{
- Trace("qcf-invalid") << "QCF invalid : body of formula cannot be processed." << std::endl;
- }
- Trace("qcf-qregister-summary") << "QCF register : " << ( d_mg->isValid() ? "VALID " : "INVALID" ) << " : " << q << std::endl;
-}
-
-void QuantInfo::registerNode( Node n, bool hasPol, bool pol, bool beneathQuant ) {
- Trace("qcf-qregister-debug2") << "Register : " << n << std::endl;
- if( n.getKind()==FORALL ){
- registerNode( n[1], hasPol, pol, true );
- }else{
- if( !MatchGen::isHandledBoolConnective( n ) ){
- if( n.hasBoundVar() ){
- //literals
- if( n.getKind()==EQUAL ){
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- flatten( n[i], beneathQuant );
- }
- }else if( MatchGen::isHandledUfTerm( n ) ){
- flatten( n, beneathQuant );
- }else if( n.getKind()==ITE ){
- for( unsigned i=1; i<=2; i++ ){
- flatten( n[i], beneathQuant );
- }
- registerNode( n[0], false, pol, beneathQuant );
- }else if( options::qcfTConstraint() ){
- //a theory-specific predicate
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- flatten( n[i], beneathQuant );
- }
- }
- }
- }else{
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- bool newHasPol;
- bool newPol;
- QuantPhaseReq::getPolarity( n, i, hasPol, pol, newHasPol, newPol );
- //QcfNode * qcfc = new QcfNode( d_c );
- //qcfc->d_parent = qcf;
- //qcf->d_child[i] = qcfc;
- registerNode( n[i], newHasPol, newPol, beneathQuant );
- }
- }
- }
-}
-
-void QuantInfo::flatten( Node n, bool beneathQuant ) {
- Trace("qcf-qregister-debug2") << "Flatten : " << n << std::endl;
- if( n.hasBoundVar() ){
- if( n.getKind()==BOUND_VARIABLE ){
- d_inMatchConstraint[n] = true;
- }
- //if( MatchGen::isHandledUfTerm( n ) || n.getKind()==ITE ){
- if( d_var_num.find( n )==d_var_num.end() ){
- Trace("qcf-qregister-debug2") << "Add FLATTEN VAR : " << n << std::endl;
- d_var_num[n] = d_vars.size();
- d_vars.push_back( n );
- d_match.push_back( TNode::null() );
- d_match_term.push_back( TNode::null() );
- if( n.getKind()==ITE ){
- registerNode( n, false, false );
- }else{
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- flatten( n[i], beneathQuant );
- }
- }
- }else{
- Trace("qcf-qregister-debug2") << "...already processed" << std::endl;
- }
- }else{
- Trace("qcf-qregister-debug2") << "...is ground." << std::endl;
- }
-}
-
-
-void QuantInfo::reset_round( QuantConflictFind * p ) {
- for( unsigned i=0; i<d_match.size(); i++ ){
- d_match[i] = TNode::null();
- d_match_term[i] = TNode::null();
- }
- d_curr_var_deq.clear();
- d_tconstraints.clear();
- //add built-in variable constraints
- for( unsigned r=0; r<2; r++ ){
- for( std::map< int, std::vector< Node > >::iterator it = d_var_constraint[r].begin();
- it != d_var_constraint[r].end(); ++it ){
- for( unsigned j=0; j<it->second.size(); j++ ){
- Node rr = it->second[j];
- if( !isVar( rr ) ){
- rr = p->getRepresentative( rr );
- }
- if( addConstraint( p, it->first, rr, r==0 )==-1 ){
- d_var_constraint[0].clear();
- d_var_constraint[1].clear();
- //quantified formula is actually equivalent to true
- Trace("qcf-qregister") << "Quantifier is equivalent to true!!!" << std::endl;
- d_mg->d_children.clear();
- d_mg->d_n = NodeManager::currentNM()->mkConst( true );
- d_mg->d_type = MatchGen::typ_ground;
- return;
- }
- }
- }
- }
- d_mg->reset_round( p );
- for( std::map< int, MatchGen * >::iterator it = d_var_mg.begin(); it != d_var_mg.end(); ++it ){
- it->second->reset_round( p );
- }
- //now, reset for matching
- d_mg->reset( p, false, this );
-}
-
-int QuantInfo::getCurrentRepVar( int v ) {
- if( v!=-1 && !d_match[v].isNull() ){
- int vn = getVarNum( d_match[v] );
- if( vn!=-1 ){
- //int vr = getCurrentRepVar( vn );
- //d_match[v] = d_vars[vr];
- //return vr;
- return getCurrentRepVar( vn );
- }
- }
- return v;
-}
-
-TNode QuantInfo::getCurrentValue( TNode n ) {
- int v = getVarNum( n );
- if( v==-1 ){
- return n;
- }else{
- if( d_match[v].isNull() ){
- return n;
- }else{
- Assert( getVarNum( d_match[v] )!=v );
- return getCurrentValue( d_match[v] );
- }
- }
-}
-
-TNode QuantInfo::getCurrentExpValue( TNode n ) {
- int v = getVarNum( n );
- if( v==-1 ){
- return n;
- }else{
- if( d_match[v].isNull() ){
- return n;
- }else{
- Assert( getVarNum( d_match[v] )!=v );
- if( d_match_term[v].isNull() ){
- return getCurrentValue( d_match[v] );
- }else{
- return d_match_term[v];
- }
- }
- }
-}
-
-bool QuantInfo::getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq ) {
- //check disequalities
- std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v );
- if( itd!=d_curr_var_deq.end() ){
- for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){
- Node cv = getCurrentValue( it->first );
- Debug("qcf-ccbe") << "compare " << cv << " " << n << std::endl;
- if( cv==n ){
- return false;
- }else if( chDiseq && !isVar( n ) && !isVar( cv ) ){
- //they must actually be disequal if we are looking for conflicts
- if( !p->areDisequal( n, cv ) ){
- //TODO : check for entailed disequal
-
- return false;
- }
- }
- }
- }
- return true;
-}
-
-int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity ) {
- v = getCurrentRepVar( v );
- int vn = getVarNum( n );
- vn = vn==-1 ? -1 : getCurrentRepVar( vn );
- n = getCurrentValue( n );
- return addConstraint( p, v, n, vn, polarity, false );
-}
-
-int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove ) {
- //for handling equalities between variables, and disequalities involving variables
- Debug("qcf-match-debug") << "- " << (doRemove ? "un" : "" ) << "constrain : " << v << " -> " << n << " (cv=" << getCurrentValue( n ) << ")";
- Debug("qcf-match-debug") << ", (vn=" << vn << "), polarity = " << polarity << std::endl;
- Assert( doRemove || n==getCurrentValue( n ) );
- Assert( doRemove || v==getCurrentRepVar( v ) );
- Assert( doRemove || vn==getCurrentRepVar( getVarNum( n ) ) );
- if( polarity ){
- if( vn!=v ){
- if( doRemove ){
- if( vn!=-1 ){
- //if set to this in the opposite direction, clean up opposite instead
- // std::map< int, TNode >::iterator itmn = d_match.find( vn );
- if( d_match[vn]==d_vars[v] ){
- return addConstraint( p, vn, d_vars[v], v, true, true );
- }else{
- //unsetting variables equal
- std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( vn );
- if( itd!=d_curr_var_deq.end() ){
- //remove disequalities owned by this
- std::vector< TNode > remDeq;
- for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){
- if( it->second==v ){
- remDeq.push_back( it->first );
- }
- }
- for( unsigned i=0; i<remDeq.size(); i++ ){
- d_curr_var_deq[vn].erase( remDeq[i] );
- }
- }
- }
- }
- d_match[v] = TNode::null();
- return 1;
- }else{
- //std::map< int, TNode >::iterator itm = d_match.find( v );
-
- if( vn!=-1 ){
- Debug("qcf-match-debug") << " ...Variable bound to variable" << std::endl;
- //std::map< int, TNode >::iterator itmn = d_match.find( vn );
- if( d_match[v].isNull() ){
- //setting variables equal
- bool alreadySet = false;
- if( !d_match[vn].isNull() ){
- alreadySet = true;
- Assert( !isVar( d_match[vn] ) );
- }
-
- //copy or check disequalities
- std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v );
- if( itd!=d_curr_var_deq.end() ){
- for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){
- Node dv = getCurrentValue( it->first );
- if( !alreadySet ){
- if( d_curr_var_deq[vn].find( dv )==d_curr_var_deq[vn].end() ){
- d_curr_var_deq[vn][dv] = v;
- }
- }else{
- if( !p->areMatchDisequal( d_match[vn], dv ) ){
- Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;
- return -1;
- }
- }
- }
- }
- if( alreadySet ){
- n = getCurrentValue( n );
- }
- }else{
- if( d_match[vn].isNull() ){
- Debug("qcf-match-debug") << " ...Reverse direction" << std::endl;
- //set the opposite direction
- return addConstraint( p, vn, d_vars[v], v, true, false );
- }else{
- Debug("qcf-match-debug") << " -> Both variables bound, compare" << std::endl;
- //are they currently equal
- return p->areMatchEqual( d_match[v], d_match[vn] ) ? 0 : -1;
- }
- }
- }else{
- Debug("qcf-match-debug") << " ...Variable bound to ground" << std::endl;
- if( d_match[v].isNull() ){
- }else{
- //compare ground values
- Debug("qcf-match-debug") << " -> Ground value, compare " << d_match[v] << " "<< n << std::endl;
- return p->areMatchEqual( d_match[v], n ) ? 0 : -1;
- }
- }
- if( setMatch( p, v, n ) ){
- Debug("qcf-match-debug") << " -> success" << std::endl;
- return 1;
- }else{
- Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;
- return -1;
- }
- }
- }else{
- Debug("qcf-match-debug") << " -> redundant, variable identity" << std::endl;
- return 0;
- }
- }else{
- if( vn==v ){
- Debug("qcf-match-debug") << " -> fail, variable identity" << std::endl;
- return -1;
- }else{
- if( doRemove ){
- Assert( d_curr_var_deq[v].find( n )!=d_curr_var_deq[v].end() );
- d_curr_var_deq[v].erase( n );
- return 1;
- }else{
- if( d_curr_var_deq[v].find( n )==d_curr_var_deq[v].end() ){
- //check if it respects equality
- //std::map< int, TNode >::iterator itm = d_match.find( v );
- if( !d_match[v].isNull() ){
- TNode nv = getCurrentValue( n );
- if( !p->areMatchDisequal( nv, d_match[v] ) ){
- Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;
- return -1;
- }
- }
- d_curr_var_deq[v][n] = v;
- Debug("qcf-match-debug") << " -> success" << std::endl;
- return 1;
- }else{
- Debug("qcf-match-debug") << " -> redundant disequality" << std::endl;
- return 0;
- }
- }
- }
- }
-}
-
-bool QuantInfo::isConstrainedVar( int v ) {
- if( d_curr_var_deq.find( v )!=d_curr_var_deq.end() && !d_curr_var_deq[v].empty() ){
- return true;
- }else{
- Node vv = getVar( v );
- //for( std::map< int, TNode >::iterator it = d_match.begin(); it != d_match.end(); ++it ){
- for( unsigned i=0; i<d_match.size(); i++ ){
- if( d_match[i]==vv ){
- return true;
- }
- }
- for( std::map< int, std::map< TNode, int > >::iterator it = d_curr_var_deq.begin(); it != d_curr_var_deq.end(); ++it ){
- for( std::map< TNode, int >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
- if( it2->first==vv ){
- return true;
- }
- }
- }
- return false;
- }
-}
-
-bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n ) {
- if( getCurrentCanBeEqual( p, v, n ) ){
- Debug("qcf-match-debug") << "-- bind : " << v << " -> " << n << ", checked " << d_curr_var_deq[v].size() << " disequalities" << std::endl;
- d_match[v] = n;
- return true;
- }else{
- return false;
- }
-}
-
-bool QuantInfo::isMatchSpurious( QuantConflictFind * p ) {
- for( int i=0; i<getNumVars(); i++ ){
- //std::map< int, TNode >::iterator it = d_match.find( i );
- if( !d_match[i].isNull() ){
- if( !getCurrentCanBeEqual( p, i, d_match[i], p->d_effort==QuantConflictFind::effort_conflict ) ){
- return true;
- }
- }
- }
- return false;
-}
-
-bool QuantInfo::isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms ) {
- if( !d_tconstraints.empty() ){
- //check constraints
- for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){
- //apply substitution to the tconstraint
- Node cons = it->first.substitute( p->getQuantifiersEngine()->getTermDatabase()->d_vars[d_q].begin(),
- p->getQuantifiersEngine()->getTermDatabase()->d_vars[d_q].end(),
- terms.begin(), terms.end() );
- cons = it->second ? cons : cons.negate();
- if( !entailmentTest( p, cons, p->d_effort==QuantConflictFind::effort_conflict ) ){
- return true;
- }
- }
- }
- return false;
-}
-
-bool QuantInfo::entailmentTest( QuantConflictFind * p, Node lit, bool chEnt ) {
- Trace("qcf-tconstraint-debug") << "Check : " << lit << std::endl;
- Node rew = Rewriter::rewrite( lit );
- if( rew==p->d_false ){
- Trace("qcf-tconstraint-debug") << "...constraint " << lit << " is disentailed (rewrites to false)." << std::endl;
- return false;
- }else if( rew!=p->d_true ){
- //if checking for conflicts, we must be sure that the constraint is entailed
- if( chEnt ){
- //check if it is entailed
- Trace("qcf-tconstraint-debug") << "Check entailment of " << rew << "..." << std::endl;
- std::pair<bool, Node> et = p->getQuantifiersEngine()->getTheoryEngine()->entailmentCheck(THEORY_OF_TYPE_BASED, rew );
- ++(p->d_statistics.d_entailment_checks);
- Trace("qcf-tconstraint-debug") << "ET result : " << et.first << " " << et.second << std::endl;
- if( !et.first ){
- Trace("qcf-tconstraint-debug") << "...cannot show entailment of " << rew << "." << std::endl;
- return false;
- }else{
- return true;
- }
- }else{
- Trace("qcf-tconstraint-debug") << "...does not need to be entailed." << std::endl;
- return true;
- }
- }else{
- Trace("qcf-tconstraint-debug") << "...rewrites to true." << std::endl;
- return true;
- }
-}
-
-bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue ) {
- //assign values for variables that were unassigned (usually not necessary, but handles corner cases)
- bool doFail = false;
- bool success = true;
- if( doContinue ){
- doFail = true;
- success = false;
- }else{
- //solve for interpreted symbol matches
- // this breaks the invariant that all introduced constraints are over existing terms
- for( int i=(int)(d_tsym_vars.size()-1); i>=0; i-- ){
- int index = d_tsym_vars[i];
- TNode v = getCurrentValue( d_vars[index] );
- int slv_v = -1;
- if( v==d_vars[index] ){
- slv_v = index;
- }
- Trace("qcf-tconstraint-debug") << "Solve " << d_vars[index] << " = " << v << " " << d_vars[index].getKind() << std::endl;
- if( d_vars[index].getKind()==PLUS || d_vars[index].getKind()==MULT ){
- Kind k = d_vars[index].getKind();
- std::vector< TNode > children;
- for( unsigned j=0; j<d_vars[index].getNumChildren(); j++ ){
- int vn = getVarNum( d_vars[index][j] );
- if( vn!=-1 ){
- TNode vv = getCurrentValue( d_vars[index][j] );
- if( vv==d_vars[index][j] ){
- //we will assign this
- if( slv_v==-1 ){
- Trace("qcf-tconstraint-debug") << "...will solve for var #" << vn << std::endl;
- slv_v = vn;
- if( p->d_effort!=QuantConflictFind::effort_conflict ){
- break;
- }
- }else{
- Node z = p->getZero( k );
- if( !z.isNull() ){
- Trace("qcf-tconstraint-debug") << "...set " << d_vars[vn] << " = " << z << std::endl;
- assigned.push_back( vn );
- if( !setMatch( p, vn, z ) ){
- success = false;
- break;
- }
- }
- }
- }else{
- Trace("qcf-tconstraint-debug") << "...sum value " << vv << std::endl;
- children.push_back( vv );
- }
- }else{
- Trace("qcf-tconstraint-debug") << "...sum " << d_vars[index][j] << std::endl;
- children.push_back( d_vars[index][j] );
- }
- }
- if( success ){
- if( slv_v!=-1 ){
- Node lhs;
- if( children.empty() ){
- lhs = p->getZero( k );
- }else if( children.size()==1 ){
- lhs = children[0];
- }else{
- lhs = NodeManager::currentNM()->mkNode( k, children );
- }
- Node sum;
- if( v==d_vars[index] ){
- sum = lhs;
- }else{
- if( p->d_effort==QuantConflictFind::effort_conflict ){
- Kind kn = k;
- if( d_vars[index].getKind()==PLUS ){
- kn = MINUS;
- }
- if( kn!=k ){
- sum = NodeManager::currentNM()->mkNode( kn, v, lhs );
- }
- }
- }
- if( !sum.isNull() ){
- assigned.push_back( slv_v );
- Trace("qcf-tconstraint-debug") << "...set " << d_vars[slv_v] << " = " << sum << std::endl;
- if( !setMatch( p, slv_v, sum ) ){
- success = false;
- }
- p->d_tempCache.push_back( sum );
- }
- }else{
- //must show that constraint is met
- Node sum = NodeManager::currentNM()->mkNode( k, children );
- Node eq = sum.eqNode( v );
- if( !entailmentTest( p, eq ) ){
- success = false;
- }
- p->d_tempCache.push_back( sum );
- }
- }
- }
-
- if( !success ){
- break;
- }
- }
- if( success ){
- //check what is left to assign
- d_unassigned.clear();
- d_unassigned_tn.clear();
- std::vector< int > unassigned[2];
- std::vector< TypeNode > unassigned_tn[2];
- for( int i=0; i<getNumVars(); i++ ){
- if( d_match[i].isNull() ){
- int rindex = d_var_mg.find( i )==d_var_mg.end() ? 1 : 0;
- unassigned[rindex].push_back( i );
- unassigned_tn[rindex].push_back( getVar( i ).getType() );
- assigned.push_back( i );
- }
- }
- d_unassigned_nvar = unassigned[0].size();
- for( unsigned i=0; i<2; i++ ){
- d_unassigned.insert( d_unassigned.end(), unassigned[i].begin(), unassigned[i].end() );
- d_unassigned_tn.insert( d_unassigned_tn.end(), unassigned_tn[i].begin(), unassigned_tn[i].end() );
- }
- d_una_eqc_count.clear();
- d_una_index = 0;
- }
- }
-
- if( !d_unassigned.empty() && ( success || doContinue ) ){
- Trace("qcf-check") << "Assign to unassigned..." << std::endl;
- do {
- if( doFail ){
- Trace("qcf-check-unassign") << "Failure, try again..." << std::endl;
- }
- bool invalidMatch = false;
- while( ( d_una_index>=0 && (int)d_una_index<(int)d_unassigned.size() ) || invalidMatch || doFail ){
- invalidMatch = false;
- if( !doFail && d_una_index==(int)d_una_eqc_count.size() ){
- //check if it has now been assigned
- if( d_una_index<d_unassigned_nvar ){
- if( !isConstrainedVar( d_unassigned[d_una_index] ) ){
- d_una_eqc_count.push_back( -1 );
- }else{
- d_var_mg[ d_unassigned[d_una_index] ]->reset( p, true, this );
- d_una_eqc_count.push_back( 0 );
- }
- }else{
- d_una_eqc_count.push_back( 0 );
- }
- }else{
- bool failed = false;
- if( !doFail ){
- if( d_una_index<d_unassigned_nvar ){
- if( !isConstrainedVar( d_unassigned[d_una_index] ) ){
- Trace("qcf-check-unassign") << "Succeeded, variable unconstrained at " << d_una_index << std::endl;
- d_una_index++;
- }else if( d_var_mg[d_unassigned[d_una_index]]->getNextMatch( p, this ) ){
- Trace("qcf-check-unassign") << "Succeeded match with mg at " << d_una_index << std::endl;
- d_una_index++;
- }else{
- failed = true;
- Trace("qcf-check-unassign") << "Failed match with mg at " << d_una_index << std::endl;
- }
- }else{
- Assert( doFail || d_una_index==(int)d_una_eqc_count.size()-1 );
- if( d_una_eqc_count[d_una_index]<(int)p->d_eqcs[d_unassigned_tn[d_una_index]].size() ){
- int currIndex = d_una_eqc_count[d_una_index];
- d_una_eqc_count[d_una_index]++;
- Trace("qcf-check-unassign") << d_unassigned[d_una_index] << "->" << p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] << std::endl;
- if( setMatch( p, d_unassigned[d_una_index], p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] ) ){
- d_match_term[d_unassigned[d_una_index]] = TNode::null();
- Trace("qcf-check-unassign") << "Succeeded match " << d_una_index << std::endl;
- d_una_index++;
- }else{
- Trace("qcf-check-unassign") << "Failed match " << d_una_index << std::endl;
- invalidMatch = true;
- }
- }else{
- failed = true;
- Trace("qcf-check-unassign") << "No more matches " << d_una_index << std::endl;
- }
- }
- }
- if( doFail || failed ){
- do{
- if( !doFail ){
- d_una_eqc_count.pop_back();
- }else{
- doFail = false;
- }
- d_una_index--;
- }while( d_una_index>=0 && d_una_eqc_count[d_una_index]==-1 );
- }
- }
- }
- success = d_una_index>=0;
- if( success ){
- doFail = true;
- Trace("qcf-check-unassign") << " Try: " << std::endl;
- for( unsigned i=0; i<d_unassigned.size(); i++ ){
- int ui = d_unassigned[i];
- if( !d_match[ui].isNull() ){
- Trace("qcf-check-unassign") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl;
- }
- }
- }
- }while( success && isMatchSpurious( p ) );
- }
- if( success ){
- for( unsigned i=0; i<d_unassigned.size(); i++ ){
- int ui = d_unassigned[i];
- if( !d_match[ui].isNull() ){
- Trace("qcf-check") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl;
- }
- }
- return true;
- }else{
- for( unsigned i=0; i<assigned.size(); i++ ){
- d_match[ assigned[i] ] = TNode::null();
- }
- assigned.clear();
- return false;
- }
-}
-
-void QuantInfo::getMatch( std::vector< Node >& terms ){
- for( unsigned i=0; i<d_q[0].getNumChildren(); i++ ){
- //Node cv = qi->getCurrentValue( qi->d_match[i] );
- int repVar = getCurrentRepVar( i );
- Node cv;
- //std::map< int, TNode >::iterator itmt = qi->d_match_term.find( repVar );
- if( !d_match_term[repVar].isNull() ){
- cv = d_match_term[repVar];
- }else{
- cv = d_match[repVar];
- }
- Debug("qcf-check-inst") << "INST : " << i << " -> " << cv << ", from " << d_match[i] << std::endl;
- terms.push_back( cv );
- }
-}
-
-void QuantInfo::revertMatch( std::vector< int >& assigned ) {
- for( unsigned i=0; i<assigned.size(); i++ ){
- d_match[ assigned[i] ] = TNode::null();
- }
-}
-
-void QuantInfo::debugPrintMatch( const char * c ) {
- for( int i=0; i<getNumVars(); i++ ){
- Trace(c) << " " << d_vars[i] << " -> ";
- if( !d_match[i].isNull() ){
- Trace(c) << d_match[i];
- }else{
- Trace(c) << "(unassigned) ";
- }
- if( !d_curr_var_deq[i].empty() ){
- Trace(c) << ", DEQ{ ";
- for( std::map< TNode, int >::iterator it = d_curr_var_deq[i].begin(); it != d_curr_var_deq[i].end(); ++it ){
- Trace(c) << it->first << " ";
- }
- Trace(c) << "}";
- }
- if( !d_match_term[i].isNull() && d_match_term[i]!=d_match[i] ){
- Trace(c) << ", EXP : " << d_match_term[i];
- }
- Trace(c) << std::endl;
- }
- if( !d_tconstraints.empty() ){
- Trace(c) << "ADDITIONAL CONSTRAINTS : " << std::endl;
- for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){
- Trace(c) << " " << it->first << " -> " << it->second << std::endl;
- }
- }
-}
-
-MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar ){
- Trace("qcf-qregister-debug") << "Make match gen for " << n << ", isVar = " << isVar << std::endl;
- std::vector< Node > qni_apps;
- d_qni_size = 0;
- if( isVar ){
- Assert( qi->d_var_num.find( n )!=qi->d_var_num.end() );
- if( n.getKind()==ITE ){
- d_type = typ_ite_var;
- d_type_not = false;
- d_n = n;
- d_children.push_back( MatchGen( qi, d_n[0] ) );
- if( d_children[0].isValid() ){
- d_type = typ_ite_var;
- for( unsigned i=1; i<=2; i++ ){
- Node nn = n.eqNode( n[i] );
- d_children.push_back( MatchGen( qi, nn ) );
- d_children[d_children.size()-1].d_qni_bound_except.push_back( 0 );
- if( !d_children[d_children.size()-1].isValid() ){
- setInvalid();
- break;
- }
- }
- }else{
- d_type = typ_invalid;
- }
- }else{
- d_type = isHandledUfTerm( n ) ? typ_var : typ_tsym;
- d_qni_var_num[0] = qi->getVarNum( n );
- d_qni_size++;
- d_type_not = false;
- d_n = n;
- //Node f = getOperator( n );
- for( unsigned j=0; j<d_n.getNumChildren(); j++ ){
- Node nn = d_n[j];
- Trace("qcf-qregister-debug") << " " << d_qni_size;
- if( qi->isVar( nn ) ){
- int v = qi->d_var_num[nn];
- Trace("qcf-qregister-debug") << " is var #" << v << std::endl;
- d_qni_var_num[d_qni_size] = v;
- //qi->addFuncParent( v, f, j );
- }else{
- Trace("qcf-qregister-debug") << " is gterm " << nn << std::endl;
- d_qni_gterm[d_qni_size] = nn;
- }
- d_qni_size++;
- }
- }
- }else{
- if( n.hasBoundVar() ){
- d_type_not = false;
- d_n = n;
- if( d_n.getKind()==NOT ){
- d_n = d_n[0];
- d_type_not = !d_type_not;
- }
-
- if( isHandledBoolConnective( d_n ) ){
- //non-literals
- d_type = typ_formula;
- for( unsigned i=0; i<d_n.getNumChildren(); i++ ){
- if( d_n.getKind()!=FORALL || i==1 ){
- d_children.push_back( MatchGen( qi, d_n[i], false ) );
- if( !d_children[d_children.size()-1].isValid() ){
- setInvalid();
- break;
- }
- }
- /*
- else if( isTop && n.getKind()==OR && d_children[d_children.size()-1].d_type==typ_var_eq ){
- Trace("qcf-qregister-debug") << "Remove child, make built-in constraint" << std::endl;
- //if variable equality/disequality at top level, remove immediately
- bool cIsNot = d_children[d_children.size()-1].d_type_not;
- Node cn = d_children[d_children.size()-1].d_n;
- Assert( cn.getKind()==EQUAL );
- Assert( p->d_qinfo[q].isVar( cn[0] ) || p->d_qinfo[q].isVar( cn[1] ) );
- //make it a built-in constraint instead
- for( unsigned i=0; i<2; i++ ){
- if( p->d_qinfo[q].isVar( cn[i] ) ){
- int v = p->d_qinfo[q].getVarNum( cn[i] );
- Node cno = cn[i==0 ? 1 : 0];
- p->d_qinfo[q].d_var_constraint[ cIsNot ? 0 : 1 ][v].push_back( cno );
- break;
- }
- }
- d_children.pop_back();
- }
- */
- }
- }else{
- d_type = typ_invalid;
- //literals
- if( isHandledUfTerm( d_n ) ){
- Assert( qi->isVar( d_n ) );
- d_type = typ_pred;
- }else if( d_n.getKind()==BOUND_VARIABLE ){
- Assert( d_n.getType().isBoolean() );
- d_type = typ_bool_var;
- }else if( d_n.getKind()==EQUAL || options::qcfTConstraint() ){
- for( unsigned i=0; i<d_n.getNumChildren(); i++ ){
- if( d_n[i].hasBoundVar() ){
- if( !qi->isVar( d_n[i] ) ){
- Trace("qcf-qregister-debug") << "ERROR : not var " << d_n[i] << std::endl;
- }
- Assert( qi->isVar( d_n[i] ) );
- if( d_n.getKind()!=EQUAL && qi->isVar( d_n[i] ) ){
- d_qni_var_num[i+1] = qi->d_var_num[d_n[i]];
- }
- }else{
- d_qni_gterm[i] = d_n[i];
- }
- }
- d_type = d_n.getKind()==EQUAL ? typ_eq : typ_tconstraint;
- Trace("qcf-tconstraint") << "T-Constraint : " << d_n << std::endl;
- }
- }
- }else{
- //we will just evaluate
- d_n = n;
- d_type = typ_ground;
- }
- //if( d_type!=typ_invalid ){
- //determine an efficient children ordering
- //if( !d_children.empty() ){
- //for( unsigned i=0; i<d_children.size(); i++ ){
- // d_children_order.push_back( i );
- //}
- //if( !d_n.isNull() && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF ) ){
- //sort based on the type of the constraint : ground comes first, then literals, then others
- //MatchGenSort mgs;
- //mgs.d_mg = this;
- //std::sort( d_children_order.begin(), d_children_order.end(), mgs );
- //}
- //}
- //}
- }
- Trace("qcf-qregister-debug") << "Done make match gen " << n << ", type = ";
- debugPrintType( "qcf-qregister-debug", d_type, true );
- Trace("qcf-qregister-debug") << std::endl;
- //Assert( d_children.size()==d_children_order.size() );
-
-}
-
-void MatchGen::collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars ) {
- int v = qi->getVarNum( n );
- if( v!=-1 && std::find( cbvars.begin(), cbvars.end(), v )==cbvars.end() ){
- cbvars.push_back( v );
- }
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- collectBoundVar( qi, n[i], cbvars );
- }
-}
-
-void MatchGen::determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars ) {
- Trace("qcf-qregister-debug") << "Determine variable order " << d_n << std::endl;
- bool isCom = d_type==typ_formula && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF );
- std::map< int, std::vector< int > > c_to_vars;
- std::map< int, std::vector< int > > vars_to_c;
- std::map< int, int > vb_count;
- std::map< int, int > vu_count;
- std::vector< bool > assigned;
- Trace("qcf-qregister-debug") << "Calculate bound variables..." << std::endl;
- for( unsigned i=0; i<d_children.size(); i++ ){
- collectBoundVar( qi, d_children[i].d_n, c_to_vars[i] );
- assigned.push_back( false );
- vb_count[i] = 0;
- vu_count[i] = 0;
- for( unsigned j=0; j<c_to_vars[i].size(); j++ ){
- int v = c_to_vars[i][j];
- vars_to_c[v].push_back( i );
- if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){
- vu_count[i]++;
- if( !isCom ){
- bvars.push_back( v );
- }
- }else{
- vb_count[i]++;
- }
- }
- }
- if( isCom ){
- //children that bind the least number of unbound variables go first
- do {
- int min_score = -1;
- int min_score_index = -1;
- for( unsigned i=0; i<d_children.size(); i++ ){
- if( !assigned[i] ){
- int score = vu_count[i];
- if( min_score==-1 || score<min_score ){
- min_score = score;
- min_score_index = i;
- }
- }
- }
- Trace("qcf-qregister-debug") << "...assign child " << min_score_index << "/" << d_children.size() << std::endl;
- Assert( min_score_index!=-1 );
- //add to children order
- d_children_order.push_back( min_score_index );
- assigned[min_score_index] = true;
- //if( vb_count[min_score_index]==0 ){
- // d_independent.push_back( min_score_index );
- //}
- //determine order internal to children
- d_children[min_score_index].determineVariableOrder( qi, bvars );
- Trace("qcf-qregister-debug") << "...bind variables" << std::endl;
- //now, make it a bound variable
- for( unsigned i=0; i<c_to_vars[min_score_index].size(); i++ ){
- int v = c_to_vars[min_score_index][i];
- if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){
- for( unsigned j=0; j<vars_to_c[v].size(); j++ ){
- int vc = vars_to_c[v][j];
- vu_count[vc]--;
- vb_count[vc]++;
- }
- bvars.push_back( v );
- }
- }
- Trace("qcf-qregister-debug") << "...done assign child " << min_score_index << std::endl;
- }while( d_children_order.size()!=d_children.size() );
- Trace("qcf-qregister-debug") << "Done assign variable ordering for " << d_n << std::endl;
- }else{
- for( unsigned i=0; i<d_children.size(); i++ ){
- d_children_order.push_back( i );
- d_children[i].determineVariableOrder( qi, bvars );
- }
- }
-}
-
-
-void MatchGen::reset_round( QuantConflictFind * p ) {
- d_wasSet = false;
- for( unsigned i=0; i<d_children.size(); i++ ){
- d_children[i].reset_round( p );
- }
- for( std::map< int, TNode >::iterator it = d_qni_gterm.begin(); it != d_qni_gterm.end(); ++it ){
- d_qni_gterm_rep[it->first] = p->getRepresentative( it->second );
- }
- if( d_type==typ_ground ){
- int e = p->evaluate( d_n );
- if( e==1 ){
- d_ground_eval[0] = p->d_true;
- }else if( e==-1 ){
- d_ground_eval[0] = p->d_false;
- }
- }else if( d_type==typ_eq ){
- for( unsigned i=0; i<d_n.getNumChildren(); i++ ){
- if( !d_n[i].hasBoundVar() ){
- d_ground_eval[i] = p->evaluateTerm( d_n[i] );
- }
- }
- }
- d_qni_bound_cons.clear();
- d_qni_bound_cons_var.clear();
- d_qni_bound.clear();
-}
-
-void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {
- d_tgt = d_type_not ? !tgt : tgt;
- Debug("qcf-match") << " Reset for : " << d_n << ", type : ";
- debugPrintType( "qcf-match", d_type );
- Debug("qcf-match") << ", tgt = " << d_tgt << ", children = " << d_children.size() << " " << d_children_order.size() << std::endl;
- d_qn.clear();
- d_qni.clear();
- d_qni_bound.clear();
- d_child_counter = -1;
- d_tgt_orig = d_tgt;
-
- //set up processing matches
- if( d_type==typ_invalid ){
- //do nothing
- }else if( d_type==typ_ground ){
- if( d_ground_eval[0]==( d_tgt ? p->d_true : p->d_false ) ){
- d_child_counter = 0;
- }
- }else if( d_type==typ_bool_var ){
- //get current value of the variable
- TNode n = qi->getCurrentValue( d_n );
- int vn = qi->getCurrentRepVar( qi->getVarNum( n ) );
- if( vn==-1 ){
- //evaluate the value, see if it is compatible
- int e = p->evaluate( n );
- if( ( e==1 && d_tgt ) || ( e==0 && !d_tgt ) ){
- d_child_counter = 0;
- }
- }else{
- //unassigned, set match to true/false
- d_qni_bound[0] = vn;
- qi->setMatch( p, vn, d_tgt ? p->d_true : p->d_false );
- d_child_counter = 0;
- }
- if( d_child_counter==0 ){
- d_qn.push_back( NULL );
- }
- }else if( d_type==typ_var ){
- Assert( isHandledUfTerm( d_n ) );
- Node f = getOperator( p, d_n );
- Debug("qcf-match-debug") << " reset: Var will match operators of " << f << std::endl;
- QcfNodeIndex * qni = p->getQcfNodeIndex( Node::null(), f );
- if( qni!=NULL ){
- d_qn.push_back( qni );
- }
- d_matched_basis = false;
- }else if( d_type==typ_tsym || d_type==typ_tconstraint ){
- for( std::map< int, int >::iterator it = d_qni_var_num.begin(); it != d_qni_var_num.end(); ++it ){
- int repVar = qi->getCurrentRepVar( it->second );
- if( qi->d_match[repVar].isNull() ){
- Debug("qcf-match-debug") << "Force matching on child #" << it->first << ", which is var #" << repVar << std::endl;
- d_qni_bound[it->first] = repVar;
- }
- }
- d_qn.push_back( NULL );
- }else if( d_type==typ_pred || d_type==typ_eq ){
- //add initial constraint
- Node nn[2];
- int vn[2];
- if( d_type==typ_pred ){
- nn[0] = qi->getCurrentValue( d_n );
- vn[0] = qi->getCurrentRepVar( qi->getVarNum( nn[0] ) );
- nn[1] = p->getRepresentative( d_tgt ? p->d_true : p->d_false );
- vn[1] = -1;
- d_tgt = true;
- }else{
- for( unsigned i=0; i<2; i++ ){
- TNode nc;
- std::map< int, TNode >::iterator it = d_qni_gterm_rep.find( i );
- if( it!=d_qni_gterm_rep.end() ){
- nc = it->second;
- }else{
- nc = d_n[i];
- }
- nn[i] = qi->getCurrentValue( nc );
- vn[i] = qi->getCurrentRepVar( qi->getVarNum( nn[i] ) );
- }
- }
- bool success;
- if( vn[0]==-1 && vn[1]==-1 ){
- //Trace("qcf-explain") << " reset : " << d_n << " check ground values " << nn[0] << " " << nn[1] << " (tgt=" << d_tgt << ")" << std::endl;
- Debug("qcf-match-debug") << " reset: check ground values " << nn[0] << " " << nn[1] << " (" << d_tgt << ")" << std::endl;
- //just compare values
- if( d_tgt ){
- success = p->areMatchEqual( nn[0], nn[1] );
- }else{
- if( p->d_effort==QuantConflictFind::effort_conflict ){
- success = p->areDisequal( nn[0], nn[1] );
- }else{
- success = p->areMatchDisequal( nn[0], nn[1] );
- }
- }
- }else{
- //otherwise, add a constraint to a variable
- if( vn[1]!=-1 && vn[0]==-1 ){
- //swap
- Node t = nn[1];
- nn[1] = nn[0];
- nn[0] = t;
- vn[0] = vn[1];
- vn[1] = -1;
- }
- Debug("qcf-match-debug") << " reset: add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << std::endl;
- //add some constraint
- int addc = qi->addConstraint( p, vn[0], nn[1], vn[1], d_tgt, false );
- success = addc!=-1;
- //if successful and non-redundant, store that we need to cleanup this
- if( addc==1 ){
- //Trace("qcf-explain") << " reset: " << d_n << " add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << ", d_tgt = " << d_tgt << std::endl;
- for( unsigned i=0; i<2; i++ ){
- if( vn[i]!=-1 && std::find( d_qni_bound_except.begin(), d_qni_bound_except.end(), i )==d_qni_bound_except.end() ){
- d_qni_bound[vn[i]] = vn[i];
- }
- }
- d_qni_bound_cons[vn[0]] = nn[1];
- d_qni_bound_cons_var[vn[0]] = vn[1];
- }
- }
- //if successful, we will bind values to variables
- if( success ){
- d_qn.push_back( NULL );
- }
- }else{
- if( d_children.empty() ){
- //add dummy
- d_qn.push_back( NULL );
- }else{
- if( d_tgt && d_n.getKind()==FORALL ){
- //do nothing
- }else{
- //reset the first child to d_tgt
- d_child_counter = 0;
- getChild( d_child_counter )->reset( p, d_tgt, qi );
- }
- }
- }
- d_binding = false;
- d_wasSet = true;
- Debug("qcf-match") << " reset: Finished reset for " << d_n << ", success = " << ( !d_qn.empty() || d_child_counter!=-1 ) << std::endl;
-}
-
-bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) {
- Debug("qcf-match") << " Get next match for : " << d_n << ", type = ";
- debugPrintType( "qcf-match", d_type );
- Debug("qcf-match") << ", children = " << d_children.size() << ", binding = " << d_binding << std::endl;
- if( d_type==typ_invalid || d_type==typ_ground ){
- if( d_child_counter==0 ){
- d_child_counter = -1;
- return true;
- }else{
- d_wasSet = false;
- return false;
- }
- }else if( d_type==typ_var || d_type==typ_eq || d_type==typ_pred || d_type==typ_bool_var || d_type==typ_tconstraint || d_type==typ_tsym ){
- bool success = false;
- bool terminate = false;
- do {
- bool doReset = false;
- bool doFail = false;
- if( !d_binding ){
- if( doMatching( p, qi ) ){
- Debug("qcf-match-debug") << " - Matching succeeded" << std::endl;
- d_binding = true;
- d_binding_it = d_qni_bound.begin();
- doReset = true;
- //for tconstraint, add constraint
- if( d_type==typ_tconstraint ){
- std::map< Node, bool >::iterator it = qi->d_tconstraints.find( d_n );
- if( it==qi->d_tconstraints.end() ){
- qi->d_tconstraints[d_n] = d_tgt;
- //store that we added this constraint
- d_qni_bound_cons[0] = d_n;
- }else if( d_tgt!=it->second ){
- success = false;
- terminate = true;
- }
- }
- }else{
- Debug("qcf-match-debug") << " - Matching failed" << std::endl;
- success = false;
- terminate = true;
- }
- }else{
- doFail = true;
- }
- if( d_binding ){
- //also need to create match for each variable we bound
- success = true;
- Debug("qcf-match-debug") << " Produce matches for bound variables by " << d_n << ", type = ";
- debugPrintType( "qcf-match-debug", d_type );
- Debug("qcf-match-debug") << "..." << std::endl;
-
- while( ( success && d_binding_it!=d_qni_bound.end() ) || doFail ){
- std::map< int, MatchGen * >::iterator itm;
- if( !doFail ){
- Debug("qcf-match-debug") << " check variable " << d_binding_it->second << std::endl;
- itm = qi->d_var_mg.find( d_binding_it->second );
- }
- if( doFail || ( d_binding_it->first!=0 && itm!=qi->d_var_mg.end() ) ){
- Debug("qcf-match-debug") << " we had bound variable " << d_binding_it->second << ", reset = " << doReset << std::endl;
- if( doReset ){
- itm->second->reset( p, true, qi );
- }
- if( doFail || !itm->second->getNextMatch( p, qi ) ){
- do {
- if( d_binding_it==d_qni_bound.begin() ){
- Debug("qcf-match-debug") << " failed." << std::endl;
- success = false;
- }else{
- --d_binding_it;
- Debug("qcf-match-debug") << " decrement..." << std::endl;
- }
- }while( success && ( d_binding_it->first==0 || qi->d_var_mg.find( d_binding_it->second )==qi->d_var_mg.end() ) );
- doReset = false;
- doFail = false;
- }else{
- Debug("qcf-match-debug") << " increment..." << std::endl;
- ++d_binding_it;
- doReset = true;
- }
- }else{
- Debug("qcf-match-debug") << " skip..." << d_binding_it->second << std::endl;
- ++d_binding_it;
- doReset = true;
- }
- }
- if( !success ){
- d_binding = false;
- }else{
- terminate = true;
- if( d_binding_it==d_qni_bound.begin() ){
- d_binding = false;
- }
- }
- }
- }while( !terminate );
- //if not successful, clean up the variables you bound
- if( !success ){
- if( d_type==typ_eq || d_type==typ_pred ){
- //clean up the constraints you added
- for( std::map< int, TNode >::iterator it = d_qni_bound_cons.begin(); it != d_qni_bound_cons.end(); ++it ){
- if( !it->second.isNull() ){
- Debug("qcf-match") << " Clean up bound var " << it->first << (d_tgt ? "!" : "") << " = " << it->second << std::endl;
- std::map< int, int >::iterator itb = d_qni_bound_cons_var.find( it->first );
- int vn = itb!=d_qni_bound_cons_var.end() ? itb->second : -1;
- //Trace("qcf-explain") << " cleanup: " << d_n << " remove constraint " << it->first << " -> " << it->second << " (vn=" << vn << ")" << ", d_tgt = " << d_tgt << std::endl;
- qi->addConstraint( p, it->first, it->second, vn, d_tgt, true );
- }
- }
- d_qni_bound_cons.clear();
- d_qni_bound_cons_var.clear();
- d_qni_bound.clear();
- }else{
- //clean up the matches you set
- for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){
- Debug("qcf-match") << " Clean up bound var " << it->second << std::endl;
- Assert( it->second<qi->getNumVars() );
- qi->d_match[ it->second ] = TNode::null();
- qi->d_match_term[ it->second ] = TNode::null();
- }
- d_qni_bound.clear();
- }
- if( d_type==typ_tconstraint ){
- //remove constraint if applicable
- if( d_qni_bound_cons.find( 0 )!=d_qni_bound_cons.end() ){
- qi->d_tconstraints.erase( d_n );
- d_qni_bound_cons.clear();
- }
- }
- /*
- if( d_type==typ_var && p->d_effort==QuantConflictFind::effort_mc && !d_matched_basis ){
- d_matched_basis = true;
- Node f = getOperator( d_n );
- TNode mbo = p->getQuantifiersEngine()->getTermDatabase()->getModelBasisOpTerm( f );
- if( qi->setMatch( p, d_qni_var_num[0], mbo ) ){
- success = true;
- d_qni_bound[0] = d_qni_var_num[0];
- }
- }
- */
- }
- Debug("qcf-match") << " ...finished matching for " << d_n << ", success = " << success << std::endl;
- d_wasSet = success;
- return success;
- }else if( d_type==typ_formula || d_type==typ_ite_var ){
- bool success = false;
- if( d_child_counter<0 ){
- if( d_child_counter<-1 ){
- success = true;
- d_child_counter = -1;
- }
- }else{
- while( !success && d_child_counter>=0 ){
- //transition system based on d_child_counter
- if( d_n.getKind()==OR || d_n.getKind()==AND ){
- if( (d_n.getKind()==AND)==d_tgt ){
- //all children must match simultaneously
- if( getChild( d_child_counter )->getNextMatch( p, qi ) ){
- if( d_child_counter<(int)(getNumChildren()-1) ){
- d_child_counter++;
- Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << std::endl;
- getChild( d_child_counter )->reset( p, d_tgt, qi );
- }else{
- success = true;
- }
- }else{
- //if( std::find( d_independent.begin(), d_independent.end(), d_child_counter )!=d_independent.end() ){
- // d_child_counter--;
- //}else{
- d_child_counter--;
- //}
- }
- }else{
- //one child must match
- if( !getChild( d_child_counter )->getNextMatch( p, qi ) ){
- if( d_child_counter<(int)(getNumChildren()-1) ){
- d_child_counter++;
- Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << ", one match" << std::endl;
- getChild( d_child_counter )->reset( p, d_tgt, qi );
- }else{
- d_child_counter = -1;
- }
- }else{
- success = true;
- }
- }
- }else if( d_n.getKind()==IFF ){
- //construct match based on both children
- if( d_child_counter%2==0 ){
- if( getChild( 0 )->getNextMatch( p, qi ) ){
- d_child_counter++;
- getChild( 1 )->reset( p, d_child_counter==1, qi );
- }else{
- if( d_child_counter==0 ){
- d_child_counter = 2;
- getChild( 0 )->reset( p, !d_tgt, qi );
- }else{
- d_child_counter = -1;
- }
- }
- }
- if( d_child_counter>=0 && d_child_counter%2==1 ){
- if( getChild( 1 )->getNextMatch( p, qi ) ){
- success = true;
- }else{
- d_child_counter--;
- }
- }
- }else if( d_n.getKind()==ITE ){
- if( d_child_counter%2==0 ){
- int index1 = d_child_counter==4 ? 1 : 0;
- if( getChild( index1 )->getNextMatch( p, qi ) ){
- d_child_counter++;
- getChild( d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2) )->reset( p, d_tgt, qi );
- }else{
- if( d_child_counter==4 || ( d_type==typ_ite_var && d_child_counter==2 ) ){
- d_child_counter = -1;
- }else{
- d_child_counter +=2;
- getChild( d_child_counter==2 ? 0 : 1 )->reset( p, d_child_counter==2 ? !d_tgt : d_tgt, qi );
- }
- }
- }
- if( d_child_counter>=0 && d_child_counter%2==1 ){
- int index2 = d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2);
- if( getChild( index2 )->getNextMatch( p, qi ) ){
- success = true;
- }else{
- d_child_counter--;
- }
- }
- }else if( d_n.getKind()==FORALL ){
- if( getChild( d_child_counter )->getNextMatch( p, qi ) ){
- success = true;
- }else{
- d_child_counter = -1;
- }
- }
- }
- d_wasSet = success;
- Debug("qcf-match") << " ...finished construct match for " << d_n << ", success = " << success << std::endl;
- return success;
- }
- }
- Debug("qcf-match") << " ...already finished for " << d_n << std::endl;
- return false;
-}
-
-bool MatchGen::getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp ) {
- if( d_type==typ_eq ){
- Node n[2];
- for( unsigned i=0; i<2; i++ ){
- Trace("qcf-explain") << "Explain term " << d_n[i] << "..." << std::endl;
- n[i] = getExplanationTerm( p, qi, d_n[i], exp );
- }
- Node eq = n[0].eqNode( n[1] );
- if( !d_tgt_orig ){
- eq = eq.negate();
- }
- exp.push_back( eq );
- Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << eq << ", set = " << d_wasSet << std::endl;
- return true;
- }else if( d_type==typ_pred ){
- Trace("qcf-explain") << "Explain term " << d_n << "..." << std::endl;
- Node n = getExplanationTerm( p, qi, d_n, exp );
- if( !d_tgt_orig ){
- n = n.negate();
- }
- exp.push_back( n );
- Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << n << ", set = " << d_wasSet << std::endl;
- return true;
- }else if( d_type==typ_formula ){
- Trace("qcf-explain") << "Explanation get for " << d_n << ", counter = " << d_child_counter << ", tgt = " << d_tgt_orig << ", set = " << d_wasSet << std::endl;
- if( d_n.getKind()==OR || d_n.getKind()==AND ){
- if( (d_n.getKind()==AND)==d_tgt ){
- for( unsigned i=0; i<getNumChildren(); i++ ){
- if( !getChild( i )->getExplanation( p, qi, exp ) ){
- return false;
- }
- }
- }else{
- return getChild( d_child_counter )->getExplanation( p, qi, exp );
- }
- }else if( d_n.getKind()==IFF ){
- for( unsigned i=0; i<2; i++ ){
- if( !getChild( i )->getExplanation( p, qi, exp ) ){
- return false;
- }
- }
- }else if( d_n.getKind()==ITE ){
- for( unsigned i=0; i<3; i++ ){
- bool isActive = ( ( i==0 && d_child_counter!=5 ) ||
- ( i==1 && d_child_counter!=( d_tgt ? 3 : 1 ) ) ||
- ( i==2 && d_child_counter!=( d_tgt ? 1 : 3 ) ) );
- if( isActive ){
- if( !getChild( i )->getExplanation( p, qi, exp ) ){
- return false;
- }
- }
- }
- }else{
- return false;
- }
- return true;
- }else{
- return false;
- }
-}
-
-Node MatchGen::getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp ) {
- Node v = qi->getCurrentExpValue( t );
- if( isHandledUfTerm( t ) ){
- for( unsigned i=0; i<t.getNumChildren(); i++ ){
- Node vi = getExplanationTerm( p, qi, t[i], exp );
- if( vi!=v[i] ){
- Node eq = vi.eqNode( v[i] );
- if( std::find( exp.begin(), exp.end(), eq )==exp.end() ){
- Trace("qcf-explain") << " add : " << eq << "." << std::endl;
- exp.push_back( eq );
- }
- }
- }
- }
- return v;
-}
-
-bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) {
- if( !d_qn.empty() ){
- if( d_qn[0]==NULL ){
- d_qn.clear();
- return true;
- }else{
- Assert( d_type==typ_var );
- Assert( d_qni_size>0 );
- bool invalidMatch;
- do {
- invalidMatch = false;
- Debug("qcf-match-debug") << " Do matching " << d_n << " " << d_qn.size() << " " << d_qni.size() << std::endl;
- if( d_qn.size()==d_qni.size()+1 ) {
- int index = (int)d_qni.size();
- //initialize
- TNode val;
- std::map< int, int >::iterator itv = d_qni_var_num.find( index );
- if( itv!=d_qni_var_num.end() ){
- //get the representative variable this variable is equal to
- int repVar = qi->getCurrentRepVar( itv->second );
- Debug("qcf-match-debug") << " Match " << index << " is a variable " << itv->second << ", which is repVar " << repVar << std::endl;
- //get the value the rep variable
- //std::map< int, TNode >::iterator itm = qi->d_match.find( repVar );
- if( !qi->d_match[repVar].isNull() ){
- val = qi->d_match[repVar];
- Debug("qcf-match-debug") << " Variable is already bound to " << val << std::endl;
- }else{
- //binding a variable
- d_qni_bound[index] = repVar;
- std::map< TNode, QcfNodeIndex >::iterator it = d_qn[index]->d_children.begin();
- if( it != d_qn[index]->d_children.end() ) {
- d_qni.push_back( it );
- //set the match
- if( qi->setMatch( p, d_qni_bound[index], it->first ) ){
- Debug("qcf-match-debug") << " Binding variable" << std::endl;
- if( d_qn.size()<d_qni_size ){
- d_qn.push_back( &it->second );
- }
- }else{
- Debug("qcf-match") << " Binding variable, currently fail." << std::endl;
- invalidMatch = true;
- }
- }else{
- Debug("qcf-match-debug") << " Binding variable, fail, no more variables to bind" << std::endl;
- d_qn.pop_back();
- }
- }
- }else{
- Debug("qcf-match-debug") << " Match " << index << " is ground term" << std::endl;
- Assert( d_qni_gterm.find( index )!=d_qni_gterm.end() );
- Assert( d_qni_gterm_rep.find( index )!=d_qni_gterm_rep.end() );
- val = d_qni_gterm_rep[index];
- Assert( !val.isNull() );
- }
- if( !val.isNull() ){
- //constrained by val
- std::map< TNode, QcfNodeIndex >::iterator it = d_qn[index]->d_children.find( val );
- if( it!=d_qn[index]->d_children.end() ){
- Debug("qcf-match-debug") << " Match" << std::endl;
- d_qni.push_back( it );
- if( d_qn.size()<d_qni_size ){
- d_qn.push_back( &it->second );
- }
- }else{
- Debug("qcf-match-debug") << " Failed to match" << std::endl;
- d_qn.pop_back();
- }
- }
- }else{
- Assert( d_qn.size()==d_qni.size() );
- int index = d_qni.size()-1;
- //increment if binding this variable
- bool success = false;
- std::map< int, int >::iterator itb = d_qni_bound.find( index );
- if( itb!=d_qni_bound.end() ){
- d_qni[index]++;
- if( d_qni[index]!=d_qn[index]->d_children.end() ){
- success = true;
- if( qi->setMatch( p, itb->second, d_qni[index]->first ) ){
- Debug("qcf-match-debug") << " Bind next variable" << std::endl;
- if( d_qn.size()<d_qni_size ){
- d_qn.push_back( &d_qni[index]->second );
- }
- }else{
- Debug("qcf-match-debug") << " Bind next variable, currently fail" << std::endl;
- invalidMatch = true;
- }
- }else{
- qi->d_match[ itb->second ] = TNode::null();
- qi->d_match_term[ itb->second ] = TNode::null();
- Debug("qcf-match-debug") << " Bind next variable, no more variables to bind" << std::endl;
- }
- }else{
- //TODO : if it equal to something else, also try that
- }
- //if not incrementing, move to next
- if( !success ){
- d_qn.pop_back();
- d_qni.pop_back();
- }
- }
- }while( ( !d_qn.empty() && d_qni.size()!=d_qni_size ) || invalidMatch );
- if( d_qni.size()==d_qni_size ){
- //Assert( !d_qni[d_qni.size()-1]->second.d_children.empty() );
- //Debug("qcf-match-debug") << " We matched " << d_qni[d_qni.size()-1]->second.d_children.begin()->first << std::endl;
- Assert( !d_qni[d_qni.size()-1]->second.d_children.empty() );
- TNode t = d_qni[d_qni.size()-1]->second.d_children.begin()->first;
- Debug("qcf-match-debug") << " " << d_n << " matched " << t << std::endl;
- qi->d_match_term[d_qni_var_num[0]] = t;
- //set the match terms
- for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){
- Debug("qcf-match-debug") << " position " << it->first << " bounded " << it->second << " / " << qi->d_q[0].getNumChildren() << std::endl;
- //if( it->second<(int)qi->d_q[0].getNumChildren() ){ //if it is an actual variable, we are interested in knowing the actual term
- if( it->first>0 ){
- Assert( !qi->d_match[ it->second ].isNull() );
- Assert( p->areEqual( t[it->first-1], qi->d_match[ it->second ] ) );
- qi->d_match_term[it->second] = t[it->first-1];
- }
- //}
- }
- }
- }
- }
- return !d_qn.empty();
-}
-
-void MatchGen::debugPrintType( const char * c, short typ, bool isTrace ) {
- if( isTrace ){
- switch( typ ){
- case typ_invalid: Trace(c) << "invalid";break;
- case typ_ground: Trace(c) << "ground";break;
- case typ_eq: Trace(c) << "eq";break;
- case typ_pred: Trace(c) << "pred";break;
- case typ_formula: Trace(c) << "formula";break;
- case typ_var: Trace(c) << "var";break;
- case typ_ite_var: Trace(c) << "ite_var";break;
- case typ_bool_var: Trace(c) << "bool_var";break;
- }
- }else{
- switch( typ ){
- case typ_invalid: Debug(c) << "invalid";break;
- case typ_ground: Debug(c) << "ground";break;
- case typ_eq: Debug(c) << "eq";break;
- case typ_pred: Debug(c) << "pred";break;
- case typ_formula: Debug(c) << "formula";break;
- case typ_var: Debug(c) << "var";break;
- case typ_ite_var: Debug(c) << "ite_var";break;
- case typ_bool_var: Debug(c) << "bool_var";break;
- }
- }
-}
-
-void MatchGen::setInvalid() {
- d_type = typ_invalid;
- d_children.clear();
-}
-
-bool MatchGen::isHandledBoolConnective( TNode n ) {
- return n.getType().isBoolean() && ( n.getKind()==OR || n.getKind()==AND || n.getKind()==IFF || n.getKind()==ITE || n.getKind()==FORALL || n.getKind()==NOT );
-}
-
-bool MatchGen::isHandledUfTerm( TNode n ) {
- //return n.getKind()==APPLY_UF || n.getKind()==STORE || n.getKind()==SELECT ||
- // n.getKind()==APPLY_CONSTRUCTOR || n.getKind()==APPLY_SELECTOR_TOTAL || n.getKind()==APPLY_TESTER;
- return inst::Trigger::isAtomicTriggerKind( n.getKind() );
-}
-
-Node MatchGen::getOperator( QuantConflictFind * p, Node n ) {
- if( isHandledUfTerm( n ) ){
- return p->getQuantifiersEngine()->getTermDatabase()->getOperator( n );
- }else{
- return Node::null();
- }
-}
-
-bool MatchGen::isHandled( TNode n ) {
- if( n.getKind()!=BOUND_VARIABLE && n.hasBoundVar() ){
- if( !isHandledBoolConnective( n ) && !isHandledUfTerm( n ) && n.getKind()!=EQUAL && n.getKind()!=ITE ){
- return false;
- }
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- if( !isHandled( n[i] ) ){
- return false;
- }
- }
- }
- return true;
-}
-
-
-QuantConflictFind::QuantConflictFind( QuantifiersEngine * qe, context::Context* c ) :
-QuantifiersModule( qe ),
-d_c( c ),
-d_conflict( c, false ),
-d_qassert( c ) {
- d_fid_count = 0;
- d_true = NodeManager::currentNM()->mkConst<bool>(true);
- d_false = NodeManager::currentNM()->mkConst<bool>(false);
-}
-
-Node QuantConflictFind::mkEqNode( Node a, Node b ) {
- if( a.getType().isBoolean() ){
- return a.iffNode( b );
- }else{
- return a.eqNode( b );
- }
-}
-
-//-------------------------------------------------- registration
-
-void QuantConflictFind::registerQuantifier( Node q ) {
- if( !TermDb::isRewriteRule( q ) ){
- d_quants.push_back( q );
- d_quant_id[q] = d_quants.size();
- Trace("qcf-qregister") << "Register ";
- debugPrintQuant( "qcf-qregister", q );
- Trace("qcf-qregister") << " : " << q << std::endl;
- //make QcfNode structure
- Trace("qcf-qregister") << "- Get relevant equality/disequality pairs, calculate flattening..." << std::endl;
- d_qinfo[q].initialize( q, q[1] );
-
- //debug print
- Trace("qcf-qregister") << "- Flattened structure is :" << std::endl;
- Trace("qcf-qregister") << " ";
- debugPrintQuantBody( "qcf-qregister", q, q[1] );
- Trace("qcf-qregister") << std::endl;
- if( d_qinfo[q].d_vars.size()>q[0].getNumChildren() ){
- Trace("qcf-qregister") << " with additional constraints : " << std::endl;
- for( unsigned j=q[0].getNumChildren(); j<d_qinfo[q].d_vars.size(); j++ ){
- Trace("qcf-qregister") << " ?x" << j << " = ";
- debugPrintQuantBody( "qcf-qregister", q, d_qinfo[q].d_vars[j], false );
- Trace("qcf-qregister") << std::endl;
- }
- }
-
- Trace("qcf-qregister") << "Done registering quantifier." << std::endl;
- }
-}
-
-int QuantConflictFind::evaluate( Node n, bool pref, bool hasPref ) {
- int ret = 0;
- if( n.getKind()==EQUAL ){
- Node n1 = evaluateTerm( n[0] );
- Node n2 = evaluateTerm( n[1] );
- Debug("qcf-eval") << "Evaluate : Normalize " << n << " to " << n1 << " = " << n2 << std::endl;
- if( areEqual( n1, n2 ) ){
- ret = 1;
- }else if( areDisequal( n1, n2 ) ){
- ret = -1;
- }
- //else if( d_effort>QuantConflictFind::effort_conflict ){
- // ret = -1;
- //}
- }else if( MatchGen::isHandledUfTerm( n ) ){ //predicate
- Node nn = evaluateTerm( n );
- Debug("qcf-eval") << "Evaluate : Normalize " << nn << " to " << n << std::endl;
- if( areEqual( nn, d_true ) ){
- ret = 1;
- }else if( areEqual( nn, d_false ) ){
- ret = -1;
- }
- //else if( d_effort>QuantConflictFind::effort_conflict ){
- // ret = -1;
- //}
- }else if( n.getKind()==NOT ){
- return -evaluate( n[0] );
- }else if( n.getKind()==ITE ){
- int cev1 = evaluate( n[0] );
- int cevc[2] = { 0, 0 };
- for( unsigned i=0; i<2; i++ ){
- if( ( i==0 && cev1!=-1 ) || ( i==1 && cev1!=1 ) ){
- cevc[i] = evaluate( n[i+1] );
- if( cev1!=0 ){
- ret = cevc[i];
- break;
- }else if( cevc[i]==0 ){
- break;
- }
- }
- }
- if( ret==0 && cevc[0]!=0 && cevc[0]==cevc[1] ){
- ret = cevc[0];
- }
- }else if( n.getKind()==IFF ){
- int cev1 = evaluate( n[0] );
- if( cev1!=0 ){
- int cev2 = evaluate( n[1] );
- if( cev2!=0 ){
- ret = cev1==cev2 ? 1 : -1;
- }
- }
-
- }else{
- int ssval = 0;
- if( n.getKind()==OR ){
- ssval = 1;
- }else if( n.getKind()==AND ){
- ssval = -1;
- }
- bool isUnk = false;
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- int cev = evaluate( n[i] );
- if( cev==ssval ){
- ret = ssval;
- break;
- }else if( cev==0 ){
- isUnk = true;
- }
- }
- if( ret==0 && !isUnk ){
- ret = -ssval;
- }
- }
- Debug("qcf-eval") << "Evaluate " << n << " to " << ret << std::endl;
- return ret;
-}
-
-short QuantConflictFind::getMaxQcfEffort() {
- if( options::qcfMode()==QCF_CONFLICT_ONLY ){
- return effort_conflict;
- }else if( options::qcfMode()==QCF_PROP_EQ ){
- return effort_prop_eq;
- }else if( options::qcfMode()==QCF_MC ){
- return effort_mc;
- }else{
- return 0;
- }
-}
-
-bool QuantConflictFind::areMatchEqual( TNode n1, TNode n2 ) {
- //if( d_effort==QuantConflictFind::effort_mc ){
- // return n1==n2 || !areDisequal( n1, n2 );
- //}else{
- return n1==n2;
- //}
-}
-
-bool QuantConflictFind::areMatchDisequal( TNode n1, TNode n2 ) {
- //if( d_effort==QuantConflictFind::effort_conflict ){
- // return areDisequal( n1, n2 );
- //}else{
- return n1!=n2;
- //}
-}
-
-//-------------------------------------------------- handling assertions / eqc
-
-void QuantConflictFind::assertNode( Node q ) {
- if( !TermDb::isRewriteRule( q ) ){
- Trace("qcf-proc") << "QCF : assertQuantifier : ";
- debugPrintQuant("qcf-proc", q);
- Trace("qcf-proc") << std::endl;
- d_qassert.push_back( q );
- //set the eqRegistries that this depends on to true
- //for( std::map< EqRegistry *, bool >::iterator it = d_qinfo[q].d_rel_eqr.begin(); it != d_qinfo[q].d_rel_eqr.end(); ++it ){
- // it->first->d_active.set( true );
- //}
- }
-}
-
-eq::EqualityEngine * QuantConflictFind::getEqualityEngine() {
- //return ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( theory::THEORY_UF ))->getEqualityEngine();
- return d_quantEngine->getTheoryEngine()->getMasterEqualityEngine();
-}
-bool QuantConflictFind::areEqual( Node n1, Node n2 ) {
- return getEqualityEngine()->hasTerm( n1 ) && getEqualityEngine()->hasTerm( n2 ) && getEqualityEngine()->areEqual( n1,n2 );
-}
-bool QuantConflictFind::areDisequal( Node n1, Node n2 ) {
- return n1!=n2 && getEqualityEngine()->hasTerm( n1 ) && getEqualityEngine()->hasTerm( n2 ) && getEqualityEngine()->areDisequal( n1,n2, false );
-}
-Node QuantConflictFind::getRepresentative( Node n ) {
- if( getEqualityEngine()->hasTerm( n ) ){
- return getEqualityEngine()->getRepresentative( n );
- }else{
- return n;
- }
-}
-Node QuantConflictFind::evaluateTerm( Node n ) {
- if( MatchGen::isHandledUfTerm( n ) ){
- Node f = MatchGen::getOperator( this, n );
- Node nn;
- computeUfTerms( f );
- if( getEqualityEngine()->hasTerm( n ) ){
- computeArgReps( n );
- nn = d_uf_terms[f].existsTerm( n, d_arg_reps[n] );
- }else{
- std::vector< TNode > args;
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- Node c = evaluateTerm( n[i] );
- args.push_back( c );
- }
- nn = d_uf_terms[f].existsTerm( n, args );
- }
- if( !nn.isNull() ){
- Debug("qcf-eval") << "GT: Term " << nn << " for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl;
- return getRepresentative( nn );
- }else{
- Debug("qcf-eval") << "GT: No term for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl;
- return n;
- }
- }else if( n.getKind()==ITE ){
- int v = evaluate( n[0], false, false );
- if( v==1 ){
- return evaluateTerm( n[1] );
- }else if( v==-1 ){
- return evaluateTerm( n[2] );
- }
- }
- return getRepresentative( n );
-}
-
-/*
-QuantConflictFind::EqcInfo * QuantConflictFind::getEqcInfo( Node n, bool doCreate ) {
- std::map< Node, EqcInfo * >::iterator it2 = d_eqc_info.find( n );
- if( it2==d_eqc_info.end() ){
- if( doCreate ){
- EqcInfo * eqci = new EqcInfo( d_c );
- d_eqc_info[n] = eqci;
- return eqci;
- }else{
- return NULL;
- }
- }
- return it2->second;
-}
-*/
-
-QcfNodeIndex * QuantConflictFind::getQcfNodeIndex( Node eqc, Node f ) {
- computeUfTerms( f );
- std::map< TNode, QcfNodeIndex >::iterator itut = d_eqc_uf_terms.find( f );
- if( itut==d_eqc_uf_terms.end() ){
- return NULL;
- }else{
- if( eqc.isNull() ){
- return &itut->second;
- }else{
- std::map< TNode, QcfNodeIndex >::iterator itute = itut->second.d_children.find( eqc );
- if( itute!=itut->second.d_children.end() ){
- return &itute->second;
- }else{
- return NULL;
- }
- }
- }
-}
-
-QcfNodeIndex * QuantConflictFind::getQcfNodeIndex( Node f ) {
- computeUfTerms( f );
- std::map< TNode, QcfNodeIndex >::iterator itut = d_uf_terms.find( f );
- if( itut!=d_uf_terms.end() ){
- return &itut->second;
- }else{
- return NULL;
- }
-}
-
-/** new node */
-void QuantConflictFind::newEqClass( Node n ) {
- //Trace("qcf-proc-debug") << "QCF : newEqClass : " << n << std::endl;
- //Trace("qcf-proc2-debug") << "QCF : finished newEqClass : " << n << std::endl;
-}
-
-/** merge */
-void QuantConflictFind::merge( Node a, Node b ) {
- /*
- if( b.getKind()==EQUAL ){
- if( a==d_true ){
- //will merge anyways
- //merge( b[0], b[1] );
- }else if( a==d_false ){
- assertDisequal( b[0], b[1] );
- }
- }else{
- Trace("qcf-proc") << "QCF : merge : " << a << " " << b << std::endl;
- EqcInfo * eqc_b = getEqcInfo( b, false );
- EqcInfo * eqc_a = NULL;
- if( eqc_b ){
- eqc_a = getEqcInfo( a );
- //move disequalities of b into a
- for( NodeBoolMap::iterator it = eqc_b->d_diseq.begin(); it != eqc_b->d_diseq.end(); ++it ){
- if( (*it).second ){
- Node n = (*it).first;
- EqcInfo * eqc_n = getEqcInfo( n, false );
- Assert( eqc_n );
- if( !eqc_n->isDisequal( a ) ){
- Assert( !eqc_a->isDisequal( n ) );
- eqc_n->setDisequal( a );
- eqc_a->setDisequal( n );
- //setEqual( eqc_a, eqc_b, a, n, false );
- }
- eqc_n->setDisequal( b, false );
- }
- }
- ////move all previous EqcRegistry's regarding equalities within b
- //for( NodeBoolMap::iterator it = eqc_b->d_rel_eqr_e.begin(); it != eqc_b->d_rel_eqr_e.end(); ++it ){
- // if( (*it).second ){
- // eqc_a->d_rel_eqr_e[(*it).first] = true;
- // }
- //}
- }
- //process new equalities
- //setEqual( eqc_a, eqc_b, a, b, true );
- Trace("qcf-proc2") << "QCF : finished merge : " << a << " " << b << std::endl;
- }
- */
-}
-
-/** assert disequal */
-void QuantConflictFind::assertDisequal( Node a, Node b ) {
- /*
- a = getRepresentative( a );
- b = getRepresentative( b );
- Trace("qcf-proc") << "QCF : assert disequal : " << a << " " << b << std::endl;
- EqcInfo * eqc_a = getEqcInfo( a );
- EqcInfo * eqc_b = getEqcInfo( b );
- if( !eqc_a->isDisequal( b ) ){
- Assert( !eqc_b->isDisequal( a ) );
- eqc_b->setDisequal( a );
- eqc_a->setDisequal( b );
- //setEqual( eqc_a, eqc_b, a, b, false );
- }
- Trace("qcf-proc2") << "QCF : finished assert disequal : " << a << " " << b << std::endl;
- */
-}
-
-//-------------------------------------------------- check function
-
-void QuantConflictFind::reset_round( Theory::Effort level ) {
- d_needs_computeRelEqr = true;
-}
-
-/** check */
-void QuantConflictFind::check( Theory::Effort level ) {
- Trace("qcf-check") << "QCF : check : " << level << std::endl;
- if( d_conflict ){
- Trace("qcf-check2") << "QCF : finished check : already in conflict." << std::endl;
- if( level>=Theory::EFFORT_FULL ){
- Trace("qcf-warn") << "ALREADY IN CONFLICT? " << level << std::endl;
- //Assert( false );
- }
- }else{
- int addedLemmas = 0;
- if( d_performCheck ){
- ++(d_statistics.d_inst_rounds);
- double clSet = 0;
- int prevEt = 0;
- if( Trace.isOn("qcf-engine") ){
- prevEt = d_statistics.d_entailment_checks.getData();
- clSet = double(clock())/double(CLOCKS_PER_SEC);
- Trace("qcf-engine") << "---Conflict Find Engine Round, effort = " << level << "---" << std::endl;
- }
- computeRelevantEqr();
-
- //determine order for quantified formulas
- std::vector< Node > qorder;
- std::map< Node, bool > qassert;
- //mark which are asserted
- for( unsigned i=0; i<d_qassert.size(); i++ ){
- qassert[d_qassert[i]] = true;
- }
- //add which ones are specified in the order
- for( unsigned i=0; i<d_quant_order.size(); i++ ){
- Node n = d_quant_order[i];
- if( std::find( qorder.begin(), qorder.end(), n )==qorder.end() && qassert.find( n )!=qassert.end() ){
- qorder.push_back( n );
- }
- }
- d_quant_order.clear();
- d_quant_order.insert( d_quant_order.begin(), qorder.begin(), qorder.end() );
- //add remaining
- for( unsigned i=0; i<d_qassert.size(); i++ ){
- Node n = d_qassert[i];
- if( std::find( qorder.begin(), qorder.end(), n )==qorder.end() ){
- qorder.push_back( n );
- }
- }
-
- if( Trace.isOn("qcf-debug") ){
- Trace("qcf-debug") << std::endl;
- debugPrint("qcf-debug");
- Trace("qcf-debug") << std::endl;
- }
- short end_e = getMaxQcfEffort();
- for( short e = effort_conflict; e<=end_e; e++ ){
- d_effort = e;
- Trace("qcf-check") << "Checking quantified formulas at effort " << e << "..." << std::endl;
- for( unsigned j=0; j<qorder.size(); j++ ){
- Node q = qorder[j];
- QuantInfo * qi = &d_qinfo[q];
-
- Assert( d_qinfo.find( q )!=d_qinfo.end() );
- if( qi->d_mg->isValid() ){
- Trace("qcf-check") << "Check quantified formula ";
- debugPrintQuant("qcf-check", q);
- Trace("qcf-check") << " : " << q << "..." << std::endl;
-
- Trace("qcf-check-debug") << "Reset round..." << std::endl;
- qi->reset_round( this );
- //try to make a matches making the body false
- Trace("qcf-check-debug") << "Get next match..." << std::endl;
- while( qi->d_mg->getNextMatch( this, qi ) ){
- Trace("qcf-check") << "*** Produced match at effort " << e << " : " << std::endl;
- qi->debugPrintMatch("qcf-check");
- Trace("qcf-check") << std::endl;
- std::vector< int > assigned;
- if( !qi->isMatchSpurious( this ) ){
- if( qi->completeMatch( this, assigned ) ){
- /*
- if( options::qcfExp() && d_effort==effort_conflict ){
- std::vector< Node > exp;
- if( qi->d_mg->getExplanation( this, qi, exp ) ){
- Trace("qcf-check-exp") << "Base explanation is : " << std::endl;
- for( unsigned c=0; c<exp.size(); c++ ){
- Trace("qcf-check-exp") << " " << exp[c] << std::endl;
- }
- std::vector< TNode > c_exp;
- eq::EqualityEngine* ee = ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getEqualityEngine() ;
- for( unsigned c=0; c<exp.size(); c++ ){
- bool pol = exp[c].getKind()!=NOT;
- TNode lit = pol ? exp[c] : exp[c][0];
- Trace("qcf-check-exp") << "Explain " << lit << ", polarity " << pol << std::endl;
- if( lit.getKind()==EQUAL ){
- if( !pol && !ee->areDisequal( lit[0], lit[1], true ) ){
- exit( 98 );
- }else if( pol && !ee->areEqual( lit[0], lit[1] ) ){
- exit( 99 );
- }
- ee->explainEquality( lit[0], lit[1], pol, c_exp );
- }else{
- if( !ee->areEqual( lit, pol ? d_true : d_false ) ){
- exit( pol ? 96 : 97 );
- }
- ee->explainPredicate( lit, pol, c_exp );
- }
- }
- std::vector< Node > c_lem;
- Trace("qcf-check-exp") << "Actual explanation is : " << std::endl;
- for( unsigned c=0; c<c_exp.size(); c++ ){
- Trace("qcf-check-exp") << " " << c_exp[c] << std::endl;
- Node ccc = c_exp[c].negate();
- if( std::find( c_lem.begin(), c_lem.end(), ccc )==c_lem.end() ){
- c_lem.push_back( ccc );
- }
- }
-
- c_lem.push_back( q.negate() );
- Node conf = NodeManager::currentNM()->mkNode( OR, c_lem );
- Trace("qcf-conflict") << "QCF conflict : " << conf << std::endl;
- d_quantEngine->addLemma( conf, false );
- d_conflict.set( true );
- ++(d_statistics.d_conflict_inst);
- ++addedLemmas;
- break;
- }
- }
- */
- std::vector< Node > terms;
- qi->getMatch( terms );
- if( !qi->isTConstraintSpurious( this, terms ) ){
- if( Debug.isOn("qcf-check-inst") ){
- //if( e==effort_conflict ){
- Node inst = d_quantEngine->getInstantiation( q, terms );
- Debug("qcf-check-inst") << "Check instantiation " << inst << "..." << std::endl;
- Assert( evaluate( inst )!=1 );
- Assert( evaluate( inst )==-1 || e>effort_conflict );
- //}
- }
- if( d_quantEngine->addInstantiation( q, terms, false ) ){
- Trace("qcf-check") << " ... Added instantiation" << std::endl;
- Trace("qcf-inst") << "*** Was from effort " << e << " : " << std::endl;
- qi->debugPrintMatch("qcf-inst");
- Trace("qcf-inst") << std::endl;
- ++addedLemmas;
- if( e==effort_conflict ){
- d_quant_order.insert( d_quant_order.begin(), q );
- d_conflict.set( true );
- ++(d_statistics.d_conflict_inst);
- break;
- }else if( e==effort_prop_eq ){
- ++(d_statistics.d_prop_inst);
- }
- }else{
- Trace("qcf-check") << " ... Failed to add instantiation" << std::endl;
- //Assert( false );
- }
- }
- //clean up assigned
- qi->revertMatch( assigned );
- d_tempCache.clear();
- }else{
- Trace("qcf-check") << " ... Spurious instantiation (cannot assign unassigned variables)" << std::endl;
- }
- }else{
- Trace("qcf-check") << " ... Spurious instantiation (match is inconsistent)" << std::endl;
- }
- }
- if( d_conflict ){
- break;
- }
- }
- }
- if( addedLemmas>0 ){
- d_quantEngine->flushLemmas();
- break;
- }
- }
- if( Trace.isOn("qcf-engine") ){
- double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
- Trace("qcf-engine") << "Finished conflict find engine, time = " << (clSet2-clSet);
- if( addedLemmas>0 ){
- Trace("qcf-engine") << ", effort = " << ( d_effort==effort_conflict ? "conflict" : ( d_effort==effort_prop_eq ? "prop_eq" : "mc" ) );
- Trace("qcf-engine") << ", addedLemmas = " << addedLemmas;
- }
- Trace("qcf-engine") << std::endl;
- int currEt = d_statistics.d_entailment_checks.getData();
- if( currEt!=prevEt ){
- Trace("qcf-engine") << " Entailment checks = " << ( currEt - prevEt ) << std::endl;
- }
- }
- }
- Trace("qcf-check2") << "QCF : finished check : " << level << std::endl;
- }
-}
-
-bool QuantConflictFind::needsCheck( Theory::Effort level ) {
- d_performCheck = false;
- if( options::quantConflictFind() && !d_conflict ){
- if( level==Theory::EFFORT_LAST_CALL ){
- d_performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_LAST_CALL;
- }else if( level==Theory::EFFORT_FULL ){
- d_performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_DEFAULT;
- }else if( level==Theory::EFFORT_STANDARD ){
- d_performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_STD;
- }
- }
- return d_performCheck;
-}
-
-void QuantConflictFind::computeRelevantEqr() {
- if( d_needs_computeRelEqr ){
- d_needs_computeRelEqr = false;
- Trace("qcf-check") << "Compute relevant equalities..." << std::endl;
- d_uf_terms.clear();
- d_eqc_uf_terms.clear();
- d_eqcs.clear();
- d_model_basis.clear();
- d_arg_reps.clear();
- //double clSet = 0;
- //if( Trace.isOn("qcf-opt") ){
- // clSet = double(clock())/double(CLOCKS_PER_SEC);
- //}
-
- //long nTermst = 0;
- //long nTerms = 0;
- //long nEqc = 0;
-
- //which nodes are irrelevant for disequality matches
- std::map< TNode, bool > irrelevant_dnode;
- //now, store matches
- eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() );
- while( !eqcs_i.isFinished() ){
- //nEqc++;
- Node r = (*eqcs_i);
- TypeNode rtn = r.getType();
- if( options::qcfMode()==QCF_MC ){
- std::map< TypeNode, std::vector< TNode > >::iterator itt = d_eqcs.find( rtn );
- if( itt==d_eqcs.end() ){
- Node mb = getQuantifiersEngine()->getTermDatabase()->getModelBasisTerm( rtn );
- if( !getEqualityEngine()->hasTerm( mb ) ){
- Trace("qcf-warn") << "WARNING: Model basis term does not exist!" << std::endl;
- Assert( false );
- }
- Node mbr = getRepresentative( mb );
- if( mbr!=r ){
- d_eqcs[rtn].push_back( mbr );
- }
- d_eqcs[rtn].push_back( r );
- d_model_basis[rtn] = mb;
- }else{
- itt->second.push_back( r );
- }
- }else{
- d_eqcs[rtn].push_back( r );
- }
- /*
- eq::EqClassIterator eqc_i = eq::EqClassIterator( r, getEqualityEngine() );
- while( !eqc_i.isFinished() ){
- TNode n = (*eqc_i);
- if( n.hasBoundVar() ){
- std::cout << "BAD TERM IN DB : " << n << std::endl;
- exit( 199 );
- }
- ++eqc_i;
- }
-
- */
-
- //if( r.getType().isInteger() ){
- // Trace("qcf-mv") << "Model value for eqc(" << r << ") : " << d_quantEngine->getValuation().getModelValue( r ) << std::endl;
- //}
- //EqcInfo * eqcir = getEqcInfo( r, false );
- //get relevant nodes that we are disequal from
- /*
- std::vector< Node > deqc;
- if( eqcir ){
- for( NodeBoolMap::iterator it = eqcir->d_diseq.begin(); it != eqcir->d_diseq.end(); ++it ){
- if( (*it).second ){
- //Node rd = (*it).first;
- //if( rd!=getRepresentative( rd ) ){
- // std::cout << "Bad rep!" << std::endl;
- // exit( 0 );
- //}
- deqc.push_back( (*it).first );
- }
- }
- }
- */
- //process disequalities
- /*
- eq::EqClassIterator eqc_i = eq::EqClassIterator( r, getEqualityEngine() );
- while( !eqc_i.isFinished() ){
- TNode n = (*eqc_i);
- if( n.getKind()!=EQUAL ){
- nTermst++;
- //node_to_rep[n] = r;
- //if( n.getNumChildren()>0 ){
- // if( n.getKind()!=APPLY_UF ){
- // std::cout << n.getKind() << " " << n.getOperator() << " " << n << std::endl;
- // }
- //}
- if( !quantifiers::TermDb::hasBoundVarAttr( n ) ){ //temporary
-
- bool isRedundant;
- std::map< TNode, std::vector< TNode > >::iterator it_na;
- TNode fn;
- if( MatchGen::isHandledUfTerm( n ) ){
- Node f = MatchGen::getOperator( this, n );
- computeArgReps( n );
- it_na = d_arg_reps.find( n );
- Assert( it_na!=d_arg_reps.end() );
- Node nadd = d_eqc_uf_terms[f].d_children[r].addTerm( n, d_arg_reps[n] );
- isRedundant = (nadd!=n);
- d_uf_terms[f].addTerm( n, d_arg_reps[n] );
- }else{
- isRedundant = false;
- }
- nTerms += isRedundant ? 0 : 1;
- }else{
- if( Debug.isOn("qcf-nground") ){
- Debug("qcf-nground") << "Non-ground term in eqc : " << n << std::endl;
- Assert( false );
- }
- }
- }
- ++eqc_i;
- }
- */
- ++eqcs_i;
- }
- /*
- if( Trace.isOn("qcf-opt") ){
- double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
- Trace("qcf-opt") << "Compute rel eqc : " << std::endl;
- Trace("qcf-opt") << " " << nEqc << " equivalence classes. " << std::endl;
- Trace("qcf-opt") << " " << nTerms << " / " << nTermst << " terms." << std::endl;
- Trace("qcf-opt") << " Time : " << (clSet2-clSet) << std::endl;
- }
- */
- }
-}
-
-void QuantConflictFind::computeArgReps( TNode n ) {
- if( d_arg_reps.find( n )==d_arg_reps.end() ){
- Assert( MatchGen::isHandledUfTerm( n ) );
- for( unsigned j=0; j<n.getNumChildren(); j++ ){
- d_arg_reps[n].push_back( getRepresentative( n[j] ) );
- }
- }
-}
-
-void QuantConflictFind::computeUfTerms( TNode f ) {
- if( d_uf_terms.find( f )==d_uf_terms.end() ){
- d_uf_terms[f].clear();
- unsigned nt = d_quantEngine->getTermDatabase()->getNumGroundTerms( f );
- for( unsigned i=0; i<nt; i++ ){
- Node n = d_quantEngine->getTermDatabase()->d_op_map[f][i];
- if( getEqualityEngine()->hasTerm( n ) && !n.getAttribute(NoMatchAttribute()) ){
- Node r = getRepresentative( n );
- computeArgReps( n );
- d_eqc_uf_terms[f].d_children[r].addTerm( n, d_arg_reps[n] );
- d_uf_terms[f].addTerm( n, d_arg_reps[n] );
- }
- }
- }
-}
-
-//-------------------------------------------------- debugging
-
-
-void QuantConflictFind::debugPrint( const char * c ) {
- //print the equivalance classes
- Trace(c) << "----------EQ classes" << std::endl;
- eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() );
- while( !eqcs_i.isFinished() ){
- Node n = (*eqcs_i);
- //if( !n.getType().isInteger() ){
- Trace(c) << " - " << n << " : {";
- eq::EqClassIterator eqc_i = eq::EqClassIterator( n, getEqualityEngine() );
- bool pr = false;
- while( !eqc_i.isFinished() ){
- Node nn = (*eqc_i);
- if( nn.getKind()!=EQUAL && nn!=n ){
- Trace(c) << (pr ? "," : "" ) << " " << nn;
- pr = true;
- }
- ++eqc_i;
- }
- Trace(c) << (pr ? " " : "" ) << "}" << std::endl;
- /*
- EqcInfo * eqcn = getEqcInfo( n, false );
- if( eqcn ){
- Trace(c) << " DEQ : {";
- pr = false;
- for( NodeBoolMap::iterator it = eqcn->d_diseq.begin(); it != eqcn->d_diseq.end(); ++it ){
- if( (*it).second ){
- Trace(c) << (pr ? "," : "" ) << " " << (*it).first;
- pr = true;
- }
- }
- Trace(c) << (pr ? " " : "" ) << "}" << std::endl;
- }
- //}
- */
- ++eqcs_i;
- }
-}
-
-void QuantConflictFind::debugPrintQuant( const char * c, Node q ) {
- Trace(c) << "Q" << d_quant_id[q];
-}
-
-void QuantConflictFind::debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum ) {
- if( n.getNumChildren()==0 ){
- Trace(c) << n;
- }else if( doVarNum && d_qinfo[q].d_var_num.find( n )!=d_qinfo[q].d_var_num.end() ){
- Trace(c) << "?x" << d_qinfo[q].d_var_num[n];
- }else{
- Trace(c) << "(";
- if( n.getKind()==APPLY_UF ){
- Trace(c) << n.getOperator();
- }else{
- Trace(c) << n.getKind();
- }
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- Trace(c) << " ";
- debugPrintQuantBody( c, q, n[i] );
- }
- Trace(c) << ")";
- }
-}
-
-QuantConflictFind::Statistics::Statistics():
- d_inst_rounds("QuantConflictFind::Inst_Rounds", 0),
- d_conflict_inst("QuantConflictFind::Instantiations_Conflict_Find", 0 ),
- d_prop_inst("QuantConflictFind::Instantiations_Prop", 0 ),
- d_entailment_checks("QuantConflictFind::Entailment_Checks",0)
-{
- StatisticsRegistry::registerStat(&d_inst_rounds);
- StatisticsRegistry::registerStat(&d_conflict_inst);
- StatisticsRegistry::registerStat(&d_prop_inst);
- StatisticsRegistry::registerStat(&d_entailment_checks);
-}
-
-QuantConflictFind::Statistics::~Statistics(){
- StatisticsRegistry::unregisterStat(&d_inst_rounds);
- StatisticsRegistry::unregisterStat(&d_conflict_inst);
- StatisticsRegistry::unregisterStat(&d_prop_inst);
- StatisticsRegistry::unregisterStat(&d_entailment_checks);
-}
-
-TNode QuantConflictFind::getZero( Kind k ) {
- std::map< Kind, Node >::iterator it = d_zero.find( k );
- if( it==d_zero.end() ){
- Node nn;
- if( k==PLUS ){
- nn = NodeManager::currentNM()->mkConst( Rational(0) );
- }
- d_zero[k] = nn;
- return nn;
- }else{
- return it->second;
- }
-}
-
-
-}
+/********************* */ +/*! \file quant_conflict_find.cpp + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: none + ** 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 quant conflict find class + ** + **/ + +#include <vector> + +#include "theory/quantifiers/quant_conflict_find.h" +#include "theory/quantifiers/quant_util.h" +#include "theory/theory_engine.h" +#include "theory/quantifiers/options.h" +#include "theory/quantifiers/term_database.h" +#include "theory/quantifiers/trigger.h" + +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::theory; +using namespace CVC4::theory::quantifiers; +using namespace std; + +namespace CVC4 { + +Node QcfNodeIndex::existsTerm( TNode n, std::vector< TNode >& reps, int index ) { + if( index==(int)reps.size() ){ + if( d_children.empty() ){ + return Node::null(); + }else{ + return d_children.begin()->first; + } + }else{ + std::map< TNode, QcfNodeIndex >::iterator it = d_children.find( reps[index] ); + if( it==d_children.end() ){ + return Node::null(); + }else{ + return it->second.existsTerm( n, reps, index+1 ); + } + } +} + +Node QcfNodeIndex::addTerm( TNode n, std::vector< TNode >& reps, int index ) { + if( index==(int)reps.size() ){ + if( d_children.empty() ){ + d_children[ n ].clear(); + return n; + }else{ + return d_children.begin()->first; + } + }else{ + return d_children[reps[index]].addTerm( n, reps, index+1 ); + } +} + + +void QcfNodeIndex::debugPrint( const char * c, int t ) { + for( std::map< TNode, QcfNodeIndex >::iterator it = d_children.begin(); it != d_children.end(); ++it ){ + if( !it->first.isNull() ){ + for( int j=0; j<t; j++ ){ Trace(c) << " "; } + Trace(c) << it->first << " : " << std::endl; + it->second.debugPrint( c, t+1 ); + } + } +} + + +void QuantInfo::initialize( Node q, Node qn ) { + d_q = q; + for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ + d_match.push_back( TNode::null() ); + d_match_term.push_back( TNode::null() ); + } + + //register the variables + for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ + d_var_num[q[0][i]] = i; + d_vars.push_back( q[0][i] ); + } + + registerNode( qn, true, true ); + + + Trace("qcf-qregister") << "- Make match gen structure..." << std::endl; + d_mg = new MatchGen( this, qn ); + + if( d_mg->isValid() ){ + /* + for( unsigned j=0; j<q[0].getNumChildren(); j++ ){ + if( d_inMatchConstraint.find( q[0][j] )==d_inMatchConstraint.end() ){ + Trace("qcf-invalid") << "QCF invalid : variable " << q[0][j] << " does not exist in a matching constraint." << std::endl; + d_mg->setInvalid(); + break; + } + } + */ + if( d_mg->isValid() ){ + for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){ + if( d_vars[j].getKind()!=BOUND_VARIABLE ){ + d_var_mg[j] = NULL; + bool is_tsym = false; + if( !MatchGen::isHandledUfTerm( d_vars[j] ) && d_vars[j].getKind()!=ITE ){ + is_tsym = true; + d_tsym_vars.push_back( j ); + } + if( !is_tsym || options::qcfTConstraint() ){ + d_var_mg[j] = new MatchGen( this, d_vars[j], true ); + } + if( !d_var_mg[j] || !d_var_mg[j]->isValid() ){ + Trace("qcf-invalid") << "QCF invalid : cannot match for " << d_vars[j] << std::endl; + d_mg->setInvalid(); + break; + }else{ + std::vector< int > bvars; + d_var_mg[j]->determineVariableOrder( this, bvars ); + } + } + } + if( d_mg->isValid() ){ + std::vector< int > bvars; + d_mg->determineVariableOrder( this, bvars ); + } + } + }else{ + Trace("qcf-invalid") << "QCF invalid : body of formula cannot be processed." << std::endl; + } + Trace("qcf-qregister-summary") << "QCF register : " << ( d_mg->isValid() ? "VALID " : "INVALID" ) << " : " << q << std::endl; +} + +void QuantInfo::registerNode( Node n, bool hasPol, bool pol, bool beneathQuant ) { + Trace("qcf-qregister-debug2") << "Register : " << n << std::endl; + if( n.getKind()==FORALL ){ + registerNode( n[1], hasPol, pol, true ); + }else{ + if( !MatchGen::isHandledBoolConnective( n ) ){ + if( n.hasBoundVar() ){ + //literals + if( n.getKind()==EQUAL ){ + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + flatten( n[i], beneathQuant ); + } + }else if( MatchGen::isHandledUfTerm( n ) ){ + flatten( n, beneathQuant ); + }else if( n.getKind()==ITE ){ + for( unsigned i=1; i<=2; i++ ){ + flatten( n[i], beneathQuant ); + } + registerNode( n[0], false, pol, beneathQuant ); + }else if( options::qcfTConstraint() ){ + //a theory-specific predicate + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + flatten( n[i], beneathQuant ); + } + } + } + }else{ + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + bool newHasPol; + bool newPol; + QuantPhaseReq::getPolarity( n, i, hasPol, pol, newHasPol, newPol ); + //QcfNode * qcfc = new QcfNode( d_c ); + //qcfc->d_parent = qcf; + //qcf->d_child[i] = qcfc; + registerNode( n[i], newHasPol, newPol, beneathQuant ); + } + } + } +} + +void QuantInfo::flatten( Node n, bool beneathQuant ) { + Trace("qcf-qregister-debug2") << "Flatten : " << n << std::endl; + if( n.hasBoundVar() ){ + if( n.getKind()==BOUND_VARIABLE ){ + d_inMatchConstraint[n] = true; + } + //if( MatchGen::isHandledUfTerm( n ) || n.getKind()==ITE ){ + if( d_var_num.find( n )==d_var_num.end() ){ + Trace("qcf-qregister-debug2") << "Add FLATTEN VAR : " << n << std::endl; + d_var_num[n] = d_vars.size(); + d_vars.push_back( n ); + d_match.push_back( TNode::null() ); + d_match_term.push_back( TNode::null() ); + if( n.getKind()==ITE ){ + registerNode( n, false, false ); + }else{ + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + flatten( n[i], beneathQuant ); + } + } + }else{ + Trace("qcf-qregister-debug2") << "...already processed" << std::endl; + } + }else{ + Trace("qcf-qregister-debug2") << "...is ground." << std::endl; + } +} + + +void QuantInfo::reset_round( QuantConflictFind * p ) { + for( unsigned i=0; i<d_match.size(); i++ ){ + d_match[i] = TNode::null(); + d_match_term[i] = TNode::null(); + } + d_curr_var_deq.clear(); + d_tconstraints.clear(); + //add built-in variable constraints + for( unsigned r=0; r<2; r++ ){ + for( std::map< int, std::vector< Node > >::iterator it = d_var_constraint[r].begin(); + it != d_var_constraint[r].end(); ++it ){ + for( unsigned j=0; j<it->second.size(); j++ ){ + Node rr = it->second[j]; + if( !isVar( rr ) ){ + rr = p->getRepresentative( rr ); + } + if( addConstraint( p, it->first, rr, r==0 )==-1 ){ + d_var_constraint[0].clear(); + d_var_constraint[1].clear(); + //quantified formula is actually equivalent to true + Trace("qcf-qregister") << "Quantifier is equivalent to true!!!" << std::endl; + d_mg->d_children.clear(); + d_mg->d_n = NodeManager::currentNM()->mkConst( true ); + d_mg->d_type = MatchGen::typ_ground; + return; + } + } + } + } + d_mg->reset_round( p ); + for( std::map< int, MatchGen * >::iterator it = d_var_mg.begin(); it != d_var_mg.end(); ++it ){ + it->second->reset_round( p ); + } + //now, reset for matching + d_mg->reset( p, false, this ); +} + +int QuantInfo::getCurrentRepVar( int v ) { + if( v!=-1 && !d_match[v].isNull() ){ + int vn = getVarNum( d_match[v] ); + if( vn!=-1 ){ + //int vr = getCurrentRepVar( vn ); + //d_match[v] = d_vars[vr]; + //return vr; + return getCurrentRepVar( vn ); + } + } + return v; +} + +TNode QuantInfo::getCurrentValue( TNode n ) { + int v = getVarNum( n ); + if( v==-1 ){ + return n; + }else{ + if( d_match[v].isNull() ){ + return n; + }else{ + Assert( getVarNum( d_match[v] )!=v ); + return getCurrentValue( d_match[v] ); + } + } +} + +TNode QuantInfo::getCurrentExpValue( TNode n ) { + int v = getVarNum( n ); + if( v==-1 ){ + return n; + }else{ + if( d_match[v].isNull() ){ + return n; + }else{ + Assert( getVarNum( d_match[v] )!=v ); + if( d_match_term[v].isNull() ){ + return getCurrentValue( d_match[v] ); + }else{ + return d_match_term[v]; + } + } + } +} + +bool QuantInfo::getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq ) { + //check disequalities + std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v ); + if( itd!=d_curr_var_deq.end() ){ + for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){ + Node cv = getCurrentValue( it->first ); + Debug("qcf-ccbe") << "compare " << cv << " " << n << std::endl; + if( cv==n ){ + return false; + }else if( chDiseq && !isVar( n ) && !isVar( cv ) ){ + //they must actually be disequal if we are looking for conflicts + if( !p->areDisequal( n, cv ) ){ + //TODO : check for entailed disequal + + return false; + } + } + } + } + return true; +} + +int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity ) { + v = getCurrentRepVar( v ); + int vn = getVarNum( n ); + vn = vn==-1 ? -1 : getCurrentRepVar( vn ); + n = getCurrentValue( n ); + return addConstraint( p, v, n, vn, polarity, false ); +} + +int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove ) { + //for handling equalities between variables, and disequalities involving variables + Debug("qcf-match-debug") << "- " << (doRemove ? "un" : "" ) << "constrain : " << v << " -> " << n << " (cv=" << getCurrentValue( n ) << ")"; + Debug("qcf-match-debug") << ", (vn=" << vn << "), polarity = " << polarity << std::endl; + Assert( doRemove || n==getCurrentValue( n ) ); + Assert( doRemove || v==getCurrentRepVar( v ) ); + Assert( doRemove || vn==getCurrentRepVar( getVarNum( n ) ) ); + if( polarity ){ + if( vn!=v ){ + if( doRemove ){ + if( vn!=-1 ){ + //if set to this in the opposite direction, clean up opposite instead + // std::map< int, TNode >::iterator itmn = d_match.find( vn ); + if( d_match[vn]==d_vars[v] ){ + return addConstraint( p, vn, d_vars[v], v, true, true ); + }else{ + //unsetting variables equal + std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( vn ); + if( itd!=d_curr_var_deq.end() ){ + //remove disequalities owned by this + std::vector< TNode > remDeq; + for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){ + if( it->second==v ){ + remDeq.push_back( it->first ); + } + } + for( unsigned i=0; i<remDeq.size(); i++ ){ + d_curr_var_deq[vn].erase( remDeq[i] ); + } + } + } + } + d_match[v] = TNode::null(); + return 1; + }else{ + //std::map< int, TNode >::iterator itm = d_match.find( v ); + + if( vn!=-1 ){ + Debug("qcf-match-debug") << " ...Variable bound to variable" << std::endl; + //std::map< int, TNode >::iterator itmn = d_match.find( vn ); + if( d_match[v].isNull() ){ + //setting variables equal + bool alreadySet = false; + if( !d_match[vn].isNull() ){ + alreadySet = true; + Assert( !isVar( d_match[vn] ) ); + } + + //copy or check disequalities + std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v ); + if( itd!=d_curr_var_deq.end() ){ + for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){ + Node dv = getCurrentValue( it->first ); + if( !alreadySet ){ + if( d_curr_var_deq[vn].find( dv )==d_curr_var_deq[vn].end() ){ + d_curr_var_deq[vn][dv] = v; + } + }else{ + if( !p->areMatchDisequal( d_match[vn], dv ) ){ + Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl; + return -1; + } + } + } + } + if( alreadySet ){ + n = getCurrentValue( n ); + } + }else{ + if( d_match[vn].isNull() ){ + Debug("qcf-match-debug") << " ...Reverse direction" << std::endl; + //set the opposite direction + return addConstraint( p, vn, d_vars[v], v, true, false ); + }else{ + Debug("qcf-match-debug") << " -> Both variables bound, compare" << std::endl; + //are they currently equal + return p->areMatchEqual( d_match[v], d_match[vn] ) ? 0 : -1; + } + } + }else{ + Debug("qcf-match-debug") << " ...Variable bound to ground" << std::endl; + if( d_match[v].isNull() ){ + }else{ + //compare ground values + Debug("qcf-match-debug") << " -> Ground value, compare " << d_match[v] << " "<< n << std::endl; + return p->areMatchEqual( d_match[v], n ) ? 0 : -1; + } + } + if( setMatch( p, v, n ) ){ + Debug("qcf-match-debug") << " -> success" << std::endl; + return 1; + }else{ + Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl; + return -1; + } + } + }else{ + Debug("qcf-match-debug") << " -> redundant, variable identity" << std::endl; + return 0; + } + }else{ + if( vn==v ){ + Debug("qcf-match-debug") << " -> fail, variable identity" << std::endl; + return -1; + }else{ + if( doRemove ){ + Assert( d_curr_var_deq[v].find( n )!=d_curr_var_deq[v].end() ); + d_curr_var_deq[v].erase( n ); + return 1; + }else{ + if( d_curr_var_deq[v].find( n )==d_curr_var_deq[v].end() ){ + //check if it respects equality + //std::map< int, TNode >::iterator itm = d_match.find( v ); + if( !d_match[v].isNull() ){ + TNode nv = getCurrentValue( n ); + if( !p->areMatchDisequal( nv, d_match[v] ) ){ + Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl; + return -1; + } + } + d_curr_var_deq[v][n] = v; + Debug("qcf-match-debug") << " -> success" << std::endl; + return 1; + }else{ + Debug("qcf-match-debug") << " -> redundant disequality" << std::endl; + return 0; + } + } + } + } +} + +bool QuantInfo::isConstrainedVar( int v ) { + if( d_curr_var_deq.find( v )!=d_curr_var_deq.end() && !d_curr_var_deq[v].empty() ){ + return true; + }else{ + Node vv = getVar( v ); + //for( std::map< int, TNode >::iterator it = d_match.begin(); it != d_match.end(); ++it ){ + for( unsigned i=0; i<d_match.size(); i++ ){ + if( d_match[i]==vv ){ + return true; + } + } + for( std::map< int, std::map< TNode, int > >::iterator it = d_curr_var_deq.begin(); it != d_curr_var_deq.end(); ++it ){ + for( std::map< TNode, int >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ + if( it2->first==vv ){ + return true; + } + } + } + return false; + } +} + +bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n ) { + if( getCurrentCanBeEqual( p, v, n ) ){ + Debug("qcf-match-debug") << "-- bind : " << v << " -> " << n << ", checked " << d_curr_var_deq[v].size() << " disequalities" << std::endl; + d_match[v] = n; + return true; + }else{ + return false; + } +} + +bool QuantInfo::isMatchSpurious( QuantConflictFind * p ) { + for( int i=0; i<getNumVars(); i++ ){ + //std::map< int, TNode >::iterator it = d_match.find( i ); + if( !d_match[i].isNull() ){ + if( !getCurrentCanBeEqual( p, i, d_match[i], p->d_effort==QuantConflictFind::effort_conflict ) ){ + return true; + } + } + } + return false; +} + +bool QuantInfo::isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms ) { + if( !d_tconstraints.empty() ){ + //check constraints + for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){ + //apply substitution to the tconstraint + Node cons = it->first.substitute( p->getQuantifiersEngine()->getTermDatabase()->d_vars[d_q].begin(), + p->getQuantifiersEngine()->getTermDatabase()->d_vars[d_q].end(), + terms.begin(), terms.end() ); + cons = it->second ? cons : cons.negate(); + if( !entailmentTest( p, cons, p->d_effort==QuantConflictFind::effort_conflict ) ){ + return true; + } + } + } + return false; +} + +bool QuantInfo::entailmentTest( QuantConflictFind * p, Node lit, bool chEnt ) { + Trace("qcf-tconstraint-debug") << "Check : " << lit << std::endl; + Node rew = Rewriter::rewrite( lit ); + if( rew==p->d_false ){ + Trace("qcf-tconstraint-debug") << "...constraint " << lit << " is disentailed (rewrites to false)." << std::endl; + return false; + }else if( rew!=p->d_true ){ + //if checking for conflicts, we must be sure that the constraint is entailed + if( chEnt ){ + //check if it is entailed + Trace("qcf-tconstraint-debug") << "Check entailment of " << rew << "..." << std::endl; + std::pair<bool, Node> et = p->getQuantifiersEngine()->getTheoryEngine()->entailmentCheck(THEORY_OF_TYPE_BASED, rew ); + ++(p->d_statistics.d_entailment_checks); + Trace("qcf-tconstraint-debug") << "ET result : " << et.first << " " << et.second << std::endl; + if( !et.first ){ + Trace("qcf-tconstraint-debug") << "...cannot show entailment of " << rew << "." << std::endl; + return false; + }else{ + return true; + } + }else{ + Trace("qcf-tconstraint-debug") << "...does not need to be entailed." << std::endl; + return true; + } + }else{ + Trace("qcf-tconstraint-debug") << "...rewrites to true." << std::endl; + return true; + } +} + +bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue ) { + //assign values for variables that were unassigned (usually not necessary, but handles corner cases) + bool doFail = false; + bool success = true; + if( doContinue ){ + doFail = true; + success = false; + }else{ + //solve for interpreted symbol matches + // this breaks the invariant that all introduced constraints are over existing terms + for( int i=(int)(d_tsym_vars.size()-1); i>=0; i-- ){ + int index = d_tsym_vars[i]; + TNode v = getCurrentValue( d_vars[index] ); + int slv_v = -1; + if( v==d_vars[index] ){ + slv_v = index; + } + Trace("qcf-tconstraint-debug") << "Solve " << d_vars[index] << " = " << v << " " << d_vars[index].getKind() << std::endl; + if( d_vars[index].getKind()==PLUS || d_vars[index].getKind()==MULT ){ + Kind k = d_vars[index].getKind(); + std::vector< TNode > children; + for( unsigned j=0; j<d_vars[index].getNumChildren(); j++ ){ + int vn = getVarNum( d_vars[index][j] ); + if( vn!=-1 ){ + TNode vv = getCurrentValue( d_vars[index][j] ); + if( vv==d_vars[index][j] ){ + //we will assign this + if( slv_v==-1 ){ + Trace("qcf-tconstraint-debug") << "...will solve for var #" << vn << std::endl; + slv_v = vn; + if( p->d_effort!=QuantConflictFind::effort_conflict ){ + break; + } + }else{ + Node z = p->getZero( k ); + if( !z.isNull() ){ + Trace("qcf-tconstraint-debug") << "...set " << d_vars[vn] << " = " << z << std::endl; + assigned.push_back( vn ); + if( !setMatch( p, vn, z ) ){ + success = false; + break; + } + } + } + }else{ + Trace("qcf-tconstraint-debug") << "...sum value " << vv << std::endl; + children.push_back( vv ); + } + }else{ + Trace("qcf-tconstraint-debug") << "...sum " << d_vars[index][j] << std::endl; + children.push_back( d_vars[index][j] ); + } + } + if( success ){ + if( slv_v!=-1 ){ + Node lhs; + if( children.empty() ){ + lhs = p->getZero( k ); + }else if( children.size()==1 ){ + lhs = children[0]; + }else{ + lhs = NodeManager::currentNM()->mkNode( k, children ); + } + Node sum; + if( v==d_vars[index] ){ + sum = lhs; + }else{ + if( p->d_effort==QuantConflictFind::effort_conflict ){ + Kind kn = k; + if( d_vars[index].getKind()==PLUS ){ + kn = MINUS; + } + if( kn!=k ){ + sum = NodeManager::currentNM()->mkNode( kn, v, lhs ); + } + } + } + if( !sum.isNull() ){ + assigned.push_back( slv_v ); + Trace("qcf-tconstraint-debug") << "...set " << d_vars[slv_v] << " = " << sum << std::endl; + if( !setMatch( p, slv_v, sum ) ){ + success = false; + } + p->d_tempCache.push_back( sum ); + } + }else{ + //must show that constraint is met + Node sum = NodeManager::currentNM()->mkNode( k, children ); + Node eq = sum.eqNode( v ); + if( !entailmentTest( p, eq ) ){ + success = false; + } + p->d_tempCache.push_back( sum ); + } + } + } + + if( !success ){ + break; + } + } + if( success ){ + //check what is left to assign + d_unassigned.clear(); + d_unassigned_tn.clear(); + std::vector< int > unassigned[2]; + std::vector< TypeNode > unassigned_tn[2]; + for( int i=0; i<getNumVars(); i++ ){ + if( d_match[i].isNull() ){ + int rindex = d_var_mg.find( i )==d_var_mg.end() ? 1 : 0; + unassigned[rindex].push_back( i ); + unassigned_tn[rindex].push_back( getVar( i ).getType() ); + assigned.push_back( i ); + } + } + d_unassigned_nvar = unassigned[0].size(); + for( unsigned i=0; i<2; i++ ){ + d_unassigned.insert( d_unassigned.end(), unassigned[i].begin(), unassigned[i].end() ); + d_unassigned_tn.insert( d_unassigned_tn.end(), unassigned_tn[i].begin(), unassigned_tn[i].end() ); + } + d_una_eqc_count.clear(); + d_una_index = 0; + } + } + + if( !d_unassigned.empty() && ( success || doContinue ) ){ + Trace("qcf-check") << "Assign to unassigned..." << std::endl; + do { + if( doFail ){ + Trace("qcf-check-unassign") << "Failure, try again..." << std::endl; + } + bool invalidMatch = false; + while( ( d_una_index>=0 && (int)d_una_index<(int)d_unassigned.size() ) || invalidMatch || doFail ){ + invalidMatch = false; + if( !doFail && d_una_index==(int)d_una_eqc_count.size() ){ + //check if it has now been assigned + if( d_una_index<d_unassigned_nvar ){ + if( !isConstrainedVar( d_unassigned[d_una_index] ) ){ + d_una_eqc_count.push_back( -1 ); + }else{ + d_var_mg[ d_unassigned[d_una_index] ]->reset( p, true, this ); + d_una_eqc_count.push_back( 0 ); + } + }else{ + d_una_eqc_count.push_back( 0 ); + } + }else{ + bool failed = false; + if( !doFail ){ + if( d_una_index<d_unassigned_nvar ){ + if( !isConstrainedVar( d_unassigned[d_una_index] ) ){ + Trace("qcf-check-unassign") << "Succeeded, variable unconstrained at " << d_una_index << std::endl; + d_una_index++; + }else if( d_var_mg[d_unassigned[d_una_index]]->getNextMatch( p, this ) ){ + Trace("qcf-check-unassign") << "Succeeded match with mg at " << d_una_index << std::endl; + d_una_index++; + }else{ + failed = true; + Trace("qcf-check-unassign") << "Failed match with mg at " << d_una_index << std::endl; + } + }else{ + Assert( doFail || d_una_index==(int)d_una_eqc_count.size()-1 ); + if( d_una_eqc_count[d_una_index]<(int)p->d_eqcs[d_unassigned_tn[d_una_index]].size() ){ + int currIndex = d_una_eqc_count[d_una_index]; + d_una_eqc_count[d_una_index]++; + Trace("qcf-check-unassign") << d_unassigned[d_una_index] << "->" << p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] << std::endl; + if( setMatch( p, d_unassigned[d_una_index], p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] ) ){ + d_match_term[d_unassigned[d_una_index]] = TNode::null(); + Trace("qcf-check-unassign") << "Succeeded match " << d_una_index << std::endl; + d_una_index++; + }else{ + Trace("qcf-check-unassign") << "Failed match " << d_una_index << std::endl; + invalidMatch = true; + } + }else{ + failed = true; + Trace("qcf-check-unassign") << "No more matches " << d_una_index << std::endl; + } + } + } + if( doFail || failed ){ + do{ + if( !doFail ){ + d_una_eqc_count.pop_back(); + }else{ + doFail = false; + } + d_una_index--; + }while( d_una_index>=0 && d_una_eqc_count[d_una_index]==-1 ); + } + } + } + success = d_una_index>=0; + if( success ){ + doFail = true; + Trace("qcf-check-unassign") << " Try: " << std::endl; + for( unsigned i=0; i<d_unassigned.size(); i++ ){ + int ui = d_unassigned[i]; + if( !d_match[ui].isNull() ){ + Trace("qcf-check-unassign") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl; + } + } + } + }while( success && isMatchSpurious( p ) ); + } + if( success ){ + for( unsigned i=0; i<d_unassigned.size(); i++ ){ + int ui = d_unassigned[i]; + if( !d_match[ui].isNull() ){ + Trace("qcf-check") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl; + } + } + return true; + }else{ + for( unsigned i=0; i<assigned.size(); i++ ){ + d_match[ assigned[i] ] = TNode::null(); + } + assigned.clear(); + return false; + } +} + +void QuantInfo::getMatch( std::vector< Node >& terms ){ + for( unsigned i=0; i<d_q[0].getNumChildren(); i++ ){ + //Node cv = qi->getCurrentValue( qi->d_match[i] ); + int repVar = getCurrentRepVar( i ); + Node cv; + //std::map< int, TNode >::iterator itmt = qi->d_match_term.find( repVar ); + if( !d_match_term[repVar].isNull() ){ + cv = d_match_term[repVar]; + }else{ + cv = d_match[repVar]; + } + Debug("qcf-check-inst") << "INST : " << i << " -> " << cv << ", from " << d_match[i] << std::endl; + terms.push_back( cv ); + } +} + +void QuantInfo::revertMatch( std::vector< int >& assigned ) { + for( unsigned i=0; i<assigned.size(); i++ ){ + d_match[ assigned[i] ] = TNode::null(); + } +} + +void QuantInfo::debugPrintMatch( const char * c ) { + for( int i=0; i<getNumVars(); i++ ){ + Trace(c) << " " << d_vars[i] << " -> "; + if( !d_match[i].isNull() ){ + Trace(c) << d_match[i]; + }else{ + Trace(c) << "(unassigned) "; + } + if( !d_curr_var_deq[i].empty() ){ + Trace(c) << ", DEQ{ "; + for( std::map< TNode, int >::iterator it = d_curr_var_deq[i].begin(); it != d_curr_var_deq[i].end(); ++it ){ + Trace(c) << it->first << " "; + } + Trace(c) << "}"; + } + if( !d_match_term[i].isNull() && d_match_term[i]!=d_match[i] ){ + Trace(c) << ", EXP : " << d_match_term[i]; + } + Trace(c) << std::endl; + } + if( !d_tconstraints.empty() ){ + Trace(c) << "ADDITIONAL CONSTRAINTS : " << std::endl; + for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){ + Trace(c) << " " << it->first << " -> " << it->second << std::endl; + } + } +} + +MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar ){ + Trace("qcf-qregister-debug") << "Make match gen for " << n << ", isVar = " << isVar << std::endl; + std::vector< Node > qni_apps; + d_qni_size = 0; + if( isVar ){ + Assert( qi->d_var_num.find( n )!=qi->d_var_num.end() ); + if( n.getKind()==ITE ){ + d_type = typ_ite_var; + d_type_not = false; + d_n = n; + d_children.push_back( MatchGen( qi, d_n[0] ) ); + if( d_children[0].isValid() ){ + d_type = typ_ite_var; + for( unsigned i=1; i<=2; i++ ){ + Node nn = n.eqNode( n[i] ); + d_children.push_back( MatchGen( qi, nn ) ); + d_children[d_children.size()-1].d_qni_bound_except.push_back( 0 ); + if( !d_children[d_children.size()-1].isValid() ){ + setInvalid(); + break; + } + } + }else{ + d_type = typ_invalid; + } + }else{ + d_type = isHandledUfTerm( n ) ? typ_var : typ_tsym; + d_qni_var_num[0] = qi->getVarNum( n ); + d_qni_size++; + d_type_not = false; + d_n = n; + //Node f = getOperator( n ); + for( unsigned j=0; j<d_n.getNumChildren(); j++ ){ + Node nn = d_n[j]; + Trace("qcf-qregister-debug") << " " << d_qni_size; + if( qi->isVar( nn ) ){ + int v = qi->d_var_num[nn]; + Trace("qcf-qregister-debug") << " is var #" << v << std::endl; + d_qni_var_num[d_qni_size] = v; + //qi->addFuncParent( v, f, j ); + }else{ + Trace("qcf-qregister-debug") << " is gterm " << nn << std::endl; + d_qni_gterm[d_qni_size] = nn; + } + d_qni_size++; + } + } + }else{ + if( n.hasBoundVar() ){ + d_type_not = false; + d_n = n; + if( d_n.getKind()==NOT ){ + d_n = d_n[0]; + d_type_not = !d_type_not; + } + + if( isHandledBoolConnective( d_n ) ){ + //non-literals + d_type = typ_formula; + for( unsigned i=0; i<d_n.getNumChildren(); i++ ){ + if( d_n.getKind()!=FORALL || i==1 ){ + d_children.push_back( MatchGen( qi, d_n[i], false ) ); + if( !d_children[d_children.size()-1].isValid() ){ + setInvalid(); + break; + } + } + /* + else if( isTop && n.getKind()==OR && d_children[d_children.size()-1].d_type==typ_var_eq ){ + Trace("qcf-qregister-debug") << "Remove child, make built-in constraint" << std::endl; + //if variable equality/disequality at top level, remove immediately + bool cIsNot = d_children[d_children.size()-1].d_type_not; + Node cn = d_children[d_children.size()-1].d_n; + Assert( cn.getKind()==EQUAL ); + Assert( p->d_qinfo[q].isVar( cn[0] ) || p->d_qinfo[q].isVar( cn[1] ) ); + //make it a built-in constraint instead + for( unsigned i=0; i<2; i++ ){ + if( p->d_qinfo[q].isVar( cn[i] ) ){ + int v = p->d_qinfo[q].getVarNum( cn[i] ); + Node cno = cn[i==0 ? 1 : 0]; + p->d_qinfo[q].d_var_constraint[ cIsNot ? 0 : 1 ][v].push_back( cno ); + break; + } + } + d_children.pop_back(); + } + */ + } + }else{ + d_type = typ_invalid; + //literals + if( isHandledUfTerm( d_n ) ){ + Assert( qi->isVar( d_n ) ); + d_type = typ_pred; + }else if( d_n.getKind()==BOUND_VARIABLE ){ + Assert( d_n.getType().isBoolean() ); + d_type = typ_bool_var; + }else if( d_n.getKind()==EQUAL || options::qcfTConstraint() ){ + for( unsigned i=0; i<d_n.getNumChildren(); i++ ){ + if( d_n[i].hasBoundVar() ){ + if( !qi->isVar( d_n[i] ) ){ + Trace("qcf-qregister-debug") << "ERROR : not var " << d_n[i] << std::endl; + } + Assert( qi->isVar( d_n[i] ) ); + if( d_n.getKind()!=EQUAL && qi->isVar( d_n[i] ) ){ + d_qni_var_num[i+1] = qi->d_var_num[d_n[i]]; + } + }else{ + d_qni_gterm[i] = d_n[i]; + } + } + d_type = d_n.getKind()==EQUAL ? typ_eq : typ_tconstraint; + Trace("qcf-tconstraint") << "T-Constraint : " << d_n << std::endl; + } + } + }else{ + //we will just evaluate + d_n = n; + d_type = typ_ground; + } + //if( d_type!=typ_invalid ){ + //determine an efficient children ordering + //if( !d_children.empty() ){ + //for( unsigned i=0; i<d_children.size(); i++ ){ + // d_children_order.push_back( i ); + //} + //if( !d_n.isNull() && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF ) ){ + //sort based on the type of the constraint : ground comes first, then literals, then others + //MatchGenSort mgs; + //mgs.d_mg = this; + //std::sort( d_children_order.begin(), d_children_order.end(), mgs ); + //} + //} + //} + } + Trace("qcf-qregister-debug") << "Done make match gen " << n << ", type = "; + debugPrintType( "qcf-qregister-debug", d_type, true ); + Trace("qcf-qregister-debug") << std::endl; + //Assert( d_children.size()==d_children_order.size() ); + +} + +void MatchGen::collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars ) { + int v = qi->getVarNum( n ); + if( v!=-1 && std::find( cbvars.begin(), cbvars.end(), v )==cbvars.end() ){ + cbvars.push_back( v ); + } + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + collectBoundVar( qi, n[i], cbvars ); + } +} + +void MatchGen::determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars ) { + Trace("qcf-qregister-debug") << "Determine variable order " << d_n << std::endl; + bool isCom = d_type==typ_formula && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF ); + std::map< int, std::vector< int > > c_to_vars; + std::map< int, std::vector< int > > vars_to_c; + std::map< int, int > vb_count; + std::map< int, int > vu_count; + std::vector< bool > assigned; + Trace("qcf-qregister-debug") << "Calculate bound variables..." << std::endl; + for( unsigned i=0; i<d_children.size(); i++ ){ + collectBoundVar( qi, d_children[i].d_n, c_to_vars[i] ); + assigned.push_back( false ); + vb_count[i] = 0; + vu_count[i] = 0; + for( unsigned j=0; j<c_to_vars[i].size(); j++ ){ + int v = c_to_vars[i][j]; + vars_to_c[v].push_back( i ); + if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){ + vu_count[i]++; + if( !isCom ){ + bvars.push_back( v ); + } + }else{ + vb_count[i]++; + } + } + } + if( isCom ){ + //children that bind the least number of unbound variables go first + do { + int min_score = -1; + int min_score_index = -1; + for( unsigned i=0; i<d_children.size(); i++ ){ + if( !assigned[i] ){ + int score = vu_count[i]; + if( min_score==-1 || score<min_score ){ + min_score = score; + min_score_index = i; + } + } + } + Trace("qcf-qregister-debug") << "...assign child " << min_score_index << "/" << d_children.size() << std::endl; + Assert( min_score_index!=-1 ); + //add to children order + d_children_order.push_back( min_score_index ); + assigned[min_score_index] = true; + //if( vb_count[min_score_index]==0 ){ + // d_independent.push_back( min_score_index ); + //} + //determine order internal to children + d_children[min_score_index].determineVariableOrder( qi, bvars ); + Trace("qcf-qregister-debug") << "...bind variables" << std::endl; + //now, make it a bound variable + for( unsigned i=0; i<c_to_vars[min_score_index].size(); i++ ){ + int v = c_to_vars[min_score_index][i]; + if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){ + for( unsigned j=0; j<vars_to_c[v].size(); j++ ){ + int vc = vars_to_c[v][j]; + vu_count[vc]--; + vb_count[vc]++; + } + bvars.push_back( v ); + } + } + Trace("qcf-qregister-debug") << "...done assign child " << min_score_index << std::endl; + }while( d_children_order.size()!=d_children.size() ); + Trace("qcf-qregister-debug") << "Done assign variable ordering for " << d_n << std::endl; + }else{ + for( unsigned i=0; i<d_children.size(); i++ ){ + d_children_order.push_back( i ); + d_children[i].determineVariableOrder( qi, bvars ); + } + } +} + + +void MatchGen::reset_round( QuantConflictFind * p ) { + d_wasSet = false; + for( unsigned i=0; i<d_children.size(); i++ ){ + d_children[i].reset_round( p ); + } + for( std::map< int, TNode >::iterator it = d_qni_gterm.begin(); it != d_qni_gterm.end(); ++it ){ + d_qni_gterm_rep[it->first] = p->getRepresentative( it->second ); + } + if( d_type==typ_ground ){ + int e = p->evaluate( d_n ); + if( e==1 ){ + d_ground_eval[0] = p->d_true; + }else if( e==-1 ){ + d_ground_eval[0] = p->d_false; + } + }else if( d_type==typ_eq ){ + for( unsigned i=0; i<d_n.getNumChildren(); i++ ){ + if( !d_n[i].hasBoundVar() ){ + d_ground_eval[i] = p->evaluateTerm( d_n[i] ); + } + } + } + d_qni_bound_cons.clear(); + d_qni_bound_cons_var.clear(); + d_qni_bound.clear(); +} + +void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) { + d_tgt = d_type_not ? !tgt : tgt; + Debug("qcf-match") << " Reset for : " << d_n << ", type : "; + debugPrintType( "qcf-match", d_type ); + Debug("qcf-match") << ", tgt = " << d_tgt << ", children = " << d_children.size() << " " << d_children_order.size() << std::endl; + d_qn.clear(); + d_qni.clear(); + d_qni_bound.clear(); + d_child_counter = -1; + d_tgt_orig = d_tgt; + + //set up processing matches + if( d_type==typ_invalid ){ + //do nothing + }else if( d_type==typ_ground ){ + if( d_ground_eval[0]==( d_tgt ? p->d_true : p->d_false ) ){ + d_child_counter = 0; + } + }else if( d_type==typ_bool_var ){ + //get current value of the variable + TNode n = qi->getCurrentValue( d_n ); + int vn = qi->getCurrentRepVar( qi->getVarNum( n ) ); + if( vn==-1 ){ + //evaluate the value, see if it is compatible + int e = p->evaluate( n ); + if( ( e==1 && d_tgt ) || ( e==0 && !d_tgt ) ){ + d_child_counter = 0; + } + }else{ + //unassigned, set match to true/false + d_qni_bound[0] = vn; + qi->setMatch( p, vn, d_tgt ? p->d_true : p->d_false ); + d_child_counter = 0; + } + if( d_child_counter==0 ){ + d_qn.push_back( NULL ); + } + }else if( d_type==typ_var ){ + Assert( isHandledUfTerm( d_n ) ); + Node f = getOperator( p, d_n ); + Debug("qcf-match-debug") << " reset: Var will match operators of " << f << std::endl; + QcfNodeIndex * qni = p->getQcfNodeIndex( Node::null(), f ); + if( qni!=NULL ){ + d_qn.push_back( qni ); + } + d_matched_basis = false; + }else if( d_type==typ_tsym || d_type==typ_tconstraint ){ + for( std::map< int, int >::iterator it = d_qni_var_num.begin(); it != d_qni_var_num.end(); ++it ){ + int repVar = qi->getCurrentRepVar( it->second ); + if( qi->d_match[repVar].isNull() ){ + Debug("qcf-match-debug") << "Force matching on child #" << it->first << ", which is var #" << repVar << std::endl; + d_qni_bound[it->first] = repVar; + } + } + d_qn.push_back( NULL ); + }else if( d_type==typ_pred || d_type==typ_eq ){ + //add initial constraint + Node nn[2]; + int vn[2]; + if( d_type==typ_pred ){ + nn[0] = qi->getCurrentValue( d_n ); + vn[0] = qi->getCurrentRepVar( qi->getVarNum( nn[0] ) ); + nn[1] = p->getRepresentative( d_tgt ? p->d_true : p->d_false ); + vn[1] = -1; + d_tgt = true; + }else{ + for( unsigned i=0; i<2; i++ ){ + TNode nc; + std::map< int, TNode >::iterator it = d_qni_gterm_rep.find( i ); + if( it!=d_qni_gterm_rep.end() ){ + nc = it->second; + }else{ + nc = d_n[i]; + } + nn[i] = qi->getCurrentValue( nc ); + vn[i] = qi->getCurrentRepVar( qi->getVarNum( nn[i] ) ); + } + } + bool success; + if( vn[0]==-1 && vn[1]==-1 ){ + //Trace("qcf-explain") << " reset : " << d_n << " check ground values " << nn[0] << " " << nn[1] << " (tgt=" << d_tgt << ")" << std::endl; + Debug("qcf-match-debug") << " reset: check ground values " << nn[0] << " " << nn[1] << " (" << d_tgt << ")" << std::endl; + //just compare values + if( d_tgt ){ + success = p->areMatchEqual( nn[0], nn[1] ); + }else{ + if( p->d_effort==QuantConflictFind::effort_conflict ){ + success = p->areDisequal( nn[0], nn[1] ); + }else{ + success = p->areMatchDisequal( nn[0], nn[1] ); + } + } + }else{ + //otherwise, add a constraint to a variable + if( vn[1]!=-1 && vn[0]==-1 ){ + //swap + Node t = nn[1]; + nn[1] = nn[0]; + nn[0] = t; + vn[0] = vn[1]; + vn[1] = -1; + } + Debug("qcf-match-debug") << " reset: add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << std::endl; + //add some constraint + int addc = qi->addConstraint( p, vn[0], nn[1], vn[1], d_tgt, false ); + success = addc!=-1; + //if successful and non-redundant, store that we need to cleanup this + if( addc==1 ){ + //Trace("qcf-explain") << " reset: " << d_n << " add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << ", d_tgt = " << d_tgt << std::endl; + for( unsigned i=0; i<2; i++ ){ + if( vn[i]!=-1 && std::find( d_qni_bound_except.begin(), d_qni_bound_except.end(), i )==d_qni_bound_except.end() ){ + d_qni_bound[vn[i]] = vn[i]; + } + } + d_qni_bound_cons[vn[0]] = nn[1]; + d_qni_bound_cons_var[vn[0]] = vn[1]; + } + } + //if successful, we will bind values to variables + if( success ){ + d_qn.push_back( NULL ); + } + }else{ + if( d_children.empty() ){ + //add dummy + d_qn.push_back( NULL ); + }else{ + if( d_tgt && d_n.getKind()==FORALL ){ + //do nothing + }else{ + //reset the first child to d_tgt + d_child_counter = 0; + getChild( d_child_counter )->reset( p, d_tgt, qi ); + } + } + } + d_binding = false; + d_wasSet = true; + Debug("qcf-match") << " reset: Finished reset for " << d_n << ", success = " << ( !d_qn.empty() || d_child_counter!=-1 ) << std::endl; +} + +bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) { + Debug("qcf-match") << " Get next match for : " << d_n << ", type = "; + debugPrintType( "qcf-match", d_type ); + Debug("qcf-match") << ", children = " << d_children.size() << ", binding = " << d_binding << std::endl; + if( d_type==typ_invalid || d_type==typ_ground ){ + if( d_child_counter==0 ){ + d_child_counter = -1; + return true; + }else{ + d_wasSet = false; + return false; + } + }else if( d_type==typ_var || d_type==typ_eq || d_type==typ_pred || d_type==typ_bool_var || d_type==typ_tconstraint || d_type==typ_tsym ){ + bool success = false; + bool terminate = false; + do { + bool doReset = false; + bool doFail = false; + if( !d_binding ){ + if( doMatching( p, qi ) ){ + Debug("qcf-match-debug") << " - Matching succeeded" << std::endl; + d_binding = true; + d_binding_it = d_qni_bound.begin(); + doReset = true; + //for tconstraint, add constraint + if( d_type==typ_tconstraint ){ + std::map< Node, bool >::iterator it = qi->d_tconstraints.find( d_n ); + if( it==qi->d_tconstraints.end() ){ + qi->d_tconstraints[d_n] = d_tgt; + //store that we added this constraint + d_qni_bound_cons[0] = d_n; + }else if( d_tgt!=it->second ){ + success = false; + terminate = true; + } + } + }else{ + Debug("qcf-match-debug") << " - Matching failed" << std::endl; + success = false; + terminate = true; + } + }else{ + doFail = true; + } + if( d_binding ){ + //also need to create match for each variable we bound + success = true; + Debug("qcf-match-debug") << " Produce matches for bound variables by " << d_n << ", type = "; + debugPrintType( "qcf-match-debug", d_type ); + Debug("qcf-match-debug") << "..." << std::endl; + + while( ( success && d_binding_it!=d_qni_bound.end() ) || doFail ){ + std::map< int, MatchGen * >::iterator itm; + if( !doFail ){ + Debug("qcf-match-debug") << " check variable " << d_binding_it->second << std::endl; + itm = qi->d_var_mg.find( d_binding_it->second ); + } + if( doFail || ( d_binding_it->first!=0 && itm!=qi->d_var_mg.end() ) ){ + Debug("qcf-match-debug") << " we had bound variable " << d_binding_it->second << ", reset = " << doReset << std::endl; + if( doReset ){ + itm->second->reset( p, true, qi ); + } + if( doFail || !itm->second->getNextMatch( p, qi ) ){ + do { + if( d_binding_it==d_qni_bound.begin() ){ + Debug("qcf-match-debug") << " failed." << std::endl; + success = false; + }else{ + --d_binding_it; + Debug("qcf-match-debug") << " decrement..." << std::endl; + } + }while( success && ( d_binding_it->first==0 || qi->d_var_mg.find( d_binding_it->second )==qi->d_var_mg.end() ) ); + doReset = false; + doFail = false; + }else{ + Debug("qcf-match-debug") << " increment..." << std::endl; + ++d_binding_it; + doReset = true; + } + }else{ + Debug("qcf-match-debug") << " skip..." << d_binding_it->second << std::endl; + ++d_binding_it; + doReset = true; + } + } + if( !success ){ + d_binding = false; + }else{ + terminate = true; + if( d_binding_it==d_qni_bound.begin() ){ + d_binding = false; + } + } + } + }while( !terminate ); + //if not successful, clean up the variables you bound + if( !success ){ + if( d_type==typ_eq || d_type==typ_pred ){ + //clean up the constraints you added + for( std::map< int, TNode >::iterator it = d_qni_bound_cons.begin(); it != d_qni_bound_cons.end(); ++it ){ + if( !it->second.isNull() ){ + Debug("qcf-match") << " Clean up bound var " << it->first << (d_tgt ? "!" : "") << " = " << it->second << std::endl; + std::map< int, int >::iterator itb = d_qni_bound_cons_var.find( it->first ); + int vn = itb!=d_qni_bound_cons_var.end() ? itb->second : -1; + //Trace("qcf-explain") << " cleanup: " << d_n << " remove constraint " << it->first << " -> " << it->second << " (vn=" << vn << ")" << ", d_tgt = " << d_tgt << std::endl; + qi->addConstraint( p, it->first, it->second, vn, d_tgt, true ); + } + } + d_qni_bound_cons.clear(); + d_qni_bound_cons_var.clear(); + d_qni_bound.clear(); + }else{ + //clean up the matches you set + for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){ + Debug("qcf-match") << " Clean up bound var " << it->second << std::endl; + Assert( it->second<qi->getNumVars() ); + qi->d_match[ it->second ] = TNode::null(); + qi->d_match_term[ it->second ] = TNode::null(); + } + d_qni_bound.clear(); + } + if( d_type==typ_tconstraint ){ + //remove constraint if applicable + if( d_qni_bound_cons.find( 0 )!=d_qni_bound_cons.end() ){ + qi->d_tconstraints.erase( d_n ); + d_qni_bound_cons.clear(); + } + } + /* + if( d_type==typ_var && p->d_effort==QuantConflictFind::effort_mc && !d_matched_basis ){ + d_matched_basis = true; + Node f = getOperator( d_n ); + TNode mbo = p->getQuantifiersEngine()->getTermDatabase()->getModelBasisOpTerm( f ); + if( qi->setMatch( p, d_qni_var_num[0], mbo ) ){ + success = true; + d_qni_bound[0] = d_qni_var_num[0]; + } + } + */ + } + Debug("qcf-match") << " ...finished matching for " << d_n << ", success = " << success << std::endl; + d_wasSet = success; + return success; + }else if( d_type==typ_formula || d_type==typ_ite_var ){ + bool success = false; + if( d_child_counter<0 ){ + if( d_child_counter<-1 ){ + success = true; + d_child_counter = -1; + } + }else{ + while( !success && d_child_counter>=0 ){ + //transition system based on d_child_counter + if( d_n.getKind()==OR || d_n.getKind()==AND ){ + if( (d_n.getKind()==AND)==d_tgt ){ + //all children must match simultaneously + if( getChild( d_child_counter )->getNextMatch( p, qi ) ){ + if( d_child_counter<(int)(getNumChildren()-1) ){ + d_child_counter++; + Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << std::endl; + getChild( d_child_counter )->reset( p, d_tgt, qi ); + }else{ + success = true; + } + }else{ + //if( std::find( d_independent.begin(), d_independent.end(), d_child_counter )!=d_independent.end() ){ + // d_child_counter--; + //}else{ + d_child_counter--; + //} + } + }else{ + //one child must match + if( !getChild( d_child_counter )->getNextMatch( p, qi ) ){ + if( d_child_counter<(int)(getNumChildren()-1) ){ + d_child_counter++; + Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << ", one match" << std::endl; + getChild( d_child_counter )->reset( p, d_tgt, qi ); + }else{ + d_child_counter = -1; + } + }else{ + success = true; + } + } + }else if( d_n.getKind()==IFF ){ + //construct match based on both children + if( d_child_counter%2==0 ){ + if( getChild( 0 )->getNextMatch( p, qi ) ){ + d_child_counter++; + getChild( 1 )->reset( p, d_child_counter==1, qi ); + }else{ + if( d_child_counter==0 ){ + d_child_counter = 2; + getChild( 0 )->reset( p, !d_tgt, qi ); + }else{ + d_child_counter = -1; + } + } + } + if( d_child_counter>=0 && d_child_counter%2==1 ){ + if( getChild( 1 )->getNextMatch( p, qi ) ){ + success = true; + }else{ + d_child_counter--; + } + } + }else if( d_n.getKind()==ITE ){ + if( d_child_counter%2==0 ){ + int index1 = d_child_counter==4 ? 1 : 0; + if( getChild( index1 )->getNextMatch( p, qi ) ){ + d_child_counter++; + getChild( d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2) )->reset( p, d_tgt, qi ); + }else{ + if( d_child_counter==4 || ( d_type==typ_ite_var && d_child_counter==2 ) ){ + d_child_counter = -1; + }else{ + d_child_counter +=2; + getChild( d_child_counter==2 ? 0 : 1 )->reset( p, d_child_counter==2 ? !d_tgt : d_tgt, qi ); + } + } + } + if( d_child_counter>=0 && d_child_counter%2==1 ){ + int index2 = d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2); + if( getChild( index2 )->getNextMatch( p, qi ) ){ + success = true; + }else{ + d_child_counter--; + } + } + }else if( d_n.getKind()==FORALL ){ + if( getChild( d_child_counter )->getNextMatch( p, qi ) ){ + success = true; + }else{ + d_child_counter = -1; + } + } + } + d_wasSet = success; + Debug("qcf-match") << " ...finished construct match for " << d_n << ", success = " << success << std::endl; + return success; + } + } + Debug("qcf-match") << " ...already finished for " << d_n << std::endl; + return false; +} + +bool MatchGen::getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp ) { + if( d_type==typ_eq ){ + Node n[2]; + for( unsigned i=0; i<2; i++ ){ + Trace("qcf-explain") << "Explain term " << d_n[i] << "..." << std::endl; + n[i] = getExplanationTerm( p, qi, d_n[i], exp ); + } + Node eq = n[0].eqNode( n[1] ); + if( !d_tgt_orig ){ + eq = eq.negate(); + } + exp.push_back( eq ); + Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << eq << ", set = " << d_wasSet << std::endl; + return true; + }else if( d_type==typ_pred ){ + Trace("qcf-explain") << "Explain term " << d_n << "..." << std::endl; + Node n = getExplanationTerm( p, qi, d_n, exp ); + if( !d_tgt_orig ){ + n = n.negate(); + } + exp.push_back( n ); + Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << n << ", set = " << d_wasSet << std::endl; + return true; + }else if( d_type==typ_formula ){ + Trace("qcf-explain") << "Explanation get for " << d_n << ", counter = " << d_child_counter << ", tgt = " << d_tgt_orig << ", set = " << d_wasSet << std::endl; + if( d_n.getKind()==OR || d_n.getKind()==AND ){ + if( (d_n.getKind()==AND)==d_tgt ){ + for( unsigned i=0; i<getNumChildren(); i++ ){ + if( !getChild( i )->getExplanation( p, qi, exp ) ){ + return false; + } + } + }else{ + return getChild( d_child_counter )->getExplanation( p, qi, exp ); + } + }else if( d_n.getKind()==IFF ){ + for( unsigned i=0; i<2; i++ ){ + if( !getChild( i )->getExplanation( p, qi, exp ) ){ + return false; + } + } + }else if( d_n.getKind()==ITE ){ + for( unsigned i=0; i<3; i++ ){ + bool isActive = ( ( i==0 && d_child_counter!=5 ) || + ( i==1 && d_child_counter!=( d_tgt ? 3 : 1 ) ) || + ( i==2 && d_child_counter!=( d_tgt ? 1 : 3 ) ) ); + if( isActive ){ + if( !getChild( i )->getExplanation( p, qi, exp ) ){ + return false; + } + } + } + }else{ + return false; + } + return true; + }else{ + return false; + } +} + +Node MatchGen::getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp ) { + Node v = qi->getCurrentExpValue( t ); + if( isHandledUfTerm( t ) ){ + for( unsigned i=0; i<t.getNumChildren(); i++ ){ + Node vi = getExplanationTerm( p, qi, t[i], exp ); + if( vi!=v[i] ){ + Node eq = vi.eqNode( v[i] ); + if( std::find( exp.begin(), exp.end(), eq )==exp.end() ){ + Trace("qcf-explain") << " add : " << eq << "." << std::endl; + exp.push_back( eq ); + } + } + } + } + return v; +} + +bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) { + if( !d_qn.empty() ){ + if( d_qn[0]==NULL ){ + d_qn.clear(); + return true; + }else{ + Assert( d_type==typ_var ); + Assert( d_qni_size>0 ); + bool invalidMatch; + do { + invalidMatch = false; + Debug("qcf-match-debug") << " Do matching " << d_n << " " << d_qn.size() << " " << d_qni.size() << std::endl; + if( d_qn.size()==d_qni.size()+1 ) { + int index = (int)d_qni.size(); + //initialize + TNode val; + std::map< int, int >::iterator itv = d_qni_var_num.find( index ); + if( itv!=d_qni_var_num.end() ){ + //get the representative variable this variable is equal to + int repVar = qi->getCurrentRepVar( itv->second ); + Debug("qcf-match-debug") << " Match " << index << " is a variable " << itv->second << ", which is repVar " << repVar << std::endl; + //get the value the rep variable + //std::map< int, TNode >::iterator itm = qi->d_match.find( repVar ); + if( !qi->d_match[repVar].isNull() ){ + val = qi->d_match[repVar]; + Debug("qcf-match-debug") << " Variable is already bound to " << val << std::endl; + }else{ + //binding a variable + d_qni_bound[index] = repVar; + std::map< TNode, QcfNodeIndex >::iterator it = d_qn[index]->d_children.begin(); + if( it != d_qn[index]->d_children.end() ) { + d_qni.push_back( it ); + //set the match + if( qi->setMatch( p, d_qni_bound[index], it->first ) ){ + Debug("qcf-match-debug") << " Binding variable" << std::endl; + if( d_qn.size()<d_qni_size ){ + d_qn.push_back( &it->second ); + } + }else{ + Debug("qcf-match") << " Binding variable, currently fail." << std::endl; + invalidMatch = true; + } + }else{ + Debug("qcf-match-debug") << " Binding variable, fail, no more variables to bind" << std::endl; + d_qn.pop_back(); + } + } + }else{ + Debug("qcf-match-debug") << " Match " << index << " is ground term" << std::endl; + Assert( d_qni_gterm.find( index )!=d_qni_gterm.end() ); + Assert( d_qni_gterm_rep.find( index )!=d_qni_gterm_rep.end() ); + val = d_qni_gterm_rep[index]; + Assert( !val.isNull() ); + } + if( !val.isNull() ){ + //constrained by val + std::map< TNode, QcfNodeIndex >::iterator it = d_qn[index]->d_children.find( val ); + if( it!=d_qn[index]->d_children.end() ){ + Debug("qcf-match-debug") << " Match" << std::endl; + d_qni.push_back( it ); + if( d_qn.size()<d_qni_size ){ + d_qn.push_back( &it->second ); + } + }else{ + Debug("qcf-match-debug") << " Failed to match" << std::endl; + d_qn.pop_back(); + } + } + }else{ + Assert( d_qn.size()==d_qni.size() ); + int index = d_qni.size()-1; + //increment if binding this variable + bool success = false; + std::map< int, int >::iterator itb = d_qni_bound.find( index ); + if( itb!=d_qni_bound.end() ){ + d_qni[index]++; + if( d_qni[index]!=d_qn[index]->d_children.end() ){ + success = true; + if( qi->setMatch( p, itb->second, d_qni[index]->first ) ){ + Debug("qcf-match-debug") << " Bind next variable" << std::endl; + if( d_qn.size()<d_qni_size ){ + d_qn.push_back( &d_qni[index]->second ); + } + }else{ + Debug("qcf-match-debug") << " Bind next variable, currently fail" << std::endl; + invalidMatch = true; + } + }else{ + qi->d_match[ itb->second ] = TNode::null(); + qi->d_match_term[ itb->second ] = TNode::null(); + Debug("qcf-match-debug") << " Bind next variable, no more variables to bind" << std::endl; + } + }else{ + //TODO : if it equal to something else, also try that + } + //if not incrementing, move to next + if( !success ){ + d_qn.pop_back(); + d_qni.pop_back(); + } + } + }while( ( !d_qn.empty() && d_qni.size()!=d_qni_size ) || invalidMatch ); + if( d_qni.size()==d_qni_size ){ + //Assert( !d_qni[d_qni.size()-1]->second.d_children.empty() ); + //Debug("qcf-match-debug") << " We matched " << d_qni[d_qni.size()-1]->second.d_children.begin()->first << std::endl; + Assert( !d_qni[d_qni.size()-1]->second.d_children.empty() ); + TNode t = d_qni[d_qni.size()-1]->second.d_children.begin()->first; + Debug("qcf-match-debug") << " " << d_n << " matched " << t << std::endl; + qi->d_match_term[d_qni_var_num[0]] = t; + //set the match terms + for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){ + Debug("qcf-match-debug") << " position " << it->first << " bounded " << it->second << " / " << qi->d_q[0].getNumChildren() << std::endl; + //if( it->second<(int)qi->d_q[0].getNumChildren() ){ //if it is an actual variable, we are interested in knowing the actual term + if( it->first>0 ){ + Assert( !qi->d_match[ it->second ].isNull() ); + Assert( p->areEqual( t[it->first-1], qi->d_match[ it->second ] ) ); + qi->d_match_term[it->second] = t[it->first-1]; + } + //} + } + } + } + } + return !d_qn.empty(); +} + +void MatchGen::debugPrintType( const char * c, short typ, bool isTrace ) { + if( isTrace ){ + switch( typ ){ + case typ_invalid: Trace(c) << "invalid";break; + case typ_ground: Trace(c) << "ground";break; + case typ_eq: Trace(c) << "eq";break; + case typ_pred: Trace(c) << "pred";break; + case typ_formula: Trace(c) << "formula";break; + case typ_var: Trace(c) << "var";break; + case typ_ite_var: Trace(c) << "ite_var";break; + case typ_bool_var: Trace(c) << "bool_var";break; + } + }else{ + switch( typ ){ + case typ_invalid: Debug(c) << "invalid";break; + case typ_ground: Debug(c) << "ground";break; + case typ_eq: Debug(c) << "eq";break; + case typ_pred: Debug(c) << "pred";break; + case typ_formula: Debug(c) << "formula";break; + case typ_var: Debug(c) << "var";break; + case typ_ite_var: Debug(c) << "ite_var";break; + case typ_bool_var: Debug(c) << "bool_var";break; + } + } +} + +void MatchGen::setInvalid() { + d_type = typ_invalid; + d_children.clear(); +} + +bool MatchGen::isHandledBoolConnective( TNode n ) { + return n.getType().isBoolean() && ( n.getKind()==OR || n.getKind()==AND || n.getKind()==IFF || n.getKind()==ITE || n.getKind()==FORALL || n.getKind()==NOT ); +} + +bool MatchGen::isHandledUfTerm( TNode n ) { + //return n.getKind()==APPLY_UF || n.getKind()==STORE || n.getKind()==SELECT || + // n.getKind()==APPLY_CONSTRUCTOR || n.getKind()==APPLY_SELECTOR_TOTAL || n.getKind()==APPLY_TESTER; + return inst::Trigger::isAtomicTriggerKind( n.getKind() ); +} + +Node MatchGen::getOperator( QuantConflictFind * p, Node n ) { + if( isHandledUfTerm( n ) ){ + return p->getQuantifiersEngine()->getTermDatabase()->getOperator( n ); + }else{ + return Node::null(); + } +} + +bool MatchGen::isHandled( TNode n ) { + if( n.getKind()!=BOUND_VARIABLE && n.hasBoundVar() ){ + if( !isHandledBoolConnective( n ) && !isHandledUfTerm( n ) && n.getKind()!=EQUAL && n.getKind()!=ITE ){ + return false; + } + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + if( !isHandled( n[i] ) ){ + return false; + } + } + } + return true; +} + + +QuantConflictFind::QuantConflictFind( QuantifiersEngine * qe, context::Context* c ) : +QuantifiersModule( qe ), +d_c( c ), +d_conflict( c, false ), +d_qassert( c ) { + d_fid_count = 0; + d_true = NodeManager::currentNM()->mkConst<bool>(true); + d_false = NodeManager::currentNM()->mkConst<bool>(false); +} + +Node QuantConflictFind::mkEqNode( Node a, Node b ) { + if( a.getType().isBoolean() ){ + return a.iffNode( b ); + }else{ + return a.eqNode( b ); + } +} + +//-------------------------------------------------- registration + +void QuantConflictFind::registerQuantifier( Node q ) { + if( !TermDb::isRewriteRule( q ) ){ + d_quants.push_back( q ); + d_quant_id[q] = d_quants.size(); + Trace("qcf-qregister") << "Register "; + debugPrintQuant( "qcf-qregister", q ); + Trace("qcf-qregister") << " : " << q << std::endl; + //make QcfNode structure + Trace("qcf-qregister") << "- Get relevant equality/disequality pairs, calculate flattening..." << std::endl; + d_qinfo[q].initialize( q, q[1] ); + + //debug print + Trace("qcf-qregister") << "- Flattened structure is :" << std::endl; + Trace("qcf-qregister") << " "; + debugPrintQuantBody( "qcf-qregister", q, q[1] ); + Trace("qcf-qregister") << std::endl; + if( d_qinfo[q].d_vars.size()>q[0].getNumChildren() ){ + Trace("qcf-qregister") << " with additional constraints : " << std::endl; + for( unsigned j=q[0].getNumChildren(); j<d_qinfo[q].d_vars.size(); j++ ){ + Trace("qcf-qregister") << " ?x" << j << " = "; + debugPrintQuantBody( "qcf-qregister", q, d_qinfo[q].d_vars[j], false ); + Trace("qcf-qregister") << std::endl; + } + } + + Trace("qcf-qregister") << "Done registering quantifier." << std::endl; + } +} + +int QuantConflictFind::evaluate( Node n, bool pref, bool hasPref ) { + int ret = 0; + if( n.getKind()==EQUAL ){ + Node n1 = evaluateTerm( n[0] ); + Node n2 = evaluateTerm( n[1] ); + Debug("qcf-eval") << "Evaluate : Normalize " << n << " to " << n1 << " = " << n2 << std::endl; + if( areEqual( n1, n2 ) ){ + ret = 1; + }else if( areDisequal( n1, n2 ) ){ + ret = -1; + } + //else if( d_effort>QuantConflictFind::effort_conflict ){ + // ret = -1; + //} + }else if( MatchGen::isHandledUfTerm( n ) ){ //predicate + Node nn = evaluateTerm( n ); + Debug("qcf-eval") << "Evaluate : Normalize " << nn << " to " << n << std::endl; + if( areEqual( nn, d_true ) ){ + ret = 1; + }else if( areEqual( nn, d_false ) ){ + ret = -1; + } + //else if( d_effort>QuantConflictFind::effort_conflict ){ + // ret = -1; + //} + }else if( n.getKind()==NOT ){ + return -evaluate( n[0] ); + }else if( n.getKind()==ITE ){ + int cev1 = evaluate( n[0] ); + int cevc[2] = { 0, 0 }; + for( unsigned i=0; i<2; i++ ){ + if( ( i==0 && cev1!=-1 ) || ( i==1 && cev1!=1 ) ){ + cevc[i] = evaluate( n[i+1] ); + if( cev1!=0 ){ + ret = cevc[i]; + break; + }else if( cevc[i]==0 ){ + break; + } + } + } + if( ret==0 && cevc[0]!=0 && cevc[0]==cevc[1] ){ + ret = cevc[0]; + } + }else if( n.getKind()==IFF ){ + int cev1 = evaluate( n[0] ); + if( cev1!=0 ){ + int cev2 = evaluate( n[1] ); + if( cev2!=0 ){ + ret = cev1==cev2 ? 1 : -1; + } + } + + }else{ + int ssval = 0; + if( n.getKind()==OR ){ + ssval = 1; + }else if( n.getKind()==AND ){ + ssval = -1; + } + bool isUnk = false; + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + int cev = evaluate( n[i] ); + if( cev==ssval ){ + ret = ssval; + break; + }else if( cev==0 ){ + isUnk = true; + } + } + if( ret==0 && !isUnk ){ + ret = -ssval; + } + } + Debug("qcf-eval") << "Evaluate " << n << " to " << ret << std::endl; + return ret; +} + +short QuantConflictFind::getMaxQcfEffort() { + if( options::qcfMode()==QCF_CONFLICT_ONLY ){ + return effort_conflict; + }else if( options::qcfMode()==QCF_PROP_EQ ){ + return effort_prop_eq; + }else if( options::qcfMode()==QCF_MC ){ + return effort_mc; + }else{ + return 0; + } +} + +bool QuantConflictFind::areMatchEqual( TNode n1, TNode n2 ) { + //if( d_effort==QuantConflictFind::effort_mc ){ + // return n1==n2 || !areDisequal( n1, n2 ); + //}else{ + return n1==n2; + //} +} + +bool QuantConflictFind::areMatchDisequal( TNode n1, TNode n2 ) { + //if( d_effort==QuantConflictFind::effort_conflict ){ + // return areDisequal( n1, n2 ); + //}else{ + return n1!=n2; + //} +} + +//-------------------------------------------------- handling assertions / eqc + +void QuantConflictFind::assertNode( Node q ) { + if( !TermDb::isRewriteRule( q ) ){ + Trace("qcf-proc") << "QCF : assertQuantifier : "; + debugPrintQuant("qcf-proc", q); + Trace("qcf-proc") << std::endl; + d_qassert.push_back( q ); + //set the eqRegistries that this depends on to true + //for( std::map< EqRegistry *, bool >::iterator it = d_qinfo[q].d_rel_eqr.begin(); it != d_qinfo[q].d_rel_eqr.end(); ++it ){ + // it->first->d_active.set( true ); + //} + } +} + +eq::EqualityEngine * QuantConflictFind::getEqualityEngine() { + //return ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( theory::THEORY_UF ))->getEqualityEngine(); + return d_quantEngine->getTheoryEngine()->getMasterEqualityEngine(); +} +bool QuantConflictFind::areEqual( Node n1, Node n2 ) { + return getEqualityEngine()->hasTerm( n1 ) && getEqualityEngine()->hasTerm( n2 ) && getEqualityEngine()->areEqual( n1,n2 ); +} +bool QuantConflictFind::areDisequal( Node n1, Node n2 ) { + return n1!=n2 && getEqualityEngine()->hasTerm( n1 ) && getEqualityEngine()->hasTerm( n2 ) && getEqualityEngine()->areDisequal( n1,n2, false ); +} +Node QuantConflictFind::getRepresentative( Node n ) { + if( getEqualityEngine()->hasTerm( n ) ){ + return getEqualityEngine()->getRepresentative( n ); + }else{ + return n; + } +} +Node QuantConflictFind::evaluateTerm( Node n ) { + if( MatchGen::isHandledUfTerm( n ) ){ + Node f = MatchGen::getOperator( this, n ); + Node nn; + computeUfTerms( f ); + if( getEqualityEngine()->hasTerm( n ) ){ + computeArgReps( n ); + nn = d_uf_terms[f].existsTerm( n, d_arg_reps[n] ); + }else{ + std::vector< TNode > args; + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + Node c = evaluateTerm( n[i] ); + args.push_back( c ); + } + nn = d_uf_terms[f].existsTerm( n, args ); + } + if( !nn.isNull() ){ + Debug("qcf-eval") << "GT: Term " << nn << " for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl; + return getRepresentative( nn ); + }else{ + Debug("qcf-eval") << "GT: No term for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl; + return n; + } + }else if( n.getKind()==ITE ){ + int v = evaluate( n[0], false, false ); + if( v==1 ){ + return evaluateTerm( n[1] ); + }else if( v==-1 ){ + return evaluateTerm( n[2] ); + } + } + return getRepresentative( n ); +} + +/* +QuantConflictFind::EqcInfo * QuantConflictFind::getEqcInfo( Node n, bool doCreate ) { + std::map< Node, EqcInfo * >::iterator it2 = d_eqc_info.find( n ); + if( it2==d_eqc_info.end() ){ + if( doCreate ){ + EqcInfo * eqci = new EqcInfo( d_c ); + d_eqc_info[n] = eqci; + return eqci; + }else{ + return NULL; + } + } + return it2->second; +} +*/ + +QcfNodeIndex * QuantConflictFind::getQcfNodeIndex( Node eqc, Node f ) { + computeUfTerms( f ); + std::map< TNode, QcfNodeIndex >::iterator itut = d_eqc_uf_terms.find( f ); + if( itut==d_eqc_uf_terms.end() ){ + return NULL; + }else{ + if( eqc.isNull() ){ + return &itut->second; + }else{ + std::map< TNode, QcfNodeIndex >::iterator itute = itut->second.d_children.find( eqc ); + if( itute!=itut->second.d_children.end() ){ + return &itute->second; + }else{ + return NULL; + } + } + } +} + +QcfNodeIndex * QuantConflictFind::getQcfNodeIndex( Node f ) { + computeUfTerms( f ); + std::map< TNode, QcfNodeIndex >::iterator itut = d_uf_terms.find( f ); + if( itut!=d_uf_terms.end() ){ + return &itut->second; + }else{ + return NULL; + } +} + +/** new node */ +void QuantConflictFind::newEqClass( Node n ) { + //Trace("qcf-proc-debug") << "QCF : newEqClass : " << n << std::endl; + //Trace("qcf-proc2-debug") << "QCF : finished newEqClass : " << n << std::endl; +} + +/** merge */ +void QuantConflictFind::merge( Node a, Node b ) { + /* + if( b.getKind()==EQUAL ){ + if( a==d_true ){ + //will merge anyways + //merge( b[0], b[1] ); + }else if( a==d_false ){ + assertDisequal( b[0], b[1] ); + } + }else{ + Trace("qcf-proc") << "QCF : merge : " << a << " " << b << std::endl; + EqcInfo * eqc_b = getEqcInfo( b, false ); + EqcInfo * eqc_a = NULL; + if( eqc_b ){ + eqc_a = getEqcInfo( a ); + //move disequalities of b into a + for( NodeBoolMap::iterator it = eqc_b->d_diseq.begin(); it != eqc_b->d_diseq.end(); ++it ){ + if( (*it).second ){ + Node n = (*it).first; + EqcInfo * eqc_n = getEqcInfo( n, false ); + Assert( eqc_n ); + if( !eqc_n->isDisequal( a ) ){ + Assert( !eqc_a->isDisequal( n ) ); + eqc_n->setDisequal( a ); + eqc_a->setDisequal( n ); + //setEqual( eqc_a, eqc_b, a, n, false ); + } + eqc_n->setDisequal( b, false ); + } + } + ////move all previous EqcRegistry's regarding equalities within b + //for( NodeBoolMap::iterator it = eqc_b->d_rel_eqr_e.begin(); it != eqc_b->d_rel_eqr_e.end(); ++it ){ + // if( (*it).second ){ + // eqc_a->d_rel_eqr_e[(*it).first] = true; + // } + //} + } + //process new equalities + //setEqual( eqc_a, eqc_b, a, b, true ); + Trace("qcf-proc2") << "QCF : finished merge : " << a << " " << b << std::endl; + } + */ +} + +/** assert disequal */ +void QuantConflictFind::assertDisequal( Node a, Node b ) { + /* + a = getRepresentative( a ); + b = getRepresentative( b ); + Trace("qcf-proc") << "QCF : assert disequal : " << a << " " << b << std::endl; + EqcInfo * eqc_a = getEqcInfo( a ); + EqcInfo * eqc_b = getEqcInfo( b ); + if( !eqc_a->isDisequal( b ) ){ + Assert( !eqc_b->isDisequal( a ) ); + eqc_b->setDisequal( a ); + eqc_a->setDisequal( b ); + //setEqual( eqc_a, eqc_b, a, b, false ); + } + Trace("qcf-proc2") << "QCF : finished assert disequal : " << a << " " << b << std::endl; + */ +} + +//-------------------------------------------------- check function + +void QuantConflictFind::reset_round( Theory::Effort level ) { + d_needs_computeRelEqr = true; +} + +/** check */ +void QuantConflictFind::check( Theory::Effort level ) { + Trace("qcf-check") << "QCF : check : " << level << std::endl; + if( d_conflict ){ + Trace("qcf-check2") << "QCF : finished check : already in conflict." << std::endl; + if( level>=Theory::EFFORT_FULL ){ + Trace("qcf-warn") << "ALREADY IN CONFLICT? " << level << std::endl; + //Assert( false ); + } + }else{ + int addedLemmas = 0; + if( d_performCheck ){ + ++(d_statistics.d_inst_rounds); + double clSet = 0; + int prevEt = 0; + if( Trace.isOn("qcf-engine") ){ + prevEt = d_statistics.d_entailment_checks.getData(); + clSet = double(clock())/double(CLOCKS_PER_SEC); + Trace("qcf-engine") << "---Conflict Find Engine Round, effort = " << level << "---" << std::endl; + } + computeRelevantEqr(); + + //determine order for quantified formulas + std::vector< Node > qorder; + std::map< Node, bool > qassert; + //mark which are asserted + for( unsigned i=0; i<d_qassert.size(); i++ ){ + qassert[d_qassert[i]] = true; + } + //add which ones are specified in the order + for( unsigned i=0; i<d_quant_order.size(); i++ ){ + Node n = d_quant_order[i]; + if( std::find( qorder.begin(), qorder.end(), n )==qorder.end() && qassert.find( n )!=qassert.end() ){ + qorder.push_back( n ); + } + } + d_quant_order.clear(); + d_quant_order.insert( d_quant_order.begin(), qorder.begin(), qorder.end() ); + //add remaining + for( unsigned i=0; i<d_qassert.size(); i++ ){ + Node n = d_qassert[i]; + if( std::find( qorder.begin(), qorder.end(), n )==qorder.end() ){ + qorder.push_back( n ); + } + } + + if( Trace.isOn("qcf-debug") ){ + Trace("qcf-debug") << std::endl; + debugPrint("qcf-debug"); + Trace("qcf-debug") << std::endl; + } + short end_e = getMaxQcfEffort(); + for( short e = effort_conflict; e<=end_e; e++ ){ + d_effort = e; + Trace("qcf-check") << "Checking quantified formulas at effort " << e << "..." << std::endl; + for( unsigned j=0; j<qorder.size(); j++ ){ + Node q = qorder[j]; + QuantInfo * qi = &d_qinfo[q]; + + Assert( d_qinfo.find( q )!=d_qinfo.end() ); + if( qi->d_mg->isValid() ){ + Trace("qcf-check") << "Check quantified formula "; + debugPrintQuant("qcf-check", q); + Trace("qcf-check") << " : " << q << "..." << std::endl; + + Trace("qcf-check-debug") << "Reset round..." << std::endl; + qi->reset_round( this ); + //try to make a matches making the body false + Trace("qcf-check-debug") << "Get next match..." << std::endl; + while( qi->d_mg->getNextMatch( this, qi ) ){ + Trace("qcf-check") << "*** Produced match at effort " << e << " : " << std::endl; + qi->debugPrintMatch("qcf-check"); + Trace("qcf-check") << std::endl; + std::vector< int > assigned; + if( !qi->isMatchSpurious( this ) ){ + if( qi->completeMatch( this, assigned ) ){ + /* + if( options::qcfExp() && d_effort==effort_conflict ){ + std::vector< Node > exp; + if( qi->d_mg->getExplanation( this, qi, exp ) ){ + Trace("qcf-check-exp") << "Base explanation is : " << std::endl; + for( unsigned c=0; c<exp.size(); c++ ){ + Trace("qcf-check-exp") << " " << exp[c] << std::endl; + } + std::vector< TNode > c_exp; + eq::EqualityEngine* ee = ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getEqualityEngine() ; + for( unsigned c=0; c<exp.size(); c++ ){ + bool pol = exp[c].getKind()!=NOT; + TNode lit = pol ? exp[c] : exp[c][0]; + Trace("qcf-check-exp") << "Explain " << lit << ", polarity " << pol << std::endl; + if( lit.getKind()==EQUAL ){ + if( !pol && !ee->areDisequal( lit[0], lit[1], true ) ){ + exit( 98 ); + }else if( pol && !ee->areEqual( lit[0], lit[1] ) ){ + exit( 99 ); + } + ee->explainEquality( lit[0], lit[1], pol, c_exp ); + }else{ + if( !ee->areEqual( lit, pol ? d_true : d_false ) ){ + exit( pol ? 96 : 97 ); + } + ee->explainPredicate( lit, pol, c_exp ); + } + } + std::vector< Node > c_lem; + Trace("qcf-check-exp") << "Actual explanation is : " << std::endl; + for( unsigned c=0; c<c_exp.size(); c++ ){ + Trace("qcf-check-exp") << " " << c_exp[c] << std::endl; + Node ccc = c_exp[c].negate(); + if( std::find( c_lem.begin(), c_lem.end(), ccc )==c_lem.end() ){ + c_lem.push_back( ccc ); + } + } + + c_lem.push_back( q.negate() ); + Node conf = NodeManager::currentNM()->mkNode( OR, c_lem ); + Trace("qcf-conflict") << "QCF conflict : " << conf << std::endl; + d_quantEngine->addLemma( conf, false ); + d_conflict.set( true ); + ++(d_statistics.d_conflict_inst); + ++addedLemmas; + break; + } + } + */ + std::vector< Node > terms; + qi->getMatch( terms ); + if( !qi->isTConstraintSpurious( this, terms ) ){ + if( Debug.isOn("qcf-check-inst") ){ + //if( e==effort_conflict ){ + Node inst = d_quantEngine->getInstantiation( q, terms ); + Debug("qcf-check-inst") << "Check instantiation " << inst << "..." << std::endl; + Assert( evaluate( inst )!=1 ); + Assert( evaluate( inst )==-1 || e>effort_conflict ); + //} + } + if( d_quantEngine->addInstantiation( q, terms, false ) ){ + Trace("qcf-check") << " ... Added instantiation" << std::endl; + Trace("qcf-inst") << "*** Was from effort " << e << " : " << std::endl; + qi->debugPrintMatch("qcf-inst"); + Trace("qcf-inst") << std::endl; + ++addedLemmas; + if( e==effort_conflict ){ + d_quant_order.insert( d_quant_order.begin(), q ); + d_conflict.set( true ); + ++(d_statistics.d_conflict_inst); + break; + }else if( e==effort_prop_eq ){ + ++(d_statistics.d_prop_inst); + } + }else{ + Trace("qcf-check") << " ... Failed to add instantiation" << std::endl; + //Assert( false ); + } + } + //clean up assigned + qi->revertMatch( assigned ); + d_tempCache.clear(); + }else{ + Trace("qcf-check") << " ... Spurious instantiation (cannot assign unassigned variables)" << std::endl; + } + }else{ + Trace("qcf-check") << " ... Spurious instantiation (match is inconsistent)" << std::endl; + } + } + if( d_conflict ){ + break; + } + } + } + if( addedLemmas>0 ){ + d_quantEngine->flushLemmas(); + break; + } + } + if( Trace.isOn("qcf-engine") ){ + double clSet2 = double(clock())/double(CLOCKS_PER_SEC); + Trace("qcf-engine") << "Finished conflict find engine, time = " << (clSet2-clSet); + if( addedLemmas>0 ){ + Trace("qcf-engine") << ", effort = " << ( d_effort==effort_conflict ? "conflict" : ( d_effort==effort_prop_eq ? "prop_eq" : "mc" ) ); + Trace("qcf-engine") << ", addedLemmas = " << addedLemmas; + } + Trace("qcf-engine") << std::endl; + int currEt = d_statistics.d_entailment_checks.getData(); + if( currEt!=prevEt ){ + Trace("qcf-engine") << " Entailment checks = " << ( currEt - prevEt ) << std::endl; + } + } + } + Trace("qcf-check2") << "QCF : finished check : " << level << std::endl; + } +} + +bool QuantConflictFind::needsCheck( Theory::Effort level ) { + d_performCheck = false; + if( options::quantConflictFind() && !d_conflict ){ + if( level==Theory::EFFORT_LAST_CALL ){ + d_performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_LAST_CALL; + }else if( level==Theory::EFFORT_FULL ){ + d_performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_DEFAULT; + }else if( level==Theory::EFFORT_STANDARD ){ + d_performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_STD; + } + } + return d_performCheck; +} + +void QuantConflictFind::computeRelevantEqr() { + if( d_needs_computeRelEqr ){ + d_needs_computeRelEqr = false; + Trace("qcf-check") << "Compute relevant equalities..." << std::endl; + d_uf_terms.clear(); + d_eqc_uf_terms.clear(); + d_eqcs.clear(); + d_model_basis.clear(); + d_arg_reps.clear(); + //double clSet = 0; + //if( Trace.isOn("qcf-opt") ){ + // clSet = double(clock())/double(CLOCKS_PER_SEC); + //} + + //long nTermst = 0; + //long nTerms = 0; + //long nEqc = 0; + + //which nodes are irrelevant for disequality matches + std::map< TNode, bool > irrelevant_dnode; + //now, store matches + eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() ); + while( !eqcs_i.isFinished() ){ + //nEqc++; + Node r = (*eqcs_i); + TypeNode rtn = r.getType(); + if( options::qcfMode()==QCF_MC ){ + std::map< TypeNode, std::vector< TNode > >::iterator itt = d_eqcs.find( rtn ); + if( itt==d_eqcs.end() ){ + Node mb = getQuantifiersEngine()->getTermDatabase()->getModelBasisTerm( rtn ); + if( !getEqualityEngine()->hasTerm( mb ) ){ + Trace("qcf-warn") << "WARNING: Model basis term does not exist!" << std::endl; + Assert( false ); + } + Node mbr = getRepresentative( mb ); + if( mbr!=r ){ + d_eqcs[rtn].push_back( mbr ); + } + d_eqcs[rtn].push_back( r ); + d_model_basis[rtn] = mb; + }else{ + itt->second.push_back( r ); + } + }else{ + d_eqcs[rtn].push_back( r ); + } + /* + eq::EqClassIterator eqc_i = eq::EqClassIterator( r, getEqualityEngine() ); + while( !eqc_i.isFinished() ){ + TNode n = (*eqc_i); + if( n.hasBoundVar() ){ + std::cout << "BAD TERM IN DB : " << n << std::endl; + exit( 199 ); + } + ++eqc_i; + } + + */ + + //if( r.getType().isInteger() ){ + // Trace("qcf-mv") << "Model value for eqc(" << r << ") : " << d_quantEngine->getValuation().getModelValue( r ) << std::endl; + //} + //EqcInfo * eqcir = getEqcInfo( r, false ); + //get relevant nodes that we are disequal from + /* + std::vector< Node > deqc; + if( eqcir ){ + for( NodeBoolMap::iterator it = eqcir->d_diseq.begin(); it != eqcir->d_diseq.end(); ++it ){ + if( (*it).second ){ + //Node rd = (*it).first; + //if( rd!=getRepresentative( rd ) ){ + // std::cout << "Bad rep!" << std::endl; + // exit( 0 ); + //} + deqc.push_back( (*it).first ); + } + } + } + */ + //process disequalities + /* + eq::EqClassIterator eqc_i = eq::EqClassIterator( r, getEqualityEngine() ); + while( !eqc_i.isFinished() ){ + TNode n = (*eqc_i); + if( n.getKind()!=EQUAL ){ + nTermst++; + //node_to_rep[n] = r; + //if( n.getNumChildren()>0 ){ + // if( n.getKind()!=APPLY_UF ){ + // std::cout << n.getKind() << " " << n.getOperator() << " " << n << std::endl; + // } + //} + if( !quantifiers::TermDb::hasBoundVarAttr( n ) ){ //temporary + + bool isRedundant; + std::map< TNode, std::vector< TNode > >::iterator it_na; + TNode fn; + if( MatchGen::isHandledUfTerm( n ) ){ + Node f = MatchGen::getOperator( this, n ); + computeArgReps( n ); + it_na = d_arg_reps.find( n ); + Assert( it_na!=d_arg_reps.end() ); + Node nadd = d_eqc_uf_terms[f].d_children[r].addTerm( n, d_arg_reps[n] ); + isRedundant = (nadd!=n); + d_uf_terms[f].addTerm( n, d_arg_reps[n] ); + }else{ + isRedundant = false; + } + nTerms += isRedundant ? 0 : 1; + }else{ + if( Debug.isOn("qcf-nground") ){ + Debug("qcf-nground") << "Non-ground term in eqc : " << n << std::endl; + Assert( false ); + } + } + } + ++eqc_i; + } + */ + ++eqcs_i; + } + /* + if( Trace.isOn("qcf-opt") ){ + double clSet2 = double(clock())/double(CLOCKS_PER_SEC); + Trace("qcf-opt") << "Compute rel eqc : " << std::endl; + Trace("qcf-opt") << " " << nEqc << " equivalence classes. " << std::endl; + Trace("qcf-opt") << " " << nTerms << " / " << nTermst << " terms." << std::endl; + Trace("qcf-opt") << " Time : " << (clSet2-clSet) << std::endl; + } + */ + } +} + +void QuantConflictFind::computeArgReps( TNode n ) { + if( d_arg_reps.find( n )==d_arg_reps.end() ){ + Assert( MatchGen::isHandledUfTerm( n ) ); + for( unsigned j=0; j<n.getNumChildren(); j++ ){ + d_arg_reps[n].push_back( getRepresentative( n[j] ) ); + } + } +} + +void QuantConflictFind::computeUfTerms( TNode f ) { + if( d_uf_terms.find( f )==d_uf_terms.end() ){ + d_uf_terms[f].clear(); + unsigned nt = d_quantEngine->getTermDatabase()->getNumGroundTerms( f ); + for( unsigned i=0; i<nt; i++ ){ + Node n = d_quantEngine->getTermDatabase()->d_op_map[f][i]; + if( getEqualityEngine()->hasTerm( n ) && !n.getAttribute(NoMatchAttribute()) ){ + Node r = getRepresentative( n ); + computeArgReps( n ); + d_eqc_uf_terms[f].d_children[r].addTerm( n, d_arg_reps[n] ); + d_uf_terms[f].addTerm( n, d_arg_reps[n] ); + } + } + } +} + +//-------------------------------------------------- debugging + + +void QuantConflictFind::debugPrint( const char * c ) { + //print the equivalance classes + Trace(c) << "----------EQ classes" << std::endl; + eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() ); + while( !eqcs_i.isFinished() ){ + Node n = (*eqcs_i); + //if( !n.getType().isInteger() ){ + Trace(c) << " - " << n << " : {"; + eq::EqClassIterator eqc_i = eq::EqClassIterator( n, getEqualityEngine() ); + bool pr = false; + while( !eqc_i.isFinished() ){ + Node nn = (*eqc_i); + if( nn.getKind()!=EQUAL && nn!=n ){ + Trace(c) << (pr ? "," : "" ) << " " << nn; + pr = true; + } + ++eqc_i; + } + Trace(c) << (pr ? " " : "" ) << "}" << std::endl; + /* + EqcInfo * eqcn = getEqcInfo( n, false ); + if( eqcn ){ + Trace(c) << " DEQ : {"; + pr = false; + for( NodeBoolMap::iterator it = eqcn->d_diseq.begin(); it != eqcn->d_diseq.end(); ++it ){ + if( (*it).second ){ + Trace(c) << (pr ? "," : "" ) << " " << (*it).first; + pr = true; + } + } + Trace(c) << (pr ? " " : "" ) << "}" << std::endl; + } + //} + */ + ++eqcs_i; + } +} + +void QuantConflictFind::debugPrintQuant( const char * c, Node q ) { + Trace(c) << "Q" << d_quant_id[q]; +} + +void QuantConflictFind::debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum ) { + if( n.getNumChildren()==0 ){ + Trace(c) << n; + }else if( doVarNum && d_qinfo[q].d_var_num.find( n )!=d_qinfo[q].d_var_num.end() ){ + Trace(c) << "?x" << d_qinfo[q].d_var_num[n]; + }else{ + Trace(c) << "("; + if( n.getKind()==APPLY_UF ){ + Trace(c) << n.getOperator(); + }else{ + Trace(c) << n.getKind(); + } + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + Trace(c) << " "; + debugPrintQuantBody( c, q, n[i] ); + } + Trace(c) << ")"; + } +} + +QuantConflictFind::Statistics::Statistics(): + d_inst_rounds("QuantConflictFind::Inst_Rounds", 0), + d_conflict_inst("QuantConflictFind::Instantiations_Conflict_Find", 0 ), + d_prop_inst("QuantConflictFind::Instantiations_Prop", 0 ), + d_entailment_checks("QuantConflictFind::Entailment_Checks",0) +{ + StatisticsRegistry::registerStat(&d_inst_rounds); + StatisticsRegistry::registerStat(&d_conflict_inst); + StatisticsRegistry::registerStat(&d_prop_inst); + StatisticsRegistry::registerStat(&d_entailment_checks); +} + +QuantConflictFind::Statistics::~Statistics(){ + StatisticsRegistry::unregisterStat(&d_inst_rounds); + StatisticsRegistry::unregisterStat(&d_conflict_inst); + StatisticsRegistry::unregisterStat(&d_prop_inst); + StatisticsRegistry::unregisterStat(&d_entailment_checks); +} + +TNode QuantConflictFind::getZero( Kind k ) { + std::map< Kind, Node >::iterator it = d_zero.find( k ); + if( it==d_zero.end() ){ + Node nn; + if( k==PLUS ){ + nn = NodeManager::currentNM()->mkConst( Rational(0) ); + } + d_zero[k] = nn; + return nn; + }else{ + return it->second; + } +} + + +} diff --git a/src/theory/quantifiers/quant_conflict_find.h b/src/theory/quantifiers/quant_conflict_find.h index 64ece7ed0..6ea7849c4 100755 --- a/src/theory/quantifiers/quant_conflict_find.h +++ b/src/theory/quantifiers/quant_conflict_find.h @@ -1,297 +1,297 @@ -/********************* */
-/*! \file quant_conflict_find.h
- ** \verbatim
- ** Original author: Andrew Reynolds
- ** Major contributors: none
- ** 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 quantifiers conflict find class
- **/
-
-#include "cvc4_private.h"
-
-#ifndef QUANT_CONFLICT_FIND
-#define QUANT_CONFLICT_FIND
-
-#include "context/cdhashmap.h"
-#include "context/cdchunk_list.h"
-#include "theory/quantifiers_engine.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-class QcfNode;
-
-class QuantConflictFind;
-
-class QcfNodeIndex {
-public:
- std::map< TNode, QcfNodeIndex > d_children;
- void clear() { d_children.clear(); }
- void debugPrint( const char * c, int t );
- Node existsTerm( TNode n, std::vector< TNode >& reps, int index = 0 );
- Node addTerm( TNode n, std::vector< TNode >& reps, int index = 0 );
-};
-
-class QuantInfo;
-
-//match generator
-class MatchGen {
- friend class QuantInfo;
-private:
- //current children information
- int d_child_counter;
- //children of this object
- std::vector< int > d_children_order;
- unsigned getNumChildren() { return d_children.size(); }
- MatchGen * getChild( int i ) { return &d_children[d_children_order[i]]; }
- //MatchGen * getChild( int i ) { return &d_children[i]; }
- //current matching information
- std::vector< QcfNodeIndex * > d_qn;
- std::vector< std::map< TNode, QcfNodeIndex >::iterator > d_qni;
- bool doMatching( QuantConflictFind * p, QuantInfo * qi );
- //for matching : each index is either a variable or a ground term
- unsigned d_qni_size;
- std::map< int, int > d_qni_var_num;
- std::map< int, TNode > d_qni_gterm;
- std::map< int, TNode > d_qni_gterm_rep;
- std::map< int, int > d_qni_bound;
- std::vector< int > d_qni_bound_except;
- std::map< int, TNode > d_qni_bound_cons;
- std::map< int, int > d_qni_bound_cons_var;
- std::map< int, int >::iterator d_binding_it;
- //std::vector< int > d_independent;
- bool d_matched_basis;
- bool d_binding;
- //int getVarBindingVar();
- std::map< int, Node > d_ground_eval;
- //determine variable order
- void determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars );
- void collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars );
-public:
- //type of the match generator
- enum {
- typ_invalid,
- typ_ground,
- typ_pred,
- typ_eq,
- typ_formula,
- typ_var,
- typ_ite_var,
- typ_bool_var,
- typ_tconstraint,
- typ_tsym,
- };
- void debugPrintType( const char * c, short typ, bool isTrace = false );
-public:
- MatchGen() : d_type( typ_invalid ){}
- MatchGen( QuantInfo * qi, Node n, bool isVar = false );
- bool d_tgt;
- bool d_tgt_orig;
- bool d_wasSet;
- Node d_n;
- std::vector< MatchGen > d_children;
- short d_type;
- bool d_type_not;
- void reset_round( QuantConflictFind * p );
- void reset( QuantConflictFind * p, bool tgt, QuantInfo * qi );
- bool getNextMatch( QuantConflictFind * p, QuantInfo * qi );
- bool getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp );
- Node getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp );
- bool isValid() { return d_type!=typ_invalid; }
- void setInvalid();
-
- // is this term treated as UF application?
- static bool isHandledBoolConnective( TNode n );
- static bool isHandledUfTerm( TNode n );
- static Node getOperator( QuantConflictFind * p, Node n );
- //can this node be handled by the algorithm
- static bool isHandled( TNode n );
-};
-
-//info for quantifiers
-class QuantInfo {
-private:
- void registerNode( Node n, bool hasPol, bool pol, bool beneathQuant = false );
- void flatten( Node n, bool beneathQuant );
-private: //for completing match
- std::vector< int > d_unassigned;
- std::vector< TypeNode > d_unassigned_tn;
- int d_unassigned_nvar;
- int d_una_index;
- std::vector< int > d_una_eqc_count;
-public:
- QuantInfo() : d_mg( NULL ) {}
- ~QuantInfo() { delete d_mg; }
- std::vector< TNode > d_vars;
- std::map< TNode, int > d_var_num;
- std::vector< int > d_tsym_vars;
- std::map< TNode, bool > d_inMatchConstraint;
- std::map< int, std::vector< Node > > d_var_constraint[2];
- int getVarNum( TNode v ) { return d_var_num.find( v )!=d_var_num.end() ? d_var_num[v] : -1; }
- bool isVar( TNode v ) { return d_var_num.find( v )!=d_var_num.end(); }
- int getNumVars() { return (int)d_vars.size(); }
- TNode getVar( int i ) { return d_vars[i]; }
-
- MatchGen * d_mg;
- Node d_q;
- std::map< int, MatchGen * > d_var_mg;
- void reset_round( QuantConflictFind * p );
-public:
- //initialize
- void initialize( Node q, Node qn );
- //current constraints
- std::vector< TNode > d_match;
- std::vector< TNode > d_match_term;
- std::map< int, std::map< TNode, int > > d_curr_var_deq;
- std::map< Node, bool > d_tconstraints;
- int getCurrentRepVar( int v );
- TNode getCurrentValue( TNode n );
- TNode getCurrentExpValue( TNode n );
- bool getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq = false );
- int addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity );
- int addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove );
- bool setMatch( QuantConflictFind * p, int v, TNode n );
- bool isMatchSpurious( QuantConflictFind * p );
- bool isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms );
- bool entailmentTest( QuantConflictFind * p, Node lit, bool chEnt = true );
- bool completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue = false );
- void revertMatch( std::vector< int >& assigned );
- void debugPrintMatch( const char * c );
- bool isConstrainedVar( int v );
-public:
- void getMatch( std::vector< Node >& terms );
-};
-
-class QuantConflictFind : public QuantifiersModule
-{
- friend class QcfNodeIndex;
- friend class MatchGen;
- friend class QuantInfo;
- typedef context::CDChunkList<Node> NodeList;
- typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
-private:
- context::Context* d_c;
- context::CDO< bool > d_conflict;
- bool d_performCheck;
- std::vector< Node > d_quant_order;
- std::map< Kind, Node > d_zero;
- //for storing nodes created during t-constraint solving (prevents memory leaks)
- std::vector< Node > d_tempCache;
-private:
- std::map< Node, Node > d_op_node;
- int d_fid_count;
- std::map< Node, int > d_fid;
- Node mkEqNode( Node a, Node b );
-public: //for ground terms
- Node d_true;
- Node d_false;
- TNode getZero( Kind k );
-private:
- Node evaluateTerm( Node n );
- int evaluate( Node n, bool pref = false, bool hasPref = false );
-private:
- //currently asserted quantifiers
- NodeList d_qassert;
- std::map< Node, QuantInfo > d_qinfo;
-private: //for equivalence classes
- eq::EqualityEngine * getEqualityEngine();
- bool areDisequal( Node n1, Node n2 );
- bool areEqual( Node n1, Node n2 );
- Node getRepresentative( Node n );
-
-/*
- class EqcInfo {
- public:
- EqcInfo( context::Context* c ) : d_diseq( c ) {}
- NodeBoolMap d_diseq;
- bool isDisequal( Node n ) { return d_diseq.find( n )!=d_diseq.end() && d_diseq[n]; }
- void setDisequal( Node n, bool val = true ) { d_diseq[n] = val; }
- //NodeBoolMap& getRelEqr( int index ) { return index==0 ? d_rel_eqr_e : d_rel_eqr_d; }
- };
- std::map< Node, EqcInfo * > d_eqc_info;
- EqcInfo * getEqcInfo( Node n, bool doCreate = true );
-*/
- // operator -> index(terms)
- std::map< TNode, QcfNodeIndex > d_uf_terms;
- // operator -> index(eqc -> terms)
- std::map< TNode, QcfNodeIndex > d_eqc_uf_terms;
- //get qcf node index
- QcfNodeIndex * getQcfNodeIndex( Node eqc, Node f );
- QcfNodeIndex * getQcfNodeIndex( Node f );
- // type -> list(eqc)
- std::map< TypeNode, std::vector< TNode > > d_eqcs;
- std::map< TypeNode, Node > d_model_basis;
- //mapping from UF terms to representatives of their arguments
- std::map< TNode, std::vector< TNode > > d_arg_reps;
- //compute arg reps
- void computeArgReps( TNode n );
- //compute
- void computeUfTerms( TNode f );
-public:
- enum {
- effort_conflict,
- effort_prop_eq,
- effort_mc,
- };
- short d_effort;
- void setEffort( int e ) { d_effort = e; }
- static short getMaxQcfEffort();
- bool areMatchEqual( TNode n1, TNode n2 );
- bool areMatchDisequal( TNode n1, TNode n2 );
-public:
- QuantConflictFind( QuantifiersEngine * qe, context::Context* c );
- /** register quantifier */
- void registerQuantifier( Node q );
-public:
- /** assert quantifier */
- void assertNode( Node q );
- /** new node */
- void newEqClass( Node n );
- /** merge */
- void merge( Node a, Node b );
- /** assert disequal */
- void assertDisequal( Node a, Node b );
- /** reset round */
- void reset_round( Theory::Effort level );
- /** check */
- void check( Theory::Effort level );
- /** needs check */
- bool needsCheck( Theory::Effort level );
-private:
- bool d_needs_computeRelEqr;
-public:
- void computeRelevantEqr();
-private:
- void debugPrint( const char * c );
- //for debugging
- std::vector< Node > d_quants;
- std::map< Node, int > d_quant_id;
- void debugPrintQuant( const char * c, Node q );
- void debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum = true );
-public:
- /** statistics class */
- class Statistics {
- public:
- IntStat d_inst_rounds;
- IntStat d_conflict_inst;
- IntStat d_prop_inst;
- IntStat d_entailment_checks;
- Statistics();
- ~Statistics();
- };
- Statistics d_statistics;
- /** Identify this module */
- std::string identify() const { return "QcfEngine"; }
-};
-
-}
-}
-}
-
-#endif
+/********************* */ +/*! \file quant_conflict_find.h + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: none + ** 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 quantifiers conflict find class + **/ + +#include "cvc4_private.h" + +#ifndef QUANT_CONFLICT_FIND +#define QUANT_CONFLICT_FIND + +#include "context/cdhashmap.h" +#include "context/cdchunk_list.h" +#include "theory/quantifiers_engine.h" + +namespace CVC4 { +namespace theory { +namespace quantifiers { + +class QcfNode; + +class QuantConflictFind; + +class QcfNodeIndex { +public: + std::map< TNode, QcfNodeIndex > d_children; + void clear() { d_children.clear(); } + void debugPrint( const char * c, int t ); + Node existsTerm( TNode n, std::vector< TNode >& reps, int index = 0 ); + Node addTerm( TNode n, std::vector< TNode >& reps, int index = 0 ); +}; + +class QuantInfo; + +//match generator +class MatchGen { + friend class QuantInfo; +private: + //current children information + int d_child_counter; + //children of this object + std::vector< int > d_children_order; + unsigned getNumChildren() { return d_children.size(); } + MatchGen * getChild( int i ) { return &d_children[d_children_order[i]]; } + //MatchGen * getChild( int i ) { return &d_children[i]; } + //current matching information + std::vector< QcfNodeIndex * > d_qn; + std::vector< std::map< TNode, QcfNodeIndex >::iterator > d_qni; + bool doMatching( QuantConflictFind * p, QuantInfo * qi ); + //for matching : each index is either a variable or a ground term + unsigned d_qni_size; + std::map< int, int > d_qni_var_num; + std::map< int, TNode > d_qni_gterm; + std::map< int, TNode > d_qni_gterm_rep; + std::map< int, int > d_qni_bound; + std::vector< int > d_qni_bound_except; + std::map< int, TNode > d_qni_bound_cons; + std::map< int, int > d_qni_bound_cons_var; + std::map< int, int >::iterator d_binding_it; + //std::vector< int > d_independent; + bool d_matched_basis; + bool d_binding; + //int getVarBindingVar(); + std::map< int, Node > d_ground_eval; + //determine variable order + void determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars ); + void collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars ); +public: + //type of the match generator + enum { + typ_invalid, + typ_ground, + typ_pred, + typ_eq, + typ_formula, + typ_var, + typ_ite_var, + typ_bool_var, + typ_tconstraint, + typ_tsym, + }; + void debugPrintType( const char * c, short typ, bool isTrace = false ); +public: + MatchGen() : d_type( typ_invalid ){} + MatchGen( QuantInfo * qi, Node n, bool isVar = false ); + bool d_tgt; + bool d_tgt_orig; + bool d_wasSet; + Node d_n; + std::vector< MatchGen > d_children; + short d_type; + bool d_type_not; + void reset_round( QuantConflictFind * p ); + void reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ); + bool getNextMatch( QuantConflictFind * p, QuantInfo * qi ); + bool getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp ); + Node getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp ); + bool isValid() { return d_type!=typ_invalid; } + void setInvalid(); + + // is this term treated as UF application? + static bool isHandledBoolConnective( TNode n ); + static bool isHandledUfTerm( TNode n ); + static Node getOperator( QuantConflictFind * p, Node n ); + //can this node be handled by the algorithm + static bool isHandled( TNode n ); +}; + +//info for quantifiers +class QuantInfo { +private: + void registerNode( Node n, bool hasPol, bool pol, bool beneathQuant = false ); + void flatten( Node n, bool beneathQuant ); +private: //for completing match + std::vector< int > d_unassigned; + std::vector< TypeNode > d_unassigned_tn; + int d_unassigned_nvar; + int d_una_index; + std::vector< int > d_una_eqc_count; +public: + QuantInfo() : d_mg( NULL ) {} + ~QuantInfo() { delete d_mg; } + std::vector< TNode > d_vars; + std::map< TNode, int > d_var_num; + std::vector< int > d_tsym_vars; + std::map< TNode, bool > d_inMatchConstraint; + std::map< int, std::vector< Node > > d_var_constraint[2]; + int getVarNum( TNode v ) { return d_var_num.find( v )!=d_var_num.end() ? d_var_num[v] : -1; } + bool isVar( TNode v ) { return d_var_num.find( v )!=d_var_num.end(); } + int getNumVars() { return (int)d_vars.size(); } + TNode getVar( int i ) { return d_vars[i]; } + + MatchGen * d_mg; + Node d_q; + std::map< int, MatchGen * > d_var_mg; + void reset_round( QuantConflictFind * p ); +public: + //initialize + void initialize( Node q, Node qn ); + //current constraints + std::vector< TNode > d_match; + std::vector< TNode > d_match_term; + std::map< int, std::map< TNode, int > > d_curr_var_deq; + std::map< Node, bool > d_tconstraints; + int getCurrentRepVar( int v ); + TNode getCurrentValue( TNode n ); + TNode getCurrentExpValue( TNode n ); + bool getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq = false ); + int addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity ); + int addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove ); + bool setMatch( QuantConflictFind * p, int v, TNode n ); + bool isMatchSpurious( QuantConflictFind * p ); + bool isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms ); + bool entailmentTest( QuantConflictFind * p, Node lit, bool chEnt = true ); + bool completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue = false ); + void revertMatch( std::vector< int >& assigned ); + void debugPrintMatch( const char * c ); + bool isConstrainedVar( int v ); +public: + void getMatch( std::vector< Node >& terms ); +}; + +class QuantConflictFind : public QuantifiersModule +{ + friend class QcfNodeIndex; + friend class MatchGen; + friend class QuantInfo; + typedef context::CDChunkList<Node> NodeList; + typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap; +private: + context::Context* d_c; + context::CDO< bool > d_conflict; + bool d_performCheck; + std::vector< Node > d_quant_order; + std::map< Kind, Node > d_zero; + //for storing nodes created during t-constraint solving (prevents memory leaks) + std::vector< Node > d_tempCache; +private: + std::map< Node, Node > d_op_node; + int d_fid_count; + std::map< Node, int > d_fid; + Node mkEqNode( Node a, Node b ); +public: //for ground terms + Node d_true; + Node d_false; + TNode getZero( Kind k ); +private: + Node evaluateTerm( Node n ); + int evaluate( Node n, bool pref = false, bool hasPref = false ); +private: + //currently asserted quantifiers + NodeList d_qassert; + std::map< Node, QuantInfo > d_qinfo; +private: //for equivalence classes + eq::EqualityEngine * getEqualityEngine(); + bool areDisequal( Node n1, Node n2 ); + bool areEqual( Node n1, Node n2 ); + Node getRepresentative( Node n ); + +/* + class EqcInfo { + public: + EqcInfo( context::Context* c ) : d_diseq( c ) {} + NodeBoolMap d_diseq; + bool isDisequal( Node n ) { return d_diseq.find( n )!=d_diseq.end() && d_diseq[n]; } + void setDisequal( Node n, bool val = true ) { d_diseq[n] = val; } + //NodeBoolMap& getRelEqr( int index ) { return index==0 ? d_rel_eqr_e : d_rel_eqr_d; } + }; + std::map< Node, EqcInfo * > d_eqc_info; + EqcInfo * getEqcInfo( Node n, bool doCreate = true ); +*/ + // operator -> index(terms) + std::map< TNode, QcfNodeIndex > d_uf_terms; + // operator -> index(eqc -> terms) + std::map< TNode, QcfNodeIndex > d_eqc_uf_terms; + //get qcf node index + QcfNodeIndex * getQcfNodeIndex( Node eqc, Node f ); + QcfNodeIndex * getQcfNodeIndex( Node f ); + // type -> list(eqc) + std::map< TypeNode, std::vector< TNode > > d_eqcs; + std::map< TypeNode, Node > d_model_basis; + //mapping from UF terms to representatives of their arguments + std::map< TNode, std::vector< TNode > > d_arg_reps; + //compute arg reps + void computeArgReps( TNode n ); + //compute + void computeUfTerms( TNode f ); +public: + enum { + effort_conflict, + effort_prop_eq, + effort_mc, + }; + short d_effort; + void setEffort( int e ) { d_effort = e; } + static short getMaxQcfEffort(); + bool areMatchEqual( TNode n1, TNode n2 ); + bool areMatchDisequal( TNode n1, TNode n2 ); +public: + QuantConflictFind( QuantifiersEngine * qe, context::Context* c ); + /** register quantifier */ + void registerQuantifier( Node q ); +public: + /** assert quantifier */ + void assertNode( Node q ); + /** new node */ + void newEqClass( Node n ); + /** merge */ + void merge( Node a, Node b ); + /** assert disequal */ + void assertDisequal( Node a, Node b ); + /** reset round */ + void reset_round( Theory::Effort level ); + /** check */ + void check( Theory::Effort level ); + /** needs check */ + bool needsCheck( Theory::Effort level ); +private: + bool d_needs_computeRelEqr; +public: + void computeRelevantEqr(); +private: + void debugPrint( const char * c ); + //for debugging + std::vector< Node > d_quants; + std::map< Node, int > d_quant_id; + void debugPrintQuant( const char * c, Node q ); + void debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum = true ); +public: + /** statistics class */ + class Statistics { + public: + IntStat d_inst_rounds; + IntStat d_conflict_inst; + IntStat d_prop_inst; + IntStat d_entailment_checks; + Statistics(); + ~Statistics(); + }; + Statistics d_statistics; + /** Identify this module */ + std::string identify() const { return "QcfEngine"; } +}; + +} +} +} + +#endif diff --git a/src/theory/strings/regexp_operation.cpp b/src/theory/strings/regexp_operation.cpp index aee6294bc..18df0f759 100644 --- a/src/theory/strings/regexp_operation.cpp +++ b/src/theory/strings/regexp_operation.cpp @@ -1,1521 +1,1521 @@ -/********************* */
+/********************* */ -/*! \file regexp_operation.cpp
- ** \verbatim
- ** Original author: Tianyi Liang
- ** Major contributors: none
- ** 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 Symbolic Regular Expresion Operations
- **
- ** Symbolic Regular Expresion Operations
- **/
-
-#include "theory/strings/regexp_operation.h"
-#include "expr/kind.h"
-
-namespace CVC4 {
-namespace theory {
-namespace strings {
-
-RegExpOpr::RegExpOpr() {
- d_emptyString = NodeManager::currentNM()->mkConst( ::CVC4::String("") );
- d_true = NodeManager::currentNM()->mkConst( true );
- d_false = NodeManager::currentNM()->mkConst( false );
- d_zero = NodeManager::currentNM()->mkConst( ::CVC4::Rational(0) );
- d_one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) );
- d_emptySingleton = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString );
- std::vector< Node > nvec;
- d_emptyRegexp = NodeManager::currentNM()->mkNode( kind::REGEXP_EMPTY, nvec );
- d_sigma = NodeManager::currentNM()->mkNode( kind::REGEXP_SIGMA, nvec );
- d_sigma_star = NodeManager::currentNM()->mkNode( kind::REGEXP_STAR, d_sigma );
- d_card = 256;
-}
-
-int RegExpOpr::gcd ( int a, int b ) {
- int c;
- while ( a != 0 ) {
- c = a; a = b%a; b = c;
- }
- return b;
-}
-
-bool RegExpOpr::checkConstRegExp( Node r ) {
- Trace("strings-regexp-cstre") << "RegExp-CheckConstRegExp starts with " << mkString( r ) << std::endl;
- bool ret = true;
- if( d_cstre_cache.find( r ) != d_cstre_cache.end() ) {
- ret = d_cstre_cache[r];
- } else {
- if(r.getKind() == kind::STRING_TO_REGEXP) {
- Node tmp = Rewriter::rewrite( r[0] );
- ret = tmp.isConst();
- } else {
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(!checkConstRegExp(r[i])) {
- ret = false; break;
- }
- }
- }
- d_cstre_cache[r] = ret;
- }
- return ret;
-}
-
-// 0-unknown, 1-yes, 2-no
-int RegExpOpr::delta( Node r, Node &exp ) {
- Trace("regexp-delta") << "RegExp-Delta starts with " << mkString( r ) << std::endl;
- int ret = 0;
- if( d_delta_cache.find( r ) != d_delta_cache.end() ) {
- ret = d_delta_cache[r].first;
- exp = d_delta_cache[r].second;
- } else {
- int k = r.getKind();
- switch( k ) {
- case kind::REGEXP_EMPTY: {
- ret = 2;
- break;
- }
- case kind::REGEXP_SIGMA: {
- ret = 2;
- break;
- }
- case kind::STRING_TO_REGEXP: {
- Node tmp = Rewriter::rewrite(r[0]);
- if(tmp.isConst()) {
- if(tmp == d_emptyString) {
- ret = 1;
- } else {
- ret = 2;
- }
- } else {
- ret = 0;
- if(tmp.getKind() == kind::STRING_CONCAT) {
- for(unsigned i=0; i<tmp.getNumChildren(); i++) {
- if(tmp[i].isConst()) {
- ret = 2; break;
- }
- }
-
- }
- if(ret == 0) {
- exp = r[0].eqNode(d_emptyString);
- }
- }
- break;
- }
- case kind::REGEXP_CONCAT: {
- bool flag = false;
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- Node exp2;
- int tmp = delta( r[i], exp2 );
- if(tmp == 2) {
- ret = 2;
- break;
- } else if(tmp == 0) {
- vec_nodes.push_back( exp2 );
- flag = true;
- }
- }
- if(ret != 2) {
- if(!flag) {
- ret = 1;
- } else {
- exp = vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode(kind::AND, vec_nodes);
- }
- }
- break;
- }
- case kind::REGEXP_UNION: {
- bool flag = false;
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- Node exp2;
- int tmp = delta( r[i], exp2 );
- if(tmp == 1) {
- ret = 1;
- break;
- } else if(tmp == 0) {
- vec_nodes.push_back( exp2 );
- flag = true;
- }
- }
- if(ret != 1) {
- if(!flag) {
- ret = 2;
- } else {
- exp = vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode(kind::OR, vec_nodes);
- }
- }
- break;
- }
- case kind::REGEXP_INTER: {
- bool flag = false;
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- Node exp2;
- int tmp = delta( r[i], exp2 );
- if(tmp == 2) {
- ret = 2;
- break;
- } else if(tmp == 0) {
- vec_nodes.push_back( exp2 );
- flag = true;
- }
- }
- if(ret != 2) {
- if(!flag) {
- ret = 1;
- } else {
- exp = vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode(kind::AND, vec_nodes);
- }
- }
- break;
- }
- case kind::REGEXP_STAR: {
- ret = 1;
- break;
- }
- case kind::REGEXP_PLUS: {
- ret = delta( r[0], exp );
- break;
- }
- case kind::REGEXP_OPT: {
- ret = 1;
- break;
- }
- case kind::REGEXP_RANGE: {
- ret = 2;
- break;
- }
- default: {
- Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in delta of RegExp." << std::endl;
- Assert( false );
- //return Node::null();
- }
- }
- if(!exp.isNull()) {
- exp = Rewriter::rewrite(exp);
- }
- std::pair< int, Node > p(ret, exp);
- d_delta_cache[r] = p;
- }
- Trace("regexp-delta") << "RegExp-Delta returns : " << ret << std::endl;
- return ret;
-}
-
-// 0-unknown, 1-yes, 2-no
-int RegExpOpr::derivativeS( Node r, CVC4::String c, Node &retNode ) {
- Assert( c.size() < 2 );
- Trace("regexp-derive") << "RegExp-derive starts with R{ " << mkString( r ) << " }, c=" << c << std::endl;
-
- int ret = 1;
- retNode = d_emptyRegexp;
-
- PairNodeStr dv = std::make_pair( r, c );
- if( d_deriv_cache.find( dv ) != d_deriv_cache.end() ) {
- retNode = d_deriv_cache[dv].first;
- ret = d_deriv_cache[dv].second;
- } else if( c.isEmptyString() ) {
- Node expNode;
- ret = delta( r, expNode );
- if(ret == 0) {
- retNode = NodeManager::currentNM()->mkNode(kind::ITE, expNode, r, d_emptyRegexp);
- } else if(ret == 1) {
- retNode = r;
- }
- std::pair< Node, int > p(retNode, ret);
- d_deriv_cache[dv] = p;
- } else {
- switch( r.getKind() ) {
- case kind::REGEXP_EMPTY: {
- ret = 2;
- break;
- }
- case kind::REGEXP_SIGMA: {
- retNode = d_emptySingleton;
- break;
- }
- case kind::STRING_TO_REGEXP: {
- Node tmp = Rewriter::rewrite(r[0]);
- if(tmp.isConst()) {
- if(tmp == d_emptyString) {
- ret = 2;
- } else {
- if(tmp.getConst< CVC4::String >().getFirstChar() == c.getFirstChar()) {
- retNode = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP,
- tmp.getConst< CVC4::String >().size() == 1 ? d_emptyString : NodeManager::currentNM()->mkConst( tmp.getConst< CVC4::String >().substr(1) ) );
- } else {
- ret = 2;
- }
- }
- } else {
- ret = 0;
- Node rest;
- if(tmp.getKind() == kind::STRING_CONCAT) {
- Node t2 = tmp[0];
- if(t2.isConst()) {
- if(t2.getConst< CVC4::String >().getFirstChar() == c.getFirstChar()) {
- Node n = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP,
- tmp.getConst< CVC4::String >().size() == 1 ? d_emptyString : NodeManager::currentNM()->mkConst( tmp.getConst< CVC4::String >().substr(1) ) );
- std::vector< Node > vec_nodes;
- vec_nodes.push_back(n);
- for(unsigned i=1; i<tmp.getNumChildren(); i++) {
- vec_nodes.push_back(tmp[i]);
- }
- retNode = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vec_nodes);
- ret = 1;
- } else {
- ret = 2;
- }
- } else {
- tmp = tmp[0];
- std::vector< Node > vec_nodes;
- for(unsigned i=1; i<tmp.getNumChildren(); i++) {
- vec_nodes.push_back(tmp[i]);
- }
- rest = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vec_nodes);
- }
- }
- if(ret == 0) {
- Node sk = NodeManager::currentNM()->mkSkolem( "rsp", NodeManager::currentNM()->stringType(), "Split RegExp" );
- retNode = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, sk);
- if(!rest.isNull()) {
- retNode = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, retNode, rest));
- }
- Node exp = tmp.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_CONCAT,
- NodeManager::currentNM()->mkConst(c), sk));
- retNode = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::ITE, exp, retNode, d_emptyRegexp));
- }
- }
- break;
- }
- case kind::REGEXP_CONCAT: {
- std::vector< Node > vec_nodes;
- std::vector< Node > delta_nodes;
- Node dnode = d_true;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- Node dc;
- Node exp2;
- int rt = derivativeS(r[i], c, dc);
- if(rt != 2) {
- if(rt == 0) {
- ret = 0;
- }
- std::vector< Node > vec_nodes2;
- if(dc != d_emptySingleton) {
- vec_nodes2.push_back( dc );
- }
- for(unsigned j=i+1; j<r.getNumChildren(); ++j) {
- if(r[j] != d_emptySingleton) {
- vec_nodes2.push_back( r[j] );
- }
- }
- Node tmp = vec_nodes2.size()==0 ? d_emptySingleton :
- vec_nodes2.size()==1 ? vec_nodes2[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, vec_nodes2 );
- if(dnode != d_true) {
- tmp = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::ITE, dnode, tmp, d_emptyRegexp));
- ret = 0;
- }
- if(std::find(vec_nodes.begin(), vec_nodes.end(), tmp) == vec_nodes.end()) {
- vec_nodes.push_back( tmp );
- }
- }
- Node exp3;
- int rt2 = delta( r[i], exp3 );
- if( rt2 == 0 ) {
- dnode = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND, dnode, exp3));
- } else if( rt2 == 2 ) {
- break;
- }
- }
- retNode = vec_nodes.size() == 0 ? d_emptyRegexp :
- ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) );
- if(retNode == d_emptyRegexp) {
- ret = 2;
- }
- break;
- }
- case kind::REGEXP_UNION: {
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- Node dc;
- int rt = derivativeS(r[i], c, dc);
- if(rt == 0) {
- ret = 0;
- }
- if(rt != 2) {
- if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {
- vec_nodes.push_back( dc );
- }
- }
- Trace("regexp-derive") << "RegExp-derive OR R[" << i << "]{ " << mkString(r[i]) << " returns " << mkString(dc) << std::endl;
- }
- retNode = vec_nodes.size() == 0 ? d_emptyRegexp :
- ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) );
- if(retNode == d_emptyRegexp) {
- ret = 2;
- }
- break;
- }
- case kind::REGEXP_INTER: {
- bool flag = true;
- bool flag_sg = false;
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- Node dc;
- int rt = derivativeS(r[i], c, dc);
- if(rt == 0) {
- ret = 0;
- } else if(rt == 2) {
- flag = false;
- break;
- }
- if(dc == d_sigma_star) {
- flag_sg = true;
- } else {
- if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {
- vec_nodes.push_back( dc );
- }
- }
- }
- if(flag) {
- if(vec_nodes.size() == 0 && flag_sg) {
- retNode = d_sigma_star;
- } else {
- retNode = vec_nodes.size() == 0 ? d_emptyRegexp :
- ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_INTER, vec_nodes ) );
- if(retNode == d_emptyRegexp) {
- ret = 2;
- }
- }
- } else {
- retNode = d_emptyRegexp;
- ret = 2;
- }
- break;
- }
- case kind::REGEXP_STAR: {
- Node dc;
- ret = derivativeS(r[0], c, dc);
- retNode = dc==d_emptyRegexp ? dc : (dc==d_emptySingleton ? r : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, dc, r ));
- break;
- }
- default: {
- Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in derivative of RegExp." << std::endl;
- Assert( false, "Unsupported Term" );
- }
- }
- if(retNode != d_emptyRegexp) {
- retNode = Rewriter::rewrite( retNode );
- }
- std::pair< Node, int > p(retNode, ret);
- d_deriv_cache[dv] = p;
- }
-
- Trace("regexp-derive") << "RegExp-derive returns : " << mkString( retNode ) << std::endl;
- return ret;
-}
-
-Node RegExpOpr::derivativeSingle( Node r, CVC4::String c ) {
- Assert( c.size() < 2 );
- Trace("regexp-derive") << "RegExp-derive starts with R{ " << mkString( r ) << " }, c=" << c << std::endl;
- Node retNode = d_emptyRegexp;
- PairNodeStr dv = std::make_pair( r, c );
- if( d_dv_cache.find( dv ) != d_dv_cache.end() ) {
- retNode = d_dv_cache[dv];
- } else if( c.isEmptyString() ){
- Node exp;
- int tmp = delta( r, exp );
- if(tmp == 0) {
- // TODO variable
- retNode = d_emptyRegexp;
- } else if(tmp == 1) {
- retNode = r;
- } else {
- retNode = d_emptyRegexp;
- }
- } else {
- int k = r.getKind();
- switch( k ) {
- case kind::REGEXP_EMPTY: {
- retNode = d_emptyRegexp;
- break;
- }
- case kind::REGEXP_SIGMA: {
- retNode = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString );
- break;
- }
- case kind::STRING_TO_REGEXP: {
- if(r[0].isConst()) {
- if(r[0] == d_emptyString) {
- retNode = d_emptyRegexp;
- } else {
- if(r[0].getConst< CVC4::String >().getFirstChar() == c.getFirstChar()) {
- retNode = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP,
- r[0].getConst< CVC4::String >().size() == 1 ? d_emptyString : NodeManager::currentNM()->mkConst( r[0].getConst< CVC4::String >().substr(1) ) );
- } else {
- retNode = d_emptyRegexp;
- }
- }
- } else {
- // TODO variable
- retNode = d_emptyRegexp;
- }
- break;
- }
- case kind::REGEXP_CONCAT: {
- Node rees = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString );
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- Node dc = derivativeSingle(r[i], c);
- if(dc != d_emptyRegexp) {
- std::vector< Node > vec_nodes2;
- if(dc != rees) {
- vec_nodes2.push_back( dc );
- }
- for(unsigned j=i+1; j<r.getNumChildren(); ++j) {
- if(r[j] != rees) {
- vec_nodes2.push_back( r[j] );
- }
- }
- Node tmp = vec_nodes2.size()==0 ? rees :
- vec_nodes2.size()==1 ? vec_nodes2[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, vec_nodes2 );
- if(std::find(vec_nodes.begin(), vec_nodes.end(), tmp) == vec_nodes.end()) {
- vec_nodes.push_back( tmp );
- }
- }
- Node exp;
- if( delta( r[i], exp ) != 1 ) {
- break;
- }
- }
- retNode = vec_nodes.size() == 0 ? d_emptyRegexp :
- ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) );
- break;
- }
- case kind::REGEXP_UNION: {
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- Node dc = derivativeSingle(r[i], c);
- if(dc != d_emptyRegexp) {
- if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {
- vec_nodes.push_back( dc );
- }
- }
- Trace("regexp-derive") << "RegExp-derive OR R[" << i << "]{ " << mkString(r[i]) << " returns " << mkString(dc) << std::endl;
- }
- retNode = vec_nodes.size() == 0 ? d_emptyRegexp :
- ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) );
- break;
- }
- case kind::REGEXP_INTER: {
- bool flag = true;
- bool flag_sg = false;
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- Node dc = derivativeSingle(r[i], c);
- if(dc != d_emptyRegexp) {
- if(dc == d_sigma_star) {
- flag_sg = true;
- } else {
- if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {
- vec_nodes.push_back( dc );
- }
- }
- } else {
- flag = false;
- break;
- }
- }
- if(flag) {
- if(vec_nodes.size() == 0 && flag_sg) {
- retNode = d_sigma_star;
- } else {
- retNode = vec_nodes.size() == 0 ? d_emptyRegexp :
- ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_INTER, vec_nodes ) );
- }
- } else {
- retNode = d_emptyRegexp;
- }
- break;
- }
- case kind::REGEXP_STAR: {
- Node dc = derivativeSingle(r[0], c);
- if(dc != d_emptyRegexp) {
- retNode = dc==NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString ) ? r : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, dc, r );
- } else {
- retNode = d_emptyRegexp;
- }
- break;
- }
- default: {
- //TODO: special sym: sigma, none, all
- Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in derivative of RegExp." << std::endl;
- Assert( false, "Unsupported Term" );
- //return Node::null();
- }
- }
- if(retNode != d_emptyRegexp) {
- retNode = Rewriter::rewrite( retNode );
- }
- d_dv_cache[dv] = retNode;
- }
- Trace("regexp-derive") << "RegExp-derive returns : " << mkString( retNode ) << std::endl;
- return retNode;
-}
-
-//TODO:
-bool RegExpOpr::guessLength( Node r, int &co ) {
- int k = r.getKind();
- switch( k ) {
- case kind::STRING_TO_REGEXP:
- {
- if(r[0].isConst()) {
- co += r[0].getConst< CVC4::String >().size();
- return true;
- } else {
- return false;
- }
- }
- break;
- case kind::REGEXP_CONCAT:
- {
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(!guessLength( r[i], co)) {
- return false;
- }
- }
- return true;
- }
- break;
- case kind::REGEXP_UNION:
- {
- int g_co;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- int cop = 0;
- if(!guessLength( r[i], cop)) {
- return false;
- }
- if(i == 0) {
- g_co = cop;
- } else {
- g_co = gcd(g_co, cop);
- }
- }
- return true;
- }
- break;
- case kind::REGEXP_INTER:
- {
- int g_co;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- int cop = 0;
- if(!guessLength( r[i], cop)) {
- return false;
- }
- if(i == 0) {
- g_co = cop;
- } else {
- g_co = gcd(g_co, cop);
- }
- }
- return true;
- }
- break;
- case kind::REGEXP_STAR:
- {
- co = 0;
- return true;
- }
- break;
- default:
- Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in membership of RegExp." << std::endl;
- return false;
- }
-}
-
-void RegExpOpr::firstChars( Node r, std::set<unsigned> &pcset, SetNodes &pvset ) {
- std::map< Node, std::pair< std::set<unsigned>, SetNodes > >::const_iterator itr = d_fset_cache.find(r);
- if(itr != d_fset_cache.end()) {
- pcset.insert((itr->second).first.begin(), (itr->second).first.end());
- pvset.insert((itr->second).second.begin(), (itr->second).second.end());
- } else {
- std::set<unsigned> cset;
- SetNodes vset;
- int k = r.getKind();
- switch( k ) {
- case kind::REGEXP_EMPTY: {
- break;
- }
- case kind::REGEXP_SIGMA: {
- for(unsigned i=0; i<d_card; i++) {
- cset.insert(i);
- }
- break;
- }
- case kind::STRING_TO_REGEXP: {
- Node st = Rewriter::rewrite(r[0]);
- if(st.isConst()) {
- CVC4::String s = st.getConst< CVC4::String >();
- if(s.size() != 0) {
- cset.insert(s[0]);
- }
- } else if(st.getKind() == kind::VARIABLE) {
- vset.insert( st );
- } else {
- if(st[0].isConst()) {
- CVC4::String s = st[0].getConst< CVC4::String >();
- cset.insert(s[0]);
- } else {
- vset.insert( st[0] );
- }
- }
- break;
- }
- case kind::REGEXP_CONCAT: {
- for(unsigned i=0; i<r.getNumChildren(); i++) {
- firstChars(r[i], cset, vset);
- Node n = r[i];
- Node exp;
- int r = delta( n, exp );
- if(r != 1) {
- break;
- }
- }
- break;
- }
- case kind::REGEXP_UNION: {
- for(unsigned i=0; i<r.getNumChildren(); i++) {
- firstChars(r[i], cset, vset);
- }
- break;
- }
- case kind::REGEXP_INTER: {
- //TODO: Overapproximation for now
- for(unsigned i=0; i<r.getNumChildren(); i++) {
- firstChars(r[i], cset, vset);
- }
- break;
- }
- case kind::REGEXP_STAR: {
- firstChars(r[0], cset, vset);
- break;
- }
- default: {
- Trace("strings-regexp") << "Unsupported term: " << r << " in getCharSet." << std::endl;
- Assert( false, "Unsupported Term" );
- }
- }
- pcset.insert(cset.begin(), cset.end());
- pvset.insert(vset.begin(), vset.end());
- std::pair< std::set<unsigned>, SetNodes > p(cset, vset);
- d_fset_cache[r] = p;
-
- Trace("regexp-fset") << "FSET( " << mkString(r) << " ) = { ";
- for(std::set<unsigned>::const_iterator itr = cset.begin();
- itr != cset.end(); itr++) {
- Trace("regexp-fset") << CVC4::String::convertUnsignedIntToChar(*itr) << ",";
- }
- Trace("regexp-fset") << " }" << std::endl;
- }
-}
-
-bool RegExpOpr::follow( Node r, CVC4::String c, std::vector< char > &vec_chars ) {
- int k = r.getKind();
- switch( k ) {
- case kind::STRING_TO_REGEXP:
- {
- if(r[0].isConst()) {
- if(r[0] != d_emptyString) {
- char t1 = r[0].getConst< CVC4::String >().getFirstChar();
- if(c.isEmptyString()) {
- vec_chars.push_back( t1 );
- return true;
- } else {
- char t2 = c.getFirstChar();
- if(t1 != t2) {
- return false;
- } else {
- if(c.size() >= 2) {
- vec_chars.push_back( c.substr(1,1).getFirstChar() );
- } else {
- vec_chars.push_back( '\0' );
- }
- return true;
- }
- }
- } else {
- return false;
- }
- } else {
- return false;
- }
- }
- break;
- case kind::REGEXP_CONCAT:
- {
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if( follow(r[i], c, vec_chars) ) {
- if(vec_chars[vec_chars.size() - 1] == '\0') {
- vec_chars.pop_back();
- c = d_emptyString.getConst< CVC4::String >();
- }
- } else {
- return false;
- }
- }
- vec_chars.push_back( '\0' );
- return true;
- }
- break;
- case kind::REGEXP_UNION:
- {
- bool flag = false;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if( follow(r[i], c, vec_chars) ) {
- flag=true;
- }
- }
- return flag;
- }
- break;
- case kind::REGEXP_INTER:
- {
- std::vector< char > vt2;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- std::vector< char > v_tmp;
- if( !follow(r[i], c, v_tmp) ) {
- return false;
- }
- std::vector< char > vt3(vt2);
- vt2.clear();
- std::set_intersection( vt3.begin(), vt3.end(), v_tmp.begin(), v_tmp.end(), vt2.begin() );
- if(vt2.size() == 0) {
- return false;
- }
- }
- vec_chars.insert( vec_chars.end(), vt2.begin(), vt2.end() );
- return true;
- }
- break;
- case kind::REGEXP_STAR:
- {
- if(follow(r[0], c, vec_chars)) {
- if(vec_chars[vec_chars.size() - 1] == '\0') {
- if(c.isEmptyString()) {
- return true;
- } else {
- vec_chars.pop_back();
- c = d_emptyString.getConst< CVC4::String >();
- return follow(r[0], c, vec_chars);
- }
- } else {
- return true;
- }
- } else {
- vec_chars.push_back( '\0' );
- return true;
- }
- }
- break;
- default: {
- Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in delta of RegExp." << std::endl;
- //AlwaysAssert( false );
- //return Node::null();
- return false;
- }
- }
-}
-
-Node RegExpOpr::mkAllExceptOne( char exp_c ) {
- std::vector< Node > vec_nodes;
- for(char c=d_char_start; c<=d_char_end; ++c) {
- if(c != exp_c ) {
- Node n = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst( ::CVC4::String( c ) ) );
- vec_nodes.push_back( n );
- }
- }
- return NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes );
-}
-
-//simplify
-void RegExpOpr::simplify(Node t, std::vector< Node > &new_nodes, bool polarity) {
- Trace("strings-regexp-simpl") << "RegExp-Simpl starts with " << t << ", polarity=" << polarity << std::endl;
- Assert(t.getKind() == kind::STRING_IN_REGEXP);
- Node str = Rewriter::rewrite(t[0]);
- Node re = Rewriter::rewrite(t[1]);
- if(polarity) {
- simplifyPRegExp( str, re, new_nodes );
- } else {
- simplifyNRegExp( str, re, new_nodes );
- }
- Trace("strings-regexp-simpl") << "RegExp-Simpl returns (" << new_nodes.size() << "):\n";
- for(unsigned i=0; i<new_nodes.size(); i++) {
- Trace("strings-regexp-simpl") << "\t" << new_nodes[i] << std::endl;
- }
-}
-void RegExpOpr::simplifyNRegExp( Node s, Node r, std::vector< Node > &new_nodes ) {
- std::pair < Node, Node > p(s, r);
- std::map < std::pair< Node, Node >, Node >::const_iterator itr = d_simpl_neg_cache.find(p);
- if(itr != d_simpl_neg_cache.end()) {
- new_nodes.push_back( itr->second );
- } else {
- int k = r.getKind();
- Node conc;
- switch( k ) {
- case kind::REGEXP_EMPTY: {
- conc = d_true;
- break;
- }
- case kind::REGEXP_SIGMA: {
- conc = d_one.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s)).negate();
- break;
- }
- case kind::STRING_TO_REGEXP: {
- conc = s.eqNode(r[0]).negate();
- break;
- }
- case kind::REGEXP_CONCAT: {
- //TODO: rewrite empty
- Node lens = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s);
- Node b1 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());
- Node b1v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b1);
- Node g1 = NodeManager::currentNM()->mkNode( kind::AND, NodeManager::currentNM()->mkNode(kind::GEQ, b1, d_zero),
- NodeManager::currentNM()->mkNode( kind::GEQ, NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s), b1 ) );
- Node s1 = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, d_zero, b1));
- Node s2 = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, b1, NodeManager::currentNM()->mkNode(kind::MINUS, lens, b1)));
- Node s1r1 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s1, r[0]).negate();
- if(r[0].getKind() == kind::STRING_TO_REGEXP) {
- s1r1 = s1.eqNode(r[0][0]).negate();
- } else if(r[0].getKind() == kind::REGEXP_EMPTY) {
- s1r1 = d_true;
- }
- Node r2 = r[1];
- if(r.getNumChildren() > 2) {
- std::vector< Node > nvec;
- for(unsigned i=1; i<r.getNumChildren(); i++) {
- nvec.push_back( r[i] );
- }
- r2 = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, nvec);
- }
- r2 = Rewriter::rewrite(r2);
- Node s2r2 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s2, r2).negate();
- if(r2.getKind() == kind::STRING_TO_REGEXP) {
- s2r2 = s2.eqNode(r2[0]).negate();
- } else if(r2.getKind() == kind::REGEXP_EMPTY) {
- s2r2 = d_true;
- }
-
- conc = NodeManager::currentNM()->mkNode(kind::OR, s1r1, s2r2);
- conc = NodeManager::currentNM()->mkNode(kind::IMPLIES, g1, conc);
- conc = NodeManager::currentNM()->mkNode(kind::FORALL, b1v, conc);
- break;
- }
- case kind::REGEXP_UNION: {
- std::vector< Node > c_and;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(r[i].getKind() == kind::STRING_TO_REGEXP) {
- c_and.push_back( r[i][0].eqNode(s).negate() );
- } else if(r[i].getKind() == kind::REGEXP_EMPTY) {
- continue;
- } else {
- c_and.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]).negate());
- }
- }
- conc = c_and.size() == 0 ? d_true :
- c_and.size() == 1 ? c_and[0] : NodeManager::currentNM()->mkNode(kind::AND, c_and);
- break;
- }
- case kind::REGEXP_INTER: {
- bool emptyflag = false;
- std::vector< Node > c_or;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(r[i].getKind() == kind::STRING_TO_REGEXP) {
- c_or.push_back( r[i][0].eqNode(s).negate() );
- } else if(r[i].getKind() == kind::REGEXP_EMPTY) {
- emptyflag = true;
- break;
- } else {
- c_or.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]).negate());
- }
- }
- if(emptyflag) {
- conc = d_true;
- } else {
- conc = c_or.size() == 1 ? c_or[0] : NodeManager::currentNM()->mkNode(kind::OR, c_or);
- }
- break;
- }
- case kind::REGEXP_STAR: {
- if(s == d_emptyString) {
- conc = d_false;
- } else if(r[0].getKind() == kind::REGEXP_EMPTY) {
- conc = s.eqNode(d_emptyString).negate();
- } else if(r[0].getKind() == kind::REGEXP_SIGMA) {
- conc = d_false;
- } else {
- Node lens = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s);
- Node sne = s.eqNode(d_emptyString).negate();
- Node b1 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());
- Node b1v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b1);
- Node g1 = NodeManager::currentNM()->mkNode( kind::AND, NodeManager::currentNM()->mkNode(kind::GEQ, b1, d_one),
- NodeManager::currentNM()->mkNode( kind::GEQ, lens, b1 ) );
- //internal
- Node s1 = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, d_zero, b1);
- Node s2 = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, b1, NodeManager::currentNM()->mkNode(kind::MINUS, lens, b1));
- Node s1r1 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s1, r[0]).negate();
- Node s2r2 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s2, r).negate();
-
- conc = NodeManager::currentNM()->mkNode(kind::OR, s1r1, s2r2);
- conc = NodeManager::currentNM()->mkNode(kind::IMPLIES, g1, conc);
- conc = NodeManager::currentNM()->mkNode(kind::FORALL, b1v, conc);
- conc = NodeManager::currentNM()->mkNode(kind::AND, sne, conc);
- }
- break;
- }
- default: {
- Trace("strings-regexp") << "Unsupported term: " << r << " in simplifyNRegExp." << std::endl;
- Assert( false, "Unsupported Term" );
- }
- }
- conc = Rewriter::rewrite( conc );
- new_nodes.push_back( conc );
- d_simpl_neg_cache[p] = conc;
- }
-}
-void RegExpOpr::simplifyPRegExp( Node s, Node r, std::vector< Node > &new_nodes ) {
- std::pair < Node, Node > p(s, r);
- std::map < std::pair< Node, Node >, Node >::const_iterator itr = d_simpl_cache.find(p);
- if(itr != d_simpl_cache.end()) {
- new_nodes.push_back( itr->second );
- } else {
- int k = r.getKind();
- Node conc;
- switch( k ) {
- case kind::REGEXP_EMPTY: {
- conc = d_false;
- break;
- }
- case kind::REGEXP_SIGMA: {
- conc = d_one.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s));
- break;
- }
- case kind::STRING_TO_REGEXP: {
- conc = s.eqNode(r[0]);
- break;
- }
- case kind::REGEXP_CONCAT: {
- std::vector< Node > nvec;
- std::vector< Node > cc;
- bool emptyflag = false;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(r[i].getKind() == kind::STRING_TO_REGEXP) {
- cc.push_back( r[i][0] );
- } else if(r[i].getKind() == kind::REGEXP_EMPTY) {
- emptyflag = true;
- break;
- } else {
- Node sk = NodeManager::currentNM()->mkSkolem( "rc", s.getType(), "created for regular expression concat" );
- Node lem = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, sk, r[i]);
- nvec.push_back(lem);
- cc.push_back(sk);
- }
- }
- if(emptyflag) {
- conc = d_false;
- } else {
- Node lem = s.eqNode( NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, cc) );
- nvec.push_back(lem);
- conc = nvec.size() == 1 ? nvec[0] : NodeManager::currentNM()->mkNode(kind::AND, nvec);
- }
- break;
- }
- case kind::REGEXP_UNION: {
- std::vector< Node > c_or;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(r[i].getKind() == kind::STRING_TO_REGEXP) {
- c_or.push_back( r[i][0].eqNode(s) );
- } else if(r[i].getKind() == kind::REGEXP_EMPTY) {
- continue;
- } else {
- c_or.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]));
- }
- }
- conc = c_or.size() == 0 ? d_false :
- c_or.size() == 1 ? c_or[0] : NodeManager::currentNM()->mkNode(kind::OR, c_or);
- break;
- }
- case kind::REGEXP_INTER: {
- std::vector< Node > c_and;
- bool emptyflag = false;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(r[i].getKind() == kind::STRING_TO_REGEXP) {
- c_and.push_back( r[i][0].eqNode(s) );
- } else if(r[i].getKind() == kind::REGEXP_EMPTY) {
- emptyflag = true;
- break;
- } else {
- c_and.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]));
- }
- }
- if(emptyflag) {
- conc = d_false;
- } else {
- conc = c_and.size() == 1 ? c_and[0] : NodeManager::currentNM()->mkNode(kind::AND, c_and);
- }
- break;
- }
- case kind::REGEXP_STAR: {
- if(s == d_emptyString) {
- conc = d_true;
- } else if(r[0].getKind() == kind::REGEXP_EMPTY) {
- conc = s.eqNode(d_emptyString);
- } else if(r[0].getKind() == kind::REGEXP_SIGMA) {
- conc = d_true;
- } else {
- Node se = s.eqNode(d_emptyString);
- Node sinr = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[0]);
- Node sk1 = NodeManager::currentNM()->mkSkolem( "rs", s.getType(), "created for regular expression star" );
- Node sk2 = NodeManager::currentNM()->mkSkolem( "rs", s.getType(), "created for regular expression star" );
- Node s1nz = sk1.eqNode(d_emptyString).negate();
- Node s2nz = sk2.eqNode(d_emptyString).negate();
- Node s1inr = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, sk1, r[0]);
- Node s2inrs = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, sk2, r);
- Node s12 = s.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, sk1, sk2));
-
- conc = NodeManager::currentNM()->mkNode(kind::AND, s12, s1nz, s2nz, s1inr, s2inrs);
- conc = NodeManager::currentNM()->mkNode(kind::OR, se, sinr, conc);
- }
- break;
- }
- default: {
- Trace("strings-regexp") << "Unsupported term: " << r << " in simplifyPRegExp." << std::endl;
- Assert( false, "Unsupported Term" );
- }
- }
- conc = Rewriter::rewrite( conc );
- new_nodes.push_back( conc );
- d_simpl_cache[p] = conc;
- }
-}
-
-void RegExpOpr::getCharSet( Node r, std::set<unsigned> &pcset, SetNodes &pvset ) {
- std::map< Node, std::pair< std::set<unsigned>, SetNodes > >::const_iterator itr = d_cset_cache.find(r);
- if(itr != d_cset_cache.end()) {
- pcset.insert((itr->second).first.begin(), (itr->second).first.end());
- pvset.insert((itr->second).second.begin(), (itr->second).second.end());
- } else {
- std::set<unsigned> cset;
- SetNodes vset;
- int k = r.getKind();
- switch( k ) {
- case kind::REGEXP_EMPTY: {
- break;
- }
- case kind::REGEXP_SIGMA: {
- for(unsigned i=0; i<d_card; i++) {
- cset.insert(i);
- }
- break;
- }
- case kind::STRING_TO_REGEXP: {
- Node st = Rewriter::rewrite(r[0]);
- if(st.isConst()) {
- CVC4::String s = st.getConst< CVC4::String >();
- s.getCharSet( cset );
- } else if(st.getKind() == kind::VARIABLE) {
- vset.insert( st );
- } else {
- for(unsigned i=0; i<st.getNumChildren(); i++) {
- if(st[i].isConst()) {
- CVC4::String s = st[i].getConst< CVC4::String >();
- s.getCharSet( cset );
- } else {
- vset.insert( st[i] );
- }
- }
- }
- break;
- }
- case kind::REGEXP_CONCAT: {
- for(unsigned i=0; i<r.getNumChildren(); i++) {
- getCharSet(r[i], cset, vset);
- }
- break;
- }
- case kind::REGEXP_UNION: {
- for(unsigned i=0; i<r.getNumChildren(); i++) {
- getCharSet(r[i], cset, vset);
- }
- break;
- }
- case kind::REGEXP_INTER: {
- //TODO: Overapproximation for now
- for(unsigned i=0; i<r.getNumChildren(); i++) {
- getCharSet(r[i], cset, vset);
- }
- break;
- }
- case kind::REGEXP_STAR: {
- getCharSet(r[0], cset, vset);
- break;
- }
- default: {
- Trace("strings-regexp") << "Unsupported term: " << r << " in getCharSet." << std::endl;
- Assert( false, "Unsupported Term" );
- }
- }
- pcset.insert(cset.begin(), cset.end());
- pvset.insert(vset.begin(), vset.end());
- std::pair< std::set<unsigned>, SetNodes > p(cset, vset);
- d_cset_cache[r] = p;
-
- Trace("regexp-cset") << "CSET( " << mkString(r) << " ) = { ";
- for(std::set<unsigned>::const_iterator itr = cset.begin();
- itr != cset.end(); itr++) {
- Trace("regexp-cset") << CVC4::String::convertUnsignedIntToChar(*itr) << ",";
- }
- Trace("regexp-cset") << " }" << std::endl;
- }
-}
-
+/*! \file regexp_operation.cpp + ** \verbatim + ** Original author: Tianyi Liang + ** Major contributors: none + ** 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 Symbolic Regular Expresion Operations + ** + ** Symbolic Regular Expresion Operations + **/ -Node RegExpOpr::intersectInternal( Node r1, Node r2, std::map< unsigned, std::set< PairNodes > > cache, bool &spflag ) {
- if(spflag) {
- //TODO: var
- return Node::null();
- }
- std::pair < Node, Node > p(r1, r2);
- std::map < std::pair< Node, Node >, Node >::const_iterator itr = d_inter_cache.find(p);
- Node rNode;
- if(itr != d_inter_cache.end()) {
- rNode = itr->second;
- } else {
- if(r1 == r2) {
- rNode = r1;
- } else if(r1 == d_emptyRegexp || r2 == d_emptyRegexp) {
- rNode = d_emptyRegexp;
- } else if(r1 == d_emptySingleton || r2 == d_emptySingleton) {
- Node exp;
- int r = delta((r1 == d_emptySingleton ? r2 : r1), exp);
- if(r == 0) {
- //TODO: variable
- spflag = true;
- } else if(r == 1) {
- rNode = d_emptySingleton;
- } else {
- rNode = d_emptyRegexp;
- }
- } else {
- std::set< unsigned > cset, cset2;
- std::set< Node > vset, vset2;
- getCharSet(r1, cset, vset);
- getCharSet(r2, cset2, vset2);
- if(vset.empty() && vset2.empty()) {
- cset.clear();
- firstChars(r1, cset, vset);
- std::vector< Node > vec_nodes;
- for(std::set<unsigned>::const_iterator itr = cset.begin();
- itr != cset.end(); itr++) {
- CVC4::String c( CVC4::String::convertUnsignedIntToChar(*itr) );
- std::pair< Node, Node > p(r1, r2);
- if(cache[ *itr ].find(p) == cache[ *itr ].end()) {
- Node r1l = derivativeSingle(r1, c);
- Node r2l = derivativeSingle(r2, c);
- std::map< unsigned, std::set< PairNodes > > cache2(cache);
- PairNodes p(r1l, r2l);
- cache2[ *itr ].insert( p );
- Node rt = intersectInternal(r1l, r2l, cache2, spflag);
- if(spflag) {
- //TODO:
- return Node::null();
- }
- rt = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT,
- NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(c)), rt) );
- vec_nodes.push_back(rt);
- }
- }
- rNode = vec_nodes.size()==0 ? d_emptyRegexp : vec_nodes.size()==1 ? vec_nodes[0] :
- NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vec_nodes);
- rNode = Rewriter::rewrite( rNode );
- } else {
- //TODO: non-empty var set
- spflag = true;
- }
- }
- d_inter_cache[p] = rNode;
- }
- Trace("regexp-intersect") << "INTERSECT( " << mkString(r1) << ", " << mkString(r2) << " ) = " << mkString(rNode) << std::endl;
- return rNode;
-}
-Node RegExpOpr::intersect(Node r1, Node r2, bool &spflag) {
- std::map< unsigned, std::set< PairNodes > > cache;
- if(checkConstRegExp(r1) && checkConstRegExp(r2)) {
- return intersectInternal(r1, r2, cache, spflag);
- } else {
- spflag = true;
- return Node::null();
- }
-}
-
-Node RegExpOpr::complement(Node r, int &ret) {
- Node rNode;
- ret = 1;
- if(d_compl_cache.find(r) != d_compl_cache.end()) {
- rNode = d_compl_cache[r].first;
- ret = d_compl_cache[r].second;
- } else {
- if(r == d_emptyRegexp) {
- rNode = d_sigma_star;
- } else if(r == d_emptySingleton) {
- rNode = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, d_sigma, d_sigma_star);
- } else if(!checkConstRegExp(r)) {
- //TODO: var to be extended
- ret = 0;
- } else {
- std::set<unsigned> cset;
- SetNodes vset;
- firstChars(r, cset, vset);
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<d_card; i++) {
- CVC4::String c = CVC4::String::convertUnsignedIntToChar(i);
- Node n = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(c));
- Node r2;
- if(cset.find(i) == cset.end()) {
- r2 = d_sigma_star;
- } else {
- int rt;
- derivativeS(r, c, r2);
- if(r2 == r) {
- r2 = d_emptyRegexp;
- } else {
- r2 = complement(r2, rt);
- }
- }
- n = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, n, r2));
- vec_nodes.push_back(n);
- }
- rNode = vec_nodes.size()==0? d_emptyRegexp : vec_nodes.size()==1? vec_nodes[0] :
- NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vec_nodes);
- }
- rNode = Rewriter::rewrite(rNode);
- std::pair< Node, int > p(rNode, ret);
- d_compl_cache[r] = p;
- }
- Trace("regexp-compl") << "COMPL( " << mkString(r) << " ) = " << mkString(rNode) << ", ret=" << ret << std::endl;
- return rNode;
-}
-
-void RegExpOpr::splitRegExp(Node r, std::vector< PairNodes > &pset) {
- Assert(checkConstRegExp(r));
- if(d_split_cache.find(r) != d_split_cache.end()) {
- pset = d_split_cache[r];
- } else {
- switch( r.getKind() ) {
- case kind::REGEXP_EMPTY: {
- break;
- }
- case kind::REGEXP_OPT: {
- PairNodes tmp(d_emptySingleton, d_emptySingleton);
- pset.push_back(tmp);
- }
- case kind::REGEXP_RANGE:
- case kind::REGEXP_SIGMA: {
- PairNodes tmp1(d_emptySingleton, r);
- PairNodes tmp2(r, d_emptySingleton);
- pset.push_back(tmp1);
- pset.push_back(tmp2);
- break;
- }
- case kind::STRING_TO_REGEXP: {
- Assert(r[0].isConst());
- CVC4::String s = r[0].getConst< CVC4::String >();
- PairNodes tmp1(d_emptySingleton, r);
- pset.push_back(tmp1);
- for(unsigned i=1; i<s.size(); i++) {
- CVC4::String s1 = s.substr(0, i);
- CVC4::String s2 = s.substr(i);
- Node n1 = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(s1));
- Node n2 = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(s2));
- PairNodes tmp3(n1, n2);
- pset.push_back(tmp3);
- }
- PairNodes tmp2(r, d_emptySingleton);
- pset.push_back(tmp2);
- break;
- }
- case kind::REGEXP_CONCAT: {
- for(unsigned i=0; i<r.getNumChildren(); i++) {
- std::vector< PairNodes > tset;
- splitRegExp(r[i], tset);
- std::vector< Node > hvec;
- std::vector< Node > tvec;
- for(unsigned j=0; j<=i; j++) {
- hvec.push_back(r[j]);
- }
- for(unsigned j=i; j<r.getNumChildren(); j++) {
- tvec.push_back(r[j]);
- }
- for(unsigned j=0; j<tset.size(); j++) {
- hvec[i] = tset[j].first;
- tvec[0] = tset[j].second;
- Node r1 = Rewriter::rewrite( hvec.size()==1?hvec[0]:NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, hvec) );
- Node r2 = Rewriter::rewrite( tvec.size()==1?tvec[0]:NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, tvec) );
- PairNodes tmp2(r1, r2);
- pset.push_back(tmp2);
- }
- }
- break;
- }
- case kind::REGEXP_UNION: {
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- std::vector< PairNodes > tset;
- splitRegExp(r[i], tset);
- pset.insert(pset.end(), tset.begin(), tset.end());
- }
- break;
- }
- case kind::REGEXP_INTER: {
- bool spflag = false;
- Node tmp = r[0];
- for(unsigned i=1; i<r.getNumChildren(); i++) {
- tmp = intersect(tmp, r[i], spflag);
- }
- splitRegExp(tmp, pset);
- break;
- }
- case kind::REGEXP_STAR: {
- std::vector< PairNodes > tset;
- splitRegExp(r[0], tset);
- PairNodes tmp1(d_emptySingleton, d_emptySingleton);
- pset.push_back(tmp1);
- for(unsigned i=0; i<tset.size(); i++) {
- Node r1 = tset[i].first==d_emptySingleton ? r : NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, r, tset[i].first);
- Node r2 = tset[i].second==d_emptySingleton ? r : NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, tset[i].second, r);
- PairNodes tmp2(r1, r2);
- pset.push_back(tmp2);
- }
- break;
- }
- case kind::REGEXP_PLUS: {
- std::vector< PairNodes > tset;
- splitRegExp(r[0], tset);
- for(unsigned i=0; i<tset.size(); i++) {
- Node r1 = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, r, tset[i].first);
- Node r2 = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, tset[i].second, r);
- PairNodes tmp2(r1, r2);
- pset.push_back(tmp2);
- }
- break;
- }
- default: {
- Trace("strings-error") << "Unsupported term: " << r << " in splitRegExp." << std::endl;
- Assert( false );
- //return Node::null();
- }
- }
- d_split_cache[r] = pset;
- }
-}
-
-//printing
-std::string RegExpOpr::niceChar( Node r ) {
- if(r.isConst()) {
- std::string s = r.getConst<CVC4::String>().toString() ;
- return s == "" ? "{E}" : ( s == " " ? "{ }" : s.size()>1? "("+s+")" : s );
- } else {
- std::string ss = "$" + r.toString();
- return ss;
- }
-}
-std::string RegExpOpr::mkString( Node r ) {
- std::string retStr;
- if(r.isNull()) {
- retStr = "Empty";
- } else {
- int k = r.getKind();
- switch( k ) {
- case kind::REGEXP_EMPTY: {
- retStr += "Empty";
- break;
- }
- case kind::REGEXP_SIGMA: {
- retStr += "{W}";
- break;
- }
- case kind::STRING_TO_REGEXP: {
- retStr += niceChar( r[0] );
- break;
- }
- case kind::REGEXP_CONCAT: {
- retStr += "(";
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- //if(i != 0) retStr += ".";
- retStr += mkString( r[i] );
- }
- retStr += ")";
- break;
- }
- case kind::REGEXP_UNION: {
- if(r == d_sigma) {
- retStr += "{A}";
- } else {
- retStr += "(";
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(i != 0) retStr += "|";
- retStr += mkString( r[i] );
- }
- retStr += ")";
- }
- break;
- }
- case kind::REGEXP_INTER: {
- retStr += "(";
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(i != 0) retStr += "&";
- retStr += mkString( r[i] );
- }
- retStr += ")";
- break;
- }
- case kind::REGEXP_STAR: {
- retStr += mkString( r[0] );
- retStr += "*";
- break;
- }
- case kind::REGEXP_PLUS: {
- retStr += mkString( r[0] );
- retStr += "+";
- break;
- }
- case kind::REGEXP_OPT: {
- retStr += mkString( r[0] );
- retStr += "?";
- break;
- }
- case kind::REGEXP_RANGE: {
- retStr += "[";
- retStr += niceChar( r[0] );
- retStr += "-";
- retStr += niceChar( r[1] );
- retStr += "]";
- break;
- }
- default:
- Trace("strings-error") << "Unsupported term: " << r << " in RegExp." << std::endl;
- //Assert( false );
- //return Node::null();
- }
- }
-
- return retStr;
-}
-
-}/* CVC4::theory::strings namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
+#include "theory/strings/regexp_operation.h" +#include "expr/kind.h" + +namespace CVC4 { +namespace theory { +namespace strings { + +RegExpOpr::RegExpOpr() { + d_emptyString = NodeManager::currentNM()->mkConst( ::CVC4::String("") ); + d_true = NodeManager::currentNM()->mkConst( true ); + d_false = NodeManager::currentNM()->mkConst( false ); + d_zero = NodeManager::currentNM()->mkConst( ::CVC4::Rational(0) ); + d_one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) ); + d_emptySingleton = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString ); + std::vector< Node > nvec; + d_emptyRegexp = NodeManager::currentNM()->mkNode( kind::REGEXP_EMPTY, nvec ); + d_sigma = NodeManager::currentNM()->mkNode( kind::REGEXP_SIGMA, nvec ); + d_sigma_star = NodeManager::currentNM()->mkNode( kind::REGEXP_STAR, d_sigma ); + d_card = 256; +} + +int RegExpOpr::gcd ( int a, int b ) { + int c; + while ( a != 0 ) { + c = a; a = b%a; b = c; + } + return b; +} + +bool RegExpOpr::checkConstRegExp( Node r ) { + Trace("strings-regexp-cstre") << "RegExp-CheckConstRegExp starts with " << mkString( r ) << std::endl; + bool ret = true; + if( d_cstre_cache.find( r ) != d_cstre_cache.end() ) { + ret = d_cstre_cache[r]; + } else { + if(r.getKind() == kind::STRING_TO_REGEXP) { + Node tmp = Rewriter::rewrite( r[0] ); + ret = tmp.isConst(); + } else { + for(unsigned i=0; i<r.getNumChildren(); ++i) { + if(!checkConstRegExp(r[i])) { + ret = false; break; + } + } + } + d_cstre_cache[r] = ret; + } + return ret; +} + +// 0-unknown, 1-yes, 2-no +int RegExpOpr::delta( Node r, Node &exp ) { + Trace("regexp-delta") << "RegExp-Delta starts with " << mkString( r ) << std::endl; + int ret = 0; + if( d_delta_cache.find( r ) != d_delta_cache.end() ) { + ret = d_delta_cache[r].first; + exp = d_delta_cache[r].second; + } else { + int k = r.getKind(); + switch( k ) { + case kind::REGEXP_EMPTY: { + ret = 2; + break; + } + case kind::REGEXP_SIGMA: { + ret = 2; + break; + } + case kind::STRING_TO_REGEXP: { + Node tmp = Rewriter::rewrite(r[0]); + if(tmp.isConst()) { + if(tmp == d_emptyString) { + ret = 1; + } else { + ret = 2; + } + } else { + ret = 0; + if(tmp.getKind() == kind::STRING_CONCAT) { + for(unsigned i=0; i<tmp.getNumChildren(); i++) { + if(tmp[i].isConst()) { + ret = 2; break; + } + } + + } + if(ret == 0) { + exp = r[0].eqNode(d_emptyString); + } + } + break; + } + case kind::REGEXP_CONCAT: { + bool flag = false; + std::vector< Node > vec_nodes; + for(unsigned i=0; i<r.getNumChildren(); ++i) { + Node exp2; + int tmp = delta( r[i], exp2 ); + if(tmp == 2) { + ret = 2; + break; + } else if(tmp == 0) { + vec_nodes.push_back( exp2 ); + flag = true; + } + } + if(ret != 2) { + if(!flag) { + ret = 1; + } else { + exp = vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode(kind::AND, vec_nodes); + } + } + break; + } + case kind::REGEXP_UNION: { + bool flag = false; + std::vector< Node > vec_nodes; + for(unsigned i=0; i<r.getNumChildren(); ++i) { + Node exp2; + int tmp = delta( r[i], exp2 ); + if(tmp == 1) { + ret = 1; + break; + } else if(tmp == 0) { + vec_nodes.push_back( exp2 ); + flag = true; + } + } + if(ret != 1) { + if(!flag) { + ret = 2; + } else { + exp = vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode(kind::OR, vec_nodes); + } + } + break; + } + case kind::REGEXP_INTER: { + bool flag = false; + std::vector< Node > vec_nodes; + for(unsigned i=0; i<r.getNumChildren(); ++i) { + Node exp2; + int tmp = delta( r[i], exp2 ); + if(tmp == 2) { + ret = 2; + break; + } else if(tmp == 0) { + vec_nodes.push_back( exp2 ); + flag = true; + } + } + if(ret != 2) { + if(!flag) { + ret = 1; + } else { + exp = vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode(kind::AND, vec_nodes); + } + } + break; + } + case kind::REGEXP_STAR: { + ret = 1; + break; + } + case kind::REGEXP_PLUS: { + ret = delta( r[0], exp ); + break; + } + case kind::REGEXP_OPT: { + ret = 1; + break; + } + case kind::REGEXP_RANGE: { + ret = 2; + break; + } + default: { + Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in delta of RegExp." << std::endl; + Assert( false ); + //return Node::null(); + } + } + if(!exp.isNull()) { + exp = Rewriter::rewrite(exp); + } + std::pair< int, Node > p(ret, exp); + d_delta_cache[r] = p; + } + Trace("regexp-delta") << "RegExp-Delta returns : " << ret << std::endl; + return ret; +} + +// 0-unknown, 1-yes, 2-no +int RegExpOpr::derivativeS( Node r, CVC4::String c, Node &retNode ) { + Assert( c.size() < 2 ); + Trace("regexp-derive") << "RegExp-derive starts with R{ " << mkString( r ) << " }, c=" << c << std::endl; + + int ret = 1; + retNode = d_emptyRegexp; + + PairNodeStr dv = std::make_pair( r, c ); + if( d_deriv_cache.find( dv ) != d_deriv_cache.end() ) { + retNode = d_deriv_cache[dv].first; + ret = d_deriv_cache[dv].second; + } else if( c.isEmptyString() ) { + Node expNode; + ret = delta( r, expNode ); + if(ret == 0) { + retNode = NodeManager::currentNM()->mkNode(kind::ITE, expNode, r, d_emptyRegexp); + } else if(ret == 1) { + retNode = r; + } + std::pair< Node, int > p(retNode, ret); + d_deriv_cache[dv] = p; + } else { + switch( r.getKind() ) { + case kind::REGEXP_EMPTY: { + ret = 2; + break; + } + case kind::REGEXP_SIGMA: { + retNode = d_emptySingleton; + break; + } + case kind::STRING_TO_REGEXP: { + Node tmp = Rewriter::rewrite(r[0]); + if(tmp.isConst()) { + if(tmp == d_emptyString) { + ret = 2; + } else { + if(tmp.getConst< CVC4::String >().getFirstChar() == c.getFirstChar()) { + retNode = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, + tmp.getConst< CVC4::String >().size() == 1 ? d_emptyString : NodeManager::currentNM()->mkConst( tmp.getConst< CVC4::String >().substr(1) ) ); + } else { + ret = 2; + } + } + } else { + ret = 0; + Node rest; + if(tmp.getKind() == kind::STRING_CONCAT) { + Node t2 = tmp[0]; + if(t2.isConst()) { + if(t2.getConst< CVC4::String >().getFirstChar() == c.getFirstChar()) { + Node n = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, + tmp.getConst< CVC4::String >().size() == 1 ? d_emptyString : NodeManager::currentNM()->mkConst( tmp.getConst< CVC4::String >().substr(1) ) ); + std::vector< Node > vec_nodes; + vec_nodes.push_back(n); + for(unsigned i=1; i<tmp.getNumChildren(); i++) { + vec_nodes.push_back(tmp[i]); + } + retNode = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vec_nodes); + ret = 1; + } else { + ret = 2; + } + } else { + tmp = tmp[0]; + std::vector< Node > vec_nodes; + for(unsigned i=1; i<tmp.getNumChildren(); i++) { + vec_nodes.push_back(tmp[i]); + } + rest = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vec_nodes); + } + } + if(ret == 0) { + Node sk = NodeManager::currentNM()->mkSkolem( "rsp", NodeManager::currentNM()->stringType(), "Split RegExp" ); + retNode = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, sk); + if(!rest.isNull()) { + retNode = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, retNode, rest)); + } + Node exp = tmp.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, + NodeManager::currentNM()->mkConst(c), sk)); + retNode = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::ITE, exp, retNode, d_emptyRegexp)); + } + } + break; + } + case kind::REGEXP_CONCAT: { + std::vector< Node > vec_nodes; + std::vector< Node > delta_nodes; + Node dnode = d_true; + for(unsigned i=0; i<r.getNumChildren(); ++i) { + Node dc; + Node exp2; + int rt = derivativeS(r[i], c, dc); + if(rt != 2) { + if(rt == 0) { + ret = 0; + } + std::vector< Node > vec_nodes2; + if(dc != d_emptySingleton) { + vec_nodes2.push_back( dc ); + } + for(unsigned j=i+1; j<r.getNumChildren(); ++j) { + if(r[j] != d_emptySingleton) { + vec_nodes2.push_back( r[j] ); + } + } + Node tmp = vec_nodes2.size()==0 ? d_emptySingleton : + vec_nodes2.size()==1 ? vec_nodes2[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, vec_nodes2 ); + if(dnode != d_true) { + tmp = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::ITE, dnode, tmp, d_emptyRegexp)); + ret = 0; + } + if(std::find(vec_nodes.begin(), vec_nodes.end(), tmp) == vec_nodes.end()) { + vec_nodes.push_back( tmp ); + } + } + Node exp3; + int rt2 = delta( r[i], exp3 ); + if( rt2 == 0 ) { + dnode = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND, dnode, exp3)); + } else if( rt2 == 2 ) { + break; + } + } + retNode = vec_nodes.size() == 0 ? d_emptyRegexp : + ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) ); + if(retNode == d_emptyRegexp) { + ret = 2; + } + break; + } + case kind::REGEXP_UNION: { + std::vector< Node > vec_nodes; + for(unsigned i=0; i<r.getNumChildren(); ++i) { + Node dc; + int rt = derivativeS(r[i], c, dc); + if(rt == 0) { + ret = 0; + } + if(rt != 2) { + if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) { + vec_nodes.push_back( dc ); + } + } + Trace("regexp-derive") << "RegExp-derive OR R[" << i << "]{ " << mkString(r[i]) << " returns " << mkString(dc) << std::endl; + } + retNode = vec_nodes.size() == 0 ? d_emptyRegexp : + ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) ); + if(retNode == d_emptyRegexp) { + ret = 2; + } + break; + } + case kind::REGEXP_INTER: { + bool flag = true; + bool flag_sg = false; + std::vector< Node > vec_nodes; + for(unsigned i=0; i<r.getNumChildren(); ++i) { + Node dc; + int rt = derivativeS(r[i], c, dc); + if(rt == 0) { + ret = 0; + } else if(rt == 2) { + flag = false; + break; + } + if(dc == d_sigma_star) { + flag_sg = true; + } else { + if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) { + vec_nodes.push_back( dc ); + } + } + } + if(flag) { + if(vec_nodes.size() == 0 && flag_sg) { + retNode = d_sigma_star; + } else { + retNode = vec_nodes.size() == 0 ? d_emptyRegexp : + ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_INTER, vec_nodes ) ); + if(retNode == d_emptyRegexp) { + ret = 2; + } + } + } else { + retNode = d_emptyRegexp; + ret = 2; + } + break; + } + case kind::REGEXP_STAR: { + Node dc; + ret = derivativeS(r[0], c, dc); + retNode = dc==d_emptyRegexp ? dc : (dc==d_emptySingleton ? r : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, dc, r )); + break; + } + default: { + Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in derivative of RegExp." << std::endl; + Assert( false, "Unsupported Term" ); + } + } + if(retNode != d_emptyRegexp) { + retNode = Rewriter::rewrite( retNode ); + } + std::pair< Node, int > p(retNode, ret); + d_deriv_cache[dv] = p; + } + + Trace("regexp-derive") << "RegExp-derive returns : " << mkString( retNode ) << std::endl; + return ret; +} + +Node RegExpOpr::derivativeSingle( Node r, CVC4::String c ) { + Assert( c.size() < 2 ); + Trace("regexp-derive") << "RegExp-derive starts with R{ " << mkString( r ) << " }, c=" << c << std::endl; + Node retNode = d_emptyRegexp; + PairNodeStr dv = std::make_pair( r, c ); + if( d_dv_cache.find( dv ) != d_dv_cache.end() ) { + retNode = d_dv_cache[dv]; + } else if( c.isEmptyString() ){ + Node exp; + int tmp = delta( r, exp ); + if(tmp == 0) { + // TODO variable + retNode = d_emptyRegexp; + } else if(tmp == 1) { + retNode = r; + } else { + retNode = d_emptyRegexp; + } + } else { + int k = r.getKind(); + switch( k ) { + case kind::REGEXP_EMPTY: { + retNode = d_emptyRegexp; + break; + } + case kind::REGEXP_SIGMA: { + retNode = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString ); + break; + } + case kind::STRING_TO_REGEXP: { + if(r[0].isConst()) { + if(r[0] == d_emptyString) { + retNode = d_emptyRegexp; + } else { + if(r[0].getConst< CVC4::String >().getFirstChar() == c.getFirstChar()) { + retNode = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, + r[0].getConst< CVC4::String >().size() == 1 ? d_emptyString : NodeManager::currentNM()->mkConst( r[0].getConst< CVC4::String >().substr(1) ) ); + } else { + retNode = d_emptyRegexp; + } + } + } else { + // TODO variable + retNode = d_emptyRegexp; + } + break; + } + case kind::REGEXP_CONCAT: { + Node rees = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString ); + std::vector< Node > vec_nodes; + for(unsigned i=0; i<r.getNumChildren(); ++i) { + Node dc = derivativeSingle(r[i], c); + if(dc != d_emptyRegexp) { + std::vector< Node > vec_nodes2; + if(dc != rees) { + vec_nodes2.push_back( dc ); + } + for(unsigned j=i+1; j<r.getNumChildren(); ++j) { + if(r[j] != rees) { + vec_nodes2.push_back( r[j] ); + } + } + Node tmp = vec_nodes2.size()==0 ? rees : + vec_nodes2.size()==1 ? vec_nodes2[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, vec_nodes2 ); + if(std::find(vec_nodes.begin(), vec_nodes.end(), tmp) == vec_nodes.end()) { + vec_nodes.push_back( tmp ); + } + } + Node exp; + if( delta( r[i], exp ) != 1 ) { + break; + } + } + retNode = vec_nodes.size() == 0 ? d_emptyRegexp : + ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) ); + break; + } + case kind::REGEXP_UNION: { + std::vector< Node > vec_nodes; + for(unsigned i=0; i<r.getNumChildren(); ++i) { + Node dc = derivativeSingle(r[i], c); + if(dc != d_emptyRegexp) { + if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) { + vec_nodes.push_back( dc ); + } + } + Trace("regexp-derive") << "RegExp-derive OR R[" << i << "]{ " << mkString(r[i]) << " returns " << mkString(dc) << std::endl; + } + retNode = vec_nodes.size() == 0 ? d_emptyRegexp : + ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) ); + break; + } + case kind::REGEXP_INTER: { + bool flag = true; + bool flag_sg = false; + std::vector< Node > vec_nodes; + for(unsigned i=0; i<r.getNumChildren(); ++i) { + Node dc = derivativeSingle(r[i], c); + if(dc != d_emptyRegexp) { + if(dc == d_sigma_star) { + flag_sg = true; + } else { + if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) { + vec_nodes.push_back( dc ); + } + } + } else { + flag = false; + break; + } + } + if(flag) { + if(vec_nodes.size() == 0 && flag_sg) { + retNode = d_sigma_star; + } else { + retNode = vec_nodes.size() == 0 ? d_emptyRegexp : + ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_INTER, vec_nodes ) ); + } + } else { + retNode = d_emptyRegexp; + } + break; + } + case kind::REGEXP_STAR: { + Node dc = derivativeSingle(r[0], c); + if(dc != d_emptyRegexp) { + retNode = dc==NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString ) ? r : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, dc, r ); + } else { + retNode = d_emptyRegexp; + } + break; + } + default: { + //TODO: special sym: sigma, none, all + Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in derivative of RegExp." << std::endl; + Assert( false, "Unsupported Term" ); + //return Node::null(); + } + } + if(retNode != d_emptyRegexp) { + retNode = Rewriter::rewrite( retNode ); + } + d_dv_cache[dv] = retNode; + } + Trace("regexp-derive") << "RegExp-derive returns : " << mkString( retNode ) << std::endl; + return retNode; +} + +//TODO: +bool RegExpOpr::guessLength( Node r, int &co ) { + int k = r.getKind(); + switch( k ) { + case kind::STRING_TO_REGEXP: + { + if(r[0].isConst()) { + co += r[0].getConst< CVC4::String >().size(); + return true; + } else { + return false; + } + } + break; + case kind::REGEXP_CONCAT: + { + for(unsigned i=0; i<r.getNumChildren(); ++i) { + if(!guessLength( r[i], co)) { + return false; + } + } + return true; + } + break; + case kind::REGEXP_UNION: + { + int g_co; + for(unsigned i=0; i<r.getNumChildren(); ++i) { + int cop = 0; + if(!guessLength( r[i], cop)) { + return false; + } + if(i == 0) { + g_co = cop; + } else { + g_co = gcd(g_co, cop); + } + } + return true; + } + break; + case kind::REGEXP_INTER: + { + int g_co; + for(unsigned i=0; i<r.getNumChildren(); ++i) { + int cop = 0; + if(!guessLength( r[i], cop)) { + return false; + } + if(i == 0) { + g_co = cop; + } else { + g_co = gcd(g_co, cop); + } + } + return true; + } + break; + case kind::REGEXP_STAR: + { + co = 0; + return true; + } + break; + default: + Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in membership of RegExp." << std::endl; + return false; + } +} + +void RegExpOpr::firstChars( Node r, std::set<unsigned> &pcset, SetNodes &pvset ) { + std::map< Node, std::pair< std::set<unsigned>, SetNodes > >::const_iterator itr = d_fset_cache.find(r); + if(itr != d_fset_cache.end()) { + pcset.insert((itr->second).first.begin(), (itr->second).first.end()); + pvset.insert((itr->second).second.begin(), (itr->second).second.end()); + } else { + std::set<unsigned> cset; + SetNodes vset; + int k = r.getKind(); + switch( k ) { + case kind::REGEXP_EMPTY: { + break; + } + case kind::REGEXP_SIGMA: { + for(unsigned i=0; i<d_card; i++) { + cset.insert(i); + } + break; + } + case kind::STRING_TO_REGEXP: { + Node st = Rewriter::rewrite(r[0]); + if(st.isConst()) { + CVC4::String s = st.getConst< CVC4::String >(); + if(s.size() != 0) { + cset.insert(s[0]); + } + } else if(st.getKind() == kind::VARIABLE) { + vset.insert( st ); + } else { + if(st[0].isConst()) { + CVC4::String s = st[0].getConst< CVC4::String >(); + cset.insert(s[0]); + } else { + vset.insert( st[0] ); + } + } + break; + } + case kind::REGEXP_CONCAT: { + for(unsigned i=0; i<r.getNumChildren(); i++) { + firstChars(r[i], cset, vset); + Node n = r[i]; + Node exp; + int r = delta( n, exp ); + if(r != 1) { + break; + } + } + break; + } + case kind::REGEXP_UNION: { + for(unsigned i=0; i<r.getNumChildren(); i++) { + firstChars(r[i], cset, vset); + } + break; + } + case kind::REGEXP_INTER: { + //TODO: Overapproximation for now + for(unsigned i=0; i<r.getNumChildren(); i++) { + firstChars(r[i], cset, vset); + } + break; + } + case kind::REGEXP_STAR: { + firstChars(r[0], cset, vset); + break; + } + default: { + Trace("strings-regexp") << "Unsupported term: " << r << " in getCharSet." << std::endl; + Assert( false, "Unsupported Term" ); + } + } + pcset.insert(cset.begin(), cset.end()); + pvset.insert(vset.begin(), vset.end()); + std::pair< std::set<unsigned>, SetNodes > p(cset, vset); + d_fset_cache[r] = p; + + Trace("regexp-fset") << "FSET( " << mkString(r) << " ) = { "; + for(std::set<unsigned>::const_iterator itr = cset.begin(); + itr != cset.end(); itr++) { + Trace("regexp-fset") << CVC4::String::convertUnsignedIntToChar(*itr) << ","; + } + Trace("regexp-fset") << " }" << std::endl; + } +} + +bool RegExpOpr::follow( Node r, CVC4::String c, std::vector< char > &vec_chars ) { + int k = r.getKind(); + switch( k ) { + case kind::STRING_TO_REGEXP: + { + if(r[0].isConst()) { + if(r[0] != d_emptyString) { + char t1 = r[0].getConst< CVC4::String >().getFirstChar(); + if(c.isEmptyString()) { + vec_chars.push_back( t1 ); + return true; + } else { + char t2 = c.getFirstChar(); + if(t1 != t2) { + return false; + } else { + if(c.size() >= 2) { + vec_chars.push_back( c.substr(1,1).getFirstChar() ); + } else { + vec_chars.push_back( '\0' ); + } + return true; + } + } + } else { + return false; + } + } else { + return false; + } + } + break; + case kind::REGEXP_CONCAT: + { + for(unsigned i=0; i<r.getNumChildren(); ++i) { + if( follow(r[i], c, vec_chars) ) { + if(vec_chars[vec_chars.size() - 1] == '\0') { + vec_chars.pop_back(); + c = d_emptyString.getConst< CVC4::String >(); + } + } else { + return false; + } + } + vec_chars.push_back( '\0' ); + return true; + } + break; + case kind::REGEXP_UNION: + { + bool flag = false; + for(unsigned i=0; i<r.getNumChildren(); ++i) { + if( follow(r[i], c, vec_chars) ) { + flag=true; + } + } + return flag; + } + break; + case kind::REGEXP_INTER: + { + std::vector< char > vt2; + for(unsigned i=0; i<r.getNumChildren(); ++i) { + std::vector< char > v_tmp; + if( !follow(r[i], c, v_tmp) ) { + return false; + } + std::vector< char > vt3(vt2); + vt2.clear(); + std::set_intersection( vt3.begin(), vt3.end(), v_tmp.begin(), v_tmp.end(), vt2.begin() ); + if(vt2.size() == 0) { + return false; + } + } + vec_chars.insert( vec_chars.end(), vt2.begin(), vt2.end() ); + return true; + } + break; + case kind::REGEXP_STAR: + { + if(follow(r[0], c, vec_chars)) { + if(vec_chars[vec_chars.size() - 1] == '\0') { + if(c.isEmptyString()) { + return true; + } else { + vec_chars.pop_back(); + c = d_emptyString.getConst< CVC4::String >(); + return follow(r[0], c, vec_chars); + } + } else { + return true; + } + } else { + vec_chars.push_back( '\0' ); + return true; + } + } + break; + default: { + Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in delta of RegExp." << std::endl; + //AlwaysAssert( false ); + //return Node::null(); + return false; + } + } +} + +Node RegExpOpr::mkAllExceptOne( char exp_c ) { + std::vector< Node > vec_nodes; + for(char c=d_char_start; c<=d_char_end; ++c) { + if(c != exp_c ) { + Node n = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst( ::CVC4::String( c ) ) ); + vec_nodes.push_back( n ); + } + } + return NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ); +} + +//simplify +void RegExpOpr::simplify(Node t, std::vector< Node > &new_nodes, bool polarity) { + Trace("strings-regexp-simpl") << "RegExp-Simpl starts with " << t << ", polarity=" << polarity << std::endl; + Assert(t.getKind() == kind::STRING_IN_REGEXP); + Node str = Rewriter::rewrite(t[0]); + Node re = Rewriter::rewrite(t[1]); + if(polarity) { + simplifyPRegExp( str, re, new_nodes ); + } else { + simplifyNRegExp( str, re, new_nodes ); + } + Trace("strings-regexp-simpl") << "RegExp-Simpl returns (" << new_nodes.size() << "):\n"; + for(unsigned i=0; i<new_nodes.size(); i++) { + Trace("strings-regexp-simpl") << "\t" << new_nodes[i] << std::endl; + } +} +void RegExpOpr::simplifyNRegExp( Node s, Node r, std::vector< Node > &new_nodes ) { + std::pair < Node, Node > p(s, r); + std::map < std::pair< Node, Node >, Node >::const_iterator itr = d_simpl_neg_cache.find(p); + if(itr != d_simpl_neg_cache.end()) { + new_nodes.push_back( itr->second ); + } else { + int k = r.getKind(); + Node conc; + switch( k ) { + case kind::REGEXP_EMPTY: { + conc = d_true; + break; + } + case kind::REGEXP_SIGMA: { + conc = d_one.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s)).negate(); + break; + } + case kind::STRING_TO_REGEXP: { + conc = s.eqNode(r[0]).negate(); + break; + } + case kind::REGEXP_CONCAT: { + //TODO: rewrite empty + Node lens = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s); + Node b1 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType()); + Node b1v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b1); + Node g1 = NodeManager::currentNM()->mkNode( kind::AND, NodeManager::currentNM()->mkNode(kind::GEQ, b1, d_zero), + NodeManager::currentNM()->mkNode( kind::GEQ, NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s), b1 ) ); + Node s1 = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, d_zero, b1)); + Node s2 = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, b1, NodeManager::currentNM()->mkNode(kind::MINUS, lens, b1))); + Node s1r1 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s1, r[0]).negate(); + if(r[0].getKind() == kind::STRING_TO_REGEXP) { + s1r1 = s1.eqNode(r[0][0]).negate(); + } else if(r[0].getKind() == kind::REGEXP_EMPTY) { + s1r1 = d_true; + } + Node r2 = r[1]; + if(r.getNumChildren() > 2) { + std::vector< Node > nvec; + for(unsigned i=1; i<r.getNumChildren(); i++) { + nvec.push_back( r[i] ); + } + r2 = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, nvec); + } + r2 = Rewriter::rewrite(r2); + Node s2r2 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s2, r2).negate(); + if(r2.getKind() == kind::STRING_TO_REGEXP) { + s2r2 = s2.eqNode(r2[0]).negate(); + } else if(r2.getKind() == kind::REGEXP_EMPTY) { + s2r2 = d_true; + } + + conc = NodeManager::currentNM()->mkNode(kind::OR, s1r1, s2r2); + conc = NodeManager::currentNM()->mkNode(kind::IMPLIES, g1, conc); + conc = NodeManager::currentNM()->mkNode(kind::FORALL, b1v, conc); + break; + } + case kind::REGEXP_UNION: { + std::vector< Node > c_and; + for(unsigned i=0; i<r.getNumChildren(); ++i) { + if(r[i].getKind() == kind::STRING_TO_REGEXP) { + c_and.push_back( r[i][0].eqNode(s).negate() ); + } else if(r[i].getKind() == kind::REGEXP_EMPTY) { + continue; + } else { + c_and.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]).negate()); + } + } + conc = c_and.size() == 0 ? d_true : + c_and.size() == 1 ? c_and[0] : NodeManager::currentNM()->mkNode(kind::AND, c_and); + break; + } + case kind::REGEXP_INTER: { + bool emptyflag = false; + std::vector< Node > c_or; + for(unsigned i=0; i<r.getNumChildren(); ++i) { + if(r[i].getKind() == kind::STRING_TO_REGEXP) { + c_or.push_back( r[i][0].eqNode(s).negate() ); + } else if(r[i].getKind() == kind::REGEXP_EMPTY) { + emptyflag = true; + break; + } else { + c_or.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]).negate()); + } + } + if(emptyflag) { + conc = d_true; + } else { + conc = c_or.size() == 1 ? c_or[0] : NodeManager::currentNM()->mkNode(kind::OR, c_or); + } + break; + } + case kind::REGEXP_STAR: { + if(s == d_emptyString) { + conc = d_false; + } else if(r[0].getKind() == kind::REGEXP_EMPTY) { + conc = s.eqNode(d_emptyString).negate(); + } else if(r[0].getKind() == kind::REGEXP_SIGMA) { + conc = d_false; + } else { + Node lens = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s); + Node sne = s.eqNode(d_emptyString).negate(); + Node b1 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType()); + Node b1v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b1); + Node g1 = NodeManager::currentNM()->mkNode( kind::AND, NodeManager::currentNM()->mkNode(kind::GEQ, b1, d_one), + NodeManager::currentNM()->mkNode( kind::GEQ, lens, b1 ) ); + //internal + Node s1 = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, d_zero, b1); + Node s2 = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, b1, NodeManager::currentNM()->mkNode(kind::MINUS, lens, b1)); + Node s1r1 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s1, r[0]).negate(); + Node s2r2 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s2, r).negate(); + + conc = NodeManager::currentNM()->mkNode(kind::OR, s1r1, s2r2); + conc = NodeManager::currentNM()->mkNode(kind::IMPLIES, g1, conc); + conc = NodeManager::currentNM()->mkNode(kind::FORALL, b1v, conc); + conc = NodeManager::currentNM()->mkNode(kind::AND, sne, conc); + } + break; + } + default: { + Trace("strings-regexp") << "Unsupported term: " << r << " in simplifyNRegExp." << std::endl; + Assert( false, "Unsupported Term" ); + } + } + conc = Rewriter::rewrite( conc ); + new_nodes.push_back( conc ); + d_simpl_neg_cache[p] = conc; + } +} +void RegExpOpr::simplifyPRegExp( Node s, Node r, std::vector< Node > &new_nodes ) { + std::pair < Node, Node > p(s, r); + std::map < std::pair< Node, Node >, Node >::const_iterator itr = d_simpl_cache.find(p); + if(itr != d_simpl_cache.end()) { + new_nodes.push_back( itr->second ); + } else { + int k = r.getKind(); + Node conc; + switch( k ) { + case kind::REGEXP_EMPTY: { + conc = d_false; + break; + } + case kind::REGEXP_SIGMA: { + conc = d_one.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s)); + break; + } + case kind::STRING_TO_REGEXP: { + conc = s.eqNode(r[0]); + break; + } + case kind::REGEXP_CONCAT: { + std::vector< Node > nvec; + std::vector< Node > cc; + bool emptyflag = false; + for(unsigned i=0; i<r.getNumChildren(); ++i) { + if(r[i].getKind() == kind::STRING_TO_REGEXP) { + cc.push_back( r[i][0] ); + } else if(r[i].getKind() == kind::REGEXP_EMPTY) { + emptyflag = true; + break; + } else { + Node sk = NodeManager::currentNM()->mkSkolem( "rc", s.getType(), "created for regular expression concat" ); + Node lem = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, sk, r[i]); + nvec.push_back(lem); + cc.push_back(sk); + } + } + if(emptyflag) { + conc = d_false; + } else { + Node lem = s.eqNode( NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, cc) ); + nvec.push_back(lem); + conc = nvec.size() == 1 ? nvec[0] : NodeManager::currentNM()->mkNode(kind::AND, nvec); + } + break; + } + case kind::REGEXP_UNION: { + std::vector< Node > c_or; + for(unsigned i=0; i<r.getNumChildren(); ++i) { + if(r[i].getKind() == kind::STRING_TO_REGEXP) { + c_or.push_back( r[i][0].eqNode(s) ); + } else if(r[i].getKind() == kind::REGEXP_EMPTY) { + continue; + } else { + c_or.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i])); + } + } + conc = c_or.size() == 0 ? d_false : + c_or.size() == 1 ? c_or[0] : NodeManager::currentNM()->mkNode(kind::OR, c_or); + break; + } + case kind::REGEXP_INTER: { + std::vector< Node > c_and; + bool emptyflag = false; + for(unsigned i=0; i<r.getNumChildren(); ++i) { + if(r[i].getKind() == kind::STRING_TO_REGEXP) { + c_and.push_back( r[i][0].eqNode(s) ); + } else if(r[i].getKind() == kind::REGEXP_EMPTY) { + emptyflag = true; + break; + } else { + c_and.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i])); + } + } + if(emptyflag) { + conc = d_false; + } else { + conc = c_and.size() == 1 ? c_and[0] : NodeManager::currentNM()->mkNode(kind::AND, c_and); + } + break; + } + case kind::REGEXP_STAR: { + if(s == d_emptyString) { + conc = d_true; + } else if(r[0].getKind() == kind::REGEXP_EMPTY) { + conc = s.eqNode(d_emptyString); + } else if(r[0].getKind() == kind::REGEXP_SIGMA) { + conc = d_true; + } else { + Node se = s.eqNode(d_emptyString); + Node sinr = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[0]); + Node sk1 = NodeManager::currentNM()->mkSkolem( "rs", s.getType(), "created for regular expression star" ); + Node sk2 = NodeManager::currentNM()->mkSkolem( "rs", s.getType(), "created for regular expression star" ); + Node s1nz = sk1.eqNode(d_emptyString).negate(); + Node s2nz = sk2.eqNode(d_emptyString).negate(); + Node s1inr = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, sk1, r[0]); + Node s2inrs = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, sk2, r); + Node s12 = s.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, sk1, sk2)); + + conc = NodeManager::currentNM()->mkNode(kind::AND, s12, s1nz, s2nz, s1inr, s2inrs); + conc = NodeManager::currentNM()->mkNode(kind::OR, se, sinr, conc); + } + break; + } + default: { + Trace("strings-regexp") << "Unsupported term: " << r << " in simplifyPRegExp." << std::endl; + Assert( false, "Unsupported Term" ); + } + } + conc = Rewriter::rewrite( conc ); + new_nodes.push_back( conc ); + d_simpl_cache[p] = conc; + } +} + +void RegExpOpr::getCharSet( Node r, std::set<unsigned> &pcset, SetNodes &pvset ) { + std::map< Node, std::pair< std::set<unsigned>, SetNodes > >::const_iterator itr = d_cset_cache.find(r); + if(itr != d_cset_cache.end()) { + pcset.insert((itr->second).first.begin(), (itr->second).first.end()); + pvset.insert((itr->second).second.begin(), (itr->second).second.end()); + } else { + std::set<unsigned> cset; + SetNodes vset; + int k = r.getKind(); + switch( k ) { + case kind::REGEXP_EMPTY: { + break; + } + case kind::REGEXP_SIGMA: { + for(unsigned i=0; i<d_card; i++) { + cset.insert(i); + } + break; + } + case kind::STRING_TO_REGEXP: { + Node st = Rewriter::rewrite(r[0]); + if(st.isConst()) { + CVC4::String s = st.getConst< CVC4::String >(); + s.getCharSet( cset ); + } else if(st.getKind() == kind::VARIABLE) { + vset.insert( st ); + } else { + for(unsigned i=0; i<st.getNumChildren(); i++) { + if(st[i].isConst()) { + CVC4::String s = st[i].getConst< CVC4::String >(); + s.getCharSet( cset ); + } else { + vset.insert( st[i] ); + } + } + } + break; + } + case kind::REGEXP_CONCAT: { + for(unsigned i=0; i<r.getNumChildren(); i++) { + getCharSet(r[i], cset, vset); + } + break; + } + case kind::REGEXP_UNION: { + for(unsigned i=0; i<r.getNumChildren(); i++) { + getCharSet(r[i], cset, vset); + } + break; + } + case kind::REGEXP_INTER: { + //TODO: Overapproximation for now + for(unsigned i=0; i<r.getNumChildren(); i++) { + getCharSet(r[i], cset, vset); + } + break; + } + case kind::REGEXP_STAR: { + getCharSet(r[0], cset, vset); + break; + } + default: { + Trace("strings-regexp") << "Unsupported term: " << r << " in getCharSet." << std::endl; + Assert( false, "Unsupported Term" ); + } + } + pcset.insert(cset.begin(), cset.end()); + pvset.insert(vset.begin(), vset.end()); + std::pair< std::set<unsigned>, SetNodes > p(cset, vset); + d_cset_cache[r] = p; + + Trace("regexp-cset") << "CSET( " << mkString(r) << " ) = { "; + for(std::set<unsigned>::const_iterator itr = cset.begin(); + itr != cset.end(); itr++) { + Trace("regexp-cset") << CVC4::String::convertUnsignedIntToChar(*itr) << ","; + } + Trace("regexp-cset") << " }" << std::endl; + } +} + + +Node RegExpOpr::intersectInternal( Node r1, Node r2, std::map< unsigned, std::set< PairNodes > > cache, bool &spflag ) { + if(spflag) { + //TODO: var + return Node::null(); + } + std::pair < Node, Node > p(r1, r2); + std::map < std::pair< Node, Node >, Node >::const_iterator itr = d_inter_cache.find(p); + Node rNode; + if(itr != d_inter_cache.end()) { + rNode = itr->second; + } else { + if(r1 == r2) { + rNode = r1; + } else if(r1 == d_emptyRegexp || r2 == d_emptyRegexp) { + rNode = d_emptyRegexp; + } else if(r1 == d_emptySingleton || r2 == d_emptySingleton) { + Node exp; + int r = delta((r1 == d_emptySingleton ? r2 : r1), exp); + if(r == 0) { + //TODO: variable + spflag = true; + } else if(r == 1) { + rNode = d_emptySingleton; + } else { + rNode = d_emptyRegexp; + } + } else { + std::set< unsigned > cset, cset2; + std::set< Node > vset, vset2; + getCharSet(r1, cset, vset); + getCharSet(r2, cset2, vset2); + if(vset.empty() && vset2.empty()) { + cset.clear(); + firstChars(r1, cset, vset); + std::vector< Node > vec_nodes; + for(std::set<unsigned>::const_iterator itr = cset.begin(); + itr != cset.end(); itr++) { + CVC4::String c( CVC4::String::convertUnsignedIntToChar(*itr) ); + std::pair< Node, Node > p(r1, r2); + if(cache[ *itr ].find(p) == cache[ *itr ].end()) { + Node r1l = derivativeSingle(r1, c); + Node r2l = derivativeSingle(r2, c); + std::map< unsigned, std::set< PairNodes > > cache2(cache); + PairNodes p(r1l, r2l); + cache2[ *itr ].insert( p ); + Node rt = intersectInternal(r1l, r2l, cache2, spflag); + if(spflag) { + //TODO: + return Node::null(); + } + rt = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, + NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(c)), rt) ); + vec_nodes.push_back(rt); + } + } + rNode = vec_nodes.size()==0 ? d_emptyRegexp : vec_nodes.size()==1 ? vec_nodes[0] : + NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vec_nodes); + rNode = Rewriter::rewrite( rNode ); + } else { + //TODO: non-empty var set + spflag = true; + } + } + d_inter_cache[p] = rNode; + } + Trace("regexp-intersect") << "INTERSECT( " << mkString(r1) << ", " << mkString(r2) << " ) = " << mkString(rNode) << std::endl; + return rNode; +} +Node RegExpOpr::intersect(Node r1, Node r2, bool &spflag) { + std::map< unsigned, std::set< PairNodes > > cache; + if(checkConstRegExp(r1) && checkConstRegExp(r2)) { + return intersectInternal(r1, r2, cache, spflag); + } else { + spflag = true; + return Node::null(); + } +} + +Node RegExpOpr::complement(Node r, int &ret) { + Node rNode; + ret = 1; + if(d_compl_cache.find(r) != d_compl_cache.end()) { + rNode = d_compl_cache[r].first; + ret = d_compl_cache[r].second; + } else { + if(r == d_emptyRegexp) { + rNode = d_sigma_star; + } else if(r == d_emptySingleton) { + rNode = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, d_sigma, d_sigma_star); + } else if(!checkConstRegExp(r)) { + //TODO: var to be extended + ret = 0; + } else { + std::set<unsigned> cset; + SetNodes vset; + firstChars(r, cset, vset); + std::vector< Node > vec_nodes; + for(unsigned i=0; i<d_card; i++) { + CVC4::String c = CVC4::String::convertUnsignedIntToChar(i); + Node n = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(c)); + Node r2; + if(cset.find(i) == cset.end()) { + r2 = d_sigma_star; + } else { + int rt; + derivativeS(r, c, r2); + if(r2 == r) { + r2 = d_emptyRegexp; + } else { + r2 = complement(r2, rt); + } + } + n = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, n, r2)); + vec_nodes.push_back(n); + } + rNode = vec_nodes.size()==0? d_emptyRegexp : vec_nodes.size()==1? vec_nodes[0] : + NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vec_nodes); + } + rNode = Rewriter::rewrite(rNode); + std::pair< Node, int > p(rNode, ret); + d_compl_cache[r] = p; + } + Trace("regexp-compl") << "COMPL( " << mkString(r) << " ) = " << mkString(rNode) << ", ret=" << ret << std::endl; + return rNode; +} + +void RegExpOpr::splitRegExp(Node r, std::vector< PairNodes > &pset) { + Assert(checkConstRegExp(r)); + if(d_split_cache.find(r) != d_split_cache.end()) { + pset = d_split_cache[r]; + } else { + switch( r.getKind() ) { + case kind::REGEXP_EMPTY: { + break; + } + case kind::REGEXP_OPT: { + PairNodes tmp(d_emptySingleton, d_emptySingleton); + pset.push_back(tmp); + } + case kind::REGEXP_RANGE: + case kind::REGEXP_SIGMA: { + PairNodes tmp1(d_emptySingleton, r); + PairNodes tmp2(r, d_emptySingleton); + pset.push_back(tmp1); + pset.push_back(tmp2); + break; + } + case kind::STRING_TO_REGEXP: { + Assert(r[0].isConst()); + CVC4::String s = r[0].getConst< CVC4::String >(); + PairNodes tmp1(d_emptySingleton, r); + pset.push_back(tmp1); + for(unsigned i=1; i<s.size(); i++) { + CVC4::String s1 = s.substr(0, i); + CVC4::String s2 = s.substr(i); + Node n1 = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(s1)); + Node n2 = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(s2)); + PairNodes tmp3(n1, n2); + pset.push_back(tmp3); + } + PairNodes tmp2(r, d_emptySingleton); + pset.push_back(tmp2); + break; + } + case kind::REGEXP_CONCAT: { + for(unsigned i=0; i<r.getNumChildren(); i++) { + std::vector< PairNodes > tset; + splitRegExp(r[i], tset); + std::vector< Node > hvec; + std::vector< Node > tvec; + for(unsigned j=0; j<=i; j++) { + hvec.push_back(r[j]); + } + for(unsigned j=i; j<r.getNumChildren(); j++) { + tvec.push_back(r[j]); + } + for(unsigned j=0; j<tset.size(); j++) { + hvec[i] = tset[j].first; + tvec[0] = tset[j].second; + Node r1 = Rewriter::rewrite( hvec.size()==1?hvec[0]:NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, hvec) ); + Node r2 = Rewriter::rewrite( tvec.size()==1?tvec[0]:NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, tvec) ); + PairNodes tmp2(r1, r2); + pset.push_back(tmp2); + } + } + break; + } + case kind::REGEXP_UNION: { + for(unsigned i=0; i<r.getNumChildren(); ++i) { + std::vector< PairNodes > tset; + splitRegExp(r[i], tset); + pset.insert(pset.end(), tset.begin(), tset.end()); + } + break; + } + case kind::REGEXP_INTER: { + bool spflag = false; + Node tmp = r[0]; + for(unsigned i=1; i<r.getNumChildren(); i++) { + tmp = intersect(tmp, r[i], spflag); + } + splitRegExp(tmp, pset); + break; + } + case kind::REGEXP_STAR: { + std::vector< PairNodes > tset; + splitRegExp(r[0], tset); + PairNodes tmp1(d_emptySingleton, d_emptySingleton); + pset.push_back(tmp1); + for(unsigned i=0; i<tset.size(); i++) { + Node r1 = tset[i].first==d_emptySingleton ? r : NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, r, tset[i].first); + Node r2 = tset[i].second==d_emptySingleton ? r : NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, tset[i].second, r); + PairNodes tmp2(r1, r2); + pset.push_back(tmp2); + } + break; + } + case kind::REGEXP_PLUS: { + std::vector< PairNodes > tset; + splitRegExp(r[0], tset); + for(unsigned i=0; i<tset.size(); i++) { + Node r1 = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, r, tset[i].first); + Node r2 = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, tset[i].second, r); + PairNodes tmp2(r1, r2); + pset.push_back(tmp2); + } + break; + } + default: { + Trace("strings-error") << "Unsupported term: " << r << " in splitRegExp." << std::endl; + Assert( false ); + //return Node::null(); + } + } + d_split_cache[r] = pset; + } +} + +//printing +std::string RegExpOpr::niceChar( Node r ) { + if(r.isConst()) { + std::string s = r.getConst<CVC4::String>().toString() ; + return s == "" ? "{E}" : ( s == " " ? "{ }" : s.size()>1? "("+s+")" : s ); + } else { + std::string ss = "$" + r.toString(); + return ss; + } +} +std::string RegExpOpr::mkString( Node r ) { + std::string retStr; + if(r.isNull()) { + retStr = "Empty"; + } else { + int k = r.getKind(); + switch( k ) { + case kind::REGEXP_EMPTY: { + retStr += "Empty"; + break; + } + case kind::REGEXP_SIGMA: { + retStr += "{W}"; + break; + } + case kind::STRING_TO_REGEXP: { + retStr += niceChar( r[0] ); + break; + } + case kind::REGEXP_CONCAT: { + retStr += "("; + for(unsigned i=0; i<r.getNumChildren(); ++i) { + //if(i != 0) retStr += "."; + retStr += mkString( r[i] ); + } + retStr += ")"; + break; + } + case kind::REGEXP_UNION: { + if(r == d_sigma) { + retStr += "{A}"; + } else { + retStr += "("; + for(unsigned i=0; i<r.getNumChildren(); ++i) { + if(i != 0) retStr += "|"; + retStr += mkString( r[i] ); + } + retStr += ")"; + } + break; + } + case kind::REGEXP_INTER: { + retStr += "("; + for(unsigned i=0; i<r.getNumChildren(); ++i) { + if(i != 0) retStr += "&"; + retStr += mkString( r[i] ); + } + retStr += ")"; + break; + } + case kind::REGEXP_STAR: { + retStr += mkString( r[0] ); + retStr += "*"; + break; + } + case kind::REGEXP_PLUS: { + retStr += mkString( r[0] ); + retStr += "+"; + break; + } + case kind::REGEXP_OPT: { + retStr += mkString( r[0] ); + retStr += "?"; + break; + } + case kind::REGEXP_RANGE: { + retStr += "["; + retStr += niceChar( r[0] ); + retStr += "-"; + retStr += niceChar( r[1] ); + retStr += "]"; + break; + } + default: + Trace("strings-error") << "Unsupported term: " << r << " in RegExp." << std::endl; + //Assert( false ); + //return Node::null(); + } + } + + return retStr; +} + +}/* CVC4::theory::strings namespace */ +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ diff --git a/src/theory/strings/regexp_operation.h b/src/theory/strings/regexp_operation.h index d5606627f..3d5ff2d6d 100644 --- a/src/theory/strings/regexp_operation.h +++ b/src/theory/strings/regexp_operation.h @@ -1,100 +1,100 @@ -/********************* */
-/*! \file regexp_operation.h
- ** \verbatim
- ** Original author: Tianyi Liang
- ** Major contributors: none
- ** 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 Symbolic Regular Expresion Operations
- **
- ** Symbolic Regular Expression Operations
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__STRINGS__REGEXP__OPERATION_H
-#define __CVC4__THEORY__STRINGS__REGEXP__OPERATION_H
-
-#include <vector>
-#include <set>
-#include <algorithm>
-#include "util/hash.h"
-#include "util/regexp.h"
-#include "theory/theory.h"
-#include "theory/rewriter.h"
-//#include "context/cdhashmap.h"
-
-namespace CVC4 {
-namespace theory {
-namespace strings {
-
-class RegExpOpr {
- typedef std::pair< Node, CVC4::String > PairNodeStr;
- typedef std::set< Node > SetNodes;
- typedef std::pair< Node, Node > PairNodes;
-
-private:
- unsigned d_card;
- Node d_emptyString;
- Node d_true;
- Node d_false;
- Node d_emptySingleton;
- Node d_emptyRegexp;
- Node d_zero;
- Node d_one;
-
- char d_char_start;
- char d_char_end;
- Node d_sigma;
- Node d_sigma_star;
-
- std::map< PairNodes, Node > d_simpl_cache;
- std::map< PairNodes, Node > d_simpl_neg_cache;
- std::map< Node, std::pair< int, Node > > d_delta_cache;
- std::map< PairNodeStr, Node > d_dv_cache;
- std::map< PairNodeStr, std::pair< Node, int > > d_deriv_cache;
- std::map< Node, std::pair< Node, int > > d_compl_cache;
- std::map< Node, bool > d_cstre_cache;
- std::map< Node, std::pair< std::set<unsigned>, std::set<Node> > > d_cset_cache;
- std::map< Node, std::pair< std::set<unsigned>, std::set<Node> > > d_fset_cache;
- std::map< PairNodes, Node > d_inter_cache;
- std::map< Node, std::vector< PairNodes > > d_split_cache;
- //bool checkStarPlus( Node t );
- void simplifyPRegExp( Node s, Node r, std::vector< Node > &new_nodes );
- void simplifyNRegExp( Node s, Node r, std::vector< Node > &new_nodes );
- std::string niceChar( Node r );
- int gcd ( int a, int b );
- Node mkAllExceptOne( char c );
-
- void getCharSet( Node r, std::set<unsigned> &pcset, SetNodes &pvset );
- Node intersectInternal( Node r1, Node r2, std::map< unsigned, std::set< PairNodes > > cache, bool &spflag );
- void firstChars( Node r, std::set<unsigned> &pcset, SetNodes &pvset );
-
- //TODO: for intersection
- bool follow( Node r, CVC4::String c, std::vector< char > &vec_chars );
-
-public:
- RegExpOpr();
-
- bool checkConstRegExp( Node r );
- void simplify(Node t, std::vector< Node > &new_nodes, bool polarity);
- int delta( Node r, Node &exp );
- int derivativeS( Node r, CVC4::String c, Node &retNode );
- Node derivativeSingle( Node r, CVC4::String c );
- bool guessLength( Node r, int &co );
- Node intersect(Node r1, Node r2, bool &spflag);
- Node complement(Node r, int &ret);
- void splitRegExp(Node r, std::vector< PairNodes > &pset);
-
- std::string mkString( Node r );
-};
-
-}/* CVC4::theory::strings namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__STRINGS__REGEXP__OPERATION_H */
+/********************* */ +/*! \file regexp_operation.h + ** \verbatim + ** Original author: Tianyi Liang + ** Major contributors: none + ** 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 Symbolic Regular Expresion Operations + ** + ** Symbolic Regular Expression Operations + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY__STRINGS__REGEXP__OPERATION_H +#define __CVC4__THEORY__STRINGS__REGEXP__OPERATION_H + +#include <vector> +#include <set> +#include <algorithm> +#include "util/hash.h" +#include "util/regexp.h" +#include "theory/theory.h" +#include "theory/rewriter.h" +//#include "context/cdhashmap.h" + +namespace CVC4 { +namespace theory { +namespace strings { + +class RegExpOpr { + typedef std::pair< Node, CVC4::String > PairNodeStr; + typedef std::set< Node > SetNodes; + typedef std::pair< Node, Node > PairNodes; + +private: + unsigned d_card; + Node d_emptyString; + Node d_true; + Node d_false; + Node d_emptySingleton; + Node d_emptyRegexp; + Node d_zero; + Node d_one; + + char d_char_start; + char d_char_end; + Node d_sigma; + Node d_sigma_star; + + std::map< PairNodes, Node > d_simpl_cache; + std::map< PairNodes, Node > d_simpl_neg_cache; + std::map< Node, std::pair< int, Node > > d_delta_cache; + std::map< PairNodeStr, Node > d_dv_cache; + std::map< PairNodeStr, std::pair< Node, int > > d_deriv_cache; + std::map< Node, std::pair< Node, int > > d_compl_cache; + std::map< Node, bool > d_cstre_cache; + std::map< Node, std::pair< std::set<unsigned>, std::set<Node> > > d_cset_cache; + std::map< Node, std::pair< std::set<unsigned>, std::set<Node> > > d_fset_cache; + std::map< PairNodes, Node > d_inter_cache; + std::map< Node, std::vector< PairNodes > > d_split_cache; + //bool checkStarPlus( Node t ); + void simplifyPRegExp( Node s, Node r, std::vector< Node > &new_nodes ); + void simplifyNRegExp( Node s, Node r, std::vector< Node > &new_nodes ); + std::string niceChar( Node r ); + int gcd ( int a, int b ); + Node mkAllExceptOne( char c ); + + void getCharSet( Node r, std::set<unsigned> &pcset, SetNodes &pvset ); + Node intersectInternal( Node r1, Node r2, std::map< unsigned, std::set< PairNodes > > cache, bool &spflag ); + void firstChars( Node r, std::set<unsigned> &pcset, SetNodes &pvset ); + + //TODO: for intersection + bool follow( Node r, CVC4::String c, std::vector< char > &vec_chars ); + +public: + RegExpOpr(); + + bool checkConstRegExp( Node r ); + void simplify(Node t, std::vector< Node > &new_nodes, bool polarity); + int delta( Node r, Node &exp ); + int derivativeS( Node r, CVC4::String c, Node &retNode ); + Node derivativeSingle( Node r, CVC4::String c ); + bool guessLength( Node r, int &co ); + Node intersect(Node r1, Node r2, bool &spflag); + Node complement(Node r, int &ret); + void splitRegExp(Node r, std::vector< PairNodes > &pset); + + std::string mkString( Node r ); +}; + +}/* CVC4::theory::strings namespace */ +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ + +#endif /* __CVC4__THEORY__STRINGS__REGEXP__OPERATION_H */ diff --git a/src/util/regexp.cpp b/src/util/regexp.cpp index cbc0b843b..ce6f0d29b 100644 --- a/src/util/regexp.cpp +++ b/src/util/regexp.cpp @@ -1,159 +1,159 @@ -/********************* */
-/*! \file regexp.cpp
- ** \verbatim
- ** Original author: Tianyi Liang
- ** Major contributors: none
- ** Minor contributors (to current version): Morgan Deters
- ** 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 [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-
-#include "util/regexp.h"
-#include <iostream>
-#include <iomanip>
-
-using namespace std;
-
-namespace CVC4 {
-
-void String::toInternal(const std::string &s) {
- d_str.clear();
- unsigned i=0;
- while(i < s.size()) {
- if(s[i] == '\\') {
- i++;
- if(i < s.size()) {
- switch(s[i]) {
- case 'n': {d_str.push_back( convertCharToUnsignedInt('\n') );i++;} break;
- case 't': {d_str.push_back( convertCharToUnsignedInt('\t') );i++;} break;
- case 'v': {d_str.push_back( convertCharToUnsignedInt('\v') );i++;} break;
- case 'b': {d_str.push_back( convertCharToUnsignedInt('\b') );i++;} break;
- case 'r': {d_str.push_back( convertCharToUnsignedInt('\r') );i++;} break;
- case 'f': {d_str.push_back( convertCharToUnsignedInt('\f') );i++;} break;
- case 'a': {d_str.push_back( convertCharToUnsignedInt('\a') );i++;} break;
- case '\\': {d_str.push_back( convertCharToUnsignedInt('\\') );i++;} break;
- case 'x': {
- if(i + 2 < s.size()) {
- if(isxdigit(s[i+1]) && isxdigit(s[i+2])) {
- d_str.push_back( convertCharToUnsignedInt( hexToDec(s[i+1]) * 16 + hexToDec(s[i+2]) ) );
- i += 3;
- } else {
- throw CVC4::Exception( "Illegal String Literal: \"" + s + "\"" );
- }
- } else {
- throw CVC4::Exception( "Illegal String Literal: \"" + s + "\", must have two digits after \\x" );
- }
- }
- break;
- default: {
- if(isdigit(s[i])) {
- int num = (int)s[i] - (int)'0';
- bool flag = num < 4;
- if(i+1 < s.size() && num < 8 && isdigit(s[i+1]) && s[i+1] < '8') {
- num = num * 8 + (int)s[i+1] - (int)'0';
- if(flag && i+2 < s.size() && isdigit(s[i+2]) && s[i+2] < '8') {
- num = num * 8 + (int)s[i+2] - (int)'0';
- d_str.push_back( convertCharToUnsignedInt((char)num) );
- i += 3;
- } else {
- d_str.push_back( convertCharToUnsignedInt((char)num) );
- i += 2;
- }
- } else {
- d_str.push_back( convertCharToUnsignedInt((char)num) );
- i++;
- }
- } else if((unsigned)s[i] > 127) {
- throw CVC4::Exception( "Illegal String Literal: \"" + s + "\", must use escaped sequence" );
- } else {
- d_str.push_back( convertCharToUnsignedInt(s[i]) );
- i++;
- }
- }
- }
- } else {
- throw CVC4::Exception( "should be handled by lexer: \"" + s + "\"" );
- //d_str.push_back( convertCharToUnsignedInt('\\') );
- }
- } else if((unsigned)s[i] > 127) {
- throw CVC4::Exception( "Illegal String Literal: \"" + s + "\", must use escaped sequence" );
- } else {
- d_str.push_back( convertCharToUnsignedInt(s[i]) );
- i++;
- }
- }
-}
-
-void String::getCharSet(std::set<unsigned int> &cset) const {
- for(std::vector<unsigned int>::const_iterator itr = d_str.begin();
- itr != d_str.end(); itr++) {
- cset.insert( *itr );
- }
-}
-
-std::size_t String::overlap(String &y) const {
- std::size_t i = d_str.size() < y.size() ? d_str.size() : y.size();
- for(; i>0; i--) {
- String s = suffix(i);
- String p = y.prefix(i);
- if(s == p) {
- return i;
- }
- }
- return i;
-}
-
-std::string String::toString() const {
- std::string str;
- for(unsigned int i=0; i<d_str.size(); ++i) {
- char c = convertUnsignedIntToChar( d_str[i] );
- if(isprint( c )) {
- if(c == '\\') {
- str += "\\\\";
- } else if(c == '\"') {
- str += "\\\"";
- } else {
- str += c;
- }
- } else {
- std::string s;
- switch(c) {
- case '\a': s = "\\a"; break;
- case '\b': s = "\\b"; break;
- case '\t': s = "\\t"; break;
- case '\r': s = "\\r"; break;
- case '\v': s = "\\v"; break;
- case '\f': s = "\\f"; break;
- case '\n': s = "\\n"; break;
- case '\e': s = "\\e"; break;
- default : {
- std::stringstream ss;
- ss << std::setfill ('0') << std::setw(2) << std::hex << ((int)c);
- std::string t = ss.str();
- t = t.substr(t.size()-2, 2);
- s = "\\x" + t;
- //std::string s2 = static_cast<std::ostringstream*>( &(std::ostringstream() << (int)c) )->str();
- }
- }
- str += s;
- }
- }
- return str;
-}
-
-std::ostream& operator <<(std::ostream& os, const String& s) {
- return os << "\"" << s.toString() << "\"";
-}
-
-std::ostream& operator<<(std::ostream& out, const RegExp& s) {
- return out << "regexp(" << s.getType() << ')';
-}
-
-}/* CVC4 namespace */
+/********************* */ +/*! \file regexp.cpp + ** \verbatim + ** Original author: Tianyi Liang + ** Major contributors: none + ** Minor contributors (to current version): Morgan Deters + ** 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 [[ Add one-line brief description here ]] + ** + ** [[ Add lengthier description here ]] + ** \todo document this file + **/ + +#include "util/regexp.h" +#include <iostream> +#include <iomanip> + +using namespace std; + +namespace CVC4 { + +void String::toInternal(const std::string &s) { + d_str.clear(); + unsigned i=0; + while(i < s.size()) { + if(s[i] == '\\') { + i++; + if(i < s.size()) { + switch(s[i]) { + case 'n': {d_str.push_back( convertCharToUnsignedInt('\n') );i++;} break; + case 't': {d_str.push_back( convertCharToUnsignedInt('\t') );i++;} break; + case 'v': {d_str.push_back( convertCharToUnsignedInt('\v') );i++;} break; + case 'b': {d_str.push_back( convertCharToUnsignedInt('\b') );i++;} break; + case 'r': {d_str.push_back( convertCharToUnsignedInt('\r') );i++;} break; + case 'f': {d_str.push_back( convertCharToUnsignedInt('\f') );i++;} break; + case 'a': {d_str.push_back( convertCharToUnsignedInt('\a') );i++;} break; + case '\\': {d_str.push_back( convertCharToUnsignedInt('\\') );i++;} break; + case 'x': { + if(i + 2 < s.size()) { + if(isxdigit(s[i+1]) && isxdigit(s[i+2])) { + d_str.push_back( convertCharToUnsignedInt( hexToDec(s[i+1]) * 16 + hexToDec(s[i+2]) ) ); + i += 3; + } else { + throw CVC4::Exception( "Illegal String Literal: \"" + s + "\"" ); + } + } else { + throw CVC4::Exception( "Illegal String Literal: \"" + s + "\", must have two digits after \\x" ); + } + } + break; + default: { + if(isdigit(s[i])) { + int num = (int)s[i] - (int)'0'; + bool flag = num < 4; + if(i+1 < s.size() && num < 8 && isdigit(s[i+1]) && s[i+1] < '8') { + num = num * 8 + (int)s[i+1] - (int)'0'; + if(flag && i+2 < s.size() && isdigit(s[i+2]) && s[i+2] < '8') { + num = num * 8 + (int)s[i+2] - (int)'0'; + d_str.push_back( convertCharToUnsignedInt((char)num) ); + i += 3; + } else { + d_str.push_back( convertCharToUnsignedInt((char)num) ); + i += 2; + } + } else { + d_str.push_back( convertCharToUnsignedInt((char)num) ); + i++; + } + } else if((unsigned)s[i] > 127) { + throw CVC4::Exception( "Illegal String Literal: \"" + s + "\", must use escaped sequence" ); + } else { + d_str.push_back( convertCharToUnsignedInt(s[i]) ); + i++; + } + } + } + } else { + throw CVC4::Exception( "should be handled by lexer: \"" + s + "\"" ); + //d_str.push_back( convertCharToUnsignedInt('\\') ); + } + } else if((unsigned)s[i] > 127) { + throw CVC4::Exception( "Illegal String Literal: \"" + s + "\", must use escaped sequence" ); + } else { + d_str.push_back( convertCharToUnsignedInt(s[i]) ); + i++; + } + } +} + +void String::getCharSet(std::set<unsigned int> &cset) const { + for(std::vector<unsigned int>::const_iterator itr = d_str.begin(); + itr != d_str.end(); itr++) { + cset.insert( *itr ); + } +} + +std::size_t String::overlap(String &y) const { + std::size_t i = d_str.size() < y.size() ? d_str.size() : y.size(); + for(; i>0; i--) { + String s = suffix(i); + String p = y.prefix(i); + if(s == p) { + return i; + } + } + return i; +} + +std::string String::toString() const { + std::string str; + for(unsigned int i=0; i<d_str.size(); ++i) { + char c = convertUnsignedIntToChar( d_str[i] ); + if(isprint( c )) { + if(c == '\\') { + str += "\\\\"; + } else if(c == '\"') { + str += "\\\""; + } else { + str += c; + } + } else { + std::string s; + switch(c) { + case '\a': s = "\\a"; break; + case '\b': s = "\\b"; break; + case '\t': s = "\\t"; break; + case '\r': s = "\\r"; break; + case '\v': s = "\\v"; break; + case '\f': s = "\\f"; break; + case '\n': s = "\\n"; break; + case '\e': s = "\\e"; break; + default : { + std::stringstream ss; + ss << std::setfill ('0') << std::setw(2) << std::hex << ((int)c); + std::string t = ss.str(); + t = t.substr(t.size()-2, 2); + s = "\\x" + t; + //std::string s2 = static_cast<std::ostringstream*>( &(std::ostringstream() << (int)c) )->str(); + } + } + str += s; + } + } + return str; +} + +std::ostream& operator <<(std::ostream& os, const String& s) { + return os << "\"" << s.toString() << "\""; +} + +std::ostream& operator<<(std::ostream& out, const RegExp& s) { + return out << "regexp(" << s.getType() << ')'; +} + +}/* CVC4 namespace */ |