void THandler::backtrack( ) { // Undoes the state of theory atoms if needed while ( (int)stack.size( ) > trail.size( ) ) { Enode * e = stack.back( ); stack.pop_back( ); // It was var_True or var_False if ( e == NULL ) continue; if ( !e->isTAtom( ) ) continue; core_solver.popBacktrackPoint( ); assert( e->isTAtom( ) ); assert( e->hasPolarity( ) ); assert( e->getPolarity( ) == l_True || e->getPolarity( ) == l_False ); // Reset polarity e->resetPolarity( ); assert( !e->hasPolarity( ) ); } checked_trail_size = stack.size( ); }
// // Inform Theory-Solvers of Theory-Atoms // void THandler::inform( ) { for ( ; tatoms_given < tatoms_list.size( ) ; tatoms_given ++ ) { if ( !tatoms_give[ tatoms_given ] ) continue; Enode * atm = tatoms_list[ tatoms_given ]; assert( atm ); assert( atm->isTAtom( ) ); core_solver.inform( atm ); } }
void CoreSMTSolver::printModel( ostream & out ) { for (Var v = 2; v < model.size(); v++) { Enode * e = theory_handler->varToEnode( v ); if ( e->isTAtom( ) ) continue; int tmp1, tmp2; if( sscanf( (e->getCar( )->getName( )).c_str( ), CNF_STR, &tmp1, &tmp2 ) != 1 ) if ( model[ v ] != l_Undef ) out << ( model[ v ] == l_True ? "" : "(not " ) << e << ( model[ v ] == l_True ? "" : ")" ) << endl; } }
void THandler::verifyDeductionWithExternalTool( Enode * imp ) { assert( imp->isDeduced( ) ); // First stage: print declarations const char * name = "/tmp/verifydeduction.smt2"; std::ofstream dump_out( name ); core_solver.dumpHeaderToFile( dump_out ); dump_out << "(assert" << endl; dump_out << "(and" << endl; for ( int j = 0 ; j < trail.size( ) ; j ++ ) { Var v = var( trail[ j ] ); if ( v == var_True || v == var_False ) continue; Enode * e = varToEnode( v ); assert( e ); if ( !e->isTAtom( ) ) continue; bool negated = sign( trail[ j ] ); if ( negated ) dump_out << "(not "; e->print( dump_out ); if ( negated ) dump_out << ")"; dump_out << endl; } if ( imp->getDeduced( ) == l_True ) dump_out << "(not " << imp << ")" << endl; else dump_out << imp << endl; dump_out << "))" << endl; dump_out << "(check-sat)" << endl; dump_out << "(exit)" << endl; dump_out.close( ); // Second stage, check the formula const bool tool_res = callCertifyingSolver( name ); if ( tool_res ) opensmt_error2( config.certifying_solver, " says this is not a valid deduction" ); }
void THandler::verifyCallWithExternalTool( bool res, size_t trail_size ) { // First stage: print declarations const char * name = "/tmp/verifycall.smt2"; std::ofstream dump_out( name ); core_solver.dumpHeaderToFile( dump_out ); dump_out << "(assert" << endl; dump_out << "(and" << endl; for ( size_t j = 0 ; j <= trail_size ; j ++ ) { Var v = var( trail[ j ] ); if ( v == var_True || v == var_False ) continue; // Enode * e = var_to_enode[ v ]; Enode * e = varToEnode( v ); assert( e ); if ( !e->isTAtom( ) ) continue; bool negated = sign( trail[ j ] ); if ( negated ) dump_out << "(not "; e->print( dump_out ); if ( negated ) dump_out << ")"; dump_out << endl; } dump_out << "))" << endl; dump_out << "(check-sat)" << endl; dump_out << "(exit)" << endl; dump_out.close( ); // Second stage, check the formula const bool tool_res = callCertifyingSolver( name ); if ( res == false && tool_res == true ) opensmt_error2( config.certifying_solver, " says SAT stack, but we say UNSAT" ); if ( res == true && tool_res == false ) opensmt_error2( config.certifying_solver, " says UNSAT stack, but we say SAT" ); }
bool THandler::assertLits( ) { bool res = true; assert( checked_trail_size == stack.size( ) ); assert( (int)stack.size( ) <= trail.size( ) ); DREAL_LOG_DEBUG << "THandler::assertLits()" << endl; for ( int i = checked_trail_size ; i < trail.size( ) && res ; i ++ ) { const Lit l = trail[ i ]; const Var v = var( l ); Enode * e = var_to_enode[ v ]; assert( v <= 1 || e ); stack.push_back( e ); if ( v == var_True || v == var_False ) { assert( v != var_True || sign( l ) == false ); assert( v != var_False || sign( l ) == true ); continue; } if ( !e->isTAtom( ) ) continue; // Push backtrack point core_solver.pushBacktrackPoint( ); assert( !e->hasPolarity( ) ); DREAL_LOG_DEBUG << "THandler::assertLits(): asserting " << e << " with sign = " << sign(l) << endl; e->setPolarity( (sign( l ) ? l_False : l_True) ); assert( e->hasPolarity( ) ); res = core_solver.assertLit( e ); if ( !res && config.certification_level > 2 ) verifyCallWithExternalTool( res, i ); } checked_trail_size = stack.size( ); assert( !res || trail.size( ) == (int)stack.size( ) ); return res; }
void THandler::verifyExplanationWithExternalTool( vector< Enode * > & expl ) { // First stage: print declarations const char * name = "/tmp/verifyexp.smt2"; std::ofstream dump_out( name ); core_solver.dumpHeaderToFile( dump_out ); dump_out << "(assert " << endl; dump_out << "(and" << endl; for ( size_t j = 0 ; j < expl.size( ) ; j ++ ) { Enode * e = expl[ j ]; assert( e->isTAtom( ) ); assert( e->getPolarity( ) != l_Undef ); bool negated = e->getPolarity( ) == l_False; if ( negated ) dump_out << "(not "; e->print( dump_out ); if ( negated ) dump_out << ")"; dump_out << endl; } dump_out << "))" << endl; dump_out << "(check-sat)" << endl; dump_out << "(exit)" << endl; dump_out.close( ); // Third stage, check the formula const bool tool_res = callCertifyingSolver( name ); if ( tool_res == true ) opensmt_error2( config.certifying_solver, " says this is not an explanation" ); }
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->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 ); #ifdef PRODUCE_PROOF const uint64_t partitions = getIPartitions( enode ); assert( partitions != 0 ); setIPartitions( result, partitions ); #endif 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 ); #ifdef PRODUCE_PROOF assert( partitions != 0 ); setIPartitions( e, partitions ); #endif Enode * lhs = e->get1st( ); Enode * rhs = e->get2nd( ); Enode * leq = mkLeq( cons( lhs, cons( rhs ) ) ); LAExpression b( leq ); leq = b.toEnode( *this ); #ifdef PRODUCE_PROOF assert( partitions != 0 ); setIPartitions( leq, partitions ); #endif Enode * geq = mkGeq( cons( lhs, cons( rhs ) ) ); LAExpression c( geq ); geq = c.toEnode( *this ); #ifdef PRODUCE_PROOF assert( partitions != 0 ); setIPartitions( geq, partitions ); #endif 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 ); #ifdef PRODUCE_PROOF if ( config.produce_inter > 0 ) { // Setting partitions for result setIPartitions( result, getIPartitions( enode ) ); // Setting partitions for negation as well occ if atom if ( result->hasSortBool( ) ) { setIPartitions( mkNot( cons( result ) ) , getIPartitions( enode ) ); } } #endif } 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; }
void THandler::verifyInterpolantWithExternalTool( vector< Enode * > & expl , Enode * interp_list ) { uint64_t mask = 0xFFFFFFFFFFFFFFFEULL; for ( unsigned in = 1 ; in < core_solver.getNofPartitions( ) ; in ++ ) { Enode * args = interp_list; // Advance in the interpolants list for ( unsigned i = 0 ; i < in - 1 ; i ++ ) args = args->getCdr( ); Enode * interp = args->getCar( ); mask &= ~SETBIT( in ); // Check A -> I, i.e., A & !I // First stage: print declarations const char * name = "/tmp/verifyinterp.smt2"; std::ofstream dump_out( name ); core_solver.dumpHeaderToFile( dump_out ); // Print only A atoms dump_out << "(assert " << endl; dump_out << "(and" << endl; for ( size_t j = 0 ; j < expl.size( ) ; j ++ ) { Enode * e = expl[ j ]; assert( e->isTAtom( ) ); assert( e->getPolarity( ) != l_Undef ); assert( (core_solver.getIPartitions( e ) & mask) != 0 || (core_solver.getIPartitions( e ) & ~mask) != 0 ); if ( (core_solver.getIPartitions( e ) & ~mask) != 0 ) { bool negated = e->getPolarity( ) == l_False; if ( negated ) dump_out << "(not "; e->print( dump_out ); if ( negated ) dump_out << ")"; dump_out << endl; } } dump_out << "(not " << interp << ")" << endl; dump_out << "))" << endl; dump_out << "(check-sat)" << endl; dump_out << "(exit)" << endl; dump_out.close( ); // Check ! bool tool_res; if ( int pid = fork() ) { int status; waitpid(pid, &status, 0); switch ( WEXITSTATUS( status ) ) { case 0: tool_res = false; break; case 1: tool_res = true; break; default: perror( "Tool" ); exit( EXIT_FAILURE ); } } else { execlp( "tool_wrapper.sh", "tool_wrapper.sh", name, 0 ); perror( "Tool" ); exit( 1 ); } if ( tool_res == true ) opensmt_error2( config.certifying_solver, " says A -> I does not hold" ); // Now check B & I dump_out.open( name ); core_solver.dumpHeaderToFile( dump_out ); // Print only B atoms dump_out << "(assert " << endl; dump_out << "(and" << endl; for ( size_t j = 0 ; j < expl.size( ) ; j ++ ) { Enode * e = expl[ j ]; assert( e->isTAtom( ) ); assert( e->getPolarity( ) != l_Undef ); assert( (core_solver.getIPartitions( e ) & mask) != 0 || (core_solver.getIPartitions( e ) & ~mask) != 0 ); if ( (core_solver.getIPartitions( e ) & mask) != 0 ) { bool negated = e->getPolarity( ) == l_False; if ( negated ) dump_out << "(not "; e->print( dump_out ); if ( negated ) dump_out << ")"; dump_out << endl; } } dump_out << interp << endl; dump_out << "))" << endl; dump_out << "(check-sat)" << endl; dump_out << "(exit)" << endl; dump_out.close( ); // Check ! tool_res; if ( int pid = fork() ) { int status; waitpid(pid, &status, 0); switch ( WEXITSTATUS( status ) ) { case 0: tool_res = false; break; case 1: tool_res = true; break; default: perror( "Tool" ); exit( EXIT_FAILURE ); } } else { execlp( "tool_wrapper.sh", "tool_wrapper.sh", name, 0 ); perror( "Tool" ); exit( 1 ); } if ( tool_res == true ) opensmt_error2( config.certifying_solver, " says B & I does not hold" ); } }
void THandler::getReason( Lit l, vec< Lit > & reason ) { #if LAZY_COMMUNICATION assert( checked_trail_size == stack.size( ) ); assert( static_cast< int >( checked_trail_size ) == trail.size( ) ); #else #endif Var v = var(l); Enode * e = varToEnode( v ); // It must be a TAtom and already disabled assert( e->isTAtom( ) ); assert( !e->hasPolarity( ) ); assert( e->isDeduced( ) ); assert( e->getDeduced( ) != l_Undef ); // Last assigned deduction #if LAZY_COMMUNICATION assert( e->getPolarity( ) != l_Undef ); // Last assigned polarity assert( e->getPolarity( ) == e->getDeduced( ) ); // The two coincide #else #endif core_solver.pushBacktrackPoint( ); // Assign reversed polarity temporairly e->setPolarity( e->getDeduced( ) == l_True ? l_False : l_True ); // Compute reason in whatever solver const bool res = core_solver.assertLit( e, true ) && core_solver.check( true ); // Result must be false if ( res ) { cout << endl << "unknown" << endl; exit( 1 ); } // Get Explanation vector< Enode * > & explanation = core_solver.getConflict( true ); if ( config.certification_level > 0 ) verifyExplanationWithExternalTool( explanation ); // Reserve room for implied lit reason.push( lit_Undef ); // Copy explanation while ( !explanation.empty( ) ) { Enode * ei = explanation.back( ); explanation.pop_back( ); assert( ei->hasPolarity( ) ); assert( ei->getPolarity( ) == l_True || ei->getPolarity( ) == l_False ); bool negate = ei->getPolarity( ) == l_False; Var v = enodeToVar( ei ); // Toggle polarity for deduced literal if ( e == ei ) { assert( e->getDeduced( ) != l_Undef ); // But still holds the deduced polarity // The deduced literal must have been pushed // with the the same polarity that has been deduced reason[ 0 ] = Lit( v, !negate ); } else { assert( ei->hasPolarity( ) ); // Lit in explanation is active // This assertion might fail if in your theory solver // you do not skip deduced literals during assertLit // // TODO: check ! It could be deduced: by another solver // For instance BV found conflict and ei was deduced by EUF solver // // assert( !ei->isDeduced( ) ); // and not deduced Lit l = Lit( v, !negate ); reason.push( l ); } } core_solver.popBacktrackPoint( ); // Resetting polarity e->resetPolarity( ); }
bool SimpSMTSolver::addClause( vec<Lit> & ps #ifdef PRODUCE_PROOF , const ipartitions_t & in #endif ) { //================================================================================================= // Added code if ( !use_simplification ) #ifdef PRODUCE_PROOF return CoreSMTSolver::addClause( ps, in ); #else return CoreSMTSolver::addClause( ps ); #endif // Added code //================================================================================================= for (int i = 0; i < ps.size(); i++) if (isEliminated(var(ps[i]))) remember(var(ps[i])); int nclauses = clauses.size(); if (redundancy_check && implied(ps)) return true; //================================================================================================= // Added code // // Hack to consider clauses of size 1 that // wouldn't otherwise be considered by // MiniSAT // if ( config.sat_preprocess_theory != 0 && ps.size( ) == 1 // Consider unit clauses && var(ps[0]) >= 2 ) // Don't consider true/false { Var v = var( ps[0] ); Enode * e = theory_handler->varToEnode( v ); if ( e->isTAtom( ) ) { Clause * uc = Clause_new(ps, false); unary_to_remove.push_back( uc ); Clause &c = *(unary_to_remove.back( )); Enode * x, * y; getDLVars( e, sign(ps[0]), &x, &y ); assert( x->isVar( ) ); assert( y->isVar( ) ); t_pos[ x->getId( ) ].push_back( &c ); t_neg[ y->getId( ) ].push_back( &c ); t_var[ x ].insert( y->getId( ) ); t_var[ y ].insert( x->getId( ) ); } } // Added code //================================================================================================= if (!CoreSMTSolver::addClause(ps)) return false; if (use_simplification && clauses.size() == nclauses + 1) { Clause& c = *clauses.last(); subsumption_queue.insert(&c); for (int i = 0; i < c.size(); i++) { assert(occurs.size() > var(c[i])); assert(!find(occurs[var(c[i])], &c)); occurs[var(c[i])].push(&c); n_occ[toInt(c[i])]++; touched[var(c[i])] = 1; assert(elimtable[var(c[i])].order == 0); if (elim_heap.inHeap(var(c[i]))) elim_heap.increase_(var(c[i])); } } return true; }