void nlopt_fill_gradient(const double * x, double * grad, void * extra) { auto extra_info = static_cast<tuple<Enode *, box const &, bool> *>(extra); Enode * e = get<0>(*extra_info); box const & b = get<1>(*extra_info); bool const polarity = get<2>(*extra_info); unordered_map<Enode *, double> var_map; unsigned i = 0; vector<Enode*> forall_var_vec; for (Enode * e : b.get_vars()) { if (e->isForallVar()) { var_map.emplace(e, x[i]); i++; forall_var_vec.push_back(e); } else { var_map.emplace(e, b[e].mid()); } } i = 0; for (Enode * var : forall_var_vec) { double deriv_i = deriv_enode(e->get1st(), var, var_map) - deriv_enode(e->get2nd(), var, var_map); if (e->isGt() || e->isGeq()) { deriv_i = - deriv_i; } if (!polarity) { deriv_i = - deriv_i; } grad[i] = deriv_i; i++; } }
// ∀a, i, b, j. ( a = b → i = j → W (a, i, R(b, j)) = a ) void Egraph::WoRAxiom( Enode * wor ) { assert( false ); Enode * a = wor->get1st( ); Enode * i = wor->get2nd( ); Enode * worElement = wor->get3rd( ); Enode * b = worElement->get1st( ); Enode * j = worElement->get2nd( ); assert( worElement->isDTypeArrayElement( ) ); assert( a->isDTypeArray( ) ); assert( i->isDTypeArrayIndex( ) ); assert( b->isDTypeArray( ) ); assert( j->isDTypeArrayIndex( ) ); // create term W(a,i,R(b,j)) Enode * select = mkSelect( b, j ); Enode * store = mkStore(a,i,select); // add clause IF a=b THEN IF i=j THEN W(a,i,R(b,j))=a // that is (NOT(a=b) OR NOT(i=j) OR W(a,i,R(b,j))=a) vector< Enode * > v; Enode * lit1 = mkNot(cons(mkEq(cons(a,cons(b))))); Enode * lit2 = mkNot(cons(mkEq(cons(i,cons(j))))); Enode * lit3 = mkEq(cons(store,cons(a))); v.push_back( lit1 ); v.push_back( lit2 ); v.push_back( lit3 ); #ifdef ARR_VERB cout << "Axiom WoR -> " << "(or " << lit1 << " " << lit2 << " " << lit3 << " )" << endl; #endif splitOnDemand( v, id ); handleArrayAssertedAtomTerm( a ); }
double nlopt_eval_enode(const double* x, void * extra) { auto extra_info = static_cast<tuple<Enode *, box const &, bool> *>(extra); Enode * e = get<0>(*extra_info); box const & b = get<1>(*extra_info); bool const polarity = get<2>(*extra_info); unordered_map<Enode *, double> var_map; unsigned i = 0; for (Enode * e : b.get_vars()) { if (e->isForallVar()) { var_map.emplace(e, x[i]); i++; } else { var_map.emplace(e, b[e].mid()); } } try { double const ret1 = eval_enode(e->get1st(), var_map); double const ret2 = eval_enode(e->get2nd(), var_map); double ret = 0; if (e->isLt() || e->isLeq() || e->isEq()) { ret = ret1 - ret2; } else if (e->isGt() || e->isGeq()) { ret = ret2 - ret1; } else if (e->isEq()) { throw runtime_error("nlopt_obj: something is wrong."); } if (!polarity) { ret = - ret; } return ret; } catch (exception & e) { DREAL_LOG_FATAL << "Exception in nlopt_eval_enode: " << e.what() << endl; throw e; } }
void SimpSMTSolver::getDLVars( Enode * e, bool negate, Enode ** x, Enode ** y ) { assert( config.sat_preprocess_theory != 0 ); assert( e->isLeq( ) ); Enode * lhs = e->get1st( ); Enode * rhs = e->get2nd( ); (void)rhs; assert( lhs->isMinus( ) ); assert( rhs->isConstant( ) || ( rhs->isUminus( ) && rhs->get1st( )->isConstant( ) ) ); *x = lhs->get1st( ); *y = lhs->get2nd( ); if ( negate ) { Enode *tmp = *x; *x = *y; *y = tmp; } }
//∀a, i, e, j, f i != j → W (W (a, i, e), j, f ) = W (W (a, j, f ), i, e) void Egraph::WoWNeqAxiom( Enode * wow ) { assert( false ); Enode * wowArray = wow->get1st( ); Enode * a = wowArray->get1st( ); Enode * i = wowArray->get2nd( ); Enode * e = wowArray->get3rd( ); Enode * j = wow->get2nd( ); Enode * f = wow->get3rd( ); assert( wowArray->isDTypeArray( ) ); assert( a->isDTypeArray( ) ); assert( i->isDTypeArrayIndex( ) ); assert( e->isDTypeArrayElement( ) ); assert( j->isDTypeArrayIndex( ) ); assert( f->isDTypeArrayElement( ) ); // Case i, j not coincident if( i != j ) { // create term W(W(a,j,f),i,e) Enode * store1 = mkStore(a,j,f); Enode * store2 = mkStore(store1,i,e); // add clause IF i!=j THEN W(W(a,i,e),j,f)=W(W(a,j,f),i,e) // that is (i=j OR W(W(a,i,e),j,f)=W(W(a,j,f),i,e)) vector< Enode * > v; Enode * lit1 = mkEq(cons(i,cons(j))); Enode * lit2 = mkEq(cons(wow,cons(store2))); v.push_back( lit1 ); v.push_back( lit2 ); #ifdef ARR_VERB cout << "Axiom WoW!= -> " << "(or " << lit1 << " " << lit2 << " )" << endl; #endif splitOnDemand( v, id ); handleArrayAssertedAtomTerm(store2); } }
bool CostSolver::assertLitImpl( Enode * e ) { assert( e ); assert( belongsToT( e ) ); assert( e->hasPolarity() ); assert( e->getPolarity() != l_Undef ); #if DEBUG cout << "ct assert " << (e->getPolarity() == l_True ? "" : "!") << e << endl; #endif assert( !conflict_ ); Enode * atom = e; const bool negated = e->getPolarity() == l_False; if ( atom->isCostIncur() ) { assert( nodemap_[ atom ] ); costfun & fun = *nodemap_[ atom ]; #if DEBUG print_status( cout, fun ); #endif incurnode * node = incurmap_[ atom ]; if ( node->prev ) { node->prev->next = node->next; assert( node->prev->cost <= node->cost ); } if ( node->next ) { node->next->prev = node->prev; assert( node->cost <= node->next->cost ); } else { fun.unassigned.last = node->prev; } if ( fun.unassigned.head == node ) { fun.unassigned.head = node->next; } fun.slack -= node->cost; fun.assigned.push_back( node ); if ( negated ) { undo_ops_.push( undo_op( REMOVE_INCUR_NEG, node ) ); if ( !fun.lowerbound.empty() && get_bound( fun.lowerbound.top() ) > fun.incurred + fun.slack ) { assert( explanation.empty() ); conflict_ = atom; codomain potential = fun.incurred + fun.slack; for ( costfun::nodes_t::iterator it = fun.assigned.begin(); it != fun.assigned.end(); ++it ) { incurnode * node = *it; #if ELIM_REDUNDANT if ( node->atom->getPolarity() != l_False ) { continue; } if ( potential + node->cost < get_bound( fun.lowerbound.top() ) ) { potential += node->cost; continue; } #endif if ( node->atom->getPolarity() == l_False ) { explanation.push_back( node->atom ); } } assert( potential < get_bound( fun.lowerbound.top() ) ); assert( find( explanation.begin(), explanation.end(), conflict_ ) != explanation.end() ); explanation.push_back( fun.lowerbound.top() ); #if DEBUG_CONFLICT cout << " " << explanation << " : " << fun.slack << endl; print_status( cout, fun ); cout << endl; #endif #if DEBUG cout << "conflict found " << conflict_ << endl; print_status( cout, fun ); #endif #if DEBUG_CHECK_STATUS check_status(); #endif return false; } } else { fun.incurred += node->cost; undo_ops_.push( undo_op( REMOVE_INCUR_POS, node ) ); if ( !fun.upperbound.empty() && get_bound( fun.upperbound.top() ) <= fun.incurred ) { conflict_ = atom; codomain incurred = fun.incurred; for ( costfun::nodes_t::iterator it = fun.assigned.begin(); it != fun.assigned.end(); ++it ) { incurnode * node = *it; #if ELIM_REDUNDANT if ( node->atom->getPolarity() != l_True ) { continue; } if ( incurred - node->cost >= get_bound( fun.upperbound.top() ) ) { incurred -= node->cost; continue; } #endif if ( node->atom->getPolarity() == l_True ) { explanation.push_back( node->atom ); } } assert( incurred >= get_bound( fun.upperbound.top() ) ); assert( find( explanation.begin(), explanation.end(), conflict_ ) != explanation.end() ); explanation.push_back( fun.upperbound.top() ); #if DEBUG_CONFLICT cout << explanation << " : " << fun.slack << endl; print_status( cout, fun ); cout << endl; #endif #if DEBUG cout << "conflict found " << conflict_ << endl; print_status( cout, fun ); #endif #if DEBUG_CHECK_STATUS check_status(); #endif return false; } } } else if ( atom->isCostBound() ) { #if DEBUG cout << "ct bound asserted " << atom << endl; #endif assert( nodemap_.find( atom ) != nodemap_.end() ); costfun & fun = *nodemap_[ atom ]; Enode * args = atom->getCdr(); Enode * val = args->getCdr()->getCar(); assert( val->isConstant() ); #if DEBUG cout << atom->get2nd() << endl; #endif const codomain & value = atom->get2nd()->getValue(); if ( negated ) { #if DEBUG cout << "ct bound asserted negatively " << atom << endl; #endif if ( ( !fun.lowerbound.empty() && get_bound( fun.lowerbound.top() ) < value ) || fun.lowerbound.empty() ) { #if DEBUG cout << "ct new lower bound " << atom << endl; #endif fun.lowerbound.push( atom ); undo_ops_.push( undo_op( REMOVE_LBOUND, &fun ) ); if ( fun.incurred + fun.slack < get_bound( fun.lowerbound.top() ) ) { conflict_ = atom; codomain potential = fun.incurred + fun.slack; for ( costfun::nodes_t::iterator it = fun.assigned.begin(); it != fun.assigned.end(); ++it ) { incurnode * node = *it; #if ELIM_REDUNDANT if ( node->atom->getPolarity() != l_False ) { continue; } if ( potential + node->cost < get_bound( fun.lowerbound.top() ) ) { potential += node->cost; continue; } #endif if ( node->atom->getPolarity() == l_False ) { explanation.push_back( node->atom ); } } assert( find( explanation.begin(), explanation.end(), conflict_ ) == explanation.end() ); explanation.push_back( conflict_ ); assert( potential < get_bound( fun.lowerbound.top() ) ); assert( find( explanation.begin(), explanation.end(), conflict_ ) != explanation.end() ); #if DEBUG_CONFLICT cout << explanation << " : " << fun.slack << endl; print_status( cout, fun ); cout << endl; #endif #if DEBUG cout << "conflict found " << conflict_ << endl; print_status( cout, fun ); #endif #if DEBUG_CHECK_STATUS check_status(); #endif return false; } } } else { #if DEBUG cout << "ct bound asserted positively " << atom << endl; #endif if ( ( !fun.upperbound.empty() && get_bound( fun.upperbound.top() ) > value ) || fun.upperbound.empty() ) { #if DEBUG cout << "ct new upper bound " << atom << endl; #endif fun.upperbound.push( atom ); undo_ops_.push( undo_op( REMOVE_UBOUND, &fun ) ); if ( fun.incurred >= get_bound( fun.upperbound.top() ) ) { conflict_ = atom; codomain incurred = fun.incurred; for ( costfun::nodes_t::iterator it = fun.assigned.begin(); it != fun.assigned.end(); ++it ) { incurnode * node = *it; #if ELIM_REDUNDANT if ( node->atom->getPolarity() != l_True ) { continue; } if ( incurred - node->cost >= get_bound( fun.upperbound.top() ) ) { incurred -= node->cost; continue; } #endif if ( node->atom->getPolarity() == l_True ) { explanation.push_back( node->atom ); } } assert( find( explanation.begin(), explanation.end(), conflict_ ) == explanation.end() ); assert( incurred >= get_bound( fun.upperbound.top() ) ); explanation.push_back( conflict_ ); assert( find( explanation.begin(), explanation.end(), conflict_ ) != explanation.end() ); #if DEBUG_CONFLICT cout << " " << explanation << " : " << fun.slack << endl; print_status( cout, fun ); cout << endl; #endif #if DEBUG cout << "conflict found " << conflict_ << endl; print_status( cout, fun ); #endif #if DEBUG_CHECK_STATUS check_status(); #endif return false; } } } if ( !fun.lowerbound.empty() && !fun.upperbound.empty() && get_bound( fun.lowerbound.top() ) >= get_bound( fun.upperbound.top() ) ) { conflict_ = atom; explanation.push_back( fun.lowerbound.top() ); explanation.push_back( fun.upperbound.top() ); #if DEBUG_CONFLICT cout << " " << explanation << " : " << fun.slack << endl; print_status( cout, fun ); cout << endl; #endif #if DEBUG cout << "conflict found " << conflict_ << endl; print_status( cout, fun ); #endif #if DEBUG_CHECK_STATUS check_status(); #endif return false; } } else { #if DEBUG cout << "ct unrecognized " << atom << endl; #endif } #if 1 { // Deduction costfun & fun = *nodemap_[ atom ]; if ( !fun.upperbound.empty() && fun.lowerbound.empty() && fun.unassigned.last && get_bound( fun.upperbound.top() ) <= fun.unassigned.last->cost + fun.incurred && !fun.unassigned.last->atom->isDeduced() ) { #if DEBUG cout << "deducing !" << fun.unassigned.last->atom << endl; #endif fun.unassigned.last->atom->setDeduced( l_False, id ); deductions.push_back( fun.unassigned.last->atom ); } else if ( !fun.lowerbound.empty() && fun.upperbound.empty() && fun.unassigned.last && get_bound( fun.lowerbound.top() ) > fun.incurred + fun.slack - fun.unassigned.last->cost && !fun.unassigned.last->atom->isDeduced() ) { #if DEBUG cout << "deducing " << fun.unassigned.last->atom << endl; #endif fun.unassigned.last->atom->setDeduced( l_True, id ); deductions.push_back( fun.unassigned.last->atom ); } else if ( !fun.upperbound.empty() && !fun.lowerbound.empty() && fun.unassigned.last && get_bound( fun.lowerbound.top() ) +1 == get_bound( fun.upperbound.top() ) ) { if ( fun.unassigned.last->cost == fun.slack && fun.incurred + fun.unassigned.last->cost == get_bound( fun.lowerbound.top() ) && fun.incurred + fun.slack - fun.unassigned.last->cost < get_bound( fun.lowerbound.top() ) ) { #if DEBUG cout << "deducing " << fun.unassigned.last->atom << endl; print_status( cout, fun ); #endif fun.unassigned.last->atom->setDeduced( l_True, 0 ); deductions.push_back( fun.unassigned.last->atom ); } } } #endif #if DEBUG_CHECK_STATUS check_status(); #endif return true; }
// ∀a, i, e, j, f. ( i = j → W ( W ( a, i, e ), j, f ) = W ( a, j, f ) ) void Egraph::WoWEqAxiom( Enode * wow ) { assert( false ); Enode * wowArray = wow->get1st( ); Enode * a = wowArray->get1st( ); Enode * i = wowArray->get2nd( ); Enode * e = wowArray->get3rd( ); Enode * j = wow->get2nd( ); Enode * f = wow->get3rd( ); assert( wowArray->isDTypeArray( ) ); assert( a->isDTypeArray( ) ); assert( i->isDTypeArrayIndex( ) ); assert( e->isDTypeArrayElement( ) ); assert( j->isDTypeArrayIndex( ) ); assert( f->isDTypeArrayElement( ) ); //i,j not coincident if( i != j ) { // create term W(a,j,f) Enode * store = mkStore( a, j, f ); #ifdef PRODUCE_PROOF if ( config.gconfig.print_inter > 0 ) { const uint64_t shared = getIPartitions( a ) & getIPartitions( j ) & getIPartitions( f ); // Mixed can't be one at this point assert( shared != 1 ); // Set AB-mixed partition if no intersection if ( shared == 0 ) setIPartitions( store, 1 ); // Otherwise they share something else setIPartitions( store, shared ); } #endif // add clause IF i=j THEN W(W(a,i,e),j,f)=W(a,j,f) // that is (NOT(i=j) OR W(W(a,i,e),j,f)=W(a,j,f)) vector< Enode * > v; Enode * lit1_pos = mkEq( cons( i, cons( j ) ) ); Enode * lit1 = mkNot( cons( lit1_pos ) ); #ifdef PRODUCE_PROOF if ( config.gconfig.print_inter > 0 ) { const uint64_t shared = getIPartitions( i ) & getIPartitions( j ); // Mixed can't be one at this point assert( shared != 1 ); // Set AB-mixed partition if no intersection if ( shared == 0 ) { setIPartitions( lit1_pos, 1 ); setIPartitions( lit1, 1 ); } // Otherwise they share something else { setIPartitions( lit1_pos, shared ); setIPartitions( lit1, shared ); } } #endif Enode * lit2 = mkEq( cons( wow, cons( store ) ) ); #ifdef PRODUCE_PROOF if ( config.gconfig.print_inter > 0 ) { const uint64_t shared = getIPartitions( wow ) & getIPartitions( store ); // Mixed can't be one at this point assert( shared != 1 ); // Set AB-mixed partition if no intersection if ( shared == 0 ) setIPartitions( lit2, 1 ); // Otherwise they share something else setIPartitions( lit2, shared ); } #endif v.push_back( lit1 ); v.push_back( lit2 ); #ifdef ARR_VERB cout << "Axiom WoW= -> " << "(or " << lit1 << " " << lit2 << " )" << endl; #endif splitOnDemand( v, id ); handleArrayAssertedAtomTerm( store ); } }
void Egraph::handleArrayMerge( Enode * x, Enode * y ) { assert( ( x->isDTypeArray( ) && y->isDTypeArray( ) ) || ( x->isDTypeArrayElement( ) && y->isDTypeArrayElement( ) ) ); vector< Enode * > xSelUsers, xStoUsers; getUsers( x, xSelUsers, xStoUsers ); vector<Enode * >::iterator xSelUsersIt; vector<Enode * >::iterator xStoUsersIt; vector< Enode * > ySelUsers, yStoUsers; getUsers( y, ySelUsers, yStoUsers ); vector<Enode * >::iterator ySelUsersIt; vector<Enode * >::iterator yStoUsersIt; #ifdef ARR_VERB_POSTMERGE cout << endl << "Getting x and y equivalence class users: " << endl; cout << "Equivalence class of x is: " << endl; Enode * aux=x; do { cout << aux << " "; aux=aux->getNext(); } while(aux!=x); cout << endl << "Here are x class select users: " << endl; for ( xSelUsersIt = xSelUsers.begin( ); xSelUsersIt != xSelUsers.end( ); xSelUsersIt++ ) {cout << *xSelUsersIt << " ";} cout << endl << "Here are x class store users: " << endl; for ( xStoUsersIt = xStoUsers.begin( ); xStoUsersIt != xStoUsers.end( ); xStoUsersIt++ ) {cout << *xStoUsersIt << " ";} cout << endl << "Equivalence class of y is: " << endl; aux=y; do { cout << aux << " "; aux=aux->getNext(); } while(aux!=y); cout << endl << "Here are y class select users: " << endl; for ( ySelUsersIt = ySelUsers.begin( ); ySelUsersIt != ySelUsers.end( ); ySelUsersIt++ ) {cout << *ySelUsersIt << " ";} cout << endl << "Here are y class store users: " << endl; for ( yStoUsersIt = yStoUsers.begin( ); yStoUsersIt != yStoUsers.end( ); yStoUsersIt++ ) {cout << *yStoUsersIt << " ";} cout << endl << endl; #endif Enode * z, * zIndex; // , * zElement, * zArray, // TODO join all the cases together for more efficiency // NB x,y are elements of equivalence classes X,Y, we need to scan X or Y looking for store terms if( y->isDTypeArray() ) { // Case 1: x is b, y is W(a,i,e), exists z as R(b,j) // Scan all R(b,j) for ( xSelUsersIt = xSelUsers.begin( ) ; xSelUsersIt != xSelUsers.end( ) ; xSelUsersIt++ ) { z = * xSelUsersIt; zIndex = z->get2nd( ); // scan Y looking for store terms Enode * YElem = y; do { if( YElem->isStore( ) ) { #ifdef ARR_VERB cout << "Arrow down B: " << x << " W(A,I,E): " << YElem << " R(B,J): " << z << endl; #endif // create new term R(W(a,i,e),j) Enode * s_yelem = dynamicToStatic( YElem ); Enode * s_z2nd = dynamicToStatic( z->get2nd( ) ); Enode * select = mkSelect( s_yelem, s_z2nd ); #ifdef PRODUCE_PROOF if ( config.gconfig.print_inter > 0 ) { const uint64_t shared = getIPartitions( s_yelem ) & getIPartitions( s_z2nd ); // Mixed can't be one at this point assert( shared != 1 ); // Set AB-mixed partition if no intersection if ( shared == 0 ) setIPartitions( select, 1 ); // Otherwise they share something else setIPartitions( select, shared ); } #endif handleArrayAssertedAtomTerm( select ); } YElem = YElem->getNext( ); } while ( YElem != y ); } /*// Case 2: x is b, y is W(a,i,e), exists z as W(b,j,f) // Scan all W(b,j,f) for (xStoUsersIt=xStoUsers.begin(); xStoUsersIt<xStoUsers.end(); xStoUsersIt++) { z=*xStoUsersIt; zElement=z->get3rd(); zIndex=z->get2nd(); // create new term W(W(a,i,e),j,f) newSto=mkStore(y,zIndex,zElement,present); // TODO check if term already seen in a previous assertion on the current path // deduce clauses for the new store newArrayDed(newSto); }*/ } if( x->isDTypeArray() ) { // Case 1 reverse: y is b, x is W(a,i,e), exists z as R(b,j) // Scan all R(b,j) for ( ySelUsersIt = ySelUsers.begin( ) ; ySelUsersIt != ySelUsers.end( ) ; ySelUsersIt++ ) { z = *ySelUsersIt; zIndex = z->get2nd( ); // scan X looking for store terms Enode * XElem = x; do { if( XElem->isStore( ) ) { #ifdef ARR_VERB cout << "Arrow down B: " << XElem << " W(A,I,E): " << y << " R(B,J): " << z << endl; #endif // Create new term R(W(a,i,e),j) from static version Enode * s_xelem = dynamicToStatic( XElem ); Enode * s_z2nd = dynamicToStatic( z->get2nd( ) ); Enode * select = mkSelect( s_xelem, s_z2nd ); #ifdef PRODUCE_PROOF if ( config.gconfig.print_inter > 0 ) { const uint64_t shared = getIPartitions( s_xelem ) & getIPartitions( s_z2nd ); // Mixed can't be one at this point assert( shared != 1 ); // Set AB-mixed partition if no intersection if ( shared == 0 ) setIPartitions( select, 1 ); // Otherwise they share something else setIPartitions( select, shared ); } #endif handleArrayAssertedAtomTerm( select ); } XElem = XElem->getNext( ); } while ( XElem != x ); } /*// Case 2 reverse: y is a term b of type array, x is a Store W(a,i,e), exists z as W(b,j,f) // Scan all W(b,j,f) for (yStoUsersIt=yStoUsers.begin(); yStoUsersIt<yStoUsers.end(); yStoUsersIt++) { z=*yStoUsersIt; zElement=z->get3rd(); zIndex=z->get2nd(); // create new term W(W(a,i,e),j,f) newSto=mkStore(y,zIndex,zElement,present); // TODO check if term already seen in a previous assertion on the current path // deduce clauses for the new store newArrayDed(newSto); }*/ } Enode * w; if( x->isDTypeArray( ) && y->isDTypeArray( ) ) { //Case 3: x is a term a of type array, y is a term b of type array, exist z as W(a,i,e) and w as R(b,j) //scan all W(a,i,e) and R(b,j) for ( ySelUsersIt = ySelUsers.begin( ) ; ySelUsersIt < ySelUsers.end( ) ; ySelUsersIt++ ) { for ( xStoUsersIt = xStoUsers.begin( ) ; xStoUsersIt < xStoUsers.end( ) ; xStoUsersIt++ ) { w = *ySelUsersIt; z = *xStoUsersIt; #ifdef ARR_VERB cout << "Arrow up A: " << x << " B: " << y << " W(A,I,E): " << z << " R(B,J): " << w << endl; #endif // create new term R(W(a,i,e),j) Enode * s_z = dynamicToStatic( z ); Enode * s_w2nd = dynamicToStatic( w->get2nd( ) ); Enode * select = mkSelect( s_z, s_w2nd ); #ifdef PRODUCE_PROOF if ( config.gconfig.print_inter > 0 ) { const uint64_t shared = getIPartitions( s_z ) & getIPartitions( s_w2nd ); // Mixed can't be one at this point assert( shared != 1 ); // Set AB-mixed partition if no intersection if ( shared == 0 ) setIPartitions( select, 1 ); // Otherwise they share something else setIPartitions( select, shared ); } #endif handleArrayAssertedAtomTerm( select ); } } //Case 3 reverse: y is a term a of type array, x is a term b of type array, exist z as W(a,i,e) and w as R(b,j) //scan all W(a,i,e) and R(b,j) for ( xSelUsersIt = xSelUsers.begin( ) ; xSelUsersIt < xSelUsers.end( ) ; xSelUsersIt++ ) { for ( yStoUsersIt = yStoUsers.begin( ) ; yStoUsersIt < yStoUsers.end( ) ; yStoUsersIt++) { w = *xSelUsersIt; z = *yStoUsersIt; #ifdef ARR_VERB cout << "Arrow up A: " << x << " B: " << y << " W(A,I,E): "<< z << " R(B,J): " << w << endl; #endif // create new term R(W(a,i,e),j) Enode * s_z = dynamicToStatic( z ); Enode * s_w2nd = dynamicToStatic( w->get2nd( ) ); Enode * select = mkSelect( s_z, s_w2nd ); #ifdef PRODUCE_PROOF if ( config.gconfig.print_inter > 0 ) { const uint64_t shared = getIPartitions( s_z ) & getIPartitions( s_w2nd ); // Mixed can't be one at this point assert( shared != 1 ); // Set AB-mixed partition if no intersection if ( shared == 0 ) setIPartitions( select, 1 ); // Otherwise they share something else setIPartitions( select, shared ); } #endif handleArrayAssertedAtomTerm( select ); } } } /*//Case 4: x is a term e of type element, y is a Select R(b,j), exists z as W(a,i,e) //scan all W(a,i,e) if(y->isSelect()) { for (xStoUsersIt=xStoUsers.begin(); xStoUsersIt<xStoUsers.end(); xStoUsersIt++) { z=*xStoUsersIt; zArray=z->get1st(); zIndex=z->get2nd(); // create new term W(a,i,R(b,j)) newSto=mkStore(zArray,zIndex,y); // TODO check if term already seen in a previous assertion on the current path // deduce clauses for the new store newArrayDed(newSto); } } //Case 4 reverse: y is a term e of type element, x is a Select R(b,j), exists z as W(a,i,e) //scan all W(a,i,e) if(x->isSelect()) { for (yStoUsersIt=yStoUsers.begin(); yStoUsersIt<yStoUsers.end(); yStoUsersIt++) { z=*yStoUsersIt; zArray=z->get1st(); zIndex=z->get2nd(); // create new term W(a,i,R(b,j)) newSto=mkStore(zArray,zIndex,x); // TODO check if term already seen in a previous assertion on the current path // deduce clauses for the new store newArrayDed(newSto); } }*/ }
Enode * ExpandITEs::doit( Enode * formula ) { assert( formula ); list< Enode * > new_clauses; vector< Enode * > unprocessed_enodes; egraph.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 ( 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 unprocessed // if ( egraph.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; // // At this point, every child has been processed // char def_name[ 32 ]; if ( enode->isIte( ) ) { // // Retrieve arguments // Enode * i = egraph.valDupMap1( enode->get1st( ) ); Enode * t = egraph.valDupMap1( enode->get2nd( ) ); Enode * e = egraph.valDupMap1( enode->get3rd( ) ); Enode * not_i = egraph.mkNot( egraph.cons( i ) ); // // Generate variable symbol // sprintf( def_name, ITE_STR, enode->getId( ) ); Snode * sort = enode->getLastSort( ); egraph.newSymbol( def_name, sort ); // // Generate placeholder // result = egraph.mkVar( def_name ); // // Generate additional clauses // Enode * eq_then = egraph.mkEq( egraph.cons( result , egraph.cons( t ) ) ); Enode * eq_else = egraph.mkEq( egraph.cons( result , egraph.cons( e ) ) ); new_clauses.push_back( egraph.mkOr( egraph.cons( not_i , egraph.cons( eq_then ) ) ) ); new_clauses.push_back( egraph.mkOr( egraph.cons( i , egraph.cons( eq_else ) ) ) ); } else { result = egraph.copyEnodeEtypeTermWithCache( enode ); } assert( result ); assert( egraph.valDupMap1( enode ) == NULL ); egraph.storeDupMap1( enode, result ); } Enode * new_formula = egraph.valDupMap1( formula ); assert( new_formula ); egraph.doneDupMap1( ); new_clauses.push_back( new_formula ); return egraph.mkAnd( egraph.cons( new_clauses ) ); }
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; }