示例#1
0
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;

}
示例#2
0
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;
}