diff options
author | Tuowen Zhao <ztuowen@gmail.com> | 2016-09-17 03:22:53 +0000 |
---|---|---|
committer | Tuowen Zhao <ztuowen@gmail.com> | 2016-09-17 03:22:53 +0000 |
commit | 75ff98e4d65862ff5b36b533b4f6e3ea71ede1d5 (patch) | |
tree | 498ac06b4cf78568b807fafd2619856afff69c28 /omegalib/omega_lib/src/pres_conj.cc | |
parent | 29efa7b1a0d089e02a70f73f348f11878955287c (diff) | |
download | chill-75ff98e4d65862ff5b36b533b4f6e3ea71ede1d5.tar.gz chill-75ff98e4d65862ff5b36b533b4f6e3ea71ede1d5.tar.bz2 chill-75ff98e4d65862ff5b36b533b4f6e3ea71ede1d5.zip |
cmake build
Diffstat (limited to 'omegalib/omega_lib/src/pres_conj.cc')
-rw-r--r-- | omegalib/omega_lib/src/pres_conj.cc | 1460 |
1 files changed, 1460 insertions, 0 deletions
diff --git a/omegalib/omega_lib/src/pres_conj.cc b/omegalib/omega_lib/src/pres_conj.cc new file mode 100644 index 0000000..f3f458d --- /dev/null +++ b/omegalib/omega_lib/src/pres_conj.cc @@ -0,0 +1,1460 @@ +/***************************************************************************** + Copyright (C) 1994-2000 the Omega Project Team + Copyright (C) 2005-2011 Chun Chen + All Rights Reserved. + + Purpose: + class Conjunct. + + Notes: + + History: +*****************************************************************************/ + +#include <omega/omega_core/oc.h> +#include <omega/pres_conj.h> +#include <omega/pres_cmpr.h> +#include <omega/Relation.h> +#include <omega/omega_i.h> +#include <set> + +namespace omega { + +int NR_CONJUNCTS, MAX_CONJUNCTS; + +/* + * Make a new wildcard variable, return WC number. + * Should be static to this file, but must be a friend of conjunct. + */ +int new_WC(Conjunct *nc, Problem *) { + Variable_ID wc = nc->declare(); + int wc_no = nc->map_to_column(wc); + return(wc_no); +} + + +const char* get_var_name(unsigned int col, void * void_conj) { +#if defined PRINT_COLUMN_NUMBERS + static char scum[512]; +#endif + Conjunct *c = (Conjunct *) void_conj; + if (col == 0) + return 0; + Variable_ID v = c->mappedVars[col]; + assert(v!=0); +#if defined PRINT_COLUMN_NUMBERS + strcpy(scum, v->char_name()); + sprintf(scum + strlen(scum), "(%d)", col); + return scum; +#endif + return v->char_name(); +} + +void Conjunct::promise_that_ub_solutions_exist(Relation &R) { +#ifndef NDEBUG + Relation verify=Relation(R, this); + assert(verify.is_upper_bound_satisfiable()); +#endif + verified = true; +} + + +int Conjunct::max_ufs_arity_of_set() { + int ma = 0, a; + for (Variable_ID_Iterator v(mappedVars); v; v++) + if ((*v)->kind() == Global_Var && (*v)->function_of() == Set_Tuple + && query_variable_used(*v)) { + a = (*v)->get_global_var()->arity(); + if (a > ma) + ma = a; + } + return ma; +} + + +int Conjunct::max_ufs_arity_of_in() { + int ma = 0, a; + for (Variable_ID_Iterator v(mappedVars); v; v++) + if ((*v)->kind() == Global_Var && (*v)->function_of() == Input_Tuple + && query_variable_used(*v)) { + a = (*v)->get_global_var()->arity(); + if (a > ma) + ma = a; + } + return ma; +} + + +int Conjunct::max_ufs_arity_of_out() { + int ma = 0, a; + for (Variable_ID_Iterator v(mappedVars); v; v++) + if ((*v)->kind() == Global_Var && (*v)->function_of() == Output_Tuple + && query_variable_used(*v)) { + a = (*v)->get_global_var()->arity(); + if (a > ma) + ma = a; + } + return ma; +} + + +bool Conjunct::is_unknown() const { + assert(problem || comp_problem); + return !exact && ((problem && problem->nEQs==0 && problem->nGEQs==0) || + (comp_problem && comp_problem->no_constraints())); +} + + +/* + * Remove black constraints from the problem. + * Make all the remaining red constraints black. + */ +void Conjunct::rm_color_constrs() { + int geqs = 0, eqs = 0; + + possible_leading_0s = -1; + guaranteed_leading_0s = -1; + leading_dir = 0; + + for(int i=0; i<problem->nGEQs; i++) { + if(problem->GEQs[i].color) { + if(geqs!=i) + eqnncpy(&problem->GEQs[geqs], &problem->GEQs[i], problem->nVars); + problem->GEQs[geqs].color = EQ_BLACK; + geqs++; + } + } + problem->nGEQs = geqs; + + for(int i=0; i<problem->nEQs; i++) { + if(problem->EQs[i].color) { + if(eqs!=i) + eqnncpy(&problem->EQs[eqs], &problem->EQs[i], problem->nVars); + problem->EQs[eqs].color = EQ_BLACK; + eqs++; + } + } + problem->nEQs = eqs; +} + + + +// +// Conjunct constructors. +// +Conjunct::Conjunct() : + F_Declaration(NULL, NULL), + mappedVars(0), + n_open_constraints(0), + cols_ordered(false), + simplified(false), + verified(false), + guaranteed_leading_0s(-1), + possible_leading_0s(-1), + leading_dir(0), + exact(true), + r_constrs(0) { + NR_CONJUNCTS++; + if (NR_CONJUNCTS>MAX_CONJUNCTS) MAX_CONJUNCTS = NR_CONJUNCTS; + problem = new Problem; + comp_problem = NULL; + problem->get_var_name = get_var_name; + problem->getVarNameArgs = (void *) this; +} + + +Conjunct::Conjunct(Formula *f, Rel_Body *r) : + F_Declaration(f,r), + mappedVars(0), + n_open_constraints(0), + cols_ordered(false), + simplified(false), + verified(false), + guaranteed_leading_0s(-1), + possible_leading_0s(-1), + leading_dir(0), + exact(true), + r_constrs(0) { + NR_CONJUNCTS++; + if (NR_CONJUNCTS>MAX_CONJUNCTS) MAX_CONJUNCTS = NR_CONJUNCTS; + problem = new Problem; + comp_problem = NULL; + problem->get_var_name = get_var_name; + problem->getVarNameArgs = (void *) this ; +} + +void internal_copy_conjunct(Conjunct* to, Conjunct* fr); + +// +// Copy Conjunct. +// +Conjunct* Conjunct::copy_conj_diff_relation(Formula *parent, Rel_Body *rel_body) { + Conjunct *new_conj; + if(problem && comp_problem==NULL) { + new_conj = new Conjunct(parent, rel_body); + internal_copy_conjunct(new_conj, this); + } + else if (problem==NULL && comp_problem) { + /* copy compressed conjunct */ + assert(0 && "copy compressed conjunct"); + new_conj = 0; + } + else { + assert(0 && "problem == NULL"); + new_conj = 0; + } + return new_conj; +} + + +void internal_copy_conjunct(Conjunct* to, Conjunct* fr) { + copy_conj_header(to, fr); + + // + // We repeat part of what is done by copy_conj_header(to, fr) by + // calling Problem::operator=(const Problem &). + // copy_conj_header should go away, but there is some code that still needs + // it in negate_conj. + // + to->r_constrs = fr->r_constrs; + to->simplified = fr->simplified; + to->verified = fr->verified; + to->guaranteed_leading_0s = fr->guaranteed_leading_0s; + to->possible_leading_0s = fr->possible_leading_0s; + to->leading_dir = fr->leading_dir; + // the following duplicates some work of the "copy_conj_header" brain damage + *to->problem = *fr->problem; + to->problem->getVarNameArgs = (void *)to; // important +} + + +// +// Copy Conjunct variable declarations +// and problem parameters but not problem itself. +// +void copy_conj_header(Conjunct* to, Conjunct* fr) { + free_var_decls(to->myLocals); to->myLocals.clear(); + + copy_var_decls(to->myLocals, fr->myLocals); + to->mappedVars = fr->mappedVars; + to->remap(); + reset_remap_field(fr->myLocals); + + to->cols_ordered = fr->cols_ordered; + to->r_constrs = fr->r_constrs; + to->simplified = fr->simplified; + to->verified = fr->verified; + to->guaranteed_leading_0s = fr->guaranteed_leading_0s; + to->possible_leading_0s = fr->possible_leading_0s; + to->leading_dir = fr->leading_dir; + to->n_open_constraints = fr->n_open_constraints; + to->exact=fr->exact; + + Problem *fp = fr->problem; + Problem *tp = to->problem; + tp->nVars = fp->nVars; + tp->safeVars = fp->safeVars; + tp->variablesInitialized = fp->variablesInitialized; + tp->variablesFreed = fp->variablesFreed; + for(int i=1; i<=maxVars; i++) { // only need nVars of var + tp->forwardingAddress[i] = fp->forwardingAddress[i]; + tp->var[i] = fp->var[i]; + } + to->problem->get_var_name = get_var_name; + to->problem->getVarNameArgs = (void *)to ; +} + + +void Conjunct::reverse_leading_dir_info() { + leading_dir *= -1; +} + + +void Conjunct::enforce_leading_info(int guaranteed, int possible, int dir) { + skip_finalization_check++; + guaranteed_leading_0s = guaranteed; + + int d = min(relation()->n_inp(),relation()->n_out()); + + assert(0 <= guaranteed); + assert(guaranteed <= possible); + assert(possible <= d); + + for(int i = 1; i <= guaranteed; i++) { + EQ_Handle e = add_EQ(); + e.update_coef_during_simplify(input_var(i), -1); + e.update_coef_during_simplify(output_var(i), 1); + e.finalize(); + } + + + if (guaranteed == possible && guaranteed >= 0 && possible+1 <= d && dir) { + GEQ_Handle g = add_GEQ(); + if (dir > 0) { + g.update_coef_during_simplify(input_var(possible+1), -1); + g.update_coef_during_simplify(output_var(possible+1), 1); + } + else { + g.update_coef_during_simplify(input_var(possible+1), 1); + g.update_coef_during_simplify(output_var(possible+1), -1); + } + g.update_const_during_simplify(-1); + g.finalize(); + possible_leading_0s = possible; + leading_dir = dir; + } + else { + possible_leading_0s = d; + leading_dir = 0; + } + + skip_finalization_check--; +#if ! defined NDEBUG + assert_leading_info(); +#endif +} + + +void Conjunct::invalidate_leading_info(int changed) { + if (changed == -1) { + guaranteed_leading_0s = possible_leading_0s = -1; + leading_dir = 0; + } + else { + int d = min(relation()->n_inp(), relation()->n_out()); + assert(1 <= changed && changed <= d); + if (possible_leading_0s == changed -1) { + possible_leading_0s = d; + } + guaranteed_leading_0s = min(guaranteed_leading_0s,changed-1); + } +#if ! defined NDEBUG + assert_leading_info(); +#endif +} + + +int Conjunct::leading_dir_valid_and_known() { + if (relation()->is_set()) { + return 0; + } + // if we know leading dir, we can rule out extra possible 0's + assert(leading_dir == 0 || + possible_leading_0s == guaranteed_leading_0s); + + return (possible_leading_0s == guaranteed_leading_0s && + possible_leading_0s >= 0 && + possible_leading_0s < min(relation()->n_inp(),relation()->n_out()) + && leading_dir); +} + + +#if ! defined NDEBUG +void Conjunct::assert_leading_info() { + if (relation()->is_set()) { + return; + } + + int d = min(relation()->n_inp(), relation()->n_out()); + + if ( guaranteed_leading_0s == -1 + && guaranteed_leading_0s == possible_leading_0s) + assert(leading_dir == 0); + + if(leading_dir != 0 && + possible_leading_0s != guaranteed_leading_0s) { + use_ugly_names++; + prefix_print(DebugFile); + use_ugly_names--; + } + + assert(leading_dir == 0 || possible_leading_0s == guaranteed_leading_0s); + + assert(possible_leading_0s <= d && guaranteed_leading_0s <= d); + + assert(possible_leading_0s == -1 || guaranteed_leading_0s <= possible_leading_0s); + + // check that there must be "guaranteed_leading_0s" 0s + int carried_level; + for (carried_level = 1; carried_level <= guaranteed_leading_0s; carried_level++) { + Variable_ID in = input_var(carried_level), + out = output_var(carried_level); + coef_t lb, ub; + bool guar; + query_difference(out, in, lb, ub, guar); + if (lb != 0 && ub != 0) { + // probably "query_difference" is just approximate + // add the negation of leading_dir and assert that + // the result is unsatisfiable; + // add in > out (in-out-1>=0) and assert unsatisfiable. + + Conjunct *test = copy_conj_same_relation(); + test->problem->turnRedBlack(); + skip_finalization_check++; + + GEQ_Handle g = test->add_GEQ(); + g.update_coef_during_simplify(in, -1); + g.update_coef_during_simplify(out, 1); + g.update_const_during_simplify(-1); + g.finalize(); + assert(!simplify_conj(test, true, 0, 0)); + // test was deleted by simplify_conj, as it was FALSE + + test = copy_conj_same_relation(); + test->problem->turnRedBlack(); + g = test->add_GEQ(); + g.update_coef_during_simplify(in, 1); + g.update_coef_during_simplify(out, -1); + g.update_const_during_simplify(-1); + g.finalize(); + assert(!simplify_conj(test, true, 0, 0)); + // test was deleted by simplify_conj, as it was FALSE + + skip_finalization_check--; + } + } + + carried_level = possible_leading_0s+1; + + // check that there can't be another + if (guaranteed_leading_0s == possible_leading_0s + && possible_leading_0s >= 0 && + carried_level <= min(relation()->n_inp(), relation()->n_out())) { + Variable_ID in = input_var(carried_level), + out = output_var(carried_level); + coef_t lb, ub; + bool guar; + query_difference(out, in, lb, ub, guar); + if (lb <= 0 && ub >= 0) { + // probably "query_difference" is just approximate + // add a 0 and see if its satisfiable + + Conjunct *test = copy_conj_same_relation(); + test->problem->turnRedBlack(); + skip_finalization_check++; + + EQ_Handle e = test->add_EQ(); + e.update_coef_during_simplify(in, -1); + e.update_coef_during_simplify(out, 1); + e.finalize(); + assert(!simplify_conj(test, true, 0, 0)); + // test was deleted by simplify_conj, as it was FALSE + + skip_finalization_check--; + } + } + + // check leading direction info + if (leading_dir_valid_and_known()) { + Variable_ID in = input_var(guaranteed_leading_0s+1), + out = output_var(guaranteed_leading_0s+1); + coef_t lb, ub; + bool guar; + query_difference(out, in, lb, ub, guar); + if ((leading_dir < 0 && ub >= 0) || + (leading_dir > 0 && lb <= 0)) { + // probably "query_difference" is just approximate + // add the negation of leading_dir and assert that + // the result is unsatisfiable; + // eg for leading_dir = +1 (in must be < out), + // add in >= out (in-out>=0) and assert unsatisfiable. + + Conjunct *test = copy_conj_same_relation(); + test->problem->turnRedBlack(); + skip_finalization_check++; + + GEQ_Handle g = test->add_GEQ(); + g.update_coef_during_simplify(in, leading_dir); + g.update_coef_during_simplify(out, -leading_dir); + g.finalize(); + + assert(!simplify_conj(test, true, 0, 0)); + // test was deleted by simplify_conj, as it was FALSE + + skip_finalization_check--; + } + } +} +#endif + + +Variable_ID Conjunct::declare(Const_String s) { + return do_declare(s, Wildcard_Var); +} + +Variable_ID Conjunct::declare() { + return do_declare(Const_String(), Wildcard_Var); +} + +Variable_ID Conjunct::declare(Variable_ID v) { + return do_declare(v->base_name, Wildcard_Var); +} + +Conjunct* Conjunct::really_conjunct() { + return this; +} + + +Variable_ID_Tuple* Conjunct::variables() { + return &mappedVars; +} + +Stride_Handle Conjunct::add_stride(int step, int preserves_level) { + assert_not_finalized(); + Variable_ID wild = declare(); + int c; + c = problem->newEQ(); + simplified = false; + verified = false; + if (! preserves_level) { + if (leading_dir == 0) + possible_leading_0s = -1; + // otherwise we must still have leading_dir, and thus no more 0's + } + problem->EQs[c].color = EQ_BLACK; + eqnnzero(&problem->EQs[c],problem->nVars); + n_open_constraints++; + EQ_Handle h = EQ_Handle(this, c); + h.update_coef(wild,step); + return h; +} + +// This should only be used to copy constraints from simplified relations, +// i.e. there are no quantified variables in c except wildcards. +EQ_Handle Conjunct::add_EQ(const Constraint_Handle &c, int /*preserves_level, currently unused*/) { + EQ_Handle e = add_EQ(); + copy_constraint(e,c); + return e; +} + + +EQ_Handle Conjunct::add_EQ(int preserves_level) { + assert_not_finalized(); + int c; + c = problem->newEQ(); + simplified = false; + verified = false; + if (!preserves_level) { + if (leading_dir == 0) + possible_leading_0s = -1; + // otherwise we must still have leading_dir, and thus no more 0's + } + problem->EQs[c].color = EQ_BLACK; + eqnnzero(&problem->EQs[c],problem->nVars); + n_open_constraints++; + return EQ_Handle(this, c); +} + + +// This should only be used to copy constraints from simplified relations, +// i.e. there are no quantified variables in c except wildcards. +GEQ_Handle Conjunct::add_GEQ(const Constraint_Handle &c, int /*preserves_level, currently unused */) { + GEQ_Handle g = add_GEQ(); + copy_constraint(g,c); + return g; +} + + +GEQ_Handle Conjunct::add_GEQ(int preserves_level) { + assert_not_finalized(); + int c; + c = problem->newGEQ(); + simplified = false; + verified = false; + if (!preserves_level) { + if (leading_dir == 0) + possible_leading_0s = -1; + // otherwise we must still have leading_dir, and thus no more 0's + } + problem->GEQs[c].color = EQ_BLACK; + eqnnzero(&problem->GEQs[c],problem->nVars); + n_open_constraints++; + return GEQ_Handle(this, c); +} + + +Conjunct *Conjunct::find_available_conjunct() { + return this; +} + + +bool Conjunct::can_add_child() { + return false; +} + + +void Conjunct::combine_columns() { + int nvars = mappedVars.size(),i,j,k; + + for(i=1; i<=nvars; i++) + for(j=i+1; j<=nvars; j++) { + // If they are the same, copy into the higher numbered column. + // That way we won't have problems with already-merged columns later + assert(i != j); + if(mappedVars[i] == mappedVars[j]) { + if (pres_debug) + fprintf(DebugFile, "combine_col:Actually combined %d,%d\n", + j,i); + for(k=0; k<problem->nEQs; k++) + problem->EQs[k].coef[j] += problem->EQs[k].coef[i]; + for(k=0; k<problem->nGEQs; k++) + problem->GEQs[k].coef[j] += problem->GEQs[k].coef[i]; + zero_column(problem, i, 0, 0, problem->nEQs, problem->nGEQs); + // Create a wildcard w/no constraints. temporary measure, + // so we don't have to shuffle columns + Variable_ID zero_var = declare(); + mappedVars[i] = zero_var; + break; + } + } +} + + +void Conjunct::finalize() { +// Debugging version of finalize; copy the conjunct and free the old one, +// so that purify will catch accesses to finalized constraints +// assert(n_open_constraints == 0); +// Conjunct *C = this->copy(); +// parent().replace_child(this, C); +// delete this; +} + +Conjunct::~Conjunct() { + NR_CONJUNCTS--; + delete problem; + delete comp_problem; +} + + +// +// Cost = # of terms in DNF when negated +// or CantBeNegated if too bad (i.e. bad wildcards) +// or AvoidNegating if it would be inexact +// +// Also check pres_legal_negations -- +// If set to any_negation, just return the number +// If set to one_geq_or_stride, return CantBeNegated if c > 1 +// If set to one_geq_or_eq, return CantBeNegated if not a single geq or eq +// + +int Conjunct::cost() { + int c; + int i; + int wc_no; + int wc_j = 0; // initialize to shut up the compiler + + // cost 1 per GEQ, and if 1 GEQ has wildcards, +2 for each of them + + c = problem->nGEQs; + for(i=0; i<problem->nGEQs; i++) { + wc_no = 0; + for(int j=1; j<=problem->nVars; j++) if(problem->GEQs[i].coef[j]!=0) { + Variable_ID v = mappedVars[j]; + if(v->kind()==Wildcard_Var) { + wc_no++; + c+=2; + wc_j = j; + } + } + if (wc_no > 1) return CantBeNegated; + } + + for(i=0; i<problem->nEQs; i++) { + wc_no = 0; + for(int j=1; j<=problem->nVars; j++) if(problem->EQs[i].coef[j]!=0) { + Variable_ID v = mappedVars[j]; + if(v->kind()==Wildcard_Var) { + wc_no++; + wc_j = j; + } + } + + if (wc_no == 0) // no wildcards + c+=2; + else if (wc_no == 1) { // one wildcard - maybe we can negate it + int i2; + for(i2=0; i2<problem->nEQs; i2++) + if(i != i2 && problem->EQs[i2].coef[wc_j]!=0) break; + if (i2 >= problem->nEQs) // Stride constraint + c++; + else // We are not ready to handle this + return CantBeNegated; + } + else // Multiple wildcards + return CantBeNegated; + } + if (!exact) return AvoidNegating; + + if (pres_legal_negations == any_negation) { + return c; + } + else { + // single GEQ ok either way as long as no wildcards + // (we might be able to handle wildcards, but I haven't thought about it) + if (problem->nEQs==0 && problem->nGEQs<=1) { + if (c>1) { // the GEQ had a wildcard -- I'm not ready to go here. + if (pres_debug > 0) { + fprintf(DebugFile, + "Refusing to negate a GEQ with wildcard(s)" + " under restricted_negation; " + "It may be possible to fix this.\n"); + } + return CantBeNegated; + } + return c; + } + else if (problem->nEQs==1 && problem->nGEQs==0) { + assert(c == 1 || c == 2); + + if (pres_legal_negations == one_geq_or_stride) { + if (c == 1) + return c; // stride constraint is ok + else { + if (pres_debug > 0) { + fprintf(DebugFile, "Refusing to negate a non-stride EQ under current pres_legal_negations.\n"); + } + return CantBeNegated; + } + } + else { + assert(pres_legal_negations == one_geq_or_eq); + return c; + } + } + else { + if (pres_debug > 0) { + fprintf(DebugFile, "Refusing to negate multiple constraints under current pres_legal_negations.\n"); + } + return CantBeNegated; + } + } +} + + +// +// Merge CONJ1 & CONJ2 -> CONJ. +// Action: MERGE_REGULAR or MERGE_COMPOSE: regular merge. +// MERGE_GIST make constraints from conj2 red, i.e. +// Gist Conj2 given Conj1 (T.S. comment). +// Reorder columns as we go. +// Merge the columns for identical variables. +// We assume we know nothing about the ordering of conj1, conj2. +// +// Does not consume its arguments +// +// Optional 4th argument gives the relation for the result - if +// null, conj1 and conj2 must have the same relation, which will +// be used for the result +// +// The only members of conj1 and conj2 that are used are: problem, +// mappedVars and declare(), and the leading_0s/leading_dir members +// and exact. +// +// NOTE: variables that are shared between conjuncts are necessarily +// declared above, not here; so we can simply create columns for the +// locals of each conj after doing the protected vars. +// +Conjunct* merge_conjs(Conjunct* conj1, Conjunct* conj2, + Merge_Action action, Rel_Body *body) { + // body must be set unless both conjuncts are from the same relation + assert(body || conj1->relation() == conj2->relation()); + + if (body == conj1->relation() && body == conj2->relation()) + body = 0; // we test this later to see if there is a new body + + Conjunct *conj3 = new Conjunct(NULL, body ? body : conj2->relation()); + Problem *p1 = conj1->problem; + Problem *p2 = conj2->problem; + Problem *p3 = conj3->problem; + int i; + + if (action != MERGE_COMPOSE) { + conj1->assert_leading_info(); + conj2->assert_leading_info(); + } + + if(pres_debug>=2) { + use_ugly_names++; + fprintf(DebugFile, ">>> Merge conjuncts: Merging%s:\n", + (action == MERGE_GIST ? " for gist" : + (action == MERGE_COMPOSE ? " for composition" : ""))); + conj1->prefix_print(DebugFile); + conj2->prefix_print(DebugFile); + fprintf(DebugFile, "\n"); + use_ugly_names--; + } + + + + switch(action) { + case MERGE_REGULAR: + case MERGE_COMPOSE: + conj3->exact=conj1->exact && conj2->exact; + break; + case MERGE_GIST: + conj3->exact=conj2->exact; + break; + } + + if (action == MERGE_COMPOSE) { + conj3->guaranteed_leading_0s=min(conj1->guaranteed_leading_0s, + conj2->guaranteed_leading_0s); + conj3->possible_leading_0s=min((unsigned int) conj1->possible_leading_0s, + (unsigned int) conj2->possible_leading_0s); + + assert( conj3->guaranteed_leading_0s <= conj3->possible_leading_0s); + + // investigate leading_dir - not well tested code + if (conj1->guaranteed_leading_0s<0 || conj2->guaranteed_leading_0s<0) { + conj3->leading_dir = 0; + } + else if (conj1->guaranteed_leading_0s == conj2->guaranteed_leading_0s) + if (conj1->leading_dir == conj2->leading_dir) + conj3->leading_dir = conj1->leading_dir; + else + conj3->leading_dir = 0; + else if (conj1->guaranteed_leading_0s < conj2->guaranteed_leading_0s) { + conj3->leading_dir = conj1->leading_dir; + } + else { // (conj1->guaranteed_leading_0s > conj2->guaranteed_leading_0s) + conj3->leading_dir = conj2->leading_dir; + } + + if (conj3->leading_dir == 0) + conj3->possible_leading_0s = min(conj3->relation()->n_inp(), + conj3->relation()->n_out()); + + assert(conj3->guaranteed_leading_0s <= conj3->possible_leading_0s); + assert(conj3->guaranteed_leading_0s == conj3->possible_leading_0s + || !conj3->leading_dir); + } + else if (!body) { // if body is set, who knows what leading 0's mean? + assert(action == MERGE_REGULAR || action == MERGE_GIST); + + int feasable = 1; + + int redAndBlackGuarLeadingZeros = max(conj1->guaranteed_leading_0s, + conj2->guaranteed_leading_0s); + if (action == MERGE_REGULAR) + conj3->guaranteed_leading_0s= redAndBlackGuarLeadingZeros; + else conj3->guaranteed_leading_0s=conj1->guaranteed_leading_0s; + + conj3->possible_leading_0s=min((unsigned)conj1->possible_leading_0s, + (unsigned)conj2->possible_leading_0s); + if (conj3->possible_leading_0s < redAndBlackGuarLeadingZeros) + feasable = 0; + else if (conj3->guaranteed_leading_0s == -1 + || conj3->possible_leading_0s > redAndBlackGuarLeadingZeros) + conj3->leading_dir = 0; + else { + if (conj1->guaranteed_leading_0s == conj2->guaranteed_leading_0s) + if (!conj1->leading_dir_valid_and_known()) + conj3->leading_dir = conj2->leading_dir; + else if (!conj2->leading_dir_valid_and_known()) + conj3->leading_dir = conj1->leading_dir; + else if (conj1->leading_dir * conj2->leading_dir > 0) + conj3->leading_dir = conj1->leading_dir; // 1,2 same dir + else + feasable = 0; // 1 and 2 go in opposite directions + else if (conj3->possible_leading_0s != conj3->guaranteed_leading_0s) + conj3->leading_dir = 0; + else if (conj1->guaranteed_leading_0s<conj2->guaranteed_leading_0s) { + assert(!conj1->leading_dir_valid_and_known()); + conj3->leading_dir = conj2->leading_dir; + } + else { + assert(!conj2->leading_dir_valid_and_known()); + conj3->leading_dir = conj1->leading_dir; + } + } + + if (!feasable) { + if(pres_debug>=2) + fprintf(DebugFile, ">>> Merge conjuncts: quick check proves FALSE.\n"); + + // return 0 = 1 + + int e = p3->newEQ(); + p3->EQs[e].color = EQ_BLACK; + p3->EQs[e].touched = 1; + p3->EQs[e].key = 0; + p3->EQs[e].coef[0] = 1; + + // Make sure these don't blow later assertions + conj3->possible_leading_0s = conj3->guaranteed_leading_0s = -1; + conj3->leading_dir = 0; + + return conj3; + } + } + else { // provided "body" argument but not composing, leading 0s meaningless + conj3->guaranteed_leading_0s = conj3->possible_leading_0s = -1; + conj3->leading_dir = 0; + } + + // initialize omega stuff + + for(i=0; i<p1->nGEQs+p2->nGEQs; i++) { + int e = p3->newGEQ(); + assert(e == i); + p3->GEQs[e].color = EQ_BLACK; + p3->GEQs[e].touched = 1; + p3->GEQs[e].key = 0; + } + for(i=0; i<p1->nEQs+p2->nEQs; i++) { + int e = p3->newEQ(); + assert(e == i); + p3->EQs[e].color = EQ_BLACK; + p3->EQs[e].touched = 1; + p3->EQs[e].key = 0; + } + + assert(p3->nGEQs == p1->nGEQs + p2->nGEQs); + assert(p3->nEQs == p1->nEQs + p2->nEQs); + + // flag constraints from second constraint as red, if necessary + if (action == MERGE_GIST) { + for(i=0; i<p2->nEQs; i++) { + p3->EQs[i+p1->nEQs].color = EQ_RED; + } + for(i=0; i<p2->nGEQs; i++) { + p3->GEQs[i+p1->nGEQs].color = EQ_RED; + } + } + + // copy constant column + copy_column(p3, 0, p1, 0, 0, 0); + copy_column(p3, 0, p2, 0, p1->nEQs, p1->nGEQs); + + // copy protected variables column from conj1 + int new_col = 1; + Variable_Iterator VI(conj1->mappedVars); + for(i=1; VI; VI++, i++) { + Variable_ID v = *VI; + if(v->kind() != Wildcard_Var) { + conj3->mappedVars.append(v); + int fr_ix = i; + copy_column(p3, new_col, p1, fr_ix, 0, 0); + zero_column(p3, new_col, p1->nEQs, p1->nGEQs, + p2->nEQs, p2->nGEQs); + new_col++; + } + } + + // copy protected variables column from conj2, + // checking if conj3 already has this variable from conj1 + for(i=1; i <= conj2->mappedVars.size(); i++) { + Variable_ID v = conj2->mappedVars[i]; + if(v->kind() != Wildcard_Var) { + int to_ix = conj3->mappedVars.index(v); + int fr_ix = i; + if(to_ix > 0) { + // use old column + copy_column(p3, to_ix, p2, fr_ix, p1->nEQs, p1->nGEQs); + } + else { + // create new column + conj3->mappedVars.append(v); + zero_column(p3, new_col, 0, 0, p1->nEQs, p1->nGEQs); + copy_column(p3, new_col, p2, fr_ix, p1->nEQs, p1->nGEQs); + new_col++; + } + } + } + + p3->safeVars = new_col-1; + + // copy wildcards from conj1 + for(i=1; i <= conj1->mappedVars.size(); i++) { + Variable_ID v = conj1->mappedVars[i]; + if(v->kind() == Wildcard_Var) { + Variable_ID nv = conj3->declare(v); + conj3->mappedVars.append(nv); + int fr_ix = i; + copy_column(p3, new_col, p1, fr_ix, 0, 0); + zero_column(p3, new_col, p1->nEQs, p1->nGEQs, + p2->nEQs, p2->nGEQs); + new_col++; + } + } + + // copy wildcards from conj2 + for(i=1; i <= conj2->mappedVars.size(); i++) { + Variable_ID v = conj2->mappedVars[i]; + if(v->kind() == Wildcard_Var) { + Variable_ID nv = conj3->declare(v); + conj3->mappedVars.append(nv); + int fr_ix = i; + zero_column(p3, new_col, 0, 0, p1->nEQs, p1->nGEQs); + copy_column(p3, new_col, p2, fr_ix, p1->nEQs, p1->nGEQs); + new_col++; + } + } + + p3->nVars = new_col-1; + checkVars(p3->nVars); + p3->variablesInitialized = 1; + for(i=1; i<=p3->nVars; i++) + p3->var[i] = p3->forwardingAddress[i] = i; + + conj3->cols_ordered = true; + conj3->simplified = false; + conj3->verified = false; + + if(pres_debug>=2) { + use_ugly_names++; + fprintf(DebugFile, ">>> Merge conjuncts: result is:\n"); + conj3->prefix_print(DebugFile); + fprintf(DebugFile, "\n"); + use_ugly_names--; + } + + conj3->assert_leading_info(); + + return conj3; +} + + + + +// +// Reorder variables by swapping. +// cols_ordered is just a hint that thorough check needs to be done. +// Sets _safeVars. +// +void Conjunct::reorder() { + if(!cols_ordered) { + int var_no = mappedVars.size(); + int first_wild = 1; + int last_prot = var_no; + while(first_wild < last_prot) { + for(; first_wild<=var_no && mappedVars[first_wild]->kind()!=Wildcard_Var; + first_wild++) ; + for(; last_prot>=1 && mappedVars[last_prot]->kind()==Wildcard_Var; + last_prot--) ; + if(first_wild < last_prot) { + problem->swapVars(first_wild, last_prot); + problem->variablesInitialized = false; + Var_Decl *t = mappedVars[first_wild]; + mappedVars[first_wild] = mappedVars[last_prot]; + mappedVars[last_prot] = t; + if(pres_debug) { + fprintf(DebugFile, "<<<OrderConjCols>>>: swapped var-s %d and %d\n", first_wild, last_prot); + } + } + } + + int safe_vars; + for(safe_vars=0; + safe_vars<var_no && mappedVars[safe_vars+1]->kind()!=Wildcard_Var; + safe_vars++) ; + +#if ! defined NDEBUG + for(int s = safe_vars ; s<var_no ; s++ ) { + assert(mappedVars[s+1]->kind() == Wildcard_Var); + } +#endif + + problem->safeVars = safe_vars; + cols_ordered = true; + } +} + + + +// Wherever possible, move function symbols to input tuple. +// This ensures that if in == out, red F(in) = x is redundant +// with black F(out) = x + +void Conjunct::move_UFS_to_input() { + if (guaranteed_leading_0s > 0) { + std::set<Global_Var_ID> already_done; + int remapped = 0; + skip_finalization_check++; + Rel_Body *body = relation(); + + assert(body); + + for (Variable_ID_Iterator func(*body->global_decls()); func; func++) { + Global_Var_ID f = (*func)->get_global_var(); + if (f->arity() <= guaranteed_leading_0s) + if (already_done.find(f) == already_done.end() && + body->has_local(f, Input_Tuple) && + body->has_local(f, Output_Tuple)) { + already_done.insert(f); + + // equatE f(in) = f(out) + Variable_ID f_in = body->get_local(f, Input_Tuple); + Variable_ID f_out = body->get_local(f, Output_Tuple); + if (f_in != f_out) { + EQ_Handle e = add_EQ(1); + + e.update_coef_during_simplify(f_in, -1); + e.update_coef_during_simplify(f_out, 1); + + f_out->remap = f_in; + remapped = 1; + } + } + } + + if (remapped) { + remap(); + combine_columns(); + reset_remap_field(*body->global_decls()); + remapped = 0; + } + + skip_finalization_check--; + } +} + + + + + +// +// Simplify CONJ. +// Return TRUE if there are solutions, FALSE -- no solutions. +// +int simplify_conj(Conjunct* conj, int ver_sim, int simplificationEffort, int color) { + if (conj->verified + && simplificationEffort <= conj->r_constrs + && (conj->simplified || simplificationEffort < 0) + && !color) { + if(pres_debug) { + fprintf(DebugFile, "$$$ Redundant simplify_conj ignored (%d,%d,%d)\n",ver_sim,simplificationEffort,color); + conj->prefix_print(DebugFile); + } + return 1; + } + + if (simplificationEffort < 0) simplificationEffort = 0; + conj->move_UFS_to_input(); + conj->reorder(); + + Problem *p = conj->problem; + + use_ugly_names++; + + int i; + for(i=0; i<p->nGEQs; i++) { + p->GEQs[i].touched = 1; + } + for(i=0; i<p->nEQs; i++) { + p->EQs[i].touched = 1; + } + + if(pres_debug) { + fprintf(DebugFile, "$$$ simplify_conj (%d,%d,%d)[\n",ver_sim,simplificationEffort,color); + conj->prefix_print(DebugFile); + } + + assert(conj->cols_ordered); + + int ret_code; + assert(p == conj->problem); + if(!color) { + ret_code = conj->simplifyProblem(ver_sim && ! conj->verified,0,simplificationEffort); + } + else { + ret_code = conj->redSimplifyProblem(simplificationEffort,1); + ret_code = (ret_code==redFalse ? 0 : 1); + } + assert(p->nSUBs==0); + + if(ret_code == 0) { + if(pres_debug) + fprintf(DebugFile, "] $$$ simplify_conj : false\n\n"); + delete conj; + use_ugly_names--; + return(false); + } + + + // + // mappedVars is mapping from columns to Variable_IDs. + // Recompute mappedVars for problem returned from ip.c + // + Variable_ID_Tuple new_mapped(0); // This is expanded by "append" + for (i=1; i<=p->safeVars; i++) { + // what is now in column i used to be in column p->var[i] + Variable_ID v = conj->mappedVars[p->var[i]]; + assert(v->kind() != Wildcard_Var); + new_mapped.append(v); + } + + /* Redeclare all wildcards that weren't eliminated. */ + free_var_decls(conj->myLocals); conj->myLocals.clear(); + + conj->mappedVars = new_mapped; + for (i = p->safeVars+1; i<=p->nVars; i++) { + Variable_ID v = conj->declare(); + conj->mappedVars.append(v); + } + + // reset var and forwarding address if desired. + p->variablesInitialized = 1; + for(i=1; i<=conj->problem->nVars; i++) + conj->problem->var[i] = conj->problem->forwardingAddress[i] = i; + + if(pres_debug) { + fprintf(DebugFile, "] $$$ simplify_conj\n"); + conj->prefix_print(DebugFile); + fprintf(DebugFile, "\n"); + } + + + use_ugly_names--; + conj->simplified = true; + conj->setup_anonymous_wildcard_names(); + + return(true); +} + + +int Conjunct::rank() { + Conjunct *C = this->copy_conj_same_relation(); + C->reorder(); + C->ordered_elimination(C->relation()->global_decls()->size()); + int C_rank = 0; + for(Variable_Iterator vi = C->mappedVars; vi; vi++) + if(C->find_column(*vi) > 0) C_rank++; + delete C; + return C_rank; + +} + + +void Conjunct::query_difference(Variable_ID v1, Variable_ID v2, coef_t &lowerBound, coef_t &upperBound, bool &guaranteed) { + int c1 = get_column(v1); + int c2 = get_column(v2); + assert(c1 && c2); + problem->query_difference(c1, c2, lowerBound, upperBound, guaranteed); +} + + +void Conjunct::query_variable_bounds(Variable_ID v, coef_t &lowerBound, coef_t &upperBound) { + int c = get_column(v); + assert (c); + problem->query_variable_bounds(c, &lowerBound, &upperBound); +} + +coef_t Conjunct::query_variable_mod(Variable_ID v, coef_t factor) { + int c = get_column(v); + assert(c); + return problem->query_variable_mod(c, factor); +} + +bool Conjunct::query_variable_used(Variable_ID v) { + for (GEQ_Iterator g = GEQs(); g.live(); g.next()) { + if ((*g).get_coef(v)) return true; + } + for (EQ_Iterator e = EQs(); e.live(); e.next()) { + if ((*e).get_coef(v)) return true; + } + return false; +} + + +int Conjunct::simplifyProblem(int verify, int subs, int redundantElimination) { + if (verified) verify = 0; + int result = problem->simplifyProblem(verify, subs, redundantElimination); + if (result == false && !exact) + exact=true; + assert(!(verified && verify && result == false)); + if (verify && result) verified = true; + else if (!result) verified = false; + return result; +} + + +// not as confident about this one as the previous: +int Conjunct::redSimplifyProblem(int effort, int computeGist) { + redCheck result = problem->redSimplifyProblem(effort, computeGist); + if (result == redFalse && !exact) + exact=true; + return result; +} + + +// +// Add given list of wildcards S to this Conjunct. +// Clears argument. (That's very important, otherwise those var_id's get freed) +// Push_exists takes responsibility for reusing or deleting Var_ID's; +// here we reuse them. Must also empty out the Tuple when finished (joins). +void Conjunct::push_exists(Variable_ID_Tuple &S) { + for(Tuple_Iterator<Variable_ID> VI(S); VI; VI++) { + (*VI)->var_kind = Wildcard_Var; + } + myLocals.join(S); // Sets S to be empty. + cols_ordered = false; + simplified = false; +} + + +Conjunct *Formula::add_conjunct() { + assert_not_finalized(); + assert(can_add_child()); + Conjunct *f = new Conjunct(this, myRelation); + myChildren.append(f); + return f; +} + +// Compress/uncompress functions + +bool Conjunct::is_compressed() { + if(problem!=NULL && comp_problem==NULL) { + return false; + } + else if(problem==NULL && comp_problem!=NULL) { + return true; + } + else { + assert(0 && "Conjunct::is_compressed: bad conjunct"); + return false; + } +} + + +void Conjunct::compress() { + if(!is_compressed()) { // compress + comp_problem = new Comp_Problem(problem); + delete problem; + problem = NULL; + } +} + + +void Conjunct::uncompress() { + if(is_compressed()) { + problem = comp_problem->UncompressProblem(); + delete comp_problem; + comp_problem = NULL; + } +} + + +Comp_Problem::Comp_Problem(Problem *problem) : + _nVars(problem->nVars), + _safeVars(problem->safeVars), + _get_var_name(problem->get_var_name), + _getVarNameArgs(problem->getVarNameArgs), + eqs(&problem->EQs[0],problem->nEQs,problem->nVars), + geqs(&problem->GEQs[0],problem->nGEQs,problem->nVars) { +} + +Comp_Constraints::Comp_Constraints(eqn *constrs, int no_constrs, int no_vars) : + n_constrs(no_constrs), + n_vars(no_vars) { + coefs = new coef_t[(n_vars+1)*n_constrs]; + int e, v; + for(e=0; e<n_constrs; e++) { + for(v=0; v<=n_vars; v++) { + coefs[coef_index(e,v)] = constrs[e].coef[v]; + } + } +} + + +Comp_Constraints::~Comp_Constraints() { + delete coefs; +} + + +Problem *Comp_Problem::UncompressProblem() { + Problem *p = new Problem(eqs.n_constraints(), geqs.n_constraints()); + p->get_var_name = get_var_name; + p->getVarNameArgs = _getVarNameArgs; + p->nVars = _nVars; + p->safeVars = _safeVars; + for(int i=1; i<=p->nVars; i++) { + p->forwardingAddress[i] = i; + p->var[i] = i; + } + eqs.UncompressConstr(&p->EQs[0], p->nEQs); + geqs.UncompressConstr(&p->GEQs[0], p->nGEQs); + return p; +} + +void Comp_Constraints::UncompressConstr(eqn *constrs, short &pn_constrs) { + int e, v; + for(e=0; e<n_constrs; e++) { + eqnnzero(&constrs[e], 0); + for(v=0; v<=n_vars; v++) { + constrs[e].coef[v] = coefs[coef_index(e,v)]; + } + constrs[e].touched = 1; + } + pn_constrs = n_constrs; +} + + +void Conjunct::convertEQstoGEQs(bool excludeStrides) { + simplify_conj(this,true,1,EQ_BLACK); // don't remember why I want to comment this statement out with reason "will cause inconsistency between Conjunct::mappedVars and Problem::nVars", 06/09/2009 by chun + problem->convertEQstoGEQs(excludeStrides); +} + + +void Conjunct::calculate_dimensions(Relation &R, int &ndim_all, int &ndim_domain) { + + Conjunct * c = this; + Relation rc=Relation(R, c); + + if(relation_debug) { + fprintf(DebugFile,"{{{\nIn Conjunct::calculate_dimensions:\n"); + rc.prefix_print(DebugFile); + } + + rc=Approximate(rc); + Relation rd=rc; + + if(relation_debug) { + fprintf(DebugFile,"Conjunct::calculate_dimensions: Approximated as:\n"); + rc.prefix_print(DebugFile); + } + + // skip_set_checks++; + + Conjunct * rc_conj=rc.single_conjunct(); + ndim_all=rc.n_inp()+rc.n_out(); + ndim_all-=rc_conj->n_EQs(); + + rc = Project_On_Sym(rc); + rc.simplify(); + + if(relation_debug) { + fprintf(DebugFile, "Conjunct::calculate_dimensions: after project_on_sym\n"); + rc.prefix_print(DebugFile); + } + + int n_eq_sym = 1000; + for (DNF_Iterator s(rc.query_DNF()); s.live(); s.next()) + n_eq_sym = min(n_eq_sym, s.curr()->n_EQs()); + ndim_all+=n_eq_sym; + // skip_set_checks--; + + if (R.is_set()) + ndim_domain = ndim_all; + else { + /* get dimensions for the domain (broadcasting) */ + + rd=Domain(rd); + rd.simplify(); + + if(relation_debug) { + fprintf(DebugFile,"Domain is:\n"); + rd.prefix_print(DebugFile); + } + + rc_conj=rd.single_conjunct(); + ndim_domain=rd.n_set()-rc_conj->n_EQs()+n_eq_sym; + } + + if(relation_debug) { + fprintf(DebugFile,"n_eq_sym=%d \n",n_eq_sym); + fprintf(DebugFile,"Dimensions: all=%d domain=%d\n}}}\n", ndim_all,ndim_domain); + } +} + +} // namespace |