summaryrefslogtreecommitdiff
path: root/omegalib/omega/src/Relations.cc
diff options
context:
space:
mode:
Diffstat (limited to 'omegalib/omega/src/Relations.cc')
-rw-r--r--omegalib/omega/src/Relations.cc2882
1 files changed, 0 insertions, 2882 deletions
diff --git a/omegalib/omega/src/Relations.cc b/omegalib/omega/src/Relations.cc
deleted file mode 100644
index d7dbe86..0000000
--- a/omegalib/omega/src/Relations.cc
+++ /dev/null
@@ -1,2882 +0,0 @@
-/*****************************************************************************
- Copyright (C) 1994-2000 the Omega Project Team
- Copyright (C) 2005-2011 Chun Chen
- All Rights Reserved.
-
- Purpose:
- Integer set and relation operations.
-
- Notes:
-
- History:
- 04/22/09 merge_rels, Chun Chen
-*****************************************************************************/
-
-#include <omega/Relation.h>
-#include <omega/Rel_map.h>
-#include <omega/pres_tree.h>
-#include <omega/pres_dnf.h>
-#include <omega/pres_conj.h>
-#include <omega/hull.h>
-#include <basic/Tuple.h>
-#include <basic/Map.h>
-#include <basic/util.h>
-#include <omega/omega_i.h>
-#if defined STUDY_EVACUATIONS
-#include <omega/evac.h>
-#endif
-#include <assert.h>
-
-namespace omega {
-
-#define CHECK_MAYBE_SUBSET 1
-
-int relation_debug=0;
-
-namespace {
- int leave_pufs_untouched = 0;
- Variable_ID_Tuple exists_ids;
- List<int> exists_numbers;
- F_And * and_below_exists;
-}
-
-/* The following allows us to avoid warnings about passing
- temporaries as non-const references. This is useful but
- has suddenly become illegal. */
-
-Relation consume_and_regurgitate(NOT_CONST Relation &R) {
- if(!R.is_null())
- ((Relation &) R).finalize();
- Relation S = (Relation &) R;
- (Relation &) R = Relation::Null();
- return S;
-}
-
-
-//
-// r1 Union r2.
-// align the input tuples (if any) for F and G
-// align the output tuples (if any) for F and G
-// match named variables in F and G
-// formula is f | g
-//
-Relation Union(NOT_CONST Relation &input_r1,
- NOT_CONST Relation &input_r2) {
- Relation r1 = consume_and_regurgitate(input_r1);
- Relation r2 = consume_and_regurgitate(input_r2);
- if (r1.is_null())
- return r2;
- else if (r2.is_null())
- return r1;
- if (r1.n_inp() != r2.n_inp() || r1.n_out() != r2.n_out())
- throw std::invalid_argument("relation arity does not match");
-
- // skip_set_checks++;
- // assert(r1.n_inp() == r2.n_inp());
- // assert(r1.n_out() == r2.n_out());
- // assert(!r1.is_null() && !r2.is_null());
- int in = r1.n_inp(), out = r1.n_out();
- // skip_set_checks--;
-
- return MapAndCombineRel2(r1, r2, Mapping::Identity(in, out),
- Mapping::Identity(in,out), Comb_Or);
-}
-
-
-//
-// F intersection G
-// align the input tuples (if any) for F and G
-// align the output tuples (if any) for F and G
-// match named variables in F and G
-// formula is f & g
-//
-Relation Intersection(NOT_CONST Relation &input_r1,
- NOT_CONST Relation &input_r2) {
- Relation r1 = consume_and_regurgitate(input_r1);
- Relation r2 = consume_and_regurgitate(input_r2);
- if (r1.is_null())
- return r2;
- else if (r2.is_null())
- return r1;
- if (r1.n_inp() != r2.n_inp() || r1.n_out() != r2.n_out())
- throw std::invalid_argument("relation arity does not match");
-
- // skip_set_checks++;
- // assert(r1.n_inp() == r2.n_inp());
- // assert(r1.n_out() == r2.n_out());
- // assert(!r1.is_null() && !r2.is_null());
- int in = r1.n_inp(), out = r1.n_out();
- // skip_set_checks--;
-
- return MapAndCombineRel2(r1, r2, Mapping::Identity(in,out),
- Mapping::Identity(in,out), Comb_And);
-}
-
-
-//
-// F \ G (the relation F restricted to domain G)
-// align the input tuples for F and G
-// match named variables in F and G
-// formula is f & g
-//
-Relation Restrict_Domain(NOT_CONST Relation &input_r1,
- NOT_CONST Relation &input_r2) {
- Relation r1 = consume_and_regurgitate(input_r1);
- Relation r2 = consume_and_regurgitate(input_r2);
- if (r1.is_null())
- return r1;
- else if (r2.is_null())
- return r1;
- if (r1.n_inp() != r2.n_set())
- throw std::invalid_argument("relation arity does not match");
-
- // assert(!r1.is_null() && !r2.is_null());
- // skip_set_checks++;
- // assert(r1.n_inp() == r2.n_set());
- // assert(r2.is_set());
- int in = r1.n_inp(), out = r1.n_out();
- // skip_set_checks--;
-
- int i;
- Mapping m2(r2.n_set());
- for(i=1; i<=r2.n_set(); i++) m2.set_map_set(i, Input_Var,i);
-
- // skip_set_checks++;
- assert(r2.query_guaranteed_leading_0s() == -1 &&
- r2.query_possible_leading_0s() == -1);
- // skip_set_checks--;
-
- Relation result = MapAndCombineRel2(r1, r2, Mapping::Identity(in,out),
- m2, Comb_And);
- // FERD -- update leading 0's - the may close up?
- //result.invalidate_leading_info(); // could do better
- return result;
-}
-
-//
-//
-// F / G (the relation F restricted to range G)
-// align the output tuples for F and G
-// match named variables in F and G
-// formula is f & g
-//
-Relation Restrict_Range(NOT_CONST Relation &input_r1,
- NOT_CONST Relation &input_r2) {
- Relation r1 = consume_and_regurgitate(input_r1);
- Relation r2 = consume_and_regurgitate(input_r2);
- if (r1.is_null())
- return r1;
- else if (r2.is_null())
- return r1;
- if (r1.n_out() != r2.n_set())
- throw std::invalid_argument("relation arity does not match");
-
- // skip_set_checks++;
- // assert(r1.n_out() == r2.n_set());
- // assert(r2.is_set());
- // assert(!r1.is_null() && !r2.is_null());
- int in = r1.n_inp(), out = r1.n_out();
- // skip_set_checks--;
-
- int i;
- Mapping m2(r2.n_set());
- for(i=1; i<=r2.n_set(); i++) m2.set_map_set(i, Output_Var,i);
-
- // skip_set_checks++;
- assert(r2.query_guaranteed_leading_0s() == -1 &&
- r2.query_possible_leading_0s() == -1);
- // skip_set_checks--;
-
- Relation result = MapAndCombineRel2(r1, r2, Mapping::Identity(in, out),
- m2, Comb_And);
- // FERD -- update leading 0's - the may close up?
- // result.invalidate_leading_info(); // could do better
- return result;
-}
-
-
-//
-// Add input variable to relation.
-//
-Relation Extend_Domain(NOT_CONST Relation &S) {
- Relation R = consume_and_regurgitate(S);
- if (R.is_null())
- throw std::invalid_argument("cannot extend domain on null relation");
-
- // assert(!R.is_null() && (skip_set_checks || !R.is_set()));
- // assert(!R.is_null());
- Rel_Body *r = R.split();
- r->In_Names.append(Const_String());
- r->number_input++;
- assert(!r->is_null());
-
- if (r->number_input <= r->number_output)
- R.invalidate_leading_info(r->number_input);
-
- return R;
-}
-
-//
-// Add more input variables to relation.
-//
-Relation Extend_Domain(NOT_CONST Relation &S, int more) {
- Relation R = consume_and_regurgitate(S);
- if (R.is_null())
- throw std::invalid_argument("cannot extend domain on null relation");
-
- // assert(!R.is_null());
- R.split();
- for (int i=1; i<=more; i++) R = Extend_Domain(R);
- return R;
-}
-
-
-//
-// Add output variable to relation.
-//
-Relation Extend_Range(NOT_CONST Relation &S) {
- Relation R = consume_and_regurgitate(S);
- if (R.is_null())
- throw std::invalid_argument("cannot extend range on null relation");
-
- // assert(!R.is_null() && !R.is_set());
- // assert(!R.is_null());
- Rel_Body *r = R.split();
- r->Out_Names.append(Const_String());
- r->number_output++;
- assert(!r->is_null());
-
- if (r->number_output <= r->number_input)
- R.invalidate_leading_info(r->number_output);
-
- return R;
-}
-
-//
-// Add more output variables to relation.
-//
-Relation Extend_Range(NOT_CONST Relation &S, int more) {
- Relation R = consume_and_regurgitate(S);
-
- // assert(!R.is_null());
- R.split();
- for (int i=1; i<=more; i++) R = Extend_Range(R);
- return R;
-}
-
-
-//
-// Add set variable to set.
-//
-Relation Extend_Set(NOT_CONST Relation &S) {
- Relation R = consume_and_regurgitate(S);
- if (R.is_null())
- throw std::invalid_argument("cannot extend set on null relation");
- if (R.n_out() > 0)
- throw std::invalid_argument("relation must be a set");
-
- // assert(!R.is_null() && R.is_set());
- Rel_Body *r = R.split();
- r->In_Names.append(Const_String());
- r->number_input++;
- assert(!r->is_null());
- return R;
-}
-
-//
-// Add more variables to set
-//
-Relation Extend_Set(NOT_CONST Relation &S, int more) {
- Relation R = consume_and_regurgitate(S);
- R.split();
- for (int i=1; i<=more; i++) R = Extend_Set(R);
- return R;
-}
-
-
-
-//
-// Domain and Range.
-// Make output (input) variables wildcards and simplify.
-// Move all UFS's to have have the remaining tuple as an argument,
-// and maprel will move them to the set tuple
-// RESET all leading 0's
-//
-Relation Domain(NOT_CONST Relation &S) {
- Relation r = consume_and_regurgitate(S);
- if (r.is_null())
- return r;
-
- // assert(!S.is_null());
- // assert(!r.is_set());
- // skip_set_checks++;
- int i;
- Mapping m1(r.n_inp(), r.n_out());
- for(i=1; i<=r.n_inp(); i++) m1.set_map_in (i, Set_Var,i);
- for(i=1; i<=r.n_out(); i++) m1.set_map_out(i, Exists_Var,i);
- // skip_set_checks--;
-
- int a = r.max_ufs_arity_of_out();
- if (a > 0) {
- // UFS's must evacuate from the output tuple
- Variable_ID_Tuple remapped;
-
- r.simplify();
- DNF *d = r.split()->DNFize();
- d->count_leading_0s();
- // Any conjucts with leading_0s == -1 must have >= "a" leading 0s
- // What a gross way to do this. Ferd
-
- for (DNF_Iterator conj(d); conj; conj++) {
-#if defined STUDY_EVACUATIONS
- study_evacuation(*conj, out_to_in, a);
-#endif
-
- int cL0 = (*conj)->guaranteed_leading_0s;
-
- for (Variable_ID_Iterator func((*conj)->mappedVars); func; func++)
- if ((*func)->kind() == Global_Var) {
- Global_Var_ID f = (*func)->get_global_var();
- if (f->arity() > 0 && (*func)->function_of()==Output_Tuple) {
- if (cL0 >= f->arity()) {
- (*func)->remap = r.get_local(f, Input_Tuple);
- }
- else {
- (*func)->remap = (*conj)->declare();
- (*conj)->make_inexact();
- }
- remapped.append(*func);
- }
- }
- (*conj)->remap();
- reset_remap_field(remapped);
- remapped.clear();
-
- (*conj)->guaranteed_leading_0s = (*conj)->possible_leading_0s = -1;
- (*conj)->leading_dir = 0;
- }
- }
-
- MapRel1(r, m1, Comb_Id); // this invalidates leading0s
- assert(r.is_set() || m1.n_in() == 0); // MapRel can't tell to make a set
- r.markAsSet(); // if there were no inputs.
-
- // skip_set_checks++;
- assert(r.query_guaranteed_leading_0s() == -1 && r.query_possible_leading_0s() == -1);
- // skip_set_checks--;
-
- return r;
-}
-
-
-Relation Range(NOT_CONST Relation &S) {
- Relation r = consume_and_regurgitate(S);
- if (r.is_null())
- return r;
-
- //assert(!r.is_null());
- // skip_set_checks++;
-
- int i;
- Mapping m1(r.n_inp(), r.n_out());
- for(i=1; i<=r.n_inp(); i++) m1.set_map_in (i, Exists_Var,i);
- for(i=1; i<=r.n_out(); i++) m1.set_map_out(i, Set_Var,i);
- // skip_set_checks--;
-
- int a = r.max_ufs_arity_of_in();
- if (a > 0) {
- // UFS's must evacuate from the input tuple
- Variable_ID_Tuple remapped;
-
- r.simplify();
- DNF *d = r.split()->DNFize();
- d->count_leading_0s();
- // Any conjucts with leading_0s == -1 must have >= "a" leading 0s
- // What a gross way to do this. Ferd
-
- for (DNF_Iterator conj(d); conj; conj++) {
-#if defined STUDY_EVACUATIONS
- study_evacuation(*conj, in_to_out, a);
-#endif
-
- int cL0 = (*conj)->guaranteed_leading_0s;
- for (Variable_ID_Iterator func((*conj)->mappedVars); func; func++)
- if ((*func)->kind() == Global_Var) {
- Global_Var_ID f = (*func)->get_global_var();
- if (f->arity() > 0 && (*func)->function_of()==Input_Tuple) {
- if (cL0 >= f->arity()) {
- (*func)->remap = r.get_local(f, Output_Tuple);
- }
- else {
- (*func)->remap = (*conj)->declare();
- (*conj)->make_inexact();
- }
- remapped.append(*func);
- }
- }
- (*conj)->remap();
- reset_remap_field(remapped);
- remapped.clear();
-
- (*conj)->guaranteed_leading_0s = (*conj)->possible_leading_0s = -1;
- (*conj)->leading_dir = 0;
- }
- }
-
- MapRel1(r, m1, Comb_Id); // this invalidates leading0s
- assert(r.is_set() || m1.n_out() == 0); // MapRel can't tell to make a set
- r.markAsSet(); // if there were no outputs.
-
- // skip_set_checks++;
- assert(r.query_guaranteed_leading_0s() == -1 && r.query_possible_leading_0s() == -1);
- // skip_set_checks--;
-
- return r;
-}
-
-
-//
-// Cross Product. Give two sets, A and B, create a relation whose
-// domain is A and whose range is B.
-//
-Relation Cross_Product(NOT_CONST Relation &input_A,
- NOT_CONST Relation &input_B) {
- Relation A = consume_and_regurgitate(input_A);
- Relation B = consume_and_regurgitate(input_B);
- if (A.is_null() || B.is_null())
- throw std::invalid_argument("null relation");
- if (!A.is_set() || !B.is_set())
- throw std::invalid_argument("cross product must be on two set");
-
- // assert(A.is_set());
- // assert(B.is_set());
-
- // skip_set_checks++;
- assert(A.query_guaranteed_leading_0s() == -1 &&
- A.query_possible_leading_0s() == -1);
- assert(B.query_guaranteed_leading_0s() == -1 &&
- B.query_possible_leading_0s() == -1);
- // skip_set_checks--;
-
- Mapping mA(A.n_set());
- Mapping mB(B.n_set());
- int i;
- for(i = 1; i <= B.n_set(); i++) mB.set_map_set(i, Output_Var,i);
- for(i = 1; i <= A.n_set(); i++) mA.set_map_set(i, Input_Var,i);
- return MapAndCombineRel2(A, B, mA, mB, Comb_And);
-}
-
-
-//
-// inverse F
-// reverse the input and output tuples
-//
-Relation Inverse(NOT_CONST Relation &S) {
- Relation r = consume_and_regurgitate(S);
- if (r.is_null())
- return r;
-
- // assert(!r.is_null());
- // assert(!r.is_set());
- int i;
-
- Mapping m1(r.n_inp(), r.n_out());
- for(i=1; i<=r.n_inp(); i++) m1.set_map_in (i, Output_Var,i);
- for(i=1; i<=r.n_out(); i++) m1.set_map_out(i, Input_Var,i);
-
- MapRel1(r, m1, Comb_Id, -1, -1, false);
-
- r.reverse_leading_dir_info();
-
- return r;
-}
-
-Relation After(NOT_CONST Relation &input_S,
- int carried_by, int new_output,int dir) {
- Relation S = consume_and_regurgitate(input_S);
- assert(!S.is_null());
- assert(!S.is_set());
- int i;
- Relation r(*S.split(),42);
-
- int a = r.max_ufs_arity_of_out();
- int preserved_positions = min(carried_by-1,new_output);
- if (a >= preserved_positions) {
- // UFS's must evacuate from the output tuple
- Variable_ID_Tuple remapped;
-
- r.simplify();
- DNF *d = r.split()->DNFize();
- d->count_leading_0s();
- // Any conjucts with leading_0s == -1 must have >= "a" leading 0s
- // What a gross way to do this. Ferd
-
- for (DNF_Iterator conj(d); conj; conj++) {
- int cL0 = (*conj)->guaranteed_leading_0s;
-
- for (Variable_ID_Iterator func((*conj)->mappedVars); func; func++)
- if ((*func)->kind() == Global_Var) {
- Global_Var_ID f = (*func)->get_global_var();
- if (f->arity() > preserved_positions
- && (*func)->function_of()==Output_Tuple) {
- if (cL0 >= f->arity()) {
- (*func)->remap = r.get_local(f, Input_Tuple);
- }
- else {
- (*func)->remap = (*conj)->declare();
- (*conj)->make_inexact();
- }
- remapped.append(*func);
- }
- }
- (*conj)->remap();
- reset_remap_field(remapped);
- remapped.clear();
-
- (*conj)->guaranteed_leading_0s =
- (*conj)->possible_leading_0s = -1;
- (*conj)->leading_dir = 0;
- }
- }
-
- Mapping m1(r.n_inp(), r.n_out());
- for(i=1; i<=r.n_inp(); i++) m1.set_map_in (i, Input_Var,i);
- if (carried_by > new_output) {
- int preserve = min(new_output,r.n_out());
- for(i=1; i<=preserve; i++) m1.set_map_out(i, Output_Var,i);
- for(i=preserve+1; i<=r.n_out(); i++) m1.set_map_out(i, Exists_Var,-1);
- MapRel1(r, m1, Comb_Id, -1, -1, true);
- if (new_output > preserve)
- r = Extend_Range(r,new_output-r.n_out());
- return r;
- }
-
- for(i=1; i<carried_by; i++) m1.set_map_out(i, Output_Var,i);
- m1.set_map_out(carried_by, Exists_Var,1);
- for(i=carried_by+1; i<=r.n_out(); i++) m1.set_map_out(i, Exists_Var,-1);
-
- MapRel1(r, m1, Comb_Id, -1, -1, true,false);
-
- Rel_Body *body = r.split();
- body->Out_Names.append(Const_String());
- body->number_output++;
- assert(body->n_out() <= input_vars.size());
-
-
- GEQ_Handle h = and_below_exists->add_GEQ(0);
- assert(carried_by < 128);
- h.update_coef(exists_ids[1],-dir);
- h.update_coef(r.output_var(carried_by),dir);
- h.update_const(-1);
- h.finalize();
- r.finalize();
- if (new_output > r.n_out())
- r = Extend_Range(r,new_output-r.n_out());
- return r;
-}
-
-//
-// Identity.
-//
-Relation Identity(int n_inp) {
- Relation rr(n_inp, n_inp);
- F_And *f = rr.add_and();
- for(int i=1; i<=n_inp; i++) {
- EQ_Handle e = f->add_EQ();
- e.update_coef(rr.input_var(i), -1);
- e.update_coef(rr.output_var(i), 1);
- e.finalize();
- }
- rr.finalize();
- assert(!rr.is_null());
- return rr;
-}
-
-Relation Identity(NOT_CONST Relation &input_r) {
- Relation r = consume_and_regurgitate(input_r);
- return Restrict_Domain(Identity(r.n_set()),r);
-}
-
-//
-// Deltas(F)
-// Return a set such that the ith variable is old Out_i - In_i
-// Delta variables are created as input variables.
-// Then input and output variables are projected out.
-//
-Relation Deltas(NOT_CONST Relation &S) {
- Relation R = consume_and_regurgitate(S);
- assert(!R.is_null());
- // skip_set_checks++;
- assert(R.n_inp()==R.n_out());
- int in = R.n_inp();
- // skip_set_checks--;
- return Deltas(R,in);
-}
-
-Relation Deltas(NOT_CONST Relation &S, int eq_no) {
- Relation R = consume_and_regurgitate(S);
- // skip_set_checks++;
- assert(!R.is_null());
- assert(eq_no<=R.n_inp());
- assert(eq_no<=R.n_out());
- // R.split();
-
- int no_inp = R.n_inp();
- int no_out = R.n_out();
-
- if(relation_debug) {
- fprintf(DebugFile,"Computing Deltas:\n");
- R.prefix_print(DebugFile);
- }
- int a = R.max_ufs_arity();
- if (a > 0) {
- Variable_ID_Tuple remapped;
-
- // UFS's must evacuate from all tuples - we need to go to DNF
- // to enumerate the variables, I think...
- R.simplify();
- if(relation_debug) {
- fprintf(DebugFile,"Relation simplified:\n");
- R.prefix_print(DebugFile);
- }
- DNF *d = R.split()->DNFize();
-
- for (DNF_Iterator conj(d); conj; conj++) {
- for (Variable_ID_Iterator func((*conj)->mappedVars); func; func++)
- if ((*func)->kind() == Global_Var) {
- Global_Var_ID f = (*func)->get_global_var();
- if (f->arity() > 0) {
- (*func)->remap = (*conj)->declare();
- (*conj)->make_inexact();
- remapped.append(*func);
- }
- }
- (*conj)->remap();
- reset_remap_field(remapped);
- remapped.clear();
- }
- }
-
- R = Extend_Domain(R, eq_no); // add eq_no Delta vars
- Mapping M(no_inp+eq_no, no_out);
- int i;
- for(i=1; i<=eq_no; i++) { // Set up Deltas equalities
- EQ_Handle E = R.and_with_EQ();
- /* delta_i - w_i + r_i = 0 */
- E.update_coef(R.input_var(i), 1);
- E.update_coef(R.output_var(i), -1);
- E.update_coef(R.input_var(no_inp+i), 1);
- E.finalize();
- M.set_map(Input_Var, no_inp+i, Set_Var, i); // Result will be a set
- }
- for(i=1; i<=no_inp; i++) { // project out input variables
- M.set_map(Input_Var, i, Exists_Var, i);
- }
- for(i=1; i<=no_out; i++) { // project out output variables
- M.set_map(Output_Var, i, Exists_Var, no_inp+i);
- }
- MapRel1(R, M, Comb_Id, eq_no, 0);
-
- if(relation_debug) {
- fprintf(DebugFile,"Computing deltas:\n");
- R.prefix_print(DebugFile);
- };
- R.finalize();
- assert(R.is_set()); // Should be since we map things to Set_Var
- assert(R.n_set() == eq_no);
- // skip_set_checks--;
- return R;
-}
-
-
-
-
-Relation DeltasToRelation(NOT_CONST Relation &D, int n_inputs, int n_outputs) {
- Relation R = consume_and_regurgitate(D);
-
- // skip_set_checks++;
- assert(!R.is_null());
- R.markAsRelation();
- int common = R.n_inp();
- assert(common <= n_inputs);
- assert(common <= n_outputs);
- R.split();
-
- if (R.max_ufs_arity() > 0) {
- assert(R.max_ufs_arity() == 0 &&
- "'Deltas' not ready for UFS yet"); // FERD
- fprintf(stderr, "'Deltas' not ready for UFS yet");
- exit(1);
- }
-
- R = Extend_Domain(R, n_inputs);
- R = Extend_Range(R, n_outputs);
- Mapping M(common+n_inputs, n_outputs);
- int i;
- for(i=1; i<=common; i++) { // Set up Deltas equalities
- EQ_Handle E = R.and_with_EQ();
- /* delta_i - w_i + r_i = 0 */
- E.update_coef(R.input_var(i), 1);
- E.update_coef(R.output_var(i), -1);
- E.update_coef(R.input_var(common+i), 1);
- E.finalize();
- M.set_map(Input_Var, i, Exists_Var, i); // Result will be a set
- }
- for(i=1; i<=n_inputs; i++) { // project out input variables
- M.set_map(Input_Var, common+i, Input_Var, i);
- }
- for(i=1; i<=n_outputs; i++) { // project out output variables
- M.set_map(Output_Var, i, Output_Var, i);
- }
- MapRel1(R, M, Comb_Id, n_inputs, n_outputs);
-
- if(relation_debug) {
- fprintf(DebugFile,"Computed DeltasToRelation:\n");
- R.prefix_print(DebugFile);
- }
- R.finalize();
- assert(!R.is_set());
- // skip_set_checks--;
- return R;
-}
-
-
-
-Relation Join(NOT_CONST Relation &G, NOT_CONST Relation &F) {
- return Composition(F, G);
-}
-
-bool prepare_relations_for_composition(Relation &r1,Relation &r2) {
- assert(!r2.is_null() && !r1.is_null());
-
- if(r2.is_set()) {
- int a1 = r1.max_ufs_arity_of_in(), a2 = r2.max_ufs_arity_of_set();
-
- if (a1 == 0 && a2 == 0)
- return true;
- else {
- assert(0 && "Can't compose relation and set with function symbols");
- fprintf(stderr, "Can't compose relation and set with function symbols");
- exit(1);
- return false; // make compiler shut up
- }
- }
-
- assert(r2.n_out() == r1.n_inp());
-
- int zeros = max(r1.query_guaranteed_leading_0s(),
- r2.query_guaranteed_leading_0s());
- return (zeros >= r1.max_ufs_arity_of_in()
- && zeros >= r2.max_ufs_arity_of_out());
-}
-
-//
-// Composition(F, G) = F o G, where F o G (x) = F(G(x))
-// That is, if F = { [i] -> [j] : ... }
-// and G = { [x] -> [y] : ... }
-// then Composition(F, G) = { [x] -> [j] : ... }
-//
-// align the output tuple for G and the input tuple for F,
-// these become existensially quantified variables
-// use the output tuple from F and the input tuple from G for the result
-// match named variables in G and F
-// formula is g & f
-//
-// If there are function symbols of arity > 0, we call special case
-// code to handle them. This is not set up for the r2.is_set case yet.
-//
-
-Relation Composition(NOT_CONST Relation &input_r1, NOT_CONST Relation &input_r2) {
- Relation r1 = consume_and_regurgitate(input_r1);
- Relation r2 = consume_and_regurgitate(input_r2);
- assert(!r2.is_null() && !r1.is_null());
-
- if(r2.is_set()) {
- int a1 = r1.max_ufs_arity_of_in(), a2 = r2.max_ufs_arity_of_set();
- if (r2.n_set() != r1.n_inp()) {
- fprintf(stderr,"Illegal composition/application, arities don't match\n");
- fprintf(stderr,"Trying to compute r1(r2)\n");
- fprintf(stderr,"arity of r2 must match input arity of r1\n");
- fprintf(stderr,"r1: ");
- r1.print_with_subs(stderr);
- fprintf(stderr,"r2: ");
- r2.print_with_subs(stderr);
- fprintf(stderr,"\n");
- assert(r2.n_set() == r1.n_inp());
- exit(1);
- }
- // skip_set_checks++;
- int i;
- if (a1 == 0 && a2 == 0) {
- int x = r1.n_out();
- Mapping m1(r1.n_inp(), r1.n_out());
- for(i=1; i<=r1.n_out(); i++) m1.set_map_out(i, Set_Var,i);
- for(i=1; i<=r1.n_inp(); i++) m1.set_map_in (i, Exists_Var,i);
- Mapping m2(r2.n_set());
- for(i=1; i<=r2.n_set(); i++) m2.set_map_set(i, Exists_Var,i);
- Relation R3 = MapAndCombineRel2(r2, r1, m2, m1, Comb_And);
- // skip_set_checks--;
- if (x == 0)
- R3.markAsSet();
- return R3;
- }
- else {
- assert(0 &&
- "Can't compose relation and set with function symbols");
- fprintf(stderr,
- "Can't compose relation and set with function symbols");
- exit(1);
- return Identity(0); // make compiler shut up
- }
- }
-
- if (r2.n_out() != r1.n_inp()) {
- fprintf(stderr,"Illegal composition, arities don't match\n");
- fprintf(stderr,"Trying to compute r1 compose r2\n");
- fprintf(stderr,"Output arity of r2 must match input arity of r1\n");
- fprintf(stderr,"r1: ");
- r1.print_with_subs(stderr);
- fprintf(stderr,"r2: ");
- r2.print_with_subs(stderr);
- fprintf(stderr,"\n");
- assert(r2.n_out() == r1.n_inp());
- exit(1);
- }
-
- int a1 = r1.max_ufs_arity_of_in(), a2 = r2.max_ufs_arity_of_out();
-
- if (a1 == 0 && a2 == 0 && 0 /* FERD - leading 0's go wrong here */ ) {
- // If no real UFS's, we can just use the general code:
- int i;
- Mapping m1(r1.n_inp(), r1.n_out());
- for(i=1; i<=r1.n_inp(); i++) m1.set_map_in (i, Exists_Var,i);
- for(i=1; i<=r1.n_out(); i++) m1.set_map_out(i, Output_Var,i);
- Mapping m2(r2.n_inp(), r2.n_out());
- for(i=1; i<=r2.n_inp(); i++) m2.set_map_in (i, Input_Var,i);
- for(i=1; i<=r2.n_out(); i++) m2.set_map_out(i, Exists_Var,i);
-
- return MapAndCombineRel2(r2, r1, m2, m1, Comb_And);
- }
- else {
- Relation result(r2.n_inp(), r1.n_out());
- int mid_size = r2.n_out();
- int i;
- for(i =1; i<=r2.n_inp(); i++)
- result.name_input_var(i,r2.input_var(i)->base_name);
- for(i =1; i<=r1.n_out(); i++)
- result.name_output_var(i,r1.output_var(i)->base_name);
-
- r1.simplify();
- r2.simplify();
-
- Rel_Body *b1 = r1.split(), *b2 = r2.split();
-
- if (b1 == b2) {
- assert(0 && "Compose: not ready to handle b1 == b2 yet.");
- fprintf(stderr, "Compose: not ready to handle b1 == b2 yet.\n");
- exit(1);
- }
-
- DNF *d1 = b1->DNFize();
- DNF *d2 = b2->DNFize();
-
- d1->count_leading_0s();
- d2->count_leading_0s();
- // Any conjucts with leading_0s == -1 must have >= max_arity leading 0s
- // What a gross way to do this. Ferd
-
- F_Exists *exists = result.add_exists();
- Section<Variable_ID> middle_tuple = exists->declare_tuple(mid_size);
- Map<Global_Var_ID, Variable_ID> lost_functions((Variable_ID)0);
-
- F_Or *result_conjs = exists->add_or();
-
- for (DNF_Iterator conj1(d1); conj1; conj1++)
- for (DNF_Iterator conj2(d2); conj2; conj2++) {
- // combine conj1 and conj2:
- // conj2's in becomes result's in; conj1's out becomes out
- // conj2's out and conj1's in get merged and exist. quant.
- // conj2's f(in) and conj1's f(out) become f(in) and f(out)
- // conj2's f(out) and conj1's f(in) get merged, evacuate:
- // if conj1 has f.arity leading 0s, they become f(out),
- // if conj2 has f.arity leading 0s, they become f(in)
- // if neither has enough 0s, they become a wildcard
- // and the result is inexact
- // old wildcards stay wildcards
-
-#if defined STUDY_EVACUATIONS
- study_evacuation(*conj1, *conj2, max(a1, a2));
-#endif
-
- Conjunct *copy1, *copy2;
- copy2 = (*conj2)->copy_conj_same_relation();
- copy1 = (*conj1)->copy_conj_same_relation();
-
- Variable_ID_Tuple remapped;
-
- int c1L0 = copy1->guaranteed_leading_0s;
- int c2L0 = copy2->guaranteed_leading_0s;
-
- int inexact = 0;
-
- // get rid of conj2's f(out)
- {
- for (Variable_ID_Iterator func(copy2->mappedVars); func; func++)
- if ((*func)->kind() == Global_Var) {
- Global_Var_ID f = (*func)->get_global_var();
- if (f->arity() > 0 && (*func)->function_of()==Output_Tuple) {
- if (c2L0 >= f->arity()) {
- (*func)->remap = r2.get_local(f, Input_Tuple);
- remapped.append(*func);
- }
- else if (c1L0 >= f->arity()) {
- // f->remap = copy1->get_local(f, Output_Tuple);
- // this should work with the current impl.
- // SHOULD BE A NO-OP?
- assert((*func)==r1.get_local(f,Output_Tuple));
- }
- else {
- Variable_ID f_quantified = lost_functions[f];
- if (!f_quantified) {
- f_quantified = exists->declare();
- lost_functions[f] = f_quantified;
- }
- inexact = 1;
- (*func)->remap = f_quantified;
- remapped.append(*func);
- }
- }
- }
- }
-
- // remap copy2's out
- for (i=1; i<=mid_size; i++) {
- r2.output_var(i)->remap = middle_tuple[i];
- }
-
- // do remapping for conj2, then reset everything so
- // we can go on with conj1
-
- copy2->remap();
- reset_remap_field(remapped);
- reset_remap_field(output_vars,mid_size);
-
-
- remapped.clear();
-
- // get rid of conj1's f(in)
- {
- for (Variable_ID_Iterator func(copy1->mappedVars); func; func++)
- if ((*func)->kind() == Global_Var) {
- Global_Var_ID f = (*func)->get_global_var();
- if (f->arity() > 0 && (*func)->function_of()==Input_Tuple) {
- if (c1L0 >= f->arity()) {
- (*func)->remap = r1.get_local(f,Output_Tuple);
- remapped.append(*func);
- }
- else if (c2L0 >= f->arity()) {
- // f->remap = copy2->get_local(f, Input_Tuple);
- // this should work with the current impl.
- // SHOULD BE A NO-OP?
- assert((*func)==r2.get_local(f,Input_Tuple));
- }
- else {
- Variable_ID f_quantified = lost_functions[f];
- if (!f_quantified) {
- f_quantified = exists->declare();
- lost_functions[f] = f_quantified;
- }
- inexact = 1;
- (*func)->remap = f_quantified;
- remapped.append(*func);
- }
- }
- }
- }
-
- // merge copy1's in with the already remapped copy2's out
- for (i=1; i<=mid_size; i++) {
- r1.input_var(i)->remap = middle_tuple[i];
- }
-
- copy1->remap();
- reset_remap_field(remapped);
- reset_remap_field(input_vars,mid_size);
-
- Conjunct *conj3 = merge_conjs(copy1, copy2, MERGE_COMPOSE, exists->relation());
- result_conjs->add_child(conj3);
- delete copy1;
- delete copy2;
-
- // make sure all variables used in the conjunct
- // are listed in the "result" relation
-
- for (Variable_ID_Iterator func(conj3->mappedVars); func; func++)
- if ((*func)->kind() == Global_Var) {
- Global_Var_ID f = (*func)->get_global_var();
- if (f->arity() > 0)
- result.get_local(f, (*func)->function_of());
- else
- result.get_local(f);
- }
-
- if (inexact)
- conj3->make_inexact();
- }
-
- // result.simplify(2, 4); // can't really do that now, will cause failure in chill
- result.finalize();
- r1 = r2 = Relation();
- return result;
- }
-}
-
-
-
-bool Is_Obvious_Subset(NOT_CONST Relation &input_r1, NOT_CONST Relation &input_r2) {
- Relation r1 = consume_and_regurgitate(input_r1);
- Relation r2 = consume_and_regurgitate(input_r2);
-
- assert(!r1.is_null() && !r2.is_null());
- Rel_Body *rr1 = r1.split();
- Rel_Body *rr2 = r2.split();
- rr1->simplify();
- rr2->simplify();
- use_ugly_names++;
-
- remap_DNF_vars(rr2, rr1);
-
- for(DNF_Iterator pd1(rr1->query_DNF()); pd1.live(); pd1.next()) {
- Conjunct *conj1 = pd1.curr();
- int found = false;
- for(DNF_Iterator pd2(rr2->query_DNF()); pd2.live(); pd2.next()) {
- Conjunct *conj2 = pd2.curr();
- if (!conj2->is_exact()) continue;
-
- Conjunct *cgist = merge_conjs(conj1, conj2, MERGE_GIST, conj2->relation());
-#ifndef NDEBUG
- cgist->setup_names();
-#endif
- if (cgist->redSimplifyProblem(2, 0) == noRed) {
- delete cgist;
- found = true;
- break;
- }
- delete cgist;
- }
- if (! found) {
- use_ugly_names--;
- r1 = r2 = Relation();
- return false;
- }
- }
- use_ugly_names--;
- r1 = r2 = Relation();
- return true;
-} /* Is_Obvious_Subset */
-
-
-bool do_subset_check(NOT_CONST Relation &input_r1,
- NOT_CONST Relation &input_r2);
-
-// do_subset_check really implements Must_Be_Subset anyway (due to
-// correct handling of inexactness in the negation code), but
-// still take upper and lower bounds here
-bool Must_Be_Subset(NOT_CONST Relation &r1, NOT_CONST Relation &r2) {
- Relation s1 = Upper_Bound(consume_and_regurgitate(r1));
- Relation s2 = Lower_Bound(consume_and_regurgitate(r2));
- return do_subset_check(s1,s2);
-}
-
-bool Might_Be_Subset(NOT_CONST Relation &r1, NOT_CONST Relation &r2) {
- Relation s1 = Lower_Bound(consume_and_regurgitate(r1));
- Relation s2 = Upper_Bound(consume_and_regurgitate(r2));
- return do_subset_check(s1,s2);
-}
-
-bool May_Be_Subset(NOT_CONST Relation &r1, NOT_CONST Relation &r2){
- return Might_Be_Subset(r1,r2);
-}
-
-
-
-
-//
-// F Must_Be_Subset G
-// Test that (f => g) === (~f | g) is a Tautology
-// or that (f & ~g) is unsatisfiable:
-// align the input tuples (if any) for F and G
-// align the output tuples (if any) for F and G
-// Special case: if r2 has a single conjunct then use HasRedQeuations.
-//
-
-bool do_subset_check(NOT_CONST Relation &input_r1,
- NOT_CONST Relation &input_r2) {
- Relation r1 = consume_and_regurgitate(input_r1);
- Relation r2 = consume_and_regurgitate(input_r2);
- if (r1.is_null() || r2.is_null())
- throw std::invalid_argument("null relation");
- if (r1.n_inp() != r2.n_inp() || r1.n_out() != r2.n_out())
- throw std::invalid_argument("relation arity does not match");
-
- // assert(!r1.is_null() && !r2.is_null());
- // skip_set_checks++;
- // assert(r1.n_inp() == r2.n_inp());
- // assert(r1.n_out() == r2.n_out());
- // skip_set_checks--;
- r1.simplify(1,0);
- r2.simplify(2,2);
- Rel_Body *rr1 = r1.split();
-
- if(relation_debug) {
- fprintf(DebugFile, "\n$$$ Must_Be_Subset IN $$$\n");
- }
-
- bool c = true;
-
- // Check each conjunct separately
- for(DNF_Iterator pd(rr1->query_DNF()); c && pd.live(); ) {
- Relation tmp(r1,pd.curr());
- pd.next();
-#ifndef CHECK_MAYBE_SUBSET
- if (pd.live())
- c = !Difference(tmp,copy(r2)).is_upper_bound_satisfiable();
- else
- c = !Difference(tmp,r2).is_upper_bound_satisfiable();
-#else
- Relation d=Difference(copy(tmp), copy(r2));
- c=!d.is_upper_bound_satisfiable();
- if (!c && !d.is_exact()) { // negation-induced inexactness
- static int OMEGA_WHINGE = -1;
- if (OMEGA_WHINGE < 0) {
- OMEGA_WHINGE = getenv("OMEGA_WHINGE") ? atoi(getenv("OMEGA_WHINGE")) : 0;
- }
- if (OMEGA_WHINGE) {
- fprintf(DebugFile,"\n===== r1 is maybe a Must_Be_Subset of r2 ========\n");
- fprintf(DebugFile,"-------> r1:\n");
- tmp.print_with_subs(DebugFile);
- fprintf(DebugFile,"-------> r2:\n");
- r2.print_with_subs(DebugFile);
- fprintf(DebugFile,"-------> r1-r2:\n");
- d.print_with_subs(DebugFile);
- }
- }
-#endif
- }
-
- if(relation_debug) {
- fprintf(DebugFile, "$$$ Must_Be_Subset OUT $$$\n");
- }
- r1 = r2 = Relation();
- return c;
-}
-
-
-//
-// F minus G
-//
-Relation Difference(NOT_CONST Relation &input_r1,
- NOT_CONST Relation &input_r2) {
- Relation r1 = consume_and_regurgitate(input_r1);
- Relation r2 = consume_and_regurgitate(input_r2);
- if (r1.is_null() || r2.is_null())
- return r1;
- if (r1.n_inp() != r2.n_inp() || r1.n_out() != r2.n_out())
- throw std::invalid_argument("relation arity does not match");
-
- //assert(!r1.is_null() && !r2.is_null());
- // skip_set_checks++;
- // assert(r1.n_inp() == r2.n_inp());
- // assert(r1.n_out() == r2.n_out());
-
- int i;
- Mapping m1(r1.n_inp(), r1.n_out());
- for(i=1; i<=r1.n_inp(); i++) m1.set_map_in (i, Input_Var,i);
- for(i=1; i<=r1.n_out(); i++) m1.set_map_out(i, Output_Var,i);
- Mapping m2(r2.n_inp(), r2.n_out());
- for(i=1; i<=r2.n_inp(); i++) m2.set_map_in (i, Input_Var,i);
- for(i=1; i<=r2.n_out(); i++) m2.set_map_out(i, Output_Var,i);
- // skip_set_checks--;
-
- return MapAndCombineRel2(r1, r2, m1, m2, Comb_AndNot);
-}
-
-//
-// complement F
-// not F
-//
-Relation Complement(NOT_CONST Relation &S) {
- Relation r = consume_and_regurgitate(S);
- if (r.is_null())
- return r;
-
- // assert(!r.is_null());
- // skip_set_checks++;
- int i;
- Mapping m(r.n_inp(), r.n_out());
- for(i=1; i<=r.n_inp(); i++) m.set_map_in (i, Input_Var,i);
- for(i=1; i<=r.n_out(); i++) m.set_map_out(i, Output_Var,i);
- // skip_set_checks--;
-
- MapRel1(r, m, Comb_AndNot, -1, -1, false);
- return r;
-}
-
-
-//
-// Compute (gist r1 given r2).
-// Currently we assume that r2 has only one conjunct.
-// r2 may have zero input and output OR may have # in/out vars equal to r1.
-//
-Relation GistSingleConjunct(NOT_CONST Relation &input_R1,
- NOT_CONST Relation &input_R2, int effort) {
- Relation R1 = consume_and_regurgitate(input_R1);
- Relation R2 = consume_and_regurgitate(input_R2);
-
- // skip_set_checks++;
- assert(!R1.is_null() && !R2.is_null());
- assert((R1.n_inp() == R2.n_inp() && R1.n_out() == R2.n_out()) ||
- (R2.n_inp() == 0 && R2.n_out() == 0));
- R1.simplify();
- R2.simplify();
- Rel_Body *r1 = R1.split();
- Rel_Body *r2 = R2.split();
-
- if(relation_debug) {
- fprintf(DebugFile, "\n### GIST computation start ### [\n");
- R1.prefix_print(DebugFile);
- R2.prefix_print(DebugFile);
- fprintf(DebugFile, "### ###\n");
- }
-
-
-// The merged conjunct has to have the variables of either r1 or r2, but
-// not both. Use r1's, since it'll be cheaper to remap r2's single conj.
- remap_DNF_vars(r2, r1);
- assert(r2->is_upper_bound_satisfiable() && "Gist: second operand is FALSE");
- // skip_set_checks--;
-
- Conjunct *known = r2->single_conjunct();
- assert(known != NULL && "Gist: second operand has more than 1 conjunct");
-
- DNF *new_dnf = new DNF();
- for(DNF_Iterator pd(r1->simplified_DNF); pd.live(); pd.next()) {
- Conjunct *conj = pd.curr();
- Conjunct *cgist = merge_conjs(known, conj, MERGE_GIST, conj->relation()); // Uses r1's vars
- cgist->set_relation(r1); // Thinks it's part of r1 now, for var. purposes
- if(simplify_conj(cgist, true, effort+1, EQ_RED)) {
- /* Throw out black constraints, turn red constraints into black */
- cgist->rm_color_constrs();
- if(cgist->is_true()) {
- delete new_dnf;
- delete cgist;
- // skip_set_checks++;
- Relation retval = Relation::True(r1->n_inp(), r2->n_out());
- // retval.finalize();
- retval.simplify();
- if(R1.is_set() && R2.is_set()) retval.markAsSet();
- // skip_set_checks--;
- return retval;
- }
- else {
- // since modular equations might be changed, simplify again!
- simplify_conj(cgist, true, effort+1, EQ_BLACK);
-
- new_dnf->add_conjunct(cgist);
- }
- }
- }
- delete r1->simplified_DNF;
- r1->simplified_DNF = new_dnf;
- assert(!r1->is_null());
- R1.finalize();
- if(relation_debug) {
- fprintf(DebugFile, "] ### GIST computation end ###\n");
- R1.prefix_print(DebugFile);
- fprintf(DebugFile, "### ###\n");
- }
- return(R1);
-}
-
-
-//
-// Compute gist r1 given r2. r2 can have multiple conjuncts,
-// return result is always simplified.
-//
-Relation Gist(NOT_CONST Relation &input_R1,
- NOT_CONST Relation &input_R2, int effort) {
- Relation R1 = consume_and_regurgitate(input_R1);
- Relation R2 = consume_and_regurgitate(input_R2);
- if (R1.is_null())
- return R1;
- // change the Gist semantics to allow r2 be null -- by chun 07/30/2007
- if (R2.is_null()) {
- R1.simplify();
- return R1;
- }
- if (!(R1.n_inp() == 0 && R2.n_out() == 0) &&
- (R1.n_inp() != R2.n_inp() || R1.n_out() != R2.n_out()))
- throw std::invalid_argument("relation arity does not match");
-
- // skip_set_checks++;
- // assert(!R1.is_null());
- // assert(R2.is_null() ||
- // (R1.n_inp() == R2.n_inp() && R1.n_out() == R2.n_out()) ||
- // (R2.n_inp() == 0 && R2.n_out() == 0));
- // skip_set_checks--;
- R2.simplify();
-
- if(relation_debug) {
- fprintf(DebugFile, "\n### multi-GIST computation start ### [\n");
- R1.prefix_print(DebugFile);
- R2.prefix_print(DebugFile);
- fprintf(DebugFile, "### ###\n");
- }
-
- if (!R2.is_upper_bound_satisfiable())
- return Relation::True(R1);
- if (R2.is_obvious_tautology()) {
- R1.simplify();
- return R1;
- }
- R1.simplify();
-
- if (!Intersection(copy(R1), copy(R2)).is_upper_bound_satisfiable())
- return Relation::False(R1);
-
- int nconj1=0;
- for (DNF_Iterator di(R1.simplified_DNF()); di.live(); di.next())
- nconj1++;
- int nconj2=0;
- for (DNF_Iterator di2(R2.simplified_DNF()); di2.live(); di2.next())
- nconj2++;
-
- {
- static int OMEGA_WHINGE = -1;
- if (OMEGA_WHINGE < 0) {
- OMEGA_WHINGE = getenv("OMEGA_WHINGE") ? atoi(getenv("OMEGA_WHINGE")) : 0;
- }
- if (OMEGA_WHINGE && (nconj1 + nconj2 > 50)) {
- fprintf(DebugFile,"WOW!!!! - Gist (%d conjuncts, %d conjuncts)!!!\n",
- nconj1,nconj2);
- fprintf(DebugFile,"Base:\n");
- R1.prefix_print(DebugFile);
- fprintf(DebugFile,"Context:\n");
- R2.prefix_print(DebugFile);
- }
- }
-
- if (nconj2==1)
- return GistSingleConjunct(R1,R2, effort);
- else {
- R1.simplify(0,1);
- R2.simplify(0,1);
- Relation G = Relation::True(R1);
- for (DNF_Iterator di2(R2.simplified_DNF()); di2.live(); di2.next()) {
- Conjunct * c2 = di2.curr();
- Relation G2 = Relation::False(R1);
- for (DNF_Iterator di1(R1.simplified_DNF()); di1.live(); di1.next()) {
- Conjunct * c1 = di1.curr();
- Relation G1=GistSingleConjunct(Relation(R1,c1), Relation(R2,c2),effort);
-
- if (G1.is_obvious_tautology()) {
- G2 = G1;
- break;
- }
- else if (!G1.is_upper_bound_satisfiable() || !G1.is_exact()) {
- if(relation_debug) {
- fprintf(DebugFile, "gist A given B is unsatisfiable\n");
- fprintf(DebugFile, "A:\n");
- Relation(R1,c1).prefix_print(DebugFile);
- fprintf(DebugFile, "B:\n");
- Relation(R2,c2).prefix_print(DebugFile);
- fprintf(DebugFile, "\n");
- }
- //G1 = Relation(R1,c1);
- return R1;
- }
- else if(0 && G1.is_exact() && !Must_Be_Subset(Relation(R1,c1),copy(G1))) {
- fprintf(DebugFile,"Unexpected non-Must_Be_Subset gist result!\n");
- fprintf(DebugFile,"base: \n");
- Relation(R1,c1).prefix_print(DebugFile);
- fprintf(DebugFile,"context: \n");
- Relation(R2,c2).prefix_print(DebugFile);
- fprintf(DebugFile,"result: \n");
- G1.prefix_print(DebugFile);
- fprintf(DebugFile,"base not subseteq result: \n");
- assert(!G1.is_exact() || Must_Be_Subset(Relation(R1,c1),copy(G1)));
- }
- G2=Union(G2,G1);
- }
- G2.simplify(0,1);
- G = Intersection(G,G2);
- G.simplify(0,1);
- if(relation_debug) {
- fprintf(DebugFile, "result so far is:\n");
- G.prefix_print(DebugFile);
- }
- }
-
- if(relation_debug) {
- fprintf(DebugFile, "\n### end multi-GIST computation ### ]\n");
- fprintf(DebugFile, "G is:\n");
- G.prefix_print(DebugFile);
- fprintf(DebugFile, "### ###\n");
- }
-#if ! defined NDEBUG
- Relation S1 = Intersection(copy(R1), copy(R2));
- Relation S2 = Intersection(copy(G), copy(R2));
-
-
- if(relation_debug) {
- fprintf(DebugFile, "\n---->[Checking validity of the GIST result\n");
- fprintf(DebugFile, "for G=gist R1 given R2:\n");
- fprintf(DebugFile, "R1 intersect R2 is:\n");
- S1.print_with_subs(DebugFile);
- fprintf(DebugFile, "\nG intersect R2 is:\n");
- S2.print_with_subs(DebugFile);
- fprintf(DebugFile, "---->]\n");
- }
- assert (!S1.is_exact() || !S2.is_exact() || (Must_Be_Subset(copy(S1),copy(S2)) && Must_Be_Subset(copy(S2),copy(S1))));
-#endif
- return G;
- }
-}
-
-
-// Project away all input and output variables.
-Relation Project_On_Sym(NOT_CONST Relation &S,
- NOT_CONST Relation &input_context) {
- Relation R = consume_and_regurgitate(S);
- Relation context = consume_and_regurgitate(input_context);
- int i;
-
- // skip_set_checks++;
- leave_pufs_untouched++;
- int in_arity = R.max_ufs_arity_of_in();
- int out_arity = R.max_ufs_arity_of_out();
- assert(!R.is_null());
- R.split();
-
- int no_inp = R.n_inp();
- int no_out = R.n_out();
- Mapping M(no_inp, no_out);
-
- for(i=1; i<=no_inp; i++) { // project out input variables
- M.set_map(Input_Var, i, Exists_Var, i);
- }
- for(i=1; i<=no_out; i++) { // project out output variables
- M.set_map(Output_Var, i, Exists_Var, no_inp+i);
- }
- MapRel1(R, M, Comb_Id, 0, 0);
-
- R.finalize();
- if (in_arity) R = Extend_Domain(R,in_arity);
- if (out_arity) R = Extend_Range(R,out_arity);
-
- int d = min(in_arity,out_arity);
- if (d && !context.is_null()) {
- int g = min(d,context.query_guaranteed_leading_0s());
- int p = min(d,context.query_possible_leading_0s());
- int dir = context.query_leading_dir();
- R.enforce_leading_info(g,p,dir);
- }
-
- leave_pufs_untouched--;
- // skip_set_checks--;
- if(relation_debug) {
- fprintf(DebugFile,"\nProjecting onto symbolic (%d,%d):\n",in_arity,out_arity);
- R.prefix_print(DebugFile);
- }
- return R;
-}
-
-
-//
-// Project out global variable g from relation r
-//
-Relation Project(NOT_CONST Relation &S, Global_Var_ID g) {
- Relation R = consume_and_regurgitate(S);
- assert(!R.is_null());
-
- skip_finalization_check++;
-
- Rel_Body *r = R.split();
- r->DNF_to_formula();
- Formula *f = r->rm_formula();
- F_Exists *ex = r->add_exists();
- ex->add_child(f);
-
- if (g->arity() == 0) {
- assert(R.has_local(g) && "Project: Relation doesn't contain variable to be projected");
- Variable_ID v = R.get_local(g);
-
- bool rmd = rm_variable(r->Symbolic,v);
- assert(rmd && "Project: Variable to be projected doesn't exist");
-
- v->remap = ex->declare(v->base_name);
- f->remap();
- v->remap = v;
- }
- else {
- assert((R.has_local(g, Input_Tuple) || R.has_local(g, Output_Tuple)) && "Project: Relation doesn't contain variable to be projected");
-
- if (R.has_local(g, Input_Tuple)) {
- Variable_ID v = R.get_local(g, Input_Tuple);
-
- bool rmd = rm_variable(r->Symbolic,v);
- assert(rmd && "Project: Variable to be projected doesn't exist");
-
- v->remap = ex->declare(v->base_name);
- f->remap();
- v->remap = v;
- }
- if (R.has_local(g, Output_Tuple)) {
- Variable_ID v = R.get_local(g, Output_Tuple);
-
- bool rmd = rm_variable(r->Symbolic,v);
- assert(rmd && "Project: Variable to be projected doesn't exist");
-
- v->remap = ex->declare(v->base_name);
- f->remap();
- v->remap = v;
- }
- }
-
- skip_finalization_check--;
-
- R.finalize();
- return R;
-}
-
-
-//
-// Project all symbolic variables from relation r
-//
-Relation Project_Sym(NOT_CONST Relation &S) {
- Relation R = consume_and_regurgitate(S);
- assert(!R.is_null());
-
- Rel_Body *r = R.split();
- r->DNF_to_formula();
-
- Formula *f = r->rm_formula();
-
- skip_finalization_check++;
- F_Exists *ex = r->add_exists();
- for(Variable_ID_Iterator R_Sym(r->Symbolic); R_Sym; R_Sym++) {
- Variable_ID v = *R_Sym;
- v->remap = ex->declare(v->base_name);
- }
- ex->add_child(f);
- skip_finalization_check--;
-
- f->remap();
-
- reset_remap_field(r->Symbolic);
- r->Symbolic.clear();
-
- R.finalize();
- return R;
-}
-
-//
-// Project specified variables, leaving those variables with no constraints.
-//
-Relation Project(NOT_CONST Relation &S, Sequence<Variable_ID> &s) {
- // This is difficult to do with mappings. This cheats, since it is
- // much easier and more straightforward.
-
- Relation R = consume_and_regurgitate(S);
- assert(!R.is_null());
-
- Rel_Body *r = R.split();
- r->DNF_to_formula();
- Formula *f = r->rm_formula();
- bool need_symbolic_clear = false;
-
- skip_finalization_check++;
- F_Exists *ex = r->add_exists();
- for(int i = 1; i <= s.size(); i++) {
- if (s[i]->kind() == Global_Var)
- need_symbolic_clear = true;
- s[i]->remap = ex->declare(s[i]->base_name);
- }
- ex->add_child(f);
- skip_finalization_check--;
-
- f->remap();
-
- reset_remap_field(s);
- if (need_symbolic_clear)
- r->Symbolic.clear();
-
- R.finalize();
- return R;
-}
-
-Relation Project(NOT_CONST Relation &S, int pos, Var_Kind vkind) {
- Variable_ID v = 0; // shut the compiler up
- switch (vkind) {
- case Input_Var:
- v = input_vars[pos];
- break;
- case Output_Var:
- v = output_vars[pos];
- break;
- // case Set_Var:
- // v = set_vars[pos];
- // break;
- default:
- assert(0);
- }
-
- return Project(S, v);
-}
-
-Relation Project(NOT_CONST Relation &S, Variable_ID v) {
- Tuple<Variable_ID> s;
- s.append(v);
- return Project(S, s);
-}
-
-//
-// Variables in DNF of map_rel reference declarations of map_rel (or not).
-// remap_DNF_vars makes them to reference declarations of ref_rel.
-// Ref_rel can get new global variable declarations in the process.
-//
-void remap_DNF_vars(Rel_Body *map_rel, Rel_Body *ref_rel) {
- // skip_set_checks++;
- assert (map_rel->simplified_DNF);
- assert (ref_rel->simplified_DNF);
-
- // skip_set_checks++;
-
- for(DNF_Iterator pd(map_rel->simplified_DNF); pd.live(); pd.next()) {
- Conjunct *cc = pd.curr();
- Variable_ID_Tuple &mvars = cc->mappedVars;
- for(Variable_Iterator mvarsIter=mvars; mvarsIter; mvarsIter++) {
- Variable_ID v = *mvarsIter;
- switch(v->kind()) {
- case Input_Var:
- assert(ref_rel->n_inp() >= v->get_position());
- break;
- case Output_Var:
- assert(ref_rel->n_out() >= v->get_position());
- break;
- case Global_Var:
- // The assignment is a noop, but tells ref_rel that the global may be
- // used inside it, which is required.
- *mvarsIter = ref_rel->get_local(v->get_global_var(),v->function_of());
- break;
- case Wildcard_Var:
- break;
- default:
- assert(0 && "bad variable kind");
- }
- }
- }
- // skip_set_checks--;
-}
-
-
-Relation projectOntoJust(Relation R, Variable_ID v) {
- // skip_set_checks++;
-
- int ivars = R.n_inp(), ovars = R.n_out();
- int ex_ivars= 0, ex_ovars = 0;
-
- assert(v->kind() == Input_Var || v->kind() == Output_Var);
- if (v->kind() == Input_Var) {
- ex_ivars = 1;
- R = Extend_Domain(R,1);
- }
- else {
- ex_ovars = 1;
- R = Extend_Range(R,1);
- }
-
- // Project everything except v
- Mapping m(ivars+ex_ivars,ovars+ex_ovars);
- int j;
- for(j = 1; j <=ivars+ex_ivars; j++) m.set_map_in(j, Exists_Var, j);
- for(j = 1; j <=ovars+ex_ovars; j++) m.set_map_out(j, Exists_Var, j+ivars+ex_ivars);
- m.set_map(v->kind(), v->get_position(), v->kind(), v->get_position());
-
- MapRel1(R, m, Comb_Id,-1,-1);
- R.finalize();
- // skip_set_checks--;
- return R;
-}
-
-//static
-//void copyEQtoGEQ(GEQ_Handle &g, const EQ_Handle &e, bool negate) {
-//extern void copy_constraint(Constraint_Handle H, Constraint_Handle initial);
-// copy_constraint(g, e);
-//}
-
-
-Relation EQs_to_GEQs(NOT_CONST Relation &S, bool excludeStrides) {
- Relation R = consume_and_regurgitate(S);
- assert(R.is_simplified());
- use_ugly_names++;
- for (DNF_Iterator s(R.query_DNF()); s.live(); s.next())
- s.curr()->convertEQstoGEQs(excludeStrides);
- use_ugly_names--;
- return R;
-}
-
-
-// Tuple to find values for is input+output
-Relation Symbolic_Solution(NOT_CONST Relation &R) {
- Relation S = consume_and_regurgitate(R);
- Tuple<Variable_ID> vee;
- // skip_set_checks++;
- int i;
- for(i = 1; i <= S.n_inp(); i++) vee.append(input_var(i));
- for(i = 1; i <= S.n_out(); i++) vee.append(output_var(i));
- // skip_set_checks--;
-
- return Solution(S, vee);
-}
-
-
-// Tuple to find values for is given as arg, plus input and output
-Relation Symbolic_Solution(NOT_CONST Relation &R, Sequence<Variable_ID> &for_these){
- Relation S = consume_and_regurgitate(R);
- Tuple<Variable_ID> vee;
- // skip_set_checks++;
- int i;
- for(Any_Iterator<Variable_ID> it(for_these); it; it++)
- vee.append(*it);
- for(i = 1; i <= S.n_inp(); i++) vee.append(input_var(i));
- for(i = 1; i <= S.n_out(); i++) vee.append(output_var(i));
- // skip_set_checks--;
-
- return Solution(S, vee);
-}
-
-
-// Tuple to find values for is input+output+global_decls
-Relation Sample_Solution(NOT_CONST Relation &R) {
- Relation S = consume_and_regurgitate(R);
-
- Tuple<Variable_ID> vee;
-
- // skip_set_checks++;
- int i;
- for(i = 1; i <= S.global_decls()->size(); i++)
- vee.append((*S.global_decls())[i]);
- for(i = 1; i <= S.n_inp(); i++) vee.append(input_var(i));
- for(i = 1; i <= S.n_out(); i++) vee.append(output_var(i));
- // skip_set_checks--;
-
- return Solution(S,vee);
-}
-
-
-// Tuple to find values is given as arg
-Relation Solution(NOT_CONST Relation &S, Sequence<Variable_ID> &for_these ) {
- Relation R = consume_and_regurgitate(S);
- if (R.is_null())
- return R;
-
- //assert(!R.is_null());
-
- if(!R.is_upper_bound_satisfiable()) {
- return Relation::False(R);
- }
-
- bool inexactAnswer=false;
- if(R.is_inexact()) {
- if(R.is_lower_bound_satisfiable())
- R = Lower_Bound(R); // a solution to LB is a solution to the relation
- else {
- // A solution to the UB may not be a solution to the relation:
- // There may be a solution which satisfies all known constraints, but
- // we have no way of knowing if it satisifies the unknown constraints.
- inexactAnswer = true;
- R = Upper_Bound(R);
- }
- }
-
- Sequence<Variable_ID> &vee = for_these;
- for (DNF_Iterator di(R.query_DNF()); di; di++) {
- Relation current(R, *di);
- int i;
- for(i = vee.size()-1; i >= 0; i--) {
- bool some_constraints = false, one_stride = false;
-
- int current_var = vee.size()-i;
- Section<Variable_ID> s(&vee,current_var+1,i);
-
- // Query variable in vee[current_var]
- Relation projected = Project(copy(current), s);
-
- retry_solution:
- assert(projected.has_single_conjunct());
- DNF_Iterator one = projected.query_DNF();
-
- // Look for candidate EQ's
- EQ_Handle stride;
- EQ_Iterator ei(*one);
- for(; ei; ei++) {
- if((*ei).get_coef(vee[current_var]) != 0) {
- if(!Constr_Vars_Iter(*ei,true).live()) { // no wildcards
- some_constraints = true;
- // Add this constraint to the current as an EQ
- current.and_with_EQ(*ei);
- break;
- }
- else {
- one_stride = !one_stride && !some_constraints;
- stride = *ei;
- }
- }
- }
- if(ei)
- continue; // Found an EQ, skip to next variable
- else if (one_stride && !some_constraints) {
- // if unconstrained except for a stride, pick stride as value
- Constr_Vars_Iter cvi(stride,true);
- assert(cvi.live());
- cvi++;
- if(!cvi) { // Just one existentially quantified variable
- Relation current_copy = current;
- EQ_Handle eh = current_copy.and_with_EQ();
- for(Constr_Vars_Iter si = stride; si; si++)
- if((*si).var->kind() != Wildcard_Var){
- // pick "0" for wildcard, don't set its coef
- eh.update_coef((*si).var, (*si).coef);
- }
- eh.update_const(stride.get_const());
- if(current_copy.is_upper_bound_satisfiable()){
- current = current_copy;
- continue; // skip to next var
- }
- }
- some_constraints = true; // count the stride as a constraint
- }
-
- // Can we convert a GEQ?
- GEQ_Iterator gi(*one);
- for(; gi; gi++) {
- if((*gi).get_coef(vee[current_var]) != 0) {
- some_constraints = true;
- if(!Constr_Vars_Iter(*gi,true).live()) { // no wildcards
- Relation current_copy = current;
- // Add this constraint to the current as an EQ & test
- current_copy.and_with_EQ(*gi);
- if (current_copy.is_upper_bound_satisfiable()) {
- current = current_copy;
- break;
- }
- }
- }
- }
- if (gi) continue; // Turned a GEQ into EQ, skip to next
-
- // Remove wildcards, try try again
- Relation approx = Approximate(copy(projected));
- assert(approx.has_single_conjunct());
- DNF_Iterator d2 = approx.query_DNF();
-
- EQ_Iterator ei2(*d2);
- for(; ei2; ei2++) {
- if((*ei2).get_coef(vee[current_var]) != 0) {
- some_constraints = true;
- assert(!Constr_Vars_Iter(*ei2,true).live()); // no wildcards
- Relation current_copy = current;
- // Add this constraint to the current as an EQ & test
- current_copy.and_with_EQ(*ei2);
- if (current_copy.is_upper_bound_satisfiable()) {
- current = current_copy;
- break;
- }
- }
- }
- if(ei2) continue; // Found an EQ, skip to next variable
-
- GEQ_Iterator gi2(*d2);
- for(; gi2; gi2++) {
- if((*gi2).get_coef(vee[current_var]) != 0) {
- some_constraints = true;
- assert(!Constr_Vars_Iter(*gi2,true).live()); // no wildcards
- Relation current_copy = current;
- // Add this constraint to the current as an EQ & test
- current_copy.and_with_EQ(*gi2);
- if (current_copy.is_upper_bound_satisfiable()) {
- current = current_copy;
- break;
- }
- }
- }
- if(gi2) continue;
-
- if(!some_constraints) { // No constraints on this variable were found
- EQ_Handle e = current.and_with_EQ();
- e.update_const(-42); // Be creative
- e.update_coef(vee[current_var], 1);
- continue;
- }
- else { // What to do? Find a wildcard to discard
- Variable_ID wild = NULL;
-
- for (GEQ_Iterator gi(*one); gi; gi++)
- if ((*gi).get_coef(vee[current_var]) != 0 && (*gi).has_wildcards()) {
- Constr_Vars_Iter cvi(*gi, true);
- wild = (*cvi).var;
- break;
- }
- if (wild == NULL)
- for (EQ_Iterator ei(*one); ei; ei++)
- if ((*ei).get_coef(vee[current_var]) != 0 && (*ei).has_wildcards()) {
- Constr_Vars_Iter cvi(*ei, true);
- wild = (*cvi).var;
- break;
- }
-
- if (wild != NULL) {
- // skip_set_checks++;
-
- Relation R2;
- {
- Tuple<Relation> r(1);
- r[1] = projected;
- Tuple<std::map<Variable_ID, std::pair<Var_Kind, int> > > mapping(1);
- mapping[1][wild] = std::make_pair(vee[current_var]->kind(), vee[current_var]->get_position());
- mapping[1][vee[current_var]] = std::make_pair(Exists_Var, 1);
- Tuple<bool> inverse(1);
- inverse[1] = false;
- R2 = merge_rels(r, mapping, inverse, Comb_And);
- }
-
- Variable_ID R2_v;
- switch (vee[current_var]->kind()) {
- // case Set_Var:
- case Input_Var: {
- int pos = vee[current_var]->get_position();
- R2_v = R2.input_var(pos);
- break;
- }
- case Output_Var: {
- int pos = vee[current_var]->get_position();
- R2_v = R2.output_var(pos);
- break;
- }
- case Global_Var: {
- Global_Var_ID g = vee[current_var]->get_global_var();
- if (g->arity() == 0)
- R2_v = R2.get_local(g);
- else
- R2_v = R2.get_local(g, vee[current_var]->function_of());
- }
- default:
- assert(0);
- }
-
- Relation S2;
- {
- Tuple<Variable_ID> vee;
- vee.append(R2_v);
- S2 = Solution(R2, vee);
- }
-
- Variable_ID S2_v;
- switch (vee[current_var]->kind()) {
- // case Set_Var:
- case Input_Var: {
- int pos = vee[current_var]->get_position();
- S2_v = S2.input_var(pos);
- break;
- }
- case Output_Var: {
- int pos = vee[current_var]->get_position();
- S2_v = S2.output_var(pos);
- break;
- }
- case Global_Var: {
- Global_Var_ID g = vee[current_var]->get_global_var();
- if (g->arity() == 0)
- S2_v = S2.get_local(g);
- else
- S2_v = S2.get_local(g, vee[current_var]->function_of());
- }
- default:
- assert(0);
- }
-
- Relation R3;
- {
- Tuple<Relation> r(2);
- r[1] = projected;
- r[2] = S2;
- Tuple<std::map<Variable_ID, std::pair<Var_Kind, int> > > mapping(2);
- mapping[1][wild] = std::make_pair(Exists_Var, 1);
- mapping[2][S2_v] = std::make_pair(Exists_Var, 1);
- Tuple<bool> inverse(2);
- inverse[1] = inverse[2] = false;
- R3 = merge_rels(r, mapping, inverse, Comb_And);
- }
-
- // skip_set_checks--;
-
- if (R3.is_upper_bound_satisfiable()) {
- projected = R3;
- goto retry_solution;
- }
- }
- }
-
- // If we get here, we failed to find a suitable constraint for
- // this variable at this conjunct, look for another conjunct.
- break;
- }
-
- if (i < 0) { // solution found
- if(inexactAnswer)
- current.and_with_and()->add_unknown();
- current.finalize();
- return current;
- }
- }
-
- // No solution found for any conjunct, we bail out.
- fprintf(stderr,"Couldn't find suitable constraint for variable\n");
- return Relation::Unknown(R);
-}
-
-
-Relation Approximate(NOT_CONST Relation &input_R, bool strides_allowed) {
- Relation R = consume_and_regurgitate(input_R);
- if (R.is_null())
- return R;
-
- // assert(!R.is_null());
- Rel_Body *r = R.split();
-
- // approximate can be used to remove lambda variables from farkas,
- // so be careful not to invoke simplification process for integers.
- r->simplify(-1,-1);
-
- if (pres_debug) {
- fprintf(DebugFile,"Computing approximation ");
- if (strides_allowed) fprintf(DebugFile,"with strides allowed ");
- fprintf(DebugFile,"[ \n");
- r->prefix_print(DebugFile);
- }
-
- use_ugly_names++;
- for (DNF_Iterator pd(r->simplified_DNF); pd.live(); ) {
- Conjunct *C = pd.curr();
- pd.next();
-
- for(int i = 0; i < C->problem->nGEQs; i++)
- C->problem->GEQs[i].touched = 1;
-
- C->reorder();
- if(C->problem->simplifyApproximate(strides_allowed)==0) {
- r->simplified_DNF->rm_conjunct(C);
- delete C;
- }
- else {
- C->simplifyProblem(1,0,1);
-
- free_var_decls(C->myLocals); C->myLocals.clear();
-
- Problem *p = C->problem;
- Variable_ID_Tuple new_mapped(0); // This is expanded by "append"
- for (int i = 1; i <= p->safeVars; i++) {
- // what is now in column i used to be in column p->var[i]
- Variable_ID v = C->mappedVars[p->var[i]];
- assert (v->kind() != Wildcard_Var);
- new_mapped.append(v);
- }
- assert(strides_allowed || C->problem->nVars == C->problem->safeVars);
- C->mappedVars = new_mapped;
- for (int i = p->safeVars+1; i <= p->nVars; i++) {
- Variable_ID v = C->declare();
- C->mappedVars.append(v);
- }
-
-
- // reset var and forwarding address if desired.
- p->variablesInitialized = 0;
- for(int i = 1; i < C->problem->nVars; i++)
- C->problem->var[i] = C->problem->forwardingAddress[i] = i;
- }
- }
-
- if (pres_debug)
- fprintf(DebugFile,"] done Computing approximation\n");
- use_ugly_names--;
- return R;
-}
-
-
-Relation Lower_Bound(NOT_CONST Relation &r) {
- Relation s = consume_and_regurgitate(r);
- s.interpret_unknown_as_false();
- return s;
-}
-
-
-Relation Upper_Bound(NOT_CONST Relation &r) {
- Relation s = consume_and_regurgitate(r);
- s.interpret_unknown_as_true();
- return s;
-}
-
-
-bool operator==(const Relation &, const Relation &) {
- assert(0 && "You rilly, rilly don't want to do this.\n");
- abort();
- return false;
-}
-
-
-namespace { // supporting stuff for MapRel1 and MapAndCombine2
- // Determine if a mapping requires an f_exists node
- bool has_existentials(const Mapping &m) {
- for(int i=1;i<=m.n_in(); i++)
- if (m.get_map_in_kind(i) == Exists_Var) return true;
- for(int j=1;j<=m.n_out(); j++)
- if (m.get_map_out_kind(j) == Exists_Var) return true;
- return false;
- }
-
- void get_relation_arity_from_one_mapping(const Mapping &m1,
- int &in_req, int &out_req) {
- int j, i;
- in_req = 0; out_req = 0;
- for(i = 1; i <= m1.n_in(); i++) {
- j = m1.get_map_in_pos(i);
- switch(m1.get_map_in_kind(i)) {
- case Input_Var: in_req = max(in_req, j); break;
- // case Set_Var: in_req = max(in_req, j); break;
- case Output_Var: out_req = max(out_req, j); break;
- default: break;
- }
- }
- for(i = 1; i <= m1.n_out(); i++) {
- j = m1.get_map_out_pos(i);
- switch(m1.get_map_out_kind(i)) {
- case Input_Var: in_req = max(in_req, j); break;
- // case Set_Var: in_req = max(in_req, j); break;
- case Output_Var: out_req = max(out_req, j); break;
- default: break;
- }
- }
- }
-
- // Scan mappings to see how many input and output variables they require.
- void get_relation_arity_from_mappings(const Mapping &m1,
- const Mapping &m2,
- int &in_req, int &out_req) {
- int inreq1, inreq2, outreq1, outreq2;
- get_relation_arity_from_one_mapping(m1, inreq1, outreq1);
- get_relation_arity_from_one_mapping(m2, inreq2, outreq2);
- in_req = max(inreq1, inreq2);
- out_req = max(outreq1, outreq2);
- }
-}
-
-
-//
-// Build lists of variables that need to be replaced in the given
-// Formula. Declare globals in new relation. Then call
-// map_vars to do the replacements.
-//
-// Obnoxiously many arguments here:
-// Relation arguments contain declarations of symbolic and in/out vars.
-// F_Exists argument is where needed existentially quant. vars can be decl.
-//
-// Mapping specifies how in/out vars are mapped
-// Two lists are required to be able to map in/out variables from the first
-// and second relations to the same existentially quantified variable.
-//
-void align(Rel_Body *originalr, Rel_Body *newr, F_Exists *fe,
- Formula *f, const Mapping &mapping, bool &newrIsSet,
- List<int> &seen_exists, Variable_ID_Tuple &seen_exists_ids) {
- int i, cur_ex = 0; // initialize cur_ex to shut up the compiler
-
- f->set_relation(newr); // Might not need to do this anymore, if bugs were fixed
- int input_remapped = 0;
- int output_remapped = 0;
- int sym_remapped = 0;
- // skip_set_checks++;
-
- Variable_ID new_var;
- Const_String new_name;
- int new_pos;
-
- // MAP old input variables by setting their remap fields
- for(i = 1; i <= originalr->n_inp(); i++) {
- Variable_ID this_var = originalr->input_var(i), New_E;
- Const_String this_name = originalr->In_Names[i];
-
- switch (mapping.get_map_in_kind(i)) {
- case Input_Var:
- // case Set_Var:
- // if (mapping.get_map_in_kind(i) == Set_Var)
- // newrIsSet = true; // Don't mark it just yet; we still need to
- // // refer to its "input" vars internally
-
- // assert((newrIsSet && mapping.get_map_in_kind(i) == Set_Var)
- // || ((!newrIsSet &&mapping.get_map_in_kind(i) == Input_Var)));
-
- new_pos = mapping.get_map_in_pos(i);
- new_var = newr->input_var(new_pos);
- if (this_var != new_var) {
- input_remapped = 1;
- this_var->remap = new_var;
- }
- new_name = newr->In_Names[new_pos];
- if (!this_name.null()) { // should we name this?
- if (!new_name.null()) { // already named, anonymize
- if (new_name != this_name)
- newr->name_input_var(new_pos, Const_String());
- }
- else
- newr->name_input_var(new_pos, this_name);
- }
- break;
- case Output_Var:
- assert(!newr->is_set());
- input_remapped = 1;
- new_pos = mapping.get_map_in_pos(i);
- this_var->remap = new_var = newr->output_var(new_pos);
- new_name = newr->Out_Names[new_pos];
- if (!this_name.null()) {
- if (!new_name.null()) { // already named, anonymize
- if (new_name != this_name)
- newr->name_output_var(new_pos, Const_String());
- }
- else
- newr->name_output_var(new_pos, this_name);
- }
- break;
- case Exists_Var:
- input_remapped = 1;
- // check if we have declared it, use that if so.
- // create it if not.
- if (mapping.get_map_in_pos(i) <= 0 ||
- (cur_ex = seen_exists.index(mapping.get_map_in_pos(i))) == 0){
- if (!this_name.null())
- New_E = fe->declare(this_name);
- else
- New_E = fe->declare();
- this_var->remap = New_E;
- if (mapping.get_map_in_pos(i) > 0) {
- seen_exists.append(mapping.get_map_in_pos(i));
- seen_exists_ids.append(New_E);
- }
- }
- else {
- this_var->remap = new_var = seen_exists_ids[cur_ex];
- if (!this_name.null()) { // Have we already assigned a name?
- if (!new_var->base_name.null()) {
- if (new_var->base_name != this_name)
- new_var->base_name = Const_String();
- }
- else {
- new_var->base_name = this_name;
- assert(!this_name.null());
- }
- }
- }
- break;
- default:
- assert(0 && "Unsupported var type in MapRel2");
- break;
- }
- }
-
- // MAP old output variables.
- for(i = 1; i <= originalr->n_out(); i++) {
- Variable_ID this_var = originalr->output_var(i), New_E;
- Const_String this_name = originalr->Out_Names[i];
-
- switch (mapping.get_map_out_kind(i)) {
- case Input_Var:
- // case Set_Var:
- // if (mapping.get_map_out_kind(i) == Set_Var)
- // newrIsSet = true; // Don't mark it just yet; we still need to refer to its "input" vars internally
-
- // assert((newrIsSet && mapping.get_map_out_kind(i) == Set_Var)
- // ||((!newrIsSet &&mapping.get_map_out_kind(i) == Input_Var)));
-
- output_remapped = 1;
- new_pos = mapping.get_map_out_pos(i);
- this_var->remap = new_var = newr->input_var(new_pos);
- new_name = newr->In_Names[new_pos];
- if (!this_name.null()) {
- if (!new_name.null()) { // already named, anonymize
- if (new_name != this_name)
- newr->name_input_var(new_pos, Const_String());
- }
- else
- newr->name_input_var(new_pos, this_name);
- }
- break;
- case Output_Var:
- assert(!newr->is_set());
- new_pos = mapping.get_map_out_pos(i);
- new_var = newr->output_var(new_pos);
- if (new_var != this_var) {
- output_remapped = 1;
- this_var->remap = new_var;
- }
- new_name = newr->Out_Names[new_pos];
- if (!this_name.null()) {
- if (!new_name.null()) { // already named, anonymize
- if (new_name != this_name)
- newr->name_output_var(new_pos, Const_String());
- }
- else
- newr->name_output_var(new_pos, this_name);
- }
- break;
- case Exists_Var:
- // check if we have declared it, create it if not.
- output_remapped = 1;
- if (mapping.get_map_out_pos(i) <= 0 ||
- (cur_ex = seen_exists.index(mapping.get_map_out_pos(i))) == 0) { // Declare it.
- New_E = fe->declare(this_name);
- this_var->remap = New_E;
- if (mapping.get_map_out_pos(i) > 0) {
- seen_exists.append(mapping.get_map_out_pos(i));
- seen_exists_ids.append(New_E);
- }
- }
- else {
- this_var->remap = new_var = seen_exists_ids[cur_ex];
- if (!this_name.null()) {
- if (!new_var->base_name.null()) {
- if (new_var->base_name != this_name)
- new_var->base_name = Const_String();
- }
- else {
- new_var->base_name = this_name;
- }
- }
- }
- break;
- default:
- assert(0 &&"Unsupported var type in MapRel2");
- break;
- }
- }
-
- Variable_ID_Tuple *oldSym = originalr->global_decls();
- for(i=1; i<=(*oldSym).size(); i++) {
- Variable_ID v = (*oldSym)[i];
- assert(v->kind()==Global_Var);
- if (v->get_global_var()->arity() > 0) {
- Argument_Tuple new_of = v->function_of();
- if (!leave_pufs_untouched)
- new_of = mapping.get_tuple_fate(new_of, v->get_global_var()->arity());
- if (new_of == Unknown_Tuple) {
- // hopefully v is not really used
- // if we get here, f should have been in DNF,
- // now an OR node with conjuncts below
- // we just need to check that no conjunct uses v
-#if ! defined NDEBUG
- if (f->node_type() == Op_Conjunct) {
- assert(f->really_conjunct()->mappedVars.index(v)==0
- && "v unused");
- }
-#if 0
- else {
- // assert(f->node_type() == Op_Or);
- for (List_Iterator<Formula *> conj(f->children()); conj; conj++) {
- assert((*conj)->really_conjunct()->mappedVars.index(v)==0
- && "v unused");
- }
- }
-#endif
-#endif
- // since its not really used, don't bother adding it to
- // the the global_vars list of the new relation
- continue;
- }
- if (v->function_of() != new_of) {
- Variable_ID new_v=newr->get_local(v->get_global_var(),new_of);
- assert(v != new_v);
- v->remap = new_v;
- sym_remapped = 1;
- }
- else {
- // add symbolic to symbolic list
-#if ! defined NDEBUG
- Variable_ID new_v =
-#endif
- newr->get_local(v->get_global_var(), v->function_of());
-#if ! defined NDEBUG
- assert(v == new_v);
-#endif
- }
- }
- else {
- // add symbolic to symbolic list
-#if ! defined NDEBUG
- Variable_ID new_v =
-#endif
- newr->get_local(v->get_global_var());
-#if ! defined NDEBUG
- assert(v == new_v);
-#endif
- }
- }
-
- if (sym_remapped || input_remapped || output_remapped) {
- f->remap();
-
- // If 2 vars mapped to same variable, combine them
- //There's a column to combine only when there are two equal remap fields.
- Tuple<Variable_ID> vt(0);
- bool combine = false;
- Tuple_Iterator<Variable_ID> t(input_vars);
- for(i=1; !combine && i<=originalr->n_inp(); t++, i++)
- if (vt.index((*t)->remap))
- combine = true;
- else
- vt.append((*t)->remap);
- Tuple_Iterator<Variable_ID> t2(output_vars);
- for(i=1; !combine && i <= originalr->n_out(); t2++, i++)
- if (vt.index((*t2)->remap))
- combine = true;
- else
- vt.append((*t2)->remap);
- if (combine) f->combine_columns();
-
- if (sym_remapped)
- reset_remap_field(originalr->Symbolic);
- if (input_remapped)
- reset_remap_field(input_vars,originalr->n_inp());
- if (output_remapped)
- reset_remap_field(output_vars,originalr->n_out());
- }
-
- // skip_set_checks--;
-
-#ifndef NDEBUG
- if (fe)
- foreach(v,Variable_ID,fe->myLocals,assert(v == v->remap));
-#endif
-}
-
-
-// MapRel1, MapAndCombineRel2 can be replaced by merge_rels
-void MapRel1(Relation &R, const Mapping &map, Combine_Type ctype,
- int number_input, int number_output,
- bool invalidate_resulting_leading_info,
- bool finalize) {
-#if defined(INCLUDE_COMPRESSION)
- assert(!R.is_compressed());
-#endif
- assert(!R.is_null());
-
- Relation inputRel = R;
- R = Relation();
- Rel_Body *inputRelBody = inputRel.split();
-
- int in_req=0, out_req=0;
- get_relation_arity_from_one_mapping(map, in_req, out_req);
-
- R = Relation(number_input == -1 ? in_req : number_input,
- number_output == -1 ? out_req : number_output);
-
- Rel_Body *outputRelBody = R.split();
-
- inputRelBody->DNF_to_formula();
- Formula *f1 = inputRelBody->rm_formula();
-
- F_Exists *fe;
- Formula *f;
- if (has_existentials(map)) {
- f = fe = outputRelBody->add_exists();
- }
- else {
- fe = NULL;
- f = outputRelBody;
- }
- and_below_exists = NULL;
- if (finalize) and_below_exists = NULL;
- else f = and_below_exists = f->add_and();
- if(ctype == Comb_AndNot) {
- f = f->add_not();
- }
- f->add_child(f1);
-
- exists_ids.clear();
- exists_numbers.clear();
-
- bool returnAsSet=false;
- align(inputRelBody, outputRelBody, fe, f1, map, returnAsSet,
- exists_numbers, exists_ids);
-
- if (returnAsSet ||
- (inputRelBody->is_set() && outputRelBody->n_out() == 0)) {
- R.markAsSet();
- R.invalidate_leading_info(); // nonsensical for a set
- }
-
- if (finalize) R.finalize();
- inputRel = Relation();
- if (invalidate_resulting_leading_info)
- R.invalidate_leading_info();
-}
-
-
-Relation MapAndCombineRel2(Relation &R1, Relation &R2, const Mapping &mapping1,
- const Mapping &mapping2, Combine_Type ctype,
- int number_input, int number_output) {
-#if defined(INCLUDE_COMPRESSION)
- assert(!R1.is_compressed());
- assert(!R2.is_compressed());
-#endif
- assert(!R1.is_null() && !R2.is_null());
- Rel_Body *r1 = R1.split();
- Rel_Body *r2 = R2.split();
-
- int in_req, out_req; // Create the new relation
- get_relation_arity_from_mappings(mapping1, mapping2, in_req, out_req);
- Relation R3(number_input == -1 ? in_req : number_input,
- number_output == -1 ? out_req : number_output);
- Rel_Body *r3 = R3.split(); // This is just to get the pointer, it's cheap
-
- /* permit the add_{exists,and} below, reset after they are done.*/
- skip_finalization_check++;
-
- F_Exists *fe = NULL;
- Formula *f;
- if (has_existentials(mapping1) || has_existentials(mapping2)) {
- fe = r3->add_exists();
- f = fe;
- }
- else {
- f = r3;
- }
-
- r1->DNF_to_formula();
- Formula *f1 = r1->rm_formula();
- r2->DNF_to_formula();
- Formula *f2 = r2->rm_formula();
-
- // align: change r1 vars to r3 vars in formula f1 via map mapping1,
- // declaring needed exists vars in F_Exists *fe
- // Also maps symbolic variables appropriately, sets relation ptrs in f1.
- // In order to map variables of both relations to the same variables,
- // we keep a list of new existentially quantified vars between calls.
- // returnAsSet means mark r3 as set before return. Don't mark it yet,
- // because internally we need to refer to "input_vars" of a set, and that
- // would blow assertions.
-
- bool returnAsSet=false;
- exists_ids.clear();
- exists_numbers.clear();
- align(r1, r3, fe, f1, mapping1, returnAsSet, exists_numbers, exists_ids);
- // align: change r2 vars to r3 vars in formula f2 via map mapping2
- align(r2, r3, fe, f2, mapping2, returnAsSet, exists_numbers, exists_ids);
-
- switch (ctype) {
- case Comb_Or:
- if(f1->node_type() == Op_Or) {
- f->add_child(f1);
- f = f1;
- }
- else {
- f = f->add_or();
- f->add_child(f1);
- }
- break;
- case Comb_And:
- case Comb_AndNot:
- if(f1->node_type() == Op_And) {
- f->add_child(f1);
- f = f1;
- }
- else {
- f = f->add_and();
- f->add_child(f1);
- }
- break;
- default:
- assert(0 && "Invalid combine type in MapAndCombineRel2");
- }
-
- Formula *c2;
- if (ctype==Comb_AndNot) {
- c2 = f->add_not();
- }
- else {
- c2 = f;
- }
- c2->add_child(f2);
-
- skip_finalization_check--; /* Set this back for return */
- R3.finalize();
-
- if (returnAsSet ||
- (R1.is_set() && R2.is_set() && R3.n_inp() >= 0 && R3.n_out() == 0)){
- R3.markAsSet();
- R3.invalidate_leading_info();
- }
- R1 = Relation();
- R2 = Relation();
- return R3;
-}
-
-
-//
-// Scramble each relation's variables and merge these relations
-// together. Support variable mapping to and from existentials.
-// Unspecified variables in mapping are mapped to themselves by
-// default. It intends to replace MapRel1 and MapAndCombineRel2
-// functions (the time saved by grafting formula tree might be
-// neglegible when compared to the simplification cost).
-//
-Relation merge_rels(Tuple<Relation> &R, const Tuple<std::map<Variable_ID, std::pair<Var_Kind, int> > > &mapping, const Tuple<bool> &inverse, Combine_Type ctype, int number_input, int number_output) {
- const int m = R.size();
- assert(mapping.size() == m && inverse.size() == m);
- // skip_set_checks++;
-
- // if new relation's arity is not given, calculate it on demand
- if (number_input == -1) {
- number_input = 0;
- for (int i = 1; i <= m; i++) {
- for (int j = R[i].n_inp(); j >= 1; j--) {
- Variable_ID v = R[i].input_var(j);
- std::map<Variable_ID, std::pair<Var_Kind, int> >::const_iterator p = mapping[i].find(v);
- if (p == mapping[i].end()) {
- number_input = j;
- break;
- }
- }
-
- for (std::map<Variable_ID, std::pair<Var_Kind, int> >::const_iterator j = mapping[i].begin(); j != mapping[i].end(); j++) {
- if ((*j).second.first == Input_Var || (*j).second.first == Set_Var)
- number_input = max(number_input, (*j).second.second);
- }
- }
- }
-
- if (number_output == -1) {
- number_output = 0;
- for (int i = 1; i <= m; i++) {
- for (int j = R[i].n_out(); j >= 1; j--) {
- Variable_ID v = R[i].output_var(j);
- std::map<Variable_ID, std::pair<Var_Kind, int> >::const_iterator p = mapping[i].find(v);
- if (p == mapping[i].end()) {
- number_output = j;
- break;
- }
- }
- for (std::map<Variable_ID, std::pair<Var_Kind, int> >::const_iterator j = mapping[i].begin(); j != mapping[i].end(); j++) {
- if ((*j).second.first == Output_Var)
- number_output = max(number_output, (*j).second.second);
- }
- }
- }
-
- Relation R2(number_input, number_output);
- F_Exists *fe = R2.add_exists();
- Formula *f_root;
- switch (ctype) {
- case Comb_And:
- f_root = fe->add_and();
- break;
- case Comb_Or:
- f_root = fe->add_or();
- break;
- default:
- assert(0); // unsupported merge type
- }
-
- std::map<int, Variable_ID> seen_exists_by_num;
- std::map<Variable_ID, Variable_ID> seen_exists_by_id;
-
- for (int i = 1; i <= m; i++) {
- F_Or *fo;
- if (inverse[i])
- fo = f_root->add_not()->add_or();
- else
- fo = f_root->add_or();
-
- for (DNF_Iterator di(R[i].query_DNF()); di; di++) {
- F_And *f = fo->add_and();
-
- for (GEQ_Iterator gi(*di); gi; gi++) {
- GEQ_Handle h = f->add_GEQ();
- for (Constr_Vars_Iter cvi(*gi); cvi; cvi++) {
- Variable_ID v = cvi.curr_var();
- std::map<Variable_ID, std::pair<Var_Kind, int> >::const_iterator p = mapping[i].find(v);
- if (p == mapping[i].end()) {
- switch (v->kind()) {
- // case Set_Var:
- case Input_Var: {
- int pos = v->get_position();
- h.update_coef(R2.input_var(pos), cvi.curr_coef());
- break;
- }
- case Output_Var: {
- int pos = v->get_position();
- h.update_coef(R2.output_var(pos), cvi.curr_coef());
- break;
- }
- case Exists_Var:
- case Wildcard_Var: {
- std::map<Variable_ID, Variable_ID>::iterator p2 = seen_exists_by_id.find(cvi.curr_var());
- Variable_ID e;
- if (p2 == seen_exists_by_id.end()) {
- e = fe->declare();
- seen_exists_by_id[cvi.curr_var()] = e;
- }
- else
- e = (*p2).second;
- h.update_coef(e, cvi.curr_coef());
- break;
- }
- case Global_Var: {
- Global_Var_ID g = v->get_global_var();
- Variable_ID v2;
- if (g->arity() == 0)
- v2 = R2.get_local(g);
- else
- v2 = R2.get_local(g, v->function_of());
- h.update_coef(v2, cvi.curr_coef());
- break;
- }
- default:
- assert(0); // shouldn't happen if input relations are simplified
- }
- }
- else {
- switch ((*p).second.first) {
- // case Set_Var:
- case Input_Var: {
- int pos = (*p).second.second;
- h.update_coef(R2.input_var(pos), cvi.curr_coef());
- break;
- }
- case Output_Var: {
- int pos = (*p).second.second;
- h.update_coef(R2.output_var(pos), cvi.curr_coef());
- break;
- }
- case Exists_Var:
- case Wildcard_Var: {
- int pos = (*p).second.second;
- std::map<int, Variable_ID>::iterator p2 = seen_exists_by_num.find(pos);
- Variable_ID e;
- if (p2 == seen_exists_by_num.end()) {
- e = fe->declare();
- seen_exists_by_num[pos] = e;
- }
- else
- e = (*p2).second;
- h.update_coef(e, cvi.curr_coef());
- break;
- }
- default:
- assert(0); // mapped to unsupported variable type
- }
- }
- }
- h.update_const((*gi).get_const());
- }
-
- for (EQ_Iterator ei(*di); ei; ei++) {
- EQ_Handle h = f->add_EQ();
- for (Constr_Vars_Iter cvi(*ei); cvi; cvi++) {
- Variable_ID v = cvi.curr_var();
- std::map<Variable_ID, std::pair<Var_Kind, int> >::const_iterator p = mapping[i].find(v);
- if (p == mapping[i].end()) {
- switch (v->kind()) {
- // case Set_Var:
- case Input_Var: {
- int pos = v->get_position();
- h.update_coef(R2.input_var(pos), cvi.curr_coef());
- break;
- }
- case Output_Var: {
- int pos = v->get_position();
- h.update_coef(R2.output_var(pos), cvi.curr_coef());
- break;
- }
- case Exists_Var:
- case Wildcard_Var: {
- std::map<Variable_ID, Variable_ID>::iterator p2 = seen_exists_by_id.find(v);
- Variable_ID e;
- if (p2 == seen_exists_by_id.end()) {
- e = fe->declare();
- seen_exists_by_id[v] = e;
- }
- else
- e = (*p2).second;
- h.update_coef(e, cvi.curr_coef());
- break;
- }
- case Global_Var: {
- Global_Var_ID g = v->get_global_var();
- Variable_ID v2;
- if (g->arity() == 0)
- v2 = R2.get_local(g);
- else
- v2 = R2.get_local(g, v->function_of());
- h.update_coef(v2, cvi.curr_coef());
- break;
- }
- default:
- assert(0); // shouldn't happen if input relations are simplified
- }
- }
- else {
- switch ((*p).second.first) {
- // case Set_Var:
- case Input_Var: {
- int pos = (*p).second.second;
- h.update_coef(R2.input_var(pos), cvi.curr_coef());
- break;
- }
- case Output_Var: {
- int pos = (*p).second.second;
- h.update_coef(R2.output_var(pos), cvi.curr_coef());
- break;
- }
- case Exists_Var:
- case Wildcard_Var: {
- int pos = (*p).second.second;
- std::map<int, Variable_ID>::iterator p2 = seen_exists_by_num.find(pos);
- Variable_ID e;
- if (p2 == seen_exists_by_num.end()) {
- e = fe->declare();
- seen_exists_by_num[pos] = e;
- }
- else
- e = (*p2).second;
- h.update_coef(e, cvi.curr_coef());
- break;
- }
- default:
- assert(0); // mapped to unsupported variable type
- }
- }
- }
- h.update_const((*ei).get_const());
- }
- }
- }
-
- // skip_set_checks--;
-
- if (number_output == 0) {
- R2.markAsSet();
- // R2.invalidate_leading_info();
- }
-
- return R2;
-}
-
-} // namespace