// // Performs the actual cnfization // bool Tseitin::cnfize( Enode * formula, map< enodeid_t, Enode * > & cnf_cache ) { (void)cnf_cache; assert( formula ); assert( !formula->isAnd( ) ); Enode * arg_def = egraph.valDupMap1( formula ); if ( arg_def != NULL ) { vector< Enode * > clause; clause.push_back( arg_def ); #ifdef PRODUCE_PROOF if ( config.produce_inter > 0 ) return solver.addSMTClause( clause, egraph.getIPartitions( formula ) ); #endif return solver.addSMTClause( clause ); } vector< Enode * > unprocessed_enodes; // Stack for unprocessed enodes unprocessed_enodes.push_back( formula ); // formula needs to be processed // // Visit the DAG of the formula from the leaves to the root // while( !unprocessed_enodes.empty( ) ) { Enode * enode = unprocessed_enodes.back( ); // // Skip if the node has already been processed before // if ( egraph.valDupMap1( enode ) != NULL ) { unprocessed_enodes.pop_back( ); continue; } bool unprocessed_children = false; Enode * arg_list; for ( arg_list = enode->getCdr( ) ; arg_list != egraph.enil ; arg_list = arg_list->getCdr( ) ) { Enode * arg = arg_list->getCar( ); assert( arg->isTerm( ) ); // // Push only if it is an unprocessed boolean operator // if ( enode->isBooleanOperator( ) && egraph.valDupMap1( arg ) == NULL ) { unprocessed_enodes.push_back( arg ); unprocessed_children = true; } // // If it is an atom (either boolean or theory) just // store it in the cache // else if ( arg->isAtom( ) ) { egraph.storeDupMap1( arg, arg ); } } // // SKip if unprocessed_children // if ( unprocessed_children ) continue; unprocessed_enodes.pop_back( ); Enode * result = NULL; // // At this point, every child has been processed // // // Do the actual cnfization, according to the node type // char def_name[ 32 ]; if ( enode->isLit( ) ) { result = enode; } else if ( enode->isNot( ) ) { Enode * arg_def = egraph.valDupMap1( enode->get1st( ) ); assert( arg_def ); result = egraph.mkNot( egraph.cons( arg_def ) ); // Toggle the literal } else { Enode * arg_def = NULL; Enode * new_arg_list = egraph.copyEnodeEtypeListWithCache( enode->getCdr( ) ); // // If the enode is not top-level it needs a definition // if ( formula != enode ) { sprintf( def_name, CNF_STR, formula->getId( ), enode->getId( ) ); egraph.newSymbol( def_name, sstore.mkBool( ) ); arg_def = egraph.mkVar( def_name ); #ifdef PRODUCE_PROOF if ( config.produce_inter > 0 ) { // Tag Positive and negative literals egraph.tagIFormula( arg_def , egraph.getIPartitions( enode ) ); egraph.tagIFormula( egraph.mkNot( egraph.cons( arg_def ) ) , egraph.getIPartitions( enode ) ); } #endif } #ifdef PRODUCE_PROOF uint64_t partitions = 0; if ( config.produce_inter > 0 ) { partitions = egraph.getIPartitions( enode ); assert( partitions != 0 ); } #endif // // Handle boolean operators // if ( enode->isAnd( ) ) cnfizeAnd( new_arg_list, arg_def #ifdef PRODUCE_PROOF , partitions #endif ); else if ( enode->isOr( ) ) cnfizeOr( new_arg_list, arg_def #ifdef PRODUCE_PROOF , partitions #endif ); else if ( enode->isIff( ) ) cnfizeIff( new_arg_list, arg_def #ifdef PRODUCE_PROOF , partitions #endif ); else if ( enode->isXor( ) ) cnfizeXor( new_arg_list, arg_def #ifdef PRODUCE_PROOF , partitions #endif ); else { opensmt_error2( "operator not handled ", enode->getCar( ) ); } if ( arg_def != NULL ) result = arg_def; } assert( egraph.valDupMap1( enode ) == NULL ); egraph.storeDupMap1( enode, result ); } if ( formula->isNot( ) ) { // Retrieve definition of argument Enode * arg_def = egraph.valDupMap1( formula->get1st( ) ); assert( arg_def ); vector< Enode * > clause; clause.push_back( toggleLit( arg_def ) ); #ifdef PRODUCE_PROOF if ( config.produce_inter > 0 ) return solver.addSMTClause( clause, egraph.getIPartitions( formula ) ); #endif return solver.addSMTClause( clause ); } return true; }
Enode * Egraph::canonizeDTC( Enode * formula , bool split_eqs ) { assert( config.sat_lazy_dtc != 0 ); assert( config.logic == QF_UFLRA || config.logic == QF_UFIDL ); list< Enode * > dtc_axioms; vector< Enode * > unprocessed_enodes; initDupMap1( ); unprocessed_enodes.push_back( formula ); // // Visit the DAG of the formula from the leaves to the root // while( !unprocessed_enodes.empty( ) ) { Enode * enode = unprocessed_enodes.back( ); // // Skip if the node has already been processed before // if ( valDupMap1( enode ) != NULL ) { unprocessed_enodes.pop_back( ); continue; } bool unprocessed_children = false; Enode * arg_list; for ( arg_list = enode->getCdr( ) ; arg_list != enil ; arg_list = arg_list->getCdr( ) ) { Enode * arg = arg_list->getCar( ); assert( arg->isTerm( ) ); // // Push only if it is unprocessed // if ( valDupMap1( arg ) == NULL ) { unprocessed_enodes.push_back( arg ); unprocessed_children = true; } } // // SKip if unprocessed_children // if ( unprocessed_children ) continue; unprocessed_enodes.pop_back( ); Enode * result = NULL; // // Replace arithmetic atoms with canonized version // if ( enode->isTAtom( ) && !enode->isIff( ) && !enode->isUp( ) ) { // No need to do anything if node is purely UF if ( isRootUF( enode ) ) { if ( config.verbosity > 2 ) cerr << "# Egraph::Skipping canonization of " << enode << " as it's root is purely UF" << endl; result = enode; } else { LAExpression a( enode ); result = a.toEnode( *this ); if ( split_eqs && result->isEq( ) ) { #ifdef PRODUCE_PROOF if ( config.produce_inter != 0 ) opensmt_error2( "can't compute interpolant for equalities at the moment ", enode ); #endif LAExpression aa( enode ); Enode * e = aa.toEnode( *this ); Enode * lhs = e->get1st( ); Enode * rhs = e->get2nd( ); Enode * leq = mkLeq( cons( lhs, cons( rhs ) ) ); LAExpression b( leq ); leq = b.toEnode( *this ); Enode * geq = mkGeq( cons( lhs, cons( rhs ) ) ); LAExpression c( geq ); geq = c.toEnode( *this ); Enode * not_e = mkNot( cons( enode ) ); Enode * not_l = mkNot( cons( leq ) ); Enode * not_g = mkNot( cons( geq ) ); // Add clause ( !x=y v x<=y ) Enode * c1 = mkOr( cons( not_e , cons( leq ) ) ); // Add clause ( !x=y v x>=y ) Enode * c2 = mkOr( cons( not_e , cons( geq ) ) ); // Add clause ( x=y v !x>=y v !x<=y ) Enode * c3 = mkOr( cons( enode , cons( not_l , cons( not_g ) ) ) ); // Add conjunction of clauses Enode * ax = mkAnd( cons( c1 , cons( c2 , cons( c3 ) ) ) ); dtc_axioms.push_back( ax ); result = enode; } } } // // If nothing have been done copy and simplify // if ( result == NULL ) result = copyEnodeEtypeTermWithCache( enode ); assert( valDupMap1( enode ) == NULL ); storeDupMap1( enode, result ); } Enode * new_formula = valDupMap1( formula ); assert( new_formula ); doneDupMap1( ); if ( !dtc_axioms.empty( ) ) { dtc_axioms.push_back( new_formula ); new_formula = mkAnd( cons( dtc_axioms ) ); } return new_formula; }