// // Subroutine of explain // A step of explanation for x and y // void Egraph::expExplainAlongPath ( Enode * x, Enode * y ) { Enode * v = expHighestNode( x ); Enode * to = expHighestNode( y ); while ( v != to ) { Enode * p = v->getExpParent( ); assert( p != NULL ); Enode * r = v->getExpReason( ); // If it is not a congruence edge if ( r != NULL ) { if ( !isDup1( r ) ) { assert( r->isTerm( ) ); explanation.push_back( r ); storeDup1( r ); } } // Otherwise it is a congruence edge // This means that the edge is linking nodes // like (v)f(a1,...,an) (p)f(b1,...,bn), and that // a1,...,an = b1,...bn. For each pair ai,bi // we have therefore to compute the reasons else { assert( v->getCar( ) == p->getCar( ) ); assert( v->getArity( ) == p->getArity( ) ); expEnqueueArguments( v, p ); } #ifdef PRODUCE_PROOF if ( config.produce_inter > 0 && config.logic != QF_AX ) { cgraph.addCNode( v ); cgraph.addCNode( p ); cgraph.addCEdge( v, p, r ); } #endif expUnion( v, p ); v = expHighestNode( p ); } }
// // Ackermann related routines // void Egraph::retrieveFunctionApplications( Enode * formula ) { assert( formula ); vector< Enode * > unprocessed_enodes; initDup1( ); 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 ( isDup1( enode ) ) { 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 ( !isDup1( arg ) ) { unprocessed_enodes.push_back( arg ); unprocessed_children = true; } } // // SKip if unprocessed_children // if ( unprocessed_children ) continue; unprocessed_enodes.pop_back( ); // // At this point, every child has been processed // if ( enode->isUf( ) || enode->isUp( ) ) { if ( uf_to_appl_cache[ enode->getCar( ) ].insert( enode ).second ) { uf_to_appl[ enode->getCar( ) ].push_back( enode ); undo_stack_oper.push_back( ACK_APPL ); undo_stack_term.push_back( enode ); } } assert( !isDup1( enode ) ); storeDup1( enode ); } doneDup1( ); }
void Egraph::gatherInterfaceTerms( Enode * e ) { assert( config.sat_lazy_dtc != 0 ); assert( config.logic == QF_UFIDL || config.logic == QF_UFLRA ); assert( e ); if ( config.verbosity > 2 ) cerr << "# Egraph::Gathering interface terms" << endl; vector< Enode * > unprocessed_enodes; initDup1( ); unprocessed_enodes.push_back( e ); // // Visit the DAG of the term 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 ( isDup1( enode ) ) { 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 ( !isDup1( arg ) ) { unprocessed_enodes.push_back( arg ); unprocessed_children = true; } } // // SKip if unprocessed_children // if ( unprocessed_children ) continue; unprocessed_enodes.pop_back( ); // // At this point, every child has been processed // if ( enode->isUFOp( ) ) { // Retrieve arguments for ( Enode * arg_list = enode->getCdr( ) ; !arg_list->isEnil( ) ; arg_list = arg_list->getCdr( ) ) { Enode * arg = arg_list->getCar( ); // This is for sure an interface term if ( ( arg->isArithmeticOp( ) || arg->isConstant( ) ) && interface_terms_cache.insert( arg ).second ) { if ( config.verbosity > 2 ) cerr << "# Egraph::Added interface term: " << arg << endl; // Save info for backtracking undo_stack_oper.push_back( INTERFACE_TERM ); undo_stack_term.push_back( arg ); } // We add this variable to the potential // interface terms or to interface terms if // already seen in LA else if ( arg->isVar( ) || arg->isConstant( ) ) { if ( it_la.find( arg ) == it_la.end( ) ) { if ( it_uf.insert( arg ).second ) { // Insertion took place, save undo info undo_stack_oper.push_back( INTERFACE_UF ); undo_stack_term.push_back( arg ); } } else if ( interface_terms_cache.insert( arg ).second ) { interface_terms.push_back( arg ); if ( config.verbosity > 2 ) cerr << "# Egraph::Added interface term: " << arg << endl; // Save info for backtracking undo_stack_oper.push_back( INTERFACE_TERM ); undo_stack_term.push_back( arg ); } } } } if ( enode->isArithmeticOp( ) && !isRootUF( enode ) ) { // Retrieve arguments for ( Enode * arg_list = enode->getCdr( ) ; !arg_list->isEnil( ) ; arg_list = arg_list->getCdr( ) ) { Enode * arg = arg_list->getCar( ); // This is for sure an interface term if ( arg->isUFOp( ) && !arg->isUp( ) && interface_terms_cache.insert( arg ).second ) { interface_terms.push_back( arg ); if ( config.verbosity > 2 ) cerr << "# Egraph::Added interface term: " << arg << endl; // Save info for backtracking undo_stack_oper.push_back( INTERFACE_TERM ); undo_stack_term.push_back( arg ); } // We add this variable to the potential // interface terms or to interface terms if // already seen in UF else if ( arg->isVar( ) || arg->isConstant( ) ) { if ( it_uf.find( arg ) == it_uf.end( ) ) { if ( it_la.insert( arg ).second ) { // Insertion took place, save undo info undo_stack_oper.push_back( INTERFACE_LA ); undo_stack_term.push_back( arg ); } } else if ( interface_terms_cache.insert( arg ).second ) { interface_terms.push_back( arg ); if ( config.verbosity > 2 ) cerr << "# Egraph::Added interface term: " << arg << endl; // Save info for backtracking undo_stack_oper.push_back( INTERFACE_TERM ); undo_stack_term.push_back( arg ); } } } } assert( !isDup1( enode ) ); storeDup1( enode ); } doneDup1( ); }
bool Egraph::isPureUF( Enode * e ) { assert( config.sat_lazy_dtc != 0 ); assert( config.logic == QF_UFIDL || config.logic == QF_UFLRA ); assert( e ); vector< Enode * > unprocessed_enodes; initDup1( ); unprocessed_enodes.push_back( e ); // // Visit the DAG of the term 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 ( isDup1( enode ) ) { 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 ( !isDup1( arg ) ) { unprocessed_enodes.push_back( arg ); unprocessed_children = true; } } // // SKip if unprocessed_children // if ( unprocessed_children ) continue; unprocessed_enodes.pop_back( ); // // At this point, every child has been processed // if ( enode->isArithmeticOp( ) ) { doneDup1( ); return false; } assert( !isDup1( enode ) ); storeDup1( enode ); } doneDup1( ); return true; }
void Egraph::getInterfaceVars( Enode * e, set< Enode * > & iv ) { assert( config.produce_inter != 0 ); assert( config.sat_lazy_dtc != 0 ); assert( config.logic == QF_UFIDL || config.logic == QF_UFLRA ); assert( e ); vector< Enode * > unprocessed_enodes; initDup1( ); unprocessed_enodes.push_back( e ); // // Visit the DAG of the term 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 ( isDup1( enode ) ) { 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 ( !isDup1( arg ) ) { unprocessed_enodes.push_back( arg ); unprocessed_children = true; } } // // SKip if unprocessed_children // if ( unprocessed_children ) continue; unprocessed_enodes.pop_back( ); if ( enode->isVar( ) && interface_terms_cache.find( enode ) != interface_terms_cache.end( ) ) iv.insert( enode ); assert( !isDup1( enode ) ); storeDup1( enode ); } doneDup1( ); }