summaryrefslogtreecommitdiff
path: root/lib/omega/src/RelBody.cc
diff options
context:
space:
mode:
authorTuowen Zhao <ztuowen@gmail.com>2016-09-19 21:14:58 +0000
committerTuowen Zhao <ztuowen@gmail.com>2016-09-19 21:14:58 +0000
commit210f77d2c32f14d2e99577fd3c9842bb19d47e50 (patch)
tree5edb327c919b8309e301c3440fb6668a0075c8ef /lib/omega/src/RelBody.cc
parenta66ce5cd670c4d3c0dc449720f5bc45dd4c281b8 (diff)
downloadchill-210f77d2c32f14d2e99577fd3c9842bb19d47e50.tar.gz
chill-210f77d2c32f14d2e99577fd3c9842bb19d47e50.tar.bz2
chill-210f77d2c32f14d2e99577fd3c9842bb19d47e50.zip
Moved most modules into lib
Diffstat (limited to 'lib/omega/src/RelBody.cc')
-rw-r--r--lib/omega/src/RelBody.cc906
1 files changed, 906 insertions, 0 deletions
diff --git a/lib/omega/src/RelBody.cc b/lib/omega/src/RelBody.cc
new file mode 100644
index 0000000..825b153
--- /dev/null
+++ b/lib/omega/src/RelBody.cc
@@ -0,0 +1,906 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 the Omega Project Team
+ Copyright (C) 2005-2011 Chun Chen
+ All Rights Reserved.
+
+ Purpose:
+ class Rel_Body, internal Relation representation
+
+ Notes:
+
+ History:
+ 11/26/09 Remove unecessary mandatary checking for set or relation,
+ treat them uniformly for easy coding, by Chun Chen
+*****************************************************************************/
+
+#include <basic/util.h>
+#include <omega/RelBody.h>
+#include <omega/Relation.h>
+#include <omega/pres_tree.h>
+#include <omega/pres_conj.h>
+#include <omega/omega_i.h>
+#include <assert.h>
+
+namespace omega {
+
+Rel_Body null_rel;
+bool Rel_Body::is_null() const {
+ return(this == &null_rel);
+}
+
+
+int Rel_Body::max_ufs_arity() {
+ int ma = 0, a;
+ for (Variable_ID_Iterator v(*global_decls()); v; v++) {
+ a = (*v)->get_global_var()->arity();
+ if (a > ma)
+ ma = a;
+ }
+ return ma;
+}
+
+int Rel_Body::max_ufs_arity_of_set() {
+ int ma = 0, a;
+ for (Variable_ID_Iterator v(*global_decls()); v; v++)
+ if ((*v)->function_of() == Set_Tuple) {
+ a = (*v)->get_global_var()->arity();
+ if (a > ma)
+ ma = a;
+ }
+ return ma;
+}
+
+int Rel_Body::max_ufs_arity_of_in() {
+ int ma = 0, a;
+ for (Variable_ID_Iterator v(*global_decls()); v; v++)
+ if ((*v)->function_of() == Input_Tuple) {
+ a = (*v)->get_global_var()->arity();
+ if (a > ma)
+ ma = a;
+ }
+ return ma;
+}
+
+int Rel_Body::max_ufs_arity_of_out() {
+ int ma = 0, a;
+ for (Variable_ID_Iterator v(*global_decls()); v; v++)
+ if ((*v)->function_of() == Output_Tuple) {
+ a = (*v)->get_global_var()->arity();
+ if (a > ma)
+ ma = a;
+ }
+ return ma;
+}
+
+int Rel_Body::max_shared_ufs_arity() {
+ int ma = 0, a;
+ for (Variable_ID_Iterator v(*global_decls()); v; v++)
+ for (Variable_ID_Iterator v2(*global_decls()); v2; v2++)
+ if (*v != *v2
+ && (*v)->get_global_var() == (*v2)->get_global_var()
+ && (*v)->function_of() != (*v2)->function_of()) {
+ a = (*v)->get_global_var()->arity();
+ if (a > ma)
+ ma = a;
+ }
+ return ma;
+}
+
+//
+// Input and output variables.
+//
+void Rel_Body::name_input_var(int nth, Const_String S) {
+ // assert(1 <= nth && nth <= number_input && (!is_set() || skip_set_checks > 0));
+ if (is_null())
+ throw std::invalid_argument("empty relation");
+ if (nth < 1 || nth > number_input)
+ throw std::invalid_argument("invalid input var number");
+ In_Names[nth] = S;
+}
+
+void Rel_Body::name_output_var(int nth, Const_String S) {
+ // assert(1<= nth && nth <= number_output && (!is_set() || skip_set_checks > 0));
+ if (is_null())
+ throw std::invalid_argument("empty relation");
+ if (nth < 1 || nth > number_output)
+ throw std::invalid_argument("invalid output var number");
+ Out_Names[nth] = S;
+}
+
+void Rel_Body::name_set_var(int nth, Const_String S) {
+ if (number_output != 0)
+ throw std::runtime_error("relation is not a set");
+ name_input_var(nth, S);
+}
+
+int Rel_Body::n_inp() const {
+ // assert(!is_null() && (!is_set()||skip_set_checks>0));
+ if (is_null())
+ return 0;
+ else
+ return number_input;
+}
+
+int Rel_Body::n_out() const {
+ // assert(!is_null() && (!is_set()||skip_set_checks>0));
+ if (is_null())
+ return 0;
+ else
+ return number_output;
+}
+
+int Rel_Body::n_set() const {
+ if (number_output != 0)
+ throw std::runtime_error("relation is not a set");
+ return n_inp();
+}
+
+Variable_ID Rel_Body::input_var(int nth) {
+ // assert(!is_null());
+ // assert(!is_set() || skip_set_checks>0);
+ // assert(1 <= nth && nth <= number_input);
+ if (is_null())
+ throw std::invalid_argument("empty relation");
+ if (nth < 1 || nth > number_input)
+ throw std::invalid_argument("invalid input var number");
+ input_vars[nth]->base_name = In_Names[nth];
+ return input_vars[nth];
+}
+
+Variable_ID Rel_Body::output_var(int nth) {
+ // assert(!is_null());
+ // assert(!is_set() || skip_set_checks>0);
+ // assert(1<= nth && nth <= number_output);
+ if (is_null())
+ throw std::invalid_argument("empty relation");
+ if (nth < 1 || nth > number_output)
+ throw std::invalid_argument("invalid output var number");
+ output_vars[nth]->base_name = Out_Names[nth];
+ return output_vars[nth];
+}
+
+Variable_ID Rel_Body::set_var(int nth) {
+ if (number_output != 0)
+ throw std::runtime_error("relation is not a set");
+ return input_var(nth);
+}
+
+//
+// Add the AND node to the relation.
+// Useful for adding restraints.
+//
+F_And *Rel_Body::and_with_and() {
+ assert(!is_null());
+ if (is_simplified())
+ DNF_to_formula();
+ relation()->finalized = false;
+ Formula *f = rm_formula();
+ F_And *a = add_and();
+ a->add_child(f);
+ return a;
+}
+
+//
+// Add constraint to relation at the upper level.
+//
+EQ_Handle Rel_Body::and_with_EQ() {
+ assert(!is_null());
+ if (is_simplified())
+ DNF_to_formula();
+ assert(! is_shared()); // The relation has been split.
+ relation()->finalized = false;
+ return find_available_conjunct()->add_EQ();
+}
+
+EQ_Handle Rel_Body::and_with_EQ(const Constraint_Handle &initial) {
+ assert(!is_null());
+ assert(initial.relation()->is_simplified());
+ EQ_Handle H = and_with_EQ();
+ copy_constraint(H, initial);
+ return H;
+}
+
+GEQ_Handle Rel_Body::and_with_GEQ() {
+ assert(!is_null());
+ if (is_simplified())
+ DNF_to_formula();
+ assert(! is_shared()); // The relation has been split.
+ relation()->finalized = false; // We are giving out a handle.
+ // We should evantually implement finalization
+ // of subtrees, so the existing formula cannot
+ // be modified.
+ return find_available_conjunct()->add_GEQ();
+}
+
+GEQ_Handle Rel_Body::and_with_GEQ(const Constraint_Handle &initial) {
+ assert(!is_null());
+ assert(initial.relation()->is_simplified());
+ GEQ_Handle H = and_with_GEQ();
+ copy_constraint(H, initial);
+ return H;
+}
+
+
+
+Conjunct *Rel_Body::find_available_conjunct() {
+ Conjunct *c;
+ assert(!is_null());
+
+ if (children().empty()) {
+ c = add_conjunct();
+ }
+ else {
+ assert(children().length() == 1);
+ Formula *kid = children().front(); // RelBodies have only one child
+ c = kid->find_available_conjunct();
+ if (c==NULL) {
+ remove_child(kid);
+ F_And *a = add_and();
+ a->add_child(kid);
+ c = a->add_conjunct();
+ }
+ }
+ return c;
+}
+
+void Rel_Body::finalize() {
+ assert(!is_null());
+ if (!is_finalized())
+ assert(! is_shared()); // no other pointers into here
+ finalized = true;
+ if (! children().empty())
+ children().front()->finalize(); // Can have at most one child
+}
+
+// Null Rel_Body
+// This is the only rel_body constructor that has ref_count initialized to 1;
+// That's because it's used to construct the global Rel_Body "null_rel".
+// Unfortunately because we don't know in what order global constructors will
+// be called, we could create a global relation with the default relation
+// constructor (which would set the null_rel ref count to 1), and *then*
+// call Rel_Body::Rel_Body(), which would set it back to 0, leaving a relation
+// that points to a rel_body with it's ref_count set to 0! So this is done as
+// a special case, in which the ref_count is always 1.
+Rel_Body::Rel_Body():
+ Formula(0, this),
+ ref_count(1),
+ status(under_construction),
+ number_input(0), number_output(0),
+ In_Names(0), Out_Names(0),
+ simplified_DNF(NULL),
+ r_conjs(0),
+ finalized(true),
+ _is_set(false) {
+}
+
+
+Rel_Body::Rel_Body(int n_input, int n_output):
+ Formula(0, this),
+ ref_count(0),
+ status(under_construction),
+ number_input(n_input), number_output(n_output),
+ In_Names(n_input), Out_Names(n_output),
+ simplified_DNF(NULL),
+ r_conjs(0),
+ finalized(false) {
+ if (n_output == 0)
+ _is_set = true;
+ else
+ _is_set = false;
+ if(pres_debug) {
+ fprintf(DebugFile, "+++ Create Rel_Body::Rel_Body(%d, %d) = 0x%p +++\n",
+ n_input, n_output, this);
+ }
+ int i;
+ for(i=1; i<=number_input; i++) {
+ In_Names[i] = Const_String();
+ }
+ for(i=1; i<=number_output; i++) {
+ Out_Names[i] = Const_String();
+ }
+}
+
+// Rel_Body::Rel_Body(Rel_Body *r):
+// Formula(0, this),
+// ref_count(0),
+// status(r->status),
+// number_input(r->number_input), number_output(r->number_output),
+// In_Names(r->number_input), Out_Names(r->number_output),
+// simplified_DNF(NULL),
+// r_conjs(r->r_conjs),
+// finalized(r->finalized),
+// _is_set(r->_is_set) {
+// if(pres_debug) {
+// fprintf(DebugFile, "+++ Copy Rel_Body::Rel_Body(Rel_Body * 0x%p) = 0x%p +++\n", r, this);
+// prefix_print(DebugFile);
+// }
+
+// int i;
+// for(i=1;i<=r->number_input;i++) In_Names[i] = r->In_Names[i];
+// for(i=1;i<=r->number_output;i++) Out_Names[i] = r->Out_Names[i];
+// copy_var_decls(Symbolic,r->Symbolic);
+
+// if(!r->children().empty() && r->simplified_DNF==NULL) {
+// Formula *f = r->formula()->copy(this,this);
+// f->remap();
+// children().append(f);
+// }
+// else if(r->children().empty() && r->simplified_DNF!=NULL) {
+// simplified_DNF = r->simplified_DNF->copy(this);
+// simplified_DNF->remap();
+// }
+// else { // copy NULL relation
+// }
+
+// reset_remap_field(r->Symbolic);
+// }
+
+Rel_Body *Rel_Body::clone() {
+ Rel_Body *b = new Rel_Body();
+
+ b->ref_count = 0;
+ b->status = status;
+ b->number_input = number_input;
+ b->number_output = number_output;
+ b->r_conjs = r_conjs;
+ b->finalized = finalized;
+ b->_is_set = _is_set;
+
+ b->In_Names = Tuple<Const_String>(number_input);
+ b->Out_Names = Tuple<Const_String>(number_output);
+ for(int i = 1; i <= number_input; i++)
+ b->In_Names[i] = In_Names[i];
+ for(int i = 1; i <= number_output; i++)
+ b->Out_Names[i] = Out_Names[i];
+
+ copy_var_decls(b->Symbolic, Symbolic);
+
+ if(!children().empty() && simplified_DNF==NULL) {
+ Formula *f = formula()->copy(b, b);
+ f->remap();
+ b->children().append(f);
+ }
+ else if(children().empty() && simplified_DNF!=NULL) {
+ b->simplified_DNF = simplified_DNF->copy(b);
+ b->simplified_DNF->remap();
+ }
+ else { // copy NULL relation
+ }
+
+ reset_remap_field(Symbolic);
+ return b;
+}
+
+
+Rel_Body::Rel_Body(Rel_Body *r, Conjunct *c):
+ Formula(0, this),
+ ref_count(0),
+ status(uncompressed),
+ number_input(r->number_input), number_output(r->number_output),
+ In_Names(r->number_input), Out_Names(r->number_output),
+ r_conjs(0),
+ finalized(r->finalized),
+ _is_set(r->_is_set) {
+ if(pres_debug) {
+ fprintf(DebugFile, "+++ Copy Rel_Body::Rel_Body(Rel_Body * 0x%p, Conjunct * 0x%p) = 0x%p +++\n",r,c,this);
+ }
+
+ int i;
+ for(i=1;i<=r->number_input;i++) In_Names[i] = r->In_Names[i];
+ for(i=1;i<=r->number_output;i++) Out_Names[i] = r->Out_Names[i];
+ copy_var_decls(Symbolic,r->Symbolic);
+
+ // assert that r has as many variables as c requires, or that c is from r
+ assert(r == c->relation());
+ assert(r->simplified_DNF != NULL);
+ simplified_DNF = new DNF;
+ simplified_DNF->add_conjunct(c->copy_conj_diff_relation(this,this));
+ single_conjunct()->remap();
+
+ reset_remap_field(r->Symbolic);
+}
+
+Rel_Body::~Rel_Body() {
+ if(pres_debug) {
+ fprintf(DebugFile, "+++ Destroy Rel_Body::~Rel_Body() 0x%p +++\n", this);
+ }
+ free_var_decls(Symbolic);
+ if(simplified_DNF != NULL) {
+ delete simplified_DNF;
+ }
+}
+
+//
+// Take a relation that has been simplified and convert it
+// back to formula form.
+//
+void Rel_Body::DNF_to_formula() {
+ assert(!is_null());
+ if (simplified_DNF != NULL) {
+ simplified_DNF->DNF_to_formula(this);
+ simplified_DNF = NULL;
+ status = under_construction;
+ }
+}
+
+bool Rel_Body::can_add_child() {
+ assert(this != &null_rel);
+ return n_children() < 1;
+}
+
+
+
+// ********************
+// Simplify functions
+// ********************
+
+
+extern int s_rdt_constrs;
+
+
+//
+// Simplify a given relation.
+// Store the resulting DNF in the relation, clean out the formula.
+//
+void Rel_Body::simplify(int rdt_conjs, int rdt_constrs) {
+ if(simplified_DNF == NULL) {
+ finalized = true;
+ if(children().empty()) {
+ simplified_DNF = new DNF;
+ }
+ else {
+ if(pres_debug) {
+ if(DebugFile==NULL) {
+ DebugFile = fopen("test.out", "w");
+ if(DebugFile==NULL)
+ fprintf(stderr, "Can not open file test.out\n");
+ }
+ }
+
+ assert(children().length()==1);
+ if(pres_debug) {
+ fprintf(DebugFile, "=== %p Rel_Body::simplify(%d, %d) Input tree (%d) ===\n", this,rdt_conjs,rdt_constrs,r_conjs);
+ prefix_print(DebugFile);
+ }
+ verify_tree();
+
+ beautify();
+ verify_tree();
+
+ rearrange();
+ verify_tree();
+
+ beautify();
+ verify_tree();
+
+ s_rdt_constrs = rdt_constrs;
+ if(pres_debug) {
+ fprintf(DebugFile, "\n=== In simplify, before DNFize ===\n");
+ prefix_print(DebugFile);
+ }
+ DNFize();
+ if(pres_debug) {
+ fprintf(DebugFile, "\n=== In simplify, after DNFize ===\n");
+ prefix_print(DebugFile);
+ }
+ verify_tree();
+
+
+ simplified_DNF->rm_redundant_inexact_conjs();
+ verify_tree();
+
+ if (rdt_conjs > 0 && !simplified_DNF->is_definitely_false() && simplified_DNF->length() > 1) {
+ simplified_DNF->rm_redundant_conjs(rdt_conjs-1);
+ verify_tree();
+ }
+
+ if(pres_debug) {
+ fprintf(DebugFile, "\n=== Resulting Relation ===\n");
+ prefix_print(DebugFile);
+ }
+ }
+ }
+ else {
+ /* Reprocess DNF to get rid of redundant stuff */
+
+ if (rdt_constrs < 0) return;
+ simplified_DNF->rm_redundant_inexact_conjs();
+
+ if (rdt_conjs > r_conjs) {
+ if(pres_debug)
+ fprintf(DebugFile,"=== Rel_Body::simplify() redundant CONJUNCTS ===\n");
+ simplified_DNF->rm_redundant_conjs(rdt_conjs-1);
+ }
+ if (rdt_constrs > 0 ) {
+ if(pres_debug)
+ fprintf(DebugFile,"=== Rel_Body::simplify() redundant CONSTR-S ===\n");
+ s_rdt_constrs = rdt_constrs;
+ simplified_DNF->simplify();
+ }
+ }
+
+ r_conjs = rdt_conjs;
+
+ for(DNF_Iterator D(simplified_DNF); D.live(); D.next()) {
+ D.curr()->set_relation(this);
+ D.curr()->set_parent(this);
+ }
+}
+
+
+// ******************
+// Query functions
+// ******************
+
+
+//
+// Check if relation has a single conjunct formula and return this conjunct.
+//
+Conjunct *Rel_Body::single_conjunct() {
+ simplify();
+ return simplified_DNF->single_conjunct();
+}
+
+bool Rel_Body::has_single_conjunct() {
+ simplify();
+ return simplified_DNF->has_single_conjunct();
+}
+
+//
+// Remove and return first conjunct
+//
+Conjunct *Rel_Body::rm_first_conjunct() {
+ simplify();
+ return simplified_DNF->rm_first_conjunct();
+}
+
+
+void Rel_Body::query_difference(Variable_ID v1, Variable_ID v2, coef_t &lowerBound, coef_t &upperBound, bool &guaranteed) {
+ simplify();
+
+ coef_t _lb, _ub;
+ int first = 1;
+ bool _g;
+ lowerBound = negInfinity; // default values if no DNF's
+ upperBound = posInfinity;
+ guaranteed = 0;
+
+ for (DNF_Iterator D(simplified_DNF); D.live(); D.next()) {
+ (*D)->query_difference(v1, v2, _lb, _ub, _g);
+ if (first) {
+ lowerBound = _lb;
+ upperBound = _ub;
+ guaranteed = _g;
+ first = 0;
+ }
+ else {
+ guaranteed = guaranteed && _g;
+ lowerBound = min(lowerBound, _lb);
+ upperBound = max(upperBound, _ub);
+ }
+ }
+}
+
+
+void Rel_Body::query_variable_bounds(Variable_ID v, coef_t &lowerBound, coef_t &upperBound) {
+ simplify();
+
+ coef_t _lb, _ub;
+ int first = 1;
+ lowerBound = negInfinity; // default values if no DNF's
+ upperBound = posInfinity;
+
+ for (DNF_Iterator D(simplified_DNF); D.live(); D.next()) {
+ (*D)->query_variable_bounds(v, _lb, _ub);
+ if (first) {
+ lowerBound = _lb;
+ upperBound = _ub;
+ first = 0;
+ }
+ else {
+ lowerBound = min(lowerBound, _lb);
+ upperBound = max(upperBound, _ub);
+ }
+ }
+}
+
+coef_t Rel_Body::query_variable_mod(Variable_ID v, coef_t factor) {
+ simplify();
+
+ bool first = true;
+ coef_t result;
+
+ for (DNF_Iterator D(simplified_DNF); D.live(); D.next()) {
+ coef_t t = (*D)->query_variable_mod(v, factor);
+ if (t == posInfinity)
+ return posInfinity;
+
+ if (first) {
+ result = t;
+ first = false;
+ }
+ else {
+ if (result != t)
+ return posInfinity;
+ }
+ }
+
+ return result;
+}
+
+
+
+//
+// Simplify formula if needed and return the resulting DNF.
+//
+DNF* Rel_Body::query_DNF() {
+ return(query_DNF(false,false));
+}
+
+DNF* Rel_Body::query_DNF(int rdt_conjs, int rdt_constrs) {
+ simplify(rdt_conjs, rdt_constrs);
+ return(simplified_DNF);
+}
+
+//
+// Other formula queries.
+//
+
+// Interpret UNKNOWN as true, then check satisfiability
+// i.e., check if the formula simplifies to FALSE, since the library
+// will never say that if the *known* constraints are unsatisfiable by
+// themselves.
+bool Rel_Body::is_upper_bound_satisfiable() {
+ int tmp = s_rdt_constrs;
+ s_rdt_constrs = -1;
+ simplify();
+ s_rdt_constrs = tmp;
+ return(!simplified_DNF->is_definitely_false());
+}
+
+// Interpret UNKNOWN as false, then check satisfiability
+// i.e., check if there exist any exact conjuncts in the solution
+bool Rel_Body::is_lower_bound_satisfiable() {
+ int tmp = s_rdt_constrs;
+ s_rdt_constrs = -1;
+ simplify();
+ s_rdt_constrs = tmp;
+ for(DNF_Iterator d(simplified_DNF); d; d++)
+ if((*d)->is_exact()) return true;
+ return false;
+}
+
+bool Rel_Body::is_satisfiable() {
+ assert(is_lower_bound_satisfiable() == is_upper_bound_satisfiable());
+ return is_upper_bound_satisfiable();
+}
+
+// Check if we can easily determine if the formula evaluates to true.
+bool Rel_Body::is_obvious_tautology() {
+ int tmp = s_rdt_constrs;
+ s_rdt_constrs = 0;
+ simplify();
+ s_rdt_constrs = tmp;
+ return(simplified_DNF->is_definitely_true());
+}
+
+// Expensive check to determine if the formula evaluates to true.
+bool Rel_Body::is_definite_tautology() {
+ if(is_obvious_tautology()) return true;
+ Relation l = Lower_Bound(Relation(*this,1));
+ return !(Complement(l).is_upper_bound_satisfiable());
+}
+
+bool Rel_Body::is_unknown() {
+ simplify();
+ return(has_single_conjunct() && single_conjunct()->is_unknown());
+}
+
+//
+// Get accuracy status of the relation
+//
+
+Rel_Unknown_Uses Rel_Body::unknown_uses() {
+ if (!is_simplified())
+ simplify();
+
+ Rel_Unknown_Uses local_status=0;
+ int n_conj=0;
+
+ for (DNF_Iterator c(simplified_DNF); c; c++) {
+ n_conj++;
+ if ((*c)->is_exact())
+ local_status |= no_u;
+ else if ((*c)->is_unknown())
+ local_status |= or_u;
+ else
+ local_status |= and_u;
+ }
+
+ if (n_conj == 0) {
+ assert(local_status == 0);
+ local_status = no_u;
+ }
+ assert(local_status);
+#if ! defined NDEBUG
+ Rel_Unknown_Uses impossible = (and_u | or_u);
+ assert( (local_status & impossible) != impossible);
+#endif
+
+ return local_status;
+}
+
+void Rel_Body::interpret_unknown_as_false() {
+ simplify();
+ simplified_DNF->remove_inexact_conj();
+}
+
+void Rel_Body::interpret_unknown_as_true() {
+ simplify();
+ for(DNF_Iterator d(simplified_DNF); d; d++)
+ (*d)->interpret_unknown_as_true();
+}
+
+
+void Rel_Body::reverse_leading_dir_info() {
+ if (is_simplified()) {
+ for (DNF_Iterator c(simplified_DNF); c; c++)
+ (*c)->reverse_leading_dir_info();
+ }
+ else {
+ assert(!simplified_DNF);
+ assert(children().size() == 1);
+ children().front()->reverse_leading_dir_info();
+ }
+}
+
+//
+// Rel_Body::DNFize just DNF-izes its child node and calls verify
+//
+
+DNF* Rel_Body::DNFize() {
+#if defined(INCLUDE_COMPRESSION)
+ assert(!this->is_compressed());
+#endif
+ if (! simplified_DNF) {
+ simplified_DNF = children().remove_front()->DNFize();
+
+ int mua = max_shared_ufs_arity();
+ if (mua > 0) {
+ if (pres_debug) {
+ fprintf(DebugFile, "\n=== In DNFize, before LCDNF ===\n");
+ prefix_print(DebugFile);
+ }
+
+ simplified_DNF->make_level_carried_to(mua);
+ }
+
+ if(pres_debug) {
+ fprintf(DebugFile, "\n=== In DNFize, before verify ===\n");
+ prefix_print(DebugFile);
+ }
+
+ simplified_DNF->simplify();
+ }
+
+ assert(children().length() == 0);
+
+ return simplified_DNF;
+}
+
+void Rel_Body::make_level_carried_to(int level) {
+ if (!simplified_DNF) {
+ DNFize();
+ }
+
+ assert(simplified_DNF && children().empty());
+
+ simplified_DNF->make_level_carried_to(level);
+}
+
+//
+// if direction==0, move all conjuncts with >= level leading 0's to return
+// else move all conjuncts with level-1 0's followed by
+// the appropriate signed difference to returned Relation
+//
+
+Relation Rel_Body::extract_dnf_by_carried_level(int level, int direction) {
+ if (!simplified_DNF) {
+ DNFize();
+ }
+
+ assert(simplified_DNF && children().empty());
+
+ simplified_DNF->make_level_carried_to(level);
+
+ Relation extracted(n_inp(), n_out());
+ extracted.copy_names(*this);
+ assert(extracted.rel_body->children().empty());
+ assert(extracted.rel_body->simplified_DNF == NULL);
+ extracted.rel_body->simplified_DNF = new DNF;
+ extracted.rel_body->Symbolic = Symbolic;
+
+ DNF *remaining = new DNF;
+ Conjunct *curr;
+
+ for (curr = simplified_DNF->rm_first_conjunct();
+ curr;
+ curr = simplified_DNF->rm_first_conjunct()) {
+ assert(curr->guaranteed_leading_0s >= level || curr->guaranteed_leading_0s == curr->possible_leading_0s);
+ assert(curr->possible_leading_0s >= 0);
+
+ curr->assert_leading_info();
+
+ if ((direction == 0 && curr->guaranteed_leading_0s >= level) ||
+ (curr->guaranteed_leading_0s == level-1 &&
+ curr->leading_dir_valid_and_known() &&
+ curr->leading_dir * direction > 0)) {
+ extracted.rel_body->simplified_DNF->add_conjunct(curr);
+ }
+ else {
+ remaining->add_conjunct(curr);
+ }
+ }
+ delete simplified_DNF;
+ simplified_DNF = remaining;
+
+#if ! defined NDEBUG
+ for (DNF_Iterator rc(simplified_DNF); rc; rc++)
+ (*rc)->assert_leading_info();
+
+ for (DNF_Iterator ec(extracted.rel_body->simplified_DNF); ec; ec++)
+ (*ec)->assert_leading_info();
+#endif
+
+ finalize();
+ extracted.finalize();
+ return extracted;
+}
+
+//Compress/uncompress functions
+
+bool Rel_Body::is_compressed() {
+#if defined(INCLUDE_COMPRESSION)
+ if(is_simplified()) {
+ for(DNF_Iterator p(simplified_DNF); p.live(); p.next()) {
+ if(p.curr()->is_compressed())
+ return true;
+ }
+ }
+ return false;
+#else
+ return true; // This allows is_compressed assertions to work
+#endif
+}
+
+void Rel_Body::compress() {
+#if !defined(INCLUDE_COMPRESSION)
+ return;
+#else
+ if (status == compressed)
+ return;
+ if (pres_debug)
+ fprintf(DebugFile,">>> Compressing relation %p\n",this);
+ simplify();
+ for(DNF_Iterator p(simplified_DNF); p.live(); p.next()) {
+ p.curr()->compress();
+ status = compressed;
+ }
+#endif
+}
+
+void Rel_Body::uncompress() {
+#if !defined(INCLUDE_COMPRESSION)
+ return;
+#else
+ if (pres_debug)
+ fprintf(DebugFile,"<<< Uncompressing relation %p\n",this);
+ assert(is_simplified());
+ for(DNF_Iterator p(simplified_DNF); p.live(); p.next()) {
+ p.curr()->uncompress();
+ status = uncompressed;
+ }
+#endif
+}
+
+}