From 732dc4232ccf62d9b4a3ddf49fcfbd56efabcd41 Mon Sep 17 00:00:00 2001 From: ajreynol Date: Thu, 22 Jan 2015 17:09:29 +0100 Subject: [PATCH] Narrow sygus search space based on NNF and rewriting constant arguments. --- src/smt/smt_engine.cpp | 4 + src/theory/bv/options | 2 +- src/theory/datatypes/datatypes_sygus.cpp | 224 ++++++++++++++---- src/theory/datatypes/datatypes_sygus.h | 7 + .../quantifiers/ce_guided_instantiation.cpp | 8 +- 5 files changed, 198 insertions(+), 47 deletions(-) diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp index 0e1be30de..6732b3dc7 100644 --- a/src/smt/smt_engine.cpp +++ b/src/smt/smt_engine.cpp @@ -1350,6 +1350,10 @@ void SmtEngine::setDefaults() { if( !options::quantConflictFind.wasSetByUser() ){ options::quantConflictFind.set( false ); } + //do not allow partial functions + if( !options::bitvectorDivByZeroConst.wasSetByUser() ){ + options::bitvectorDivByZeroConst.set( true ); + } } //implied options... diff --git a/src/theory/bv/options b/src/theory/bv/options index 801dec0db..eba4608d2 100644 --- a/src/theory/bv/options +++ b/src/theory/bv/options @@ -42,7 +42,7 @@ expert-option bitvectorAlgebraicBudget --bv-algebraic-budget unsigned :default 1 option bitvectorToBool --bv-to-bool bool :default false :read-write lift bit-vectors of size 1 to booleans when possible -option bitvectorDivByZeroConst --bv-div-zero-const bool :default false +option bitvectorDivByZeroConst --bv-div-zero-const bool :default false :read-write always return -1 on division by zero expert-option bvExtractArithRewrite --bv-extract-arith bool :default false :read-write diff --git a/src/theory/datatypes/datatypes_sygus.cpp b/src/theory/datatypes/datatypes_sygus.cpp index 8192ec067..84bcb5814 100644 --- a/src/theory/datatypes/datatypes_sygus.cpp +++ b/src/theory/datatypes/datatypes_sygus.cpp @@ -57,12 +57,24 @@ int SygusSplit::getConstArg( TypeNode tn, Node n ){ return -1; } +int SygusSplit::getOpArg( TypeNode tn, Node n ) { + std::map< Node, int >::iterator it = d_ops[tn].find( n ); + if( it!=d_ops[tn].end() ){ + return it->second; + }else{ + return -1; + } +} + bool SygusSplit::hasKind( TypeNode tn, Kind k ) { return getKindArg( tn, k )!=-1; } bool SygusSplit::hasConst( TypeNode tn, Node n ) { return getConstArg( tn, n )!=-1; } +bool SygusSplit::hasOp( TypeNode tn, Node n ) { + return getOpArg( tn, n )!=-1; +} bool SygusSplit::isKindArg( TypeNode tn, int i ) { Assert( isRegistered( tn ) ); @@ -95,7 +107,10 @@ void SygusSplit::getSygusSplits( Node n, const Datatype& dt, std::vector< Node > //get parent information, if possible int csIndex = -1; int sIndex = -1; - Node onComm; + Node arg1; + Kind parentKind = UNDEFINED_KIND; + bool isPComm = false; + TypeNode tnnp; if( n.getKind()==APPLY_SELECTOR_TOTAL ){ Node op = n.getOperator(); Expr selectorExpr = op.toExpr(); @@ -103,24 +118,21 @@ void SygusSplit::getSygusSplits( Node n, const Datatype& dt, std::vector< Node > Assert( pdt.isSygus() ); csIndex = Datatype::cindexOf(selectorExpr); sIndex = Datatype::indexOf(selectorExpr); - TypeNode tnnp = n[0].getType(); + tnnp = n[0].getType(); //register the constructors that are redundant children of argument sIndex of constructor index csIndex of dt registerSygusTypeConstructorArg( tnn, dt, tnnp, pdt, csIndex, sIndex ); //relationships between arguments if( isKindArg( tnnp, csIndex ) ){ - Kind parentKind = d_arg_kind[tnnp][csIndex]; - if( sIndex==1 && isComm( parentKind ) ){ + parentKind = d_arg_kind[tnnp][csIndex]; + isPComm = isComm( parentKind ); + if( sIndex==1 ){ //if commutative, normalize based on term ordering (the constructor index of left arg must be less than or equal to the right arg) Trace("sygus-split-debug") << "Commutative operator : " << parentKind << std::endl; - if( pdt[csIndex].getNumArgs()==2 ){ - TypeNode tn1 = TypeNode::fromType( ((SelectorType)pdt[csIndex][0].getType()).getRangeType() ); - TypeNode tn2 = TypeNode::fromType( ((SelectorType)pdt[csIndex][1].getType()).getRangeType() ); - if( tn1==tn2 ){ - registerSygusTypeConstructorArg( tnn, dt, tnnp, pdt, csIndex, 0 ); - onComm = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( pdt[csIndex][0].getSelector() ), n[0] ); - } + if( pdt[csIndex].getNumArgs()==2 && isArgDatatype( pdt[csIndex], 0, dt ) ){ + registerSygusTypeConstructorArg( tnn, dt, tnnp, pdt, csIndex, 0 ); + arg1 = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( pdt[csIndex][0].getSelector() ), n[0] ); } } } @@ -139,22 +151,57 @@ void SygusSplit::getSygusSplits( Node n, const Datatype& dt, std::vector< Node > if( addSplit ){ Node test = DatatypesRewriter::mkTester( n, i, dt ); if( options::sygusNormalFormArg() ){ - //strengthen based on commutativity, if possible - if( !onComm.isNull() ){ - std::vector< Node > lem_c; - for( unsigned j=0; j<=i; j++ ){ - if( d_sygus_pc_nred[tnn][csIndex][0][i] ){ - lem_c.push_back( DatatypesRewriter::mkTester( onComm, j, dt ) ); + //strengthen first argument + if( !arg1.isNull() ){ + //arguments that can be removed + std::map< int, bool > rem_arg; + if( isComm( parentKind ) ){ + for( unsigned j=0; ji ){ + //based on commutativity + // use term ordering : constructor index of first argument is not greater than constructor index of second argument + rem_arg[j] = true; + }else{ + if( parentKind!=UNDEFINED_KIND && dt[i].getNumArgs()==0 && dt[j].getNumArgs()==0 ){ + Node nr = NodeManager::currentNM()->mkNode( parentKind, dt[j].getSygusOp(), dt[i].getSygusOp() ); + Node nrr = Rewriter::rewrite( nr ); + Trace("sygus-split-debug") << " Test constant args : " << nr << " rewrites to " << nrr << std::endl; + //based on rewriting + // if rewriting the two arguments gives an operator that is in the parent syntax, remove the redundancy + if( hasOp( tnnp, nrr ) ){ + Trace("sygus-nf") << "* Sygus norm : simplify based on rewrite " << nr << " -> " << nrr << std::endl; + rem_arg[j] = true; + } + } + } + } + } + } + + if( !rem_arg.empty() ){ + std::vector< Node > lem_c; + for( unsigned j=0; jmkNode( OR, lem_c ); + Trace("sygus-str") << "...strengthen corresponding first argument of " << test << " : " << argStr << std::endl; + test = NodeManager::currentNM()->mkNode( AND, test, argStr ); } } - Assert( !lem_c.empty() ); - Node commStr = lem_c.size()==1 ? lem_c[0] : NodeManager::currentNM()->mkNode( OR, lem_c ); - Trace("sygus-nf") << "...strengthen " << test << " based on commutatitivity : " << commStr << std::endl; - test = NodeManager::currentNM()->mkNode( AND, test, commStr ); } } - d_splits[n].push_back( test ); - Trace("sygus-split-debug2") << "SUCCESS" << std::endl; + if( !test.isNull() ){ + d_splits[n].push_back( test ); + Trace("sygus-split-debug2") << "SUCCESS" << std::endl; + Trace("sygus-split") << "Disjunct #" << d_splits[n].size() << " : " << test << std::endl; + } }else{ Trace("sygus-split-debug2") << "redundant argument" << std::endl; } @@ -162,7 +209,12 @@ void SygusSplit::getSygusSplits( Node n, const Datatype& dt, std::vector< Node > Trace("sygus-split-debug2") << "redundant operator" << std::endl; } } - Assert( !d_splits[n].empty() ); + + if( d_splits[n].empty() ){ + //possible + + Assert( false ); + } } //copy to splits splits.insert( splits.end(), d_splits[n].begin(), d_splits[n].end() ); @@ -175,18 +227,19 @@ void SygusSplit::registerSygusType( TypeNode tn, const Datatype& dt ) { for( unsigned i=0; i childTypes; + for( unsigned i=0; i=0 && i<(int)c.getNumArgs() ); + return TypeNode::fromType( ((SelectorType)c[i].getType()).getRangeType() ); +} diff --git a/src/theory/datatypes/datatypes_sygus.h b/src/theory/datatypes/datatypes_sygus.h index 46497b586..55077aac7 100644 --- a/src/theory/datatypes/datatypes_sygus.h +++ b/src/theory/datatypes/datatypes_sygus.h @@ -42,12 +42,15 @@ private: std::map< TypeNode, std::map< Kind, int > > d_kinds; std::map< TypeNode, std::map< int, Node > > d_arg_const; std::map< TypeNode, std::map< Node, int > > d_consts; + std::map< TypeNode, std::map< Node, int > > d_ops; private: bool isRegistered( TypeNode tn ); int getKindArg( TypeNode tn, Kind k ); int getConstArg( TypeNode tn, Node n ); + int getOpArg( TypeNode tn, Node n ); bool hasKind( TypeNode tn, Kind k ); bool hasConst( TypeNode tn, Node n ); + bool hasOp( TypeNode tn, Node n ); bool isKindArg( TypeNode tn, int i ); bool isConstArg( TypeNode tn, int i ); private: @@ -74,6 +77,10 @@ private: Node getTypeMaxValue( TypeNode tn ); /** get first occurrence */ int getFirstArgOccurrence( const DatatypeConstructor& c, const Datatype& dt ); + /** is arg datatype */ + bool isArgDatatype( const DatatypeConstructor& c, int i, const Datatype& dt ); + /** get arg type */ + TypeNode getArgType( const DatatypeConstructor& c, int i ); public: /** get sygus splits */ void getSygusSplits( Node n, const Datatype& dt, std::vector< Node >& splits, std::vector< Node >& lemmas ); diff --git a/src/theory/quantifiers/ce_guided_instantiation.cpp b/src/theory/quantifiers/ce_guided_instantiation.cpp index f0edb7106..b1850b373 100644 --- a/src/theory/quantifiers/ce_guided_instantiation.cpp +++ b/src/theory/quantifiers/ce_guided_instantiation.cpp @@ -216,12 +216,12 @@ Node CegInstantiation::getNextDecisionRequest() { void CegInstantiation::checkCegConjecture( CegConjecture * conj ) { Node q = conj->d_quant; - Trace("cegqi-engine") << "Synthesis conjecture : " << q << std::endl; - Trace("cegqi-engine") << " * Candidate program/output symbol : "; + Trace("cegqi-engine-debug") << "Synthesis conjecture : " << q << std::endl; + Trace("cegqi-engine-debug") << " * Candidate program/output symbol : "; for( unsigned i=0; id_candidates.size(); i++ ){ - Trace("cegqi-engine") << conj->d_candidates[i] << " "; + Trace("cegqi-engine-debug") << conj->d_candidates[i] << " "; } - Trace("cegqi-engine") << std::endl; + Trace("cegqi-engine-debug") << std::endl; if( options::ceGuidedInstFair()!=CEGQI_FAIR_NONE ){ Trace("cegqi-engine") << " * Current term size : " << conj->d_curr_lit.get() << std::endl; } -- 2.30.2