CNode* VariableEliminator::remove_eq_var_with_no_parents(Clause& cl, VariableTerm* evar) { set<EqLeaf*> to_delete; set<EqLeaf*>::iterator it = cl.neg_eq.begin(); for(; it!= cl.neg_eq.end(); it++) { EqLeaf* eq = *it; Term* lhs = eq->get_lhs(); Term* rhs = eq->get_rhs(); if(lhs->contains_term(evar) || rhs->contains_term(evar)) to_delete.insert(eq); } for(it=to_delete.begin(); it!= to_delete.end(); it++) { cl.neg_eq.erase(*it); } CNode* new_node = cl.to_cnode(); return new_node; }
CNode* VariableEliminator::eliminate_var_conjunct(CNode* node, VariableTerm* evar) { if(DEBUG) { cout << "IN ELIMINATE VAR FROM CONJUNCT " << node->to_string()<< endl; cout << "Trying to eliminate: " << evar->to_string() <<endl; } int initial_count = fresh_var_counter; assert(node->is_conjunct()); Clause cl(node); map<Term*, Term*> denestings; cl.denest( &denestings); if(DEBUG) { cout << "DENESTINGS: " << endl; map<Term*, Term*>::iterator it = denestings.begin(); for(; it!= denestings.end(); it++) { cout << "\t " << it->first->to_string() << "-> " << it->second->to_string() << endl; } } ClauseSolve cs(&cl, NULL); bool res = cs.is_sat(); /* * If the clause is UNSAT, the SNC is false. * We call sat to ensure that all relevant interactions * are propagated between the ILP and EQ domains. After calling * sat, eq_members, var_to_cols etc are properly initialized. */ if(!res){ return False::make(); } Term* rep = cs.find_representative(evar); Term* valid_rep = NULL; if(rep!=NULL && !rep->contains_term(evar) && denestings.count(rep)==0) { valid_rep = rep; } else { set<Term*>& eq_class = cs.eq_members[rep]; set<Term*>::iterator it = eq_class.begin(); for(; it!= eq_class.end(); it++) { Term* cur_t = *it; if(!cur_t->contains_term(evar)&&denestings.count(cur_t)==0){ valid_rep = cur_t; break; } } } /* * We found one member in the equivalence class of this variable * that does not contain that variable. */ if(valid_rep != NULL) { map<Term*, Term*> subs; subs[evar] = valid_rep; CNode* res = node->substitute(subs); node = node->substitute(denestings); return res; } set<FunctionTerm*> direct_parents; get_direct_parents(evar, direct_parents, cs.eq_members); if(!over_approximate) { if(direct_parents.size() > 0) return False::make(); } /* * Base case: If this term does not contain any parent terms, * eliminate it from the ILP domain */ if(direct_parents.size() == 0 && cs.ilp_vars.count(evar->get_var_id()) > 0 ){ set<CNode*> mod_constraints; if(DEBUG) { cout << "ELIMINATING FROM ILP: " << cl.to_string("&") << endl; } CNode* res= eliminate_var_from_ilp_domain(cl, evar, mod_constraints); if(DEBUG) { cout << "AFTER ELIMINATING FROM ILP: " << res->to_string() << endl; } res = eliminate_denestings(res, denestings, evar, initial_count, false); return res; } else if(direct_parents.size() == 0) { CNode* res = remove_eq_var_with_no_parents(cl, evar); return eliminate_denestings(res, denestings, evar, initial_count, false); } /* * We want to replace each function term in which the variable appears with * a fresh term u, u' etc. and then introduce conditional equality * constraints. * For example, if we have f(x, a) = f(x, b), introduce a=b->u1=u2 * where u1 and u2 are the replacements for f(x,a) and f(x,b) respectively. */ map<VariableTerm*, FunctionTerm*> fresh_vars_to_functions; map<FunctionTerm*, VariableTerm*> functions_to_fresh_vars; /* * A map from function id's (e.g. f) to all the function terms containing x * as an argument to this function id. */ map<int, set<FunctionTerm*> > function_id_to_functions; { introduce_fresh_vars_for_function_terms(cl, evar, direct_parents, fresh_vars_to_functions, functions_to_fresh_vars, function_id_to_functions); if(DEBUG) { cout << "FUNCTION ID TO FUNCTIONS: " << endl; map<int, set<FunctionTerm*> >::iterator it2 = function_id_to_functions.begin(); for(; it2 != function_id_to_functions.end(); it2++){ cout << "Function: " << CNode::get_varmap().get_name(it2->first); set<FunctionTerm*>::iterator it3 = it2->second.begin(); for(; it3!= it2->second.end(); it3++) { cout << "\t " << (*it3)->to_string() << endl; } } } } /* * Introduce conditional equalities * First, introduce conditional equalities between u terms */ map<CNode*, CNode*> conditional_equalities; map<int, set<FunctionTerm*> >::iterator it = function_id_to_functions.begin(); for(; it!= function_id_to_functions.end(); it++) { set<FunctionTerm*>& s1 = it->second; set<FunctionTerm*>::iterator it2 = s1.begin(); for(; it2!= s1.end(); it2++) { FunctionTerm* ft1 = *it2; set<FunctionTerm*>::iterator it3 = it2; it3++; for(; it3 != s1.end(); it3++) { set<CNode*> ops; FunctionTerm* ft2 = *it3; assert(ft1->get_args().size() == ft2->get_args().size()); for(unsigned int i=0; i< ft1->get_args().size(); i++) { Term* cur_arg1 = ft1->get_args()[i]; Term* cur_arg2 = ft2->get_args()[i]; if(cur_arg1 == evar && cur_arg2 == evar) continue; if(cur_arg1 == evar || cur_arg2 == evar) { if(cs.ilp_vars.count(evar->get_var_id()) == 0) continue; } CNode* eq = EqLeaf::make(cur_arg1, cur_arg2); ops.insert(eq); } if(ops.size() == 0) continue; CNode* precedent = Connective::make_and(ops); assert(functions_to_fresh_vars.count(ft1) > 0); assert(functions_to_fresh_vars.count(ft2) > 0); VariableTerm* fresh1 = functions_to_fresh_vars[ft1]; VariableTerm* fresh2 = functions_to_fresh_vars[ft2]; CNode* antecedent = EqLeaf::make(fresh1, fresh2); conditional_equalities[precedent] = antecedent; } } } /* * If the variable to be eliminated is a shared variable, also need to * add conditional equalities with non-u terms. */ if(cs.ilp_vars.count(evar->get_var_id()) > 0) { map<int, set<FunctionTerm*> > functions_in_clause; get_function_terms_in_clause(cl, functions_in_clause); it = function_id_to_functions.begin(); for(; it!= function_id_to_functions.end(); it++) { set<FunctionTerm*>& evar_terms = it->second; if(functions_in_clause.count(it->first)==0) continue; set<FunctionTerm*>& clause_terms = functions_in_clause[it->first]; set<FunctionTerm*>::iterator it2 = evar_terms.begin(); for(; it2 != evar_terms.end(); it2++) { FunctionTerm* ft1 = *it2; set<FunctionTerm*>::iterator it3 = clause_terms.begin(); for(; it3 != clause_terms.end(); it3++) { set<CNode*> ops; FunctionTerm* ft2 = *it3; assert(ft1->get_args().size() == ft2->get_args().size()); for(unsigned int i=0; i< ft1->get_args().size(); i++) { Term* cur_arg1 = ft1->get_args()[i]; Term* cur_arg2 = ft2->get_args()[i]; CNode* eq = EqLeaf::make(cur_arg1, cur_arg2); ops.insert(eq); } if(ops.size() == 0) continue; CNode* precedent = Connective::make_and(ops); assert(functions_to_fresh_vars.count(ft1) > 0); VariableTerm* fresh1 = functions_to_fresh_vars[ft1]; CNode* antecedent = EqLeaf::make(fresh1, ft2); conditional_equalities[precedent] = antecedent; } } } } if(DEBUG) { cout << "CONDITIONAL EQUALITIES: " << endl; map<CNode*, CNode*>::iterator it = conditional_equalities.begin(); for(; it!= conditional_equalities.end(); it++) { CNode* precedent = it->first; CNode* antecedent = it->second; cout << precedent->to_string() << " => " << antecedent->to_string() << endl; } } /* * Make the new formula anded with the conditional constraints */ set<CNode*> new_ops; CNode* original = cl.to_cnode(); new_ops.insert(original); map<CNode*, CNode*>::iterator cond_it = conditional_equalities.begin(); for(; cond_it != conditional_equalities.end(); cond_it++) { CNode* cur_cond = Connective::make_implies(cond_it->first, cond_it->second); new_ops.insert(cur_cond); } CNode* new_node = Connective::make_and(new_ops); new_node = eliminate_denestings(new_node, denestings, evar, initial_count, true); return new_node; }