void CostSolver::check_status() { #ifndef NDEBUG for ( costfuns_t::iterator it = costfuns_.begin(); it != costfuns_.end(); ++it ) { costfun & fun = **it; codomain slack = 0; for ( incurnode * n=fun.unassigned.head; n; n=n->next ) { assert( !n->atom->hasPolarity() ); if ( n->next ) { assert( n != n->next ); if ( n->cost > n->next->cost ) { cout << n->cost << " > " << n->next->cost << endl; } assert( n->cost <= n->next->cost ); assert( n->next->prev == n ); } if ( n->prev ) { assert( n->prev != n ); assert( n->prev->next == n ); } slack += get_incurred( n->atom ); } assert( slack == fun.slack ); { codomain incurred = 0; for ( costfun::nodes_t::iterator it = fun.assigned.begin(); it != fun.assigned.end(); ++it ) { incurnode * node = *it; assert( node->atom->hasPolarity() ); if ( node->atom->getPolarity() == l_True ) { incurred += get_incurred( node->atom ); } } if ( fun.incurred != incurred ) { if ( conflict_ ) { cout << "conflict = " << conflict_ << endl; } cout << "incurred = " << incurred << endl; print_status( cout, fun ); } assert( fun.incurred == incurred ); } } if ( conflict_ ) { cout << "ct conflict " << conflict_ << endl; costfun & fun = *nodemap_.find( conflict_ )->second; codomain incurred = 0; Enode * upper_bound = 0; Enode * lower_bound = 0; for ( vector<Enode*>::iterator it = explanation.begin(); it != explanation.end(); ++it ) { Enode * atom = *it; assert( atom->hasPolarity() ); if ( atom->isCostIncur() ) { if ( atom->getPolarity() == l_True ) { incurred += get_incurred( atom ); } } if ( atom->isCostBound() ) { if ( atom->getPolarity() == l_True ) { assert( !upper_bound ); upper_bound = atom; } else { assert( !lower_bound ); assert( atom->getPolarity() == l_False ); lower_bound = atom; } } } if ( !fun.lowerbound.empty() && fun.upperbound.empty() ) { assert( fun.incurred + fun.slack < get_bound( fun.lowerbound.top() ) ); } if ( fun.lowerbound.empty() && !fun.upperbound.empty() ) { assert( fun.incurred >= get_bound( fun.upperbound.top() ) ); assert( incurred >= get_bound( upper_bound ) ); } } #endif }
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; }