summaryrefslogtreecommitdiff
path: root/omegalib/omega
diff options
context:
space:
mode:
Diffstat (limited to 'omegalib/omega')
-rw-r--r--omegalib/omega/CMakeLists.txt69
-rw-r--r--omegalib/omega/doc/interface.pdfbin0 -> 276190 bytes
-rw-r--r--omegalib/omega/include/basic/Bag.c329
-rw-r--r--omegalib/omega/include/basic/Bag.h78
-rwxr-xr-xomegalib/omega/include/basic/BoolSet.h637
-rw-r--r--omegalib/omega/include/basic/Collection.h47
-rw-r--r--omegalib/omega/include/basic/Collections.h12
-rw-r--r--omegalib/omega/include/basic/ConstString.h58
-rw-r--r--omegalib/omega/include/basic/Dynamic_Array.c219
-rw-r--r--omegalib/omega/include/basic/Dynamic_Array.h103
-rw-r--r--omegalib/omega/include/basic/Iterator.h131
-rw-r--r--omegalib/omega/include/basic/Link.h98
-rw-r--r--omegalib/omega/include/basic/List.c149
-rw-r--r--omegalib/omega/include/basic/List.h95
-rw-r--r--omegalib/omega/include/basic/Map.c63
-rw-r--r--omegalib/omega/include/basic/Map.h68
-rw-r--r--omegalib/omega/include/basic/Section.c79
-rw-r--r--omegalib/omega/include/basic/Section.h63
-rw-r--r--omegalib/omega/include/basic/SimpleList.c105
-rw-r--r--omegalib/omega/include/basic/SimpleList.h93
-rw-r--r--omegalib/omega/include/basic/Tuple.c254
-rw-r--r--omegalib/omega/include/basic/Tuple.h90
-rwxr-xr-xomegalib/omega/include/basic/boolset-test.cc72
-rw-r--r--omegalib/omega/include/basic/omega_error.h14
-rw-r--r--omegalib/omega/include/basic/util.h263
-rw-r--r--omegalib/omega/include/omega.h71
-rw-r--r--omegalib/omega/include/omega/RelBody.h165
-rw-r--r--omegalib/omega/include/omega/Rel_map.h161
-rw-r--r--omegalib/omega/include/omega/Relation.h299
-rw-r--r--omegalib/omega/include/omega/Relations.h88
-rw-r--r--omegalib/omega/include/omega/closure.h31
-rw-r--r--omegalib/omega/include/omega/evac.h15
-rw-r--r--omegalib/omega/include/omega/farkas.h19
-rw-r--r--omegalib/omega/include/omega/hull.h89
-rw-r--r--omegalib/omega/include/omega/omega_core/debugging.h30
-rw-r--r--omegalib/omega/include/omega/omega_core/oc.h350
-rw-r--r--omegalib/omega/include/omega/omega_core/oc_i.h79
-rw-r--r--omegalib/omega/include/omega/omega_i.h30
-rw-r--r--omegalib/omega/include/omega/pres_cmpr.h49
-rw-r--r--omegalib/omega/include/omega/pres_cnstr.h192
-rw-r--r--omegalib/omega/include/omega/pres_conj.h299
-rw-r--r--omegalib/omega/include/omega/pres_decl.h55
-rw-r--r--omegalib/omega/include/omega/pres_dnf.h87
-rw-r--r--omegalib/omega/include/omega/pres_form.h112
-rw-r--r--omegalib/omega/include/omega/pres_gen.h192
-rw-r--r--omegalib/omega/include/omega/pres_logic.h90
-rw-r--r--omegalib/omega/include/omega/pres_quant.h63
-rw-r--r--omegalib/omega/include/omega/pres_subs.h88
-rw-r--r--omegalib/omega/include/omega/pres_tree.h15
-rw-r--r--omegalib/omega/include/omega/pres_var.h230
-rw-r--r--omegalib/omega/include/omega/reach.h23
-rw-r--r--omegalib/omega/src/RelBody.cc906
-rw-r--r--omegalib/omega/src/RelVar.cc71
-rw-r--r--omegalib/omega/src/Relation.cc279
-rw-r--r--omegalib/omega/src/Relations.cc2882
-rw-r--r--omegalib/omega/src/basic/ConstString.cc134
-rw-r--r--omegalib/omega/src/basic/Link.cc41
-rw-r--r--omegalib/omega/src/closure.cc2100
-rw-r--r--omegalib/omega/src/evac.cc339
-rw-r--r--omegalib/omega/src/farkas.cc480
-rw-r--r--omegalib/omega/src/hull.cc1489
-rwxr-xr-xomegalib/omega/src/hull_legacy.cc1484
-rwxr-xr-xomegalib/omega/src/hull_simple.cc1013
-rw-r--r--omegalib/omega/src/omega_core/oc.cc754
-rw-r--r--omegalib/omega/src/omega_core/oc_eq.cc653
-rw-r--r--omegalib/omega/src/omega_core/oc_exp_kill.cc297
-rw-r--r--omegalib/omega/src/omega_core/oc_global.cc45
-rw-r--r--omegalib/omega/src/omega_core/oc_print.cc686
-rw-r--r--omegalib/omega/src/omega_core/oc_problems.cc198
-rw-r--r--omegalib/omega/src/omega_core/oc_query.cc478
-rw-r--r--omegalib/omega/src/omega_core/oc_quick_kill.cc775
-rw-r--r--omegalib/omega/src/omega_core/oc_simple.cc1373
-rw-r--r--omegalib/omega/src/omega_core/oc_solve.cc1378
-rw-r--r--omegalib/omega/src/omega_core/oc_util.cc327
-rw-r--r--omegalib/omega/src/pres_beaut.cc235
-rw-r--r--omegalib/omega/src/pres_cnstr.cc450
-rw-r--r--omegalib/omega/src/pres_col.cc104
-rw-r--r--omegalib/omega/src/pres_conj.cc1460
-rw-r--r--omegalib/omega/src/pres_decl.cc71
-rw-r--r--omegalib/omega/src/pres_dnf.cc1416
-rw-r--r--omegalib/omega/src/pres_form.cc147
-rw-r--r--omegalib/omega/src/pres_gen.cc45
-rw-r--r--omegalib/omega/src/pres_logic.cc226
-rw-r--r--omegalib/omega/src/pres_print.cc908
-rw-r--r--omegalib/omega/src/pres_quant.cc95
-rw-r--r--omegalib/omega/src/pres_rear.cc131
-rw-r--r--omegalib/omega/src/pres_subs.cc131
-rw-r--r--omegalib/omega/src/pres_var.cc459
-rw-r--r--omegalib/omega/src/reach.cc211
89 files changed, 30382 insertions, 0 deletions
diff --git a/omegalib/omega/CMakeLists.txt b/omegalib/omega/CMakeLists.txt
new file mode 100644
index 0000000..5bc7e0b
--- /dev/null
+++ b/omegalib/omega/CMakeLists.txt
@@ -0,0 +1,69 @@
+set(BASIC_SRC
+ src/basic/ConstString.cc
+ src/basic/Link.cc
+ )
+
+set(OC_SRC
+ src/omega_core/oc.cc
+ src/omega_core/oc_eq.cc
+ src/omega_core/oc_exp_kill.cc
+ src/omega_core/oc_global.cc
+ src/omega_core/oc_print.cc
+ src/omega_core/oc_problems.cc
+ src/omega_core/oc_simple.cc
+ src/omega_core/oc_solve.cc
+ src/omega_core/oc_query.cc
+ src/omega_core/oc_quick_kill.cc
+ src/omega_core/oc_util.cc
+ )
+
+set(PRES_SRC
+ src/pres_beaut.cc
+ src/pres_cnstr.cc
+ src/pres_col.cc
+ src/pres_conj.cc
+ src/pres_decl.cc
+ src/pres_dnf.cc
+ src/pres_form.cc
+ src/pres_gen.cc
+ src/pres_logic.cc
+ src/pres_print.cc
+ src/pres_rear.cc
+ src/pres_quant.cc
+ src/pres_subs.cc
+ src/pres_var.cc
+ )
+
+set(REL_SRC
+ src/evac.cc
+ src/farkas.cc
+ src/hull_legacy.cc
+ src/hull_simple.cc
+ src/Relation.cc
+ src/Relations.cc
+ src/RelBody.cc
+ src/RelVar.cc
+ )
+
+set(FANCY_SRC
+ src/closure.cc
+ src/reach.cc
+ )
+
+include_directories(
+ include
+ )
+
+add_library(omega
+ ${BASIC_SRC}
+ ${OC_SRC}
+ ${PRES_SRC}
+ ${REL_SRC}
+ ${FANCY_SRC}
+ )
+
+install(TARGETS omega
+ ARCHIVE DESTINATION lib)
+
+install(DIRECTORY include
+ DESTINATION .)
diff --git a/omegalib/omega/doc/interface.pdf b/omegalib/omega/doc/interface.pdf
new file mode 100644
index 0000000..7f918ae
--- /dev/null
+++ b/omegalib/omega/doc/interface.pdf
Binary files differ
diff --git a/omegalib/omega/include/basic/Bag.c b/omegalib/omega/include/basic/Bag.c
new file mode 100644
index 0000000..c3084c1
--- /dev/null
+++ b/omegalib/omega/include/basic/Bag.c
@@ -0,0 +1,329 @@
+/****************************************************************
+ * *
+ * Collection constructors, desctructors, assignments *
+ * *
+ ****************************************************************/
+
+#include <assert.h>
+
+namespace omega {
+
+template<class T> Bag<T>::Bag() {
+ contents = new List_Element <T>;
+ contents->tail = 0;
+ }
+template<class T> Bag<T>::~Bag() {
+ delete contents;
+ }
+
+template<class T> Ordered_Bag<T>::Ordered_Bag() {}
+
+template<class T> Set<T>::Set() {}
+
+template<class T> Bag<T>::Bag(const Bag<T> &L) {
+ contents = new List_Element<T>(*L.contents);
+ }
+
+template<class T> Bag<T> & Bag<T>::operator=(const Bag<T> &L) {
+ if (this != &L) {
+ delete contents;
+ contents = new List_Element<T>(*L.contents);
+ }
+ return *this;
+ }
+
+
+
+template<class T> Set<T>::Set(T e) {
+ assert(this->contents);
+ this->contents->tail = new List_Element<T>(e, 0);
+ }
+
+
+/****************************************************************
+ * *
+ * Misc. simple Collection operations *
+ * *
+ ****************************************************************/
+
+template<class T> bool Bag<T>::empty() const {
+ return contents->tail == 0;
+ }
+
+template<class T> Iterator<T> *Bag<T>::new_iterator()
+ {
+ return new List_Element_Iterator<T>(contents->tail);
+ }
+
+
+template<class T> void Bag<T>::clear() {
+ if (contents->tail) delete contents->tail;
+ contents->tail = 0;
+ }
+
+template<class T> int Bag<T>::size() const {
+ int i = 0;
+ List_Element<T> * p = contents->tail;
+ while (p) {
+ p = p->tail;
+ i++;
+ };
+ return i;
+ }
+
+
+/****************************************************************
+ * *
+ * Collection/Element operations (e.g. insert, contains) *
+ * *
+ ****************************************************************/
+
+template<class T> void Bag<T>::remove(T e) {
+ List_Element<T> * p = contents;
+ while (p->tail && p->tail->head != e) p = p->tail;
+ if (p->tail && p->tail->head == e) {
+ List_Element<T> * q = p->tail;
+ p->tail = q->tail;
+ q->tail = 0;
+ delete q;
+ }
+ }
+
+template<class T> T Bag<T>::extract() {
+ List_Element<T> * p = contents->tail;
+ T e = p->head;
+ contents->tail = p->tail;
+ p->tail = 0;
+ delete p;
+ return e;
+ }
+
+
+template<class T> void Bag<T>::insert(T e) {
+ List_Element<T> * q = new List_Element<T>(e,contents->tail);
+ contents->tail = q;
+ }
+
+template<class T> void Ordered_Bag<T>::insert(T e) {
+ List_Element<T> * p = this->contents;
+ while (p->tail && p->tail->head < e) p = p->tail;
+ if (!p->tail || p->tail->head != e) {
+ List_Element<T> * q = new List_Element<T>(e,p->tail);
+ p->tail = q;
+ }
+ }
+
+
+template<class T> bool Bag<T>::contains(T e) const {
+ List_Element<T> * p = contents;
+ while (p->tail && p->tail->head != e) p = p->tail;
+ return (p->tail && p->tail->head == e);
+ }
+
+template<class T> bool Ordered_Bag<T>::contains(T e) const {
+ List_Element<T> * p = this->contents;
+ while (p->tail && p->tail->head < e) p = p->tail;
+ return (p->tail && p->tail->head == e);
+ }
+
+
+template<class T> bool Set<T>::contains (const Set<T>& b) const {
+ List_Element<T> * p = this->contents;
+ List_Element<T> * q = b.contents;
+ do {
+ /* consume matched elements in p and q */
+ p = p->tail;
+ q = q->tail;
+ if (!q) return 1; /* no more elements to match */
+ if (!p) return 0; /* nothing left in p to match with */
+ if (q->head < p->head) {
+ /* nothing smaller than
+ p->head left in p, so q->head
+ can't be matched */
+ return 0;
+ };
+ while (p && p->head < q->head) {
+ /* toss away some elements from p */
+ p = p->tail;
+ }
+ if (!p || q->head < p->head) return 0;
+ } while (q);
+
+ return 1;
+ }
+
+
+
+/****************************************************************
+ * *
+ * Collection/Collection operations (e.g. |=) *
+ * *
+ ****************************************************************/
+
+template<class T> void Bag<T>::operator |= (const Bag<T> & b) {
+ assert(this != &b);
+ List_Element<T> * q = b.contents->tail;
+
+ while (q) {
+ List_Element<T> * r = new List_Element<T>(q->head,contents->tail);
+ contents->tail = r;
+ q = q->tail;
+ }
+ }
+
+template<class T> void Ordered_Bag<T>::operator |= (const Ordered_Bag<T> & b) {
+ if (this == &b) return;
+ List_Element<T> * p = this->contents;
+ List_Element<T> * q = b.contents->tail;
+
+ while (q) {
+ while (p->tail && p->tail->head < q->head) p = p->tail;
+ List_Element<T> * r = new List_Element<T>(q->head,p->tail);
+ p->tail = r;
+ q = q->tail;
+ }
+ }
+
+template<class T> void Ordered_Bag<T>::operator |= (const Bag<T> & b) {
+ Ordered_Bag<T> tmp;
+ for (List_Element<T> *p = b.contents; p; p=p->tail) {
+ tmp.insert(p->head);
+ }
+ *this |= tmp;
+}
+
+template<class T> void Set<T>::operator |= (const Set<T> & b) {
+ if (this == &b) return;
+ List_Element<T> * p = this->contents;
+ List_Element<T> * q = b.contents->tail;
+
+ while (q) {
+ while (p->tail && p->tail->head < q->head) p = p->tail;
+ if (!p->tail || p->tail->head != q->head) {
+ List_Element<T> * r = new List_Element<T>(q->head,p->tail);
+ p->tail = r;
+ }
+ q = q->tail;
+ }
+ }
+
+template<class T> void Set<T>::operator |= (const Ordered_Bag<T> & b) {
+ Set<T> tmp;
+ for (List_Element<T> *p = b.contents; p; p=p->tail) {
+ tmp.insert(p->head);
+ }
+ *this |= tmp;
+}
+
+template<class T> void Set<T>::operator |= (const Bag<T> & b) {
+ Set<T> tmp;
+ for (List_Element<T> *p = b.contents; p; p=p->tail) {
+ tmp.insert(p->head);
+ }
+ *this |= tmp;
+}
+
+
+
+// delete items also in b
+template<class T> void Set<T>::operator -= (const Set<T> & b) {
+ if (this == &b) {
+ this->clear();
+ return;
+ }
+ List_Element<T> * p = this->contents;
+ List_Element<T> * q = b.contents->tail;
+
+ while (q) {
+ while (p->tail && p->tail->head < q->head) p = p->tail;
+ if (p->tail && p->tail->head == q->head) {
+ List_Element<T> * r = p->tail;
+ p->tail = r->tail;
+ r->tail = 0;
+ delete r;
+ }
+ q = q->tail;
+ }
+ }
+
+
+// delete items not in b
+template<class T> void Set<T>::operator &= (const Set<T> & b)
+ {
+ if (this == &b) return;
+ List_Element<T> * p = this->contents;
+ List_Element<T> * q = b.contents->tail;
+
+ while (q) {
+ while (p->tail && p->tail->head < q->head) {
+ List_Element<T> * r = p->tail;
+ p->tail = r->tail;
+ r->tail = 0;
+ delete r;
+ };
+ if (p->tail && p->tail->head == q->head) {
+ /* allow p->tail->head into the result */
+ p = p->tail;
+ }
+ /* q->head has matched anything it is going to match */
+ q = q->tail;
+ }
+ if (p->tail) {
+ delete p->tail;
+ p->tail = 0;
+ };
+
+ }
+
+
+template<class T> bool Set<T>::operator & (const Set<T>& b) const {
+ List_Element<T> * p = this->contents;
+ List_Element<T> * q = b.contents;
+ do {
+ p = p->tail;
+ q = q->tail;
+ while (p && q && p->head != q->head) {
+ while (p && p->head < q->head) p = p->tail;
+ while (p && q && q->head < p->head) q = q->tail;
+ };
+ if (p && q && p->head == q->head) return 1;
+ } while (p && q);
+
+ return 0;
+ }
+
+
+template<class T> bool Ordered_Bag<T>::operator == (const Ordered_Bag<T>& b) const {
+ List_Element<T> * p = this->contents;
+ List_Element<T> * q = b.contents;
+ while (1) {
+ p = p->tail;
+ q = q->tail;
+ if (!p && !q) return 1;
+ if (!p || !q) return 0;
+ if (p->head != q->head) return 0;
+ };
+
+ }
+
+template<class T> bool Ordered_Bag<T>::operator != (const Ordered_Bag<T>& b) const {
+ return !(*this == b);
+ }
+
+template<class T> bool Ordered_Bag<T>::operator < (const Ordered_Bag<T>& b) const {
+ List_Element<T> * p = this->contents;
+ List_Element<T> * q = b.contents;
+ while (1) {
+ p = p->tail;
+ q = q->tail;
+ if (!p && !q) return 0;
+ if (!p) return 1;
+ if (!q) return 0;
+ if (p->head < q->head) return 1;
+ if (q->head < p->head) return 0;
+ };
+
+ return 1;
+ }
+
+} // namespace
diff --git a/omegalib/omega/include/basic/Bag.h b/omegalib/omega/include/basic/Bag.h
new file mode 100644
index 0000000..42285d0
--- /dev/null
+++ b/omegalib/omega/include/basic/Bag.h
@@ -0,0 +1,78 @@
+#if ! defined _Bag_h
+#define _Bag_h 1
+
+#include <stdio.h>
+#include <basic/Iterator.h>
+#include <basic/Collection.h>
+#include <basic/Link.h>
+
+namespace omega {
+
+template<class T> class Bag : public Collection<T> {
+public:
+virtual ~Bag();
+ Bag();
+ Bag(const Bag<T>&);
+ Bag & operator=(const Bag<T>&);
+virtual void operator |= (const Bag<T> & b); // add elements in b
+ Iterator<T> *new_iterator();
+ bool empty() const;
+ void remove(T);
+virtual void insert(T);
+ void clear();
+virtual bool contains(T) const;
+ int size() const;
+ T extract();
+// protected: breaks g++ 261
+ List_Element<T>* contents;
+};
+
+
+template<class T> class Ordered_Bag : public Bag<T> {
+public:
+ Ordered_Bag();
+// virtual ~Ordered_Bag();
+ Ordered_Bag(const Ordered_Bag<T>& B) : Bag<T>(B) {}
+ void insert(T);
+virtual void operator |= (const Ordered_Bag<T> & b); // add elements in b
+ void operator |= (const Bag<T> & b);
+ bool contains(T) const;
+ bool operator == (const Ordered_Bag<T>&) const;
+ bool operator != (const Ordered_Bag<T>&) const;
+ bool operator < (const Ordered_Bag<T>&) const;
+};
+
+template <class T> class Set : public Ordered_Bag <T> {
+public:
+ Set();
+// virtual ~Set();
+ Set(T);
+ Set(const Set<T>& S) : Ordered_Bag<T>(S) {}
+
+ bool contains (const Set<T>& b) const;
+ bool contains (T t) const { return Ordered_Bag<T>::contains(t); }
+ // the above makes "standard" C++ happy
+
+virtual void operator |= (const Set<T> & b); // add elements in b
+ void operator |= (const Ordered_Bag<T> & b);
+ void operator |= (const Bag<T> & b);
+
+ void operator -= (const Set<T> & b); // delete items also in b
+ void operator &= (const Set<T> & b); // delete items not in b
+ bool operator & (const Set<T> &) const; // check for elements in common
+};
+
+} // namespace
+
+#if ! defined DONT_INCLUDE_TEMPLATE_CODE
+#include <basic/Bag.c>
+#endif
+
+#define instantiate_Bag(T) template class Bag<T>; \
+ instantiate_List_Element(T);
+#define instantiate_Ordered_Bag(T) template class Ordered_Bag<T>; \
+ instantiate_Bag(T)
+#define instantiate_Set(T) template class Set<T>; \
+ instantiate_Ordered_Bag(T)
+
+#endif
diff --git a/omegalib/omega/include/basic/BoolSet.h b/omegalib/omega/include/basic/BoolSet.h
new file mode 100755
index 0000000..dc9ef83
--- /dev/null
+++ b/omegalib/omega/include/basic/BoolSet.h
@@ -0,0 +1,637 @@
+/*****************************************************************************
+ Copyright (C) 2009-2011 Chun Chen
+ All Rights Reserved.
+
+ Purpose:
+ BoolSet class, used as a set of integers from 0..n-1 where n is a very
+ small integer.
+
+ Notes:
+ Set operands of binary operations can be of different sizes, missing
+ elements are treated as false.
+
+ History:
+ 03/30/09 Created by Chun Chen.
+ 03/26/11 iterator added, -chun
+*****************************************************************************/
+
+#ifndef _BOOLSET_H
+#define _BOOLSET_H
+
+#include <vector>
+#include <iostream>
+#include <assert.h>
+#include <stdexcept>
+#include <iterator>
+
+namespace omega {
+
+template<typename T = unsigned int>
+class BoolSet {
+protected:
+ unsigned int size_;
+ std::vector<T> set_;
+
+public:
+ BoolSet(unsigned int size = 0);
+ ~BoolSet() {}
+
+ void set(unsigned int);
+ void unset(unsigned int);
+ void set_all();
+ void unset_all();
+ bool get(unsigned int) const;
+ unsigned int size() const {return size_;}
+ unsigned int num_elem() const;
+ bool imply(const BoolSet<T> &) const;
+ bool empty() const;
+ void dump() const;
+
+ BoolSet<T> &operator|=(const BoolSet<T> &);
+ BoolSet<T> &operator&=(const BoolSet<T> &);
+ BoolSet<T> &operator-=(const BoolSet<T> &);
+
+ template<typename TT> friend BoolSet<TT> operator|(const BoolSet<TT> &, const BoolSet<TT> &); // union
+ template<typename TT> friend BoolSet<TT> operator&(const BoolSet<TT> &, const BoolSet<TT> &); // intersection
+ template<typename TT> friend BoolSet<TT> operator-(const BoolSet<TT> &, const BoolSet<TT> &); // difference
+ template<typename TT> friend BoolSet<TT> operator~(const BoolSet<TT> &); // complement
+ template<typename TT> friend bool operator==(const BoolSet<TT> &, const BoolSet<TT> &);
+ template<typename TT> friend bool operator!=(const BoolSet<TT> &, const BoolSet<TT> &);
+ template<typename TT> friend std::ostream& operator<<(std::ostream &, const BoolSet<TT> &);
+ template<typename TT> friend bool operator<(const BoolSet<TT> &, const BoolSet<TT> &);
+
+// iterator related
+public:
+ class iterator;
+ class const_iterator;
+ iterator begin();
+ iterator end();
+ const_iterator begin() const;
+ const_iterator end() const;
+};
+
+
+template<typename T>
+BoolSet<T>::BoolSet(unsigned int size) {
+ assert(size >= 0);
+ size_ = size;
+ unsigned int n = size / (sizeof(T)*8);
+ unsigned int r = size % (sizeof(T)*8);
+ if (r != 0)
+ n++;
+ set_ = std::vector<T>(n, static_cast<T>(0));
+}
+
+
+template<typename T>
+void BoolSet<T>::set(unsigned int i) {
+ assert(i < size_ && i >= 0);
+ unsigned int n = i / (sizeof(T)*8);
+ unsigned int r = i % (sizeof(T)*8);
+
+ T t = static_cast<T>(1) << r;
+ set_[n] |= t;
+}
+
+
+template<typename T>
+void BoolSet<T>::unset(unsigned int i) {
+ assert(i < size_ && i >= 0);
+ unsigned int n = i / (sizeof(T)*8);
+ unsigned int r = i % (sizeof(T)*8);
+
+ T t = static_cast<T>(1) << r;
+ t = ~t;
+ set_[n] &= t;
+}
+
+
+template<typename T>
+void BoolSet<T>::set_all() {
+ unsigned int r = size_ % (sizeof(T)*8);
+ if (r == 0) {
+ for (unsigned int i = 0; i < set_.size(); i++)
+ set_[i] = ~static_cast<T>(0);
+ }
+ else {
+ for (unsigned int i = 0; i < set_.size()-1; i++)
+ set_[i] = ~static_cast<T>(0);
+ set_[set_.size()-1] = static_cast<T>(0);
+ T t = static_cast<T>(1);
+ for (unsigned int i = 0; i < r; i++) {
+ set_[set_.size()-1] |= t;
+ t = t<<1;
+ }
+ }
+}
+
+
+template<typename T>
+void BoolSet<T>::unset_all() {
+ for (unsigned int i = 0; i < set_.size(); i++)
+ set_[i] = static_cast<T>(0);
+}
+
+
+template<typename T>
+bool BoolSet<T>::get(unsigned int i) const {
+ assert(i < size_ && i >= 0);
+ unsigned int n = i / (sizeof(T)*8);
+ unsigned int r = i % (sizeof(T)*8);
+
+ T t = static_cast<T>(1) << r;
+ t = set_[n] & t;
+ if (t)
+ return true;
+ else
+ return false;
+}
+
+
+template<typename T>
+unsigned int BoolSet<T>::num_elem() const {
+ unsigned int n = size_;
+ unsigned int c = 0;
+ unsigned int p = 0;
+ while (n != 0) {
+ unsigned int m;
+ if (n >= sizeof(T)*8) {
+ m = sizeof(T)*8;
+ n -= sizeof(T)*8;
+ }
+ else {
+ m = n;
+ n = 0;
+ }
+
+ T v = set_[p++];
+ if (v != static_cast<T>(0)) {
+ for (unsigned int i = 0; i < m; i++) {
+ if (v & static_cast<T>(1))
+ c++;
+ v >>= 1;
+ }
+ }
+ }
+
+ return c;
+}
+
+
+template<typename T>
+bool BoolSet<T>::imply(const BoolSet<T> &b) const {
+ if (size_ >= b.size_) {
+ for (unsigned int i = 0; i < b.set_.size(); i++)
+ if ((set_[i] & b.set_[i]) != b.set_[i])
+ return false;
+ }
+ else {
+ for (unsigned int i = 0; i < set_.size(); i++)
+ if ((set_[i] & b.set_[i]) != b.set_[i])
+ return false;
+ for (unsigned int i = set_.size(); i < b.set_.size(); i++)
+ if (b.set_[i] != static_cast<T>(0))
+ return false;
+ }
+
+ return true;
+}
+
+
+template<typename T>
+bool BoolSet<T>::empty() const {
+ for (int i = 0; i < set_.size(); i++)
+ if (set_[i] != static_cast<T>(0))
+ return false;
+
+ return true;
+}
+
+
+template<typename T>
+void BoolSet<T>::dump() const {
+ int j = 1;
+ for (unsigned int i = 0; i < size(); i++) {
+ if (get(i))
+ std::cout << '1';
+ else
+ std::cout << '0';
+ if (j%10 == 0 && i != size() - 1) {
+ std::cout << ' ';
+ j = 1;
+ }
+ else
+ j++;
+ }
+ std::cout << std::endl;
+ std::cout.flush();
+}
+
+
+template<typename T>
+BoolSet<T> operator|(const BoolSet<T> &a, const BoolSet<T> &b) {
+ if (a.size_ >= b.size_) {
+ BoolSet<T> c = a;
+ for (unsigned int i = 0; i < b.set_.size(); i++)
+ c.set_[i] |= b.set_[i];
+ return c;
+ }
+ else {
+ BoolSet<T> c = b;
+ for (unsigned int i = 0; i < a.set_.size(); i++)
+ c.set_[i] |= a.set_[i];
+ return c;
+ }
+}
+
+
+template<typename T>
+BoolSet<T> operator&(const BoolSet<T> &a, const BoolSet<T> &b) {
+ if (a.size_ >= b.size_) {
+ BoolSet<T> c = a;
+ for (unsigned int i = 0; i < b.set_.size(); i++)
+ c.set_[i] &= b.set_[i];
+ for (unsigned int i = b.set_.size(); i < a.set_.size(); i++)
+ c.set_[i] = static_cast<T>(0);
+ return c;
+ }
+ else {
+ BoolSet<T> c = b;
+ for (unsigned int i = 0; i < a.set_.size(); i++)
+ c.set_[i] &= a.set_[i];
+ for (unsigned int i = a.set_.size(); i < b.set_.size(); i++)
+ c.set_[i] = static_cast<T>(0);
+ return c;
+ }
+}
+
+
+template<typename T>
+BoolSet<T> operator-(const BoolSet<T> &a, const BoolSet<T> &b) {
+ BoolSet<T> c(a.size_);
+
+ int sz = a.set_.size();
+ if (sz > b.set_.size())
+ sz = b.set_.size();
+ for (int i = 0; i < sz; i++)
+ c.set_[i] = a.set_[i] ^ (a.set_[i] & b.set_[i]);
+ for (int i = sz; i < a.set_.size(); i++)
+ c.set_[i] = a.set_[i];
+
+ return c;
+}
+
+
+template<typename T>
+BoolSet<T> operator~(const BoolSet<T> &b) {
+ unsigned int r = b.size_ % (sizeof(T)*8);
+ BoolSet<T> a(b.size_);
+ for (unsigned int i = 0; i < b.set_.size(); i++)
+ a.set_[i] = ~b.set_[i];
+
+ if (r != 0) {
+ T t = static_cast<T>(1);
+ for (unsigned int i = 1; i < r; i++)
+ t = (t << 1) | static_cast<T>(1);
+ a.set_[a.set_.size()-1] &= t;
+ }
+ return a;
+}
+
+
+template<typename T>
+bool operator==(const BoolSet<T> &a, const BoolSet<T> &b) {
+ return (a.size_ == b.size_) && (a.set_ == b.set_);
+}
+
+
+template<typename T>
+bool operator!=(const BoolSet<T> &a, const BoolSet<T> &b) {
+ return !(a == b);
+}
+
+
+
+template<typename T>
+BoolSet<T> & BoolSet<T>::operator|=(const BoolSet<T> &b) {
+ *this = *this | b;
+ return *this;
+}
+
+
+template<typename T>
+BoolSet<T> & BoolSet<T>::operator&=(const BoolSet<T> &b) {
+ *this = *this & b;
+ return *this;
+}
+
+
+template<typename T>
+BoolSet<T> & BoolSet<T>::operator-=(const BoolSet<T> &b) {
+ *this = *this - b;
+ return *this;
+}
+
+
+template<typename T>
+std::ostream& operator<<(std::ostream &os, const BoolSet<T> &b) {
+ os << '{';
+ for (typename BoolSet<T>::const_iterator i = b.begin(); i != b.end(); i++) {
+ os << *i;
+ if (i+1 != b.end())
+ os << ',';
+ }
+ os << '}';
+
+ return os;
+}
+
+
+template<typename T>
+bool operator<(const BoolSet<T> &a, const BoolSet<T> &b) {
+ unsigned int t1, t2;
+ t1 = a.num_elem();
+ t2 = b.num_elem();
+ if (t1 < t2)
+ return true;
+ else if (t1 > t2)
+ return false;
+ else {
+ t1 = a.size();
+ t2 = b.size();
+ if (t1 < t2)
+ return true;
+ else if (t1 > t2)
+ return false;
+ else
+ for (unsigned int i = 0; i < a.set_.size(); i++)
+ if (a.set_[i] < b.set_[i])
+ return true;
+ }
+ return false;
+}
+
+
+//
+// iterator for BoolSet
+//
+
+template<typename T>
+typename BoolSet<T>::iterator BoolSet<T>::begin() {
+ typename BoolSet<T>::iterator it(this, 0);
+ if (size_ == 0)
+ return it;
+ else if (set_[0] & static_cast<T>(1))
+ return it;
+ else
+ return ++it;
+}
+
+
+template<typename T>
+typename BoolSet<T>::iterator BoolSet<T>::end() {
+ return typename BoolSet<T>::iterator(this, size_);
+}
+
+
+template<typename T>
+typename BoolSet<T>::const_iterator BoolSet<T>::begin() const {
+ typename BoolSet<T>::const_iterator it(this, 0);
+ if (size_ == 0)
+ return it;
+ else if (set_[0] & static_cast<T>(1))
+ return it;
+ else
+ return ++it;
+}
+
+
+template<typename T>
+typename BoolSet<T>::const_iterator BoolSet<T>::end() const {
+ return typename BoolSet<T>::const_iterator(this, size_);
+}
+
+
+template<typename T>
+class BoolSet<T>::iterator: public std::iterator<std::forward_iterator_tag, T> {
+protected:
+ BoolSet<T> *s_;
+ unsigned int pos_;
+
+protected:
+ iterator(BoolSet<T> *s, unsigned int pos) { s_ = s; pos_ = pos; }
+
+public:
+ ~iterator() {}
+
+ typename BoolSet<T>::iterator &operator++();
+ typename BoolSet<T>::iterator operator++(int);
+ typename BoolSet<T>::iterator operator+(int) const;
+ unsigned int operator*() const;
+ bool operator==(const BoolSet<T>::iterator &) const;
+ bool operator!=(const BoolSet<T>::iterator &) const;
+ operator typename BoolSet<T>::const_iterator();
+
+ friend class BoolSet<T>;
+};
+
+
+template<typename T>
+typename BoolSet<T>::iterator &BoolSet<T>::iterator::operator++() {
+ assert(pos_ < s_->size_);
+
+ pos_++;
+ unsigned int n = pos_ / (sizeof(T)*8);
+ unsigned int r = pos_ % (sizeof(T)*8);
+ while (pos_ < s_->size_) {
+ if (s_->set_[n] == static_cast<T>(0)) {
+ pos_ += sizeof(T)*8-r;
+ n++;
+ r = 0;
+ if (pos_ >= s_->size_)
+ break;
+ }
+
+ if (r == 0) {
+ while (pos_ < s_->size_) {
+ if (s_->set_[n] == static_cast<T>(0)) {
+ pos_ += sizeof(T)*8;
+ n++;
+ }
+ else
+ break;
+ }
+ if (pos_ >= s_->size_)
+ break;
+ }
+
+ for (unsigned int i = r; i < sizeof(T)*8; i++)
+ if (s_->set_[n] & static_cast<T>(1) << i) {
+ pos_ = pos_+i-r;
+ return *this;
+ }
+
+ pos_ += sizeof(T)*8-r;
+ n++;
+ r = 0;
+ }
+
+ pos_ = s_->size_;
+ return *this;
+}
+
+
+template<typename T>
+typename BoolSet<T>::iterator BoolSet<T>::iterator::operator++(int) {
+ typename BoolSet<T>::iterator it(*this);
+ ++(*this);
+ return it;
+}
+
+
+template<typename T>
+typename BoolSet<T>::iterator BoolSet<T>::iterator::operator+(int n) const {
+ assert(n >= 0);
+ typename BoolSet<T>::iterator it(*this);
+ while (n > 0) {
+ ++it;
+ --n;
+ }
+ return it;
+}
+
+
+template<typename T>
+unsigned int BoolSet<T>::iterator::operator*() const {
+ assert(pos_ < s_->size_);
+ return pos_;
+}
+
+
+template<typename T>
+bool BoolSet<T>::iterator::operator==(const BoolSet<T>::iterator &other) const {
+ return s_ == other.s_ && pos_ == other.pos_;
+}
+
+
+template<typename T>
+bool BoolSet<T>::iterator::operator!=(const BoolSet<T>::iterator &other) const {
+ return !((*this) == other);
+}
+
+
+template<typename T>
+BoolSet<T>::iterator::operator typename BoolSet<T>::const_iterator() {
+ return BoolSet<T>::const_iterator(s_, pos_);
+}
+
+
+template<typename T>
+class BoolSet<T>::const_iterator: public std::iterator<std::forward_iterator_tag, T> {
+protected:
+ const BoolSet<T> *s_;
+ unsigned int pos_;
+
+protected:
+ const_iterator(const BoolSet<T> *s, unsigned int pos) { s_ = s; pos_ = pos; }
+
+public:
+ ~const_iterator() {}
+
+ typename BoolSet<T>::const_iterator &operator++();
+ typename BoolSet<T>::const_iterator operator++(int);
+ typename BoolSet<T>::const_iterator operator+(int) const;
+ unsigned int operator*() const;
+ bool operator==(const BoolSet<T>::const_iterator &) const;
+ bool operator!=(const BoolSet<T>::const_iterator &) const;
+
+ friend class BoolSet<T>;
+};
+
+
+template<typename T>
+typename BoolSet<T>::const_iterator &BoolSet<T>::const_iterator::operator++() {
+ assert(pos_ < s_->size_);
+
+ pos_++;
+ unsigned int n = pos_ / (sizeof(T)*8);
+ unsigned int r = pos_ % (sizeof(T)*8);
+ while (pos_ < s_->size_) {
+ if (s_->set_[n] == static_cast<T>(0)) {
+ pos_ += sizeof(T)*8-r;
+ n++;
+ r = 0;
+ if (pos_ >= s_->size_)
+ break;
+ }
+
+ if (r == 0) {
+ while (pos_ < s_->size_) {
+ if (s_->set_[n] == static_cast<T>(0)) {
+ pos_ += sizeof(T)*8;
+ n++;
+ }
+ else
+ break;
+ }
+ if (pos_ >= s_->size_)
+ break;
+ }
+
+ for (unsigned int i = r; i < sizeof(T)*8; i++)
+ if (s_->set_[n] & static_cast<T>(1) << i) {
+ pos_ = pos_+i-r;
+ return *this;
+ }
+
+ pos_ += sizeof(T)*8-r;
+ n++;
+ r = 0;
+ }
+
+ pos_ = s_->size_;
+ return *this;
+}
+
+
+template<typename T>
+typename BoolSet<T>::const_iterator BoolSet<T>::const_iterator::operator++(int) {
+ typename BoolSet<T>::const_iterator it(*this);
+ ++(*this);
+ return it;
+}
+
+
+template<typename T>
+typename BoolSet<T>::const_iterator BoolSet<T>::const_iterator::operator+(int n) const {
+ assert(n >= 0);
+ typename BoolSet<T>::const_iterator it(*this);
+ while (n > 0) {
+ ++it;
+ --n;
+ }
+ return it;
+}
+
+
+template<typename T>
+unsigned int BoolSet<T>::const_iterator::operator*() const {
+ assert(pos_ < s_->size_);
+ return pos_;
+}
+
+
+template<typename T>
+bool BoolSet<T>::const_iterator::operator==(const BoolSet<T>::const_iterator &other) const {
+ return s_ == other.s_ && pos_ == other.pos_;
+}
+
+
+template<typename T>
+bool BoolSet<T>::const_iterator::operator!=(const BoolSet<T>::const_iterator &other) const {
+ return !((*this) == other);
+}
+
+}
+
+#endif
diff --git a/omegalib/omega/include/basic/Collection.h b/omegalib/omega/include/basic/Collection.h
new file mode 100644
index 0000000..c7e4eef
--- /dev/null
+++ b/omegalib/omega/include/basic/Collection.h
@@ -0,0 +1,47 @@
+#if !defined Already_Included_Collection
+#define Already_Included_Collection
+
+namespace omega {
+
+template<class T> class Iterator;
+template<class T> class Any_Iterator;
+
+
+/*
+ * protocol for any kind of collection
+ */
+
+template<class T> class Collection {
+public:
+ virtual Iterator<T> *new_iterator() = 0;
+ virtual Any_Iterator<T> any_iterator() { return Any_Iterator<T>(new_iterator()); }
+
+ virtual int size() const = 0;
+};
+
+
+/*
+ * protocol for collections whose elements are ordered
+ * by the way they are entered into the collection, and
+ * whose elements can be accessed by "index"
+ *
+ * note that the implementation need not be a linked list
+ */
+
+template<class T> class Sequence : public Collection<T> {
+public:
+ virtual const T &operator[](int) const = 0;
+ virtual T &operator[](int) = 0;
+
+ virtual int index(const T &) const = 0; // Y in X --> X[X.index(Y)] == Y
+};
+
+} // namespace
+
+#define instantiate_Collection(T) template class Collection<T>; \
+ instantiate_Any_Iterator(T)
+#define instantiate_Sequence(T) template class Sequence<T>; \
+ instantiate_Collection(T)
+
+#endif
+
diff --git a/omegalib/omega/include/basic/Collections.h b/omegalib/omega/include/basic/Collections.h
new file mode 100644
index 0000000..1e68031
--- /dev/null
+++ b/omegalib/omega/include/basic/Collections.h
@@ -0,0 +1,12 @@
+#if !defined Already_Included_Collections
+#define Already_Included_Collections
+
+#include <stdio.h>
+#include <basic/Collection.h>
+#include <basic/Iterator.h>
+#include <basic/List.h>
+#include <basic/Bag.h>
+#include <basic/Map.h>
+
+#endif
+
diff --git a/omegalib/omega/include/basic/ConstString.h b/omegalib/omega/include/basic/ConstString.h
new file mode 100644
index 0000000..5149e55
--- /dev/null
+++ b/omegalib/omega/include/basic/ConstString.h
@@ -0,0 +1,58 @@
+#if ! defined _Const_String_h
+#define _Const_String_h 1
+
+#include <string>
+
+namespace omega {
+
+// should be inside Const_String, but I can't get it to
+// compile the hashTable when it is: hashTable can't be
+// global, but if it and its size are static to Const_String,
+// the compiler still doesn't seem to like the definition,
+// or the declaration either for that matter.
+
+class ConstStringRep {
+public:
+ const char *name;
+ int count;
+ ConstStringRep *nextInBucket;
+ ConstStringRep(const char *t);
+};
+
+class Const_String {
+private:
+ ConstStringRep *rep;
+ void buildRep(const char *t);
+
+public:
+ Const_String();
+ Const_String(const char* t);
+ Const_String(const std::string &s);
+ Const_String(const Const_String & t) {rep = t.rep;}
+
+ operator int() const;
+ int null() const;
+
+ operator const char*() const;
+ operator std::string() const;
+ int operator++(int);
+ int operator++();
+ int operator--(int);
+ int operator--();
+ friend int operator==(const Const_String &x, const Const_String &y);
+ friend int operator!=(const Const_String &x, const Const_String &y);
+ friend int operator<(const Const_String &x, const Const_String &y);
+ friend int operator >(const Const_String &x, const Const_String &y);
+
+};
+
+#if defined SCREWED_UP_CASTING_RULES
+static int operator==(const Const_String &x, const char *y)
+{ return x == (Const_String) y; }
+static int operator!=(const Const_String &x, const char *y)
+{ return x != (Const_String) y; }
+#endif
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/include/basic/Dynamic_Array.c b/omegalib/omega/include/basic/Dynamic_Array.c
new file mode 100644
index 0000000..0300fd8
--- /dev/null
+++ b/omegalib/omega/include/basic/Dynamic_Array.c
@@ -0,0 +1,219 @@
+#include <assert.h>
+#include <basic/Dynamic_Array.h>
+
+namespace omega {
+
+template<class T, int d> void Dynamic_Array<T,d>::do_constr()
+ {
+// #if ! defined SHUT_UP_ABOUT_STATEMENT_WITH_NO_EFFECT_IN_DYNAMIC_ARRAY_CREATION
+// assert(d > 0);
+// #endif
+ bounds = 0;
+ elements = 0;
+ partial = false;
+ }
+
+
+template<class T> void Dynamic_Array1<T>::do_construct(int d0)
+ {
+ this->bounds = new int[1];
+ this->bounds[0] = d0;
+ this->elements = new T [d0];
+ this->partial = false;
+ }
+
+template<class T> void Dynamic_Array2<T>::do_construct(int d0, int d1)
+ {
+ this->bounds = new int[2];
+ this->bounds[0] = d0;
+ this->bounds[1] = d1;
+ this->elements = new T [d0 * d1];
+ this->partial = false;
+ }
+
+template<class T> void Dynamic_Array3<T>::do_construct(int d0,int d1,int d2)
+ {
+ this->bounds = new int[3];
+ this->bounds[0] = d0;
+ this->bounds[1] = d1;
+ this->bounds[2] = d2;
+ this->elements = new T [d0 * d1 * d2];
+ this->partial = false;
+ }
+
+template<class T> void Dynamic_Array4<T>::do_construct(int d0,int d1,int d2,int d3)
+ {
+ this->bounds = new int[4];
+ this->bounds[0] = d0;
+ this->bounds[1] = d1;
+ this->bounds[2] = d2;
+ this->bounds[3] = d3;
+ this->elements = new T [d0 * d1 * d2 * d3];
+ this->partial = false;
+ }
+
+template<class T, int d> Dynamic_Array<T,d>::Dynamic_Array()
+ {
+ do_constr();
+ }
+
+template<class T> Dynamic_Array1<T>::Dynamic_Array1(const char *)
+ {
+ this->do_constr();
+ }
+
+template<class T> Dynamic_Array2<T>::Dynamic_Array2(const char *,const char *)
+ {
+ this->do_constr();
+ }
+
+template<class T> Dynamic_Array3<T>::Dynamic_Array3(const char *,const char *,const char *)
+ {
+ this->do_constr();
+ }
+
+template<class T> Dynamic_Array4<T>::Dynamic_Array4(const char *,const char *,const char *,const char *)
+ {
+ this->do_constr();
+ }
+
+template<class T> Dynamic_Array1<T>::Dynamic_Array1(int d0)
+ {
+ do_construct(d0);
+ }
+
+template<class T> Dynamic_Array2<T>::Dynamic_Array2(int d0, int d1)
+ {
+ do_construct(d0, d1);
+ }
+
+template<class T> Dynamic_Array3<T>::Dynamic_Array3(int d0,int d1,int d2)
+ {
+ do_construct(d0, d1, d2);
+ }
+
+template<class T> Dynamic_Array4<T>::Dynamic_Array4(int d0,int d1,int d2,int d3)
+ {
+ do_construct(d0, d1, d2, d3);
+ }
+
+
+template<class T, int d> void Dynamic_Array<T,d>::do_destruct()
+ {
+ if (! partial)
+ {
+ delete [] bounds;
+ delete [] elements;
+ }
+ }
+
+
+template<class T, int d> Dynamic_Array<T,d>::~Dynamic_Array()
+ {
+ do_destruct();
+ }
+
+
+template<class T> void Dynamic_Array1<T>::resize(int d0)
+ {
+ assert(!this->partial);
+ this->do_destruct();
+ if (d0 == 0)
+ this->do_constr();
+ else
+ do_construct(d0);
+ }
+
+template<class T> void Dynamic_Array2<T>::resize(int d0, int d1)
+ {
+ assert(!this->partial);
+ this->do_destruct();
+ if (d0 == 0 && d1 == 0)
+ this->do_constr();
+ else
+ do_construct(d0, d1);
+ }
+
+template<class T> void Dynamic_Array3<T>::resize(int d0, int d1, int d2)
+ {
+ assert(!this->partial);
+ this->do_destruct();
+ if (d0 == 0 && d1 == 0 && d2 == 0)
+ this->do_constr();
+ else
+ do_construct(d0, d1, d2);
+ }
+
+template<class T> void Dynamic_Array4<T>::resize(int d0, int d1, int d2, int d3)
+ {
+ assert(!this->partial);
+ this->do_destruct();
+ if (d0 == 0 && d1 == 0 && d2 == 0 && d3 == 0)
+ this->do_constr();
+ else
+ do_construct(d0, d1, d2, d3);
+ }
+
+
+template<class T> T& Dynamic_Array1<T>::operator[](int d0)
+ {
+#if !defined (NDEBUG)
+ assert(this->elements != 0 && "Trying to dereference undefined array");
+ assert(0 <= d0 && d0 < this->bounds[0] && "Array subscript out of bounds");
+#endif
+
+ return this->elements[d0];
+ }
+
+template<class T> Dynamic_Array1<T> Dynamic_Array2<T>::operator[](int d0)
+ {
+#if !defined (NDEBUG)
+ assert(this->elements != 0 && "Trying to dereference undefined array");
+ assert(0 <= d0 && d0 < this->bounds[0] && "Array subscript out of bounds");
+#endif
+
+ Dynamic_Array1<T> result;
+ result.bounds = this->bounds+1;
+ result.elements = this->elements + this->bounds[1] * d0;
+ result.partial = true;
+ return result;
+ }
+
+template<class T> Dynamic_Array2<T> Dynamic_Array3<T>::operator[](int d0)
+ {
+#if !defined (NDEBUG)
+ assert(this->elements != 0 && "Trying to dereference undefined array");
+ assert(0 <= d0 && d0 < this->bounds[0] && "Array subscript out of bounds");
+#endif
+ Dynamic_Array2<T> result;
+ result.bounds = this->bounds+1;
+ result.elements = this->elements + this->bounds[1] * this->bounds[2] * d0;
+ result.partial = true;
+ return result;
+ }
+
+template<class T> Dynamic_Array3<T> Dynamic_Array4<T>::operator[](int d0)
+ {
+#if !defined (NDEBUG)
+ assert(this->elements != 0 && "Trying to dereference undefined array");
+ assert(0 <= d0 && d0 < this->bounds[0] && "Array subscript out of bounds");
+#endif
+
+ Dynamic_Array3<T> result;
+ result.bounds = this->bounds+1;
+ result.elements = this->elements + this->bounds[1] * this->bounds[2] * this->bounds[3] * d0;
+ result.partial = true;
+ return result;
+ }
+
+
+template<class T, int d>
+ Dynamic_Array<T,d>::Dynamic_Array(Dynamic_Array<T,d> &D)
+ {
+ assert(D.elements != 0 && "Trying to copy an undefined array");
+ partial = true;
+ bounds = D.bounds;
+ elements = D.elements;
+ }
+
+} // namespace
diff --git a/omegalib/omega/include/basic/Dynamic_Array.h b/omegalib/omega/include/basic/Dynamic_Array.h
new file mode 100644
index 0000000..c0bdf12
--- /dev/null
+++ b/omegalib/omega/include/basic/Dynamic_Array.h
@@ -0,0 +1,103 @@
+#ifndef Already_Included_Dynamic_Array
+#define Already_Included_Dynamic_Array
+
+namespace omega {
+
+template <class T> class Dynamic_Array2;
+template <class T> class Dynamic_Array3;
+template <class T> class Dynamic_Array4;
+
+template <class T, int d> class Dynamic_Array
+ {
+ public:
+ Dynamic_Array(Dynamic_Array<T,d> &D);
+ ~Dynamic_Array();
+
+ protected:
+ Dynamic_Array();
+ bool partial;
+ int *bounds;
+ T *elements;
+
+ void do_constr();
+ void do_destruct();
+ };
+
+
+template <class T> class Dynamic_Array1 : public Dynamic_Array<T,1>
+ {
+ public:
+ Dynamic_Array1(const char *s0 = 0);
+ Dynamic_Array1(int d0);
+ void resize(int d0);
+ T& operator[](int d);
+
+ friend class Dynamic_Array2<T>;
+
+ private:
+ void do_construct(int d0);
+ };
+
+
+template <class T> class Dynamic_Array2 : public Dynamic_Array<T,2>
+ {
+ public:
+ Dynamic_Array2(const char *s0 = 0, const char *s1 = 0);
+ Dynamic_Array2(int d0, int d1);
+ void resize(int d0, int d1);
+ Dynamic_Array1<T> operator[](int d);
+
+ friend class Dynamic_Array3<T>;
+
+ private:
+ void do_construct(int d0, int d1);
+ };
+
+
+template <class T> class Dynamic_Array3 : public Dynamic_Array<T,3>
+ {
+ public:
+ Dynamic_Array3(const char *s0 = 0, const char *s1 = 0, const char *s2 = 0);
+ Dynamic_Array3(int d0, int d1, int d2);
+ void resize(int d0, int d1, int d2);
+ Dynamic_Array2<T> operator[](int d);
+
+ friend class Dynamic_Array4<T>;
+
+ private:
+ void do_construct(int d0, int d1, int d2);
+ };
+
+template <class T> class Dynamic_Array4 : public Dynamic_Array<T,4>
+ {
+ public:
+ Dynamic_Array4(const char *s0 = 0, const char *s1 = 0, const char *s2 = 0, const char *s3 = 0);
+ Dynamic_Array4(int d0, int d1, int d2, int d3);
+ void resize(int d0, int d1, int d2, int d3);
+ Dynamic_Array3<T> operator[](int d);
+
+ private:
+ void do_construct(int d0, int d1, int d2, int d3);
+ };
+
+} // namespace
+
+#if ! defined DONT_INCLUDE_TEMPLATE_CODE
+#include <basic/Dynamic_Array.c>
+#endif
+
+#define instantiate_Dynamic_Array1(T) template class Dynamic_Array1<T>; \
+ template class Dynamic_Array<T,1>;
+
+#define instantiate_Dynamic_Array2(T) template class Dynamic_Array2<T>; \
+ template class Dynamic_Array<T,2>; \
+ instantiate_Dynamic_Array1(T);
+
+#define instantiate_Dynamic_Array3(T) template class Dynamic_Array3<T>; \
+ template class Dynamic_Array<T,3>; \
+ instantiate_Dynamic_Array2(T);
+
+#define instantiate_Dynamic_Array4(T) template class Dynamic_Array4<T>; \
+ template class Dynamic_Array<T,4>; \
+ instantiate_Dynamic_Array3(T);
+#endif
diff --git a/omegalib/omega/include/basic/Iterator.h b/omegalib/omega/include/basic/Iterator.h
new file mode 100644
index 0000000..8975d9e
--- /dev/null
+++ b/omegalib/omega/include/basic/Iterator.h
@@ -0,0 +1,131 @@
+/*
+ * Base classes for iterators, generators
+ *
+ * These don't really work yet for constant collections.
+ * I'm not sure how to make that happen.
+ */
+
+#if ! defined _Iterator_h
+#define _Iterator_h 1
+
+#include <basic/Collection.h>
+
+namespace omega {
+
+#define foreach(x,T,S,A) do {for (omega::Any_Iterator<T> __P_##x = (S).any_iterator();__P_##x;__P_##x++) {T & x = *__P_##x; A;}} while (0)
+
+#define foreachSeparated(x,T,S,A,B) do {for (omega::Any_Iterator<T> __P_##x = (S).any_iterator();__P_##x;) {T & x = *__P_##x; A; __P_##x++; if (__P_##x) B;}} while (0)
+
+/*
+ * Abstract base class Iterator<type>
+ * Supports two styles of iteration:
+ *
+ * for ( ... initialize i (typically i = collection) ... ; i ; i++ )
+ * operate_on(*i)
+ *
+ * or
+ *
+ * for ( ... initialize i ... ; i.live() ; i.next() )
+ * operate_on(i.curr())
+ *
+ * >>> IF THE COLLECTION IS CHANGED, THE ITERATOR IS NO LONGER VALID <<<
+ *
+ * For collections that are not "Sequence"s, the order in
+ * which the elements are returned may not be consistent.
+ */
+
+template<class T> class Iterator {
+public:
+ virtual const T & operator*() const = 0;
+ virtual T & operator*() = 0;
+
+ virtual void operator++(int) = 0;
+ virtual void operator++() = 0;
+
+ virtual bool live() const = 0;
+ operator bool() const { return live(); }
+
+ const T & curr() const { return *(*this); }
+ T & curr() { return *(*this); }
+ void next() { (*this)++; }
+
+ virtual Iterator<T> *new_copy() const = 0;
+ virtual ~Iterator() {}
+};
+
+
+// A generator is like an iterator but it gives out values,
+// which may or may not exist in some writable collection
+
+template<class T> class Generator {
+public:
+ virtual T operator*() const = 0;
+
+ virtual void operator++(int) = 0;
+ virtual void operator++() = 0;
+
+ virtual int live() const = 0;
+ operator int() const { return live(); }
+
+ const T curr() const { return *(*this); }
+ T curr() { return *(*this); }
+ void next() { (*this)++; }
+};
+
+
+
+// Delegate to any kind of iterator (on the heap)
+// If created via a reference, become a copy of the iterator
+// If created via a pointer, manipulate that pointer and free *p when this dies
+//
+// Mostly useful for Collection::iterator
+// Iterator::Iterator(Collection)
+
+
+template<class T> class Any_Iterator : public Iterator<T> {
+public:
+ Any_Iterator(Collection<T> &c);
+ Any_Iterator(const Iterator<T> &i); // copy of i
+
+ virtual ~Any_Iterator() { delete me; }
+
+ Any_Iterator<T> &operator=(const Any_Iterator<T> &rhs)
+ { delete me; me = rhs.me->new_copy(); return *this; }
+
+ const T & operator*() const { return *(*me); }
+ T & operator*() { return *(*me); }
+ void operator++(int) { (*me)++; }
+ void operator++() { ++(*me); }
+ bool live() const { return (*me).live(); }
+
+ Iterator<T> *new_copy() const { return new Any_Iterator<T>((*me).new_copy()); }
+
+private:
+ Any_Iterator(Iterator<T> *p) // take over *p, *p MUST BE ON THE HEAP
+ { me = p; }
+ friend class Collection<T>;
+#if 0
+ // Couldn't make this work with g++258
+ friend Any_Iterator<T> Collection<T>::any_iterator();
+#endif
+ Iterator<T> *me;
+};
+
+template <class T> inline Any_Iterator<T>::Any_Iterator(Collection<T> &c)
+ {
+ me = c.new_iterator();
+ }
+
+template <class T> inline Any_Iterator<T>::Any_Iterator(const Iterator<T> &i)
+ {
+ me = i.new_copy();
+ }
+
+} // namespace
+
+#define instantiate_Iterator(T) template class Iterator<T>;
+#define instantiate_Generator(T) template class Generator<T>;
+#define instantiate_Any_Iterator(T) template class Any_Iterator<T>; \
+ instantiate_Iterator(T)
+
+#endif
diff --git a/omegalib/omega/include/basic/Link.h b/omegalib/omega/include/basic/Link.h
new file mode 100644
index 0000000..ede7a2b
--- /dev/null
+++ b/omegalib/omega/include/basic/Link.h
@@ -0,0 +1,98 @@
+#if ! defined _Link_h
+#define _Link_h 1
+
+#include <basic/Iterator.h>
+#include <stddef.h>
+
+namespace omega {
+
+// By default, if ndebug is not set, do not do free list
+
+#if ! defined ListElementFreeList
+#if ! defined NDEBUG || defined ASSERTIONS_ANYWAY
+#define ListElementFreeList 0
+#else
+#define ListElementFreeList 1
+#endif
+#endif
+
+/*
+ List_Element: one item in a list and the pointer to the next.
+ Each such object should be pointed to by either exactly one
+ other List_Element or by some other pointer(s), exactly one
+ of which will delete the List_Element.
+ ListElements should ONLY be allocated on the heap.
+ */
+
+#if ListElementFreeList
+ // g++ 2.5.8 does not allow static data in template classes, so...
+ extern void *kludgy_List_Element_new(size_t size);
+ extern void kludgy_List_Element_delete(void *ptr, size_t size);
+#endif
+
+template <class T> class List_Element {
+public:
+#if ListElementFreeList
+ void *operator new(size_t size)
+ {
+ return kludgy_List_Element_new(size);
+ }
+ void operator delete(void *ptr, size_t size)
+ {
+ kludgy_List_Element_delete(ptr, size);
+ }
+#endif
+
+ T head;
+ List_Element<T> *tail;
+
+ List_Element() {
+ tail = 0;
+ }
+ List_Element(T h, List_Element<T> * t) {
+ head = h;
+ tail = t;
+ }
+ List_Element(const List_Element<T> & L) {
+ head = L.head;
+ if (L.tail) tail = new List_Element<T>(*L.tail);
+ else tail = 0;
+ }
+ List_Element & operator=(const List_Element<T> &L) {
+ if (this != &L) {
+ head = L.head;
+ if (tail) delete tail;
+ if (L.tail) tail = new List_Element<T>(*L.tail);
+ else tail = 0;
+ }
+ return *this;
+ }
+ virtual ~List_Element() { // virtual ensures 2nd arg of delete is right
+ delete tail;
+ }
+};
+
+
+
+template<class T> class List_Element_Iterator : public Iterator<T> {
+public:
+ List_Element_Iterator(List_Element<T>* j) { i = j; }
+ virtual const T & operator*() const { return i->head; }
+ virtual T & operator*() { return i->head; }
+ virtual void operator++(int) { i = i->tail; }
+ virtual void operator++() { i = i->tail; }
+ virtual bool live() const { return i != 0; }
+ Iterator<T> * new_copy() const { return new List_Element_Iterator<T>(i);}
+
+protected:
+ List_Element<T> *i;
+};
+
+} // namespace
+
+#define instantiate_Only_List_Element(T) template class List_Element<T>; \
+ template class List_Element_Iterator<T>;
+#define instantiate_List_Element(T) instantiate_Only_List_Element(T)\
+ instantiate_Collection(T)
+
+#endif
diff --git a/omegalib/omega/include/basic/List.c b/omegalib/omega/include/basic/List.c
new file mode 100644
index 0000000..f05e0de
--- /dev/null
+++ b/omegalib/omega/include/basic/List.c
@@ -0,0 +1,149 @@
+#include <assert.h>
+
+namespace omega {
+
+template<class T> List_Iterator<T>::List_Iterator(List<T> &l)
+: List_Element_Iterator<T>(l.contents) {}
+
+template<class T> List_Iterator<T>::List_Iterator(const List<T> &l)
+: List_Element_Iterator<T>(l.contents) {}
+
+template<class T> List_Iterator<T>::List_Iterator()
+: List_Element_Iterator<T>(0) {}
+
+template<class T> Iterator<T> *List<T>::new_iterator()
+{
+ return new List_Iterator<T>(*this);
+}
+
+template<class T> const T &List<T>::operator[](int i) const
+{
+ assert(i > 0 && "Subscript out of bounds");
+ List_Iterator<T> p(*this);
+
+ while(--i > 0 && p)
+ p++;
+
+ if (p)
+ return *p;
+ else
+ return *((T *)0);
+}
+
+template<class T> T &List<T>::operator[](int i)
+{
+ assert(i > 0 && "Subscript out of bounds");
+ List_Iterator<T> p(*this);
+
+ while(--i > 0 && p)
+ p++;
+
+ if (p)
+ return *p;
+ else
+ return *((T *)0);
+}
+
+template<class T> int List<T>::index(const T &item) const
+{
+ List_Iterator<T> p(*this);
+ int i = 1;
+
+ while(p && *p != item)
+ {
+ p++;
+ i++;
+ }
+
+ if (p)
+ return i;
+ else
+ return 0;
+}
+
+template<class T> int List<T>::size() const
+ {
+ int i = 0;
+ List_Element<T> * p = contents;
+ while (p)
+ {
+ p = p->tail;
+ i++;
+ }
+ return i;
+ }
+
+template<class T> T &List<T>::front() const
+ {
+ return contents->head;
+ }
+
+template<class T> T List<T>::remove_front()
+ {
+ List_Element<T> *frunt = contents;
+ contents = contents->tail;
+ T fruntT = frunt->head;
+ frunt->tail = 0;
+ delete frunt;
+ return fruntT;
+ }
+
+template<class T> void List<T>::prepend(const T &item)
+ {
+ contents = new List_Element<T>(item, contents);
+ }
+
+
+template<class T> void List<T>::append(const T &item)
+ {
+ *(end()) = new List_Element<T>(item, 0);
+ }
+
+template<class T> void List<T>::ins_after(List_Iterator<T> i,
+ const T &item)
+ {
+#if ! defined NDEBUG
+ for (List_Element<T> *e = contents; e != &(i.element()); e=e->tail)
+ {
+ assert(e);
+ }
+#endif
+ i.element().tail = new List_Element<T>(item, i.element().tail);
+ }
+
+template<class T> void List<T>::del_front()
+ {
+ List_Element<T> *e = contents;
+ contents = contents->tail;
+ e->tail = 0;
+ delete e;
+ }
+
+template<class T> void List<T>::del_after(List_Iterator<T> i)
+ {
+#if ! defined NDEBUG
+ for (List_Element<T> *e0 = contents; e0 != &(i.element()); e0=e0->tail)
+ {
+ assert(e0);
+ }
+#endif
+ List_Element<T> *e = i.element().tail;
+ i.element().tail = e->tail;
+ e->tail = 0;
+ delete e;
+ }
+
+template<class T> void List<T>::clear()
+ {
+ delete contents;
+ contents = 0;
+ }
+
+template<class T> void List<T>::join(List<T> &consumed)
+ {
+ List_Element<T> *e = consumed.contents;
+ consumed.contents = 0;
+ *(end()) = e;
+ }
+
+} // namespace
diff --git a/omegalib/omega/include/basic/List.h b/omegalib/omega/include/basic/List.h
new file mode 100644
index 0000000..c6fc062
--- /dev/null
+++ b/omegalib/omega/include/basic/List.h
@@ -0,0 +1,95 @@
+#if ! defined _List_h
+#define _List_h 1
+
+/*
+ * Linked lists with an interface like a bit of libg++'s SLList class
+ */
+
+
+#if 0
+#include <basic/assert.h> /* List requires assert which needs Exit which */
+#endif /* needs List! just include assert in List.c */
+#include <stdio.h> // for NULL
+#include <basic/Iterator.h>
+#include <basic/Collection.h>
+#include <basic/Link.h>
+
+namespace omega {
+
+template<class T> class List_Iterator;
+
+//
+// indexing of Lists starts at 1, index == 0 means not there
+//
+
+template<class T> class List : public Sequence<T> {
+public:
+ List(const List<T> &l)
+ { contents = l.contents ? new List_Element<T>(*l.contents) : 0; }
+ List() { contents = 0; }
+ virtual ~List() { delete contents; }
+
+ Iterator<T> *new_iterator();
+ const T &operator[](int) const;
+ T &operator[](int);
+
+ int index(const T &) const;
+
+ int size() const;
+ int length() const { return size(); }
+ bool empty() const { return size() == 0; }
+
+ T &front() const;
+
+// insertion/deletion on a list invalidates any iterators
+// that are on/after the element added/removed
+
+ T remove_front();
+
+ void prepend(const T &item);
+ void append(const T &item);
+ void ins_after(List_Iterator<T> i, const T &item);
+
+ void del_front();
+ void del_after(List_Iterator<T> i);
+ void clear();
+
+ void join(List<T> &consumed);
+
+private:
+ friend class List_Iterator<T>;
+ List_Element<T> **end()
+ {
+ List_Element<T> **e = &contents;
+ while (*e)
+ e = &((*e)->tail);
+ return e;
+ }
+
+ List_Element<T> *contents;
+};
+
+
+template<class T> class List_Iterator : public List_Element_Iterator<T> {
+public:
+ List_Iterator(List<T> &l);
+ List_Iterator(const List<T> &l);
+ List_Iterator();
+private:
+ List_Element<T> &element() { return *List_Element_Iterator<T>::i; } ;
+ friend class List<T>;
+};
+
+} // namespace
+
+#if ! defined DONT_INCLUDE_TEMPLATE_CODE
+#include <basic/List.c>
+#endif
+
+#define instantiate_List(T) template class List<T>; \
+ template class List_Iterator<T>; \
+ instantiate_Only_List_Element(T) \
+ instantiate_Sequence(T)
+
+
+#endif
diff --git a/omegalib/omega/include/basic/Map.c b/omegalib/omega/include/basic/Map.c
new file mode 100644
index 0000000..69cc3f7
--- /dev/null
+++ b/omegalib/omega/include/basic/Map.c
@@ -0,0 +1,63 @@
+namespace omega {
+
+template<class K, class V> MapElement<K,V>:: MapElement(const MapElement<K,V>& M) {
+ if (M.tail) tail = new MapElement<K,V>(*M.tail);
+ else tail = 0;
+ k = M.k;
+ v = M.v;
+ }
+
+template<class K, class V> MapElement<K,V> &
+ MapElement<K,V>:: operator=(const MapElement<K,V>& M) {
+ if (this != &M) {
+ if (tail) delete tail;
+ if (M.tail) tail = new MapElement<K,V>(*M.tail);
+ else tail = 0;
+ k = M.k;
+ v = M.v;
+ }
+ return *this;
+ }
+
+
+
+
+#if ! defined linux
+template <class K, class V> Map <K,V>::Map(const V &default_value)
+#else
+template <class K, class V> Map <K,V>::Map(V default_value)
+#endif
+ : _default_value(default_value)
+ {
+ contents = 0;
+ }
+
+template <class K, class V> Map <K,V>::~Map()
+ {
+ delete contents;
+ }
+
+template <class K, class V> V Map<K,V>::operator()(K k) const {
+ MapElement <K,V> * P = contents;
+ while (P) {
+ if (P->k == k) return P->v;
+ P = P->tail;
+ };
+ return _default_value;
+ }
+
+template <class K, class V> V & Map<K,V>::operator[](K k) {
+ MapElement <K,V> * P = contents;
+ while (P) {
+ if (P->k == k) return P->v;
+ P = P->tail;
+ };
+ P = new MapElement <K,V>;
+ P->k = k;
+ P->v = _default_value;
+ P->tail = contents;
+ contents = P;
+ return P->v;
+ }
+
+} // namespace
diff --git a/omegalib/omega/include/basic/Map.h b/omegalib/omega/include/basic/Map.h
new file mode 100644
index 0000000..f94a10c
--- /dev/null
+++ b/omegalib/omega/include/basic/Map.h
@@ -0,0 +1,68 @@
+#if ! defined _Map_h
+#define _Map_h 1
+
+#include <basic/Link.h>
+#include <stdio.h> // for NULL
+
+namespace omega {
+
+#define foreach_map(k,K,v,V,M,A) {for (omega::MapElementIterator<K,V> __M_##k = (M).iterator();__M_##k;__M_##k++) {K & k = *__M_##k; V & v = __M_##k.value(); A;}}
+
+template <class K, class V> class MapElement {
+public:
+ K k;
+ V v;
+ MapElement<K,V> *tail;
+ MapElement(const MapElement<K,V>&);
+ MapElement() {}
+ MapElement & operator=(const MapElement<K,V>&);
+ ~MapElement() { delete tail; }
+};
+
+template<class K, class V> class MapElementIterator {
+public:
+ MapElementIterator(MapElement<K,V>* j) { i = j;}
+ virtual const K & operator*() const { return i->k; }
+ virtual K & operator*() { return i->k;}
+ virtual const V & value() const { return i->v; }
+ virtual V & value() { return i->v; }
+ virtual void operator++(int) { i = i->tail; }
+ virtual void operator++() { i = i->tail; }
+ virtual bool live() const { return i != NULL; }
+ operator bool() const { return live(); }
+protected:
+MapElement<K,V> *i;
+};
+
+template <class K, class V> class Map {
+public:
+#if ! defined linux
+ Map(const V &default_value);
+#else
+ // work around for '386 g++ on Linux
+ Map(V default_value);
+#endif
+ ~Map();
+ MapElementIterator<K,V> iterator()
+ {return MapElementIterator<K,V>(contents);}
+ int empty() const {return contents == NULL;}
+ V operator()(K) const;
+ V& operator[](K);
+private:
+ MapElement<K,V> * contents;
+ V _default_value;
+};
+
+} // namespace
+
+#if ! defined DONT_INCLUDE_TEMPLATE_CODE
+#include <basic/Map.c>
+#endif
+
+#define instantiate_Map(T1,T2) template class Map<T1,T2>; \
+ template class MapElement<T1,T2>; \
+ template class MapElementIterator<T1,T2>;
+#define instantiate_MapElement(T1,T2) instantiate_Map(T1,T2)
+#define instantiate_MapElementIterator(T1,T2) instantiate_Map(T1,T2)
+
+#endif
diff --git a/omegalib/omega/include/basic/Section.c b/omegalib/omega/include/basic/Section.c
new file mode 100644
index 0000000..754e002
--- /dev/null
+++ b/omegalib/omega/include/basic/Section.c
@@ -0,0 +1,79 @@
+#include <assert.h>
+
+namespace omega {
+
+template <class T> Section<T>::Section(Sequence<T> *s, int start, int length)
+ {
+ assert(s->size() >= start-1 + length);
+ it = s;
+ _start = start;
+ _length = length;
+ }
+
+template <class T> Iterator<T> *Section<T>::new_iterator()
+ {
+ return new Section_Iterator<T>(*this);
+ }
+
+template <class T> const T &Section<T>::operator[](int i) const
+ {
+ assert(1 <= i && i <= size());
+ return (*it)[i+(_start-1)];
+ }
+
+template <class T> T &Section<T>::operator[](int i)
+ {
+ assert(1 <= i && i <= size());
+ return (*it)[i+(_start-1)];
+ }
+
+template <class T> int Section<T>::index(const T &var) const
+ {
+ int i;
+ for (i=1; i<=size(); i++)
+ if ((*this)[i] == var)
+ return i;
+ return 0;
+ }
+
+template <class T> int Section<T>::size() const
+ {
+ return _length;
+ }
+
+
+template <class T> Section_Iterator<T>::Section_Iterator(Section<T> &sec)
+ {
+ it = sec.it->new_iterator();
+ for (int i = 1; i < sec._start; i++)
+ (*it)++;
+ remaining = sec.size();
+ }
+
+
+template <class T> Section_Iterator<T>::Section_Iterator(const Section_Iterator<T> &si) : it(si.it), remaining(si.remaining) {}
+
+
+template <class T> void Section_Iterator<T>::operator++()
+ { this->operator++(0); }
+
+template <class T> void Section_Iterator<T>::operator++(int)
+ {
+ if (remaining > 0)
+ {
+ (*it)++;
+ remaining--;
+ }
+ }
+
+template <class T> bool Section_Iterator<T>::live() const
+ {
+ return (remaining > 0);
+ }
+
+template <class T> Iterator<T> *Section_Iterator<T>::new_copy() const
+ {
+ return new Section_Iterator<T>(*this);
+ }
+
+} // namespace
diff --git a/omegalib/omega/include/basic/Section.h b/omegalib/omega/include/basic/Section.h
new file mode 100644
index 0000000..60821d1
--- /dev/null
+++ b/omegalib/omega/include/basic/Section.h
@@ -0,0 +1,63 @@
+#if ! defined _Section_h
+#define _Section_h 1
+/*
+ Section of an existing collection viewed as a collection
+ */
+
+#include <basic/Collection.h>
+
+namespace omega {
+
+template<class T> class Section_Iterator;
+
+template <class T> class Section : public Sequence<T> {
+public:
+ Section(Sequence<T> *, int start, int length);
+
+ Iterator<T> *new_iterator();
+
+ const T &operator[](int) const;
+ T &operator[](int);
+
+ int index(const T &) const;
+ int size() const;
+
+ friend class Section_Iterator<T>;
+
+private:
+ Sequence<T> *it;
+ int _start, _length;
+};
+
+template <class T> class Section_Iterator : public Iterator<T> {
+public:
+ Section_Iterator(Section<T> &sec);
+ virtual ~Section_Iterator() { delete it; }
+
+ const T & operator*() const { return *(*it); }
+ T & operator*() { return *(*it); }
+
+ void operator++(int);
+ void operator++();
+
+ bool live() const;
+ Iterator<T> *new_copy() const;
+
+private:
+ Section_Iterator(const Section_Iterator<T> &si);
+ Iterator<T> *it;
+ int remaining;
+};
+
+} // namespace
+
+#if ! defined DONT_INCLUDE_TEMPLATE_CODE
+#include <basic/Section.c>
+#endif
+
+#define instantiate_Section(T) template class Section<T>; \
+ template class Section_Iterator<T>; \
+ instantiate_Sequence(T)
+#define instantiate_Section_Iterator(T) instantiate_Section(T)
+
+#endif
diff --git a/omegalib/omega/include/basic/SimpleList.c b/omegalib/omega/include/basic/SimpleList.c
new file mode 100644
index 0000000..da7de9b
--- /dev/null
+++ b/omegalib/omega/include/basic/SimpleList.c
@@ -0,0 +1,105 @@
+namespace omega {
+
+template<class T> Simple_List_Iterator<T>::Simple_List_Iterator(Simple_List<T> &l)
+: List_Element_Iterator<T>(l.contents) {}
+
+template<class T> Simple_List_Iterator<T>::Simple_List_Iterator(const Simple_List<T> &l)
+: List_Element_Iterator<T>(l.contents) {}
+
+template<class T> Simple_List_Iterator<T>::Simple_List_Iterator()
+: List_Element_Iterator<T>(0) {}
+
+template<class T> Iterator<T> *Simple_List<T>::new_iterator()
+{
+ return new Simple_List_Iterator<T>(*this);
+}
+
+template<class T> const T &Simple_List<T>::operator[](int i) const
+{
+ Simple_List_Iterator<T> p(*this);
+
+ while(--i > 0 && p)
+ p++;
+
+ if (p)
+ return *p;
+ else
+ return *((T *)0);
+}
+
+template<class T> T &Simple_List<T>::operator[](int i)
+{
+ Simple_List_Iterator<T> p(*this);
+
+ while(--i > 0 && p)
+ p++;
+
+ if (p)
+ return *p;
+ else
+ return *((T *)0);
+}
+
+
+template<class T> int Simple_List<T>::size() const
+ {
+ int i = 0;
+ List_Element<T> * p = contents;
+ while (p)
+ {
+ p = p->tail;
+ i++;
+ }
+ return i;
+ }
+
+template<class T> T &Simple_List<T>::front() const
+ {
+ return contents->head;
+ }
+
+template<class T> T Simple_List<T>::remove_front()
+ {
+ List_Element<T> *frunt = contents;
+ contents = contents->tail;
+ T fruntT = frunt->head;
+ frunt->tail = 0;
+ delete frunt;
+ return fruntT;
+ }
+
+template<class T> void Simple_List<T>::prepend(const T &item)
+ {
+ contents = new List_Element<T>(item, contents);
+ }
+
+
+template<class T> void Simple_List<T>::append(const T &item)
+ {
+ *(end()) = new List_Element<T>(item, 0);
+ }
+
+
+template<class T> void Simple_List<T>::del_front()
+ {
+ List_Element<T> *e = contents;
+ contents = contents->tail;
+ e->tail = 0;
+ delete e;
+ }
+
+
+template<class T> void Simple_List<T>::clear()
+ {
+ delete contents;
+ contents = 0;
+ }
+
+template<class T> void Simple_List<T>::join(Simple_List<T> &consumed)
+ {
+ List_Element<T> *e = consumed.contents;
+ consumed.contents = 0;
+ *(end()) = e;
+ }
+
+} // namespace
diff --git a/omegalib/omega/include/basic/SimpleList.h b/omegalib/omega/include/basic/SimpleList.h
new file mode 100644
index 0000000..a08b307
--- /dev/null
+++ b/omegalib/omega/include/basic/SimpleList.h
@@ -0,0 +1,93 @@
+#if ! defined _Simple_List_h
+#define _Simple_List_h 1
+
+/*
+ * Linked lists with an interface like a bit of libg++'s SLSimple_List class
+ */
+
+#include <assert.h>
+#include <basic/Iterator.h>
+#include <basic/Collection.h>
+#include <basic/Link.h>
+
+namespace omega {
+
+#define Simple_List Omega_Simple_List
+#define Simple_List_Iterator Omega_Simple_List_Iterator
+
+template<class T> class Simple_List_Iterator;
+
+// A TEMPORARY HACK - ERROR IF YOU TRY TO USE "INDEX" - FERD
+
+template<class T> class Simple_List : public Sequence<T> {
+public:
+ Simple_List(const Simple_List<T> &l)
+ { contents = l.contents ? new List_Element<T>(*l.contents) : 0; }
+ Simple_List() { contents = 0; }
+ virtual ~Simple_List() { delete contents; }
+
+ Iterator<T> *new_iterator();
+ const T &operator[](int) const;
+ T &operator[](int);
+
+
+ int size() const;
+ int length() const { return size(); }
+ int empty() const { return size() == 0; }
+
+ T &front() const;
+
+// insertion/deletion on a list invalidates any iterators
+// that are on/after the element added/removed
+
+ T remove_front();
+
+ void prepend(const T &item);
+ void append(const T &item);
+
+ void del_front();
+ void clear();
+
+ void join(Simple_List<T> &consumed);
+
+ int index(const T &) const {
+ assert(0&&"ILLEGAL SimpleList operation\n");
+ return -1;
+ }
+
+private:
+ friend class Simple_List_Iterator<T>;
+ List_Element<T> **end()
+ {
+ List_Element<T> **e = &contents;
+ while (*e)
+ e = &((*e)->tail);
+ return e;
+ }
+
+ List_Element<T> *contents;
+};
+
+
+template<class T> class Simple_List_Iterator : public List_Element_Iterator<T> {
+public:
+ Simple_List_Iterator(Simple_List<T> &l);
+ Simple_List_Iterator(const Simple_List<T> &l);
+ Simple_List_Iterator();
+private:
+ List_Element<T> &element() { return *this->i; } ;
+ friend class Simple_List<T>;
+};
+
+} // namespace
+
+#if ! defined DONT_INCLUDE_TEMPLATE_CODE
+#include <basic/SimpleList.c>
+#endif
+
+#define instantiate_Simple_List(T) template class Simple_List<T>; \
+ template class Simple_List_Iterator<T>; \
+ instantiate_Only_List_Element(T) \
+ instantiate_Sequence(T)
+
+#endif
diff --git a/omegalib/omega/include/basic/Tuple.c b/omegalib/omega/include/basic/Tuple.c
new file mode 100644
index 0000000..ce99e82
--- /dev/null
+++ b/omegalib/omega/include/basic/Tuple.c
@@ -0,0 +1,254 @@
+/* class Tuple */
+
+// THESE FIRST TWO REALLY SHOULD BE INLINE BUT IT BREAKS CFRONT:
+
+namespace omega {
+
+template<class T> T &Tuple<T>::operator[](int index)
+ {
+ assert(1 <= index && index <= sz); return data[index-1];
+ }
+
+template<class T> const T &Tuple<T>::operator[](int index) const
+ {
+ assert(1 <= index && index <= sz); return data[index-1];
+ }
+
+
+template<class T> Tuple<T>::~Tuple()
+ {
+ if (data)
+ delete [] data;
+ }
+
+template<class T> Tuple<T>::Tuple() : sz(0), alloc_sz(0),
+ prealloc_min(20),prealloc_pad(5), data(0)
+{
+ // nothing needs be done
+ }
+
+template<class T> Tuple<T>::Tuple(int size) : sz(size),
+ prealloc_min(20),prealloc_pad(5)
+{
+ if (sz > 0)
+ {
+ alloc_sz = prealloc_size(sz);
+ data = new T[alloc_sz];
+ assert(alloc_sz >= sz);
+ //Need some handling for out of memory.
+ assert (data!=0);
+ }
+ else {
+ alloc_sz = 0;
+ data = 0;
+ }
+}
+
+
+template<class T> Tuple<T>::Tuple(const Tuple<T>& t)
+ : sz(t.sz), alloc_sz(t.alloc_sz), prealloc_min(20),prealloc_pad(5)
+{
+ if (sz > 0) {
+ data = new T[alloc_sz];
+ assert (data!=0);
+ assert (alloc_sz >= sz);
+ for (int i=0; i<sz; i++)
+ data[i] = t.data[i];
+ } else {
+ data = 0;
+ alloc_sz = 0; // THis might not be 0 if it was a "clear"ed Tuple
+// assert(alloc_sz == 0);
+ }
+}
+
+
+template<class T> Tuple<T>& Tuple<T>::operator=(const Tuple<T>& t)
+{
+ if (this != &t) { // Delete this
+ if (data)
+ delete [] data;
+ sz = t.sz;
+ alloc_sz = t.alloc_sz;
+ assert(alloc_sz >= sz);
+ if (sz > 0) { // Copy old
+ data = new T[alloc_sz];
+ assert (data!=0);
+ for (int i=0; i<sz; i++)
+ data[i] = t.data[i];
+ } else {
+ data=0;
+ alloc_sz = 0; // THis might not be 0 if it was a "clear"ed Tuple
+// assert(alloc_sz == 0);
+ }
+ }
+ return *this;
+}
+
+
+template<class T> void Tuple<T>::reallocate(const int req_size)
+{
+ if (alloc_sz >= req_size) { // if (sz >= req_size), does this.
+ sz = req_size;
+ return;
+ }
+ alloc_sz = prealloc_size(req_size);
+ T* tmp_data = new T[alloc_sz];
+ for(int i=0;i<sz;i++)
+ tmp_data[i] = data[i];
+ delete [] data;
+ data = tmp_data;
+ sz = req_size;
+ assert(alloc_sz >= req_size);
+}
+
+template<class T> void Tuple<T>::delete_last()
+{
+assert(sz > 0);
+sz --;
+}
+
+template<class T> void Tuple<T>::append(const T &v)
+{
+ // Check if reallocation is necessary.
+ if (sz == 0) { // Empty Tuple
+ assert(alloc_sz >= 0); // May be nonzero for cleared tuple
+
+ if(alloc_sz == 0) { // If it's > 1 no allocation is necessary
+ alloc_sz = prealloc_size(1);
+ data = new T[alloc_sz];
+ }
+ assert (alloc_sz > 0 && data != 0);
+ } else {
+ if(sz == alloc_sz) { // Requires new allocation
+ alloc_sz = realloc_size(alloc_sz);
+ T * data_tmp = new T[alloc_sz];
+ assert (data_tmp!=0);
+ assert (alloc_sz > sz);
+ for (int i=0; i<sz; i++)
+ data_tmp[i] = data[i];
+ delete [] data;
+ data=data_tmp;
+ } // Otherwise big enough, no reallocation necessary
+ }
+ // Make assignment
+ assert(alloc_sz >= sz);
+ data[sz++] = v;
+}
+
+template<class T> void Tuple<T>::append(const Tuple<T>& t) {
+ int old_sz = sz;
+ reallocate(t.size()+size());
+ assert(alloc_sz >= sz);
+ for(int i=0; i<t.sz; i++)
+ data[i+old_sz] = t.data[i];
+}
+
+template<class T> void Tuple<T>::join(Tuple<T>& t) {
+ int old_sz = sz;
+ reallocate(t.size()+size());
+ assert(alloc_sz >= sz);
+ for(int i=0; i<t.sz; i++)
+ data[i+old_sz] = t.data[i];
+ t.clear();
+}
+
+template<class T> void Tuple<T>::clear() { if (sz) delete [] data; data = 0; alloc_sz = 0; sz = 0; }
+
+template<class T> int Tuple<T>::empty() const { return (sz == 0); }
+
+template<class T> Iterator<T> *Tuple<T>::new_iterator()
+{
+ return new Tuple_Iterator<T>(*this);
+}
+
+template<class T> int Tuple<T>::index(const T & var) const
+/* returns index or 0 if var isn't in the tuple */
+{
+ int i;
+ for (i=0; i<sz; i++)
+ if (data[i]== var)
+ return i+1;
+ return 0;
+}
+
+template<class T> bool Tuple<T>::operator == (const Tuple<T>& b) const
+{
+ int i;
+ if (sz != b.size()) return false;
+ for (i=0; i<sz; i++)
+ if (!(data[i] == b[i+1])) return false;
+ return true;
+}
+
+/* class Tuple_Iterator */
+
+template<class T> Tuple_Iterator<T>::Tuple_Iterator(const Tuple<T> &tpl) :
+current(tpl.data), lastptr(tpl.data+tpl.sz-1), firstptr(tpl.data), sz(tpl.sz)
+{
+}
+
+template<class T> Tuple_Iterator<T>::Tuple_Iterator(T * cr, T *frst, T * lst,
+ int insz)
+ : current(cr), lastptr(lst), firstptr(frst), sz(insz)
+{
+}
+
+template<class T> const T & Tuple_Iterator<T>::operator*() const
+{
+ assert (current<=lastptr && current>=firstptr);
+ return *current;
+}
+
+template<class T> T & Tuple_Iterator<T>::operator*()
+{
+ assert (current<=lastptr && current >=firstptr);
+ return *current;
+}
+
+template<class T> void Tuple_Iterator<T>::operator++(int)
+{
+ current++;
+}
+
+template<class T> void Tuple_Iterator<T>::operator++()
+{
+ current++;
+}
+
+template<class T> void Tuple_Iterator<T>::operator--(int)
+{
+ current--;
+}
+
+template<class T> void Tuple_Iterator<T>::operator--()
+{
+ current--;
+}
+
+template<class T> void Tuple_Iterator<T>::set_to_last()
+{
+ current = lastptr;
+}
+
+template<class T> void Tuple_Iterator<T>::set_to_first()
+{
+ current = firstptr;
+}
+
+template<class T> void Tuple_Iterator<T>::set_position(const int req_pos)
+{
+ assert(req_pos <= sz && 1 <= req_pos);
+ current = firstptr + (req_pos - 1);
+}
+
+
+template<class T> bool Tuple_Iterator<T>::live() const
+{
+ return (current !=0 && current<=lastptr && current >= firstptr);
+}
+
+template<class T> Iterator<T> *Tuple_Iterator<T>::new_copy() const {
+ return new Tuple_Iterator<T>(current, firstptr, lastptr, sz);
+}
+
+} // namespace
diff --git a/omegalib/omega/include/basic/Tuple.h b/omegalib/omega/include/basic/Tuple.h
new file mode 100644
index 0000000..28e83bd
--- /dev/null
+++ b/omegalib/omega/include/basic/Tuple.h
@@ -0,0 +1,90 @@
+#if !defined _Already_defined_tuple
+#define _Already_defined_tuple
+
+#include <stdio.h>
+
+#include <basic/Collection.h>
+#include <basic/Iterator.h>
+#include <basic/util.h>
+
+namespace omega {
+
+template<class T> class Tuple_Iterator;
+
+// TUPLES ARE INDEXED STARTING AT 1
+// index\(i\) == 0 MEANS i IS NOT IN THE TUPLE
+
+template <class T> class Tuple : public Sequence<T> {
+public:
+ Tuple();
+ Tuple(int size);
+ Tuple (const Tuple<T>& tpl);
+ virtual ~Tuple();
+ Tuple<T>& operator=(const Tuple<T>& tpl);
+ int size() const { return sz; }
+ int length() const { return sz; }
+ bool operator==(const Tuple<T> &b) const;
+ void reallocate(const int);
+ void delete_last();
+ void append(const Tuple<T> &v);
+ void append(const T &v);
+ void join(Tuple<T> &v);
+ void clear();
+ int empty() const;
+
+ Iterator<T> *new_iterator();
+
+ virtual T &operator[](int index);
+ virtual const T &operator[](int index) const;
+
+ int index(const T &) const;
+
+ friend class Tuple_Iterator<T>;
+
+private:
+ int prealloc_size(const int req_size)
+ { return max(req_size+prealloc_pad,prealloc_min); }
+ int realloc_size(const int oldsize) { return 2*oldsize; }
+
+
+ int sz, alloc_sz; // Number of elements, size of allocated array
+ int prealloc_min,prealloc_pad; // These should be static, but that
+ // causes portability prob. for initialization
+
+protected:
+ T * data;
+};
+
+template <class T> class Tuple_Iterator : public Iterator <T> {
+public:
+ Tuple_Iterator(const Tuple<T> &tpl);
+ const T & operator*() const;
+ T & operator*();
+ void set_position(const int req_pos);
+ void operator++(int);
+ void operator++();
+ void operator--(int);
+ void operator--();
+ void set_to_last();
+ void set_to_first();
+// void set_position(const int req_pos); Don't do this, compiler bug
+ bool live() const;
+ Iterator<T> *new_copy() const;
+
+private:
+ Tuple_Iterator(T * cr, T * frst, T *lst, int insz);
+ T * current, * lastptr, *firstptr;
+ int sz;
+};
+
+} // namespace
+
+#if ! defined DONT_INCLUDE_TEMPLATE_CODE
+#include <basic/Tuple.c>
+#endif
+
+#define instantiate_Tuple(T) template class Tuple<T>; \
+ template class Tuple_Iterator<T>; \
+ instantiate_Sequence(T)
+
+#endif
diff --git a/omegalib/omega/include/basic/boolset-test.cc b/omegalib/omega/include/basic/boolset-test.cc
new file mode 100755
index 0000000..5b68220
--- /dev/null
+++ b/omegalib/omega/include/basic/boolset-test.cc
@@ -0,0 +1,72 @@
+#include "boolset.h"
+#include <iostream>
+
+using namespace omega;
+
+void foo(const BoolSet<> &B) {
+ for (BoolSet<>::const_iterator i = B.begin(); i != B.end(); i++)
+ std::cout << *i << ' ';
+ std::cout << std::endl;
+}
+
+int main() {
+ BoolSet<> A(13);
+
+ A.set(2);
+ std::cout << A << std::endl;
+
+ A.set_all();
+ std::cout << A << std::endl;
+
+ A.unset_all();
+ std::cout << A << std::endl;
+
+ A.set(2);
+ A.set(4);
+
+ BoolSet<> B(13);
+ B.set(2);
+
+ std::cout << "A: " << A << std::endl;
+ std::cout << "B: " << B << std::endl;
+
+ std::cout << A.imply(B) << std::endl;
+ std::cout << B.imply(A) << std::endl;
+
+ B.set(10);
+ std::cout << (A|B) << std::endl;
+ std::cout << (A&B) << std::endl;
+
+ BoolSet<> C(3);
+ C.set(0);
+ std::cout << (A|C) << std::endl;
+ std::cout << ~(A|C) << std::endl;
+
+ B = BoolSet<>(23);
+ std::cout << "test iterator\n";
+ B.set(12);
+ B.set(11);
+ B.set(0);
+ std::cout << B << std::endl;
+ for (BoolSet<>::const_iterator i = B.begin(); i != B.end(); i++) {
+ std::cout << *i << ' ';
+ if (*i == 11)
+ B.unset(*i);
+ }
+ std::cout << std::endl;
+ std::cout << B << std::endl;
+ std::cout << std::endl;
+ foo(B);
+
+ std::cout << ~BoolSet<>(5) << std::endl;
+
+ std::cout << "------\n";
+ B.dump();
+ std::cout << std::endl << *(B.begin()+1) << std::endl;
+
+ for (BoolSet<>::iterator i = B.begin(); i != B.end(); i++)
+ for (BoolSet<>::iterator j = i; j != B.end(); j++)
+ if (j == i)
+ std::cout << "ehh-";
+
+}
diff --git a/omegalib/omega/include/basic/omega_error.h b/omegalib/omega/include/basic/omega_error.h
new file mode 100644
index 0000000..e342efb
--- /dev/null
+++ b/omegalib/omega/include/basic/omega_error.h
@@ -0,0 +1,14 @@
+#ifndef OMEGA_ERROR_H
+#define OMEGA_ERROR_H
+
+namespace omega {
+
+struct presburger_error: public std::runtime_error {
+ presburger_error(const std::string &msg): std::runtime_error("presburger error: " + msg) {}
+};
+
+
+
+}
+#endif
+
diff --git a/omegalib/omega/include/basic/util.h b/omegalib/omega/include/basic/util.h
new file mode 100644
index 0000000..4e807cd
--- /dev/null
+++ b/omegalib/omega/include/basic/util.h
@@ -0,0 +1,263 @@
+#if ! defined Already_Included_Util
+#define Already_Included_Util
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string>
+#include <sstream>
+#include <stdexcept>
+
+namespace omega {
+
+#define LONG_LONG_COEF 1
+
+#if LONG_LONG_COEF
+#if defined BOGUS_LONG_DOUBLE_COEF
+typedef long double coef_t; // type of coefficients
+#define coef_fmt "%llf"
+#define posInfinity (1e+24)
+#define negInfinity (-1e+24)
+#else
+#ifdef WIN32
+typedef _int64 coef_t; // type of coefficients
+#else
+typedef long long coef_t;
+#endif
+#define coef_fmt "%lld"
+#define posInfinity (0x7ffffffffffffffLL)
+#define negInfinity (-0x7ffffffffffffffLL)
+#endif
+#else
+typedef int coef_t; // type of coefficients
+#define coef_fmt "%d"
+#define posInfinity (0x7ffffff)
+#define negInfinity (-0x7ffffff)
+#endif
+
+
+template<typename T> inline const T& max(const T &x, const T &y) {
+ if (x >= y) return x; else return y;
+}
+
+
+template<typename T> inline const T& max(const T &x, const T &y, const T &z) {
+ return max(x, max(y, z));
+}
+
+template<typename T> inline const T& min(const T &x, const T &y) {
+ if (x <= y) return x; else return y;
+}
+
+template<typename T> inline const T& min(const T &x, const T &y, const T &z) {
+ return min(x, min(y, z));
+}
+
+template<class T> inline void set_max(T &m, const T &x) {
+ if (m < x) m = x;
+}
+
+template<class T> inline void set_min(T &m, const T &x) {
+ if (m > x) m = x;
+}
+
+/* template<class T> inline void swap(T &i, T &j) { */
+/* T tmp; */
+/* tmp = i; */
+/* i = j; */
+/* j = tmp; */
+/* } */
+
+/* template<class T> inline T copy(const T &t) { return t; } */
+
+
+/* inline coef_t check_pos_mul(coef_t x, coef_t y) { */
+/* if (y >= 48051280 && y < posInfinity) */
+/* fprintf(stderr, "%d %d\n", x, y); */
+/* /\* #if !defined NDEBUG *\/ */
+/* /\* if (x != 0) *\/ */
+/* /\* assert(((MAXINT)/4) / x > y); *\/ */
+/* /\* #elif defined STILL_CHECK_MULT *\/ */
+/* /\* if (x != 0 && !(((MAXINT)/4) / x > y)) { *\/ */
+/* /\* assert(0&&"Integer overflow during multiplication (util.h)"); *\/ */
+/* /\* } *\/ */
+/* /\* #endif *\/ */
+/* #if !defined NDEBUG */
+/* if (x != 0 && y != 0) */
+/* assert(x*y > 0); */
+/* #elif defined STILL_CHECK_MULT */
+/* if (x != 0 && y != 0 && x*y < 0) */
+/* assert(0&&"Integer overflow during multiplication (util.h)"); */
+/* #endif */
+/* return x * y; */
+/* } */
+
+
+/* inline int */
+/* check_pos_mul(int x, int y) { */
+/* #if !defined NDEBUG */
+/* if (x != 0) */
+/* assert(((posInfinity)/4) / x > y); */
+/* #elif defined STILL_CHECK_MULT */
+/* if (x != 0 && !(((posInfinity)/4) / x > y)) { */
+/* assert(0&&"Integer overflow during multiplication (util.h)"); */
+/* } */
+/* #endif */
+/* return x * y; */
+/* } */
+
+/* inline LONGLONG */
+/* check_pos_mul(LONGLONG x, LONGLONG y) { */
+/* #if !defined NDEBUG */
+/* if (x != 0) */
+/* assert(((posInfinity)/4) / x > y); */
+/* #elif defined STILL_CHECK_MULT */
+/* if (x != 0 && !(((posInfinity)/4) / x > y)) { */
+/* assert(0&&"Integer overflow during multiplication (util.h)"); */
+/* } */
+/* #endif */
+/* return x * y; */
+/* } */
+
+/* inline LONGLONG abs(LONGLONG c) { return (c>=0?c:(-c)); } */
+
+template<typename T> inline T check_mul(const T &x, const T &y) {
+#if defined NDEBUG && ! defined STILL_CHECK_MULT
+ return x*y;
+#else
+ if (x == 0 || y == 0)
+ return 0;
+
+ T z = x*y;
+ int sign_x = (x>0)?1:-1;
+ int sign_y = (y>0)?1:-1;
+ int sign_z = (z>0)?1:-1;
+
+ if (sign_x * sign_y != sign_z)
+ throw std::overflow_error("coefficient multiply overflow");
+
+ return z;
+
+ /* if (x > 0) { */
+ /* if (y > 0) { */
+ /* assert(x*y > 0); */
+ /* } */
+ /* else */
+ /* assert(x*y < 0); */
+ /* } */
+ /* else { */
+ /* if (y > 0) */
+ /* assert(x*y < 0); */
+ /* else */
+ /* assert(x*y > 0); */
+ /* } */
+ /* return x*y; */
+#endif
+}
+
+template<typename T> inline T abs(const T &v) {
+ return (v >= static_cast<T>(0))?v:-v;
+}
+
+template<class T> inline T int_div(const T &a, const T &b) {
+ T result;
+ assert(b > 0);
+ if (a>0) result = a/b;
+ else result = -((-a+b-1)/b);
+ return result;
+}
+
+template<class T> inline T int_mod(const T &a, const T &b) {
+ return a-b*int_div(a,b);
+}
+
+template<class T> inline T int_mod_hat(const T &a, const T &b) {
+ T r;
+ assert(b > 0);
+ r = a-b*int_div(a,b);
+ if (r > -(r-b)) r -= b;
+ return r;
+}
+
+template<typename T> inline T gcd(T b, T a) {/* First argument is non-negative */
+ assert(a >= 0);
+ assert(b >= 0);
+ if (b == 1)
+ return (1);
+ while (b != 0) {
+ T t = b;
+ b = a % b;
+ a = t;
+ }
+ return (a);
+}
+
+template<typename T> inline T lcm(T b, T a) { /* First argument is non-negative */
+ assert(a >= 0);
+ assert(b >= 0);
+ return check_mul(a/gcd(a,b), b);
+}
+
+template<typename T> T square_root(const T &n, T precision = 1) {
+ T guess = 1;
+
+ while (true) {
+ T next_guess = 0.5*(guess+n/guess);
+ if (abs(next_guess-guess) <= precision)
+ return next_guess;
+ else
+ guess = next_guess;
+ }
+}
+
+template<typename T> T factor(const T &n) {
+ assert(n >= 0);
+ if (n == 1) return 1;
+
+ static int prime[30] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113};
+
+ if (n <= 113*113) {
+ for (int i = 0; i < 30; i++)
+ if (n % static_cast<T>(prime[i]) == 0)
+ return static_cast<T>(prime[i]);
+
+ return n;
+ }
+
+ T i = 1;
+ T k = 2;
+ T x = static_cast<T>(rand())%n;
+ T y = x;
+ while(i < square_root<float>(n, 1)) {
+ i++;
+ x = (x*x-1) % n;
+ T d = gcd(abs(y-x), n);
+ if(d != 1 && d != n)
+ return factor(d);
+ if(i == k) {
+ y = x;
+ k *= 2;
+ }
+ }
+ return n;
+}
+
+/* #define implies(A,B) (A==(A&B)) */
+
+template<typename T> std::string to_string(const T &t) {
+ std::ostringstream ss;
+ ss << t;
+ return ss.str();
+}
+
+template<typename T> T from_string(const std::string &s) {
+ std::istringstream ss(s);
+ ss.exceptions(std::ios::failbit);
+ T t;
+ ss >> t;
+ return t;
+}
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/include/omega.h b/omegalib/omega/include/omega.h
new file mode 100644
index 0000000..8aa2c08
--- /dev/null
+++ b/omegalib/omega/include/omega.h
@@ -0,0 +1,71 @@
+/*********************************************************************
+ Old license information from the Omega Project, updated one can be
+ found in LICENSE file.
+
+ Copyright (C) 1994-1996 by the Omega Project
+ All rights reserved.
+
+ NOTICE: This software is provided ``as is'', without any
+ warranty, including any implied warranty for merchantability or
+ fitness for a particular purpose. Under no circumstances shall
+ the Omega Project or its agents be liable for any use of, misuse
+ of, or inability to use this software, including incidental and
+ consequential damages.
+
+ License is hereby given to use, modify, and redistribute this
+ software, in whole or in part, for any purpose, commercial or
+ non-commercial, provided that the user agrees to the terms of this
+ copyright notice, including disclaimer of warranty, and provided
+ that this copyright notice, including disclaimer of warranty, is
+ preserved in the source code and documentation of anything derived
+ from this software. Any redistributor of this software or
+ anything derived from this software assumes responsibility for
+ ensuring that any parties to whom such a redistribution is made
+ are fully aware of the terms of this license and disclaimer.
+
+ The Omega project can be contacted at omega@cs.umd.edu
+ or http://www.cs.umd.edu/projects/omega
+*********************************************************************/
+
+#ifndef Already_Included_Omega
+#define Already_Included_Omega
+
+/*
+ * The presburger interface is divided into the following parts.
+ * These parts are all included together, but are in separate
+ * files to keep things organized a bit.
+ *
+ * In many files, you can include just some of the following,
+ * specifically: if you are building a presburger tree, just
+ * include "pres_tree.h"; if you are querying it, include
+ * "pres_dnf.d" and "pres_conj.h"; if you are doing relational
+ * operations, include "Relation.h"
+ *
+ * Most of the function definitions are in the .c files with
+ * the same name as the .h that declares them, except:
+ * the remap and push_exists functions are in pres_var.c
+ * the DNFize functions are in pres_dnf.c
+ * the functions involving printing are in pres_print.c
+ * the beautify functions are in pres_beaut.c
+ * the rearrange functions are in pres_rear.c
+ * the compression functions are in pres_cmpr.c
+ */
+
+#include <omega/omega_core/debugging.h>
+#include <omega/pres_var.h>
+#include <omega/pres_cnstr.h>
+#include <omega/pres_subs.h>
+#include <omega/pres_form.h>
+#include <omega/pres_logic.h>
+#include <omega/pres_decl.h>
+#include <omega/pres_quant.h>
+#include <omega/pres_conj.h>
+#include <omega/pres_cmpr.h>
+#include <omega/Relation.h>
+
+#include <omega/Rel_map.h>
+#include <omega/farkas.h>
+#include <omega/hull.h>
+#include <omega/closure.h>
+
+#endif
diff --git a/omegalib/omega/include/omega/RelBody.h b/omegalib/omega/include/omega/RelBody.h
new file mode 100644
index 0000000..3c11702
--- /dev/null
+++ b/omegalib/omega/include/omega/RelBody.h
@@ -0,0 +1,165 @@
+#if ! defined _RelBody_h
+#define _RelBody_h 1
+
+#include <omega/pres_form.h>
+#include <omega/pres_dnf.h>
+
+namespace omega {
+
+typedef enum {under_construction, compressed, uncompressed} Rel_Body_Status;
+typedef unsigned char Rel_Unknown_Uses;
+const Rel_Unknown_Uses no_u = 1;
+const Rel_Unknown_Uses and_u = 2;
+const Rel_Unknown_Uses or_u = 4;
+
+//
+// Relation body.
+// Body and representative are separated to do reference counting.
+//
+
+class Rel_Body : public Formula {
+public:
+ bool is_null() const;
+
+ inline Node_Type node_type() { return Op_Relation; }
+
+ inline bool is_set() const { return number_output == 0; }
+ int n_inp() const;
+ int n_out() const;
+ int n_set() const;
+
+ inline Variable_ID_Tuple *global_decls() { return &Symbolic; }
+ int max_ufs_arity();
+ int max_shared_ufs_arity();
+ int max_ufs_arity_of_set();
+ int max_ufs_arity_of_in();
+ int max_ufs_arity_of_out();
+
+ Variable_ID input_var(int nth);
+ Variable_ID output_var(int nth);
+ Variable_ID set_var(int nth);
+ Variable_ID get_local(const Variable_ID v);
+ Variable_ID get_local(const Global_Var_ID G);
+ Variable_ID get_local(const Global_Var_ID G, Argument_Tuple of);
+ bool has_local(const Global_Var_ID G);
+ bool has_local(const Global_Var_ID G, Argument_Tuple of);
+ void name_input_var(int, Const_String);
+ void name_output_var(int, Const_String);
+ void name_set_var(int, Const_String);
+
+ F_And *and_with_and();
+ EQ_Handle and_with_EQ();
+ EQ_Handle and_with_EQ(const Constraint_Handle &c);
+ GEQ_Handle and_with_GEQ();
+ GEQ_Handle and_with_GEQ(const Constraint_Handle &c);
+
+ void print();
+ void print(FILE *output_file) { print(output_file, true); }
+ void print(FILE *output_file, bool printSym);
+ std::string print_variables_to_string(bool printSym);
+ void print_with_subs(FILE *output_file, bool printSym, bool newline);
+ void print_with_subs();
+ std::string print_with_subs_to_string(bool printSym, bool newline);
+ std::string print_outputs_with_subs_to_string();
+ std::string print_outputs_with_subs_to_string(int i);
+ std::string print_formula_to_string();
+ void prefix_print();
+ void prefix_print(FILE *output_file, int debug = 1);
+
+ bool is_satisfiable();
+ bool is_lower_bound_satisfiable();
+ bool is_upper_bound_satisfiable();
+ bool is_obvious_tautology();
+ bool is_definite_tautology();
+ bool is_unknown();
+ DNF* query_DNF();
+ DNF* query_DNF(int rdt_conjs, int rdt_constrs);
+ void simplify(int rdt_conjs = 0, int rdt_constrs = 0);
+ void finalize();
+ inline bool is_finalized() { return finalized; }
+ inline bool is_shared() { return ref_count > 1; }
+
+ void query_difference(Variable_ID v1, Variable_ID v2,
+ coef_t &lowerBound, coef_t &upperBound,
+ bool &quaranteed);
+ void query_variable_bounds(Variable_ID, coef_t &lowerBound, coef_t &upperBound);
+ coef_t query_variable_mod(Variable_ID v, coef_t factor);
+
+ Relation extract_dnf_by_carried_level(int level, int direction);
+ void make_level_carried_to(int level);
+
+ // these are only public to allow the creation of "null_rel"
+ Rel_Body();
+ ~Rel_Body();
+ void setup_names();
+
+private:
+
+ // These are manipulated primarily as parts of Relations
+ friend class Relation;
+ friend_rel_ops;
+
+ friend void remap_DNF_vars(Rel_Body *new_rel, Rel_Body *old_rel);
+
+ Rel_Unknown_Uses unknown_uses();
+
+ inline bool is_simplified() const { return (simplified_DNF!=NULL && get_children().empty()); }
+ bool is_compressed();
+ Conjunct *rm_first_conjunct();
+ Conjunct *single_conjunct();
+ bool has_single_conjunct();
+
+ void beautify();
+ void rearrange();
+
+ friend class EQ_Handle; // these set up names for printing
+ friend class GEQ_Handle; // and check if simplified
+ friend class Constraint_Handle; // and update coefficients
+
+ void compress();
+ void uncompress();
+
+ void interpret_unknown_as_true();
+ void interpret_unknown_as_false();
+
+ Rel_Body(int n_input, int n_output);
+ /* Rel_Body(Rel_Body *r); */
+ Rel_Body(Rel_Body *r, Conjunct *c);
+ Rel_Body &operator=(Rel_Body &r);
+ Rel_Body *clone();
+
+ inline Formula *formula() { return children().front(); }
+ inline Formula *rm_formula() { return children().remove_front(); }
+ bool can_add_child();
+
+ void reverse_leading_dir_info();
+ void invalidate_leading_info(int changed = -1) { Formula::invalidate_leading_info(changed); }
+ void enforce_leading_info(int guaranteed, int possible, int dir) { Formula::enforce_leading_info(guaranteed, possible, dir); }
+ // re-declare this so that Relation (a friend) can call it
+
+ DNF* DNFize();
+ void DNF_to_formula();
+
+ Conjunct *find_available_conjunct();
+ F_And *find_available_And();
+
+
+/* === data === */
+private:
+
+ int ref_count;
+ Rel_Body_Status status;
+
+ int number_input, number_output;
+ Tuple<Const_String> In_Names, Out_Names;
+ Variable_ID_Tuple Symbolic;
+
+ DNF* simplified_DNF;
+ short r_conjs; // are redundant conjuncts eliminated?
+ bool finalized;
+ bool _is_set;
+};
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/include/omega/Rel_map.h b/omegalib/omega/include/omega/Rel_map.h
new file mode 100644
index 0000000..5641cb3
--- /dev/null
+++ b/omegalib/omega/include/omega/Rel_map.h
@@ -0,0 +1,161 @@
+#if ! defined _Rel_map_h
+#define _Rel_map_h 1
+
+#include <omega/pres_gen.h>
+#include <omega/pres_var.h>
+
+namespace omega {
+
+//
+// Mapping for relations
+// When a relation operation needs to re-arrange the variables,
+// it describes the re-arragement with a mapping, and then calls
+// align to re-arrange them.
+//
+// In a mapping, map_in (map_out/map_set) gives the new type and
+// position of each of the old input (output/set) variables.
+// For variables being mapped to Input, Output, or Set variables,
+// the position is the new position in the tuple.
+// For variables being mapped to Exists_Var, Forall_Var, or
+// Wildcard_Var, the positions can be used to map multiple
+// variables to the same quantified variable, by providing
+// the same position. Each variable with a negative position
+// is given a unique quantified variable that is NOT listed
+// in the seen_exists_ids list.
+// I'm not sure what the positions mean for Global_Vars - perhaps
+// they are ignored?
+//
+// Currently, align seems to support only mapping to Set, Input,
+// Output, and Exists vars.
+//
+
+class Mapping {
+public:
+ inline Mapping(int no_in, int no_out): n_input(no_in), n_output(no_out) {}
+ inline Mapping(int no_set): n_input(no_set), n_output(0){}
+ inline Mapping(const Mapping &m): n_input(m.n_input), n_output(m.n_output) {
+ int i;
+ for(i=1; i<=n_input; i++) map_in_kind[i] = m.map_in_kind[i];
+ for(i=1; i<=n_input; i++) map_in_pos[i] = m.map_in_pos[i];
+ for(i=1; i<=n_output;i++) map_out_kind[i] = m.map_out_kind[i];
+ for(i=1; i<=n_output;i++) map_out_pos[i] = m.map_out_pos[i];
+ }
+
+ inline void set_map (Var_Kind in_kind, int pos, Var_Kind type, int map) {
+ if(in_kind==Input_Var)
+ set_map_in(pos,type,map);
+ else if(in_kind==Set_Var)
+ set_map_in(pos,type,map);
+ else if(in_kind==Output_Var)
+ set_map_out(pos,type,map);
+ else
+ assert(0);
+ }
+
+ inline void set_map_in (int pos, Var_Kind type, int map) {
+ assert(pos>=1 && pos<=n_input);
+ map_in_kind[pos] = type;
+ map_in_pos[pos] = map;
+ }
+ inline void set_map_set (int pos, Var_Kind type, int map) {
+ assert(pos>=1 && pos<=n_input);
+ map_in_kind[pos] = type;
+ map_in_pos[pos] = map;
+ }
+
+ inline void set_map_out(int pos, Var_Kind type, int map) {
+ assert(pos>=1 && pos<=n_output);
+ map_out_kind[pos] = type;
+ map_out_pos[pos] = map;
+ }
+
+ inline Var_Kind get_map_in_kind(int pos) const {
+ assert(pos>=1 && pos<=n_input);
+ return map_in_kind[pos];
+ }
+
+ inline int get_map_in_pos(int pos) const {
+ assert(pos>=1 && pos<=n_input);
+ return map_in_pos[pos];
+ }
+
+ inline Var_Kind get_map_out_kind(int pos) const {
+ assert(pos>=1 && pos<=n_output);
+ return map_out_kind[pos];
+ }
+
+ inline int get_map_out_pos(int pos) const {
+ assert(pos>=1 && pos<=n_output);
+ return map_out_pos[pos];
+ }
+
+ inline int n_in() const { return n_input; }
+ inline int n_out() const { return n_output; }
+
+ // If a tuple as a whole becomes the new Input or Output tuple,
+ // return the Tuple of they will become (Input, Output)
+ // Return Unknown_Tuple otherwise
+
+ inline Argument_Tuple get_tuple_fate(Argument_Tuple t, int prefix = -1) const {
+ return t== Input_Tuple ? get_input_fate(prefix) :
+ (t==Output_Tuple ? get_output_fate(prefix) : Unknown_Tuple); }
+
+ inline Argument_Tuple get_set_fate(int prefix = -1) const {
+ return get_input_fate(prefix); }
+
+ inline Argument_Tuple get_input_fate(int prefix = -1) const {
+ if (prefix < 0) prefix = n_input;
+ assert(n_input >= prefix);
+ if (n_input < prefix)
+ return Unknown_Tuple;
+ Var_Kind vf = map_in_kind[1];
+ for (int i = 1; i<=prefix; i++)
+ if (map_in_pos[i]!=i || map_in_kind[i]!=vf)
+ return Unknown_Tuple;
+
+ return vf == Input_Var ? Input_Tuple
+ : vf == Set_Var ? Set_Tuple
+ : vf == Output_Var ? Output_Tuple
+ : Unknown_Tuple;
+ }
+
+ inline Argument_Tuple get_output_fate(int prefix = -1) const {
+ if (prefix < 0) prefix = n_output;
+ assert(n_output >= prefix);
+ if (n_output < 1)
+ return Unknown_Tuple;
+ Var_Kind vf = map_out_kind[1];
+ for (int i = 1; i<=prefix; i++)
+ if (map_out_pos[i]!=i || map_out_kind[i]!=vf)
+ return Unknown_Tuple;
+ return vf == Input_Var ? Input_Tuple
+ : vf == Set_Var ? Set_Tuple
+ : vf == Output_Var ? Output_Tuple
+ : Unknown_Tuple;
+ }
+
+ inline static Mapping Identity(int inp, int outp) {
+ Mapping m(inp, outp); int i;
+ for(i=1; i<=m.n_input; i++) m.set_map(Input_Var, i, Input_Var, i);
+ for(i=1; i<=m.n_output;i++) m.set_map(Output_Var, i, Output_Var, i);
+ return m;
+ }
+
+ inline static Mapping Identity(int setvars) {
+ Mapping m(setvars); int i;
+ for(i=1; i<=setvars; i++) m.set_map(Set_Var, i, Set_Var, i);
+ return m;
+ }
+
+private:
+ int n_input;
+ int n_output;
+ Var_Kind map_in_kind[maxVars];
+ int map_in_pos[maxVars];
+ Var_Kind map_out_kind[maxVars];
+ int map_out_pos[maxVars];
+};
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/include/omega/Relation.h b/omegalib/omega/include/omega/Relation.h
new file mode 100644
index 0000000..b41bef5
--- /dev/null
+++ b/omegalib/omega/include/omega/Relation.h
@@ -0,0 +1,299 @@
+#if ! defined _Relation_h
+#define _Relation_h 1
+
+#include <omega/RelBody.h>
+#include <omega/pres_cnstr.h>
+#include <iostream>
+#include <limits.h>
+
+namespace omega {
+
+//
+// Relation representative.
+// Body and representative are separated to do reference counting.
+//
+class Relation {
+public:
+ Relation();
+
+ Relation(int n_input, int n_output = 0);
+ Relation(const Relation &r);
+ Relation(const Relation &r, Conjunct *c);
+ Relation &operator=(const Relation &r);
+ Relation(Rel_Body &r, int foo);
+
+ static Relation Null();
+ static Relation Empty(const Relation &R);
+ static Relation True(const Relation &R);
+ static Relation True(int setvars);
+ static Relation True(int in, int out);
+ static Relation False(const Relation &R);
+ static Relation False(int setvars);
+ static Relation False(int in, int out);
+ static Relation Unknown(const Relation &R);
+ static Relation Unknown(int setvars);
+ static Relation Unknown(int in, int out);
+
+
+ bool is_null() const;
+
+ ~Relation();
+
+ inline F_Forall *add_forall()
+ { return rel_body->add_forall(); }
+ inline F_Exists *add_exists()
+ { return rel_body->add_exists(); }
+ inline F_And *add_and()
+ { return rel_body->add_and(); }
+ inline F_And *and_with()
+ { return rel_body->and_with(); }
+ inline F_Or *add_or()
+ { return rel_body->add_or(); }
+ inline F_Not *add_not()
+ { return rel_body->add_not(); }
+ inline void finalize()
+ { rel_body->finalize(); }
+ inline bool is_finalized() const
+ { return rel_body->finalized; }
+ inline bool is_set() const
+ { return rel_body->is_set(); }
+ inline int n_inp() const
+ { return rel_body->n_inp(); }
+ inline int n_out() const
+ { return rel_body->n_out(); }
+ inline int n_set() const
+ { return rel_body->n_set(); }
+
+ inline const Variable_ID_Tuple *global_decls() const
+ { return rel_body->global_decls(); }
+ inline int max_ufs_arity() const
+ { return rel_body->max_ufs_arity(); }
+ inline int max_ufs_arity_of_in() const
+ { return rel_body->max_ufs_arity_of_in(); }
+ inline int max_ufs_arity_of_set() const
+ { return rel_body->max_ufs_arity_of_set(); }
+ inline int max_ufs_arity_of_out() const
+ { return rel_body->max_ufs_arity_of_out(); }
+ inline int max_shared_ufs_arity() const
+ { return rel_body->max_shared_ufs_arity(); }
+
+ inline Variable_ID input_var(int nth)
+ { return rel_body->input_var(nth); }
+ inline Variable_ID output_var(int nth)
+ { return rel_body->output_var(nth); }
+ inline Variable_ID set_var(int nth)
+ { return rel_body->set_var(nth); }
+ inline bool has_local(const Global_Var_ID G)
+ { return rel_body->has_local(G); }
+ inline bool has_local(const Global_Var_ID G, Argument_Tuple of)
+ { return rel_body->has_local(G, of); }
+ inline Variable_ID get_local(const Variable_ID v)
+ { return split()->get_local(v); }
+ inline Variable_ID get_local(const Global_Var_ID G)
+ { return split()->get_local(G); }
+ inline Variable_ID get_local(const Global_Var_ID G, Argument_Tuple of)
+ { return split()->get_local(G, of); }
+
+ inline void name_input_var(int nth, Const_String S)
+ { split()->name_input_var(nth, S); }
+ inline void name_output_var(int nth, Const_String S)
+ { split()->name_output_var(nth, S); }
+ inline void name_set_var(int nth, Const_String S)
+ { split()->name_set_var(nth, S); }
+
+
+ inline F_And *and_with_and()
+ { return split()->and_with_and(); }
+ inline EQ_Handle and_with_EQ()
+ { return split()->and_with_EQ(); }
+ inline EQ_Handle and_with_EQ(const Constraint_Handle &c)
+ { return split()->and_with_EQ(c); }
+ inline GEQ_Handle and_with_GEQ()
+ { return split()->and_with_GEQ(); }
+ inline GEQ_Handle and_with_GEQ(const Constraint_Handle &c)
+ { return split()->and_with_GEQ(c); }
+
+ inline void print()
+ { rel_body->print(); }
+ inline void print(FILE *output_file)
+ { rel_body->print(output_file); }
+ inline void print_with_subs()
+ { rel_body->print_with_subs(); }
+ inline void print_with_subs(FILE *output_file, bool printSym=false,
+ bool newline=true)
+ { rel_body->print_with_subs(output_file, printSym, newline); }
+ inline std::string print_with_subs_to_string(bool printSym=false,
+ bool newline=true)
+ { return rel_body->print_with_subs_to_string(printSym, newline); }
+ inline std::string print_outputs_with_subs_to_string()
+ { return rel_body->print_outputs_with_subs_to_string(); }
+ inline std::string print_outputs_with_subs_to_string(int i)
+ { return rel_body->print_outputs_with_subs_to_string(i); }
+ inline void prefix_print()
+ { rel_body->prefix_print(); }
+ inline void prefix_print(FILE *output_file, int debug = 1)
+ { rel_body->prefix_print(output_file, debug); }
+ inline std::string print_formula_to_string() {
+ return rel_body->print_formula_to_string();
+ }
+ void dimensions(int & ndim_all, int &ndim_domain);
+
+ inline bool is_lower_bound_satisfiable()
+ { return rel_body->is_lower_bound_satisfiable(); }
+ inline bool is_upper_bound_satisfiable()
+ { return rel_body->is_upper_bound_satisfiable(); }
+ inline bool is_satisfiable()
+ { return rel_body->is_satisfiable(); }
+
+ inline bool is_tautology()
+ { return rel_body->is_obvious_tautology(); } // for compatibility
+ inline bool is_obvious_tautology()
+ { return rel_body->is_obvious_tautology(); }
+ inline bool is_definite_tautology()
+ { return rel_body->is_definite_tautology(); }
+
+ // return x s.t. forall conjuncts c, c has >= x leading 0s
+ // for set, return -1 (pass this in, in case there are no conjuncts
+ inline int number_of_conjuncts()
+ { return rel_body->query_DNF()->length(); }
+
+ // return x s.t. forall conjuncts c, c has >= x leading 0s
+ // for set, return -1 (pass this in, in case there are no conjuncts
+ inline int query_guaranteed_leading_0s()
+ { return rel_body->query_DNF()->query_guaranteed_leading_0s(this->is_set() ? -1 : 0); }
+
+ // return x s.t. forall conjuncts c, c has <= x leading 0s
+ // if no conjuncts return min of input and output tuple sizes, or -1 if relation is a set
+ inline int query_possible_leading_0s()
+ { return rel_body->query_DNF()->query_possible_leading_0s(
+ this->is_set()? -1 : min(n_inp(),n_out())); }
+
+ // return +-1 according to sign of leading dir, or 0 if we don't know
+ inline int query_leading_dir()
+ { return rel_body->query_DNF()->query_leading_dir(); }
+
+ inline DNF* query_DNF()
+ { return rel_body->query_DNF(); }
+ inline DNF* query_DNF(int rdt_conjs, int rdt_constrs)
+ { return rel_body->query_DNF(rdt_conjs, rdt_constrs); }
+ inline void simplify(int rdt_conjs = 0, int rdt_constrs = 0)
+ { rel_body->simplify(rdt_conjs, rdt_constrs); }
+ inline bool is_simplified()
+ { return rel_body->is_simplified(); }
+ inline bool is_compressed() const
+ { return rel_body->is_compressed(); }
+ inline Conjunct *rm_first_conjunct()
+ { return rel_body->rm_first_conjunct(); }
+ inline Conjunct *single_conjunct()
+ { return rel_body->single_conjunct(); }
+ inline bool has_single_conjunct()
+ { return rel_body->has_single_conjunct(); }
+
+
+ void query_difference(Variable_ID v1, Variable_ID v2, coef_t &lowerBound, coef_t &upperBound, bool &guaranteed) {
+ rel_body->query_difference(v1, v2, lowerBound, upperBound, guaranteed);
+ }
+ void query_variable_bounds(Variable_ID v, coef_t &lowerBound, coef_t &upperBound) {
+ rel_body->query_variable_bounds(v,lowerBound,upperBound);
+ }
+ coef_t query_variable_mod(Variable_ID v, coef_t factor) {
+ assert(factor > 0);
+ return rel_body->query_variable_mod(v, factor);
+ }
+ int query_variable_mod(Variable_ID v, int factor) {
+ assert(sizeof(int) <= sizeof(coef_t));
+ coef_t result = rel_body->query_variable_mod(v, static_cast<coef_t>(factor));
+ if (result == posInfinity)
+ return INT_MAX;
+ else
+ return static_cast<int>(result);
+ }
+
+
+ inline void make_level_carried_to(int level)
+ {
+ split()->make_level_carried_to(level);
+ }
+
+ inline Relation extract_dnf_by_carried_level(int level, int direction)
+ {
+ return split()->extract_dnf_by_carried_level(level, direction);
+ }
+
+ inline void compress()
+ {
+#if defined(INCLUDE_COMPRESSION)
+ split()->compress();
+#endif
+ }
+ void uncompress()
+ { rel_body->uncompress(); }
+
+ inline bool is_exact() const
+ { return !(rel_body->unknown_uses() & (and_u | or_u)) ; }
+ inline bool is_inexact() const
+ { return !is_exact(); }
+ inline bool is_unknown() const
+ { return rel_body->is_unknown(); }
+ inline Rel_Unknown_Uses unknown_uses() const
+ { return rel_body->unknown_uses(); }
+
+ void setup_names() {rel_body->setup_names();}
+ void copy_names(const Relation &r) {
+ copy_names(*r.rel_body);
+ };
+ void copy_names(Rel_Body &r);
+
+private:
+ // Functions that have to create sets from relations:
+ friend class Rel_Body;
+ friend_rel_ops;
+
+
+ Rel_Body *split();
+
+ DNF* simplified_DNF() {
+ simplify();
+ return rel_body->simplified_DNF;
+ };
+
+ inline void invalidate_leading_info(int changed = -1)
+ { split()->invalidate_leading_info(changed); }
+ inline void enforce_leading_info(int guaranteed, int possible, int dir)
+ {
+ split()->enforce_leading_info(guaranteed, possible, dir);
+ }
+
+
+ void makeSet();
+ void markAsSet();
+ void markAsRelation();
+
+ friend bool operator==(const Relation &, const Relation &);
+
+ void reverse_leading_dir_info()
+ { split()->reverse_leading_dir_info(); }
+ void interpret_unknown_as_true()
+ { split()->interpret_unknown_as_true(); }
+ void interpret_unknown_as_false()
+ { split()->interpret_unknown_as_false(); }
+
+
+ Rel_Body *rel_body;
+
+
+ friend 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);
+};
+
+inline std::ostream & operator<<(std::ostream &o, Relation &R)
+{
+ return o << R.print_with_subs_to_string();
+}
+
+Relation copy(const Relation &r);
+
+} // namespace
+
+#include <omega/Relations.h>
+
+#endif
diff --git a/omegalib/omega/include/omega/Relations.h b/omegalib/omega/include/omega/Relations.h
new file mode 100644
index 0000000..4fd81e6
--- /dev/null
+++ b/omegalib/omega/include/omega/Relations.h
@@ -0,0 +1,88 @@
+#if ! defined _Relations_h
+#define _Relations_h 1
+
+#include <map>
+#include <omega/Relation.h>
+
+namespace omega {
+
+// UPDATE friend_rel_ops IN pres_gen.h WHEN ADDING TO THIS LIST
+// REMEMBER TO TAKE OUT DEFAULT ARGUMENTS IN THAT FILE
+
+/* 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);
+
+//
+// Operations over relations
+//
+Relation Union(NOT_CONST Relation &r1, NOT_CONST Relation &r2);
+Relation Intersection(NOT_CONST Relation &r1, NOT_CONST Relation &r2);
+Relation Extend_Domain(NOT_CONST Relation &R);
+Relation Extend_Domain(NOT_CONST Relation &R, int more);
+Relation Extend_Range(NOT_CONST Relation &R);
+Relation Extend_Range(NOT_CONST Relation &R, int more);
+Relation Extend_Set(NOT_CONST Relation &R);
+Relation Extend_Set(NOT_CONST Relation &R, int more);
+Relation Restrict_Domain(NOT_CONST Relation &r1, NOT_CONST Relation &r2); // Takes set as 2nd
+Relation Restrict_Range(NOT_CONST Relation &r1, NOT_CONST Relation &r2); // Takes set as 2nd
+Relation Domain(NOT_CONST Relation &r); // Returns set
+Relation Range(NOT_CONST Relation &r); // Returns set
+Relation Cross_Product(NOT_CONST Relation &A, NOT_CONST Relation &B); // Takes two sets
+Relation Inverse(NOT_CONST Relation &r);
+Relation After(NOT_CONST Relation &r, int carried_by, int new_output,int dir=1);
+Relation Deltas(NOT_CONST Relation &R); // Returns set
+Relation Deltas(NOT_CONST Relation &R, int eq_no); // Returns set
+Relation DeltasToRelation(NOT_CONST Relation &R, int n_input, int n_output);
+Relation Complement(NOT_CONST Relation &r);
+Relation Project(NOT_CONST Relation &R, Global_Var_ID v);
+Relation Project(NOT_CONST Relation &r, int pos, Var_Kind vkind);
+Relation Project(NOT_CONST Relation &S, Variable_ID v);
+Relation Project(NOT_CONST Relation &S, Sequence<Variable_ID> &s);
+Relation Project_Sym(NOT_CONST Relation &R);
+Relation Project_On_Sym(NOT_CONST Relation &R,
+ NOT_CONST Relation &context = Relation::Null());
+Relation GistSingleConjunct(NOT_CONST Relation &R, NOT_CONST Relation &R2, int effort=0);
+Relation Gist(NOT_CONST Relation &R1, NOT_CONST Relation &R2, int effort=0);
+Relation Difference(NOT_CONST Relation &r1, NOT_CONST Relation &r2);
+Relation Approximate(NOT_CONST Relation &R, bool strides_allowed = false);
+Relation Identity(int n_inp);
+Relation Identity(NOT_CONST Relation &r);
+bool Must_Be_Subset(NOT_CONST Relation &r1, NOT_CONST Relation &r2);
+bool Might_Be_Subset(NOT_CONST Relation &r1, NOT_CONST Relation &r2);
+// May is the same as might, just another name
+bool May_Be_Subset(NOT_CONST Relation &r1, NOT_CONST Relation &r2);
+bool Is_Obvious_Subset(NOT_CONST Relation &r1, NOT_CONST Relation &r2);
+Relation Composition(NOT_CONST Relation &F, NOT_CONST Relation &G);
+bool prepare_relations_for_composition(Relation &F, Relation &G);
+Relation Join(NOT_CONST Relation &G, NOT_CONST Relation &F);
+Relation EQs_to_GEQs(NOT_CONST Relation &, bool excludeStrides=false);
+Relation Symbolic_Solution(NOT_CONST Relation &S);
+Relation Symbolic_Solution(NOT_CONST Relation &S, Sequence<Variable_ID> &T);
+Relation Sample_Solution(NOT_CONST Relation &S);
+Relation Solution(NOT_CONST Relation &S, Sequence<Variable_ID> &T);
+Relation Upper_Bound(NOT_CONST Relation &r);
+Relation Lower_Bound(NOT_CONST Relation &r);
+
+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 = -1, int number_output = -1);
+
+// The followings might retire in the futrue!!!
+void MapRel1(Relation &inputRel,
+ const Mapping &map,
+ Combine_Type ctype,
+ int number_input=-1, int number_output=-1,
+ bool invalidate_resulting_leading_info = true,
+ bool finalize = true);
+Relation MapAndCombineRel2(Relation &R1, Relation &R2,
+ const Mapping &mapping1, const Mapping &mapping2,
+ Combine_Type ctype,
+ int number_input=-1, int number_output=-1);
+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);
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/include/omega/closure.h b/omegalib/omega/include/omega/closure.h
new file mode 100644
index 0000000..67088dd
--- /dev/null
+++ b/omegalib/omega/include/omega/closure.h
@@ -0,0 +1,31 @@
+#if ! defined _closure_h
+#define _closure_h
+
+#include <omega/Relation.h>
+
+namespace omega {
+
+Relation VennDiagramForm(
+ Tuple<Relation> &Rs,
+ NOT_CONST Relation &Context_In);
+Relation VennDiagramForm(
+ NOT_CONST Relation &R_In,
+ NOT_CONST Relation &Context_In = Relation::Null());
+
+// Given a Relation R, returns a relation deltas
+// that correspond to the ConicHull of the detlas of R
+Relation ConicClosure (NOT_CONST Relation &R);
+
+Relation TransitiveClosure (NOT_CONST Relation &r,
+ int maxExpansion = 1,
+ NOT_CONST Relation &IterationSpace=Relation::Null());
+
+/* Tomasz Klimek */
+Relation calculateTransitiveClosure(NOT_CONST Relation &r);
+
+/* Tomasz Klimek */
+Relation ApproxClosure(NOT_CONST Relation &r);
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/include/omega/evac.h b/omegalib/omega/include/omega/evac.h
new file mode 100644
index 0000000..a561f8c
--- /dev/null
+++ b/omegalib/omega/include/omega/evac.h
@@ -0,0 +1,15 @@
+#if defined STUDY_EVACUATIONS
+
+namespace omega {
+
+// study the evacuation from one side of C to the other for UFS's of
+// arity up to max_arity
+extern void study_evacuation(Conjunct *C, which_way dir, int max_arity);
+
+// study the evacuation from the joined C2's output and C1's input to
+// either of the other possible tuples
+extern void study_evacuation(Conjunct *C1, Conjunct *C2, int max_arity);
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/include/omega/farkas.h b/omegalib/omega/include/omega/farkas.h
new file mode 100644
index 0000000..e77ed66
--- /dev/null
+++ b/omegalib/omega/include/omega/farkas.h
@@ -0,0 +1,19 @@
+#ifndef Already_Included_Affine_Closure
+#define Already_Included_Affine_Closure
+
+#include <omega/Relation.h>
+
+namespace omega {
+
+enum Farkas_Type {Basic_Farkas, Decoupled_Farkas,
+ Linear_Combination_Farkas, Positive_Combination_Farkas,
+ Affine_Combination_Farkas, Convex_Combination_Farkas };
+
+Relation Farkas(NOT_CONST Relation &R, Farkas_Type op, bool early_bailout = false);
+
+extern coef_t farkasDifficulty;
+extern Global_Var_ID coefficient_of_constant_term;
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/include/omega/hull.h b/omegalib/omega/include/omega/hull.h
new file mode 100644
index 0000000..928d0c6
--- /dev/null
+++ b/omegalib/omega/include/omega/hull.h
@@ -0,0 +1,89 @@
+#ifndef Already_Included_Hull
+#define Already_Included_Hull
+
+#include <omega/farkas.h>
+
+namespace omega {
+
+Relation SimpleHull(const Relation &R, bool allow_stride_constraint = false, bool allow_irregular_constraint = false);
+Relation SimpleHull(const std::vector<Relation> &Rs, bool allow_stride_constraint = false, bool allow_irregular_constraint = false);
+
+
+// All of the following first call approximate on R to
+// eliminate any wildcards and strides.
+
+// x in Convex Hull of R
+// iff
+// exist a_i, y_i s.t.
+// x = Sum_i a_i y_i s.t.
+// forall i, y_i in R
+// forall i, a_i >=0
+// sum_i a_i = 1
+Relation ConvexHull(NOT_CONST Relation &R);
+
+// DecoupledConvexHull is the same as ConvexHull,
+// except that it only finds constraints that involve
+// both variables x&y if there is a constraint
+// that involves both x&y in one of the conjuncts
+// of R.
+Relation DecoupledConvexHull(NOT_CONST Relation &R);
+
+// The affine hull just consists of equality constraints
+// but is otherwise the tightest hull on R.
+// x in Affine Hull of R
+// iff
+// exist a_i, y_i s.t.
+// x = Sum_i a_i y_i s.t.
+// forall i, y_i in R
+// sum_i a_i = 1
+Relation AffineHull(NOT_CONST Relation &R);
+
+// x in Linear Hull of R
+// iff
+// exist a_i, y_i s.t.
+// x = Sum_i a_i y_i s.t.
+// forall i, y_i in R
+Relation LinearHull(NOT_CONST Relation &R);
+
+// The conic hull is the tighest cone that contains R
+// x in Conic Hull of R.
+// iff
+// exist a_i, y_i s.t.
+// x = Sum_i a_i y_i s.t.
+// forall i, y_i in R
+// forall i, a_i >=0
+Relation ConicHull(NOT_CONST Relation &R);
+
+// RectHull includes readily-available constraints from relation
+// that can be part of hull, plus rectangular bounds calculated
+// from input/output/set variables' range.
+Relation RectHull(NOT_CONST Relation &Rel);
+
+// A constraint is in the result of QuickHull only if it appears in one of
+// the relations and is directly implied by a single constraint in each of
+// the other relations.
+Relation QuickHull(Relation &R); // deprecated
+Relation QuickHull(Tuple<Relation> &Rs); // deprecated
+
+Relation FastTightHull(NOT_CONST Relation &input_R,
+ NOT_CONST Relation &input_H);
+Relation Hull(NOT_CONST Relation &R,
+ bool stridesAllowed = false,
+ int effort=1,
+ NOT_CONST Relation &knownHull = Relation::Null()
+ );
+Relation Hull(Tuple<Relation> &Rs,
+ const std::vector<bool> &validMask,
+ int effort = 1,
+ bool stridesAllowed = false,
+ NOT_CONST Relation &knownHull = Relation::Null());
+
+// If a union of several conjuncts is a convex, their union
+// representaition can be simplified by their convex hull.
+Relation ConvexRepresentation(NOT_CONST Relation &R);
+Relation CheckForConvexPairs(NOT_CONST Relation &S); // deprecated
+Relation CheckForConvexRepresentation(NOT_CONST Relation &R_In); // deprecated
+
+}
+
+#endif
diff --git a/omegalib/omega/include/omega/omega_core/debugging.h b/omegalib/omega/include/omega/omega_core/debugging.h
new file mode 100644
index 0000000..e217ae9
--- /dev/null
+++ b/omegalib/omega/include/omega/omega_core/debugging.h
@@ -0,0 +1,30 @@
+#if !defined(Already_included_debugging)
+#define Already_included_debugging
+
+// Debugging flags. Can set any of these.
+
+#include <stdio.h>
+#include <ctype.h>
+
+namespace omega {
+
+
+
+extern int omega_core_debug;
+extern int pres_debug;
+extern int relation_debug;
+extern int closure_presburger_debug;
+extern int hull_debug;
+extern int farkas_debug;
+extern int code_gen_debug;
+
+enum negation_control { any_negation, one_geq_or_eq, one_geq_or_stride };
+extern negation_control pres_legal_negations;
+
+#if defined STUDY_EVACUATIONS
+extern int evac_debug;
+#endif
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/include/omega/omega_core/oc.h b/omegalib/omega/include/omega/omega_core/oc.h
new file mode 100644
index 0000000..e4f5444
--- /dev/null
+++ b/omegalib/omega/include/omega/omega_core/oc.h
@@ -0,0 +1,350 @@
+#ifndef Already_Included_OC
+#define Already_Included_OC 1
+
+#include <stdio.h>
+#include <string>
+#include <basic/util.h>
+#include <omega/omega_core/debugging.h>
+#include <basic/Tuple.h>
+
+namespace omega {
+
+// Manu:: commented the line below -- fortran bug workaround
+//#define maxVars 256 /* original 56, increased by chun */
+#define maxVars 100
+
+extern int maxGEQs;
+extern int maxEQs;
+
+// Manu:: commented the lines below -- fortran bug workaround
+//const int maxmaxGEQs = 2048; // original 512, increaded by chun
+//const int maxmaxEQs = 512; // original 256, increased by chun
+const int maxmaxGEQs = 512;
+const int maxmaxEQs = 256;
+
+/* #if ! defined maxmaxGEQs */
+/* #define maxmaxGEQs 2048 /\* original 512, increaded by chun *\/ */
+/* #endif */
+/* #if ! defined maxmaxEQs */
+/* #define maxmaxEQs 512 /\* original 256, increased by chun *\/ */
+/* #endif */
+
+
+#if 0
+#if ! defined Already_Included_Portable
+typedef unsigned char bool; /* what a gross thing to do */
+#endif
+#endif
+
+typedef int EqnKey;
+
+enum {EQ_BLACK = 0, EQ_RED = 1};
+enum {OC_SOLVE_UNKNOWN = 2, OC_SOLVE_SIMPLIFY = 3};
+
+struct eqn {
+ EqnKey key;
+ coef_t touched; // see oc_simple.c
+ int color;
+ int essential;
+ int varCount;
+ coef_t coef[maxVars + 1];
+};
+
+// typedef eqn * Eqn;
+enum redType {notRed=0, redEQ, redGEQ, redLEQ, redStride};
+enum redCheck {noRed=0, redFalse, redConstraints};
+enum normalizeReturnType {normalize_false, normalize_uncoupled,
+ normalize_coupled};
+
+extern char wildName[200][20];
+
+extern FILE *outputFile; /* printProblem writes its output to this file */
+#define doTrace (trace && TRACE)
+#define isRed(e) (desiredResult == OC_SOLVE_SIMPLIFY && (e)->color)
+// #define eqnncpy(e1,e2,s) {int *p00,*q00,*r00; p00 = (int *)(e1); q00 = (int *)(e2); r00 = &p00[headerWords+1+s]; while(p00 < r00) *p00++ = *q00++; }
+// #define eqncpy(e1,e2) eqnncpy(e1,e2,nVars)
+// #define eqnnzero(e,s) {int *p00,*r00; p00 = (int *)(e); r00 = &p00[headerWords+1+(s)]; while(p00 < r00) *p00++ = 0;}
+// #define eqnzero(e) eqnnzero(e,nVars)
+
+//void eqnncpy(eqn *dest, eqn *src, int);
+//void eqnnzero(eqn *e, int);
+
+inline void eqnncpy(eqn *dest, eqn *src, int nVars) {
+ dest->key = src->key;
+ dest->touched = src->touched;
+ dest->color = src->color;
+ dest->essential = src->essential;
+ dest->varCount = src->varCount;
+ for (int i = 0; i <= nVars; i++)
+ dest->coef[i] = src->coef[i];
+}
+
+
+inline void eqnnzero(eqn *e, int nVars) {
+ e->key = 0;
+ e->touched = 0;
+ e->color = EQ_BLACK;
+ e->essential = 0;
+ e->varCount = 0;
+ for (int i = 0; i <= nVars; i++)
+ e->coef[i] = 0;
+}
+
+extern int mayBeRed;
+
+#ifdef SPEED
+#define TRACE 0
+#define DBUG 0
+#define DEBUG 0
+#else
+#define TRACE (omega_core_debug)
+#define DBUG (omega_core_debug > 1)
+#define DEBUG (omega_core_debug > 2)
+#endif
+
+
+class Memory {
+public:
+ int length;
+ coef_t stride;
+ redType kind;
+ coef_t constantTerm;
+ coef_t coef[maxVars + 1];
+ int var[maxVars + 1];
+};
+
+/* #define headerWords ((4*sizeof(int) + sizeof(coef_t))/sizeof(int)) */
+
+void check_number_EQs(int);
+void check_number_GEQs(int);
+extern eqn SUBs[];
+extern Memory redMemory[];
+
+class Problem {
+public:
+ short nVars, safeVars;
+ short nEQs, nGEQs,nSUBs,nMemories,allocEQs,allocGEQs;
+ short varsOfInterest;
+ bool variablesInitialized;
+ bool variablesFreed;
+ short var[maxVars+2];
+ short forwardingAddress[maxVars+2];
+ // int variableColor[maxVars+2];
+ int hashVersion;
+ const char *(*get_var_name)(unsigned int var, void *args);
+ void *getVarNameArgs;
+ eqn *GEQs;
+ eqn *EQs;
+ bool isTemporary;
+
+ Problem(int in_eqs=0, int in_geqs=0);
+ Problem(const Problem &);
+ ~Problem();
+ Problem & operator=(const Problem &);
+
+/* Allocation parameters and functions */
+
+ static const int min_alloc,first_alloc_pad;
+ int padEQs(int oldalloc, int newreq) {
+ check_number_EQs(newreq);
+ return min((newreq < 2*oldalloc ? 2*oldalloc : 2*newreq),maxmaxEQs);
+ }
+ int padGEQs(int oldalloc, int newreq) {
+ check_number_GEQs(newreq);
+ return min((newreq < 2*oldalloc ? 2*oldalloc : 2*newreq),maxmaxGEQs);
+ }
+ int padEQs(int newreq) {
+ check_number_EQs(newreq);
+ return min(max(newreq+first_alloc_pad,min_alloc), maxmaxEQs);
+ }
+ int padGEQs(int newreq) {
+ check_number_GEQs(newreq);
+ return min(max(newreq+first_alloc_pad,min_alloc), maxmaxGEQs);
+ }
+
+
+ void zeroVariable(int i);
+
+ void putVariablesInStandardOrder();
+ void noteEssential(int onlyWildcards);
+ int findDifference(int e, int &v1, int &v2);
+ int chainKill(int color,int onlyWildcards);
+
+ int newGEQ();
+ int newEQ();
+ int newSUB(){
+ return nSUBs++;
+ }
+
+
+ void initializeProblem();
+ void initializeVariables() const;
+ void printProblem(int debug = 1) const;
+ void printSub(int v) const;
+ std::string print_sub_to_string(int v) const;
+ void clearSubs();
+ void printRedEquations() const;
+ int countRedEquations() const;
+ int countRedGEQs() const;
+ int countRedEQs() const;
+ int countRedSUBs() const;
+ void difficulty(int &numberNZs, coef_t &maxMinAbsCoef, coef_t &sumMinAbsCoef) const;
+ int prettyPrintProblem() const;
+ std::string prettyPrintProblemToString() const;
+ int prettyPrintRedEquations() const;
+ int simplifyProblem(int verify, int subs, int redundantElimination);
+ int simplifyProblem();
+ int simplifyAndVerifyProblem();
+ int simplifyApproximate(bool strides_allowed);
+ void coalesce();
+ void partialElimination();
+ void unprotectVariable(int var);
+ void negateGEQ(int);
+ void convertEQstoGEQs(bool excludeStrides);
+ void convertEQtoGEQs(int eq);
+ void nameWildcard(int i);
+ void useWildNames();
+ void ordered_elimination(int symbolic);
+ int eliminateRedundant (bool expensive);
+ void eliminateRed(bool expensive);
+ void constrainVariableSign(int color, int var, int sign);
+ void constrainVariableValue(int color, int var, int value);
+ void query_difference(int v1, int v2, coef_t &lowerBound, coef_t &upperBound, bool &guaranteed);
+ int solve(int desiredResult);
+ std::string print_term_to_string(const eqn *e, int c) const;
+ void printTerm(const eqn * e, int c) const;
+ std::string printEqnToString(const eqn * e, int test, int extra) const;
+ void sprintEqn(char *str, const eqn * e, int is_geq,int extra) const;
+ void printEqn(const eqn * e, int is_geq, int extra) const;
+ void printEQ(const eqn *e) const {printEqn(e,0,0); }
+ std::string print_EQ_to_string(const eqn *e) const {return printEqnToString(e,0,0);}
+ std::string print_GEQ_to_string(const eqn *e) const {return printEqnToString(e,1,0);}
+ void printGEQ(const eqn *e) const {printEqn(e,1,0); }
+ void printGEQextra(const eqn *e) const {printEqn(e,1,1); }
+ void printSubstitution(int s) const;
+ void printVars(int debug = 1) const;
+ void swapVars(int i, int j);
+ void reverseProtectedVariables();
+ redCheck redSimplifyProblem(int effort, int computeGist);
+
+ // calculate value of variable mod integer from set of equations -- by chun 12/14/2006
+ coef_t query_variable_mod(int v, coef_t factor, int color=EQ_BLACK, int nModularEQs=0, int nModularVars=0) const;
+ coef_t query_variable_mod(int v, coef_t factor, int color, int nModularEQs, int nModularVars, Tuple<bool> &working_on) const; // helper function
+
+ int queryVariable(int i, coef_t *lowerBound, coef_t *upperBound);
+ int query_variable_bounds(int i, coef_t *l, coef_t *u);
+ void queryCoupledVariable(int i, coef_t *l, coef_t *u, int *couldBeZero, coef_t lowerBound, coef_t upperBound);
+ int queryVariableSigns(int i, int dd_lt, int dd_eq, int dd_gt, coef_t lowerBound, coef_t upperBound, bool *distKnown, coef_t *dist);
+ void addingEqualityConstraint(int e);
+ normalizeReturnType normalize();
+ void normalize_ext();
+ void cleanoutWildcards();
+ void substitute(eqn *sub, int i, coef_t c);
+ void deleteVariable( int i);
+ void deleteBlack();
+ int addNewProtectedWildcard();
+ int addNewUnprotectedWildcard();
+ int protectWildcard( int i);
+ void doMod( coef_t factor, int e, int j);
+ void freeEliminations( int fv);
+ int verifyProblem();
+ void resurrectSubs();
+ int solveEQ();
+ int combineToTighten() ;
+ int quickKill(int onlyWildcards, bool desperate = false);
+ int expensiveEqualityCheck();
+ int expensiveRedKill();
+ int expensiveKill();
+ int smoothWeirdEquations();
+ void quickRedKill(int computeGist);
+ void chainUnprotect();
+ void freeRedEliminations();
+ void doElimination( int e, int i);
+ void analyzeElimination(
+ int &v,
+ int &darkConstraints,
+ int &darkShadowFeasible,
+ int &unit,
+ coef_t &parallelSplinters,
+ coef_t &disjointSplinters,
+ coef_t &lbSplinters,
+ coef_t &ubSplinters,
+ int &parallelLB);
+ int parallelSplinter(int e, int diff, int desiredResult);
+ int solveGEQ( int desiredResult);
+ void setInternals();
+ void setExternals();
+ int reduceProblem();
+ void problem_merge(Problem &);
+ void deleteRed();
+ void turnRedBlack();
+ void checkGistInvariant() const;
+ void check() const;
+ coef_t checkSum() const;
+ void rememberRedConstraint(eqn *e, redType type, coef_t stride);
+ void recallRedMemories();
+ void simplifyStrideConstraints();
+ const char * orgVariable(int i) const {
+ return ((i == 0) ? // cfront likes this form better
+ "1" :
+ ((i < 0) ?
+ wildName[-i] :
+ (*get_var_name)(i,getVarNameArgs)));
+ };
+ const char * variable(int i) const {
+ return orgVariable(var[i]) ;
+ };
+
+ void deleteGEQ(int e) {
+ if (DEBUG) {
+ fprintf(outputFile,"Deleting %d (last:%d): ",e,nGEQs-1);
+ printGEQ(&GEQs[e]);
+ fprintf(outputFile,"\n");
+ };
+ if (e < nGEQs-1)
+ eqnncpy (&GEQs[e], &GEQs[nGEQs - 1],(nVars));
+ nGEQs--;
+ };
+ void deleteEQ(int e) {
+ if (DEBUG) {
+ fprintf(outputFile,"Deleting %d (last:%d): ",e,nEQs-1);
+ printGEQ(&EQs[e]);
+ fprintf(outputFile,"\n");
+ };
+ if (e < nEQs-1)
+ eqnncpy (&EQs[e], &EQs[nEQs - 1],(nVars));
+ nEQs--;
+ };
+
+};
+
+
+
+/* #define UNKNOWN 2 */
+/* #define SIMPLIFY 3 */
+/* #define _red 1 */
+/* #define black 0 */
+
+
+extern int print_in_code_gen_style;
+
+
+void initializeOmega(void);
+
+
+/* set extra to 0 for normal use */
+int singleVarGEQ(eqn *e);
+
+void setPrintLevel(int level);
+
+void printHeader();
+
+void setOutputFile(FILE *file);
+
+extern void check_number_EQs(int nEQs);
+extern void check_number_GEQs(int nGEQs);
+extern void checkVars(int nVars);
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/include/omega/omega_core/oc_i.h b/omegalib/omega/include/omega/omega_core/oc_i.h
new file mode 100644
index 0000000..9533a40
--- /dev/null
+++ b/omegalib/omega/include/omega/omega_core/oc_i.h
@@ -0,0 +1,79 @@
+#if !defined(Already_included_oc_i)
+#define Already_included_oc_i
+
+#include <basic/util.h>
+#include <omega/omega_core/oc.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string>
+#include <vector>
+
+namespace omega {
+
+#define maxWildcards 18
+
+extern int findingImplicitEqualities;
+extern int firstCheckForRedundantEquations;
+extern int use_ugly_names;
+extern int doItAgain;
+extern int newVar;
+extern int conservative;
+extern FILE *outputFile; /* printProblem writes its output to this file */
+extern int nextWildcard;
+extern int trace;
+extern int depth;
+extern int packing[maxVars];
+extern int headerLevel;
+extern int inApproximateMode;
+extern int inStridesAllowedMode;
+extern int addingOuterEqualities;
+extern int outerColor;
+
+const int keyMult = 31;
+const int hashTableSize =5*maxmaxGEQs;
+const int maxKeys = 8*maxmaxGEQs;
+extern int hashVersion;
+extern eqn hashMaster[hashTableSize];
+extern int fastLookup[maxKeys*2];
+extern int nextKey;
+
+extern int reduceWithSubs;
+extern int pleaseNoEqualitiesInSimplifiedProblems;
+
+#define noProblem ((Problem *) 0)
+
+extern Problem *originalProblem;
+int checkIfSingleVar(eqn *e, int i);
+/* Solve e = factor alpha for x_j and substitute */
+
+void negateCoefficients(eqn * eqn, int nV);
+
+extern int omegaInitialized;
+extern Problem full_answer, context,redProblem;
+
+#if defined BRAIN_DAMAGED_FREE
+static inline void free(const Problem *p)
+{
+ free((char *)p);
+}
+#endif
+
+#if defined NDEBUG
+#define CHECK_FOR_DUPLICATE_VARIABLE_NAMES
+#else
+#define CHECK_FOR_DUPLICATE_VARIABLE_NAMES \
+ { \
+ std::vector<std::string> name(nVars); \
+ for(int i=1; i<=nVars; i++) { \
+ name[i-1] = variable(i); \
+ assert(!name[i-1].empty()); \
+ for(int j=1; j<i; j++) \
+ assert(!(name[i-1] == name[j-1])); \
+ } \
+ }
+#endif
+
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/include/omega/omega_i.h b/omegalib/omega/include/omega/omega_i.h
new file mode 100644
index 0000000..e5d9230
--- /dev/null
+++ b/omegalib/omega/include/omega/omega_i.h
@@ -0,0 +1,30 @@
+#if ! defined _omega_i_h
+#define _omega_i_h 1
+
+#include <omega/pres_var.h>
+
+namespace omega {
+
+/* #define Assert(c,t) if(!(c)) PresErrAssert(t) */
+/* void PresErrAssert(const char *t); */
+
+extern Rel_Body null_rel;
+
+extern int skip_finalization_check;
+// extern int skip_set_checks;
+
+// Global input and output variable tuples.
+
+extern Global_Input_Output_Tuple input_vars;
+extern Global_Input_Output_Tuple output_vars;
+extern Global_Input_Output_Tuple &set_vars;
+
+} // namespace
+
+#if ! defined DONT_INCLUDE_TEMPLATE_CODE
+// with g++258, everything will need to make Tuple<Relation>, as a
+// function taking it as an argument is a friend of lots of classes
+#include <omega/Relation.h>
+#endif
+
+#endif
diff --git a/omegalib/omega/include/omega/pres_cmpr.h b/omegalib/omega/include/omega/pres_cmpr.h
new file mode 100644
index 0000000..fb3e6f0
--- /dev/null
+++ b/omegalib/omega/include/omega/pres_cmpr.h
@@ -0,0 +1,49 @@
+#if ! defined _pres_cmpr_h
+#define _pres_cmpr_h 1
+
+#include <omega/omega_core/oc.h>
+
+namespace omega {
+
+//
+// Compressed problem: rectangular non-0 cut from the big problem.
+//
+class Comp_Constraints {
+public:
+ Comp_Constraints(eqn *constrs, int no_constrs, int no_vars);
+ void UncompressConstr(eqn *constrs, short &pn_constrs);
+ ~Comp_Constraints();
+ bool no_constraints() const
+ { return n_constrs == 0; }
+ int n_constraints() const
+ { return n_constrs; }
+
+protected:
+ inline int coef_index(int e, int v)
+ {return e*(n_vars+1) + v;}
+
+private:
+ int n_constrs;
+ int n_vars;
+ coef_t *coefs;
+};
+
+class Comp_Problem {
+public:
+ Comp_Problem(Problem *problem);
+ Problem *UncompressProblem();
+ bool no_constraints() const
+ { return eqs.no_constraints() && geqs.no_constraints(); }
+
+private:
+/* === data === */
+ int _nVars, _safeVars;
+ const char *(*_get_var_name)(unsigned int var, void *args);
+ void *_getVarNameArgs;
+ Comp_Constraints eqs;
+ Comp_Constraints geqs;
+};
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/include/omega/pres_cnstr.h b/omegalib/omega/include/omega/pres_cnstr.h
new file mode 100644
index 0000000..7b2d98d
--- /dev/null
+++ b/omegalib/omega/include/omega/pres_cnstr.h
@@ -0,0 +1,192 @@
+#if ! defined _pres_cnstr_h
+#define _pres_cnstr_h 1
+
+#include <omega/pres_var.h>
+#include <vector>
+
+namespace omega {
+
+//
+// Constraint handles
+//
+
+
+
+void copy_constraint(Constraint_Handle H, const Constraint_Handle initial);
+
+class Constraint_Handle {
+public:
+ Constraint_Handle() {}
+ virtual ~Constraint_Handle() {}
+
+ void update_coef(Variable_ID, coef_t delta);
+ void update_const(coef_t delta);
+ coef_t get_coef(Variable_ID v) const;
+ coef_t get_const() const;
+ bool has_wildcards() const;
+ int max_tuple_pos() const;
+ int min_tuple_pos() const;
+ bool is_const(Variable_ID v);
+ bool is_const_except_for_global(Variable_ID v);
+
+ virtual std::string print_to_string() const;
+ virtual std::string print_term_to_string() const;
+
+ Variable_ID get_local(const Global_Var_ID G);
+ Variable_ID get_local(const Global_Var_ID G, Argument_Tuple of);
+ // not sure that the second one can be used in a meaningful
+ // way if the conjunct is in multiple relations
+
+ void finalize();
+ void multiply(int multiplier);
+ Rel_Body *relation() const;
+
+
+protected:
+ Conjunct *c;
+ eqn **eqns;
+ int e;
+
+ friend class Constr_Vars_Iter;
+ friend class Constraint_Iterator;
+
+ Constraint_Handle(Conjunct *, eqn **, int);
+
+#if defined PROTECTED_DOESNT_WORK
+ friend class EQ_Handle;
+ friend class GEQ_Handle;
+#endif
+
+ void update_coef_during_simplify(Variable_ID, coef_t delta);
+ void update_const_during_simplify(coef_t delta);
+ coef_t get_const_during_simplify() const;
+ coef_t get_coef_during_simplify(Variable_ID v) const;
+
+
+public:
+ friend class Conjunct; // assert_leading_info updates coef's
+ // as does move_UFS_to_input
+ friend class DNF; // and DNF::make_level_carried_to
+
+ friend void copy_constraint(Constraint_Handle H,
+ const Constraint_Handle initial);
+ // copy_constraint does updates and gets at c and e
+
+};
+
+class GEQ_Handle : public Constraint_Handle {
+public:
+ inline GEQ_Handle() {}
+
+ virtual std::string print_to_string() const;
+ virtual std::string print_term_to_string() const;
+ bool operator==(const Constraint_Handle &that);
+
+ void negate();
+
+private:
+ friend class Conjunct;
+ friend class GEQ_Iterator;
+
+ GEQ_Handle(Conjunct *, int);
+};
+
+
+class EQ_Handle : public Constraint_Handle {
+public:
+ inline EQ_Handle() {}
+
+ virtual std::string print_to_string() const;
+ virtual std::string print_term_to_string() const;
+ bool operator==(const Constraint_Handle &that);
+
+private:
+ friend class Conjunct;
+ friend class EQ_Iterator;
+
+ EQ_Handle(Conjunct *, int);
+};
+
+
+//
+// Conjuct iterators -- for querying resulting DNF.
+//
+class Constraint_Iterator : public Generator<Constraint_Handle> {
+public:
+ Constraint_Iterator(Conjunct *);
+ int live() const;
+ void operator++(int);
+ void operator++();
+ Constraint_Handle operator* ();
+ Constraint_Handle operator* () const;
+
+private:
+ Conjunct *c;
+ int current,last;
+ eqn **eqns;
+};
+
+
+class EQ_Iterator : public Generator<EQ_Handle> {
+public:
+ EQ_Iterator(Conjunct *);
+ int live() const;
+ void operator++(int);
+ void operator++();
+ EQ_Handle operator* ();
+ EQ_Handle operator* () const;
+
+private:
+ Conjunct *c;
+ int current, last;
+};
+
+
+class GEQ_Iterator : public Generator<GEQ_Handle> {
+public:
+ GEQ_Iterator(Conjunct *);
+ int live() const;
+ void operator++(int);
+ void operator++();
+ GEQ_Handle operator* ();
+ GEQ_Handle operator* () const;
+
+private:
+ Conjunct *c;
+ int current, last;
+};
+
+
+//
+// Variables of constraint iterator.
+//
+struct Variable_Info {
+ Variable_ID var;
+ coef_t coef;
+ Variable_Info(Variable_ID _var, coef_t _coef)
+ { var = _var; coef = _coef; }
+};
+
+class Constr_Vars_Iter : public Generator<Variable_Info> {
+public:
+ Constr_Vars_Iter(const Constraint_Handle &ch, bool _wild_only = false);
+ int live() const;
+ void operator++(int);
+ void operator++();
+ Variable_Info operator*() const;
+
+ Variable_ID curr_var() const;
+ coef_t curr_coef() const;
+
+private:
+ eqn **eqns;
+ int e;
+ Problem *prob;
+ Variable_ID_Tuple &vars;
+ bool wild_only;
+ int current;
+};
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/include/omega/pres_conj.h b/omegalib/omega/include/omega/pres_conj.h
new file mode 100644
index 0000000..ea10a2c
--- /dev/null
+++ b/omegalib/omega/include/omega/pres_conj.h
@@ -0,0 +1,299 @@
+#if ! defined _pres_conj_h
+#define _pres_conj_h 1
+
+#include <limits.h>
+#include <omega/pres_decl.h>
+#include <omega/pres_logic.h>
+#include <omega/pres_cnstr.h>
+
+namespace omega {
+
+//
+// Conjunct
+//
+// About variables in Conjunct:
+// All varaibles appear in exactly one declaration.
+// All variables used in Conjunct are referenced in mappedVars.
+// Wildcard variables are referenced both in mappedVars and in myLocals,
+// since they are declared in the conjunct.
+// All other variables are declared at the levels above.
+// Column number is:
+// in forwardingAddress in Problem if variablesInitialized is set,
+// equal to position of Variable_ID in mappedVars list otherwise.
+//
+
+class Conjunct : public F_Declaration {
+public:
+ Constraint_Iterator constraints();
+ Variable_ID_Tuple *variables();
+ EQ_Iterator EQs();
+ GEQ_Iterator GEQs();
+ inline int n_EQs() { return problem->nEQs; }
+ inline int n_GEQs() { return problem->nGEQs; }
+
+ void promise_that_ub_solutions_exist(Relation &R);
+
+ inline Node_Type node_type() {return Op_Conjunct;}
+
+ inline int is_true() {return problem->nEQs==0 && problem->nGEQs==0
+ && exact;}
+
+ void query_difference(Variable_ID v1, Variable_ID v2,
+ coef_t &lowerBound, coef_t &upperBound, bool &guaranteed);
+ void query_variable_bounds(Variable_ID v, coef_t &lowerBound, coef_t &upperBound);
+ coef_t query_variable_mod(Variable_ID v, coef_t factor);
+ bool query_variable_used(Variable_ID v);
+
+ int countNonzeros() const {
+ int numberNZs;
+ coef_t maxCoef, SumAbsCoef;
+ problem->difficulty(numberNZs,maxCoef,SumAbsCoef);
+ return numberNZs;
+ }
+
+ void difficulty(int &numberNZs, coef_t &maxCoef, coef_t &SumAbsCoef) const {
+ problem->difficulty(numberNZs,maxCoef,SumAbsCoef);
+ }
+
+ int query_guaranteed_leading_0s() {
+ count_leading_0s();
+ return guaranteed_leading_0s;
+ }
+
+ int query_possible_leading_0s() {
+ count_leading_0s();
+ return possible_leading_0s;
+ }
+
+ int query_leading_dir() {
+ count_leading_0s();
+ return leading_dir;
+ }
+
+ void calculate_dimensions(Relation &R, int &ndim_all, int &ndim_domain);
+ int max_ufs_arity_of_set();
+ int max_ufs_arity_of_in();
+ int max_ufs_arity_of_out();
+
+ int rank();
+
+ ~Conjunct();
+
+ bool is_unknown() const;
+ inline bool is_exact() const { return exact;}
+ inline bool is_inexact() const { return !exact;}
+ inline void make_inexact() { exact=false;}
+
+
+#if ! defined NDEBUG
+ void assert_leading_info();
+#else
+ void assert_leading_info() {}
+#endif
+
+
+ // PRINTING FUNCTIONS
+ void print(FILE *output_file);
+ void prefix_print(FILE *output_file, int debug = 1);
+ std::string print_to_string(int true_printed);
+ std::string print_EQ_to_string(eqn *e) { return problem->print_EQ_to_string(e); }
+ std::string print_GEQ_to_string(eqn *e) { return problem->print_GEQ_to_string(e); }
+ std::string print_EQ_to_string(int e)
+ { return problem->print_EQ_to_string(&(problem->EQs[e])); }
+ std::string print_GEQ_to_string(int e)
+ { return problem->print_GEQ_to_string(&(problem->GEQs[e])); }
+ std::string print_term_to_string(eqn *e) { return problem->print_term_to_string(e,1); }
+ std::string print_EQ_term_to_string(int e)
+ { return problem->print_term_to_string(&(problem->EQs[e]),1); }
+ std::string print_GEQ_term_to_string(int e)
+ { return problem->print_term_to_string(&(problem->GEQs[e]),1); }
+ std::string print_sub_to_string(int col) { return problem->print_sub_to_string(col); }
+
+private:
+
+ inline void interpret_unknown_as_true() { exact=true;}
+
+ friend Relation approx_closure(NOT_CONST Relation &r, int n);
+
+ virtual Conjunct *really_conjunct();
+
+
+ // create new constraints with all co-efficients 0
+ // These are public in F_And, use them from there.
+ EQ_Handle add_stride(int step, int preserves_level = 0);
+ EQ_Handle add_EQ(int preserves_level = 0);
+ GEQ_Handle add_GEQ(int preserves_level = 0);
+ EQ_Handle add_EQ(const Constraint_Handle &c, int preserves_level = 0);
+ GEQ_Handle add_GEQ(const Constraint_Handle &c, int preserves_level = 0);
+
+ friend class GEQ_Handle;
+ friend class EQ_Handle;
+ friend class Sub_Handle;
+ friend class Constraint_Handle;
+ friend class Constraint_Iterator;
+ friend class GEQ_Iterator;
+ friend class EQ_Iterator;
+ friend class Sub_Iterator;
+ friend class Constr_Vars_Iter;
+
+
+ // FUNCTIONS HAVING TO DO WITH BUILDING FORMULAS/DNFs
+ bool can_add_child();
+ void remap();
+ void beautify();
+ DNF* DNFize();
+ int priority();
+ virtual Conjunct *find_available_conjunct();
+ void finalize();
+
+ friend class DNF;
+
+
+
+ // CREATING CONJUNCTS
+ Conjunct();
+ Conjunct(Conjunct &);
+ Conjunct(Formula *, Rel_Body *);
+
+ friend class Formula; // add_conjunct (a private function) creates Conjuncts
+ friend class F_Not;
+ friend class F_Or;
+ // class F_And; is a friend below
+
+
+ // VARIOUS FUNCTIONS TO CREATE / WORK WITH VARIABLES
+ Variable_ID declare(Const_String s);
+ Variable_ID declare();
+ Variable_ID declare(Variable_ID v);
+
+ friend const char *get_var_name(unsigned int, void *);
+ void push_exists(Variable_ID_Tuple &S);
+ int get_column(Variable_ID);
+ int find_column(Variable_ID);
+ int map_to_column(Variable_ID);
+ void combine_columns();
+ void reorder();
+ void reorder_for_print(bool reverseOrder=false,
+ int first_pass_input=0,
+ int first_pass_output=0,
+ bool sort=false);
+
+ friend void remap_DNF_vars(Rel_Body *new_rel, Rel_Body *old_rel);
+
+ void localize_var(Variable_ID D);
+
+
+ // this creates variables in conjuncts for us:
+ friend int new_WC(Conjunct *nc, Problem *np);
+
+
+ // UFS/LEADING ZEROS STUFF
+
+ void move_UFS_to_input();
+
+ void count_leading_0s();
+ void invalidate_leading_info(int changed = -1);
+ void enforce_leading_info(int guaranteed, int possible, int dir);
+
+ void reverse_leading_dir_info();
+
+
+
+ // CONJUNCT SPECIFIC STUFF
+
+ void rm_color_constrs();
+ inline int N_protected() { return problem->safeVars; }
+
+
+ void ordered_elimination(int symLen) { problem->ordered_elimination(symLen);}
+ void convertEQstoGEQs(bool excludeStrides);
+
+ int cost();
+
+ inline Formula* copy(Formula *parent, Rel_Body *reln)
+ { return copy_conj_diff_relation(parent,reln); }
+ Conjunct* copy_conj_diff_relation(Formula *parent, Rel_Body *reln);
+ inline Conjunct* copy_conj_same_relation()
+ { return copy_conj_diff_relation(&(parent()), relation()); }
+ friend void internal_copy_conjunct(Conjunct* to, Conjunct* fr);
+ friend void copy_constraint(Constraint_Handle H,
+ const Constraint_Handle initial);
+
+#if defined STUDY_EVACUATIONS
+ // The core function of "evac.c" does lots of work with conjuncts:
+ friend bool check_subseq_n(Conjunct *c, Sequence<Variable_ID> &evac_from, Sequence<Variable_ID> &evac_to, int n_from, int n_to, int max_arity, int n, bool allow_offset);
+ friend void assert_subbed_syms(Conjunct *c);
+ friend bool check_affine(Conjunct *d, Sequence<Variable_ID> &evac_from, Sequence<Variable_ID> &evac_to, int n_from, int n_to, int max_arity);
+ friend evac study(Conjunct *C, Sequence<Variable_ID> &evac_from, Sequence<Variable_ID> &evac_to, int n_from, int n_to, int max_arity);
+#endif
+
+ // The relational ops tend to do lots of demented things to Conjuncts:
+ friend class Rel_Body;
+ friend_rel_ops;
+
+ // F_And sometimes absorbs conjuncts
+ friend class F_And;
+
+ // Various DNFize functions also get a the problem:
+
+ friend DNF* conj_and_not_dnf(Conjunct *pos_conj, DNF *neg_conjs, bool weak);
+ friend class F_Exists;
+
+ // Substitutions are a wrapper around a low-level Problem operation
+ friend class Substitutions;
+
+ // private functions to call problem functions
+ int simplifyProblem();
+ int simplifyProblem(int verify, int subs, int redundantElimination);
+ int redSimplifyProblem(int effort, int computeGist);
+
+ friend int simplify_conj(Conjunct* conj, int ver_sim, int elim_red, int color);
+ friend DNF* negate_conj(Conjunct* conj);
+ friend Conjunct* merge_conjs(Conjunct* conj1, Conjunct* conj2,
+ Merge_Action action, Rel_Body *body = 0);
+ friend void copy_conj_header(Conjunct* to, Conjunct* fr);
+
+
+ // === at last, the data ===
+
+ Variable_ID_Tuple mappedVars;
+
+ int n_open_constraints;
+ bool cols_ordered;
+ bool simplified;
+ bool verified;
+
+ int guaranteed_leading_0s; // -1 if unknown
+ int possible_leading_0s; // -1 if unknown
+ int leading_dir; // 0 if unknown, else +/- 1
+ int leading_dir_valid_and_known();
+
+ bool exact;
+
+ short r_constrs; // are redundant constraints eliminated?
+ Problem *problem;
+
+ bool is_compressed();
+ void compress();
+ void uncompress();
+
+ friend class Comp_Problem;
+ Comp_Problem *comp_problem;
+};
+
+
+/* === Misc. problem manipulation utilities === */
+
+const int CantBeNegated = INT_MAX-10;
+const int AvoidNegating = INT_MAX-11;
+
+void copy_column(Problem *tp, int to_col,
+ Problem *fp, int fr_col,
+ int start_EQ, int start_GEQ);
+void zero_column(Problem *tp, int to_col,
+ int start_EQ, int start_GEQ,
+ int no_EQs, int no_GEQs);
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/include/omega/pres_decl.h b/omegalib/omega/include/omega/pres_decl.h
new file mode 100644
index 0000000..7fec0bc
--- /dev/null
+++ b/omegalib/omega/include/omega/pres_decl.h
@@ -0,0 +1,55 @@
+#if ! defined _pres_decl_h
+#define _pres_decl_h 1
+
+#include <omega/pres_var.h>
+#include <omega/pres_form.h>
+#include <basic/Section.h>
+
+namespace omega {
+
+//
+// Base class for presburger formula nodes with variables
+//
+
+class F_Declaration : public Formula {
+public:
+ virtual Variable_ID declare(Const_String s)=0;
+ virtual Variable_ID declare()=0;
+ virtual Variable_ID declare(Variable_ID)=0;
+ virtual Section<Variable_ID> declare_tuple(int size);
+
+ void finalize();
+
+ inline Variable_ID_Tuple &locals() {return myLocals;}
+
+protected:
+ F_Declaration(Formula *, Rel_Body *);
+ F_Declaration(Formula *, Rel_Body *, Variable_ID_Tuple &);
+ ~F_Declaration();
+
+ Variable_ID do_declare(Const_String s, Var_Kind var_kind);
+
+ void prefix_print(FILE *output_file, int debug = 1);
+ void print(FILE *output_file);
+
+ void setup_names();
+ void setup_anonymous_wildcard_names();
+
+ Variable_ID_Tuple myLocals;
+ friend class F_Forall; // rearrange needs to access myLocals
+ friend class F_Or; // push_exists
+
+private:
+ virtual bool can_add_child();
+
+ int priority();
+
+ friend 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);
+};
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/include/omega/pres_dnf.h b/omegalib/omega/include/omega/pres_dnf.h
new file mode 100644
index 0000000..93d5942
--- /dev/null
+++ b/omegalib/omega/include/omega/pres_dnf.h
@@ -0,0 +1,87 @@
+#if ! defined _pres_dnf_h
+#define _pres_dnf_h 1
+
+#include <omega/pres_gen.h>
+
+namespace omega {
+
+//
+// Disjunctive Normal Form -- list of Conjuncts
+//
+class DNF {
+public:
+ void print(FILE *out_file);
+ void prefix_print(FILE *out_file, int debug = 1, bool parent_names_setup=false);
+
+ bool is_definitely_false() const;
+ bool is_definitely_true() const;
+ int length() const;
+
+ Conjunct *single_conjunct() const;
+ bool has_single_conjunct() const;
+ Conjunct *rm_first_conjunct();
+ void clear();
+ int query_guaranteed_leading_0s(int what_to_return_for_empty_dnf);
+ int query_possible_leading_0s(int what_to_return_for_empty_dnf);
+ int query_leading_dir();
+
+private:
+ // all DNFize functions need to access the dnf builders:
+ friend class F_And;
+ friend class F_Or;
+ friend class Conjunct;
+ friend DNF * negate_conj(Conjunct *);
+
+ friend class Rel_Body;
+ friend_rel_ops;
+
+ DNF();
+ ~DNF();
+
+ DNF* copy(Rel_Body *);
+
+ void simplify();
+ void make_level_carried_to(int level);
+ void count_leading_0s();
+
+ void add_conjunct(Conjunct*);
+ void join_DNF(DNF*);
+ void rm_conjunct(Conjunct *c);
+
+ void rm_redundant_conjs(int effort);
+ void rm_redundant_inexact_conjs();
+ void DNF_to_formula(Formula* root);
+
+
+ friend void remap_DNF_vars(Rel_Body *new_rel, Rel_Body *old_rel);
+ void remap();
+
+ void setup_names();
+
+ void remove_inexact_conj();
+
+ // These may need to get at the conjList itself:
+ friend DNF* DNF_and_DNF(DNF*, DNF*);
+ friend DNF* DNF_and_conj(DNF*, Conjunct*);
+ friend DNF* conj_and_not_dnf(Conjunct *pos_conj, DNF *neg_conjs, bool weak);
+
+ friend class DNF_Iterator;
+
+ List<Conjunct*> conjList;
+};
+
+DNF* conj_and_not_dnf(Conjunct *pos_conj, DNF *neg_conjs, bool weak=false);
+
+//
+// DNF iterator
+//
+class DNF_Iterator : public List_Iterator<Conjunct*> {
+public:
+ DNF_Iterator(DNF*dnf) : List_Iterator<Conjunct*>(dnf->conjList) {}
+ DNF_Iterator() {}
+ void curr_set(Conjunct *c) { *(*this) = c; }
+};
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/include/omega/pres_form.h b/omegalib/omega/include/omega/pres_form.h
new file mode 100644
index 0000000..ed3258e
--- /dev/null
+++ b/omegalib/omega/include/omega/pres_form.h
@@ -0,0 +1,112 @@
+#if ! defined _pres_form_h
+#define _pres_form_h 1
+
+#include <omega/pres_gen.h>
+
+namespace omega {
+
+typedef enum {Op_Relation, Op_Not, Op_And, Op_Or,
+ Op_Conjunct, Op_Forall, Op_Exists} Node_Type;
+
+
+//
+// Presburger Formula base class
+//
+
+class Formula {
+public:
+ virtual Node_Type node_type()=0;
+
+ F_Forall *add_forall();
+ F_Exists *add_exists();
+ virtual F_And *and_with();
+ F_And *add_and();
+ F_Or *add_or();
+ F_Not *add_not();
+ void add_unknown();
+
+ virtual void finalize();
+ virtual void print(FILE *output_file);
+
+ Rel_Body *relation() { return myRelation; }
+
+protected:
+ virtual ~Formula();
+private:
+ Formula(Formula *, Rel_Body *);
+
+ // The relational operations need to work with formula trees
+ friend class Relation;
+ friend_rel_ops;
+ // as do the functions that build DNF's
+ friend class DNF;
+ // or other parts of the tree
+ friend class Conjunct;
+ friend class F_Declaration;
+ friend class F_Exists;
+ friend class F_Forall;
+ friend class F_Or;
+ friend class F_And;
+ friend class F_Not;
+ friend class Rel_Body;
+
+
+ // Operations needed for manipulation of formula trees:
+
+ void remove_child(Formula *);
+ void replace_child(Formula *child, Formula *new_child);
+ virtual bool can_add_child();
+ void add_child(Formula *);
+
+ Conjunct *add_conjunct();
+ virtual Conjunct *find_available_conjunct() = 0;
+
+ virtual Formula *copy(Formula *parent, Rel_Body *reln);
+ F_Exists *add_exists(Variable_ID_Tuple &S);
+ virtual void push_exists(Variable_ID_Tuple &S);
+
+ // Accessor functions for tree building
+
+ List<Formula*> &children() {return myChildren;}
+ int n_children() const {return myChildren.length();}
+ const List<Formula*> &get_children() const {return myChildren;}
+ Formula &parent() {return *myParent;}
+ void set_parent(Formula *p) {myParent = p;}
+
+
+ virtual int priority();
+
+ void verify_tree(); // should be const, but iterators are used
+
+ virtual void reverse_leading_dir_info();
+ virtual void invalidate_leading_info(int changed = -1);
+ virtual void enforce_leading_info(int guaranteed, int possible, int dir);
+
+ virtual void remap();
+ virtual DNF* DNFize() = 0;
+ virtual void beautify();
+ virtual void rearrange();
+ virtual void setup_names();
+
+ virtual void print_separator(FILE *output_file);
+ virtual void combine_columns();
+ virtual void prefix_print(FILE *output_file, int debug = 1);
+ void print_head(FILE *output_file);
+
+ void set_relation(Rel_Body *r);
+ void set_parent(Formula *parent, Rel_Body *reln);
+
+ void assert_not_finalized();
+
+ virtual Conjunct *really_conjunct(); // until we get RTTI
+
+private:
+ List<Formula*> myChildren;
+ Formula *myParent;
+ Rel_Body *myRelation;
+
+};
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/include/omega/pres_gen.h b/omegalib/omega/include/omega/pres_gen.h
new file mode 100644
index 0000000..ba6a793
--- /dev/null
+++ b/omegalib/omega/include/omega/pres_gen.h
@@ -0,0 +1,192 @@
+#if ! defined _pres_gen_h
+#define _pres_gen_h 1
+
+#include <omega/omega_core/oc.h>
+#include <basic/ConstString.h>
+#include <basic/Iterator.h>
+#include <basic/List.h>
+#include <basic/Tuple.h>
+#include <assert.h>
+#include <stdlib.h>
+
+namespace omega {
+
+//
+// general presburger stuff thats needed everywhere
+//
+
+/* The following allows us to avoid warnings about passing
+ temporaries as non-const references. This is useful but
+ has suddenly become illegal. */
+
+#if !defined(LIE_ABOUT_CONST_TO_MAKE_ANSI_COMMITTEE_HAPPY)
+#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7))
+#define LIE_ABOUT_CONST_TO_MAKE_ANSI_COMMITTEE_HAPPY 1
+#else
+#define LIE_ABOUT_CONST_TO_MAKE_ANSI_COMMITTEE_HAPPY 0
+#endif
+#endif
+
+#if LIE_ABOUT_CONST_TO_MAKE_ANSI_COMMITTEE_HAPPY
+#define NOT_CONST const
+#else
+#define NOT_CONST
+#endif
+
+//
+// I/O and error processing and control flags (also in omega_core/debugging.h)
+//
+
+extern FILE *DebugFile;
+extern int pres_debug;
+
+extern int mega_total;
+extern int use_ugly_names;
+
+extern negation_control pres_legal_negations;
+
+
+//
+// Lots of things refer to each other,
+// so we forward declare these classes:
+//
+
+class Var_Decl;
+typedef enum {Input_Var, Set_Var = Input_Var, Output_Var,
+ Global_Var, Forall_Var, Exists_Var, Wildcard_Var} Var_Kind;
+class Global_Var_Decl;
+typedef enum {Unknown_Tuple = 0, Input_Tuple = 1, Output_Tuple = 2,
+ Set_Tuple = Input_Tuple } Argument_Tuple;
+
+class Constraint_Handle;
+class EQ_Handle;
+class GEQ_Handle;
+typedef EQ_Handle Stride_Handle;
+
+class Formula;
+class F_Declaration;
+class F_Forall;
+class F_Exists;
+class F_And;
+class F_Or;
+class F_Not;
+class Conjunct;
+class Relation;
+class Rel_Body;
+class DNF;
+class Mapping;
+class Omega_Var;
+class Coef_Var_Decl;
+
+typedef Var_Decl *Variable_ID;
+typedef Global_Var_Decl *Global_Var_ID;
+
+typedef Tuple<Variable_ID> Variable_ID_Tuple;
+typedef Sequence<Variable_ID> Variable_ID_Sequence; // use only for rvalues
+typedef Tuple_Iterator<Variable_ID> Variable_ID_Tuple_Iterator;
+typedef Tuple_Iterator<Variable_ID> Variable_ID_Iterator;
+
+typedef Variable_ID_Iterator Variable_Iterator;
+
+typedef enum {Comb_Id, Comb_And, Comb_Or, Comb_AndNot} Combine_Type;
+
+
+// things that are (hopefully) used only privately
+class Comp_Problem;
+class Comp_Constraints;
+
+// this has to be here rather than in pres_conj.h because
+// MergeConj has to be a friend of Constraint_Handle
+typedef enum {MERGE_REGULAR, MERGE_COMPOSE, MERGE_GIST} Merge_Action;
+
+
+// Conjunct can be exact or lower or upper bound.
+// For lower bound conjunct, the upper bound is assumed to be true;
+// For upper bound conjunct, the lower bound is assumed to be false
+
+typedef enum {EXACT_BOUND, UPPER_BOUND, LOWER_BOUND, UNSET_BOUND} Bound_Type;
+
+
+#if defined STUDY_EVACUATIONS
+typedef enum { in_to_out = 0, out_to_in = 1} which_way;
+
+enum evac { evac_trivial = 0,
+ evac_offset = 1,
+ evac_subseq = 2,
+ evac_offset_subseq = 3,
+// evac_permutation = ,
+ evac_affine = 4,
+ evac_nasty = 5 };
+
+extern char *evac_names[];
+
+#endif
+
+// the following list should be updated in sync with Relations.h
+
+#define friend_rel_ops \
+friend Relation Union(NOT_CONST Relation &r1, NOT_CONST Relation &r2); \
+friend Relation Intersection(NOT_CONST Relation &r1, NOT_CONST Relation &r2); \
+friend Relation After(NOT_CONST Relation &R, int carried_by, int new_output, int dir);\
+friend Relation Extend_Domain(NOT_CONST Relation &R); \
+friend Relation Extend_Domain(NOT_CONST Relation &R, int more); \
+friend Relation Extend_Range(NOT_CONST Relation &R); \
+friend Relation Extend_Range(NOT_CONST Relation &R, int more); \
+friend Relation Extend_Set(NOT_CONST Relation &R); \
+friend Relation Extend_Set(NOT_CONST Relation &R, int more); \
+friend Relation Restrict_Domain(NOT_CONST Relation &r1, NOT_CONST Relation &r2); \
+friend Relation Restrict_Range(NOT_CONST Relation &r1, NOT_CONST Relation &r2); \
+friend Relation Domain(NOT_CONST Relation &r); \
+friend Relation Range(NOT_CONST Relation &r); \
+friend Relation Cross_Product(NOT_CONST Relation &A, NOT_CONST Relation &B); \
+friend Relation Inverse(NOT_CONST Relation &r); \
+friend Relation Deltas(NOT_CONST Relation &R); \
+friend Relation Deltas(NOT_CONST Relation &R, int eq_no); \
+friend Relation DeltasToRelation(NOT_CONST Relation &R, int n_input, int n_output); \
+friend Relation Complement(NOT_CONST Relation &r); \
+friend Relation Project(NOT_CONST Relation &R, Global_Var_ID v); \
+friend Relation Project(NOT_CONST Relation &r, int pos, Var_Kind vkind); \
+friend Relation Project(NOT_CONST Relation &S, Sequence<Variable_ID> &s); \
+friend Relation Project_Sym(NOT_CONST Relation &R); \
+friend Relation Project_On_Sym(NOT_CONST Relation &R, NOT_CONST Relation &context); \
+friend Relation GistSingleConjunct(NOT_CONST Relation &R1, NOT_CONST Relation &R2, int effort); \
+friend Relation Gist(NOT_CONST Relation &R1, NOT_CONST Relation &R2, int effort); \
+friend Relation Difference(NOT_CONST Relation &r1, NOT_CONST Relation &r2); \
+friend Relation Approximate(NOT_CONST Relation &R, bool strides_allowed); \
+friend Relation Identity(int n_inp); \
+friend Relation Identity(NOT_CONST Relation &r); \
+friend bool do_subset_check(NOT_CONST Relation &r1, NOT_CONST Relation &r2); \
+friend bool Must_Be_Subset(NOT_CONST Relation &r1, NOT_CONST Relation &r2); \
+friend bool Might_Be_Subset(NOT_CONST Relation &r1, NOT_CONST Relation &r2); \
+friend bool May_Be_Subset(NOT_CONST Relation &r1, NOT_CONST Relation &r2); \
+friend bool Is_Obvious_Subset(NOT_CONST Relation &r1, NOT_CONST Relation &r2); \
+friend Relation Join(NOT_CONST Relation &G, NOT_CONST Relation &F); \
+friend Relation Composition(NOT_CONST Relation &F, NOT_CONST Relation &G); \
+friend bool can_do_exact_composition(NOT_CONST Relation &F, NOT_CONST Relation &G); \
+friend Relation EQs_to_GEQs(NOT_CONST Relation &, bool excludeStrides); \
+friend Relation Symbolic_Solution(NOT_CONST Relation &S); \
+friend Relation Symbolic_Solution(NOT_CONST Relation &S, Sequence<Variable_ID> &T); \
+friend Relation Sample_Solution(NOT_CONST Relation &S); \
+friend Relation Solution(NOT_CONST Relation &S, Sequence<Variable_ID> &T); \
+friend void MapRel1(Relation &inputRel, const Mapping &map, \
+ Combine_Type ctype, int number_input, \
+ int number_output, bool, bool); \
+friend Relation MapAndCombineRel2(Relation &R1, Relation &R2, \
+ const Mapping &mapping1, \
+ const Mapping &mapping2, \
+ Combine_Type ctype, \
+ int number_input, \
+ int number_output); \
+friend void align(Rel_Body *, Rel_Body *, F_Exists *, \
+ Formula *, const Mapping &, bool &, \
+ List<int> &, Variable_ID_Tuple &); \
+friend Relation Lower_Bound(NOT_CONST Relation &r); \
+friend Relation Upper_Bound(NOT_CONST Relation &r)
+
+
+// REMEMBER - THE LAST LINE OF THE MACRO SHOULD NOT HAVE A ;
+/* TransitiveClosure doesn't need to be in friend_rel_ops */
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/include/omega/pres_logic.h b/omegalib/omega/include/omega/pres_logic.h
new file mode 100644
index 0000000..27c4553
--- /dev/null
+++ b/omegalib/omega/include/omega/pres_logic.h
@@ -0,0 +1,90 @@
+#if ! defined _pres_logic_h
+#define _pres_logic_h 1
+
+#include <omega/pres_form.h>
+
+namespace omega {
+//
+// Presburger formula classes for logical operations: and, or not
+//
+
+class F_And : public Formula {
+public:
+ inline Node_Type node_type() {return Op_And;}
+
+ // "preserves level" should be 0 unless we know this will not
+ // change the "level" of the constraints - ie the number of
+ // leading corresponding in,out variables known to be equal
+ GEQ_Handle add_GEQ(int preserves_level = 0);
+ EQ_Handle add_EQ(int preserves_level = 0);
+ Stride_Handle add_stride(int step, int preserves_level = 0);
+ EQ_Handle add_EQ(const Constraint_Handle &c, int preserves_level = 0);
+ GEQ_Handle add_GEQ(const Constraint_Handle &c, int preserves_level = 0);
+
+ F_And *and_with();
+ void add_unknown();
+
+private:
+ friend class Formula; // add_and()
+ F_And(Formula *p, Rel_Body *r);
+
+private:
+ Formula *copy(Formula *parent, Rel_Body *reln);
+ virtual Conjunct *find_available_conjunct();
+ int priority();
+ void print_separator(FILE *output_file);
+ void prefix_print(FILE *output_file, int debug = 1);
+ void beautify();
+ DNF* DNFize();
+
+ Conjunct *pos_conj;
+};
+
+
+class F_Or : public Formula {
+public:
+ inline Node_Type node_type() {return Op_Or;}
+
+private:
+ friend class Formula; // add_or
+ F_Or(Formula *, Rel_Body *);
+
+private:
+ Formula *copy(Formula *parent, Rel_Body *reln);
+
+ virtual Conjunct *find_available_conjunct();
+ void print_separator(FILE *output_file);
+ void prefix_print(FILE *output_file, int debug = 1);
+ void beautify();
+ int priority();
+ DNF* DNFize();
+ void push_exists(Variable_ID_Tuple &S);
+};
+
+
+class F_Not : public Formula {
+public:
+ inline Node_Type node_type() {return Op_Not;}
+ void finalize();
+
+private:
+ friend class Formula;
+ F_Not(Formula *, Rel_Body *);
+
+private:
+ Formula *copy(Formula *parent, Rel_Body *reln);
+
+ virtual Conjunct *find_available_conjunct();
+ friend class F_Forall;
+ bool can_add_child();
+ void beautify();
+ void rearrange();
+ int priority();
+ DNF* DNFize();
+ void print(FILE *output_file);
+ void prefix_print(FILE *output_file, int debug = 1);
+};
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/include/omega/pres_quant.h b/omegalib/omega/include/omega/pres_quant.h
new file mode 100644
index 0000000..98c30df
--- /dev/null
+++ b/omegalib/omega/include/omega/pres_quant.h
@@ -0,0 +1,63 @@
+#if ! defined _pres_quant_h
+#define _pres_quant_h 1
+
+#include <omega/pres_decl.h>
+
+namespace omega {
+
+//
+// Presburger formula nodes for quantifiers
+//
+
+class F_Exists : public F_Declaration {
+public:
+ inline Node_Type node_type() {return Op_Exists;}
+ Variable_ID declare(Const_String s);
+ Variable_ID declare();
+ Variable_ID declare(Variable_ID v);
+ virtual void push_exists(Variable_ID_Tuple &S);
+
+protected:
+ friend class Formula;
+
+ F_Exists(Formula *, Rel_Body *);
+ F_Exists(Formula *, Rel_Body *, Variable_ID_Tuple &);
+
+private:
+ Formula *copy(Formula *parent, Rel_Body *reln);
+
+ virtual Conjunct *find_available_conjunct();
+ void print(FILE *output_file);
+ void prefix_print(FILE *output_file, int debug = 1);
+ void beautify();
+ void rearrange();
+ DNF* DNFize();
+};
+
+
+class F_Forall : public F_Declaration {
+public:
+ inline Node_Type node_type() {return Op_Forall;}
+ Variable_ID declare(Const_String s);
+ Variable_ID declare();
+ Variable_ID declare(Variable_ID v);
+
+protected:
+ friend class Formula;
+
+ F_Forall(Formula *, Rel_Body *);
+
+private:
+ Formula *copy(Formula *parent, Rel_Body *reln);
+
+ virtual Conjunct *find_available_conjunct();
+ void print(FILE *output_file);
+ void prefix_print(FILE *output_file, int debug = 1);
+ void beautify();
+ void rearrange();
+ DNF* DNFize();
+};
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/include/omega/pres_subs.h b/omegalib/omega/include/omega/pres_subs.h
new file mode 100644
index 0000000..8a9ee92
--- /dev/null
+++ b/omegalib/omega/include/omega/pres_subs.h
@@ -0,0 +1,88 @@
+#if !defined(pres_subs_h)
+#define pres_subs_h
+
+/* Interface to omega core's substitutions.
+
+ Creating an object of class Substitutions causes ordered elimination,
+ i.e. variables in the input and output tuples are substituted for by
+ functions of earlier variables. Could conceivablely create a more
+ flexible interface to orderedElimination if we developed a way to
+ specify the desired variable order.
+
+ This is not an entirely consistent interface, since Sub_Handles
+ shouldn't really permit update_coef on SUBs. It is not a real
+ problem since subs are now no longer part of a conjunct, but it is
+ a slightly odd situation.
+
+ Don't try to simplify r after performing orderedElimination.
+*/
+
+
+#include <omega/pres_gen.h>
+#include <omega/Relation.h>
+#include <omega/pres_conj.h>
+#include <omega/pres_cnstr.h>
+
+namespace omega {
+
+class Sub_Handle;
+class Sub_Iterator;
+
+class Substitutions {
+public:
+ Substitutions(Relation &input_R, Conjunct *input_c);
+ ~Substitutions();
+ Sub_Handle get_sub(Variable_ID v);
+ bool substituted(Variable_ID v);
+ bool sub_involves(Variable_ID v, Var_Kind kind);
+private:
+ friend class Sub_Iterator;
+ friend class Sub_Handle;
+ Relation *r;
+ Conjunct *c;
+ eqn *subs;
+ Variable_ID_Tuple subbed_vars;
+};
+
+
+//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+
+class Sub_Handle: public Constraint_Handle {
+public:
+ inline Sub_Handle() {}
+
+ virtual std::string print_to_string() const;
+ virtual std::string print_term_to_string() const;
+ Variable_ID variable() {return v;}
+
+private:
+ friend class Substitutions;
+ friend class Sub_Iterator;
+ Sub_Handle(Substitutions *, int, Variable_ID);
+// Sub_Handle(Substitutions *, int);
+
+ Variable_ID v;
+};
+
+//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+
+class Sub_Iterator : public Generator<Sub_Handle> {
+public:
+ Sub_Iterator(Substitutions *input_s): s(input_s), current(0),
+ last(s->c->problem->nSUBs-1) {}
+ int live() const;
+ void operator++(int);
+ void operator++();
+ Sub_Handle operator* ();
+ Sub_Handle operator* () const;
+
+private:
+ Substitutions *s;
+ int current, last;
+};
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/include/omega/pres_tree.h b/omegalib/omega/include/omega/pres_tree.h
new file mode 100644
index 0000000..ad78ad0
--- /dev/null
+++ b/omegalib/omega/include/omega/pres_tree.h
@@ -0,0 +1,15 @@
+#if ! defined _pres_tree_h
+#define _pres_tree_h 1
+
+//
+// Header to include if you need all the classes to build
+// a Presburger formula:
+// variables, constraints, nodes for logical operations & quantifiers
+//
+
+#include <omega/pres_var.h>
+#include <omega/pres_cnstr.h>
+#include <omega/pres_logic.h>
+#include <omega/pres_quant.h>
+
+#endif
diff --git a/omegalib/omega/include/omega/pres_var.h b/omegalib/omega/include/omega/pres_var.h
new file mode 100644
index 0000000..bf60dcb
--- /dev/null
+++ b/omegalib/omega/include/omega/pres_var.h
@@ -0,0 +1,230 @@
+#if ! defined _pres_var_h
+#define _pres_var_h 1
+
+#include <omega/pres_gen.h>
+#include <map>
+
+namespace omega {
+
+//
+// Variable declaration.
+// Variables are free or quantified.
+// Free variables are classified as input, output and global.
+// Quantified variables are classified as forall, exists and wildcard.
+// All global variables are functions symbols of (possibly 0) arguments
+// Local variables that correspond to >0-ary functions are identified
+// as functions of a prefix of the input, output, or both tuples
+//
+//
+// typedef enum {Input_Var, Output_Var, Set_Var,
+// Global_Var, Forall_Var, Exists_Var, Wildcard_Var} Var_Kind;
+
+typedef enum {Free_Var, Coef_Var, Bomega_Var} Global_Kind;
+
+// NOW IN PRES_GEN.H, as its used as an argument and can't
+// be forward declared:
+// typedef enum {Unknown_Tuple = 0, Input_Tuple = 1, Output_Tuple = 2,
+// Set_Tuple = Input_Tuple } Argument_Tuple;
+// Only Input, Output, and Set can be passed to get_local,
+// but the values 0 and 3 are also used internally.
+
+
+class Var_Decl {
+public:
+ inline Var_Kind kind() { return var_kind; }
+ int get_position();
+ Global_Var_ID get_global_var();
+ Argument_Tuple function_of(); // valid iff kind() == Global_var
+
+ Const_String base_name;
+ void name_variable(char *newname);
+
+ // The following should be used with care, as they are only valid
+ // after setup_names has been used on the relation containing this
+ // variable.
+ std::string name();
+ const char* char_name();
+ void set_kind(Var_Kind v) { var_kind = v; }
+
+ // Operation to allow the remap field to be used for
+ // union-find operations on variables.
+ // Be sure to reset the remap fields afterward
+ void UF_union(Variable_ID v);
+ Variable_ID UF_owner();
+
+private:
+ Var_Decl(Const_String name, Var_Kind vkind, int pos);
+ Var_Decl(Var_Kind vkind, int pos);
+ Var_Decl(Variable_ID v);
+ Var_Decl(Const_String name, Global_Var_ID v);
+ Var_Decl(Const_String name, Global_Var_ID v, Argument_Tuple function_of);
+
+ friend class F_Declaration; // creates local variables
+ friend class Global_Var_Decl; // its constructors create Var_Decls.
+
+ friend class Global_Input_Output_Tuple;
+ friend void copy_var_decls(Variable_ID_Tuple &new_vl, Variable_ID_Tuple &vl);
+
+private:
+ int instance;
+ void setup_name();
+
+ // these set up the names
+ friend class Rel_Body;
+// friend class F_Declaration; already a friend
+
+private:
+ Variable_ID remap; // pointer to new copy of this node
+
+ // lots of things need to get at "remap" - lots of relation ops,
+ // and functions that move UFS's around:
+ // dnf::make_level_carried_to and Conjunct::move_UFS_to_input()
+ // Also of course Conjunct::remap and push_exists
+ friend_rel_ops;
+ friend class DNF;
+ friend class Conjunct;
+
+ // this prints remap to the debugging output
+ friend void print_var_addrs(std::string &s, Variable_ID v);
+
+ friend void reset_remap_field(Variable_ID v);
+ friend void reset_remap_field(Sequence<Variable_ID> &S);
+ friend void reset_remap_field(Sequence<Variable_ID> &S, int var_no);
+ friend void reset_remap_field(Variable_ID_Tuple &S);
+ friend void reset_remap_field(Variable_ID_Tuple &S, int var_no);
+
+private:
+
+ Var_Kind var_kind;
+ int position; // only for Input_Var, Output_Var
+ Global_Var_ID global_var; // only for Global_Var
+ Argument_Tuple of; // only for Global_Var
+};
+
+bool rm_variable(Variable_ID_Tuple &vl, Variable_ID v);
+void reset_remap_field(Sequence<Variable_ID> &S);
+void reset_remap_field(Sequence<Variable_ID> &S, int var_no);
+void reset_remap_field(Variable_ID v);
+void reset_remap_field(Variable_ID_Tuple &S);
+void reset_remap_field(Variable_ID_Tuple &S, int var_no);
+
+class Global_Input_Output_Tuple: public Tuple<Variable_ID> {
+public:
+ Global_Input_Output_Tuple(Var_Kind in_my_kind, int init=-1);
+ ~Global_Input_Output_Tuple();
+ virtual Variable_ID &operator[](int index);
+ virtual const Variable_ID &operator[](int index) const;
+private:
+ Var_Kind my_kind;
+ static const int initial_allocation;
+};
+
+extern Global_Input_Output_Tuple input_vars;
+extern Global_Input_Output_Tuple output_vars;
+// This allows the user to refer to set_vars to query sets, w/o knowing
+// they are really inputs.
+extern Global_Input_Output_Tuple &set_vars;
+
+Variable_ID input_var(int nth);
+Variable_ID output_var(int nth);
+Variable_ID set_var(int nth);
+
+
+
+//
+// Global_Var_ID uniquely identifies global var-s through the whole program.
+// Global_Var_Decl is an ADT with the following operations:
+// - create global variable,
+// - find the arity of the variable, (default = 0, for symbolic consts)
+// - get the name of global variable,
+// - tell if two variables are the same (if they are the same object)
+//
+
+class Global_Var_Decl {
+public:
+ Global_Var_Decl(Const_String baseName);
+
+ virtual Const_String base_name() const
+ {
+ return loc_rep1.base_name;
+ }
+
+ virtual void set_base_name(Const_String newName)
+ {
+ loc_rep1.base_name = newName;
+ loc_rep2.base_name = newName;
+ }
+
+ virtual int arity() const
+ {
+ return 0; // default compatible with old symbolic constant stuff
+ }
+
+ virtual Omega_Var *really_omega_var(); // until we get RTTI in C++
+ virtual Coef_Var_Decl *really_coef_var(); // until we get RTTI in C++
+ virtual Global_Kind kind() const;
+
+private:
+
+ friend class Rel_Body; // Rel_Body::get_local calls this get_local
+
+ Variable_ID get_local()
+ {
+ assert(arity() == 0);
+ return &loc_rep1;
+ }
+ Variable_ID get_local(Argument_Tuple of)
+ {
+ assert(arity() == 0 || of == Input_Tuple || of == Output_Tuple);
+ return ((arity() == 0 || of == Input_Tuple) ? &loc_rep1 : &loc_rep2);
+ }
+
+ // local representative, there is just 1 for every 0-ary global variable
+ Var_Decl loc_rep1; // arity == 0, or arity > 0 and of == In
+ Var_Decl loc_rep2; // arity > 0 and of == Out
+
+public:
+// friend class Rel_Body; // Rel_Body::setup_names sets instance
+ friend class Var_Decl;
+ int instance;
+};
+
+
+class Coef_Var_Decl : public Global_Var_Decl {
+public:
+ Coef_Var_Decl(int id, int var);
+ int stmt() const;
+ int var() const;
+ virtual Global_Kind kind() const;
+ virtual Coef_Var_Decl *really_coef_var(); // until we get RTTI in C++
+
+private:
+ int i, v;
+};
+
+
+
+//
+// Test subclass for Global_Var: named global variable
+//
+class Free_Var_Decl : public Global_Var_Decl {
+public:
+ Free_Var_Decl(Const_String name);
+ Free_Var_Decl(Const_String name, int arity);
+ int arity() const;
+ virtual Global_Kind kind() const;
+
+private:
+ int _arity;
+};
+
+
+/* === implementation functions === */
+void copy_var_decls(Variable_ID_Tuple &new_vl, Variable_ID_Tuple &vl);
+void free_var_decls(Variable_ID_Tuple &vl);
+
+extern int wildCardInstanceNumber;
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/include/omega/reach.h b/omegalib/omega/include/omega/reach.h
new file mode 100644
index 0000000..ff4bf79
--- /dev/null
+++ b/omegalib/omega/include/omega/reach.h
@@ -0,0 +1,23 @@
+#if ! defined _reach_h
+#define _reach_h 1
+
+namespace omega {
+
+class reachable_information {
+public:
+ Tuple<std::string> node_names;
+ Tuple<int> node_arity;
+ Dynamic_Array1<Relation> start_nodes;
+ Dynamic_Array2<Relation> transitions;
+};
+
+
+Dynamic_Array1<Relation> *
+Reachable_Nodes(reachable_information * reachable_info);
+
+Dynamic_Array1<Relation> *
+I_Reachable_Nodes(reachable_information * reachable_info);
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/src/RelBody.cc b/omegalib/omega/src/RelBody.cc
new file mode 100644
index 0000000..825b153
--- /dev/null
+++ b/omegalib/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
+}
+
+}
diff --git a/omegalib/omega/src/RelVar.cc b/omegalib/omega/src/RelVar.cc
new file mode 100644
index 0000000..d9b977c
--- /dev/null
+++ b/omegalib/omega/src/RelVar.cc
@@ -0,0 +1,71 @@
+#include <omega/RelBody.h>
+#include <omega/omega_i.h>
+
+namespace omega {
+
+Variable_ID Rel_Body::get_local(const Variable_ID v) {
+ Global_Var_ID g;
+ if (v->kind() == Global_Var) {
+ g = v->get_global_var();
+ if (g->arity()) return get_local(g,v->function_of());
+ return get_local(g);
+ }
+ if (is_set()) return set_var(v->get_position());
+ if (v->kind() == Input_Var) return input_var(v->get_position());
+ if (v->kind() == Output_Var) return output_var(v->get_position());
+ assert(0 && "Can only get local for variable with global scope");
+ exit(1);
+ return 0;
+}
+
+//
+// Find or declare global variable.
+// If the VarID does not exist, it is created. Otherwise it's returned.
+// Note that this version now works only for 0-ary functions.
+//
+Variable_ID Rel_Body::get_local(const Global_Var_ID G) {
+ assert(G->arity() == 0);
+ for(Variable_Iterator i(Symbolic); i; i++)
+ if ((*i)->get_global_var() == G)
+ return (*i);
+
+ Variable_ID v = G->get_local();
+ Symbolic.append(v);
+ return v;
+}
+
+
+Variable_ID Rel_Body::get_local(const Global_Var_ID G, Argument_Tuple of) {
+ assert(G->arity() == 0 || of == Input_Tuple || of == Output_Tuple);
+
+ for(Variable_Iterator i = Symbolic; i; i++)
+ if ((*i)->get_global_var() == G && (G->arity() == 0 ||
+ of == (*i)->function_of()))
+ return (*i);
+
+ Variable_ID V = G->get_local(of);
+ Symbolic.append(V);
+ return V;
+}
+
+
+bool Rel_Body::has_local(const Global_Var_ID G) {
+ assert(G->arity() == 0);
+ for(Variable_Iterator i = Symbolic; i; i++)
+ if ((*i)->get_global_var() == G)
+ return true;
+ return false;
+}
+
+
+bool Rel_Body::has_local(const Global_Var_ID G, Argument_Tuple of) {
+ assert(G->arity() == 0 || of == Input_Tuple || of == Output_Tuple);
+
+ for(Variable_Iterator i = Symbolic; i; i++)
+ if ((*i)->get_global_var() == G && (G->arity() == 0 ||
+ of == (*i)->function_of()))
+ return true;
+ return false;
+}
+
+} // namespace
diff --git a/omegalib/omega/src/Relation.cc b/omegalib/omega/src/Relation.cc
new file mode 100644
index 0000000..1cca43a
--- /dev/null
+++ b/omegalib/omega/src/Relation.cc
@@ -0,0 +1,279 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 the Omega Project Team
+ Copyright (C) 2005-2011 Chun Chen
+ All Rights Reserved.
+
+ Purpose:
+ class Relation
+
+ Notes:
+
+ History:
+*****************************************************************************/
+
+#include <omega/Relation.h>
+#include <omega/Relations.h>
+#include <omega/pres_dnf.h>
+#include <omega/pres_conj.h>
+#include <omega/Rel_map.h>
+#include <omega/omega_i.h>
+#include <omega/omega_core/debugging.h>
+
+namespace omega {
+
+// copy function for Relation, will be removed in the future
+// in favor of correct C++ copy constructor and const paramater passing
+Relation copy(const Relation &t) {
+ Relation r = t;
+ return r;
+}
+
+//
+// Create null relation.
+//
+Relation::Relation() : rel_body(&null_rel) {
+ rel_body->ref_count = 1;
+}
+
+Relation Relation::Null() {
+ return Relation();
+}
+
+bool Relation::is_null() const {
+ return(rel_body == &null_rel);
+}
+
+
+//
+// Create a relation. Its will be built later.
+//
+Relation::Relation(int n_input, int n_output) {
+ rel_body = new Rel_Body(n_input,n_output);
+ rel_body->ref_count = 1;
+}
+
+Relation::Relation(Rel_Body &r, int) {
+ rel_body = &r;
+ r.ref_count++;
+}
+
+Relation Relation::Empty(const Relation &R) {
+ if (R.is_set()) return Relation(R.n_set());
+ else return Relation(R.n_inp(),R.n_out());
+}
+
+//
+// Create relation which is FALSE or TRUE.
+//
+
+Relation Relation::True(const Relation &R) {
+ if (R.is_set()) return True(R.n_set());
+ else return True(R.n_inp(),R.n_out());
+}
+
+Relation Relation::False(const Relation &R) {
+ if (R.is_set()) return False(R.n_set());
+ else return False(R.n_inp(),R.n_out());
+}
+
+Relation Relation::Unknown(const Relation &R) {
+ if (R.is_set()) return Unknown(R.n_set());
+ else return Unknown(R.n_inp(), R.n_out());
+}
+
+
+Relation Relation::True(int setvars) {
+ Relation R(setvars);
+ R.add_and();
+ R.finalize();
+ return R;
+}
+
+Relation Relation::True (int in, int out) {
+ Relation R(in,out);
+ R.add_and();
+ R.finalize();
+ return R;
+}
+
+Relation Relation::False (int setvars) {
+ Relation R(setvars);
+ R.add_or();
+ R.finalize();
+ return R;
+}
+
+Relation Relation::False (int in, int out) {
+ Relation R(in,out);
+ R.add_or();
+ R.finalize();
+ return R;
+}
+
+
+Relation Relation::Unknown (int setvars) {
+ Relation R(setvars);
+ R.add_and();
+ R.finalize();
+ R.simplify();
+ Conjunct * c= R.single_conjunct();
+ c->make_inexact();
+ return R;
+}
+
+Relation Relation::Unknown (int in, int out) {
+ Relation R(in,out);
+ R.add_and();
+ R.finalize();
+ R.simplify();
+ Conjunct * c= R.single_conjunct();
+ c->make_inexact();
+ return R;
+}
+
+
+//
+// Copy a relation.
+//
+Relation::Relation(const Relation &r) {
+#if defined(INCLUDE_COMPRESSION)
+ assert(!r.is_compressed());
+#endif
+ if (r.is_finalized()) {
+ rel_body = r.rel_body;
+ rel_body->ref_count++;
+ } else {
+ assert(! r.rel_body->is_shared());
+ // rel_body = new Rel_Body(r.rel_body);
+ rel_body = r.rel_body->clone();
+ rel_body->ref_count = 1;
+ }
+}
+
+//
+// Copy relation r and replace formula in it with conjunct c.
+// Wayne (TM) function.
+//
+Relation::Relation(const Relation &r, Conjunct *c) {
+ rel_body = new Rel_Body(r.rel_body, c);
+ rel_body->ref_count = 1;
+}
+
+
+//
+// Assign a relation r to this relation.
+//
+Relation &Relation::operator=(const Relation &r) {
+#if defined(INCLUDE_COMPRESSION)
+ assert (!r.is_compressed());
+#endif
+
+ /* === Destroy this === */
+ assert(rel_body->ref_count >= 1);
+ if(rel_body!=&null_rel && --(rel_body->ref_count)==0) {
+ delete rel_body;
+ }
+
+ /* === Copy r to this === */
+ if (r.is_finalized()) {
+ rel_body = r.rel_body;
+ rel_body->ref_count++;
+ } else {
+ assert(! r.rel_body->is_shared());
+ // rel_body = new Rel_Body(r.rel_body);
+ rel_body = r.rel_body->clone();
+ rel_body->ref_count = 1;
+ }
+ return *this;
+}
+
+void Relation::copy_names(Rel_Body &r) {
+ int t;
+ for(t = 1; t <= r.n_inp(); t++)
+ name_input_var(t,r.input_var(t)->base_name);
+ for(t = 1; t <= r.n_out(); t++)
+ name_output_var(t,r.output_var(t)->base_name);
+}
+
+
+// Like makeSet (see Relations.c), but won't invert the relation --
+// fails if it has output instead of input variables. Called in Relation
+// functions just after a MapRel, so that we know there are no outputs anyway.
+
+void Relation::markAsSet() {
+ assert(!is_null());
+ assert(is_set() || (n_inp() >= 0 && n_out() == 0));
+ if (!is_set()) split(); // split if we'll modify this
+ rel_body->_is_set = true;
+ invalidate_leading_info();
+}
+
+void Relation::markAsRelation() {
+ assert(!is_null());
+ if (is_set()) split(); // split if we'll modify this
+ rel_body->_is_set = false;
+}
+
+
+Relation::~Relation() {
+ assert(rel_body->ref_count >= 1);
+ assert(this->is_null() == (rel_body == &null_rel));
+ if(rel_body!=&null_rel && --(rel_body->ref_count)==0) {
+ if (rel_body == &null_rel) abort();
+ delete rel_body;
+ }
+}
+
+
+
+//
+// One of the representatives using the body wants to be changed.
+// Create a separate body for this rep not to damage other reps.
+// Return address of the body. Old rep point to new body.
+//
+Rel_Body *Relation::split() {
+ assert(rel_body != &null_rel && "Error: Attempt to modify a null relation");
+ assert (rel_body->ref_count >= 1);
+ if(!(rel_body==&null_rel || rel_body->ref_count==1)) {
+ if(pres_debug) {
+ fprintf(DebugFile, "+++ SPLIT relation +++\n");
+ }
+ // Rel_Body *new_body = new Rel_Body(rel_body);
+ Rel_Body *new_body = rel_body->clone();
+ new_body->ref_count = 1;
+ rel_body->ref_count--;
+ rel_body = new_body;
+ if(pres_debug>=2) {
+ fprintf(DebugFile, " copying 0x%p to give 0x%p\n", this, rel_body);
+ }
+ }
+ return (rel_body);
+}
+
+
+void Relation::dimensions(int & ndim_all, int &ndim_domain) {
+ ndim_all = ndim_domain = 0;
+ int a,d;
+ simplify(2,2);
+ for (DNF_Iterator s(query_DNF()); s.live(); s.next()) {
+ s.curr()->calculate_dimensions(*this, a, d);
+ if (a > ndim_all) ndim_all = a;
+ if (d > ndim_domain) ndim_domain = d;
+ }
+}
+
+// Make a set: assert that it had only input or output variables, make it
+// it have only input, set a flag. Called from domain, range, and difference,
+// as well as functions that require a set as input.
+void Relation::makeSet() {
+ assert(!is_null());
+ // Assert that it is a set...
+ assert((n_inp() == 0 && n_out() >= 0) || (n_inp() >= 0 && n_out() == 0));
+
+ if ((n_inp() == 0 && n_out() != 0) || !is_set()) split(); // split if we'll modify this
+ if (n_inp() == 0 && n_out() != 0) //Inverse the relation
+ Inverse(*this); // Modifies "this"; also returns this but we ignore it
+ rel_body->_is_set = true;
+}
+
+} // namespace
diff --git a/omegalib/omega/src/Relations.cc b/omegalib/omega/src/Relations.cc
new file mode 100644
index 0000000..d7dbe86
--- /dev/null
+++ b/omegalib/omega/src/Relations.cc
@@ -0,0 +1,2882 @@
+/*****************************************************************************
+ 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
diff --git a/omegalib/omega/src/basic/ConstString.cc b/omegalib/omega/src/basic/ConstString.cc
new file mode 100644
index 0000000..7d2ec1e
--- /dev/null
+++ b/omegalib/omega/src/basic/ConstString.cc
@@ -0,0 +1,134 @@
+#include <basic/ConstString.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string>
+#include <string.h>
+
+/* static const int CS_HashTable_Size = 1000; */
+/* static ConstStringRep *hashTable[CS_HashTable_Size] = {0}; */
+
+namespace omega {
+
+const int CS_HashTable_Size = 1000;
+class CS_HashTable {
+public:
+ ConstStringRep *p[CS_HashTable_Size];
+ CS_HashTable();
+ ~CS_HashTable();
+};
+
+namespace {
+ CS_HashTable hashTable;
+}
+
+CS_HashTable::CS_HashTable() {
+ for (int i = 0; i < CS_HashTable_Size; i++)
+ p[i] = NULL;
+ }
+
+CS_HashTable::~CS_HashTable() {
+ for (int i = 0; i < CS_HashTable_Size; i++) {
+ ConstStringRep *t = p[i];
+ while (t != NULL) {
+ ConstStringRep *tt = t->nextInBucket;
+ delete []t->name;
+ delete t;
+ t = tt;
+ }
+ }
+}
+
+Const_String::Const_String() {
+ rep = 0;
+}
+
+void Const_String::buildRep(const char* t) {
+ int hash = 0;
+ const char *s = t;
+ while (*s != '\0')
+ hash = hash*33 + *s++;
+ int hashBucket = hash % CS_HashTable_Size;
+ if (hashBucket < 0) hashBucket += CS_HashTable_Size;
+ assert(0 <= hashBucket && hashBucket < CS_HashTable_Size);
+ ConstStringRep **q = &(hashTable.p[hashBucket]);
+ ConstStringRep *p = *q;
+ while (p != 0) {
+ if (strcmp(p->name,t) == 0) break;
+ q = &p->nextInBucket;
+ p = *q;
+ }
+ if (p!= 0) rep = p;
+ else {
+ rep = new ConstStringRep(t);
+ *q = rep;
+ }
+}
+
+Const_String::Const_String(const char * t) {
+ buildRep(t);
+}
+
+Const_String::Const_String(const std::string &s) {
+ buildRep(s.c_str());
+}
+
+Const_String::operator const char*() const {
+ if (!rep) return 0;
+ return rep->name;
+}
+
+Const_String::operator std::string() const {
+ if (!rep) return std::string("");
+ return std::string(rep->name);
+}
+
+int Const_String::operator++(int) {
+ return rep->count++;
+}
+
+int Const_String::operator++() {
+ return ++rep->count;
+}
+
+int Const_String:: operator--(int) {
+ return rep->count--;
+}
+
+int Const_String:: operator--() {
+ return --rep->count;
+}
+
+int operator ==(const Const_String &x, const Const_String &y) {
+ return x.rep == y.rep;
+}
+
+int operator !=(const Const_String &x, const Const_String &y) {
+ return x.rep != y.rep;
+}
+
+int operator <(const Const_String &x, const Const_String &y) {
+ return (strcmp(x.rep->name,y.rep->name) < 0);
+}
+
+int operator >(const Const_String &x, const Const_String &y) {
+ return (strcmp(x.rep->name,y.rep->name) > 0);
+}
+
+Const_String:: operator int() const {
+ return rep != 0;
+}
+
+int Const_String::null() const {
+ return rep == 0;
+}
+
+ConstStringRep:: ConstStringRep(const char *t) {
+ count = 0;
+ nextInBucket = 0;
+ char *s = new char[1+strlen(t)];
+ strcpy(s,t);
+ name = s;
+}
+
+} // namespace
diff --git a/omegalib/omega/src/basic/Link.cc b/omegalib/omega/src/basic/Link.cc
new file mode 100644
index 0000000..50b9441
--- /dev/null
+++ b/omegalib/omega/src/basic/Link.cc
@@ -0,0 +1,41 @@
+#include <basic/Link.h>
+
+namespace omega {
+
+#if ListElementFreeList
+ static List_Element<void*> *_kludgy_List_Element_free_list_pointer;
+// we rely on the fact that that is initialized to 0 before any
+// constructor-based initialization that could call List_Element::new.
+
+ void *kludgy_List_Element_new(size_t size)
+ {
+ void *mem;
+ if (size == sizeof(List_Element<void*>) &&
+ _kludgy_List_Element_free_list_pointer)
+ {
+ List_Element<void*> *it = _kludgy_List_Element_free_list_pointer;
+ _kludgy_List_Element_free_list_pointer = it->tail;
+ mem = it;
+ }
+ else
+ mem = ::operator new(size);
+
+ return mem;
+ }
+
+ void kludgy_List_Element_delete(void *ptr, size_t size)
+ {
+ if (ptr)
+ if (size == sizeof(List_Element<void*>))
+ {
+ List_Element<void*> *it = (List_Element<void*> *) ptr;
+ it->tail = _kludgy_List_Element_free_list_pointer;
+ _kludgy_List_Element_free_list_pointer = it;
+ }
+ else
+ ::operator delete(ptr);
+ }
+
+#endif
+
+} // namespace
diff --git a/omegalib/omega/src/closure.cc b/omegalib/omega/src/closure.cc
new file mode 100644
index 0000000..416a3e7
--- /dev/null
+++ b/omegalib/omega/src/closure.cc
@@ -0,0 +1,2100 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 the Omega Project Team
+ Copyright (C) 2005-2011 Chun Chen
+ Copyright (C) 2009-2011 West Pomeranian University of Technology, Szczecin
+ All Rights Reserved.
+
+ Purpose:
+ All calculations of closure are now here.
+
+ Notes:
+ Related paper:
+ - "Transitive closure of infinite graphs and its applications",
+ Wayne Kelly, William Pugh, Evan Rosser and Tatiana Shpeisman, IJPP 1996.
+ - "Computing the Transitive Closure of a Union of Affine Integer Tuple
+ Relations", Anna Beletska, Denis Barthou, Wlodzimierz Bielecki and
+ Albert Cohen, COCOA 2009.
+ - "An Iterative Algorithm of Computing the Transitive Closure of a Union
+ of Parameterized Affine Integer Tuple Relations", Bielecki Wlodzimierz,
+ Klimek Tomasz, Palkowski Marek and Anna Beletska, COCOA 2010.
+
+ History:
+ 12/27/09 move ConicClosure here, Chun Chen
+ 01/19/11 new closure algorithms, Klimek Tomzsz
+ 02/02/11 move VennDiagramFrom here, Chun Chen
+*****************************************************************************/
+
+#include <typeinfo>
+#include <assert.h>
+#include <omega.h>
+#include <omega/hull.h>
+#include <basic/Iterator.h>
+#include <basic/List.h>
+#include <basic/SimpleList.h>
+
+namespace omega {
+
+void InvestigateClosure(Relation r, Relation r_closure, Relation bounds);
+void print_given_bounds(const Relation & R1, NOT_CONST Relation& input_Bounds);
+#define printConjunctClosure (closure_presburger_debug & 0x1)
+#define detailedClosureDebug (closure_presburger_debug & 0x2)
+
+
+#ifdef TC_STATS
+extern int clock_diff();
+extern void start_clock();
+FILE *statsfile;
+int singles, totals=0;
+#endif
+
+int closure_presburger_debug = 0;
+
+
+Relation VennDiagramForm(NOT_CONST Relation &Context_In,
+ Tuple<Relation> &Rs,
+ int next,
+ bool anyPositives,
+ int weight) {
+ Relation Context = consume_and_regurgitate(Context_In);
+ if (hull_debug) {
+ fprintf(DebugFile,"[VennDiagramForm, next = %d, anyPositives = %d, weight = %d \n", next,anyPositives,weight);
+ fprintf(DebugFile,"context:\n");
+ Context.prefix_print(DebugFile);
+ }
+ if (anyPositives && weight > 3) {
+ Context.simplify();
+ if (!Context.is_upper_bound_satisfiable()) {
+ if (hull_debug)
+ fprintf(DebugFile,"] not satisfiable\n");
+ return Context;
+ }
+ weight = 0;
+ }
+ if (next > Rs.size()) {
+ if (!anyPositives) {
+ if (hull_debug)
+ fprintf(DebugFile,"] no positives\n");
+ return Relation::False(Context);
+ }
+ Context.simplify();
+ if (hull_debug) {
+ fprintf(DebugFile,"] answer is:\n");
+ Context.prefix_print(DebugFile);
+ }
+ return Context;
+ }
+ Relation Pos = VennDiagramForm(Intersection(copy(Context),copy(Rs[next])),
+ Rs,
+ next+1,
+ true,
+ weight+2);
+ Relation Neg = VennDiagramForm(Difference(Context,copy(Rs[next])),
+ Rs,
+ next+1,
+ anyPositives,
+ weight+1);
+ if (hull_debug) {
+ fprintf(DebugFile,"] VennDiagramForm\n");
+ fprintf(DebugFile,"pos part:\n");
+ Pos.prefix_print(DebugFile);
+ fprintf(DebugFile,"neg part:\n");
+ Neg.prefix_print(DebugFile);
+ }
+ return Union(Pos,Neg);
+}
+
+
+Relation VennDiagramForm(Tuple<Relation> &Rs, NOT_CONST Relation &Context_In) {
+ Relation Context = consume_and_regurgitate(Context_In);
+ if (Context.is_null()) Context = Relation::True(Rs[1]);
+ if (hull_debug) {
+ fprintf(DebugFile,"Starting computation of VennDiagramForm\n");
+ fprintf(DebugFile,"Context:\n");
+ Context.prefix_print(DebugFile);
+ for(int i = 1; i <= Rs.size(); i++) {
+ fprintf(DebugFile,"#%d:\n",i);
+ Rs[i].prefix_print(DebugFile);
+ }
+ }
+ return VennDiagramForm(Context,Rs,1,false,0);
+}
+
+Relation VennDiagramForm(NOT_CONST Relation &R_In, NOT_CONST Relation &Context_In) {
+ Relation R = consume_and_regurgitate(R_In);
+ Relation Context = consume_and_regurgitate(Context_In);
+ Tuple<Relation> Rs;
+ for (DNF_Iterator c(R.query_DNF()); c.live(); ) {
+ Rs.append(Relation(R,c.curr()));
+ c.next();
+ }
+ return VennDiagramForm(Rs,Context);
+}
+
+
+Relation ConicClosure (NOT_CONST Relation &R) {
+ int n = R.n_inp();
+ if (n != R.n_out())
+ throw std::invalid_argument("conic closure must have the same input arity and output arity");
+
+ return DeltasToRelation(ConicHull(Deltas(R)), n, n);
+}
+
+
+bool is_lex_forward(Relation R) {
+ if(R.n_inp() != R.n_out()) {
+ fprintf(stderr, "relation has wrong inputs/outpts\n");
+ exit(1);
+ }
+ Relation forw(R.n_inp(), R.n_out());
+ F_Or * o = forw.add_or();
+ for(int a = 1; a <= forw.n_inp(); a++) {
+ F_And * andd = o->add_and();
+ GEQ_Handle g = andd->add_GEQ();
+ g.update_coef(input_var(a), -1);
+ g.update_coef(output_var(a), 1);
+ g.update_const(1);
+ for(int b = 1; b < a; b++) {
+ EQ_Handle e = andd->add_EQ();
+ e.update_coef(input_var(a),1);
+ e.update_coef(output_var(a),-1);
+ }
+ }
+ Relation test = Difference(R, forw);
+ return !test.is_upper_bound_satisfiable();
+}
+
+
+static Relation compose_n(NOT_CONST Relation &input_r, int n) {
+ Relation r = consume_and_regurgitate(input_r);
+ if (n == 1)
+ return r;
+ else
+ return Composition(r, compose_n(copy(r), n-1));
+} /* compose_n */
+
+
+
+
+Relation approx_closure(NOT_CONST Relation &input_r, int n) {
+ Relation r = consume_and_regurgitate(input_r);
+ Relation r_closure;
+
+ r_closure=r;
+ int i;
+ for(i=2; i<=n; i++)
+ r_closure=Union(r_closure,compose_n(copy(r), n));
+ r_closure = Union(r_closure, Relation::Unknown(r_closure));
+
+ return r_closure;
+} /* approx_closure */
+
+
+static bool is_closure_itself(NOT_CONST Relation &r) {
+ return Must_Be_Subset(Composition(copy(r),copy(r)),copy(r));
+}
+
+
+/*****
+ * get a D form of the Relation (single conjunct).
+ * D = {[ i_1,i_2,...,i_m] -> [j_1, j_2, ..., j_m ] :
+ * (forall p, 1<= p <= m) L_p <= j_p - i_p <= U_p &&
+ * j_p - i_p == M_p alpha_p};
+ * Right now only wildcards that are in stride constraints are treated.
+ *****/
+
+Relation get_D_form (Relation & R) {
+ Relation D(R.n_inp(), R.n_out());
+
+ R.make_level_carried_to(R.n_inp());
+ assert(R.has_single_conjunct());
+ int n_zero=0;
+ for (DNF_Iterator d(R.query_DNF()); d.live(); d.next())
+ n_zero=d.curr()->query_guaranteed_leading_0s();
+
+ Relation Diff=Deltas(copy(R));
+
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "The relation projected onto differencies is:\n");
+ Diff.print_with_subs(DebugFile);
+ }
+
+
+ /* now form D */
+
+ int i;
+ coef_t l,u;
+ F_And * N = D.add_and();
+ GEQ_Handle g;
+ for (i=1; i<=Diff.n_set(); i++) {
+ Diff.query_variable_bounds(Diff.set_var(i), l,u);
+/* if (i== n_zero+1 && l==negInfinity)
+ l=1; */
+ if (l!=negInfinity) {
+ g=N->add_GEQ();
+ g.update_coef(D.input_var(i),-1);
+ g.update_coef(D.output_var(i),1);
+ g.update_const(-l);
+ g.finalize();
+ }
+ if (u!=posInfinity) {
+ g=N->add_GEQ();
+ g.update_coef(D.input_var(i),1);
+ g.update_coef(D.output_var(i),-1);
+ g.update_const(u);
+ g.finalize();
+ }
+ }
+
+ /* add all stride constrains if they do exist */
+
+ Conjunct *c = Diff.single_conjunct();
+
+ if (c->locals().size()>0) {// there are local variables
+ // now go through all the equalities
+
+ coef_t coef=0;
+ int pos=0;
+ for (EQ_Iterator eq = c->EQs(); eq.live(); eq.next()) {
+ // constraint is in stride form if it has 2 vars,
+ // one of which is wildcard. Count number if vars and wildcard vars
+ int nwild=0,nvar=0;
+
+ for (Constr_Vars_Iter cvi(*eq, false); cvi; cvi++) {
+ if ((*cvi).var->kind() == Global_Var)
+ continue;
+ else if ((*cvi).var->kind() == Wildcard_Var) {
+ coef=(*cvi).coef;
+ nwild++;
+ }
+ else
+ pos=(*cvi).var->get_position();
+ nvar++;
+ }
+ if (nvar==2 && nwild==1) { //stride constraint
+ EQ_Handle e=N->add_stride(coef);
+ e.update_coef(D.input_var(pos),-1);
+ e.update_coef(D.output_var(pos),1);
+ e.finalize();
+ }
+ }
+ } // end search of stride constrains
+
+ D.finalize();
+ D.simplify();
+ return D;
+} /* end get_D_form */
+
+/****
+ * get relation A x A describing a region of domain and range:
+ * A=Hull(Domain(R), Range(R)) intersection IterationSpace
+ * returns cross product A x A
+ ***/
+
+Relation form_region(const Relation &R, const Relation& IterationSpace) {
+ Relation H=Union(Domain(copy(R)), Range(copy(R)));
+ H.simplify(1,1);
+ H = EQs_to_GEQs(H);
+ H=Hull(H);
+ Relation A=Intersection(H, copy(IterationSpace));
+ Relation A1=A;
+ return Cross_Product(A,A1);
+}
+
+Relation form_region1(const Relation &R, const Relation& IterationSpace) {
+ Relation Dom=Intersection(Domain(copy(R)), copy(IterationSpace));
+ Relation Ran=Intersection(Range(copy(R)), copy(IterationSpace));
+ return Cross_Product(Dom,Ran);
+}
+
+
+/****
+ * Check if we can use D instead of R
+ * i.e. D intersection (A cross A) is Must_Be_Subset of R
+ ***/
+
+bool isD_OK(Relation &R, Relation &D, Relation &AxA) {
+ Relation B=Intersection(copy(D), copy(AxA));
+ B.simplify();
+
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "Intersection of D and AxA is:\n");
+ B.print_with_subs(DebugFile);
+ }
+ assert (Must_Be_Subset(copy(R),copy(B)));
+
+ return Must_Be_Subset(B, copy(R));
+}
+
+
+
+/****
+ * check if the constraint is a stride one. Here we say that an equality
+ * constraint is a stride constraint if it has exatly one wildcard.
+ * The function returns number of the wildcards in the constraint.
+ * So if we know that constraint is from the relation in D form, then
+ * it cannot have more than 1 wildcard variables, and the result of
+ * this functions can be treated as bool.
+ ***/
+
+static int is_stride(const EQ_Handle &eq) {
+ int n=0;
+
+ for (Constr_Vars_Iter cvi(eq,true); cvi; cvi++)
+ n++;
+
+ return n;
+}
+
+
+
+/*****
+ * check if the constraint is in the form i_k' - i_k comp_op c
+ * return v - the number of the var and the type of the comp_op:
+ * 1 - >, -1 - <, 0 - not in the right form
+ * if this is equality constraint in the right form any 1 or -1 can be
+ * returned
+ ******/
+
+static coef_t is_constraint_in_D_form(Relation &r, const Constraint_Handle &h, int &v) {
+ v=-1;
+ coef_t c_out = 0;
+ for (int i = 1; i <= r.n_inp(); i++) {
+ coef_t c_in = h.get_coef(r.input_var(i));
+ if (c_in) {
+ if (v!=-1)
+ return 0;
+ v=i;
+ c_out = h.get_coef(r.output_var(i));
+
+ // special case for modular constraint -- by chun 04/02/2009
+ if (h.has_wildcards() && typeid(h) == typeid(EQ_Handle)) {
+ coef_t g = 0;
+ for (Constr_Vars_Iter cvi(h, true); cvi; cvi++)
+ g = gcd(g, abs(cvi.curr_coef()));
+ c_in = int_mod_hat(c_in, g);
+ c_out = int_mod_hat(c_out, g);
+
+ if (g == 2) {
+ if (c_in * c_out == 1) {
+ c_out = -1;
+ }
+ else
+ return 0;
+ }
+ else if (c_in * c_out != -1)
+ return 0;
+ }
+ // other cases
+ else if (c_in * c_out != -1)
+ return 0;
+ }
+ }
+ return c_out;
+}
+
+
+/***
+ * Check if relation is in the D form
+ * D = {[ i_1,i_2,...,i_m] -> [j_1, j_2, ..., j_m ] :
+ * (forall p, 1<= p <= m) L_p <= j_p - i_p <= U_p &&
+ * j_p - i_p == M_p alpha_p};
+ * Right now we do not check for multiple stride constraints for one var.
+ * Probably they cannot exist in simplified conjunct
+ * This function will be used in assertions
+ *****/
+
+bool is_in_D_form(Relation & D) {
+ /* check that D has one conjunct */
+
+ if (! D.has_single_conjunct())
+ return false;
+
+ Conjunct * c=D.single_conjunct();
+
+ if (D.global_decls()->size() != 0) // there are symbolic vars
+ return false;
+
+ if (D.n_inp() != D.n_out())
+ return false;
+
+ int n=D.n_inp();
+
+ Tuple<int> bl(n), bu(n);
+
+ for (int i=1; i<= n; i++)
+ bl[i]=bu[i]=0;
+
+ int v;
+ coef_t res;
+
+ for (EQ_Iterator eq = c->EQs(); eq.live(); eq.next()) {
+ if ((res=is_constraint_in_D_form(D,*eq,v))==0)
+ return false;
+ int n_wild=is_stride(*eq);
+ if (n_wild>=2)
+ return false;
+ if (n_wild==0) { // not stride constraint
+ if (bl[v] || bu[v])
+ return false;
+ bl[v]=bu[v]=1;
+ }
+ }
+
+ for (GEQ_Iterator geq = c->GEQs(); geq.live(); geq.next()) {
+ if ((res=is_constraint_in_D_form(D,*geq,v))==0)
+ return false;
+ if ((res>0 && bl[v]) || (res<0 && bu[v]))
+ return false;
+ if (res>0)
+ bl[v]=1;
+ else
+ bu[v]=1;
+ }
+
+ return true;
+}
+
+
+#define get_D_plus_form(R) (get_D_closure(R,1))
+#define get_D_star_form(R) (get_D_closure(R,0))
+
+/****
+ * Get D+ or D* from the relation that is in D form
+ * To get D+ calculate:
+ * D+= {[i1, i2 .. i_m] -> {j1, j2, ..., j_m]:
+ * exists s s.t. s>=1 and
+ * (forall p, 1<= p <= m) L_p * s<= j_p - i_p <= U_p*s &&
+ * j_p - i_p == M_p alpha_p};
+ * To get D* calculate almost the same relation but s>=0.
+ * Parameter n is 1 for getting D+ and 0 for D*
+ ****/
+
+
+Relation get_D_closure(Relation & D, int n) {
+ assert (is_in_D_form(D));
+ assert(n==0 || n==1);
+
+ Conjunct *c=D.single_conjunct();
+
+ Relation R(D.n_inp(), D.n_out());
+
+ F_Exists * ex = R.add_exists();
+ Variable_ID s = ex->declare("s");
+ F_And * N = ex->add_and();
+
+ /* add s>=1 or s>=0 */
+
+ GEQ_Handle geq= N->add_GEQ();
+ geq.update_coef(s,1);
+ geq.update_const(-n);
+ geq.finalize();
+
+
+ /* copy and modify all the EQs */
+
+ for (EQ_Iterator j= c->EQs(); j.live(); j.next()) {
+ EQ_Handle eq=N->add_EQ();
+ copy_constraint(eq, *j);
+
+ // if it's stride constraint do not change it
+
+ if (!is_stride(*j)) {
+ /* eq is j_k -i_k = c, replace c buy s*c */
+
+ eq.update_coef(s, (*j).get_const());
+ eq.update_const(-(*j).get_const());
+ }
+ eq.finalize();
+ }
+
+ /* copy and modify all the GEQs */
+
+ for (GEQ_Iterator gi= c->GEQs(); gi.live(); gi.next()) {
+ geq=N->add_GEQ();
+ copy_constraint(geq, *gi);
+
+ /* geq is j_k -i_k >=c or i_k-j_k >=c, replace c buy s*c */
+
+ geq.update_coef(s,(*gi).get_const());
+ geq.update_const(-(*gi).get_const());
+ geq.finalize();
+ }
+
+ R.finalize();
+
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "Simplified D%c is:\n", n==1?'+':'*');
+ R.print_with_subs(DebugFile);
+ }
+
+ return R;
+}
+
+
+/***
+ * Check if we can easily calculate the D* (D* will be convex).
+ * We can calculate D* if all differences have both lower and upper
+ * bounds to be non -/+ infinity
+ ***/
+
+
+bool can_get_D_star_form(Relation &D) {
+ assert(is_in_D_form(D));
+ Conjunct *c=D.single_conjunct();
+
+ int n=D.n_inp();
+ Tuple<int> bl(n), bu(n);
+ int i;
+
+ for (i=1; i<=n; i++)
+ bl[i]=bu[i]=0;
+
+ for (EQ_Iterator eq = c->EQs(); eq.live(); eq.next()) {
+ // do not check stride constraints
+ if (!is_stride(*eq)) {
+ for (i=1; i<=n; i++) {
+ if ((*eq).get_coef(D.input_var(i)) !=0 )
+ bl[i]=bu[i]=1;
+ }
+ }
+ }
+
+
+ for (GEQ_Iterator geq = c->GEQs(); geq.live(); geq.next()) {
+ for (i=1; i<=n; i++) {
+ coef_t k;
+ if ((k=(*geq).get_coef(D.input_var(i))) != 0) {
+ if (k>0)
+ bu[i]=1;
+ else
+ bl[i]=1;
+ }
+ }
+ }
+
+ for (i=1; i<=n; i++)
+ if (!bl[i] || !bu[i])
+ return false;
+
+ return true;
+}
+
+
+
+/*****
+ * Check whether the relation intersect with identity or not
+ ****/
+
+bool does_intersect_with_identity(Relation &R) {
+ assert (R.n_inp() == R.n_out());
+
+ Relation I=Identity(R.n_inp());
+ Relation C=Intersection(I, copy(R));
+ return C.is_upper_bound_satisfiable();
+}
+
+bool does_include_identity(Relation &R) {
+ Relation I=Identity(R.n_inp());
+ return Must_Be_Subset(I, copy(R));
+}
+
+/*****
+ * Bill's closure: check if it is possible to calculate transitive closure
+ * of the relation using the Bill's algorithm.
+ * Return the transitive closure relation if it is possible and null relation
+ * otherwise
+ ****/
+
+bool Bill_closure(Relation &R, Relation& IterationSpace, Relation & R_plus, Relation & R_star) {
+#ifdef TC_STATS
+ fprintf(statsfile,"start bill closure\n");
+#endif
+
+ if (does_include_identity(R))
+ return false;
+
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "\nApplying Bill's method to calculate transitive closure\n");
+ }
+
+ // get D and AxA
+ Relation D=get_D_form(R);
+
+
+ if (detailedClosureDebug) {
+ fprintf(DebugFile,"\n D form for the relation:\n");
+ D.print_with_subs(DebugFile);
+ }
+
+ Relation AxA=form_region1(R, IterationSpace);
+
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "\n AxA for the relation:\n");
+ AxA.print_with_subs(DebugFile);
+ }
+
+ // compute R_+
+
+ R_plus=Intersection(get_D_plus_form(D), copy(AxA));
+
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "\nR_+= D+ intersection AxA is:\n");
+ R_plus.print_with_subs(DebugFile);
+ }
+
+ // compute R_*
+ R_star=Intersection(get_D_star_form(D), form_region(R,IterationSpace));
+
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "\nR_*= D* intersection AxA is:\n");
+ R_star.print_with_subs(DebugFile);
+ }
+
+/* Check that R_+ is acyclic.
+ Given the way we constructed R_+, R_+=(R_+)+.
+ As a result it's enough to verify that R_+ intersection I = 0,
+ to prove that R_+ is acyclic.
+*/
+
+ if (does_intersect_with_identity(R_plus)) {
+ if (detailedClosureDebug) {
+ fprintf(DebugFile,"R_+ is not acyclic.\n");
+ }
+ return false;
+ }
+
+ //Check R_+ - R is Must_Be_Subset of R o R_+
+
+ if (!Must_Be_Subset(Difference(copy(R_plus), copy(R)), Composition(copy(R), copy(R_plus)))) {
+#if defined(TC_STATS)
+ fprintf(statsfile, "R_+ -R is not a Must_Be_Subset of R o R_+\n");
+ fprintf(statsfile, "Bill Method is not applicable\n");
+#endif
+ return false;
+ }
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "R_+ -R is a Must_Be_Subset of R o R_+ - good\n");
+ }
+
+// if we are here than all tests worked, and R_+ is transitive closure
+// of R.
+
+#if defined(TC_STATS)
+ fprintf(statsfile,"\nAll three tests succeeded -- exact closure found\n");
+ fprintf(statsfile, "Transitive closure is R_+\n");
+#endif
+// assert(isD_OK(R,D,AxA));
+ return true;
+}
+
+
+/**********************************************************************
+ * print the relation given the bounds on the iteration space
+ * If the bounds are unknown (Bounds is Null), then just print relation
+ * itself
+ ****/
+
+void print_given_bounds( const Relation& R1, NOT_CONST Relation& input_Bounds) {
+ Relation & Bounds = (Relation &)input_Bounds;
+ Relation r;
+ if (Bounds.is_null())
+ r=R1;
+ else
+ r = Gist(copy(R1),copy(Bounds),1);
+ r.print_with_subs(DebugFile);
+}
+
+/**********************************************************************
+ * Investigate closure:
+ * checks if the copmuted approximation on the Transitive closure
+ * is upper and lower bound. If it's both - it's exact.
+ * This function doesn't return any value. It's just prints a lot
+ * of debug output
+ * INPUT:
+ * r - relation
+ * r_closure - approximation on r+.
+ * F - iteration space
+ **********************************************************************/
+
+void InvestigateClosure(Relation r, Relation r_closure, Relation F) {
+ Relation r3;
+ bool LB_res, UB_res;
+
+ if (!F.is_null())
+ F=Cross_Product(copy(F),copy(F));
+
+ fprintf(DebugFile, "\n\n--->investigating the closure of the relation:\n");
+ print_given_bounds(r,F);
+
+ fprintf(DebugFile, "\nComputed closure is:\n");
+ print_given_bounds(r_closure,F);
+
+ r3=Composition(copy(r),copy(r_closure));
+ r3.simplify(1,1);
+
+ r3=Union(r3,Composition(copy(r_closure),copy(r)));
+ r3.simplify(1,1);
+
+ r3=Union(r3,copy(r));
+ r3.simplify(1,1);
+
+ Relation remainder = Difference(copy(r3),copy(r_closure));
+
+ if (!F.is_null()) {
+ r3=Gist(r3,F,1);
+ }
+ r3.simplify(1,1);
+
+ if (!F.is_null()) {
+ r_closure=Gist(r_closure,F,1);
+ }
+ r_closure.simplify(1,1);
+
+ LB_res= Must_Be_Subset(copy(r_closure),copy(r3));
+
+ UB_res=Must_Be_Subset(copy(r3),copy(r_closure));
+
+ fprintf(DebugFile,"\nThe results of checking closure (gist) are:\n");
+ fprintf(DebugFile,"LB - %s, UB - %s\n", LB_res?"YES":"NO", UB_res?"YES":"NO");
+
+ if (!UB_res) {
+ remainder.simplify(2,2);
+ fprintf(DebugFile,"Dependences not included include:\n");
+ print_given_bounds(remainder,F);
+ }
+}
+
+
+
+/****
+ * Transitive closure of the relation containing single conjunct
+ ****/
+
+bool ConjunctTransitiveClosure (NOT_CONST Relation & input_R, Relation & IterationSpace, Relation & R_plus, Relation & R_star) {
+ Relation R = consume_and_regurgitate(input_R);
+ assert(R.has_single_conjunct());
+
+ if (printConjunctClosure) {
+ fprintf(DebugFile,"\nTaking closure of the single conjunct: [\n");
+ R.print_with_subs(DebugFile);
+ }
+#ifdef TC_STATS
+ fprintf(statsfile,"start conjuncttransitiveclosure\n");
+ singles++;
+#endif
+
+ if (is_closure_itself(copy(R))) {
+#ifdef TC_STATS
+ fprintf(statsfile, "Relation is closure itself\n");
+#endif
+ int ndim_all, ndim_domain;
+ R.dimensions(ndim_all,ndim_domain);
+ if (ndim_all == ndim_domain +1) {
+ Relation ispace = Cross_Product(Domain(copy(R)),Range(copy(R)));
+ Relation R_zero = Intersection(copy(ispace),Identity(R.n_inp()));
+ R_star = Hull(Union(copy(R),R_zero),true,1,ispace);
+ R_plus=R;
+ if (printConjunctClosure) {
+ fprintf(DebugFile, "\n] For this relation R+=R\n");
+ fprintf(DebugFile,"R*:\n");
+ R_star.print_with_subs(DebugFile);
+ }
+ return true;
+ }
+ else {
+ R_star=R;
+ R_plus=R;
+ if (printConjunctClosure) {
+ fprintf(DebugFile, "\n] For this relation R+=R, not appropriate for R*\n");
+ }
+ return false;
+ }
+ }
+ else {
+ bool done=false;
+ if (!IterationSpace.is_null()) {
+// Bill's closure requires the information about Iteration Space.
+// So if IterationSpace is NULL, i.e. unknown( e.g. when calling from parser,
+// we do not do Bill's closure
+
+ done = Bill_closure(R, IterationSpace, R_plus, R_star);
+#ifdef TC_STATS
+ fprintf(statsfile,"Bill closure is %sapplicable\n",done?"":"not ");
+#endif
+ if (printConjunctClosure) {
+ if (!done)
+ fprintf(DebugFile, "Bill's closure is not applicable\n");
+ else {
+ fprintf(DebugFile, "Bill's closure is applicable\n");
+ fprintf (DebugFile, " For R:\n");
+ R.print_with_subs(DebugFile);
+ fprintf(DebugFile, "R+ is:\n");
+ R_plus.print_with_subs(DebugFile);
+ fprintf(DebugFile, "R* is:\n");
+ R_star.print_with_subs(DebugFile);
+ fprintf(DebugFile, "\n");
+ InvestigateClosure(R, R_plus, IterationSpace);
+ }
+ }
+ }
+ if (done) {
+ if (printConjunctClosure) {
+ fprintf(DebugFile, "]\n");
+ }
+ return true;
+ }
+ else {
+ // do and check approximate closure (several compositions)
+ R_plus = approx_closure(copy(R), 2);
+#ifdef TC_STATS
+ fprintf(statsfile,"Approximating closure with 2 compositions\n");
+#endif
+ if (printConjunctClosure) {
+ fprintf(DebugFile, "Doing approximate closure\n");
+ InvestigateClosure(R, R_plus, IterationSpace);
+ }
+ } //end else (!done after Bill Closure or Iteration space is NULL)
+
+ if (printConjunctClosure) {
+ fprintf(DebugFile, "]\n");
+ }
+ }
+ return false;
+}
+
+
+/*********************************************************************
+ * try to get conjunct transitive closure.
+ * it we can get it easy get it, return true.
+ * if not - return false
+ ********************************************************************/
+
+
+bool TryConjunctTransitiveClosure (NOT_CONST Relation & input_R, Relation & IterationSpace, Relation & R_plus) {
+ Relation R = consume_and_regurgitate(input_R);
+ assert(R.has_single_conjunct());
+#ifdef TC_STATS
+ fprintf(statsfile,"start tryconjuncttransitiveclosure\n");
+ singles++;
+#endif
+
+ if (printConjunctClosure) {
+ fprintf(DebugFile,"\nTrying to take closure of the single conjunct: [\n");
+ R.print_with_subs(DebugFile);
+ }
+
+ if (is_closure_itself(copy(R))) {
+#ifdef TC_STATS
+ fprintf(statsfile, "Relation is closure itself, leave alone (try)\n");
+#endif
+ if (printConjunctClosure)
+ fprintf(DebugFile, "\n ]The relation is closure itself. Leave it alone\n");
+ return false;
+ }
+ else {
+ bool done;
+ assert(!IterationSpace.is_null());
+ Relation R_star;
+ done = Bill_closure(R, IterationSpace, R_plus, R_star);
+#ifdef TC_STATS
+ fprintf(statsfile, "Bill closure is %sapplicable (try)\n", done?"":"NOT ");
+#endif
+ if (printConjunctClosure) {
+ if (!done)
+ fprintf(DebugFile, "]Bill's closure is not applicable\n");
+ else {
+ fprintf(DebugFile, "]Bill's closure is applicable\n");
+ fprintf (DebugFile, " For R:\n");
+ R.print_with_subs(DebugFile);
+ fprintf(DebugFile, "R+ is:\n");
+ R_plus.print_with_subs(DebugFile);
+ fprintf(DebugFile, "R* is:\n");
+ R_star.print_with_subs(DebugFile);
+ fprintf(DebugFile, "\n");
+ InvestigateClosure(R, R_plus, IterationSpace);
+ }
+ }
+ return done;
+ }
+ //return false;
+}
+
+
+bool Equal (const Relation & r1, const Relation & r2) {
+ bool res=Must_Be_Subset (copy(r1), copy(r2));
+ if (!res)
+ return false;
+ return Must_Be_Subset (copy(r2),copy(r1));
+}
+
+
+void appendClausesToList(Simple_List<Relation> &L, Relation &R) {
+ R.make_level_carried_to(R.n_inp());
+ R.simplify(2,2);
+ for(int depth = R.n_inp(); depth >= -1; depth--)
+ for (DNF_Iterator d(R.query_DNF()); d.live(); d.next())
+ if (d.curr()->query_guaranteed_leading_0s() == depth) {
+ L.append(Relation(R, d.curr()));
+ }
+}
+
+void printRelationList(Simple_List<Relation> &L) {
+ for (Simple_List_Iterator<Relation> li(L); li.live(); li.next()) {
+ li.curr().print_with_subs(DebugFile);
+ }
+}
+
+/****
+ * Transitive closure of the relation containing multiple conjuncts
+ * New (Bill's) version
+ ***/
+
+Relation TransitiveClosure0(NOT_CONST Relation &input_r, int maxExpansion, NOT_CONST Relation & input_IterationSpace) {
+ Relation r = consume_and_regurgitate(input_r);
+ Relation IterationSpace = consume_and_regurgitate(input_IterationSpace);
+
+ if (closure_presburger_debug)
+ fprintf(DebugFile, "\n\n[Transitive closure\n\n");
+
+ Relation result;
+
+#ifdef TC_STATS
+#define TC_RUNS 1
+ int in_conj = copy(r).query_DNF()->length();
+ totals++;
+ fprintf(statsfile,"%d closure run\n", totals);
+ if(is_in_D_form(copy(r)))
+ fprintf(statsfile, "Relation initially in D form\n");
+ else
+ fprintf(statsfile, "Relation initially NOT in D form\n");
+ if(is_lex_forward(copy(r)))
+ fprintf(statsfile, "Relation is initially lex forw\n");
+ else
+ fprintf(statsfile, "Relation is NOT initially lex forw\n");
+ start_clock();
+ for(int tc_loop = 1; tc_loop <= TC_RUNS; tc_loop++) {
+ singles = 0;
+#endif
+
+ assert(!r.is_null());
+ assert(r.n_inp() == r.n_out());
+
+ if (r.max_ufs_arity() > 0) {
+ assert(r.max_ufs_arity() == 0 && "Can't take transitive closure with UFS yet.");
+
+ fprintf(stderr, "Can't take transitive closure with UFS yet.");
+ exit(1);
+ }
+
+ r.simplify(2,2);
+ if (!r.is_upper_bound_satisfiable()) {
+#ifdef TC_STATS
+ int totalTime = clock_diff();
+ fprintf(statsfile, "Relation is unsatisfiable\n");
+ fprintf(statsfile, "input conj: %d output conj: %d #singe conj closures: %d time: %d\n",
+ in_conj, copy(result).query_DNF()->length(),
+ singles,
+ totalTime/TC_RUNS);
+#endif
+
+
+ if (closure_presburger_debug)
+ fprintf(DebugFile, "]TC : relation is false\n");
+ return r;
+ }
+
+ IterationSpace = Hull(Union(Domain(copy(r)),Range(copy(r))), true, 1, IterationSpace);
+
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "r is:\n");
+ r.print_with_subs(DebugFile);
+ fprintf(DebugFile, "IS is:\n");
+ IterationSpace.print_with_subs(DebugFile);
+ }
+ Relation dom = Domain(copy(r));
+ dom.simplify(2,1);
+ Relation rng = Range(copy(r));
+ rng.simplify(2,1);
+ Relation AC = ConicClosure(Restrict_Range(Restrict_Domain(copy(r),copy(rng)),copy(dom)));
+ Relation UB = Union(copy(r),Join(copy(r),Join(AC,copy(r))));
+ UB.simplify(2,1);
+
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "UB is:\n");
+ UB.print_with_subs(DebugFile);
+ }
+ result = Relation::False(r);
+ Simple_List<Relation> firstChoice,secondChoice;
+
+ r.simplify(2,2);
+
+ Relation test = Difference(copy(r),Composition(copy(r),copy(r)));
+ test.simplify(2,2);
+ if (r.number_of_conjuncts() > test.number_of_conjuncts()) {
+ Relation test2 = Union(copy(test),Composition(copy(test),copy(test)));
+ test2.simplify(2,2);
+ if (Must_Be_Subset(copy(r),copy(test2))) r = test;
+ else if (detailedClosureDebug) {
+ fprintf(DebugFile, "Transitive reduction not possible:\n");
+ fprintf(DebugFile, "R is:\n");
+ r.print_with_subs(DebugFile);
+ fprintf(DebugFile, "test2 is:\n");
+ test2.print_with_subs(DebugFile);
+ }
+ }
+
+ r.make_level_carried_to(r.n_inp());
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "r is:\n");
+ r.print_with_subs(DebugFile);
+ }
+ for(int depth = r.n_inp(); depth >= -1; depth--)
+ for (DNF_Iterator d(r.query_DNF()); d.live(); d.next())
+ if (d.curr()->query_guaranteed_leading_0s() == depth) {
+ Relation C(r, d.curr());
+ firstChoice.append(C);
+ }
+
+ bool first_conj=true;
+ for (Simple_List_Iterator<Relation> sli(firstChoice); sli; sli++) {
+ if (first_conj)
+ first_conj=false;
+ else {
+ Relation C_plus;
+ bool change=TryConjunctTransitiveClosure(
+ copy(sli.curr()), IterationSpace, C_plus);
+ if (change)
+ sli.curr()=C_plus;
+ }
+ }
+
+ //compute closure
+ int maxClauses = 3+firstChoice.size()*(1+maxExpansion);
+
+ int resultConjuncts = 0;
+ int numFails = 0;
+ bool resultInexact = false;
+ while (!firstChoice.empty() || !secondChoice.empty()) {
+ Relation R_plus, R_star;
+
+ if (detailedClosureDebug) {
+ fprintf(DebugFile,"Main loop of TC:\n");
+ if (!firstChoice.empty()) {
+ fprintf(DebugFile,"First choice:\n");
+ printRelationList(firstChoice);
+ }
+ if (!secondChoice.empty()) {
+ fprintf(DebugFile,"Second choice:\n");
+ printRelationList(secondChoice);
+ }
+ }
+
+ Relation R;
+ if (!firstChoice.empty())
+ R = firstChoice.remove_front();
+ else R = secondChoice.remove_front();
+
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "Working with conjunct:\n");
+ R.print_with_subs(DebugFile);
+ }
+
+ bool known=ConjunctTransitiveClosure(copy(R),IterationSpace, R_plus, R_star);
+
+ if (!known && numFails < firstChoice.size()) {
+ numFails++;
+ firstChoice.append(R);
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "\nTry another conjunct, R is not suitable\n");
+ R.print_with_subs(DebugFile);
+ }
+ continue;
+ }
+
+
+ if (detailedClosureDebug) {
+ fprintf(DebugFile,"\nR+ is:\n");
+ R_plus.print_with_subs(DebugFile);
+ if (known) {
+ fprintf(DebugFile, "Known R? is :\n");
+ R_star.print_with_subs(DebugFile);
+ }
+ else
+ fprintf(DebugFile, "The R* for this relation is not calculated\n");
+ }
+
+ Relation R_z;
+ if (known) {
+ R_z=Difference(copy(R_star),copy(R_plus));
+ known = R_z.is_upper_bound_satisfiable();
+ if (known) {
+ int d = R.single_conjunct()->query_guaranteed_leading_0s();
+ R_z.make_level_carried_to(min(R.n_inp(),d+1));
+ if (R_z.query_DNF()->length() > 1) known = false;
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "\nForced R_Z to be level carried at level %d\n",min(R.n_inp(),d+1));
+ }
+ }
+ if (detailedClosureDebug) {
+ if (known) {
+ fprintf(DebugFile, "\nDifference between R? and R+ is:\n");
+ R_z.print_with_subs(DebugFile);
+ }
+ else
+ fprintf(DebugFile, "\nR_z is unusable\n");
+ }
+ }
+ else R_z = Relation::False(r);
+
+ if (!known)
+ numFails++;
+ else numFails = 0;
+ if (!known && numFails <= firstChoice.size()) {
+ firstChoice.append(R);
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "\nTry another conjunct, Rz is avaiable for R:\n");
+ R.print_with_subs(DebugFile);
+ }
+ continue;
+ }
+
+ //make N empty list
+ Relation N = Relation::False(r);
+
+ //append R+ to T
+ result = Union(result, copy(R_plus));
+ resultConjuncts++;
+
+ int expansion = maxClauses - (resultConjuncts + 2*firstChoice.size() + secondChoice.size());
+ if (expansion < 0) expansion = 0;
+ if (detailedClosureDebug) {
+ fprintf(DebugFile,"Max clauses = %d\n",maxClauses);
+ fprintf(DebugFile,"result conjuncts = %d\n",resultConjuncts);
+ fprintf(DebugFile,"firstChoice's = %d\n",firstChoice.size());
+ fprintf(DebugFile,"secondChoice's = %d\n",secondChoice.size());
+ fprintf(DebugFile,"Allowed expansion is %d\n",expansion);
+ }
+
+ bool firstPart=true;
+ if (!known && expansion == 0) {
+ if (detailedClosureDebug) {
+ fprintf(DebugFile,"Expansion = 0, R? unknown, skipping composition\n");
+ }
+ if (!resultInexact && detailedClosureDebug) fprintf(DebugFile,"RESULT BECOMES INEXACT 1\n");
+ resultInexact = true;
+ }
+ else
+ for (Simple_List_Iterator<Relation> s(firstChoice);
+ firstPart?
+ (s.live()?true:
+ (s = Simple_List_Iterator<Relation>(secondChoice),
+ firstPart = false,
+ s.live()))
+ :s.live();
+ s.next()) {
+ assert(s.live());
+ Relation C=(s.curr());
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "\nComposing chosen conjunct with C:\n");
+ C.print_with_subs(DebugFile);
+ }
+
+ if (!known) {
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "\nR? is unknown! No debug info here yet\n");
+ }
+ Relation C1=Composition(copy(C), copy(R_plus));
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "\nGenerating \n");
+ C1.print_with_subs(DebugFile);
+ }
+ C1.simplify();
+ Relation newStuff =
+ Difference(
+ Difference(copy(C1),copy(C)),
+ copy(R_plus));
+ newStuff.simplify();
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "New Stuff:\n");
+ newStuff.print_with_subs(DebugFile);
+ }
+ bool C1_contains_new_stuff = newStuff.is_upper_bound_satisfiable();
+ if (C1_contains_new_stuff) {
+ if (newStuff.has_single_conjunct())
+ C1 = newStuff;
+ if (expansion) {
+ N = Union(N,copy(C1));
+ expansion--;
+ }
+ else {
+ if (!resultInexact && detailedClosureDebug) fprintf(DebugFile,"RESULT BECOMES INEXACT 2\n");
+ resultInexact = true;
+ break;
+ }
+ }
+ else C1 = Relation::False(C1);
+
+ Relation C2(Composition(copy(R_plus),copy(C)));
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "\nGenerating \n");
+ C2.print_with_subs(DebugFile);
+ }
+ newStuff =
+ Difference(
+ Difference(
+ Difference(copy(C2),copy(C)),
+ copy(C1)),
+ copy(R_plus));
+ newStuff.simplify();
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "New Stuff:\n");
+ newStuff.print_with_subs(DebugFile);
+ }
+ if (newStuff.is_upper_bound_satisfiable()) {
+ if (newStuff.has_single_conjunct())
+ C2 = newStuff;
+ if (expansion) {
+ N = Union(N,copy(C2));
+ expansion--;
+ }
+ else {
+ if (!resultInexact && detailedClosureDebug) fprintf(DebugFile,"RESULT BECOMES INEXACT 3\n");
+ resultInexact = true;
+ break;
+ }
+ }
+ else C2 = Relation::False(C2);
+
+ if (C1_contains_new_stuff) {
+ Relation C3(Composition(copy(R_plus),copy(C1)));
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "\nGenerating \n");
+ C3.print_with_subs(DebugFile);
+ }
+ newStuff =
+ Difference(
+ Difference(
+ Difference(
+ Difference(copy(C3),copy(C)),
+ copy(C1)),
+ copy(C2)),
+ copy(R_plus));
+ newStuff.simplify();
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "New Stuff:\n");
+ newStuff.print_with_subs(DebugFile);
+ }
+ if (newStuff.is_upper_bound_satisfiable()) {
+ if (newStuff.has_single_conjunct())
+ C3 = newStuff;
+ if (expansion) {
+ N = Union(N,C3);
+ expansion--;
+ }
+ else {
+ if (!resultInexact && detailedClosureDebug) fprintf(DebugFile,"RESULT BECOMES INEXACT 4\n");
+ resultInexact = true;
+ break;
+ }
+ }
+ }
+
+ }
+ else {
+ Relation C_Rz(Composition(copy(C),copy(R_z)));
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "C o Rz is:\n");
+ C_Rz.print_with_subs(DebugFile);
+ }
+
+ Relation Rz_C_Rz(Composition(copy(R_z),copy(C_Rz)));
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "\nRz o C o Rz is:\n");
+ Rz_C_Rz.print_with_subs(DebugFile);
+ }
+
+ if (Equal(C,Rz_C_Rz)) {
+#if defined(TC_STATS)
+ fprintf(statsfile,"weak test selects C?\n");
+#endif
+ Relation tmp = Composition(C,copy(R_star));
+ tmp.simplify();
+ Relation tmp2 = Composition(copy(R_star),copy(tmp));
+ tmp2.simplify();
+ if (Must_Be_Subset(copy(tmp2),copy(tmp)))
+ *s = tmp;
+ else
+ *s = tmp2;
+ if (detailedClosureDebug) {
+ fprintf(DebugFile,"\nC is equal to Rz o C o Rz so R? o C o R? replaces C\n");
+ fprintf(DebugFile, "R? o C o R? is:\n");
+ (*s).print_with_subs(DebugFile);
+ }
+ }
+ else {
+#if defined(TC_STATS)
+ fprintf(statsfile,"weak test fails\n");
+#endif
+ if (Equal(C, C_Rz)) {
+ *s=Composition(copy(C),copy(R_star));
+ Relation p(Composition(copy(R_plus), copy(*s)));
+ p.simplify();
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "\nC is equal to C o Rz, so C o Rz replaces C\n");
+ fprintf (DebugFile, "C o R? is:\n");
+ (*s).print_with_subs(DebugFile);
+ fprintf (DebugFile, "R+ o C o R? is added to list N. It's :\n");
+ p.print_with_subs(DebugFile);
+ }
+ if (!Is_Obvious_Subset(copy(p),copy(R_plus))
+ && !Is_Obvious_Subset(copy(p),copy(C))) {
+ if (expansion) {
+ p.simplify(2,2);
+ expansion--;
+ }
+ else {
+ if (!resultInexact && detailedClosureDebug) fprintf(DebugFile,"RESULT BECOMES INEXACT 5\n");
+ resultInexact = true;
+ break;
+ }
+ }
+ }
+ else {
+ Relation Rz_C(Composition(copy(R_z),copy(C)));
+
+ if (Equal(C,Rz_C)) {
+ *s=Composition(copy(R_star),copy(C));
+ Relation Rstar_C_Rplus(Composition(copy(*s),copy(R_plus)));
+ Rstar_C_Rplus.simplify();
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "\nC is equal to Rz o C , so R? o C replaces C\n");
+ fprintf (DebugFile, "R? o C is:\n");
+ (*s).print_with_subs(DebugFile);
+ fprintf (DebugFile, "R+ o C is added to list N. It's :\n");
+ Rstar_C_Rplus.print_with_subs(DebugFile);
+ }
+ if (!Is_Obvious_Subset(copy(Rstar_C_Rplus),copy(R_plus))
+ && !Is_Obvious_Subset(copy(Rstar_C_Rplus),copy(C))) {
+ if (expansion)
+ N = Union(N,Rstar_C_Rplus);
+ else {
+ if (!resultInexact && detailedClosureDebug) fprintf(DebugFile,"RESULT BECOMES INEXACT 6\n");
+ resultInexact = true;
+ break;
+ }
+ }
+ }
+ else {
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "\nHave to handle it the hard way\n");
+ }
+ Relation C1=Composition(copy(C), copy(R_plus));
+ C1.simplify();
+ if (!Is_Obvious_Subset(copy(C1),copy(R_plus))
+ && !Is_Obvious_Subset(copy(C1),copy(C))) {
+ if (expansion) {
+ N = Union(N,copy(C1));
+ expansion--;
+ }
+ else {
+ if (!resultInexact && detailedClosureDebug) fprintf(DebugFile,"RESULT BECOMES INEXACT 7\n");
+ resultInexact = true;
+ break;
+ }
+ }
+
+ Relation C2(Composition(copy(R_plus),copy(C)));
+ C2.simplify();
+ if (!Is_Obvious_Subset(copy(C2),copy(R_plus))
+ && !Is_Obvious_Subset(copy(C2),copy(C))) {
+ if (expansion) {
+ N = Union(N,C2);
+ expansion--;
+ }
+ else {
+ if (!resultInexact && detailedClosureDebug) {
+ fprintf(DebugFile,"RESULT BECOMES INEXACT 8\n");
+ fprintf(DebugFile,"Have to discard:\n");
+ C2.print_with_subs(DebugFile);
+ }
+ resultInexact = true;
+ break;
+ }
+ }
+ Relation C3(Composition(copy(R_plus),C1));
+ C3.simplify();
+ if (!Is_Obvious_Subset(copy(C3),copy(R_plus)) && !Is_Obvious_Subset(copy(C3),copy(C))) {
+ if (expansion) {
+ N = Union(N,C3);
+ expansion--;
+ }
+ else {
+ if (!resultInexact && detailedClosureDebug)
+ fprintf(DebugFile,"RESULT BECOMES INEXACT 9\n");
+ resultInexact = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //now we processed the first conjunct.
+ if (detailedClosureDebug) {
+ N.simplify(2,2);
+ fprintf(DebugFile, "\nNew conjuncts:\n");
+ N.print_with_subs(DebugFile);
+ }
+
+ N.simplify(2,2);
+ appendClausesToList(secondChoice,N);
+ }
+
+ //Did we do all conjuncts? If not, make T be inexact
+ result.copy_names(r);
+
+ result.simplify(2,2);
+
+ if (!result.is_exact()) {
+ result = Lower_Bound(result);
+ resultInexact = true;
+ }
+ if (resultInexact) {
+ Relation test(Composition(copy(result),copy(result)));
+ test.simplify(2,2);
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "\nResult is:\n");
+ result.print_with_subs(DebugFile);
+ fprintf(DebugFile, "\nResult composed with itself is:\n");
+ test.print_with_subs(DebugFile);
+ }
+ if (!Must_Be_Subset(test,copy(result))) {
+ result = Union(result,Intersection(UB, Relation::Unknown(result)));
+ }
+ }
+
+#ifdef TC_STATS
+ {
+ Relation rcopy = result;
+ Relation test2(Composition(copy(rcopy),copy(rcopy)));
+ test2.simplify(2,2);
+ test2.remove_disjunction_with_unknown();
+ rcopy.remove_disjunction_with_unknown();
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "\nResult is:\n");
+ rcopy.print_with_subs(DebugFile);
+ fprintf(DebugFile, "\nResult composed with itself is:\n");
+ test2.print_with_subs(DebugFile);
+ }
+ if (!Must_Be_Subset(test2,copy(rcopy))) {
+ fprintf(statsfile,"multi TC result is inexact\n");
+ }
+ else
+ fprintf(statsfile,"TC result is exact%s\n", (resultInexact || !rcopy.is_exact())?" despite perceived inexactness":"");
+ }
+#endif
+
+#ifdef TC_STATS
+ }
+ int totalTime = clock_diff();
+ fprintf(statsfile, "input conj: %d output conj: %d #singe conj closures: %d time: %d\n",
+ in_conj, copy(result).query_DNF()->length(),
+ singles,
+ totalTime/TC_RUNS);
+#endif
+
+ if (closure_presburger_debug || detailedClosureDebug) {
+ if (detailedClosureDebug) {
+ fprintf(DebugFile, "\nThe transitive closure is :\n");
+ result.print_with_subs(DebugFile);
+ }
+ fprintf(DebugFile, "\n\n] END Transitive closure\n\n");
+ }
+ return result;
+}
+
+
+Relation TransitiveClosure(NOT_CONST Relation &input_r,
+ int maxExpansion,
+ NOT_CONST Relation & input_IterationSpace) {
+ Relation r = consume_and_regurgitate(input_r);
+ Relation IterationSpace = consume_and_regurgitate(input_IterationSpace);
+ if (r.is_null())
+ return r;
+ if (r.n_out() == 0)
+ throw std::invalid_argument("transitive closure does not apply to set");
+ if (r.n_inp() != r.n_out())
+ throw std::invalid_argument("transitive closure must has the same input and output arity");
+
+ if (closure_presburger_debug) {
+ fprintf(DebugFile,"\nComputing Transitive closure of:\n");
+ r.print_with_subs(DebugFile);
+ fprintf(DebugFile,"\nIteration space is:\n");
+ IterationSpace.print_with_subs(DebugFile);
+ }
+ if (!r.is_upper_bound_satisfiable()) {
+ if (closure_presburger_debug)
+ fprintf(DebugFile, "]TC : relation is false\n");
+ return r;
+ }
+
+ Relation UB = DeltasToRelation(ConicHull(Project_Sym(Deltas(copy(r)))),
+ r.n_inp(),r.n_out());
+ if (closure_presburger_debug) {
+ fprintf(DebugFile,"UB is:\n");
+ UB.print_with_subs(DebugFile);
+ }
+
+ Relation conditions = Restrict_Domain(copy(UB),Domain(copy(r)));
+ conditions.simplify();
+ if (closure_presburger_debug) {
+ fprintf(DebugFile,"Forward reachable is:\n");
+ conditions.print_with_subs(DebugFile);
+ }
+ conditions = Composition(Inverse(copy(UB)),conditions);
+ conditions.simplify();
+ if (closure_presburger_debug) {
+ fprintf(DebugFile,"Backward/forward reachable is:\n");
+ conditions.print_with_subs(DebugFile);
+ }
+ conditions = Range(conditions);
+ conditions.simplify();
+ // conditions = Approximate(conditions);
+ // conditions.simplify();
+ conditions = VennDiagramForm(conditions);
+ conditions.simplify();
+
+ if (closure_presburger_debug) {
+ fprintf(DebugFile,"Condition regions are:\n");
+ conditions.print_with_subs(DebugFile);
+ }
+
+ if (conditions.is_obvious_tautology()) {
+ return TransitiveClosure0(r, maxExpansion, IterationSpace);
+ }
+ else {
+ Relation answer = Relation::False(r);
+ answer.copy_names(r);
+ answer.setup_names();
+
+ for (DNF_Iterator c(conditions.query_DNF()); c.live(); c.next()) {
+ Relation tmp = Relation(conditions, c.curr());
+ if (closure_presburger_debug) {
+ fprintf(DebugFile,"\nComputing Transitive closure:\n");
+ fprintf(DebugFile,"\nRegion:\n");
+ tmp.prefix_print(DebugFile);
+ }
+
+ Relation tmp3 = Restrict_Domain(copy(r),tmp);
+ tmp3.simplify(2,2);
+ if (closure_presburger_debug) {
+ fprintf(DebugFile,"\nRelation:\n");
+ tmp3.prefix_print(DebugFile);
+ }
+
+ answer = Union(answer, TransitiveClosure0(tmp3, maxExpansion,copy(IterationSpace)));
+ }
+ return answer;
+ }
+}
+
+
+/* ********************************* */
+/* Function check if relation */
+/* belong to d-form or */
+/* uniform relaion class */
+/* ********************************* */
+
+Relation is_DForm_or_Uniform(NOT_CONST Relation &r){
+
+ Relation s = consume_and_regurgitate(r);
+ Relation Rtmp, Rdelta, delta;
+
+ delta = Deltas(copy(s));
+ Rdelta = DeltasToRelation(copy(delta), s.n_inp(), s.n_out());
+ Rtmp = DeltasToRelation(Project_Sym(delta), s.n_inp(), s.n_out());
+
+ Rtmp = Restrict_Domain(Rtmp, Domain(copy(Rdelta)));
+ Rtmp = Restrict_Range(Rtmp, Range(Rdelta));
+
+ Rdelta = copy(Rtmp);
+
+ Rtmp = Restrict_Domain(Rtmp, Domain(copy(s)));
+ Rtmp = Restrict_Range(Rtmp, Range(copy(s)));
+
+ if (Must_Be_Subset( copy(Rtmp), copy(s)) && \
+ Must_Be_Subset(copy(s), copy(Rtmp))) {
+ Rtmp = Relation::Null();
+ }
+ else {
+ Rtmp = Rdelta = Relation::Null();
+ }
+
+ return Rdelta;
+ }
+
+
+
+ /* ********************************* */
+ /* Get a conjunction for */
+ /* a given number from set */
+ /* of relations */
+ /* ********************************* */
+
+Relation getConjunctionNr(NOT_CONST Relation &r, int conjNr) {
+
+ Relation s = consume_and_regurgitate(r);
+ int i = 1;
+
+ for (DNF_Iterator c(s.query_DNF()); c; c++,i++) {
+ if ( i == conjNr ) {
+ return Relation(s, c.curr());
+ }
+ }
+
+ return Relation::False(s.n_inp(), s.n_out());
+
+ }
+
+
+/* ********************************* */
+/* Get a common region for */
+/* a given set of relations */
+/* ********************************* */
+
+Relation getCommonRegion( NOT_CONST Relation &r, const long* relTab, const long relCount) {
+
+ Relation s = consume_and_regurgitate(r);
+ Relation commonRegion, Rcurr;
+ long i = 0;
+
+ Rcurr = getConjunctionNr( copy(s), relTab[0]);
+ commonRegion = Union(Domain(copy(Rcurr)), Range(copy(Rcurr)));
+
+ for( i=1; i < relCount; i++ ){
+ Rcurr = getConjunctionNr( copy(s), relTab[i]);
+ commonRegion = Intersection( commonRegion, Union( Domain(copy(Rcurr)), Range(copy(Rcurr))) );
+ }
+
+ return commonRegion;
+ }
+
+
+/* ********************************* */
+/* Get a set of relations */
+/* ********************************* */
+
+Relation getRelationsSet( NOT_CONST Relation &r, const long* relTab, const long relCount) {
+
+ Relation s = consume_and_regurgitate(r);
+ Relation R = Relation::False(s.n_inp(), s.n_out());
+ long i = 0;
+
+ for( i=0; i < relCount; i++ ){
+ R = Union( R, getConjunctionNr( copy(s), relTab[i]) );
+ }
+
+ return R;
+ }
+
+
+/* ********************************* */
+/* Get a set of relations */
+/* from a common region */
+/* ********************************* */
+
+Relation relationsOnCommonRegion( NOT_CONST Relation &r, NOT_CONST Relation &region ) {
+
+ Relation set = consume_and_regurgitate(r);
+ Relation reg = consume_and_regurgitate(region);
+ Relation R = Relation::True(set.n_inp(), set.n_out());
+
+ R = Restrict_Domain(R, copy(reg));
+ R.simplify(2,1);
+ R = Restrict_Range(R, reg);
+ R.simplify(2,1);
+
+ R = Intersection(R, set);
+
+ return R;
+
+ }
+
+
+Relation compose_N(NOT_CONST Relation &input_r) {
+ Relation r = consume_and_regurgitate(input_r);
+ Relation powerR, powerR2;
+
+ r = Union(r, Identity(r.n_inp()));
+ powerR = copy(r);
+
+ for(;;){
+ if (powerR.number_of_conjuncts() > 50) {
+ powerR = Relation::Null();
+ return powerR;
+ }
+
+ powerR2 = Composition(copy(powerR), copy(r));
+ powerR2.simplify(2,1);
+
+ if (Must_Be_Subset( copy(powerR2), copy(powerR))) {
+ powerR2 = Relation::Null();
+ return powerR;
+ }
+
+ powerR = Relation::Null();
+ powerR = copy(powerR2);
+ powerR2 = Relation::Null();
+ }
+}
+
+
+/****************************** */
+/* Check exactness of R+ */
+/* */
+/* Tomasz Klimek 05-06-2010 */
+/****************************** */
+
+bool checkExactness(NOT_CONST Relation &r, NOT_CONST Relation &rplus){
+
+
+Relation s1 = consume_and_regurgitate(r);
+Relation s2 = consume_and_regurgitate(rplus);
+Relation R;
+
+R = Composition(copy(s1), copy(s2));
+R = Union(s1, R);
+
+ if( Must_Be_Subset(copy(s2), copy(R)) && \
+ Must_Be_Subset(copy(R), copy(s2))) {
+ R = Relation::Null();
+ s1 = Relation::Null();
+ return true;
+ }
+
+ R = Relation::Null();
+ s1 = Relation::Null();
+
+ return false;
+
+}
+
+/************************************** */
+/* Calculate approximation of R* */
+/* */
+/* Tomasz Klimek 05-06-2010 */
+/************************************** */
+
+
+Relation ApproxClosure(NOT_CONST Relation &r) {
+
+ Relation s = consume_and_regurgitate(r);
+ Relation R = Relation::False(s.n_inp(), s.n_out());
+ Relation tc = Identity(s.n_inp());
+ Relation Rtmp;
+
+
+ for (DNF_Iterator c(s.query_DNF()); c; c++) {
+ Rtmp = Hull(Project_Sym(Deltas(Relation(s, c.curr()))), false, 1, Relation::Null());
+ R = Union(R, TransitiveClosure(DeltasToRelation(Rtmp,s.n_inp(),s.n_out()), 1, Relation::Null()));
+ }
+
+ for (DNF_Iterator c(R.query_DNF()); c; c++) {
+ Rtmp = Union(Identity(s.n_inp()), Relation(R, c.curr()));
+ tc = Composition(tc, Rtmp);
+ tc = Hull(tc, false, 1, Relation::Null());
+ }
+
+ tc = Restrict_Domain(tc,Domain(copy(s)));
+ tc.simplify(2,1);
+ tc = Restrict_Range(tc,Range(s));
+ tc.simplify(2,1);
+ tc = Intersection(tc, Relation::Unknown(tc));
+
+ return tc;
+}
+
+
+/************************************** */
+/* Calculate R* on unbounded region */
+/* */
+/* Tomasz Klimek 05-06-2010 */
+/************************************** */
+
+Relation ClosureOnUnboundedRegion(NOT_CONST Relation &r) {
+
+ Relation s = consume_and_regurgitate(r);
+ Relation R = Relation::False(s.n_inp(), s.n_out());
+ Relation tc = Identity(s.n_inp());
+ Relation Rtmp,tcTmp;
+
+ for (DNF_Iterator c(s.query_DNF()); c; c++) {
+ Rtmp = is_DForm_or_Uniform(Relation(s, c.curr()));
+
+ if (!(Rtmp.is_null())) {
+ tcTmp = TransitiveClosure(Rtmp, 1, Relation::Null());
+
+ if (!(tcTmp.is_exact())){
+ tcTmp = R = Relation::Null();
+ /* fprintf(DebugFile,"\nTC is inexact!"); */
+ return tcTmp;
+ }
+ }
+ else {
+ R = Relation::Null();
+ /* fprintf(DebugFile,"\nR is not d-form relation!"); */
+ return Relation::Null();
+ }
+
+ R = Union(R, tcTmp);
+ }
+
+ for (DNF_Iterator c(R.query_DNF()); c; c++) {
+ Rtmp = Union(Identity(s.n_inp()), Relation(R, c.curr()));
+ tc = Composition(tc, Rtmp);
+ tc.simplify(2,1);
+ }
+
+ tc = Difference(tc, Identity(s.n_inp()));
+
+ return tc;
+
+}
+
+
+
+
+/******************************* */
+/* Try to select sets of domain */
+/* and range */
+/* */
+/* Tomasz Klimek 05-06-2010 */
+/******************************* */
+
+Relation SelectRegionForClosure(NOT_CONST Relation &r){
+
+ Relation s = consume_and_regurgitate(r);
+ Relation DR = Union(Domain(copy(s)),Range(copy(s)));
+ Relation region,tc,tcTmp;
+
+ region = SimpleHull(copy(DR));
+ region.simplify(2,1);
+
+ tc = ClosureOnUnboundedRegion(copy(s));
+
+ if (tc.is_null()) {
+ return tc;
+ }
+
+ tcTmp = Restrict_Domain(copy(tc),copy(region));
+ tcTmp.simplify(2,1);
+ tcTmp = Restrict_Range(tcTmp,region);
+ tcTmp.simplify(2,1);
+
+ if (checkExactness(copy(s), copy(tcTmp))) {
+ s = tc = Relation::Null();
+ return tcTmp;
+ }
+
+ tcTmp = Relation::Null();
+ region = Hull(DR,false,1,Relation::Null());
+
+ tcTmp = Restrict_Domain(copy(tc),copy(region));
+ tcTmp.simplify(2,1);
+ tcTmp = Restrict_Range(tcTmp,region);
+ tcTmp.simplify(2,1);
+
+ if (checkExactness(copy(s), copy(tcTmp))) {
+ s = tc = Relation::Null();
+ return tcTmp;
+ }
+
+ tcTmp = Relation::Null();
+
+ tc = Restrict_Domain(tc,Domain(copy(s)));
+ tc.simplify(2,1);
+ tc = Restrict_Range(tc,Domain(copy(s)));
+ tc.simplify(2,1);
+
+ if (checkExactness(copy(s), copy(tc))) {
+ s = Relation::Null();
+ return tc;
+ }
+
+ tc = Relation::Null();
+
+ return ApproxClosure(s);
+
+}
+
+
+
+
+/************************************** */
+/* Calculate R* */
+/* */
+/* Tomasz Klimek 05-06-2010 */
+/************************************** */
+
+Relation calculateTransitiveClosure(NOT_CONST Relation &r) {
+
+ Relation s = consume_and_regurgitate(r);
+ Relation tc = Relation::False(s.n_inp(), s.n_out());
+ long* relationsSet = NULL;
+ Relation commonRegion, regionTmp;
+ Relation inputRelations;
+ long i,j=-1;
+ long N,M;
+ Relation R;
+
+
+ commonRegion = SelectRegionForClosure(copy(s));
+
+ if (commonRegion.is_null()) {
+ return ApproxClosure(s);
+ }
+
+ if (commonRegion.is_exact()) {
+ return commonRegion;
+ }
+
+ commonRegion = Relation::Null();
+ N = M = s.number_of_conjuncts();
+ relationsSet = (long*)calloc(N,sizeof(long));
+
+ if (relationsSet == NULL) {
+ return Relation::False(s.n_inp(), s.n_out());
+ }
+
+ for (; N > 1;) {
+ for ( i=0; i<N; i++ ) {
+ if ( i < j ) {
+ continue;
+ }
+ else if ( j == -1 ) {
+ relationsSet[i] = 1;
+ }
+ else if ( i > j ) {
+ relationsSet[i] = relationsSet[i-1] + 1;
+ }
+ else if ( i == j ) {
+ relationsSet[i] += 1;
+ }
+ if ( relationsSet[i] <= M ) {
+ j = i;
+ }
+ else {
+ j = i - 1;
+ break;
+ }
+ }
+
+ if ( j+1 == N) {
+ /* fprintf(DebugFile,"\n");
+ for(i=0;i<N;i++){
+ fprintf(DebugFile," %ld", relationsSet[i]);
+ }
+ fprintf(DebugFile,"\n"); */
+
+ commonRegion = getCommonRegion( copy(s), relationsSet, N);
+ commonRegion.simplify(2,1);
+ inputRelations = getRelationsSet( copy(s), relationsSet, N);
+ inputRelations.simplify(2,1);
+
+ /* ******************* */
+ /* Check on rectangle */
+ /* ******************* */
+ regionTmp = SimpleHull(copy(commonRegion));
+ regionTmp.simplify(2,1);
+ R = relationsOnCommonRegion( copy(inputRelations), regionTmp);
+ R.simplify(2,1);
+ regionTmp = SelectRegionForClosure(R);
+
+ if (regionTmp.is_exact()) {
+ /* fprintf(DebugFile,"\nDescribed on rectangle region\n"); */
+ tc = Union( tc, regionTmp );
+ }
+ else {
+ /* ******************* */
+ /* Check on hull */
+ /* ******************* */
+
+ R = Relation::Null();
+ regionTmp = Relation::Null();
+ regionTmp = Hull(copy(commonRegion),false,1,Relation::Null());
+ regionTmp.simplify(2,1);
+ R = relationsOnCommonRegion( copy(inputRelations), regionTmp);
+ R.simplify(2,1);
+ regionTmp = SelectRegionForClosure(R);
+
+ if (regionTmp.is_exact()) {
+ /* fprintf(DebugFile,"\nDescribed on Hull\n"); */
+ tc = Union( tc, regionTmp);
+ }
+ else {
+ /* ********************************** */
+ /* Check on sets of domain and range */
+ /* ********************************** */
+
+ R = Relation::Null();
+ regionTmp = Relation::Null();
+ R = relationsOnCommonRegion( copy(inputRelations), copy(commonRegion) );
+ R.simplify(2,1);
+ regionTmp = SelectRegionForClosure(R);
+
+ if (regionTmp.is_exact()) {
+ /* fprintf(DebugFile,"\nDescribed on sets of doamin and range\n"); */
+ tc = Union( tc, regionTmp );
+ }
+ else {
+ commonRegion = Relation::Null();
+ inputRelations = Relation::Null();
+ regionTmp = Relation::Null();
+ R = Relation::Null();
+
+ return ApproxClosure(s);
+ }
+ }
+ }
+
+ commonRegion = Relation::Null();
+ inputRelations = Relation::Null();
+
+ regionTmp = Relation::Null();
+ R = Relation::Null();
+ }
+
+ if ( j == -1 ) N--;
+
+ }
+
+ R = Relation::Null();
+
+ for (DNF_Iterator c(s.query_DNF()); c; c++) {
+ if (!Must_Be_Subset(Relation(s, c.curr()), copy(tc))) {
+ /* fprintf(DebugFile,"\nIs not a subset\n"); */
+ tc = Union( tc, SelectRegionForClosure(Relation(s, c.curr())));
+ }
+ }
+
+ if (!(tc.is_exact())){
+ return ApproxClosure(s);
+ }
+
+ tc = compose_N(tc);
+
+ if (tc.is_null()) {
+ return ApproxClosure(s);
+ }
+
+ return tc;
+
+}
+
+
+
+
+
+} // namespace
diff --git a/omegalib/omega/src/evac.cc b/omegalib/omega/src/evac.cc
new file mode 100644
index 0000000..ff872c9
--- /dev/null
+++ b/omegalib/omega/src/evac.cc
@@ -0,0 +1,339 @@
+#if defined STUDY_EVACUATIONS
+
+#include <omega/Relations.h>
+#include <omega/pres_conj.h>
+#include <omega/evac.h>
+#include <omega/omega_core/debugging.h>
+#include <omega/omega_core/oc_i.h>
+
+namespace omega {
+
+int evac_debug = 0;
+
+char *evac_names[] = { "trivial",
+ "offset",
+ "subseq",
+ "off_sub",
+// "perm.",
+ "affine",
+ "nasty" };
+
+int single_evacs[evac_nasty+1];
+int double_evacs[evac_nasty+1][evac_nasty+1];
+
+/*
+ * We're going to try to describe the equalities among a set of variables
+ * We want to perform some substitutions to ensure that we don't miss
+ * v_1 = v_2 due to its expression as v_1 = v_3 && v_2 = v_3
+ * We therefore try to substitute out all variables that we don't care
+ * about (e.g., v_3 in the above example).
+ */
+
+static bool try_to_sub(Problem *p, int col) {
+ int e, i;
+
+ if (!p->variablesInitialized) {
+ p->initializeVariables();
+ }
+
+ assert(col <= p->nVars);
+ assert(!inApproximateMode);
+
+ for(e=0;e<p->nEQs;e++)
+ if (p->EQs[e].coef[col] == 1 || p->EQs[e].coef[col] == -1) {
+ int var = p->var[col];
+ p->doElimination(e, col);
+ if (col != p->nVars + 1)
+ p->forwardingAddress[p->var[p->nVars+1]] = col;
+ assert(p->SUBs[p->nSUBs-1].key = var);
+ p->forwardingAddress[var] = -p->nSUBs;
+ break;
+ }
+
+ if (e == p->nEQs)
+ return false;
+
+ for (int c=0;c<=p->nVars;c++) {
+ assert(p->EQs[e].coef[c] == 0);
+ }
+
+ p->nEQs--;
+ if (e < p->nEQs) eqnncpy(&p->EQs[e], &p->EQs[p->nEQs], p->nVars);
+
+ for (i = 0; i < p->nSUBs; i++) {
+ assert(p->forwardingAddress[p->SUBs[i].key] == -i - 1);
+ }
+
+ return true;
+}
+
+
+// should be static, but must be a friend
+bool check_subseq_n(Conjunct *c, Sequence<Variable_ID> &evac_from, Sequence<Variable_ID> &evac_to, int n_from, int n_to, int max_arity, int n, bool allow_offset) {
+ // check each position v to see if from[v] == to[v+n] (+ offset)
+
+ assert(max_arity + n <= n_to);
+
+ for (int v = 1; v <= max_arity; v++){
+ // first, get rid of possible interlopers:
+ int col;
+ Conjunct *d = c->copy_conj_same_relation();
+ for (int tv = 1; tv <= n_to; tv++)
+ if (tv != v+n)
+ if ((col = d->find_column(evac_to[tv])) > 0)
+ try_to_sub(d->problem, col);
+ for (int fv = 1; fv <= n_from; fv++)
+ if (fv != v)
+ if ((col = d->find_column(evac_from[fv])) > 0)
+ try_to_sub(d->problem, col);
+
+ int c_to = d->find_column(evac_to[v+n]);
+ int c_from = d->find_column(evac_from[v]);
+ assert(c_to > 0);
+ assert(c_from > 0);
+ assert(c_to != c_from);
+
+ // now, just look for an equality c_to = c_from + offset
+
+ bool found_needed_eq = false;
+
+ for (int e = 0; e < d->problem->nEQs; e++) {
+ if (d->problem->EQs[e].coef[c_from] != 0) {
+ for (int k = allow_offset?1:0; k < d->problem->nVars; k++)
+ if (k!=c_to && k!=c_from && d->problem->EQs[e].coef[k]!=0)
+ break; // this EQ is not what we need
+ if (k == d->problem->nVars) { // this EQ is what we need
+ found_needed_eq = true;
+ break;
+ }
+ }
+ }
+
+ delete d;
+
+ if (!found_needed_eq)
+ return false; // no EQ did what we need
+ }
+
+ return true;
+}
+
+void assert_subbed_syms(Conjunct *c) {
+ int v, col;
+
+ // where possible, symbolic constants must have been subbed out
+ for (v = 1; v <= c->relation()->global_decls()->length(); v++)
+ if ((col = c->find_column((*c->relation()->global_decls())[v]))>0)
+ assert(!try_to_sub(c->problem, col));
+}
+
+
+static bool check_offset(Conjunct *c, Sequence<Variable_ID> &evac_from, Sequence<Variable_ID> &evac_to, int n_from, int n_to, int max_arity) {
+ assert_subbed_syms(c);
+
+ return check_subseq_n(c,evac_from,evac_to,n_from,n_to,max_arity,0,true);
+}
+
+static bool check_subseq(Conjunct *c, Sequence<Variable_ID> &evac_from, Sequence<Variable_ID> &evac_to, int n_from, int n_to, int max_arity) {
+ assert_subbed_syms(c);
+
+ for (int i = 0; i <= n_to - max_arity; i++)
+ if (check_subseq_n(c,evac_from,evac_to,n_from,n_to,max_arity,i,false))
+ return true;
+
+ return false;
+}
+
+static bool check_offset_subseq(Conjunct *c, Sequence<Variable_ID> &evac_from, Sequence<Variable_ID> &evac_to, int n_from, int n_to, int max_arity) {
+ assert_subbed_syms(c);
+
+ for (int i = 0; i <= n_to - max_arity; i++)
+ if (check_subseq_n(c,evac_from,evac_to,n_from,n_to,max_arity,i,true))
+ return true;
+
+ return false;
+}
+
+bool check_affine(Conjunct *d, Sequence<Variable_ID> &evac_from, Sequence<Variable_ID> &evac_to, int n_from, int n_to, int max_arity) {
+ int v, col;
+ Conjunct *c = d->copy_conj_same_relation();
+ assert_subbed_syms(c);
+
+ // try to find substitutions for all evac_to variables
+ for (v = 1; v <= max_arity; v++)
+ if ((col = c->find_column(evac_to[v])) > 0)
+ try_to_sub(c->problem, col);
+
+ // any that didn't have substitutions, aren't affine
+ for (v = 1; v <= max_arity; v++)
+ if (c->find_column(evac_to[v]) >= 0) {
+ delete c;
+ return false;
+ }
+
+ // FERD - disallow symbolic constants?
+ delete c;
+ return true;
+}
+
+
+evac study(Conjunct *C, Sequence<Variable_ID> &evac_from, Sequence<Variable_ID> &evac_to, int n_from, int n_to, int max_arity) {
+ assert(max_arity > 0);
+ assert(max_arity <= C->relation()->n_inp());
+ assert(max_arity <= C->relation()->n_out());
+
+ assert((&evac_from == &input_vars && &evac_to == &output_vars) ||
+ (&evac_from == &output_vars && &evac_to == &input_vars));
+
+ evac ret = evac_nasty;
+
+ if (C->query_guaranteed_leading_0s() >= max_arity)
+ ret = evac_trivial;
+ else {
+ Conjunct *c = C->copy_conj_same_relation();
+ assert(c->relation() == C->relation());
+
+ if (evac_debug >= 3) {
+ fprintf(DebugFile, "About to study %s evacuation for conjunct\n",
+ &evac_from == &input_vars ? "In-->Out" : "Out-->In");
+ use_ugly_names++;
+ C->prefix_print(DebugFile);
+ use_ugly_names--;
+ }
+
+ bool sat = simplify_conj(c, true, 4, black);
+ assert(sat); // else c is deleted
+
+ int v, col;
+
+ // Substitute out all possible symbolic constants
+ assert(c->problem->nSUBs == 0);
+ for (v = 1; v <= c->relation()->global_decls()->length(); v++)
+ if ((col = c->find_column((*c->relation()->global_decls())[v]))>0)
+ try_to_sub(c->problem, col);
+
+ if (check_offset(c, evac_from, evac_to, n_from, n_to, max_arity))
+ ret = evac_offset;
+ else if (check_subseq(c, evac_from, evac_to, n_from, n_to, max_arity))
+ ret = evac_subseq;
+ else if (check_offset_subseq(c, evac_from, evac_to, n_from, n_to, max_arity))
+ ret = evac_offset_subseq;
+ else if (check_affine(c, evac_from, evac_to, n_from, n_to, max_arity))
+ ret = evac_affine;
+
+ delete c;
+ }
+
+ if (evac_debug >= 2) {
+ if ((evac_debug == 2 && ret != evac_trivial && ret != evac_nasty)) {
+ fprintf(DebugFile, "Studied %s evacuation for conjunct\n",
+ &evac_from == &input_vars ? "In-->Out" : "Out-->In");
+ use_ugly_names++;
+ C->prefix_print(DebugFile);
+ use_ugly_names--;
+ }
+
+ fprintf(DebugFile, "Saw evacuation type %s\n", evac_names[ret]);
+ }
+
+ return ret;
+}
+
+
+void study_evacuation(Conjunct *C, which_way dir, int max_arity) {
+ if (evac_debug > 0) {
+ assert(max_arity >= 0);
+
+ if (max_arity > 0)
+ if (dir == in_to_out) {
+ assert(max_arity <= C->relation()->n_inp());
+ if (max_arity <= C->relation()->n_out())
+ single_evacs[study(C, input_vars, output_vars,
+ C->relation()->n_inp(),
+ C->relation()->n_out(),
+ max_arity)]++;
+ }
+ else {
+ assert(max_arity <= C->relation()->n_out());
+ if (max_arity <= C->relation()->n_inp())
+ single_evacs[study(C, output_vars, input_vars,
+ C->relation()->n_out(),
+ C->relation()->n_inp(),
+ max_arity)]++;
+ }
+ }
+}
+
+void study_evacuation(Conjunct *C1, Conjunct *C2, int max_arity) {
+ if (evac_debug > 0) {
+ assert(max_arity >= 0);
+ assert(max_arity <= C1->relation()->n_inp());
+ assert(C2->relation()->n_out() == C1->relation()->n_inp());
+
+ if (max_arity > 0)
+ if (max_arity <= C1->relation()->n_out() &&
+ max_arity <= C2->relation()->n_inp()) {
+ double_evacs[study(C1, input_vars, output_vars,
+ C1->relation()->n_inp(),
+ C1->relation()->n_out(),
+ max_arity)]
+ [study(C2, output_vars, input_vars,
+ C2->relation()->n_out(),
+ C2->relation()->n_inp(),
+ max_arity)]++;
+ }
+ else if (max_arity <= C1->relation()->n_out()) {
+ single_evacs[study(C1, input_vars, output_vars,
+ C1->relation()->n_inp(),
+ C1->relation()->n_out(),
+ max_arity)]++;
+ }
+ else if (max_arity <= C2->relation()->n_inp()) {
+ single_evacs[study(C2, output_vars, input_vars,
+ C2->relation()->n_out(),
+ C2->relation()->n_inp(),
+ max_arity)]++;
+ }
+ }
+}
+
+class Evac_info_printer {
+public:
+ ~Evac_info_printer();
+};
+
+Evac_info_printer::~Evac_info_printer() {
+ if (evac_debug > 0) {
+ int i, j;
+
+ fprintf(DebugFile, "\n");
+
+ fprintf(DebugFile, "SINGLE");
+ for (i = 0; i <= evac_nasty; i++)
+ fprintf(DebugFile, "\t%s", evac_names[i]);
+ fprintf(DebugFile, "\n");
+
+ for (i = 0; i <= evac_nasty; i++)
+ fprintf(DebugFile, "\t%d", single_evacs[i]);
+ fprintf(DebugFile, "\n\n");
+
+
+ fprintf(DebugFile, "DOUBLE");
+ for (i = 0; i <= evac_nasty; i++)
+ fprintf(DebugFile, "\t%s", evac_names[i]);
+ fprintf(DebugFile, "\n");
+
+ for (i = 0; i <= evac_nasty; i++) {
+ fprintf(DebugFile, "%s\t", evac_names[i]);
+ for (j = 0; j <= evac_nasty; j++)
+ fprintf(DebugFile, "%d\t", double_evacs[i][j]);
+ fprintf(DebugFile, "\n");
+ }
+ }
+}
+
+static Evac_info_printer print_stats_at_exit;
+
+} // namespace
+
+#endif
diff --git a/omegalib/omega/src/farkas.cc b/omegalib/omega/src/farkas.cc
new file mode 100644
index 0000000..1b3ef87
--- /dev/null
+++ b/omegalib/omega/src/farkas.cc
@@ -0,0 +1,480 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 the Omega Project Team
+ Copyright (C) 2005-2011 Chun Chen
+ All Rights Reserved.
+
+ Purpose:
+ convert to dual cone for manipulation.
+
+ Notes:
+
+ History:
+*****************************************************************************/
+
+#include <basic/Bag.h>
+#include <basic/Map.h>
+#include <omega.h>
+#include <omega/farkas.h>
+
+namespace omega {
+
+static Global_Var_Decl constant_term("constantTerm");
+
+// class Constant_Term {
+// public:
+// Global_Var_Decl *p;
+
+// Constant_Term();
+// ~Constant_Term();
+// };
+
+// namespace {
+// Constant_Term constant_term;
+// }
+
+// Constant_Term::Constant_Term() {
+// p = new Global_Var_Decl("constantTerm");
+// }
+
+// Constant_Term::~Constant_Term() {
+// delete p;
+// }
+
+// Global_Var_ID coefficient_of_constant_term = constant_term.p;
+
+Global_Var_ID coefficient_of_constant_term = &constant_term;
+
+extern int inApproximateMode;
+
+int farkas_debug = 0;
+
+coef_t farkasDifficulty;
+
+//*****************************************************************************
+//
+// forall x1,..,xn s.t. a10 + a11 x1 + ... + a1n xn >= 0 and
+// ...
+// am0 + am1 x1 + ... + amn xn >= 0
+//
+// b0 + b1 x1 + ... + bn xn >= 0
+//
+// iff
+//
+// exists lambda_0,...,lambda_m >= 0 s.t.
+// forall x1,..,xn
+// lambda_0 +
+// lambda_1 ( a10 + a11 x1 + ... + a1n xn) +
+// ...
+// lambda_m ( am0 + am1 x1 + ... + amn xn) =
+//
+// b0 + b1 x1 + ... + bn xn
+//
+// iff
+//
+// exists lambda_0,...,lambda_m >= 0 s.t.
+// lambda_0 + sum_i ( lambda_i a_i0 ) = b_0
+// for j in 1..n
+// sum_i ( a_ij lambda_i ) = b_j
+//
+// iff
+//
+// exists lambda0,...,lambda_m s.t.
+// lambda1,...,lambda_m >= 0
+// lambda0 >= 0
+// lambda_0 = b_0 - sum_i ( lambda_i a_i0 )
+// for j in 1..n
+// sum_i ( a_ij lambda_i ) = b_j
+// iff
+//
+// exists lambda1,...,lambda_m s.t.
+// lambda1,...,lambda_m >= 0
+// b_0 - sum_i ( lambda_i a_i0 ) >= 0
+// for j in 1..n
+// sum_i ( a_ij lambda_i ) = b_j
+//
+// a_ij come from relation rel
+//
+// x_1,...,x_n are input and output variables from rel.
+//
+// b_0,...,b_m are input and output arrays of coef_vars
+//
+//*****************************************************************************
+
+
+// Given a Relation/Set R
+// Compute A,B,C such that
+// Ax+By + C >= 0 is true for all x,y in R
+// iff [A,B] : constantTerm=C is in AffineClosure(R)
+// Note: constantTerm is a special global variable
+// If constantTerm appears in the incoming relation
+// then set it's coefficient to be 1 in the result
+
+
+// # For example, given
+// R := {[i,j] : 1 <= i <= 10 && 1 <= j <= n};
+// # the farkas closure of R is:
+// # ac := approximate {[i,j] : exists (lambda0, lambda1,lambda2,lambda3,lambda4 :
+// # 0 <= lambda1,lambda2,lambda3,lambda4
+// # && constantTerm - (-lambda1+ 10 lambda2 - lambda3) >= 0
+// # && i = lambda1-lambda2
+// # && j = lambda3-lambda4
+// # && n = lambda4)};
+// #
+// # ac;
+//
+// {[i,j]: 0 <= n && 0 <= n+constantTerm+i+j
+// && 0 <= n+constantTerm+10i+j && 0 <= n+j}
+//
+// The ConvexCombination of ac is:
+//#
+//# approximate {[i,j] : exists (lambda1,lambda2,lambda3,lambda4 :
+//# 0 <= lambda1,lambda2,lambda3,lambda4
+//# && 1 = lambda2+lambda3
+//# && i = lambda2+10lambda3
+//# && j = lambda2+lambda3+lambda4
+//# && n = lambda1+lambda2+lambda3+lambda4
+//# )};
+//
+//{[i,j]: 1 <= i <= 10 && 1 <= j <= n}
+//
+
+static void handleVariable(Relation &farkas, Conjunct * conj,
+ F_And* and_node,
+ Map<GEQ_Handle, Variable_ID> &gMap,
+ Map<EQ_Handle, Variable_ID> &eMap,
+ Variable_ID v) {
+ use_ugly_names++;
+ if (farkas_debug > 1) {
+ fprintf(DebugFile,"Building equality for %s\n", v->name().c_str());
+ }
+
+ EQ_Handle e = and_node->add_EQ();
+
+ for (GEQ_Iterator g = conj->GEQs(); g.live(); g.next())
+ if (gMap(*g) != (Variable_ID) 0) {
+ coef_t c = (*g).get_coef(v);
+ if (c != 0) {
+ e.update_coef(gMap(*g), c);
+ }
+ }
+
+ for (EQ_Iterator eq = conj->EQs(); eq.live(); eq.next())
+ if (eMap(*eq) != (Variable_ID) 0) {
+ coef_t c = (*eq).get_coef(v);
+ if (c != 0) {
+ e.update_coef(eMap(*eq), c);
+ }
+ }
+
+ if ((v)->kind() == Global_Var &&
+ (v)->get_global_var() == coefficient_of_constant_term)
+ e.update_const(-1);
+ else
+ e.update_coef(farkas.get_local(v), -1);
+
+ e.finalize();
+ if (farkas_debug > 1) {
+ fprintf(DebugFile,"Constraint is %s\n", e.print_to_string().c_str());
+ }
+ use_ugly_names--;
+}
+
+
+Relation Farkas(NOT_CONST Relation &input_R, Farkas_Type op, bool early_bailout) {
+ assert(!input_R.is_null());
+ int saved_use_ugly_names = use_ugly_names;
+
+ use_ugly_names++;
+ farkasDifficulty = 0;
+
+ Relation R = consume_and_regurgitate(input_R);
+
+ if (op == Basic_Farkas || op == Decoupled_Farkas) {
+ R.simplify(2, 4);
+ R = Approximate(R, false);
+ }
+
+ Relation result = Relation::False(R);
+
+ if (farkas_debug) {
+ fprintf(DebugFile,"Computing farka of: [\n");
+ R.prefix_print(DebugFile);
+ }
+
+ Variable_ID_Tuple vars;
+ for (Variable_ID_Iterator v(*R.global_decls()); v; v++) vars.append(*v);
+ if (R.is_set())
+ for(int i=1; i <= R.n_set(); i++) vars.append(R.set_var(i));
+ else {
+ int i;
+ for(i=1; i <= R.n_inp(); i++) vars.append(R.input_var(i));
+ for(i=1; i <= R.n_out(); i++) vars.append(R.output_var(i));
+ }
+
+ Set<Variable_ID> empty;
+ Variable_ID_Tuple owners;
+ Map<Variable_ID, Set<Variable_ID> > connectedVariables(empty);
+
+ if (op == Decoupled_Farkas) {
+ for (Variable_ID_Iterator v(*R.global_decls()); v; v++)
+ if ((*v)->kind() == Global_Var) {
+ Global_Var_ID g = (*v)->get_global_var();
+ if (g->arity() > 0) {
+ if (R.is_set())
+ for(int i=1; i <= g->arity(); i++)
+ (*v)->UF_union(R.set_var(i));
+ else if ((*v)->function_of() == Input_Tuple)
+ for(int i=1; i <= g->arity(); i++)
+ (*v)->UF_union(R.input_var(i));
+ else
+ for(int i=1; i <= g->arity(); i++)
+ (*v)->UF_union(R.output_var(i));
+ }
+ }
+
+ for (DNF_Iterator s(R.query_DNF()); s.live(); s.next()) {
+ for (Variable_ID_Iterator v1(*(*s)->variables()); v1; v1++) {
+ for (EQ_Iterator eq = (*s)->EQs(); eq.live(); eq.next())
+ if ((*eq).get_coef(*v1))
+ for (Variable_ID_Iterator v2(*(*s)->variables()); v2; v2++)
+ if ((*eq).get_coef(*v2))
+ (*v1)->UF_union(*v2);
+ for (GEQ_Iterator g = (*s)->GEQs(); g.live(); g.next())
+ if ((*g).get_coef(*v1))
+ for (Variable_ID_Iterator v2(*(*s)->variables()); v2; v2++)
+ if ((*g).get_coef(*v2))
+ (*v1)->UF_union(*v2);
+ }
+ }
+ for (Variable_ID_Iterator v3(vars); v3.live(); v3.next())
+ connectedVariables[(*v3)->UF_owner()] |= *v3;
+
+ foreach_map(v,Variable_ID,s,Set<Variable_ID>,connectedVariables,
+ owners.append(v);
+ if (farkas_debug) {
+ fprintf(DebugFile,"%s:",v->char_name());
+ foreach(v2,Variable_ID,s,
+ fprintf(DebugFile," %s",v2->char_name());
+ );
+ fprintf(DebugFile,"\n");
+ }
+ );
+ }
+
+ Variable_ID_Iterator varGroup(owners);
+ int lambda_cnt = 1;
+
+ Relation partialResult;
+ bool firstGroup = true;
+ try {
+ while ((op == Decoupled_Farkas && varGroup.live())
+ || (op != Decoupled_Farkas && firstGroup)) {
+
+ if (farkas_debug && op == Decoupled_Farkas) {
+ fprintf(DebugFile,"[Computing decoupled farkas for:");
+ foreach(v2,Variable_ID,connectedVariables(varGroup.curr()),
+ fprintf(DebugFile," %s",v2->char_name());
+ );
+ fprintf(DebugFile,"\n");
+ }
+ firstGroup = false;
+ partialResult = Relation::True(R);
+ coef_t difficulty = 0;
+ for (DNF_Iterator s(R.query_DNF()); s.live(); s.next()) {
+ int nz;
+ coef_t m,sum;
+ (*s)->difficulty(nz,m,sum);
+ difficulty = max((coef_t) nz,2*nz+2*m+sum);
+ if (farkas_debug) {
+ fprintf(DebugFile,"Computing farka of conjunct: \n");
+ (*s)->prefix_print(DebugFile);
+ fprintf(DebugFile,"Difficulty is " coef_fmt "(%d," coef_fmt "," coef_fmt ")\n", difficulty,nz,m,sum);
+ }
+ if (early_bailout && difficulty >= 500) {
+ farkasDifficulty = difficulty;
+ if (farkas_debug) {
+ fprintf(DebugFile,"Too ugly, returning dull result\n");
+ }
+ use_ugly_names--;
+ if (op == Basic_Farkas || op == Decoupled_Farkas)
+ return Relation::False(partialResult);
+ else return Relation::True(partialResult);
+ }
+ Relation farkas = Relation::Empty(R);
+ farkas.copy_names(R);
+ F_Exists* exist = farkas.add_exists();
+ F_And* and_node = exist->add_and();
+ Map<GEQ_Handle, Variable_ID> gMap((Variable_ID)0);
+ Map<EQ_Handle, Variable_ID> eMap((Variable_ID)0);
+ for (EQ_Iterator eq = (*s)->EQs(); eq.live(); eq.next()) {
+ if (op == Decoupled_Farkas) {
+ bool ShouldConsider = true;
+ for (Variable_ID_Iterator v(*(*s)->variables()); v; v++) {
+ if ((*eq).get_coef(*v) != 0
+ && (*v)->UF_owner() != varGroup.curr()) {
+ ShouldConsider = false;
+ break;
+ }
+ }
+ if (!ShouldConsider) continue;
+ }
+ char s[10];
+ sprintf(s, "lambda%d", lambda_cnt++);
+ eMap[*eq] = exist->declare(s);
+ assert(op == Basic_Farkas || op == Decoupled_Farkas
+ || (*eq).get_const() == 0);
+ }
+ for (GEQ_Iterator g = (*s)->GEQs(); g.live(); g.next()) {
+ if (op == Decoupled_Farkas) {
+ bool ShouldConsider = true;
+ for (Variable_ID_Iterator v(*(*s)->variables()); v; v++) {
+ if ((*g).get_coef(*v) != 0
+ && (*v)->UF_owner() != varGroup.curr()) {
+ ShouldConsider = false;
+ break;
+ }
+ }
+ if (!ShouldConsider) continue;
+ }
+ char s[10];
+ sprintf(s, "lambda%d", lambda_cnt++);
+ Variable_ID lambda = exist->declare(s);
+ GEQ_Handle positive;
+ switch(op) {
+ case Positive_Combination_Farkas:
+ case Convex_Combination_Farkas:
+ case Basic_Farkas:
+ case Decoupled_Farkas:
+ positive = and_node->add_GEQ();
+ positive.update_coef(lambda, 1);
+ positive.finalize();
+ break;
+ case Linear_Combination_Farkas:
+ case Affine_Combination_Farkas:
+ break;
+ }
+ gMap[*g] = lambda;
+ assert(op == Basic_Farkas || op == Decoupled_Farkas || (*g).get_const() == 0);
+ }
+
+ for (Variable_ID_Iterator v(vars); v; v++) {
+ assert((*v)->kind() != Wildcard_Var);
+ if ((*v)->kind() == Global_Var
+ && (*v)->get_global_var() == coefficient_of_constant_term) {
+ assert(op != Basic_Farkas && op != Decoupled_Farkas);
+ if (op == Linear_Combination_Farkas) continue;
+ if (op == Positive_Combination_Farkas) continue;
+ }
+ if (op == Decoupled_Farkas && (*v)->UF_owner() != varGroup.curr()) {
+ EQ_Handle e = and_node->add_EQ();
+ e.update_coef(farkas.get_local(*v),-1);
+ continue;
+ }
+ handleVariable(farkas, *s, and_node, gMap,eMap, *v);
+ }
+
+ if (op == Basic_Farkas || op == Decoupled_Farkas) {
+ GEQ_Handle e = and_node->add_GEQ();
+ e.update_coef(farkas.get_local(coefficient_of_constant_term),1);
+ for (GEQ_Iterator g = s.curr()->GEQs(); g.live(); g.next())
+ if (gMap(*g) != (Variable_ID) 0)
+ e.update_coef( gMap(*g),-(*g).get_const());
+ for (EQ_Iterator eq = s.curr()->EQs(); eq.live(); eq.next())
+ if (eMap(*eq) != (Variable_ID) 0)
+ e.update_coef(eMap(*eq),-(*eq).get_const());
+ e.finalize();
+ }
+
+ // lambda variables are not integers, so disable integer problem solving,
+ // we just mark it as simplified.
+ farkas.simplify(-1, -1);
+
+ farkas.single_conjunct()->difficulty(nz,m,sum);
+ difficulty = max((coef_t) nz,2*nz+2*m+sum);
+ if (farkas_debug) {
+ fprintf(DebugFile,"farka has difficulty " coef_fmt "(%d," coef_fmt "," coef_fmt "):\n", difficulty,nz,m,sum);
+ farkas.prefix_print(DebugFile);
+ }
+ if (early_bailout && difficulty >= 500) {
+ farkasDifficulty = difficulty;
+ if (farkas_debug) {
+ fprintf(DebugFile,"Too ugly, returning dull result\n");
+ }
+ use_ugly_names--;
+ if (op == Basic_Farkas || op == Decoupled_Farkas)
+ return Relation::False(partialResult);
+ else return Relation::True(partialResult);
+ }
+ farkas = Approximate(farkas);
+ if (farkas_debug) {
+ fprintf(DebugFile,"simplified:\n");
+ farkas.prefix_print(DebugFile);
+ }
+ partialResult = Approximate(Intersection(partialResult,farkas));
+ if (farkas_debug) {
+ fprintf(DebugFile,"combined:\n");
+ partialResult.prefix_print(DebugFile);
+ }
+ if (partialResult.has_single_conjunct()) {
+ partialResult.single_conjunct()->difficulty(nz,m,sum);
+ difficulty = max((coef_t) nz,2*nz+2*m+sum);
+ }
+ else
+ difficulty = 1000;
+ if (early_bailout && difficulty >= 500) {
+ farkasDifficulty = difficulty;
+ if (farkas_debug) {
+ fprintf(DebugFile,"Too ugly, returning dull result\n");
+ }
+ use_ugly_names--;
+ if (op == Basic_Farkas || op == Decoupled_Farkas)
+ return Relation::False(partialResult);
+ else return Relation::True(partialResult);
+ }
+ }
+ farkasDifficulty += difficulty;
+
+ if (farkas_debug) {
+ fprintf(DebugFile,"] done computing farkas\n");
+ partialResult.prefix_print(DebugFile);
+ }
+
+ if (op == Decoupled_Farkas) {
+ result = Union(result,partialResult);
+ varGroup.next();
+ }
+ }
+ }
+ catch (const std::overflow_error &e) {
+ // clear global variables
+ inApproximateMode = 0;
+ use_ugly_names = saved_use_ugly_names;
+
+ if (early_bailout) {
+ if (farkasDifficulty < 1000)
+ farkasDifficulty = 1000;
+ // return dull result
+ if (op == Basic_Farkas || op == Decoupled_Farkas)
+ return Relation::False(partialResult);
+ else
+ return Relation::True(partialResult);
+ }
+ else
+ throw std::overflow_error("farkas too ugly");
+ }
+
+ if (1 || op == Decoupled_Farkas) {
+ foreach(v,Variable_ID,vars, reset_remap_field(v));
+ }
+ use_ugly_names--;
+ if (op == Decoupled_Farkas) {
+ if (farkas_debug) {
+ fprintf(DebugFile,"] decoupled result:\n");
+ result.prefix_print(DebugFile);
+ }
+ return result;
+ }
+ return partialResult;
+}
+
+} // namespace
diff --git a/omegalib/omega/src/hull.cc b/omegalib/omega/src/hull.cc
new file mode 100644
index 0000000..f1b0601
--- /dev/null
+++ b/omegalib/omega/src/hull.cc
@@ -0,0 +1,1489 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 University of Maryland
+ Copyright (C) 2008 University of Southern California
+ Copyright (C) 2009-2010 University of Utah
+ All Rights Reserved.
+
+ Purpose:
+ Various hull calculations.
+
+ Notes:
+
+ History:
+ 06/15/09 ConvexRepresentation, Chun Chen
+ 11/25/09 RectHull, Chun Chen
+*****************************************************************************/
+
+#include <omega.h>
+#include <omega/farkas.h>
+#include <omega/hull.h>
+#include <basic/Bag.h>
+#include <basic/Map.h>
+#include <basic/omega_error.h>
+#include <list>
+#include <vector>
+#include <set>
+
+namespace omega {
+
+int hull_debug = 0;
+
+Relation ConvexHull(NOT_CONST Relation &R) {
+ Relation S = Approximate(consume_and_regurgitate(R));
+ if (!S.is_upper_bound_satisfiable())
+ return S;
+ if (S.has_single_conjunct())
+ return S;
+ return Farkas(Farkas(S,Basic_Farkas), Convex_Combination_Farkas);
+}
+
+Relation DecoupledConvexHull(NOT_CONST Relation &R) {
+ Relation S = Approximate(consume_and_regurgitate(R));
+ if (!S.is_upper_bound_satisfiable())
+ return S;
+ if (S.has_single_conjunct())
+ return S;
+ return Farkas(Farkas(S,Decoupled_Farkas), Convex_Combination_Farkas);
+}
+
+Relation AffineHull(NOT_CONST Relation &R) {
+ Relation S = Approximate(consume_and_regurgitate(R));
+ if (!S.is_upper_bound_satisfiable())
+ return S;
+ return Farkas(Farkas(S,Basic_Farkas), Affine_Combination_Farkas);
+}
+
+Relation LinearHull(NOT_CONST Relation &R) {
+ Relation S = Approximate(consume_and_regurgitate(R));
+ if (!S.is_upper_bound_satisfiable())
+ return S;
+ return Farkas(Farkas(S,Basic_Farkas), Linear_Combination_Farkas);
+}
+
+Relation ConicHull(NOT_CONST Relation &R) {
+ Relation S = Approximate(consume_and_regurgitate(R));
+ if (!S.is_upper_bound_satisfiable())
+ return S;
+ return Farkas(Farkas(S,Basic_Farkas), Positive_Combination_Farkas);
+}
+
+
+Relation FastTightHull(NOT_CONST Relation &input_R, NOT_CONST Relation &input_H) {
+ Relation R = Approximate(consume_and_regurgitate(input_R));
+ Relation H = Approximate(consume_and_regurgitate(input_H));
+
+ if (hull_debug) {
+ fprintf(DebugFile,"[ Computing FastTightHull of:\n");
+ R.prefix_print(DebugFile);
+ fprintf(DebugFile,"given known hull of:\n");
+ H.prefix_print(DebugFile);
+ }
+
+ if (!H.has_single_conjunct()) {
+ if (hull_debug)
+ fprintf(DebugFile, "] bailing out of FastTightHull, known hull not convex\n");
+ return H;
+ }
+
+ if (!H.is_obvious_tautology()) {
+ R = Gist(R,copy(H));
+ R.simplify(1,0);
+ }
+
+ if (R.has_single_conjunct()) {
+ R = Intersection(R,H);
+ if (hull_debug) {
+ fprintf(DebugFile, "] quick easy answer to FastTightHull\n");
+ R.prefix_print(DebugFile);
+ }
+ return R;
+ }
+ if (R.has_local(coefficient_of_constant_term)) {
+ if (hull_debug) {
+ fprintf(DebugFile, "] Can't handle recursive application of Farkas lemma\n");
+ }
+ return H;
+ }
+
+ if (hull_debug) {
+ fprintf(DebugFile,"Gist of R given H is:\n");
+ R.prefix_print(DebugFile);
+ }
+
+ if (1) {
+ Set<Variable_ID> vars;
+ int conjuncts = 0;
+ for (DNF_Iterator s(R.query_DNF()); s.live(); s.next()) {
+ conjuncts++;
+ for (Variable_ID_Iterator v(*((*s)->variables())); v.live(); v++) {
+ bool found = false;
+ for (EQ_Iterator eq = (*s)->EQs(); eq.live(); eq.next())
+ if ((*eq).get_coef(*v) != 0) {
+ if (!found) vars.insert(*v);
+ found = true;
+ break;
+ }
+ if (!found)
+ for (GEQ_Iterator geq = (*s)->GEQs(); geq.live(); geq.next())
+ if ((*geq).get_coef(*v) != 0) {
+ if (!found) vars.insert(*v);
+ found = true;
+ break;
+ }
+ }
+ }
+
+
+ // We now know which variables appear in R
+ if (hull_debug) {
+ fprintf(DebugFile,"Variables we need a better hull on are: ");
+ foreach(v,Variable_ID,vars,
+ fprintf(DebugFile," %s",v->char_name()));
+ fprintf(DebugFile,"\n");
+ }
+ Conjunct *c = H.single_conjunct();
+ int total=0;
+ int copied = 0;
+ for (EQ_Iterator eq = c->EQs(); eq.live(); eq.next()) {
+ total++;
+ foreach(v,Variable_ID,vars,
+ if ((*eq).get_coef(v) != 0) {
+ R.and_with_EQ(*eq);
+ copied++;
+ break; // out of variable loop
+ }
+ );
+ }
+ for (GEQ_Iterator geq = c->GEQs(); geq.live(); geq.next()) {
+ total++;
+ foreach(v,Variable_ID,vars,
+ if ((*geq).get_coef(v) != 0) {
+ R.and_with_GEQ(*geq);
+ copied++;
+ break; // out of variable loop
+ }
+ );
+ }
+ if (copied < total) {
+ R = Approximate(R);
+
+ if (hull_debug) {
+ fprintf(DebugFile,"Decomposed relation, copied only %d of %d constraints\n",copied,total);
+ fprintf(DebugFile,"Original R:\n");
+ R.prefix_print(DebugFile);
+ fprintf(DebugFile,"Known hull:\n");
+ H.prefix_print(DebugFile);
+ fprintf(DebugFile,"New R:\n");
+ R.prefix_print(DebugFile);
+ }
+ }
+ }
+
+ Relation F = Farkas(copy(R), Basic_Farkas, true);
+ if (hull_debug)
+ fprintf(DebugFile,"Farkas Difficulty = " coef_fmt "\n", farkasDifficulty);
+ if (farkasDifficulty > 260) {
+ if (hull_debug) {
+ fprintf(DebugFile, "] bailing out, farkas is way too complex\n");
+ fprintf(DebugFile,"Farkas:\n");
+ F.prefix_print(DebugFile);
+ }
+ return H;
+ }
+ else if (farkasDifficulty > 130) {
+ // Bail out
+ if (hull_debug) {
+ fprintf(DebugFile, coef_fmt " non-zeros in original farkas\n", farkasDifficulty);
+ }
+ Relation tmp = Farkas(R, Decoupled_Farkas, true);
+
+ if (hull_debug) {
+ fprintf(DebugFile, coef_fmt " non-zeros in decoupled farkas\n", farkasDifficulty);
+ }
+ if (farkasDifficulty > 260) {
+ if (hull_debug) {
+ fprintf(DebugFile, "] bailing out, farkas is way too complex\n");
+ fprintf(DebugFile,"Farkas:\n");
+ F.prefix_print(DebugFile);
+ }
+ return H;
+ }
+ else {
+ if (farkasDifficulty > 130)
+ R = Intersection(H, Farkas(tmp, Affine_Combination_Farkas, true));
+ else R = Intersection(H,
+ Intersection(Farkas(tmp, Convex_Combination_Farkas, true),
+ Farkas(F, Affine_Combination_Farkas, true)));
+ if (hull_debug) {
+ fprintf(DebugFile, "] bailing out, farkas is too complex, using affine hull\n");
+ fprintf(DebugFile,"Farkas:\n");
+ F.prefix_print(DebugFile);
+ fprintf(DebugFile,"Affine hull:\n");
+ R.prefix_print(DebugFile);
+ }
+ return R;
+ }
+ }
+
+ R = Intersection(H, Farkas(F, Convex_Combination_Farkas, true));
+ if (hull_debug) {
+ fprintf(DebugFile, "] Result of FastTightHull:\n");
+ R.prefix_print(DebugFile);
+ }
+ return R;
+}
+
+
+
+namespace {
+ bool parallel(const GEQ_Handle &g1, const GEQ_Handle &g2) {
+ for(Constr_Vars_Iter cvi(g1, false); cvi; cvi++) {
+ coef_t c1 = (*cvi).coef;
+ coef_t c2 = g2.get_coef((*cvi).var);
+ if (c1 != c2) return false;
+ }
+ {
+ for(Constr_Vars_Iter cvi(g2, false); cvi; cvi++) {
+ coef_t c1 = g1.get_coef((*cvi).var);
+ coef_t c2 = (*cvi).coef;
+ if (c1 != c2) return false;
+ }
+ }
+ return true;
+ }
+
+
+ bool hull(const EQ_Handle &e, const GEQ_Handle &g, coef_t &hull) {
+ int sign = 0;
+ for(Constr_Vars_Iter cvi(e, false); cvi; cvi++) {
+ coef_t c1 = (*cvi).coef;
+ coef_t c2 = g.get_coef((*cvi).var);
+ if (sign == 0) sign = (c1*c2>=0?1:-1);
+ if (sign*c1 != c2) return false;
+ }
+ assert(sign != 0);
+ {
+ for(Constr_Vars_Iter cvi(g, false); cvi; cvi++) {
+ coef_t c1 = e.get_coef((*cvi).var);
+ coef_t c2 = (*cvi).coef;
+ if (sign*c1 != c2) return false;
+ }
+ }
+ hull = max(sign * e.get_const(), g.get_const());
+ if (hull_debug) {
+ fprintf(DebugFile,"Hull of:\n %s\n", e.print_to_string().c_str());
+ fprintf(DebugFile," %s\n", g.print_to_string().c_str());
+ fprintf(DebugFile,"is " coef_fmt "\n\n",hull);
+ }
+ return true;
+ }
+
+ bool eq(const EQ_Handle &e1, const EQ_Handle &e2) {
+ int sign = 0;
+ for(Constr_Vars_Iter cvi(e1, false); cvi; cvi++) {
+ coef_t c1 = (*cvi).coef;
+ coef_t c2 = e2.get_coef((*cvi).var);
+ if (sign == 0) sign = (c1*c2>=0?1:-1);
+ if (sign*c1 != c2) return false;
+ }
+ assert(sign != 0);
+ {
+ for(Constr_Vars_Iter cvi(e2, false); cvi; cvi++) {
+ coef_t c1 = e1.get_coef((*cvi).var);
+ coef_t c2 = (*cvi).coef;
+ if (sign*c1 != c2) return false;
+ }
+ }
+ return sign * e1.get_const() == e2.get_const();
+ }
+}
+
+
+// This function is deprecated!!!
+Relation QuickHull(Relation &R) {
+ Tuple<Relation> Rs(1);
+ Rs[1] = R;
+ return QuickHull(Rs);
+}
+
+
+// This function is deprecated!!!
+Relation QuickHull(Tuple<Relation> &Rs) {
+ assert(!Rs.empty());
+
+ // if (Rs.size() == 1) return Rs[1];
+
+ Tuple<Relation> l_Rs;
+ for (int i = 1; i <= Rs.size(); i++)
+ for (DNF_Iterator c(Rs[i].query_DNF()); c; c++) {
+ Relation r = Relation(Rs[i], c.curr());
+ l_Rs.append(Approximate(r));
+ }
+
+ if (l_Rs.size() == 1)
+ return l_Rs[1];
+
+ Relation result = Relation::True(Rs[1]);
+ result.copy_names(Rs[1]);
+
+ use_ugly_names++;
+
+ if (hull_debug > 1)
+ for (int i = 1; i <= l_Rs.size(); i++) {
+ fprintf(DebugFile,"#%d \n",i);
+ l_Rs[i].prefix_print(DebugFile);
+ }
+
+
+// Relation R = copy(Rs[1]);
+// for (int i = 2; i <= Rs.size(); i++)
+// R = Union(R,copy(Rs[i]));
+
+// #if 0
+// if (!R.is_set()) {
+// if (R.n_inp() == R.n_out()) {
+// Relation AC = DeltasToRelation(Hull(Deltas(copy(R),
+// min(R.n_inp(),R.n_out()))),
+// R.n_inp(),R.n_out());
+// Relation dH = Hull(Domain(copy(R)),false);
+// Relation rH = Hull(Range(copy(R)),false);
+// result = Intersection(AC,Cross_Product(dH,rH));
+// }
+// else {
+// Relation dH = Hull(Domain(copy(R)),false);
+// Relation rH = Hull(Range(copy(R)),false);
+// result = Cross_Product(dH,rH);
+// assert(Must_Be_Subset(copy(R),copy(result)));
+// }
+// }
+
+// #endif
+
+ Conjunct *first;
+ l_Rs[1] = EQs_to_GEQs(l_Rs[1]);
+ first = l_Rs[1].single_conjunct();
+ for (GEQ_Iterator candidate(first->GEQs()); candidate.live(); candidate.next()) {
+ coef_t maxConstantTerm = (*candidate).get_const();
+ bool found = true;
+ if (hull_debug > 1) {
+ fprintf(DebugFile,"searching for bound on:\n %s\n", (*candidate).print_to_string().c_str());
+ }
+ for (int i = 2; i <= l_Rs.size(); i++) {
+ Conjunct *other = l_Rs[i].single_conjunct();
+ bool found_for_i = false;
+ for (GEQ_Iterator target(other->GEQs()); target.live(); target.next()) {
+ if (hull_debug > 2) {
+ fprintf(DebugFile,"candidate:\n %s\n", (*candidate).print_to_string().c_str());
+ fprintf(DebugFile,"target:\n %s\n", (*target).print_to_string().c_str());
+ }
+ if (parallel(*candidate,*target)) {
+ if (hull_debug > 1)
+ fprintf(DebugFile,"Found bound:\n %s\n", (*target).print_to_string().c_str());
+ maxConstantTerm = max(maxConstantTerm,(*target).get_const());
+ found_for_i = true;
+ break;
+ }
+ }
+ if (!found_for_i) {
+ for (EQ_Iterator target_e(other->EQs()); target_e.live(); target_e.next()) {
+ coef_t h;
+ if (hull(*target_e,*candidate,h)) {
+ if (hull_debug > 1)
+ fprintf(DebugFile,"Found bound of " coef_fmt ":\n %s\n", h, (*target_e).print_to_string().c_str());
+ maxConstantTerm = max(maxConstantTerm,h);
+ found_for_i = true;
+ break;
+ }
+ };
+ if (!found_for_i) {
+ if (hull_debug > 1) {
+ fprintf(DebugFile,"No bound found in:\n");
+ fprintf(DebugFile, "%s", l_Rs[i].print_with_subs_to_string().c_str());
+ }
+ //if nothing found
+ found = false;
+ break;
+ }
+ }
+ }
+
+ if (found) {
+ GEQ_Handle h = result.and_with_GEQ();
+ copy_constraint(h,*candidate);
+ if (hull_debug > 1)
+ fprintf(DebugFile,"Setting constant term to " coef_fmt " in\n %s\n", maxConstantTerm, h.print_to_string().c_str());
+ h.update_const(maxConstantTerm - (*candidate).get_const());
+ if (hull_debug > 1)
+ fprintf(DebugFile,"Updated constraint is\n %s\n", h.print_to_string().c_str());
+ }
+ }
+
+
+ for (EQ_Iterator candidate_eq(first->EQs()); candidate_eq.live(); candidate_eq.next()) {
+ bool found = true;
+ for (int i = 2; i <= l_Rs.size(); i++) {
+ Conjunct *C = l_Rs[i].single_conjunct();
+ bool found_for_i = false;
+
+ for (EQ_Iterator target(C->EQs()); target.live(); target.next()) {
+ if (eq(*candidate_eq,*target)) {
+ found_for_i = true;
+ break;
+ }
+ }
+ if (!found_for_i) {
+ //if nothing found
+ found = false;
+ break;
+ }
+ }
+
+ if (found) {
+ EQ_Handle h = result.and_with_EQ();
+ copy_constraint(h,*candidate_eq);
+ if (hull_debug > 1)
+ fprintf(DebugFile,"Adding eq constraint: %s\n", h.print_to_string().c_str());
+ }
+ }
+
+ use_ugly_names--;
+ if (hull_debug > 1) {
+ fprintf(DebugFile,"quick hull is of:");
+ result.print_with_subs(DebugFile);
+ }
+ return result;
+}
+
+
+// Relation Hull2(Tuple<Relation> &Rs, Tuple<int> &active) {
+// assert(Rs.size() == active.size() && Rs.size() > 0);
+
+// Tuple<Relation> l_Rs;
+// for (int i = 1; i <= Rs.size(); i++)
+// if (active[i])
+// l_Rs.append(copy(Rs[i]));
+
+// if (l_Rs.size() == 0)
+// return Relation::False(Rs[1]);
+
+// try {
+// Relation r = l_Rs[1];
+// for (int i = 2; i <= l_Rs.size(); i++) {
+// r = Union(r, copy(l_Rs[i]));
+// r.simplify();
+// }
+
+// // Relation F = Farkas(r, Basic_Farkas, true);
+// // if (farkasDifficulty >= 500)
+// // throw std::overflow_error("loop convex hull too complicated.");
+// // F = Farkas(F, Convex_Combination_Farkas, true);
+// return Farkas(Farkas(r, Basic_Farkas, true), Convex_Combination_Farkas, true);
+// }
+// catch (std::overflow_error) {
+// return QuickHull(l_Rs);
+// }
+// }
+
+
+namespace {
+ void printRs(Tuple<Relation> &Rs) {
+ fprintf(DebugFile,"Rs:\n");
+ for (int i = 1; i <= Rs.size(); i++)
+ fprintf(DebugFile,"#%d : %s\n",i,
+ Rs[i].print_with_subs_to_string().c_str());
+ }
+}
+
+Relation BetterHull(Tuple<Relation> &Rs, bool stridesAllowed, bool checkSubsets,
+ NOT_CONST Relation &input_knownHull = Relation::Null()) {
+ Relation knownHull = consume_and_regurgitate(input_knownHull);
+ static int OMEGA_WHINGE = -1;
+ if (OMEGA_WHINGE < 0) {
+ OMEGA_WHINGE = getenv("OMEGA_WHINGE") ? atoi(getenv("OMEGA_WHINGE")) : 0;
+ }
+ assert(!Rs.empty());
+ if (Rs.size() == 1) {
+ if (stridesAllowed) return Rs[1];
+ else return Approximate(Rs[1]);
+ }
+
+ if (checkSubsets) {
+ Tuple<bool> live(Rs.size());
+ if (hull_debug) {
+ fprintf(DebugFile,"Checking subsets in hull computation:\n");
+ printRs(Rs);
+ }
+ int i;
+ for(i=1;i <=Rs.size(); i++) live[i] = true;
+ for(i=1;i <=Rs.size(); i++)
+ for(int j=1;j <=Rs.size(); j++) if (i != j && live[j]) {
+ if (hull_debug) fprintf(DebugFile,"checking %d Is_Obvious_Subset %d\n",i,j);
+ if (Is_Obvious_Subset(copy(Rs[i]),copy(Rs[j]))) {
+ if (hull_debug) fprintf(DebugFile,"yes...\n");
+ live[i] = false;
+ break;
+ }
+ }
+ for(i=1;i <=Rs.size(); i++) if (!live[i]) {
+ if (i < Rs.size()) {
+ Rs[i] = Rs[Rs.size()];
+ live[i] = live[Rs.size()];
+ }
+ Rs[Rs.size()] = Relation();
+ Rs.delete_last();
+ i--;
+ }
+ }
+ Relation hull;
+ if (hull_debug) {
+ fprintf(DebugFile,"Better Hull:\n");
+ printRs(Rs);
+ fprintf(DebugFile,"known hull: %s\n", knownHull.print_with_subs_to_string().c_str());
+ }
+ if (knownHull.is_null()) hull = QuickHull(Rs);
+ else hull = Intersection(QuickHull(Rs),knownHull);
+ // for (int i = 1; i <= Rs.size(); i++)
+ // hull = RectHull(Union(hull, copy(Rs[i])));
+ // hull = Intersection(hull, knownHull);
+ hull.simplify();
+ if (hull_debug) {
+ fprintf(DebugFile,"quick hull: %s\n", hull.print_with_subs_to_string().c_str());
+ }
+
+ Relation orig = Relation::False(Rs[1]);
+ int i;
+ for (i = 1; i <= Rs.size(); i++)
+ orig = Union(orig,copy(Rs[i]));
+
+ orig.simplify();
+
+ for (i = 1; i <= Rs.size(); i++) {
+ if (!hull.is_obvious_tautology()) Rs[i] = Gist(Rs[i],copy(hull));
+ Rs[i].simplify();
+ if (Rs[i].is_obvious_tautology()) return hull;
+ if (Rs[i].has_single_conjunct()) {
+ Rs[i] = EQs_to_GEQs(Rs[i]);
+ if (hull_debug) {
+ fprintf(DebugFile,"Checking for hull constraints in:\n %s\n", Rs[i].print_with_subs_to_string().c_str());
+ }
+ Conjunct *c = Rs[i].single_conjunct();
+ for (GEQ_Iterator g(c->GEQs()); g.live(); g.next()) {
+ Relation tmp = Relation::True(Rs[i]);
+ tmp.and_with_GEQ(*g);
+ if (!Difference(copy(orig),tmp).is_upper_bound_satisfiable())
+ hull.and_with_GEQ(*g);
+ }
+ for (EQ_Iterator e(c->EQs()); e.live(); e.next()) {
+ Relation tmp = Relation::True(Rs[i]);
+ tmp.and_with_EQ(*e);
+ if (!Difference(copy(orig),tmp).is_upper_bound_satisfiable())
+ hull.and_with_EQ(*e);
+ }
+ }
+ }
+
+ hull = FastTightHull(orig,hull);
+ assert(hull.has_single_conjunct());
+
+ if (stridesAllowed) return hull;
+ else return Approximate(hull);
+
+}
+
+
+
+Relation Hull(NOT_CONST Relation &S,
+ bool stridesAllowed,
+ int effort,
+ NOT_CONST Relation &knownHull) {
+ Relation R = consume_and_regurgitate(S);
+ R.simplify(1,0);
+ if (!R.is_upper_bound_satisfiable()) return R;
+ Tuple<Relation> Rs;
+ for (DNF_Iterator c(R.query_DNF()); c.live(); ) {
+ Rs.append(Relation(R,c.curr()));
+ c.next();
+ }
+ if (effort == 1)
+ return BetterHull(Rs,stridesAllowed,false,knownHull);
+ else
+ return QuickHull(Rs);
+}
+
+
+
+Relation Hull(Tuple<Relation> &Rs,
+ Tuple<int> &validMask,
+ int effort,
+ bool stridesAllowed,
+ NOT_CONST Relation &knownHull) {
+ // Use relation of index i only when validMask[i] != 0
+ Tuple<Relation> Rs2;
+ for(int i = 1; i <= Rs.size(); i++) {
+ if (validMask[i]) {
+ Rs[i].simplify();
+ for (DNF_Iterator c(Rs[i].query_DNF()); c.live(); ) {
+ Rs2.append(Relation(Rs[i],c.curr()));
+ c.next();
+ }
+ }
+ }
+ assert(effort == 0 || effort == 1);
+ if (effort == 1)
+ return BetterHull(Rs2,stridesAllowed,true,knownHull);
+ else
+ return QuickHull(Rs2);
+}
+
+
+// This function is deprecated!!!
+Relation CheckForConvexRepresentation(NOT_CONST Relation &R_In) {
+ Relation R = consume_and_regurgitate(R_In);
+ Relation h = Hull(copy(R));
+ if (!Difference(copy(h),copy(R)).is_upper_bound_satisfiable())
+ return h;
+ else
+ return R;
+}
+
+// This function is deprecated!!!
+Relation CheckForConvexPairs(NOT_CONST Relation &S) {
+ Relation R = consume_and_regurgitate(S);
+ Relation hull = FastTightHull(copy(R),Relation::True(R));
+ R.simplify(1,0);
+ if (!R.is_upper_bound_satisfiable() || R.number_of_conjuncts() < 2) return R;
+ Tuple<Relation> Rs;
+ for (DNF_Iterator c(R.query_DNF()); c.live(); ) {
+ Rs.append(Relation(R,c.curr()));
+ c.next();
+ }
+
+ bool *dead = new bool[Rs.size()+1];
+ int i;
+ for(i = 1; i<=Rs.size();i++) dead[i] = false;
+
+ for(i = 1; i<=Rs.size();i++)
+ if (!dead[i])
+ for(int j = i+1; j<=Rs.size();j++) if (!dead[j]) {
+ if (hull_debug) {
+ fprintf(DebugFile,"Comparing #%d and %d\n",i,j);
+ }
+ Relation U = Union(copy(Rs[i]),copy(Rs[j]));
+ Relation H_ij = FastTightHull(copy(U),copy(hull));
+ if (!Difference(copy(H_ij),U).is_upper_bound_satisfiable()) {
+ Rs[i] = H_ij;
+ dead[j] = true;
+ if (hull_debug) {
+ fprintf(DebugFile,"Combined them\n");
+ }
+ }
+ }
+ i = 1;
+ while(i<=Rs.size() && dead[i]) i++;
+ assert(i<=Rs.size());
+ R = Rs[i];
+ i++;
+ for(; i<=Rs.size();i++)
+ if (!dead[i])
+ R = Union(R,Rs[i]);
+ delete []dead;
+ return R;
+}
+
+//
+// Supporting functions for ConvexRepresentation
+//
+namespace {
+struct Interval {
+ std::list<std::pair<Relation, Relation> >::iterator pos;
+ coef_t lb;
+ coef_t ub;
+ bool change;
+ coef_t modulo;
+ Interval(std::list<std::pair<Relation, Relation> >::iterator pos_, coef_t lb_, coef_t ub_):
+ pos(pos_), lb(lb_), ub(ub_) {}
+ friend bool operator<(const Interval &a, const Interval &b);
+};
+
+bool operator<(const Interval &a, const Interval &b) {
+ return a.lb < b.lb;
+}
+
+struct Modulo_Interval {
+ coef_t modulo;
+ coef_t start;
+ coef_t size;
+ Modulo_Interval(coef_t modulo_, coef_t start_, coef_t size_):
+ modulo(modulo_), start(start_), size(size_) {}
+ friend bool operator<(const Interval &a, const Interval &b);
+};
+
+bool operator<(const Modulo_Interval &a, const Modulo_Interval &b) {
+ if (a.modulo == b.modulo) {
+ if (a.start == b.start)
+ return a.size < b.size;
+ else
+ return a.start < b.start;
+ }
+ else
+ return a.modulo < b.modulo;
+}
+
+void merge_intervals(std::list<Interval> &intervals, coef_t modulo, std::list<std::pair<Relation, Relation> > &Rs, std::list<std::pair<Relation, Relation> >::iterator orig) {
+ // normalize intervals
+ for (std::list<Interval>::iterator i = intervals.begin(); i != intervals.end(); i++) {
+ (*i).modulo = modulo;
+ (*i).change = false;
+ if ((*i).ub - (*i).lb + 1>= modulo) {
+ (*i).lb = 0;
+ (*i).ub = modulo - 1;
+ }
+ else if ((*i).ub < 0 || (*i).lb >= modulo) {
+ coef_t range = (*i).ub - (*i).lb;
+ (*i).lb = int_mod((*i).lb, modulo);
+ (*i).ub = (*i).lb + range;
+ }
+ }
+
+ intervals.sort();
+
+ // merge neighboring intervals
+ std::list<Interval>::iterator p = intervals.begin();
+ while (p != intervals.end()) {
+ std::list<Interval>::iterator q = p;
+ q++;
+ while (q != intervals.end()) {
+ if ((*p).ub + 1 >= (*q).lb) {
+ Relation hull = ConvexHull(Union(copy((*(*p).pos).first), copy((*(*q).pos).first)));
+ Relation remainder = Difference(Difference(copy(hull), copy((*(*p).pos).first)), copy((*(*q).pos).first));
+ if (!remainder.is_upper_bound_satisfiable()) {
+ if ((*q).pos == orig)
+ std::swap((*p).pos, (*q).pos);
+ (*(*p).pos).first = hull;
+ (*p).ub = max((*p).ub, (*q).ub);
+ (*p).change = true;
+ Rs.erase((*q).pos);
+ q = intervals.erase(q);
+ }
+ else
+ break;
+ }
+ else
+ break;
+ }
+
+ bool p_moved = false;
+ q = p;
+ q++;
+ while (q != intervals.end()) {
+ if ((*q).ub >= modulo && int_mod((*q).ub, modulo) + 1 >= (*p).lb) {
+ Relation hull = ConvexHull(Union(copy((*(*p).pos).first), copy((*(*q).pos).first)));
+ Relation remainder = Difference(Difference(copy(hull), copy((*(*p).pos).first)), copy((*(*q).pos).first));
+ if (!remainder.is_upper_bound_satisfiable()) {
+ if ((*p).pos == orig)
+ std::swap((*p).pos, (*q).pos);
+ (*(*q).pos).first = hull;
+ coef_t t = (*p).ub - int_mod((*q).ub, modulo);
+ if (t > 0)
+ (*q).ub = (*q).ub + t;
+ (*q).change = true;
+ Rs.erase((*p).pos);
+ p = intervals.erase(p);
+ p_moved = true;
+ break;
+ }
+ else
+ q++;
+ }
+ else
+ q++;
+ }
+
+ if (!p_moved)
+ p++;
+ }
+
+ // merge by reducing the strengh of modulo
+ std::list<Modulo_Interval> modulo_intervals;
+ coef_t max_distance = modulo/2;
+ for (std::list<Interval>::iterator p = intervals.begin(); p != intervals.end(); p++) {
+ if ((*p).lb >= max_distance)
+ break;
+
+ coef_t size = (*p).ub - (*p).lb;
+
+ std::list<Interval>::iterator q = p;
+ q++;
+ while (q != intervals.end()) {
+ coef_t distance = (*q).lb - (*p).lb;
+ if (distance > max_distance)
+ break;
+
+ if ((*q).ub - (*q).lb != size || int_mod(modulo, distance) != 0) {
+ q++;
+ continue;
+ }
+
+ int num_reduced = 0;
+ coef_t looking_for = int_mod((*p).lb, distance);
+ for (std::list<Interval>::iterator k = intervals.begin(); k != intervals.end(); k++) {
+ if ((*k).lb == looking_for && (*k).ub - (*k).lb == size) {
+ num_reduced++;
+ looking_for += distance;
+ if (looking_for >= modulo)
+ break;
+ }
+ else if ((*k).lb <= looking_for && (*k).ub >= looking_for + size) {
+ looking_for += distance;
+ if (looking_for >= modulo)
+ break;
+ }
+ else if ((*k).lb > looking_for)
+ break;
+ }
+
+ if (looking_for >= modulo && num_reduced > 1)
+ modulo_intervals.push_back(Modulo_Interval(distance, int_mod((*p).lb, distance), size));
+
+ q++;
+ }
+ }
+
+ modulo_intervals.sort();
+
+ // remove redundant reduced-strength intervals
+ std::list<Modulo_Interval>::iterator p2 = modulo_intervals.begin();
+ while (p2 != modulo_intervals.end()) {
+ std::list<Modulo_Interval>::iterator q2 = p2;
+ q2++;
+ while (q2 != modulo_intervals.end()) {
+ if ((*p2).modulo == (*q2).modulo && (*p2).start == (*q2).start)
+ q2 = modulo_intervals.erase(q2);
+ else if (int_mod((*q2).modulo, (*p2).modulo) == 0 &&
+ (*p2).start == int_mod((*q2).start, (*p2).modulo) &&
+ (*p2).size >= (*q2).size)
+ q2 = modulo_intervals.erase(q2);
+ else
+ q2++;
+ }
+ p2++;
+ }
+
+ // replace original intervals with new reduced-strength ones
+ for (std::list<Modulo_Interval>::iterator i = modulo_intervals.begin(); i != modulo_intervals.end(); i++) {
+ std::vector<Relation *> candidates;
+ int num_replaced = 0;
+ for (std::list<Interval>::iterator j = intervals.begin(); j != intervals.end(); j++)
+ if (int_mod((*j).modulo, (*i).modulo) == 0 &&
+ (*j).ub - (*j).lb >= (*i).size &&
+ (int_mod((*j).lb, (*i).modulo) == (*i).start ||
+ int_mod((*j).ub, (*i).modulo) == (*i).start + (*i).size)) {
+ candidates.push_back(&((*(*j).pos).first));
+ if (int_mod((*j).lb, (*i).modulo) == (*i).start &&
+ (*j).ub - (*j).lb == (*i).size)
+ num_replaced++;
+ }
+ if (num_replaced <= 1)
+ continue;
+
+ Relation R = copy(*candidates[0]);
+ for (size_t k = 1; k < candidates.size(); k++)
+ R = Union(R, copy(*candidates[k]));
+ Relation hull = ConvexHull(copy(R));
+ Relation remainder = Difference(copy(hull), copy(R));
+ if (!remainder.is_upper_bound_satisfiable()) {
+ std::list<Interval>::iterator replaced_one = intervals.end();
+ for (std::list<Interval>::iterator j = intervals.begin(); j != intervals.end();)
+ if (int_mod((*j).modulo, (*i).modulo) == 0 &&
+ (*j).ub - (*j).lb >= (*i).size &&
+ (int_mod((*j).lb, (*i).modulo) == (*i).start ||
+ int_mod((*j).ub, (*i).modulo) == (*i).start + (*i).size)) {
+ if (int_mod((*j).lb, (*i).modulo) == (*i).start &&
+ (*j).ub - (*j).lb == (*i).size) {
+ if (replaced_one == intervals.end()) {
+ (*(*j).pos).first = hull;
+ (*j).lb = int_mod((*j).lb, (*i).modulo);
+ (*j).ub = int_mod((*j).ub, (*i).modulo);
+ (*j).modulo = (*i).modulo;
+ (*j).change = true;
+ replaced_one = j;
+ j++;
+ }
+ else {
+ if ((*j).pos == orig) {
+ std::swap((*replaced_one).pos, (*j).pos);
+ (*(*replaced_one).pos).first = (*(*j).pos).first;
+ }
+ Rs.erase((*j).pos);
+ j = intervals.erase(j);
+ }
+ }
+ else {
+ if (int_mod((*j).lb, (*i).modulo) == (*i).start)
+ (*j).lb = (*j).lb + (*i).size + 1;
+ else
+ (*j).ub = (*j).ub - (*i).size - 1;
+ (*j).change = true;
+ j++;
+ }
+ }
+ else
+ j++;
+ }
+ }
+}
+} // namespace
+
+
+//
+// Simplify a union of sets/relations to a minimal (may not be
+// optimal) number of convex regions. It intends to replace
+// CheckForConvexRepresentation and CheckForConvexPairs functions.
+//
+Relation ConvexRepresentation(NOT_CONST Relation &R) {
+ Relation l_R = copy(R);
+ if (!l_R.is_upper_bound_satisfiable() || l_R.number_of_conjuncts() < 2)
+ return R;
+
+ // separate each conjunct into smooth convex region and holes
+ std::list<std::pair<Relation, Relation> > Rs; // pair(smooth region, hole condition)
+ for (DNF_Iterator c(l_R.query_DNF()); c.live(); c++) {
+ Relation r1 = Relation(l_R, c.curr());
+ Relation r2 = Approximate(copy(r1));
+ r1 = Gist(r1, copy(r2));
+ Rs.push_back(std::make_pair(r2, r1));
+ }
+
+ try {
+ bool change = true;
+ while (change) {
+ change = false;
+
+ std::list<std::pair<Relation, Relation> >::iterator i = Rs.begin();
+ while (i != Rs.end()) {
+ // find regions with identical hole conditions to merge
+ {
+ std::list<std::pair<Relation, Relation> >::iterator j = i;
+ j++;
+ while (j != Rs.end()) {
+ if (!Difference(copy((*i).second), copy((*j).second)).is_upper_bound_satisfiable() &&
+ !Difference(copy((*j).second), copy((*i).second)).is_upper_bound_satisfiable()) {
+ if (Must_Be_Subset(copy((*j).first), copy((*i).first))) {
+ j = Rs.erase(j);
+ }
+ else if (Must_Be_Subset(copy((*i).first), copy((*j).first))) {
+ (*i).first = (*j).first;
+ j = Rs.erase(j);
+ change = true;
+ }
+ else {
+ Relation r;
+ bool already_use_recthull = false;
+ try {
+ // chun's debug
+ // throw std::runtime_error("dfdf");
+
+ r = ConvexHull(Union(copy((*i).first), copy((*j).first)));
+ }
+ catch (const std::overflow_error &e) {
+ r = RectHull(Union(copy((*i).first), copy((*j).first)));
+ already_use_recthull = true;
+ }
+ retry_recthull:
+ Relation r2 = Difference(Difference(copy(r), copy((*i).first)), copy((*j).first));
+ if (!r2.is_upper_bound_satisfiable()) { // convex hull is tight
+ (*i).first = r;
+ j = Rs.erase(j);
+ change = true;
+ }
+ else {
+ if (!already_use_recthull) {
+ r = RectHull(Union(copy((*i).first), copy((*j).first)));
+ already_use_recthull = true;
+ goto retry_recthull;
+ }
+ else
+ j++;
+ }
+ }
+ }
+ else
+ j++;
+ }
+ }
+
+ // find identical smooth regions as candidates for hole merge
+ std::list<std::list<std::pair<Relation, Relation> >::iterator> s;
+ for (std::list<std::pair<Relation, Relation> >::iterator j = Rs.begin(); j != Rs.end(); j++)
+ if (j != i) {
+ if (!Intersection(Difference(copy((*i).first), copy((*j).first)), copy((*j).second)).is_upper_bound_satisfiable() &&
+ !Intersection(Difference(copy((*j).first), copy((*i).first)), copy((*i).second)).is_upper_bound_satisfiable())
+ s.push_back(j);
+ }
+
+ if (s.size() != 0) {
+ // convert hole condition c1*x1+c2*x2+... = c*alpha+d to a pair of inequalities
+ (*i).second = EQs_to_GEQs((*i).second, false);
+
+ // find potential wildcards that can be used for hole conditions
+ std::set<Variable_ID> nonsingle_wild;
+ for (EQ_Iterator ei((*i).second.single_conjunct()); ei; ei++)
+ if ((*ei).has_wildcards())
+ for (Constr_Vars_Iter cvi(*ei, true); cvi; cvi++)
+ nonsingle_wild.insert(cvi.curr_var());
+ for (GEQ_Iterator gei((*i).second.single_conjunct()); gei; gei++)
+ if ((*gei).has_wildcards()) {
+ Constr_Vars_Iter cvi(*gei, true);
+ Constr_Vars_Iter cvi2 = cvi;
+ cvi2++;
+ if (cvi2) {
+ nonsingle_wild.insert(cvi.curr_var());
+ for (; cvi2; cvi2++)
+ nonsingle_wild.insert(cvi2.curr_var());
+ }
+ }
+
+ // find hole condition in c*alpha+d1<=c1*x1+c2*x2+...<=c*alpha+d2 format
+ for (GEQ_Iterator gei((*i).second.single_conjunct()); gei; gei++)
+ if ((*gei).has_wildcards()) {
+ coef_t c;
+ Variable_ID v;
+ {
+ Constr_Vars_Iter cvi(*gei, true);
+ v = cvi.curr_var();
+ c = cvi.curr_coef();
+ if (c < 0 || nonsingle_wild.find(v) != nonsingle_wild.end())
+ continue;
+ }
+
+ coef_t lb = posInfinity;
+ for (GEQ_Iterator gei2((*i).second.single_conjunct()); gei2; gei2++) {
+ if (!(*gei2 == *gei) && (*gei2).get_coef(v) != 0) {
+ if (lb != posInfinity) {
+ nonsingle_wild.insert(v);
+ break;
+ }
+
+ bool match = true;
+ for (Constr_Vars_Iter cvi2(*gei); cvi2; cvi2++)
+ if (cvi2.curr_coef() != -((*gei2).get_coef(cvi2.curr_var()))) {
+ match = false;
+ break;
+ }
+ if (match)
+ for (Constr_Vars_Iter cvi2(*gei2); cvi2; cvi2++)
+ if (cvi2.curr_coef() != -((*gei).get_coef(cvi2.curr_var()))) {
+ match = false;
+ break;
+ }
+ if (!match) {
+ nonsingle_wild.insert(v);
+ break;
+ }
+
+ lb = -(*gei2).get_const();
+ }
+ }
+
+ if (nonsingle_wild.find(v) != nonsingle_wild.end())
+ continue;
+
+ Relation stride_cond = Relation::True((*i).second);
+ F_Exists *f_exists = stride_cond.and_with_and()->add_exists();
+ Variable_ID e = f_exists->declare();
+ F_And *f_root = f_exists->add_and();
+ GEQ_Handle h1 = f_root->add_GEQ();
+ GEQ_Handle h2 = f_root->add_GEQ();
+ for (Constr_Vars_Iter cvi2(*gei); cvi2; cvi2++) {
+ Variable_ID v = cvi2.curr_var();
+ switch (v->kind()) {
+ case Wildcard_Var:
+ h1.update_coef(e, cvi2.curr_coef());
+ h2.update_coef(e, -cvi2.curr_coef());
+ break;
+ case Global_Var: {
+ Global_Var_ID g = v->get_global_var();
+ Variable_ID v2;
+ if (g->arity() == 0)
+ v2 = stride_cond.get_local(g);
+ else
+ v2 = stride_cond.get_local(g, v->function_of());
+ h1.update_coef(v2, cvi2.curr_coef());
+ h2.update_coef(v2, -cvi2.curr_coef());
+ break;
+ }
+ default:
+ h1.update_coef(v, cvi2.curr_coef());
+ h2.update_coef(v, -cvi2.curr_coef());
+ }
+ }
+ h1.update_const((*gei).get_const());
+ h2.update_const(-lb);
+
+ stride_cond.simplify();
+ Relation other_cond = Gist(copy((*i).second), copy(stride_cond));
+
+ // find regions with potential mergeable stride condition with this one
+ std::list<Interval> intervals;
+ intervals.push_back(Interval(i, lb, (*gei).get_const()));
+
+ for (std::list<std::list<std::pair<Relation, Relation> >::iterator>::iterator j = s.begin(); j != s.end(); j++)
+ if (Must_Be_Subset(copy((**j).second), copy(other_cond))) {
+ Relation stride_cond2 = Gist(copy((**j).second), copy(other_cond));
+
+ // interval can be removed
+ if (stride_cond2.is_obvious_tautology()) {
+ intervals.push_back(Interval(*j, 0, c-1));
+ continue;
+ }
+
+ stride_cond2 = EQs_to_GEQs(stride_cond2, false);
+ coef_t lb, ub;
+ GEQ_Iterator gei2(stride_cond2.single_conjunct());
+ coef_t sign = 0;
+ for (Constr_Vars_Iter cvi(*gei2, true); cvi; cvi++)
+ if (sign != 0) {
+ sign = 0;
+ break;
+ }
+ else if (cvi.curr_coef() == c)
+ sign = 1;
+ else if (cvi.curr_coef() == -c)
+ sign = -1;
+ else {
+ sign = 0;
+ break;
+ }
+ if (sign == 0)
+ continue;
+
+ bool match = true;
+ for (Constr_Vars_Iter cvi(*gei2); cvi; cvi++) {
+ Variable_ID v = cvi.curr_var();
+ if (v->kind() == Wildcard_Var)
+ continue;
+ else if (v->kind() == Global_Var) {
+ Global_Var_ID g = v->get_global_var();
+ if (g->arity() == 0)
+ v = (*i).second.get_local(g);
+ else
+ v = (*i).second.get_local(g, v->function_of());
+ }
+
+ if (cvi.curr_coef() != sign * (*gei).get_coef(v)) {
+ match = false;
+ break;
+ }
+ }
+ if (!match)
+ continue;
+
+ for (Constr_Vars_Iter cvi(*gei); cvi; cvi++) {
+ Variable_ID v = cvi.curr_var();
+ if (v->kind() == Wildcard_Var)
+ continue;
+ else if (v->kind() == Global_Var) {
+ Global_Var_ID g = v->get_global_var();
+ if (g->arity() == 0)
+ v = stride_cond2.get_local(g);
+ else
+ v = stride_cond2.get_local(g, v->function_of());
+ }
+
+ if (cvi.curr_coef() != sign * (*gei2).get_coef(v)) {
+ match = false;
+ break;
+ }
+ }
+ if (!match)
+ continue;
+ if (sign > 0)
+ ub = (*gei2).get_const();
+ else
+ lb = -(*gei2).get_const();
+
+ gei2++;
+ if (!gei2)
+ continue;
+
+ coef_t sign2 = 0;
+ for (Constr_Vars_Iter cvi(*gei2, true); cvi; cvi++)
+ if (sign2 != 0) {
+ sign2 = 0;
+ break;
+ }
+ else if (cvi.curr_coef() == c)
+ sign2 = 1;
+ else if (cvi.curr_coef() == -c)
+ sign2 = -1;
+ else {
+ sign2 = 0;
+ break;
+ }
+ if (sign2 != -sign)
+ continue;
+
+ for (Constr_Vars_Iter cvi(*gei2); cvi; cvi++) {
+ Variable_ID v = cvi.curr_var();
+ if (v->kind() == Wildcard_Var)
+ continue;
+ else if (v->kind() == Global_Var) {
+ Global_Var_ID g = v->get_global_var();
+ if (g->arity() == 0)
+ v = (*i).second.get_local(g);
+ else
+ v = (*i).second.get_local(g, v->function_of());
+ }
+
+ if (cvi.curr_coef() != sign2 * (*gei).get_coef(v)) {
+ match = false;
+ break;
+ }
+ }
+ if (!match)
+ continue;
+
+ for (Constr_Vars_Iter cvi(*gei); cvi; cvi++) {
+ Variable_ID v = cvi.curr_var();
+ if (v->kind() == Wildcard_Var)
+ continue;
+ else if (v->kind() == Global_Var) {
+ Global_Var_ID g = v->get_global_var();
+ if (g->arity() == 0)
+ v = stride_cond2.get_local(g);
+ else
+ v = stride_cond2.get_local(g, v->function_of());
+ }
+
+ if (cvi.curr_coef() != sign2 * (*gei2).get_coef(v)) {
+ match = false;
+ break;
+ }
+ }
+ if (!match)
+ continue;
+ if (sign2 > 0)
+ ub = (*gei2).get_const();
+ else
+ lb = -(*gei2).get_const();
+
+ gei2++;
+ if (gei2)
+ continue;
+
+ intervals.push_back(Interval(*j, lb, ub));
+ }
+
+ merge_intervals(intervals, c, Rs, i);
+
+ // make current region the last one being updated
+ bool invalid = false;
+ for (std::list<Interval>::iterator ii = intervals.begin(); ii != intervals.end(); ii++)
+ if ((*ii).change && (*ii).pos == i) {
+ invalid = true;
+ intervals.push_back(*ii);
+ intervals.erase(ii);
+ break;
+ }
+
+ // update hole condition for each region
+ for (std::list<Interval>::iterator ii = intervals.begin(); ii != intervals.end(); ii++)
+ if ((*ii).change) {
+ change = true;
+
+ if ((*ii).ub - (*ii).lb + 1 >= (*ii).modulo)
+ (*(*ii).pos).second = copy(other_cond);
+ else {
+ Relation stride_cond = Relation::True((*i).second);
+ F_Exists *f_exists = stride_cond.and_with_and()->add_exists();
+ Variable_ID e = f_exists->declare();
+ F_And *f_root = f_exists->add_and();
+ GEQ_Handle h1 = f_root->add_GEQ();
+ GEQ_Handle h2 = f_root->add_GEQ();
+ for (Constr_Vars_Iter cvi2(*gei); cvi2; cvi2++) {
+ Variable_ID v = cvi2.curr_var();
+ switch (v->kind()) {
+ case Wildcard_Var:
+ h1.update_coef(e, (*ii).modulo);
+ h2.update_coef(e, -(*ii).modulo);
+ break;
+ case Global_Var: {
+ Global_Var_ID g = v->get_global_var();
+ Variable_ID v2;
+ if (g->arity() == 0)
+ v2 = stride_cond.get_local(g);
+ else
+ v2 = stride_cond.get_local(g, v->function_of());
+ h1.update_coef(v2, cvi2.curr_coef());
+ h2.update_coef(v2, -cvi2.curr_coef());
+ break;
+ }
+ default:
+ h1.update_coef(v, cvi2.curr_coef());
+ h2.update_coef(v, -cvi2.curr_coef());
+ }
+ }
+ h1.update_const((*ii).ub);
+ h2.update_const(-(*ii).lb);
+
+ (*(*ii).pos).second = Intersection(copy(other_cond), stride_cond);
+ (*(*ii).pos).second.simplify();
+ }
+ }
+
+ if (invalid)
+ break;
+ }
+ }
+ i++;
+ }
+ }
+ }
+ catch (const presburger_error &e) {
+ throw e;
+ }
+
+ Relation R2 = Relation::False(l_R);
+ for (std::list<std::pair<Relation, Relation> >::iterator i = Rs.begin(); i != Rs.end(); i++)
+ R2 = Union(R2, Intersection((*i).first, (*i).second));
+ R2.simplify(0, 1);
+
+ return R2;
+}
+
+
+//
+// Use gist and value range to calculate a quick rectangular hull. It
+// intends to replace all hull calculations (QuickHull, BetterHull,
+// FastTightHull) beyond the method of ConvexHull (dual
+// representations). In the future, it will support max(...)-like
+// upper bound. So RectHull complements ConvexHull in two ways: first
+// for relations that ConvexHull gets too complicated, second for
+// relations where different conjuncts have different symbolic upper
+// bounds.
+//
+Relation RectHull(NOT_CONST Relation &Rel) {
+ Relation R = Approximate(consume_and_regurgitate(Rel));
+ if (!R.is_upper_bound_satisfiable())
+ return R;
+ if (R.has_single_conjunct())
+ return R;
+
+ std::vector<std::string> input_names(R.n_inp());
+ for (int i = 1; i <= R.n_inp(); i++)
+ input_names[i-1] = R.input_var(i)->name();
+ std::vector<std::string> output_names(R.n_out());
+ for (int i = 1; i <= R.n_out(); i++)
+ output_names[i-1] = R.output_var(i)->name();
+
+ DNF_Iterator c(R.query_DNF());
+ Relation r = Relation(R, c.curr());
+ c++;
+ std::vector<std::pair<coef_t, coef_t> > bounds1(R.n_inp());
+ std::vector<std::pair<coef_t, coef_t> > bounds2(R.n_out());
+ {
+ Relation t = Project_Sym(copy(r));
+ t.simplify();
+ for (int i = 1; i <= R.n_inp(); i++) {
+ Tuple<Variable_ID> v;
+ for (int j = 1; j <= R.n_inp(); j++)
+ if (j != i)
+ v.append(r.input_var(j));
+ for (int j = 1; j <= R.n_out(); j++)
+ v.append(r.output_var(j));
+ Relation t2 = Project(copy(t), v);
+ t2.query_variable_bounds(t2.input_var(i), bounds1[i-1].first, bounds1[i-1].second);
+ }
+ for (int i = 1; i <= R.n_out(); i++) {
+ Tuple<Variable_ID> v;
+ for (int j = 1; j <= R.n_out(); j++)
+ if (j != i)
+ v.append(r.output_var(j));
+ for (int j = 1; j <= R.n_inp(); j++)
+ v.append(r.input_var(j));
+ Relation t2 = Project(copy(t), v);
+ t2.query_variable_bounds(t2.output_var(i), bounds2[i-1].first, bounds2[i-1].second);
+ }
+ }
+
+ while (c.live()) {
+ Relation r2 = Relation(R, c.curr());
+ c++;
+ Relation x = Gist(copy(r), Gist(copy(r), copy(r2), 1), 1);
+ if (Difference(copy(r2), copy(x)).is_upper_bound_satisfiable())
+ x = Relation::True(R);
+ Relation y = Gist(copy(r2), Gist(copy(r2), copy(r), 1), 1);
+ if (Difference(copy(r), copy(y)).is_upper_bound_satisfiable())
+ y = Relation::True(R);
+ r = Intersection(x, y);
+
+ {
+ Relation t = Project_Sym(copy(r2));
+ t.simplify();
+ for (int i = 1; i <= R.n_inp(); i++) {
+ Tuple<Variable_ID> v;
+ for (int j = 1; j <= R.n_inp(); j++)
+ if (j != i)
+ v.append(r2.input_var(j));
+ for (int j = 1; j <= R.n_out(); j++)
+ v.append(r2.output_var(j));
+ Relation t2 = Project(copy(t), v);
+ coef_t lbound, ubound;
+ t2.query_variable_bounds(t2.input_var(i), lbound, ubound);
+ bounds1[i-1].first = min(bounds1[i-1].first, lbound);
+ bounds1[i-1].second = max(bounds1[i-1].second, ubound);
+ }
+ for (int i = 1; i <= R.n_out(); i++) {
+ Tuple<Variable_ID> v;
+ for (int j = 1; j <= R.n_out(); j++)
+ if (j != i)
+ v.append(r2.output_var(j));
+ for (int j = 1; j <= R.n_inp(); j++)
+ v.append(r2.input_var(j));
+ Relation t2 = Project(copy(t), v);
+ coef_t lbound, ubound;
+ t2.query_variable_bounds(t2.output_var(i), lbound, ubound);
+ bounds2[i-1].first = min(bounds2[i-1].first, lbound);
+ bounds2[i-1].second = max(bounds2[i-1].second, ubound);
+ }
+ }
+
+ Relation r3(R.n_inp(), R.n_out());
+ F_And *f_root = r3.add_and();
+ for (int i = 1; i <= R.n_inp(); i++) {
+ if (bounds1[i-1].first != -posInfinity) {
+ GEQ_Handle h = f_root->add_GEQ();
+ h.update_coef(r3.input_var(i), 1);
+ h.update_const(-bounds1[i-1].first);
+ }
+ if (bounds1[i-1].second != posInfinity) {
+ GEQ_Handle h = f_root->add_GEQ();
+ h.update_coef(r3.input_var(i), -1);
+ h.update_const(bounds1[i-1].second);
+ }
+ }
+ for (int i = 1; i <= R.n_out(); i++) {
+ if (bounds2[i-1].first != -posInfinity) {
+ GEQ_Handle h = f_root->add_GEQ();
+ h.update_coef(r3.output_var(i), 1);
+ h.update_const(-bounds2[i-1].first);
+ }
+ if (bounds2[i-1].second != posInfinity) {
+ GEQ_Handle h = f_root->add_GEQ();
+ h.update_coef(r3.output_var(i), -1);
+ h.update_const(bounds2[i-1].second);
+ }
+ }
+ r = Intersection(r, r3);
+ r.simplify();
+ }
+
+ for (int i = 1; i <= r.n_inp(); i++)
+ r.name_input_var(i, input_names[i-1]);
+ for (int i = 1; i <= r.n_out(); i++)
+ r.name_output_var(i, output_names[i-1]);
+ r.setup_names();
+ return r;
+}
+
+} // namespace
diff --git a/omegalib/omega/src/hull_legacy.cc b/omegalib/omega/src/hull_legacy.cc
new file mode 100755
index 0000000..a59d34f
--- /dev/null
+++ b/omegalib/omega/src/hull_legacy.cc
@@ -0,0 +1,1484 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 the Omega Project Team
+ Copyright (C) 2005-2011 Chun Chen
+ All Rights Reserved.
+
+ Purpose:
+ Legacy hull calculations' implementation.
+
+ Notes:
+
+ History:
+ 06/15/09 ConvexRepresentation, Chun Chen
+ 11/25/09 RectHull, Chun Chen
+*****************************************************************************/
+
+#include <omega.h>
+#include <omega/farkas.h>
+#include <omega/hull.h>
+#include <basic/Bag.h>
+#include <basic/omega_error.h>
+#include <list>
+#include <vector>
+#include <set>
+
+namespace omega {
+
+int hull_debug = 0;
+
+Relation ConvexHull(NOT_CONST Relation &R) {
+ Relation S = Approximate(consume_and_regurgitate(R));
+ if (!S.is_upper_bound_satisfiable())
+ return S;
+ if (S.has_single_conjunct())
+ return S;
+ return Farkas(Farkas(S,Basic_Farkas), Convex_Combination_Farkas);
+}
+
+Relation DecoupledConvexHull(NOT_CONST Relation &R) {
+ Relation S = Approximate(consume_and_regurgitate(R));
+ if (!S.is_upper_bound_satisfiable())
+ return S;
+ if (S.has_single_conjunct())
+ return S;
+ return Farkas(Farkas(S,Decoupled_Farkas), Convex_Combination_Farkas);
+}
+
+Relation AffineHull(NOT_CONST Relation &R) {
+ Relation S = Approximate(consume_and_regurgitate(R));
+ if (!S.is_upper_bound_satisfiable())
+ return S;
+ return Farkas(Farkas(S,Basic_Farkas), Affine_Combination_Farkas);
+}
+
+Relation LinearHull(NOT_CONST Relation &R) {
+ Relation S = Approximate(consume_and_regurgitate(R));
+ if (!S.is_upper_bound_satisfiable())
+ return S;
+ return Farkas(Farkas(S,Basic_Farkas), Linear_Combination_Farkas);
+}
+
+Relation ConicHull(NOT_CONST Relation &R) {
+ Relation S = Approximate(consume_and_regurgitate(R));
+ if (!S.is_upper_bound_satisfiable())
+ return S;
+ return Farkas(Farkas(S,Basic_Farkas), Positive_Combination_Farkas);
+}
+
+
+Relation FastTightHull(NOT_CONST Relation &input_R, NOT_CONST Relation &input_H) {
+ Relation R = Approximate(consume_and_regurgitate(input_R));
+ Relation H = Approximate(consume_and_regurgitate(input_H));
+
+ if (hull_debug) {
+ fprintf(DebugFile,"[ Computing FastTightHull of:\n");
+ R.prefix_print(DebugFile);
+ fprintf(DebugFile,"given known hull of:\n");
+ H.prefix_print(DebugFile);
+ }
+
+ if (!H.has_single_conjunct()) {
+ if (hull_debug)
+ fprintf(DebugFile, "] bailing out of FastTightHull, known hull not convex\n");
+ return H;
+ }
+
+ if (!H.is_obvious_tautology()) {
+ R = Gist(R,copy(H));
+ R.simplify(1,0);
+ }
+
+ if (R.has_single_conjunct()) {
+ R = Intersection(R,H);
+ if (hull_debug) {
+ fprintf(DebugFile, "] quick easy answer to FastTightHull\n");
+ R.prefix_print(DebugFile);
+ }
+ return R;
+ }
+ if (R.has_local(coefficient_of_constant_term)) {
+ if (hull_debug) {
+ fprintf(DebugFile, "] Can't handle recursive application of Farkas lemma\n");
+ }
+ return H;
+ }
+
+ if (hull_debug) {
+ fprintf(DebugFile,"Gist of R given H is:\n");
+ R.prefix_print(DebugFile);
+ }
+
+ if (1) {
+ Set<Variable_ID> vars;
+ int conjuncts = 0;
+ for (DNF_Iterator s(R.query_DNF()); s.live(); s.next()) {
+ conjuncts++;
+ for (Variable_ID_Iterator v(*((*s)->variables())); v.live(); v++) {
+ bool found = false;
+ for (EQ_Iterator eq = (*s)->EQs(); eq.live(); eq.next())
+ if ((*eq).get_coef(*v) != 0) {
+ if (!found) vars.insert(*v);
+ found = true;
+ break;
+ }
+ if (!found)
+ for (GEQ_Iterator geq = (*s)->GEQs(); geq.live(); geq.next())
+ if ((*geq).get_coef(*v) != 0) {
+ if (!found) vars.insert(*v);
+ found = true;
+ break;
+ }
+ }
+ }
+
+
+ // We now know which variables appear in R
+ if (hull_debug) {
+ fprintf(DebugFile,"Variables we need a better hull on are: ");
+ foreach(v,Variable_ID,vars,
+ fprintf(DebugFile," %s",v->char_name()));
+ fprintf(DebugFile,"\n");
+ }
+ Conjunct *c = H.single_conjunct();
+ int total=0;
+ int copied = 0;
+ for (EQ_Iterator eq = c->EQs(); eq.live(); eq.next()) {
+ total++;
+ foreach(v,Variable_ID,vars,
+ if ((*eq).get_coef(v) != 0) {
+ R.and_with_EQ(*eq);
+ copied++;
+ break; // out of variable loop
+ }
+ );
+ }
+ for (GEQ_Iterator geq = c->GEQs(); geq.live(); geq.next()) {
+ total++;
+ foreach(v,Variable_ID,vars,
+ if ((*geq).get_coef(v) != 0) {
+ R.and_with_GEQ(*geq);
+ copied++;
+ break; // out of variable loop
+ }
+ );
+ }
+ if (copied < total) {
+ R = Approximate(R);
+
+ if (hull_debug) {
+ fprintf(DebugFile,"Decomposed relation, copied only %d of %d constraints\n",copied,total);
+ fprintf(DebugFile,"Original R:\n");
+ R.prefix_print(DebugFile);
+ fprintf(DebugFile,"Known hull:\n");
+ H.prefix_print(DebugFile);
+ fprintf(DebugFile,"New R:\n");
+ R.prefix_print(DebugFile);
+ }
+ }
+ }
+
+ Relation F = Farkas(copy(R), Basic_Farkas, true);
+ if (hull_debug)
+ fprintf(DebugFile,"Farkas Difficulty = " coef_fmt "\n", farkasDifficulty);
+ if (farkasDifficulty > 260) {
+ if (hull_debug) {
+ fprintf(DebugFile, "] bailing out, farkas is way too complex\n");
+ fprintf(DebugFile,"Farkas:\n");
+ F.prefix_print(DebugFile);
+ }
+ return H;
+ }
+ else if (farkasDifficulty > 130) {
+ // Bail out
+ if (hull_debug) {
+ fprintf(DebugFile, coef_fmt " non-zeros in original farkas\n", farkasDifficulty);
+ }
+ Relation tmp = Farkas(R, Decoupled_Farkas, true);
+
+ if (hull_debug) {
+ fprintf(DebugFile, coef_fmt " non-zeros in decoupled farkas\n", farkasDifficulty);
+ }
+ if (farkasDifficulty > 260) {
+ if (hull_debug) {
+ fprintf(DebugFile, "] bailing out, farkas is way too complex\n");
+ fprintf(DebugFile,"Farkas:\n");
+ F.prefix_print(DebugFile);
+ }
+ return H;
+ }
+ else {
+ if (farkasDifficulty > 130)
+ R = Intersection(H, Farkas(tmp, Affine_Combination_Farkas, true));
+ else R = Intersection(H,
+ Intersection(Farkas(tmp, Convex_Combination_Farkas, true),
+ Farkas(F, Affine_Combination_Farkas, true)));
+ if (hull_debug) {
+ fprintf(DebugFile, "] bailing out, farkas is too complex, using affine hull\n");
+ fprintf(DebugFile,"Farkas:\n");
+ F.prefix_print(DebugFile);
+ fprintf(DebugFile,"Affine hull:\n");
+ R.prefix_print(DebugFile);
+ }
+ return R;
+ }
+ }
+
+ R = Intersection(H, Farkas(F, Convex_Combination_Farkas, true));
+ if (hull_debug) {
+ fprintf(DebugFile, "] Result of FastTightHull:\n");
+ R.prefix_print(DebugFile);
+ }
+ return R;
+}
+
+
+
+namespace {
+ bool parallel(const GEQ_Handle &g1, const GEQ_Handle &g2) {
+ for(Constr_Vars_Iter cvi(g1, false); cvi; cvi++) {
+ coef_t c1 = (*cvi).coef;
+ coef_t c2 = g2.get_coef((*cvi).var);
+ if (c1 != c2) return false;
+ }
+ {
+ for(Constr_Vars_Iter cvi(g2, false); cvi; cvi++) {
+ coef_t c1 = g1.get_coef((*cvi).var);
+ coef_t c2 = (*cvi).coef;
+ if (c1 != c2) return false;
+ }
+ }
+ return true;
+ }
+
+
+ bool hull(const EQ_Handle &e, const GEQ_Handle &g, coef_t &hull) {
+ int sign = 0;
+ for(Constr_Vars_Iter cvi(e, false); cvi; cvi++) {
+ coef_t c1 = (*cvi).coef;
+ coef_t c2 = g.get_coef((*cvi).var);
+ if (sign == 0) sign = (c1*c2>=0?1:-1);
+ if (sign*c1 != c2) return false;
+ }
+ assert(sign != 0);
+ {
+ for(Constr_Vars_Iter cvi(g, false); cvi; cvi++) {
+ coef_t c1 = e.get_coef((*cvi).var);
+ coef_t c2 = (*cvi).coef;
+ if (sign*c1 != c2) return false;
+ }
+ }
+ hull = max(sign * e.get_const(), g.get_const());
+ if (hull_debug) {
+ fprintf(DebugFile,"Hull of:\n %s\n", e.print_to_string().c_str());
+ fprintf(DebugFile," %s\n", g.print_to_string().c_str());
+ fprintf(DebugFile,"is " coef_fmt "\n\n",hull);
+ }
+ return true;
+ }
+
+ bool eq(const EQ_Handle &e1, const EQ_Handle &e2) {
+ int sign = 0;
+ for(Constr_Vars_Iter cvi(e1, false); cvi; cvi++) {
+ coef_t c1 = (*cvi).coef;
+ coef_t c2 = e2.get_coef((*cvi).var);
+ if (sign == 0) sign = (c1*c2>=0?1:-1);
+ if (sign*c1 != c2) return false;
+ }
+ assert(sign != 0);
+ {
+ for(Constr_Vars_Iter cvi(e2, false); cvi; cvi++) {
+ coef_t c1 = e1.get_coef((*cvi).var);
+ coef_t c2 = (*cvi).coef;
+ if (sign*c1 != c2) return false;
+ }
+ }
+ return sign * e1.get_const() == e2.get_const();
+ }
+}
+
+
+// This function is deprecated!!!
+Relation QuickHull(Relation &R) {
+ Tuple<Relation> Rs(1);
+ Rs[1] = R;
+ return QuickHull(Rs);
+}
+
+
+// This function is deprecated!!!
+Relation QuickHull(Tuple<Relation> &Rs) {
+ assert(!Rs.empty());
+
+ // if (Rs.size() == 1) return Rs[1];
+
+ Tuple<Relation> l_Rs;
+ for (int i = 1; i <= Rs.size(); i++)
+ for (DNF_Iterator c(Rs[i].query_DNF()); c; c++) {
+ Relation r = Relation(Rs[i], c.curr());
+ l_Rs.append(Approximate(r));
+ }
+
+ if (l_Rs.size() == 1)
+ return l_Rs[1];
+
+ Relation result = Relation::True(Rs[1]);
+ result.copy_names(Rs[1]);
+
+ use_ugly_names++;
+
+ if (hull_debug > 1)
+ for (int i = 1; i <= l_Rs.size(); i++) {
+ fprintf(DebugFile,"#%d \n",i);
+ l_Rs[i].prefix_print(DebugFile);
+ }
+
+
+// Relation R = copy(Rs[1]);
+// for (int i = 2; i <= Rs.size(); i++)
+// R = Union(R,copy(Rs[i]));
+
+// #if 0
+// if (!R.is_set()) {
+// if (R.n_inp() == R.n_out()) {
+// Relation AC = DeltasToRelation(Hull(Deltas(copy(R),
+// min(R.n_inp(),R.n_out()))),
+// R.n_inp(),R.n_out());
+// Relation dH = Hull(Domain(copy(R)),false);
+// Relation rH = Hull(Range(copy(R)),false);
+// result = Intersection(AC,Cross_Product(dH,rH));
+// }
+// else {
+// Relation dH = Hull(Domain(copy(R)),false);
+// Relation rH = Hull(Range(copy(R)),false);
+// result = Cross_Product(dH,rH);
+// assert(Must_Be_Subset(copy(R),copy(result)));
+// }
+// }
+
+// #endif
+
+ Conjunct *first;
+ l_Rs[1] = EQs_to_GEQs(l_Rs[1]);
+ first = l_Rs[1].single_conjunct();
+ for (GEQ_Iterator candidate(first->GEQs()); candidate.live(); candidate.next()) {
+ coef_t maxConstantTerm = (*candidate).get_const();
+ bool found = true;
+ if (hull_debug > 1) {
+ fprintf(DebugFile,"searching for bound on:\n %s\n", (*candidate).print_to_string().c_str());
+ }
+ for (int i = 2; i <= l_Rs.size(); i++) {
+ Conjunct *other = l_Rs[i].single_conjunct();
+ bool found_for_i = false;
+ for (GEQ_Iterator target(other->GEQs()); target.live(); target.next()) {
+ if (hull_debug > 2) {
+ fprintf(DebugFile,"candidate:\n %s\n", (*candidate).print_to_string().c_str());
+ fprintf(DebugFile,"target:\n %s\n", (*target).print_to_string().c_str());
+ }
+ if (parallel(*candidate,*target)) {
+ if (hull_debug > 1)
+ fprintf(DebugFile,"Found bound:\n %s\n", (*target).print_to_string().c_str());
+ maxConstantTerm = max(maxConstantTerm,(*target).get_const());
+ found_for_i = true;
+ break;
+ }
+ }
+ if (!found_for_i) {
+ for (EQ_Iterator target_e(other->EQs()); target_e.live(); target_e.next()) {
+ coef_t h;
+ if (hull(*target_e,*candidate,h)) {
+ if (hull_debug > 1)
+ fprintf(DebugFile,"Found bound of " coef_fmt ":\n %s\n", h, (*target_e).print_to_string().c_str());
+ maxConstantTerm = max(maxConstantTerm,h);
+ found_for_i = true;
+ break;
+ }
+ };
+ if (!found_for_i) {
+ if (hull_debug > 1) {
+ fprintf(DebugFile,"No bound found in:\n");
+ fprintf(DebugFile, "%s", l_Rs[i].print_with_subs_to_string().c_str());
+ }
+ //if nothing found
+ found = false;
+ break;
+ }
+ }
+ }
+
+ if (found) {
+ GEQ_Handle h = result.and_with_GEQ();
+ copy_constraint(h,*candidate);
+ if (hull_debug > 1)
+ fprintf(DebugFile,"Setting constant term to " coef_fmt " in\n %s\n", maxConstantTerm, h.print_to_string().c_str());
+ h.update_const(maxConstantTerm - (*candidate).get_const());
+ if (hull_debug > 1)
+ fprintf(DebugFile,"Updated constraint is\n %s\n", h.print_to_string().c_str());
+ }
+ }
+
+
+ for (EQ_Iterator candidate_eq(first->EQs()); candidate_eq.live(); candidate_eq.next()) {
+ bool found = true;
+ for (int i = 2; i <= l_Rs.size(); i++) {
+ Conjunct *C = l_Rs[i].single_conjunct();
+ bool found_for_i = false;
+
+ for (EQ_Iterator target(C->EQs()); target.live(); target.next()) {
+ if (eq(*candidate_eq,*target)) {
+ found_for_i = true;
+ break;
+ }
+ }
+ if (!found_for_i) {
+ //if nothing found
+ found = false;
+ break;
+ }
+ }
+
+ if (found) {
+ EQ_Handle h = result.and_with_EQ();
+ copy_constraint(h,*candidate_eq);
+ if (hull_debug > 1)
+ fprintf(DebugFile,"Adding eq constraint: %s\n", h.print_to_string().c_str());
+ }
+ }
+
+ use_ugly_names--;
+ if (hull_debug > 1) {
+ fprintf(DebugFile,"quick hull is of:");
+ result.print_with_subs(DebugFile);
+ }
+ return result;
+}
+
+
+// Relation Hull2(Tuple<Relation> &Rs, Tuple<int> &active) {
+// assert(Rs.size() == active.size() && Rs.size() > 0);
+
+// Tuple<Relation> l_Rs;
+// for (int i = 1; i <= Rs.size(); i++)
+// if (active[i])
+// l_Rs.append(copy(Rs[i]));
+
+// if (l_Rs.size() == 0)
+// return Relation::False(Rs[1]);
+
+// try {
+// Relation r = l_Rs[1];
+// for (int i = 2; i <= l_Rs.size(); i++) {
+// r = Union(r, copy(l_Rs[i]));
+// r.simplify();
+// }
+
+// // Relation F = Farkas(r, Basic_Farkas, true);
+// // if (farkasDifficulty >= 500)
+// // throw std::overflow_error("loop convex hull too complicated.");
+// // F = Farkas(F, Convex_Combination_Farkas, true);
+// return Farkas(Farkas(r, Basic_Farkas, true), Convex_Combination_Farkas, true);
+// }
+// catch (std::overflow_error) {
+// return QuickHull(l_Rs);
+// }
+// }
+
+
+namespace {
+ void printRs(Tuple<Relation> &Rs) {
+ fprintf(DebugFile,"Rs:\n");
+ for (int i = 1; i <= Rs.size(); i++)
+ fprintf(DebugFile,"#%d : %s\n",i,
+ Rs[i].print_with_subs_to_string().c_str());
+ }
+}
+
+Relation BetterHull(Tuple<Relation> &Rs, bool stridesAllowed, bool checkSubsets,
+ NOT_CONST Relation &input_knownHull = Relation::Null()) {
+ Relation knownHull = consume_and_regurgitate(input_knownHull);
+ static int OMEGA_WHINGE = -1;
+ if (OMEGA_WHINGE < 0) {
+ OMEGA_WHINGE = getenv("OMEGA_WHINGE") ? atoi(getenv("OMEGA_WHINGE")) : 0;
+ }
+ assert(!Rs.empty());
+ if (Rs.size() == 1) {
+ if (stridesAllowed) return Rs[1];
+ else return Approximate(Rs[1]);
+ }
+
+ if (checkSubsets) {
+ Tuple<bool> live(Rs.size());
+ if (hull_debug) {
+ fprintf(DebugFile,"Checking subsets in hull computation:\n");
+ printRs(Rs);
+ }
+ int i;
+ for(i=1;i <=Rs.size(); i++) live[i] = true;
+ for(i=1;i <=Rs.size(); i++)
+ for(int j=1;j <=Rs.size(); j++) if (i != j && live[j]) {
+ if (hull_debug) fprintf(DebugFile,"checking %d Is_Obvious_Subset %d\n",i,j);
+ if (Is_Obvious_Subset(copy(Rs[i]),copy(Rs[j]))) {
+ if (hull_debug) fprintf(DebugFile,"yes...\n");
+ live[i] = false;
+ break;
+ }
+ }
+ for(i=1;i <=Rs.size(); i++) if (!live[i]) {
+ if (i < Rs.size()) {
+ Rs[i] = Rs[Rs.size()];
+ live[i] = live[Rs.size()];
+ }
+ Rs[Rs.size()] = Relation();
+ Rs.delete_last();
+ i--;
+ }
+ }
+ Relation hull;
+ if (hull_debug) {
+ fprintf(DebugFile,"Better Hull:\n");
+ printRs(Rs);
+ fprintf(DebugFile,"known hull: %s\n", knownHull.print_with_subs_to_string().c_str());
+ }
+ if (knownHull.is_null()) hull = QuickHull(Rs);
+ else hull = Intersection(QuickHull(Rs),knownHull);
+ // for (int i = 1; i <= Rs.size(); i++)
+ // hull = RectHull(Union(hull, copy(Rs[i])));
+ // hull = Intersection(hull, knownHull);
+ hull.simplify();
+ if (hull_debug) {
+ fprintf(DebugFile,"quick hull: %s\n", hull.print_with_subs_to_string().c_str());
+ }
+
+ Relation orig = Relation::False(Rs[1]);
+ int i;
+ for (i = 1; i <= Rs.size(); i++)
+ orig = Union(orig,copy(Rs[i]));
+
+ orig.simplify();
+
+ for (i = 1; i <= Rs.size(); i++) {
+ if (!hull.is_obvious_tautology()) Rs[i] = Gist(Rs[i],copy(hull));
+ Rs[i].simplify();
+ if (Rs[i].is_obvious_tautology()) return hull;
+ if (Rs[i].has_single_conjunct()) {
+ Rs[i] = EQs_to_GEQs(Rs[i]);
+ if (hull_debug) {
+ fprintf(DebugFile,"Checking for hull constraints in:\n %s\n", Rs[i].print_with_subs_to_string().c_str());
+ }
+ Conjunct *c = Rs[i].single_conjunct();
+ for (GEQ_Iterator g(c->GEQs()); g.live(); g.next()) {
+ Relation tmp = Relation::True(Rs[i]);
+ tmp.and_with_GEQ(*g);
+ if (!Difference(copy(orig),tmp).is_upper_bound_satisfiable())
+ hull.and_with_GEQ(*g);
+ }
+ for (EQ_Iterator e(c->EQs()); e.live(); e.next()) {
+ Relation tmp = Relation::True(Rs[i]);
+ tmp.and_with_EQ(*e);
+ if (!Difference(copy(orig),tmp).is_upper_bound_satisfiable())
+ hull.and_with_EQ(*e);
+ }
+ }
+ }
+
+ hull = FastTightHull(orig,hull);
+ assert(hull.has_single_conjunct());
+
+ if (stridesAllowed) return hull;
+ else return Approximate(hull);
+
+}
+
+
+
+Relation Hull(NOT_CONST Relation &S,
+ bool stridesAllowed,
+ int effort,
+ NOT_CONST Relation &knownHull) {
+ Relation R = consume_and_regurgitate(S);
+ R.simplify(1,0);
+ if (!R.is_upper_bound_satisfiable()) return R;
+ Tuple<Relation> Rs;
+ for (DNF_Iterator c(R.query_DNF()); c.live(); ) {
+ Rs.append(Relation(R,c.curr()));
+ c.next();
+ }
+ if (effort == 1)
+ return BetterHull(Rs,stridesAllowed,false,knownHull);
+ else
+ return QuickHull(Rs);
+}
+
+
+
+Relation Hull(Tuple<Relation> &Rs,
+ const std::vector<bool> &validMask,
+ int effort,
+ bool stridesAllowed,
+ NOT_CONST Relation &knownHull) {
+ // Use relation of index i only when validMask[i] != 0
+ Tuple<Relation> Rs2;
+ for(int i = 1; i <= Rs.size(); i++) {
+ if (validMask[i-1]) {
+ Rs[i].simplify();
+ for (DNF_Iterator c(Rs[i].query_DNF()); c.live(); ) {
+ Rs2.append(Relation(Rs[i],c.curr()));
+ c.next();
+ }
+ }
+ }
+ assert(effort == 0 || effort == 1);
+ if (effort == 1)
+ return BetterHull(Rs2,stridesAllowed,true,knownHull);
+ else
+ return QuickHull(Rs2);
+}
+
+
+// This function is deprecated!!!
+Relation CheckForConvexRepresentation(NOT_CONST Relation &R_In) {
+ Relation R = consume_and_regurgitate(R_In);
+ Relation h = Hull(copy(R));
+ if (!Difference(copy(h),copy(R)).is_upper_bound_satisfiable())
+ return h;
+ else
+ return R;
+}
+
+// This function is deprecated!!!
+Relation CheckForConvexPairs(NOT_CONST Relation &S) {
+ Relation R = consume_and_regurgitate(S);
+ Relation hull = FastTightHull(copy(R),Relation::True(R));
+ R.simplify(1,0);
+ if (!R.is_upper_bound_satisfiable() || R.number_of_conjuncts() < 2) return R;
+ Tuple<Relation> Rs;
+ for (DNF_Iterator c(R.query_DNF()); c.live(); ) {
+ Rs.append(Relation(R,c.curr()));
+ c.next();
+ }
+
+ bool *dead = new bool[Rs.size()+1];
+ int i;
+ for(i = 1; i<=Rs.size();i++) dead[i] = false;
+
+ for(i = 1; i<=Rs.size();i++)
+ if (!dead[i])
+ for(int j = i+1; j<=Rs.size();j++) if (!dead[j]) {
+ if (hull_debug) {
+ fprintf(DebugFile,"Comparing #%d and %d\n",i,j);
+ }
+ Relation U = Union(copy(Rs[i]),copy(Rs[j]));
+ Relation H_ij = FastTightHull(copy(U),copy(hull));
+ if (!Difference(copy(H_ij),U).is_upper_bound_satisfiable()) {
+ Rs[i] = H_ij;
+ dead[j] = true;
+ if (hull_debug) {
+ fprintf(DebugFile,"Combined them\n");
+ }
+ }
+ }
+ i = 1;
+ while(i<=Rs.size() && dead[i]) i++;
+ assert(i<=Rs.size());
+ R = Rs[i];
+ i++;
+ for(; i<=Rs.size();i++)
+ if (!dead[i])
+ R = Union(R,Rs[i]);
+ delete []dead;
+ return R;
+}
+
+//
+// Supporting functions for ConvexRepresentation
+//
+namespace {
+struct Interval {
+ std::list<std::pair<Relation, Relation> >::iterator pos;
+ coef_t lb;
+ coef_t ub;
+ bool change;
+ coef_t modulo;
+ Interval(std::list<std::pair<Relation, Relation> >::iterator pos_, coef_t lb_, coef_t ub_):
+ pos(pos_), lb(lb_), ub(ub_) {}
+ friend bool operator<(const Interval &a, const Interval &b);
+};
+
+bool operator<(const Interval &a, const Interval &b) {
+ return a.lb < b.lb;
+}
+
+struct Modulo_Interval {
+ coef_t modulo;
+ coef_t start;
+ coef_t size;
+ Modulo_Interval(coef_t modulo_, coef_t start_, coef_t size_):
+ modulo(modulo_), start(start_), size(size_) {}
+ friend bool operator<(const Interval &a, const Interval &b);
+};
+
+bool operator<(const Modulo_Interval &a, const Modulo_Interval &b) {
+ if (a.modulo == b.modulo) {
+ if (a.start == b.start)
+ return a.size < b.size;
+ else
+ return a.start < b.start;
+ }
+ else
+ return a.modulo < b.modulo;
+}
+
+void merge_intervals(std::list<Interval> &intervals, coef_t modulo, std::list<std::pair<Relation, Relation> > &Rs, std::list<std::pair<Relation, Relation> >::iterator orig) {
+ // normalize intervals
+ for (std::list<Interval>::iterator i = intervals.begin(); i != intervals.end(); i++) {
+ (*i).modulo = modulo;
+ (*i).change = false;
+ if ((*i).ub - (*i).lb + 1>= modulo) {
+ (*i).lb = 0;
+ (*i).ub = modulo - 1;
+ }
+ else if ((*i).ub < 0 || (*i).lb >= modulo) {
+ coef_t range = (*i).ub - (*i).lb;
+ (*i).lb = int_mod((*i).lb, modulo);
+ (*i).ub = (*i).lb + range;
+ }
+ }
+
+ intervals.sort();
+
+ // merge neighboring intervals
+ std::list<Interval>::iterator p = intervals.begin();
+ while (p != intervals.end()) {
+ std::list<Interval>::iterator q = p;
+ q++;
+ while (q != intervals.end()) {
+ if ((*p).ub + 1 >= (*q).lb) {
+ Relation hull = ConvexHull(Union(copy((*(*p).pos).first), copy((*(*q).pos).first)));
+ Relation remainder = Difference(Difference(copy(hull), copy((*(*p).pos).first)), copy((*(*q).pos).first));
+ if (!remainder.is_upper_bound_satisfiable()) {
+ if ((*q).pos == orig)
+ std::swap((*p).pos, (*q).pos);
+ (*(*p).pos).first = hull;
+ (*p).ub = max((*p).ub, (*q).ub);
+ (*p).change = true;
+ Rs.erase((*q).pos);
+ q = intervals.erase(q);
+ }
+ else
+ break;
+ }
+ else
+ break;
+ }
+
+ bool p_moved = false;
+ q = p;
+ q++;
+ while (q != intervals.end()) {
+ if ((*q).ub >= modulo && int_mod((*q).ub, modulo) + 1 >= (*p).lb) {
+ Relation hull = ConvexHull(Union(copy((*(*p).pos).first), copy((*(*q).pos).first)));
+ Relation remainder = Difference(Difference(copy(hull), copy((*(*p).pos).first)), copy((*(*q).pos).first));
+ if (!remainder.is_upper_bound_satisfiable()) {
+ if ((*p).pos == orig)
+ std::swap((*p).pos, (*q).pos);
+ (*(*q).pos).first = hull;
+ coef_t t = (*p).ub - int_mod((*q).ub, modulo);
+ if (t > 0)
+ (*q).ub = (*q).ub + t;
+ (*q).change = true;
+ Rs.erase((*p).pos);
+ p = intervals.erase(p);
+ p_moved = true;
+ break;
+ }
+ else
+ q++;
+ }
+ else
+ q++;
+ }
+
+ if (!p_moved)
+ p++;
+ }
+
+ // merge by reducing the strengh of modulo
+ std::list<Modulo_Interval> modulo_intervals;
+ coef_t max_distance = modulo/2;
+ for (std::list<Interval>::iterator p = intervals.begin(); p != intervals.end(); p++) {
+ if ((*p).lb >= max_distance)
+ break;
+
+ coef_t size = (*p).ub - (*p).lb;
+
+ std::list<Interval>::iterator q = p;
+ q++;
+ while (q != intervals.end()) {
+ coef_t distance = (*q).lb - (*p).lb;
+ if (distance > max_distance)
+ break;
+
+ if ((*q).ub - (*q).lb != size || int_mod(modulo, distance) != 0) {
+ q++;
+ continue;
+ }
+
+ int num_reduced = 0;
+ coef_t looking_for = int_mod((*p).lb, distance);
+ for (std::list<Interval>::iterator k = intervals.begin(); k != intervals.end(); k++) {
+ if ((*k).lb == looking_for && (*k).ub - (*k).lb == size) {
+ num_reduced++;
+ looking_for += distance;
+ if (looking_for >= modulo)
+ break;
+ }
+ else if ((*k).lb <= looking_for && (*k).ub >= looking_for + size) {
+ looking_for += distance;
+ if (looking_for >= modulo)
+ break;
+ }
+ else if ((*k).lb > looking_for)
+ break;
+ }
+
+ if (looking_for >= modulo && num_reduced > 1)
+ modulo_intervals.push_back(Modulo_Interval(distance, int_mod((*p).lb, distance), size));
+
+ q++;
+ }
+ }
+
+ modulo_intervals.sort();
+
+ // remove redundant reduced-strength intervals
+ std::list<Modulo_Interval>::iterator p2 = modulo_intervals.begin();
+ while (p2 != modulo_intervals.end()) {
+ std::list<Modulo_Interval>::iterator q2 = p2;
+ q2++;
+ while (q2 != modulo_intervals.end()) {
+ if ((*p2).modulo == (*q2).modulo && (*p2).start == (*q2).start)
+ q2 = modulo_intervals.erase(q2);
+ else if (int_mod((*q2).modulo, (*p2).modulo) == 0 &&
+ (*p2).start == int_mod((*q2).start, (*p2).modulo) &&
+ (*p2).size >= (*q2).size)
+ q2 = modulo_intervals.erase(q2);
+ else
+ q2++;
+ }
+ p2++;
+ }
+
+ // replace original intervals with new reduced-strength ones
+ for (std::list<Modulo_Interval>::iterator i = modulo_intervals.begin(); i != modulo_intervals.end(); i++) {
+ std::vector<Relation *> candidates;
+ int num_replaced = 0;
+ for (std::list<Interval>::iterator j = intervals.begin(); j != intervals.end(); j++)
+ if (int_mod((*j).modulo, (*i).modulo) == 0 &&
+ (*j).ub - (*j).lb >= (*i).size &&
+ (int_mod((*j).lb, (*i).modulo) == (*i).start ||
+ int_mod((*j).ub, (*i).modulo) == (*i).start + (*i).size)) {
+ candidates.push_back(&((*(*j).pos).first));
+ if (int_mod((*j).lb, (*i).modulo) == (*i).start &&
+ (*j).ub - (*j).lb == (*i).size)
+ num_replaced++;
+ }
+ if (num_replaced <= 1)
+ continue;
+
+ Relation R = copy(*candidates[0]);
+ for (size_t k = 1; k < candidates.size(); k++)
+ R = Union(R, copy(*candidates[k]));
+ Relation hull = ConvexHull(copy(R));
+ Relation remainder = Difference(copy(hull), copy(R));
+ if (!remainder.is_upper_bound_satisfiable()) {
+ std::list<Interval>::iterator replaced_one = intervals.end();
+ for (std::list<Interval>::iterator j = intervals.begin(); j != intervals.end();)
+ if (int_mod((*j).modulo, (*i).modulo) == 0 &&
+ (*j).ub - (*j).lb >= (*i).size &&
+ (int_mod((*j).lb, (*i).modulo) == (*i).start ||
+ int_mod((*j).ub, (*i).modulo) == (*i).start + (*i).size)) {
+ if (int_mod((*j).lb, (*i).modulo) == (*i).start &&
+ (*j).ub - (*j).lb == (*i).size) {
+ if (replaced_one == intervals.end()) {
+ (*(*j).pos).first = hull;
+ (*j).lb = int_mod((*j).lb, (*i).modulo);
+ (*j).ub = int_mod((*j).ub, (*i).modulo);
+ (*j).modulo = (*i).modulo;
+ (*j).change = true;
+ replaced_one = j;
+ j++;
+ }
+ else {
+ if ((*j).pos == orig) {
+ std::swap((*replaced_one).pos, (*j).pos);
+ (*(*replaced_one).pos).first = (*(*j).pos).first;
+ }
+ Rs.erase((*j).pos);
+ j = intervals.erase(j);
+ }
+ }
+ else {
+ if (int_mod((*j).lb, (*i).modulo) == (*i).start)
+ (*j).lb = (*j).lb + (*i).size + 1;
+ else
+ (*j).ub = (*j).ub - (*i).size - 1;
+ (*j).change = true;
+ j++;
+ }
+ }
+ else
+ j++;
+ }
+ }
+}
+} // namespace
+
+
+//
+// Simplify a union of sets/relations to a minimal (may not be
+// optimal) number of convex regions. It intends to replace
+// CheckForConvexRepresentation and CheckForConvexPairs functions.
+//
+Relation ConvexRepresentation(NOT_CONST Relation &R) {
+ Relation l_R = copy(R);
+ if (!l_R.is_upper_bound_satisfiable() || l_R.number_of_conjuncts() < 2)
+ return R;
+
+ // separate each conjunct into smooth convex region and holes
+ std::list<std::pair<Relation, Relation> > Rs; // pair(smooth region, hole condition)
+ for (DNF_Iterator c(l_R.query_DNF()); c.live(); c++) {
+ Relation r1 = Relation(l_R, c.curr());
+ Relation r2 = Approximate(copy(r1));
+ r1 = Gist(r1, copy(r2));
+ Rs.push_back(std::make_pair(r2, r1));
+ }
+
+ try {
+ bool change = true;
+ while (change) {
+ change = false;
+
+ std::list<std::pair<Relation, Relation> >::iterator i = Rs.begin();
+ while (i != Rs.end()) {
+ // find regions with identical hole conditions to merge
+ {
+ std::list<std::pair<Relation, Relation> >::iterator j = i;
+ j++;
+ while (j != Rs.end()) {
+ if (!Difference(copy((*i).second), copy((*j).second)).is_upper_bound_satisfiable() &&
+ !Difference(copy((*j).second), copy((*i).second)).is_upper_bound_satisfiable()) {
+ if (Must_Be_Subset(copy((*j).first), copy((*i).first))) {
+ j = Rs.erase(j);
+ }
+ else if (Must_Be_Subset(copy((*i).first), copy((*j).first))) {
+ (*i).first = (*j).first;
+ j = Rs.erase(j);
+ change = true;
+ }
+ else {
+ Relation r;
+ bool already_use_recthull = false;
+ try {
+ r = ConvexHull(Union(copy((*i).first), copy((*j).first)));
+ }
+ catch (const std::overflow_error &e) {
+ r = SimpleHull(Union(copy((*i).first), copy((*j).first)));
+ already_use_recthull = true;
+ }
+ retry_recthull:
+ Relation r2 = Difference(Difference(copy(r), copy((*i).first)), copy((*j).first));
+ if (!r2.is_upper_bound_satisfiable()) { // convex hull is tight
+ (*i).first = r;
+ j = Rs.erase(j);
+ change = true;
+ }
+ else {
+ if (!already_use_recthull) {
+ r = SimpleHull(Union(copy((*i).first), copy((*j).first)));
+ already_use_recthull = true;
+ goto retry_recthull;
+ }
+ else
+ j++;
+ }
+ }
+ }
+ else
+ j++;
+ }
+ }
+
+ // find identical smooth regions as candidates for hole merge
+ std::list<std::list<std::pair<Relation, Relation> >::iterator> s;
+ for (std::list<std::pair<Relation, Relation> >::iterator j = Rs.begin(); j != Rs.end(); j++)
+ if (j != i) {
+ if (!Intersection(Difference(copy((*i).first), copy((*j).first)), copy((*j).second)).is_upper_bound_satisfiable() &&
+ !Intersection(Difference(copy((*j).first), copy((*i).first)), copy((*i).second)).is_upper_bound_satisfiable())
+ s.push_back(j);
+ }
+
+ if (s.size() != 0) {
+ // convert hole condition c1*x1+c2*x2+... = c*alpha+d to a pair of inequalities
+ (*i).second = EQs_to_GEQs((*i).second, false);
+
+ // find potential wildcards that can be used for hole conditions
+ std::set<Variable_ID> nonsingle_wild;
+ for (EQ_Iterator ei((*i).second.single_conjunct()); ei; ei++)
+ if ((*ei).has_wildcards())
+ for (Constr_Vars_Iter cvi(*ei, true); cvi; cvi++)
+ nonsingle_wild.insert(cvi.curr_var());
+ for (GEQ_Iterator gei((*i).second.single_conjunct()); gei; gei++)
+ if ((*gei).has_wildcards()) {
+ Constr_Vars_Iter cvi(*gei, true);
+ Constr_Vars_Iter cvi2 = cvi;
+ cvi2++;
+ if (cvi2) {
+ nonsingle_wild.insert(cvi.curr_var());
+ for (; cvi2; cvi2++)
+ nonsingle_wild.insert(cvi2.curr_var());
+ }
+ }
+
+ // find hole condition in c*alpha+d1<=c1*x1+c2*x2+...<=c*alpha+d2 format
+ for (GEQ_Iterator gei((*i).second.single_conjunct()); gei; gei++)
+ if ((*gei).has_wildcards()) {
+ coef_t c;
+ Variable_ID v;
+ {
+ Constr_Vars_Iter cvi(*gei, true);
+ v = cvi.curr_var();
+ c = cvi.curr_coef();
+ if (c < 0 || nonsingle_wild.find(v) != nonsingle_wild.end())
+ continue;
+ }
+
+ coef_t lb = posInfinity;
+ for (GEQ_Iterator gei2((*i).second.single_conjunct()); gei2; gei2++) {
+ if (!(*gei2 == *gei) && (*gei2).get_coef(v) != 0) {
+ if (lb != posInfinity) {
+ nonsingle_wild.insert(v);
+ break;
+ }
+
+ bool match = true;
+ for (Constr_Vars_Iter cvi2(*gei); cvi2; cvi2++)
+ if (cvi2.curr_coef() != -((*gei2).get_coef(cvi2.curr_var()))) {
+ match = false;
+ break;
+ }
+ if (match)
+ for (Constr_Vars_Iter cvi2(*gei2); cvi2; cvi2++)
+ if (cvi2.curr_coef() != -((*gei).get_coef(cvi2.curr_var()))) {
+ match = false;
+ break;
+ }
+ if (!match) {
+ nonsingle_wild.insert(v);
+ break;
+ }
+
+ lb = -(*gei2).get_const();
+ }
+ }
+
+ if (nonsingle_wild.find(v) != nonsingle_wild.end())
+ continue;
+
+ Relation stride_cond = Relation::True((*i).second);
+ F_Exists *f_exists = stride_cond.and_with_and()->add_exists();
+ Variable_ID e = f_exists->declare();
+ F_And *f_root = f_exists->add_and();
+ GEQ_Handle h1 = f_root->add_GEQ();
+ GEQ_Handle h2 = f_root->add_GEQ();
+ for (Constr_Vars_Iter cvi2(*gei); cvi2; cvi2++) {
+ Variable_ID v = cvi2.curr_var();
+ switch (v->kind()) {
+ case Wildcard_Var:
+ h1.update_coef(e, cvi2.curr_coef());
+ h2.update_coef(e, -cvi2.curr_coef());
+ break;
+ case Global_Var: {
+ Global_Var_ID g = v->get_global_var();
+ Variable_ID v2;
+ if (g->arity() == 0)
+ v2 = stride_cond.get_local(g);
+ else
+ v2 = stride_cond.get_local(g, v->function_of());
+ h1.update_coef(v2, cvi2.curr_coef());
+ h2.update_coef(v2, -cvi2.curr_coef());
+ break;
+ }
+ default:
+ h1.update_coef(v, cvi2.curr_coef());
+ h2.update_coef(v, -cvi2.curr_coef());
+ }
+ }
+ h1.update_const((*gei).get_const());
+ h2.update_const(-lb);
+
+ stride_cond.simplify();
+ Relation other_cond = Gist(copy((*i).second), copy(stride_cond));
+
+ // find regions with potential mergeable stride condition with this one
+ std::list<Interval> intervals;
+ intervals.push_back(Interval(i, lb, (*gei).get_const()));
+
+ for (std::list<std::list<std::pair<Relation, Relation> >::iterator>::iterator j = s.begin(); j != s.end(); j++)
+ if (Must_Be_Subset(copy((**j).second), copy(other_cond))) {
+ Relation stride_cond2 = Gist(copy((**j).second), copy(other_cond));
+
+ // interval can be removed
+ if (stride_cond2.is_obvious_tautology()) {
+ intervals.push_back(Interval(*j, 0, c-1));
+ continue;
+ }
+
+ stride_cond2 = EQs_to_GEQs(stride_cond2, false);
+ coef_t lb, ub;
+ GEQ_Iterator gei2(stride_cond2.single_conjunct());
+ coef_t sign = 0;
+ for (Constr_Vars_Iter cvi(*gei2, true); cvi; cvi++)
+ if (sign != 0) {
+ sign = 0;
+ break;
+ }
+ else if (cvi.curr_coef() == c)
+ sign = 1;
+ else if (cvi.curr_coef() == -c)
+ sign = -1;
+ else {
+ sign = 0;
+ break;
+ }
+ if (sign == 0)
+ continue;
+
+ bool match = true;
+ for (Constr_Vars_Iter cvi(*gei2); cvi; cvi++) {
+ Variable_ID v = cvi.curr_var();
+ if (v->kind() == Wildcard_Var)
+ continue;
+ else if (v->kind() == Global_Var) {
+ Global_Var_ID g = v->get_global_var();
+ if (g->arity() == 0)
+ v = (*i).second.get_local(g);
+ else
+ v = (*i).second.get_local(g, v->function_of());
+ }
+
+ if (cvi.curr_coef() != sign * (*gei).get_coef(v)) {
+ match = false;
+ break;
+ }
+ }
+ if (!match)
+ continue;
+
+ for (Constr_Vars_Iter cvi(*gei); cvi; cvi++) {
+ Variable_ID v = cvi.curr_var();
+ if (v->kind() == Wildcard_Var)
+ continue;
+ else if (v->kind() == Global_Var) {
+ Global_Var_ID g = v->get_global_var();
+ if (g->arity() == 0)
+ v = stride_cond2.get_local(g);
+ else
+ v = stride_cond2.get_local(g, v->function_of());
+ }
+
+ if (cvi.curr_coef() != sign * (*gei2).get_coef(v)) {
+ match = false;
+ break;
+ }
+ }
+ if (!match)
+ continue;
+ if (sign > 0)
+ ub = (*gei2).get_const();
+ else
+ lb = -(*gei2).get_const();
+
+ gei2++;
+ if (!gei2)
+ continue;
+
+ coef_t sign2 = 0;
+ for (Constr_Vars_Iter cvi(*gei2, true); cvi; cvi++)
+ if (sign2 != 0) {
+ sign2 = 0;
+ break;
+ }
+ else if (cvi.curr_coef() == c)
+ sign2 = 1;
+ else if (cvi.curr_coef() == -c)
+ sign2 = -1;
+ else {
+ sign2 = 0;
+ break;
+ }
+ if (sign2 != -sign)
+ continue;
+
+ for (Constr_Vars_Iter cvi(*gei2); cvi; cvi++) {
+ Variable_ID v = cvi.curr_var();
+ if (v->kind() == Wildcard_Var)
+ continue;
+ else if (v->kind() == Global_Var) {
+ Global_Var_ID g = v->get_global_var();
+ if (g->arity() == 0)
+ v = (*i).second.get_local(g);
+ else
+ v = (*i).second.get_local(g, v->function_of());
+ }
+
+ if (cvi.curr_coef() != sign2 * (*gei).get_coef(v)) {
+ match = false;
+ break;
+ }
+ }
+ if (!match)
+ continue;
+
+ for (Constr_Vars_Iter cvi(*gei); cvi; cvi++) {
+ Variable_ID v = cvi.curr_var();
+ if (v->kind() == Wildcard_Var)
+ continue;
+ else if (v->kind() == Global_Var) {
+ Global_Var_ID g = v->get_global_var();
+ if (g->arity() == 0)
+ v = stride_cond2.get_local(g);
+ else
+ v = stride_cond2.get_local(g, v->function_of());
+ }
+
+ if (cvi.curr_coef() != sign2 * (*gei2).get_coef(v)) {
+ match = false;
+ break;
+ }
+ }
+ if (!match)
+ continue;
+ if (sign2 > 0)
+ ub = (*gei2).get_const();
+ else
+ lb = -(*gei2).get_const();
+
+ gei2++;
+ if (gei2)
+ continue;
+
+ intervals.push_back(Interval(*j, lb, ub));
+ }
+
+ merge_intervals(intervals, c, Rs, i);
+
+ // make current region the last one being updated
+ bool invalid = false;
+ for (std::list<Interval>::iterator ii = intervals.begin(); ii != intervals.end(); ii++)
+ if ((*ii).change && (*ii).pos == i) {
+ invalid = true;
+ intervals.push_back(*ii);
+ intervals.erase(ii);
+ break;
+ }
+
+ // update hole condition for each region
+ for (std::list<Interval>::iterator ii = intervals.begin(); ii != intervals.end(); ii++)
+ if ((*ii).change) {
+ change = true;
+
+ if ((*ii).ub - (*ii).lb + 1 >= (*ii).modulo)
+ (*(*ii).pos).second = copy(other_cond);
+ else {
+ Relation stride_cond = Relation::True((*i).second);
+ F_Exists *f_exists = stride_cond.and_with_and()->add_exists();
+ Variable_ID e = f_exists->declare();
+ F_And *f_root = f_exists->add_and();
+ GEQ_Handle h1 = f_root->add_GEQ();
+ GEQ_Handle h2 = f_root->add_GEQ();
+ for (Constr_Vars_Iter cvi2(*gei); cvi2; cvi2++) {
+ Variable_ID v = cvi2.curr_var();
+ switch (v->kind()) {
+ case Wildcard_Var:
+ h1.update_coef(e, (*ii).modulo);
+ h2.update_coef(e, -(*ii).modulo);
+ break;
+ case Global_Var: {
+ Global_Var_ID g = v->get_global_var();
+ Variable_ID v2;
+ if (g->arity() == 0)
+ v2 = stride_cond.get_local(g);
+ else
+ v2 = stride_cond.get_local(g, v->function_of());
+ h1.update_coef(v2, cvi2.curr_coef());
+ h2.update_coef(v2, -cvi2.curr_coef());
+ break;
+ }
+ default:
+ h1.update_coef(v, cvi2.curr_coef());
+ h2.update_coef(v, -cvi2.curr_coef());
+ }
+ }
+ h1.update_const((*ii).ub);
+ h2.update_const(-(*ii).lb);
+
+ (*(*ii).pos).second = Intersection(copy(other_cond), stride_cond);
+ (*(*ii).pos).second.simplify();
+ }
+ }
+
+ if (invalid)
+ break;
+ }
+ }
+ i++;
+ }
+ }
+ }
+ catch (const presburger_error &e) {
+ throw e;
+ }
+
+ Relation R2 = Relation::False(l_R);
+ for (std::list<std::pair<Relation, Relation> >::iterator i = Rs.begin(); i != Rs.end(); i++)
+ R2 = Union(R2, Intersection((*i).first, (*i).second));
+ R2.simplify(0, 1);
+
+ return R2;
+}
+
+//
+// Use gist and value range to calculate a quick rectangular hull. It
+// intends to replace all hull calculations (QuickHull, BetterHull,
+// FastTightHull) beyond the method of ConvexHull (dual
+// representations). In the future, it will support max(...)-like
+// upper bound. So RectHull complements ConvexHull in two ways: first
+// for relations that ConvexHull gets too complicated, second for
+// relations where different conjuncts have different symbolic upper
+// bounds.
+//
+Relation RectHull(NOT_CONST Relation &Rel) {
+ Relation R = Approximate(consume_and_regurgitate(Rel));
+ if (!R.is_upper_bound_satisfiable())
+ return R;
+ if (R.has_single_conjunct())
+ return R;
+
+ std::vector<std::string> input_names(R.n_inp());
+ for (int i = 1; i <= R.n_inp(); i++)
+ input_names[i-1] = R.input_var(i)->name();
+ std::vector<std::string> output_names(R.n_out());
+ for (int i = 1; i <= R.n_out(); i++)
+ output_names[i-1] = R.output_var(i)->name();
+
+ DNF_Iterator c(R.query_DNF());
+ Relation r = Relation(R, c.curr());
+ c++;
+ std::vector<std::pair<coef_t, coef_t> > bounds1(R.n_inp());
+ std::vector<std::pair<coef_t, coef_t> > bounds2(R.n_out());
+ {
+ Relation t = Project_Sym(copy(r));
+ t.simplify();
+ for (int i = 1; i <= R.n_inp(); i++) {
+ Tuple<Variable_ID> v;
+ for (int j = 1; j <= R.n_inp(); j++)
+ if (j != i)
+ v.append(r.input_var(j));
+ for (int j = 1; j <= R.n_out(); j++)
+ v.append(r.output_var(j));
+ Relation t2 = Project(copy(t), v);
+ t2.query_variable_bounds(t2.input_var(i), bounds1[i-1].first, bounds1[i-1].second);
+ }
+ for (int i = 1; i <= R.n_out(); i++) {
+ Tuple<Variable_ID> v;
+ for (int j = 1; j <= R.n_out(); j++)
+ if (j != i)
+ v.append(r.output_var(j));
+ for (int j = 1; j <= R.n_inp(); j++)
+ v.append(r.input_var(j));
+ Relation t2 = Project(copy(t), v);
+ t2.query_variable_bounds(t2.output_var(i), bounds2[i-1].first, bounds2[i-1].second);
+ }
+ }
+
+ while (c.live()) {
+ Relation r2 = Relation(R, c.curr());
+ c++;
+ Relation x = Gist(copy(r), Gist(copy(r), copy(r2), 1), 1);
+ if (Difference(copy(r2), copy(x)).is_upper_bound_satisfiable())
+ x = Relation::True(R);
+ Relation y = Gist(copy(r2), Gist(copy(r2), copy(r), 1), 1);
+ if (Difference(copy(r), copy(y)).is_upper_bound_satisfiable())
+ y = Relation::True(R);
+ r = Intersection(x, y);
+
+ {
+ Relation t = Project_Sym(copy(r2));
+ t.simplify();
+ for (int i = 1; i <= R.n_inp(); i++) {
+ Tuple<Variable_ID> v;
+ for (int j = 1; j <= R.n_inp(); j++)
+ if (j != i)
+ v.append(r2.input_var(j));
+ for (int j = 1; j <= R.n_out(); j++)
+ v.append(r2.output_var(j));
+ Relation t2 = Project(copy(t), v);
+ coef_t lbound, ubound;
+ t2.query_variable_bounds(t2.input_var(i), lbound, ubound);
+ bounds1[i-1].first = min(bounds1[i-1].first, lbound);
+ bounds1[i-1].second = max(bounds1[i-1].second, ubound);
+ }
+ for (int i = 1; i <= R.n_out(); i++) {
+ Tuple<Variable_ID> v;
+ for (int j = 1; j <= R.n_out(); j++)
+ if (j != i)
+ v.append(r2.output_var(j));
+ for (int j = 1; j <= R.n_inp(); j++)
+ v.append(r2.input_var(j));
+ Relation t2 = Project(copy(t), v);
+ coef_t lbound, ubound;
+ t2.query_variable_bounds(t2.output_var(i), lbound, ubound);
+ bounds2[i-1].first = min(bounds2[i-1].first, lbound);
+ bounds2[i-1].second = max(bounds2[i-1].second, ubound);
+ }
+ }
+
+ Relation r3(R.n_inp(), R.n_out());
+ F_And *f_root = r3.add_and();
+ for (int i = 1; i <= R.n_inp(); i++) {
+ if (bounds1[i-1].first != -posInfinity) {
+ GEQ_Handle h = f_root->add_GEQ();
+ h.update_coef(r3.input_var(i), 1);
+ h.update_const(-bounds1[i-1].first);
+ }
+ if (bounds1[i-1].second != posInfinity) {
+ GEQ_Handle h = f_root->add_GEQ();
+ h.update_coef(r3.input_var(i), -1);
+ h.update_const(bounds1[i-1].second);
+ }
+ }
+ for (int i = 1; i <= R.n_out(); i++) {
+ if (bounds2[i-1].first != -posInfinity) {
+ GEQ_Handle h = f_root->add_GEQ();
+ h.update_coef(r3.output_var(i), 1);
+ h.update_const(-bounds2[i-1].first);
+ }
+ if (bounds2[i-1].second != posInfinity) {
+ GEQ_Handle h = f_root->add_GEQ();
+ h.update_coef(r3.output_var(i), -1);
+ h.update_const(bounds2[i-1].second);
+ }
+ }
+ r = Intersection(r, r3);
+ r.simplify();
+ }
+
+ for (int i = 1; i <= r.n_inp(); i++)
+ r.name_input_var(i, input_names[i-1]);
+ for (int i = 1; i <= r.n_out(); i++)
+ r.name_output_var(i, output_names[i-1]);
+ r.setup_names();
+ return r;
+}
+
+}
+
diff --git a/omegalib/omega/src/hull_simple.cc b/omegalib/omega/src/hull_simple.cc
new file mode 100755
index 0000000..62dcb26
--- /dev/null
+++ b/omegalib/omega/src/hull_simple.cc
@@ -0,0 +1,1013 @@
+/*****************************************************************************
+ Copyright (C) 2011 Chun Chen
+ All Rights Reserved.
+
+ Purpose:
+ Hull approximation including lattice and irregular constraints that
+ involves wildcards.
+
+ Notes:
+
+ History:
+ 03/12/11 Created by Chun Chen
+ *****************************************************************************/
+
+#include <assert.h>
+#include <omega.h>
+#include <basic/BoolSet.h>
+#include <vector>
+#include <list>
+#include <set>
+#include <string>
+#include <algorithm>
+
+namespace omega {
+
+Relation SimpleHull(const Relation &R, bool allow_stride_constraint,
+ bool allow_irregular_constraint) {
+ std::vector<Relation> Rs;
+ Rs.push_back(R);
+ return SimpleHull(Rs, allow_stride_constraint, allow_irregular_constraint);
+}
+
+Relation SimpleHull(const std::vector<Relation> &Rs,
+ bool allow_stride_constraint, bool allow_irregular_constraint) {
+ // check for sanity of parameters
+ if (Rs.size() == 0)
+ return Relation::False(0);
+ int num_dim = -1;
+ int first_non_null;
+ for (int i = 0; i < Rs.size(); i++) {
+ if (Rs[i].is_null())
+ continue;
+
+ if (num_dim == -1) {
+ num_dim = Rs[i].n_inp();
+ first_non_null = i;
+ }
+
+ if (Rs[i].n_inp() != num_dim)
+ throw std::invalid_argument(
+ "relations for hull must have same dimension");
+ if (Rs[i].n_out() != 0)
+ throw std::invalid_argument(
+ "hull calculation must be set relation");
+ }
+
+ // convert to a list of relations each with a single conjunct
+ std::vector<Relation> l_Rs;
+ for (int i = 0; i < Rs.size(); i++) {
+ if (Rs[i].is_null())
+ continue;
+
+ Relation r = copy(Rs[i]);
+
+ //r.simplify(2, 4);
+ r.simplify();
+ DNF_Iterator c(r.query_DNF());
+ int top = l_Rs.size();
+ while (c.live()) {
+ Relation r2 = Relation(r, c.curr());
+
+ // quick elimination of redundant conjuncts
+ bool already_included = false;
+ for (int j = 0; j < top; j++)
+ if (Must_Be_Subset(copy(r2), copy(l_Rs[j]))) {
+ already_included = true;
+ break;
+ } else if (Must_Be_Subset(copy(l_Rs[j]), copy(r2))) {
+ l_Rs.erase(l_Rs.begin() + j);
+ top--;
+ break;
+ }
+
+ if (!already_included)
+ l_Rs.push_back(r2);
+ c++;
+ }
+ }
+
+ // shortcut for simple case
+ if (l_Rs.size() == 0) {
+ if (num_dim == -1)
+ return Relation::False(0);
+ else {
+ Relation r = Relation::False(num_dim);
+ r.copy_names(Rs[first_non_null]);
+ r.setup_names();
+ return r;
+ }
+ } else if (l_Rs.size() == 1) {
+ if (allow_stride_constraint && allow_irregular_constraint) {
+ l_Rs[0].copy_names(Rs[first_non_null]);
+ l_Rs[0].setup_names();
+ return l_Rs[0];
+ } else if (!allow_stride_constraint && !allow_irregular_constraint) {
+ l_Rs[0] = Approximate(l_Rs[0]);
+ l_Rs[0].copy_names(Rs[first_non_null]);
+ l_Rs[0].setup_names();
+ return l_Rs[0];
+ }
+ }
+
+ Relation hull = Relation::True(num_dim);
+
+ // lattice union approximation
+ if (allow_stride_constraint) {
+ std::vector<std::vector<std::pair<EQ_Handle, BoolSet<> > > > strides(
+ l_Rs.size());
+ for (int i = 0; i < l_Rs.size(); i++)
+ for (EQ_Iterator e = l_Rs[i].single_conjunct()->EQs(); e; e++)
+ if ((*e).has_wildcards()) {
+ int num_wildcard = 0;
+ BoolSet<> affected(num_dim);
+ for (Constr_Vars_Iter cvi(*e); cvi; cvi++) {
+ if (cvi.curr_var()->kind() == Wildcard_Var)
+ num_wildcard++;
+ else if (cvi.curr_var()->kind() == Input_Var)
+ affected.set(cvi.curr_var()->get_position() - 1);
+ }
+ if (num_wildcard == 1)
+ strides[i].push_back(std::make_pair(*e, affected));
+ }
+
+ for (int i = 0; i < strides[0].size(); i++) {
+ coef_t c =
+ abs(
+ strides[0][i].first.get_coef(
+ Constr_Vars_Iter(strides[0][i].first, true).curr_var()));
+ coef_t old_c = c;
+ bool is_stride = true;
+ for (int j = 1; j < l_Rs.size(); j++) {
+ std::list<coef_t> candidates;
+ for (int k = 0; k < strides[j].size(); k++)
+ if (!(strides[0][i].second & strides[j][k].second).empty()) {
+ coef_t t = gcd(c,
+ abs(
+ strides[j][k].first.get_coef(
+ Constr_Vars_Iter(
+ strides[j][k].first,
+ true).curr_var())));
+ if (t != 1) {
+ std::list<coef_t>::iterator p = candidates.begin();
+ while (p != candidates.end() && *p > t)
+ ++p;
+ if (p == candidates.end() || *p != t)
+ candidates.insert(p, t);
+
+ t = gcd(t, abs(strides[0][i].first.get_const()));
+ t = gcd(t, abs(strides[j][k].first.get_const()));
+ if (t != 1) {
+ std::list<coef_t>::iterator p =
+ candidates.begin();
+ while (p != candidates.end() && *p > t)
+ ++p;
+ if (p == candidates.end() || *p != t)
+ candidates.insert(p, t);
+ }
+ }
+ }
+
+ bool found_matched_stride = false;
+ for (std::list<coef_t>::iterator k = candidates.begin();
+ k != candidates.end(); k++) {
+ Relation r = Relation::True(num_dim);
+ EQ_Handle h = r.and_with_EQ(strides[0][i].first);
+ h.update_coef(Constr_Vars_Iter(h, true).curr_var(),
+ -old_c + *k);
+ r.simplify();
+ if (Must_Be_Subset(copy(l_Rs[j]), copy(r))) {
+ c = *k;
+ found_matched_stride = true;
+ break;
+ }
+ }
+
+ if (!found_matched_stride) {
+ is_stride = false;
+ break;
+ }
+ }
+
+ if (is_stride) {
+ Relation r = Relation::True(num_dim);
+ EQ_Handle h = r.and_with_EQ(strides[0][i].first);
+ h.update_coef(Constr_Vars_Iter(h, true).curr_var(), -old_c + c);
+ r.simplify();
+ hull = Intersection(hull, r);
+ }
+ }
+ }
+
+ // consider some special wildcard constraints
+ if (allow_irregular_constraint) {
+ std::vector<
+ std::vector<
+ std::pair<Variable_ID, std::map<Variable_ID, coef_t> > > > ranges(
+ l_Rs.size());
+ for (int i = 0; i < l_Rs.size(); i++) {
+ std::vector<std::pair<GEQ_Handle, std::map<Variable_ID, coef_t> > > geqs_ub;
+ std::vector<std::pair<GEQ_Handle, std::map<Variable_ID, coef_t> > > geqs_lb;
+ for (GEQ_Iterator e = l_Rs[i].single_conjunct()->GEQs(); e; e++)
+ if ((*e).has_wildcards()) {
+ int num_wildcard = 0;
+ std::map<Variable_ID, coef_t> formula;
+ int direction;
+ for (Constr_Vars_Iter cvi(*e); cvi; cvi++) {
+ Variable_ID v = cvi.curr_var();
+ switch (v->kind()) {
+ case Wildcard_Var:
+ num_wildcard++;
+ if (cvi.curr_coef() > 0)
+ direction = true;
+ else
+ direction = false;
+ break;
+ case Input_Var:
+ case Global_Var:
+ formula[cvi.curr_var()] = cvi.curr_coef();
+ break;
+ default:
+ assert(false);
+ }
+ }
+ if (num_wildcard == 1) {
+ if (direction) {
+ for (std::map<Variable_ID, coef_t>::iterator j =
+ formula.begin(); j != formula.end(); j++)
+ j->second = -j->second;
+ geqs_ub.push_back(std::make_pair(*e, formula));
+ } else
+ geqs_lb.push_back(std::make_pair(*e, formula));
+ }
+ }
+ for (int j = 0; j < geqs_lb.size(); j++) {
+ Variable_ID v =
+ Constr_Vars_Iter(geqs_lb[j].first, true).curr_var();
+ for (int k = 0; k < geqs_ub.size(); k++)
+ if (v == Constr_Vars_Iter(geqs_ub[k].first, true).curr_var()
+ && geqs_lb[j].second == geqs_ub[k].second)
+ ranges[i].push_back(
+ std::make_pair(v, geqs_lb[j].second));
+ }
+ }
+
+ // find compatible wildcard match
+ // TODO: evaluate to find the best match, also avoid mapping two wildcards
+ // in a single conjunct to one variable (incorrect)
+ std::vector<std::vector<int> > all_match;
+ for (int i = 0; i < ranges[0].size(); i++) {
+ std::vector<int> match(l_Rs.size(), -1);
+ match[0] = i;
+ for (int j = 1; j < l_Rs.size(); j++) {
+ for (int k = 0; k < ranges[j].size(); k++)
+ if (ranges[0][i].second == ranges[j][k].second) {
+ match[j] = k;
+ break;
+ }
+ if (match[j] == -1)
+ break;
+ }
+ if (match[l_Rs.size() - 1] != -1)
+ all_match.push_back(match);
+ }
+
+ // map compatible wildcards to input variables
+ std::vector<Relation> ll_Rs(l_Rs.size());
+ for (int i = 0; i < l_Rs.size(); i++) {
+ Relation r(num_dim + all_match.size());
+ F_Exists *f_exists = r.add_and()->add_exists();
+ F_And *f_root = f_exists->add_and();
+ std::map<Variable_ID, Variable_ID> wc_map;
+ for (int j = 0; j < all_match.size(); j++)
+ wc_map[ranges[i][all_match[j][i]].first] = r.set_var(j + 1);
+
+ for (EQ_Iterator e(l_Rs[i].single_conjunct()->EQs()); e; e++)
+ if (!(*e).has_wildcards()) {
+ EQ_Handle h = f_root->add_EQ();
+ for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
+ switch (cvi.curr_var()->kind()) {
+ case Input_Var: {
+ h.update_coef(
+ r.set_var(
+ cvi.curr_var()->get_position()
+ + all_match.size()),
+ cvi.curr_coef());
+ break;
+ }
+ case Global_Var: {
+ Global_Var_ID g = cvi.curr_var()->get_global_var();
+ Variable_ID v;
+ if (g->arity() == 0)
+ v = r.get_local(g);
+ else
+ v = r.get_local(g,
+ cvi.curr_var()->function_of());
+ h.update_coef(v, cvi.curr_coef());
+ break;
+ }
+ default:
+ assert(false);
+ }
+ h.update_const((*e).get_const());
+ }
+
+ for (GEQ_Iterator e(l_Rs[i].single_conjunct()->GEQs()); e; e++) {
+ GEQ_Handle h = f_root->add_GEQ();
+ for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
+ switch (cvi.curr_var()->kind()) {
+ case Input_Var: {
+ h.update_coef(
+ r.set_var(
+ cvi.curr_var()->get_position()
+ + all_match.size()),
+ cvi.curr_coef());
+ break;
+ }
+ case Global_Var: {
+ Global_Var_ID g = cvi.curr_var()->get_global_var();
+ Variable_ID v;
+ if (g->arity() == 0)
+ v = r.get_local(g);
+ else
+ v = r.get_local(g, cvi.curr_var()->function_of());
+ h.update_coef(v, cvi.curr_coef());
+ break;
+ }
+ case Wildcard_Var: {
+ std::map<Variable_ID, Variable_ID>::iterator p =
+ wc_map.find(cvi.curr_var());
+ Variable_ID v;
+ if (p == wc_map.end()) {
+ v = f_exists->declare();
+ wc_map[cvi.curr_var()] = v;
+ } else
+ v = p->second;
+ h.update_coef(v, cvi.curr_coef());
+ break;
+ }
+ default:
+ assert(false);
+ }
+ h.update_const((*e).get_const());
+ }
+
+ r.simplify();
+ ll_Rs[i] = r;
+ }
+
+ // now use SimpleHull on regular bounds only
+ Relation result = SimpleHull(ll_Rs, false, false);
+
+ // convert imaginary input variables back to wildcards
+ Relation mapping(num_dim + all_match.size(), num_dim);
+ F_And *f_root = mapping.add_and();
+ for (int i = 0; i < num_dim; i++) {
+ EQ_Handle h = f_root->add_EQ();
+ h.update_coef(mapping.input_var(all_match.size() + i + 1), 1);
+ h.update_coef(mapping.output_var(i + 1), -1);
+ }
+ result = Range(Restrict_Domain(mapping, result));
+
+ hull = Intersection(hull, result);
+ hull.simplify();
+ hull.copy_names(Rs[first_non_null]);
+ hull.setup_names();
+ return hull;
+ }
+
+ // check regular bounds
+ if (l_Rs.size() == 1) {
+ hull = Intersection(hull, Approximate(copy(l_Rs[0])));
+ } else {
+ for (int i = 0; i < l_Rs.size(); i++) {
+ l_Rs[i] = Approximate(l_Rs[i]);
+ l_Rs[i].simplify(2, 4);
+ }
+
+ // check global variables
+ // TODO: global variable function_of() is not considered for now
+ std::map<Global_Var_ID, int> globals;
+ for (int i = 0; i < l_Rs.size(); i++)
+ for (Constraint_Iterator e(
+ l_Rs[i].single_conjunct()->constraints()); e; e++)
+ for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
+ if (cvi.curr_var()->kind() == Global_Var)
+ globals[cvi.curr_var()->get_global_var()] = -1;
+
+ if (globals.size() > 0) {
+ int count = 1;
+ for (std::map<Global_Var_ID, int>::iterator i = globals.begin();
+ i != globals.end(); i++)
+ i->second = count++;
+
+ std::vector<Relation> ll_Rs(l_Rs.size());
+ for (int i = 0; i < l_Rs.size(); i++) {
+ Relation r(num_dim + globals.size());
+ F_And *f_root = r.add_and();
+ for (EQ_Iterator e(l_Rs[i].single_conjunct()->EQs()); e; e++) {
+ EQ_Handle h = f_root->add_EQ();
+ for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
+ switch (cvi.curr_var()->kind()) {
+ case Input_Var: {
+ h.update_coef(
+ r.set_var(
+ cvi.curr_var()->get_position()
+ + globals.size()),
+ cvi.curr_coef());
+ break;
+ }
+ case Global_Var: {
+ h.update_coef(
+ r.set_var(
+ globals[cvi.curr_var()->get_global_var()]),
+ cvi.curr_coef());
+ break;
+ }
+ default:
+ assert(false);
+ }
+ h.update_const((*e).get_const());
+ }
+ for (GEQ_Iterator e(l_Rs[i].single_conjunct()->GEQs()); e;
+ e++) {
+ GEQ_Handle h = f_root->add_GEQ();
+ for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
+ switch (cvi.curr_var()->kind()) {
+ case Input_Var: {
+ h.update_coef(
+ r.set_var(
+ cvi.curr_var()->get_position()
+ + globals.size()),
+ cvi.curr_coef());
+ break;
+ }
+ case Global_Var: {
+ h.update_coef(
+ r.set_var(
+ globals[cvi.curr_var()->get_global_var()]),
+ cvi.curr_coef());
+ break;
+ }
+ default:
+ assert(false);
+ }
+ h.update_const((*e).get_const());
+ }
+
+ ll_Rs[i] = r;
+ }
+
+ Relation result = SimpleHull(ll_Rs, false, false);
+
+ std::map<int, Global_Var_ID> globals_reverse;
+ for (std::map<Global_Var_ID, int>::iterator i = globals.begin();
+ i != globals.end(); i++)
+ globals_reverse[i->second] = i->first;
+
+ Relation r(num_dim);
+ F_And *f_root = r.add_and();
+ for (EQ_Iterator e(result.single_conjunct()->EQs()); e; e++) {
+ EQ_Handle h = f_root->add_EQ();
+ for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
+ switch (cvi.curr_var()->kind()) {
+ case Input_Var: {
+ int pos = cvi.curr_var()->get_position();
+ if (pos > globals_reverse.size())
+ h.update_coef(
+ r.set_var(pos - globals_reverse.size()),
+ cvi.curr_coef());
+ else {
+ Global_Var_ID g = globals_reverse[pos];
+ h.update_coef(r.get_local(g), cvi.curr_coef());
+ }
+ break;
+ }
+ default:
+ assert(false);
+ }
+ h.update_const((*e).get_const());
+ }
+ for (GEQ_Iterator e(result.single_conjunct()->GEQs()); e; e++) {
+ GEQ_Handle h = f_root->add_GEQ();
+ for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
+ switch (cvi.curr_var()->kind()) {
+ case Input_Var: {
+ int pos = cvi.curr_var()->get_position();
+ if (pos > globals_reverse.size())
+ h.update_coef(
+ r.set_var(pos - globals_reverse.size()),
+ cvi.curr_coef());
+ else {
+ Global_Var_ID g = globals_reverse[pos];
+ h.update_coef(r.get_local(g), cvi.curr_coef());
+ }
+ break;
+ }
+ default:
+ assert(false);
+ }
+ h.update_const((*e).get_const());
+ }
+
+ hull = Intersection(hull, r);
+ hull.simplify();
+ hull.copy_names(Rs[first_non_null]);
+ hull.setup_names();
+ return hull;
+ } else {
+ std::vector<std::vector<Relation> > projected(num_dim + 1,
+ std::vector<Relation>(l_Rs.size()));
+ for (int i = 0; i < l_Rs.size(); i++) {
+ projected[num_dim][i] = copy(l_Rs[i]);
+ for (int j = num_dim - 1; j >= 0; j--) {
+ projected[j][i] = Project(copy(projected[j + 1][i]),
+ projected[j + 1][i].input_var(j + 1));
+ projected[j][i].simplify(2, 4);
+ }
+ }
+
+ std::vector<bool> has_lb(num_dim, false);
+ std::vector<bool> has_ub(num_dim, false);
+ for (int i = 0; i < num_dim; i++) {
+ bool skip_lb = false;
+ bool skip_ub = false;
+ std::vector<Relation> bound(l_Rs.size());
+ for (int j = 0; j < l_Rs.size(); j++) {
+ bound[j] = Gist(copy(projected[i + 1][j]),
+ copy(projected[i][j]), 1);
+ bound[j] = Approximate(bound[j]);
+ bound[j] = EQs_to_GEQs(bound[j]);
+
+ bool has_lb_not_in_hull = false;
+ bool has_ub_not_in_hull = false;
+ for (GEQ_Iterator e = bound[j].single_conjunct()->GEQs(); e;
+ e++) {
+ coef_t coef = (*e).get_coef(bound[j].input_var(i + 1));
+ if (!skip_lb && coef > 0) {
+ Relation r = Relation::True(bound[j].n_inp());
+ r.and_with_GEQ(*e);
+ r.simplify();
+
+ if (j != 0 && l_Rs.size() > 2
+ && Must_Be_Subset(copy(hull), copy(r)))
+ continue;
+
+ bool belong_to_hull = true;
+ for (int k = 0; k < l_Rs.size(); k++)
+ if (k != j
+ && !Must_Be_Subset(copy(l_Rs[k]),
+ copy(r))) {
+ belong_to_hull = false;
+ break;
+ }
+ if (belong_to_hull) {
+ hull.and_with_GEQ(*e);
+ has_lb[i] = true;
+ } else
+ has_lb_not_in_hull = true;
+ } else if (!skip_ub && coef < 0) {
+ Relation r = Relation::True(bound[j].n_inp());
+ r.and_with_GEQ(*e);
+ r.simplify();
+
+ if (j != 0 && l_Rs.size() > 2
+ && Must_Be_Subset(copy(hull), copy(r)))
+ continue;
+
+ bool belong_to_hull = true;
+ for (int k = 0; k < l_Rs.size(); k++)
+ if (k != j
+ && !Must_Be_Subset(copy(l_Rs[k]),
+ copy(r))) {
+ belong_to_hull = false;
+ break;
+ }
+ if (belong_to_hull) {
+ hull.and_with_GEQ(*e);
+ has_ub[i] = true;
+ } else
+ has_ub_not_in_hull = true;
+ }
+ }
+
+ if (!has_lb_not_in_hull)
+ skip_lb = true;
+ if (!has_ub_not_in_hull)
+ skip_ub = true;
+ if (skip_lb && skip_ub)
+ break;
+ }
+
+ // no ready lower bound, approximate it
+ bool got_rect_lb = false;
+ if (!skip_lb) {
+ for (int j = 0; j < l_Rs.size(); j++) {
+ std::set<BoolSet<> > S;
+ for (GEQ_Iterator e =
+ bound[j].single_conjunct()->GEQs(); e; e++) {
+ coef_t coef = (*e).get_coef(
+ bound[j].input_var(i + 1));
+ if (coef > 0) {
+ BoolSet<> s(i);
+ for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
+ if ((*cvi).var->kind() == Input_Var
+ && (*cvi).var->get_position() - 1
+ != i) {
+ if (((*cvi).coef > 0
+ && has_ub[(*cvi).var->get_position()
+ - 1])
+ || ((*cvi).coef < 0
+ && has_lb[(*cvi).var->get_position()
+ - 1]))
+ s.set(
+ (*cvi).var->get_position()
+ - 1);
+ else {
+ for (GEQ_Iterator e2 =
+ bound[j].single_conjunct()->GEQs();
+ e2; e2++)
+ if (e2 != e
+ && (((*cvi).coef > 0
+ && (*e2).get_coef(
+ (*cvi).var)
+ < 0)
+ || ((*cvi).coef
+ < 0
+ && (*e2).get_coef(
+ (*cvi).var)
+ > 0))) {
+ s.set(
+ (*cvi).var->get_position()
+ - 1);
+ break;
+ }
+ }
+ }
+
+ if (s.num_elem() > 0)
+ S.insert(s);
+ }
+ }
+
+ if (S.size() > 0) {
+ BoolSet<> s(i);
+ for (std::set<BoolSet<> >::iterator k = S.begin();
+ k != S.end(); k++)
+ s |= *k;
+ for (int k = 0; k < i; k++)
+ if (s.get(k)) {
+ BoolSet<> t(i);
+ t.set(k);
+ S.insert(t);
+ }
+
+ for (std::set<BoolSet<> >::iterator k = S.begin();
+ k != S.end(); k++) {
+
+ bool do_again = false;
+ std::set<int> vars;
+ int round_trip = 0;
+ do {
+ Relation r = copy(projected[i + 1][j]);
+
+ if (!do_again) {
+ for (int kk = 0; kk < i; kk++)
+ if ((*k).get(kk)) {
+ r = Project(r,
+ r.input_var(kk + 1));
+ vars.insert(kk + 1);
+ }
+ } else {
+ for (std::set<int>::iterator vars_it =
+ vars.begin();
+ vars_it != vars.end();
+ vars_it++)
+ if (*vars_it < i + 1)
+ r = Project(r,
+ r.input_var(*vars_it));
+ }
+
+ r.simplify(2, 4);
+ Relation r2 = Project(copy(r),
+ r.input_var(i + 1));
+ Relation b = Gist(copy(r), copy(r2), 1);
+ // Relation c = Project(copy(r),r.input_var(4) );
+
+ // c.simplify(2,4);
+ // Relation d = Project(copy(c), r.input_var(i+1));
+ // Relation e = Gist(copy(c), copy(d), 1);
+
+ b = Approximate(b);
+ b = EQs_to_GEQs(b);
+
+ for (GEQ_Iterator e =
+ b.single_conjunct()->GEQs(); e;
+ e++) {
+ coef_t coef = (*e).get_coef(
+ b.input_var(i + 1));
+ if (coef > 0) {
+ Relation r = Relation::True(
+ b.n_inp());
+ r.and_with_GEQ(*e);
+ r.simplify();
+
+ if (Must_Be_Subset(copy(hull),
+ copy(r)))
+ continue;
+
+ bool belong_to_hull = true;
+ for (int k = 0; k < l_Rs.size();
+ k++)
+ if (k != j
+ && !Must_Be_Subset(
+ copy(l_Rs[k]),
+ copy(r))) {
+ belong_to_hull = false;
+ break;
+ }
+ if (belong_to_hull) {
+ hull.and_with_GEQ(*e);
+ got_rect_lb = true;
+ }
+ }
+ }
+ do_again = false;
+ if (!got_rect_lb) {
+ bool found = false;
+ for (GEQ_Iterator e =
+ b.single_conjunct()->GEQs(); e;
+ e++) {
+ coef_t coef = (*e).get_coef(
+ b.input_var(i + 1));
+
+ if (coef > 0) {
+ for (Constr_Vars_Iter cvi(*e);
+ cvi; cvi++)
+ if ((*cvi).var->kind()
+ == Input_Var
+ && (*cvi).var->get_position()
+ - 1 != i) {
+
+ if (((*cvi).coef > 0
+ && has_ub[(*cvi).var->get_position()
+ - 1])
+ || ((*cvi).coef
+ < 0
+ && has_lb[(*cvi).var->get_position()
+ - 1])) {
+ vars.insert(
+ (*cvi).var->get_position());
+ found = true;
+ } else {
+ for (GEQ_Iterator e2 =
+ b.single_conjunct()->GEQs();
+ e2; e2++)
+ if (e2 != e
+ && (((*cvi).coef
+ > 0
+ && (*e2).get_coef(
+ (*cvi).var)
+ < 0)
+ || ((*cvi).coef
+ < 0
+ && (*e2).get_coef(
+ (*cvi).var)
+ > 0))) {
+ vars.insert(
+ (*cvi).var->get_position());
+ found =
+ true;
+ break;
+ }
+ }
+
+ }
+
+ }
+ if (found)
+ break;
+
+ }
+ if (found && (round_trip < i))
+ do_again = true;
+
+ }
+ round_trip++;
+ } while (do_again);
+ }
+
+ if (got_rect_lb)
+ break;
+ }
+ }
+ }
+
+ // no ready upper bound, approximate it
+ bool got_rect_ub = false;
+ if (!skip_ub) {
+ for (int j = 0; j < l_Rs.size(); j++) {
+ std::set<BoolSet<> > S;
+ for (GEQ_Iterator e =
+ bound[j].single_conjunct()->GEQs(); e; e++) {
+ coef_t coef = (*e).get_coef(
+ bound[j].input_var(i + 1));
+ if (coef < 0) {
+ BoolSet<> s(i);
+ for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
+ if ((*cvi).var->kind() == Input_Var
+ && (*cvi).var->get_position() - 1
+ != i) {
+ if (((*cvi).coef > 0
+ && has_ub[(*cvi).var->get_position()
+ - 1])
+ || ((*cvi).coef < 0
+ && has_lb[(*cvi).var->get_position()
+ - 1]))
+ s.set(
+ (*cvi).var->get_position()
+ - 1);
+ else {
+ for (GEQ_Iterator e2 =
+ bound[j].single_conjunct()->GEQs();
+ e2; e2++)
+ if (e2 != e
+ && (((*cvi).coef > 0
+ && (*e2).get_coef(
+ (*cvi).var)
+ < 0)
+ || ((*cvi).coef
+ < 0
+ && (*e2).get_coef(
+ (*cvi).var)
+ > 0))) {
+ s.set(
+ (*cvi).var->get_position()
+ - 1);
+ break;
+ }
+ }
+ }
+
+ if (s.num_elem() > 0)
+ S.insert(s);
+ }
+ }
+
+ if (S.size() > 0) {
+ BoolSet<> s(i);
+ for (std::set<BoolSet<> >::iterator k = S.begin();
+ k != S.end(); k++)
+ s |= *k;
+ for (int k = 0; k < i; k++)
+ if (s.get(k)) {
+ BoolSet<> t(i);
+ t.set(k);
+ S.insert(t);
+ }
+
+ for (std::set<BoolSet<> >::iterator k = S.begin();
+ k != S.end(); k++) {
+
+ bool do_again = false;
+ std::set<int> vars;
+ int round_trip = 0;
+ do {
+
+ Relation r = copy(projected[i + 1][j]);
+
+ if (!do_again) {
+ for (int kk = 0; kk < i; kk++)
+ if ((*k).get(kk)) {
+ r = Project(r,
+ r.input_var(kk + 1));
+ vars.insert(kk + 1);
+ }
+ } else {
+ for (std::set<int>::iterator vars_it =
+ vars.begin();
+ vars_it != vars.end();
+ vars_it++)
+ if (*vars_it < i + 1)
+ r = Project(r,
+ r.input_var(*vars_it));
+ }
+
+ r.simplify(2, 4);
+ Relation r2 = Project(copy(r),
+ r.input_var(i + 1));
+ // r2.simplify(2,4);
+ Relation b = Gist(r, r2, 1);
+ b = Approximate(b);
+ b = EQs_to_GEQs(b);
+
+ for (GEQ_Iterator e =
+ b.single_conjunct()->GEQs(); e;
+ e++) {
+ coef_t coef = (*e).get_coef(
+ b.input_var(i + 1));
+ if (coef < 0) {
+ Relation r = Relation::True(
+ b.n_inp());
+ r.and_with_GEQ(*e);
+ r.simplify();
+
+ if (Must_Be_Subset(copy(hull),
+ copy(r)))
+ continue;
+
+ bool belong_to_hull = true;
+ for (int k = 0; k < l_Rs.size();
+ k++)
+ if (k != j
+ && !Must_Be_Subset(
+ copy(l_Rs[k]),
+ copy(r))) {
+ belong_to_hull = false;
+ break;
+ }
+ if (belong_to_hull) {
+ hull.and_with_GEQ(*e);
+ got_rect_ub = true;
+ }
+ }
+ }
+ do_again = false;
+ if (!got_rect_ub) {
+ bool found = false;
+ for (GEQ_Iterator e =
+ b.single_conjunct()->GEQs(); e;
+ e++) {
+ coef_t coef = (*e).get_coef(
+ b.input_var(i + 1));
+ if (coef < 0) {
+ for (Constr_Vars_Iter cvi(*e);
+ cvi; cvi++)
+ if ((*cvi).var->kind()
+ == Input_Var
+ && (*cvi).var->get_position()
+ - 1 != i) {
+
+ if (((*cvi).coef > 0
+ && has_ub[(*cvi).var->get_position()
+ - 1])
+ || ((*cvi).coef
+ < 0
+ && has_lb[(*cvi).var->get_position()
+ - 1])) {
+ vars.insert(
+ (*cvi).var->get_position());
+ found = true;
+ } else {
+ for (GEQ_Iterator e2 =
+ b.single_conjunct()->GEQs();
+ e2; e2++)
+ if (e2 != e
+ && (((*cvi).coef
+ > 0
+ && (*e2).get_coef(
+ (*cvi).var)
+ < 0)
+ || ((*cvi).coef
+ < 0
+ && (*e2).get_coef(
+ (*cvi).var)
+ > 0))) {
+ vars.insert(
+ (*cvi).var->get_position());
+ found =
+ true;
+ break;
+ }
+ }
+
+ }
+ }
+ if (found)
+ break;
+ }
+ if (found && (round_trip < i))
+ do_again = true;
+
+ }
+ round_trip++;
+ } while (do_again);
+ }
+
+ if (got_rect_ub)
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ hull.simplify();
+ hull.copy_names(Rs[first_non_null]);
+ hull.setup_names();
+ return hull;
+}
+
+}
+
diff --git a/omegalib/omega/src/omega_core/oc.cc b/omegalib/omega/src/omega_core/oc.cc
new file mode 100644
index 0000000..0dc9b49
--- /dev/null
+++ b/omegalib/omega/src/omega_core/oc.cc
@@ -0,0 +1,754 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 the Omega Project Team
+ Copyright (C) 2005-2011 Chun Chen
+ All Rights Reserved.
+
+ Purpose:
+ Simplify a problem.
+
+ Notes:
+
+ History:
+ 12/10/06 Improved gist function, by Chun Chen.
+*****************************************************************************/
+
+#include <omega/omega_core/oc_i.h>
+
+namespace omega {
+
+eqn SUBs[maxVars+1];
+Memory redMemory[maxVars+1];
+
+int Problem::reduceProblem() {
+ int result;
+ checkVars(nVars+1);
+ assert(omegaInitialized);
+ if (nVars > nEQs + 3 * safeVars)
+ freeEliminations(safeVars);
+
+ check();
+ if (!mayBeRed && nSUBs == 0 && safeVars == 0) {
+ result = solve(OC_SOLVE_UNKNOWN);
+ nGEQs = 0;
+ nEQs = 0;
+ nSUBs = 0;
+ nMemories = 0;
+ if (!result) {
+ int e = newEQ();
+ assert(e == 0);
+ eqnnzero(&EQs[0], nVars);
+ EQs[0].color = EQ_BLACK;
+ EQs[0].coef[0] = 1;
+ }
+ check();
+ return result;
+ }
+ return solve(OC_SOLVE_SIMPLIFY);
+}
+
+
+int Problem::simplifyProblem(int verify, int subs, int redundantElimination) {
+ checkVars(nVars+1);
+ assert(omegaInitialized);
+ setInternals();
+ check();
+ if (!reduceProblem()) goto returnFalse;
+ if (verify) {
+ addingOuterEqualities++;
+ int r = verifyProblem();
+ addingOuterEqualities--;
+ if (!r) goto returnFalse;
+ if (nEQs) { // found some equality constraints during verification
+ int numRed = 0;
+ if (mayBeRed)
+ for (int e = nGEQs - 1; e >= 0; e--) if (GEQs[e].color == EQ_RED) numRed++;
+ if (mayBeRed && nVars == safeVars && numRed == 1)
+ nEQs = 0; // discard them
+ else if (!reduceProblem()) {
+ assert(0 && "Added equality constraint to verified problem generates false");
+ }
+ }
+ }
+ if (redundantElimination) {
+ if (redundantElimination > 1) {
+ if (!expensiveEqualityCheck()) goto returnFalse;
+ }
+ if (!quickKill(0)) goto returnFalse;
+ if (redundantElimination > 1) {
+ if (!expensiveKill()) goto returnFalse;
+ }
+ }
+ resurrectSubs();
+ if (redundantElimination)
+ simplifyStrideConstraints();
+ if (redundantElimination > 2 && safeVars < nVars) {
+ if (!quickKill(0)) goto returnFalse;
+ return simplifyProblem(verify, subs, redundantElimination-2);
+ }
+ setExternals();
+ assert(nMemories == 0);
+ return (1);
+
+returnFalse:
+ nGEQs = 0;
+ nEQs = 0;
+ resurrectSubs();
+ nGEQs = 0;
+ nEQs = 0;
+ int neweq = newEQ();
+ assert(neweq == 0);
+ eqnnzero(&EQs[neweq], nVars);
+ EQs[neweq].color = EQ_BLACK;
+ EQs[neweq].coef[0] = 1;
+ nMemories = 0;
+ return 0;
+}
+
+int Problem::simplifyApproximate(bool strides_allowed) {
+ int result;
+ checkVars(nVars+1);
+ assert(inApproximateMode == 0);
+
+ inApproximateMode = 1;
+ inStridesAllowedMode = strides_allowed;
+ if (TRACE)
+ fprintf(outputFile, "Entering Approximate Mode [\n");
+
+ assert(omegaInitialized);
+ result = simplifyProblem(0,0,0);
+
+ while (result && !strides_allowed && nVars > safeVars) {
+ int e;
+ for (e = nGEQs - 1; e >= 0; e--)
+ if (GEQs[e].coef[nVars]) deleteGEQ(e);
+ for (e = nEQs - 1; e >= 0; e--)
+ if (EQs[e].coef[nVars]) deleteEQ(e);
+ nVars--;
+ result = simplifyProblem(0,0,0);
+ }
+
+ if (TRACE)
+ fprintf(outputFile, "] Leaving Approximate Mode\n");
+
+ assert(inApproximateMode == 1);
+ inApproximateMode=0;
+ inStridesAllowedMode = 0;
+
+ assert(nMemories == 0);
+ return (result);
+}
+
+
+
+
+/*
+ * Return 1 if red equations constrain the set of possible
+ * solutions. We assume that there are solutions to the black
+ * equations by themselves, so if there is no solution to the combined
+ * problem, we return 1.
+ */
+
+#ifdef GIST_CHECK
+Problem full_answer, context;
+Problem redProblem;
+#endif
+
+redCheck Problem::redSimplifyProblem(int effort, int computeGist) {
+ int result;
+ int e;
+
+ checkVars(nVars+1);
+ assert(mayBeRed >= 0);
+ mayBeRed++;
+
+ assert(omegaInitialized);
+ if (TRACE) {
+ fprintf(outputFile, "Checking for red equations:\n");
+ printProblem();
+ }
+ setInternals();
+
+#ifdef GIST_CHECK
+ int r1,r2;
+ if (TRACE)
+ fprintf(outputFile,"Set-up for gist invariant checking[\n");
+ redProblem = *this;
+ redProblem.check();
+ full_answer = *this;
+ full_answer.check();
+ full_answer.turnRedBlack();
+ full_answer.check();
+ r1 = full_answer.simplifyProblem(1,0,1);
+ full_answer.check();
+ if (DBUG) fprintf(outputFile,"Simplifying context [\n");
+ context = *this;
+ context.check();
+ context.deleteRed();
+ context.check();
+ r2 = context.simplifyProblem(1,0,1);
+ context.check();
+ if (DBUG) fprintf(outputFile,"] Simplifying context\n");
+
+ if (!r2 && TRACE) fprintf(outputFile, "WARNING: Gist context is false!\n");
+ if (TRACE)
+ fprintf(outputFile,"] Set-up for gist invariant checking done\n");
+#endif
+
+ // Save known integer modular equations, -- by chun 12/10/2006
+ eqn ModularEQs[nEQs];
+ int nModularEQs = 0;
+ int old_nVars = nVars;
+ for (int e = 0; e < nEQs; e++)
+ if (EQs[e].color != EQ_RED)
+ for (int i = safeVars+1; i <= nVars; i++)
+ if (EQs[e].coef[i] != 0) {
+ eqnncpy(&(ModularEQs[nModularEQs++]), &(EQs[e]), nVars);
+ break;
+ }
+
+
+ if (solveEQ() == false) {
+ if (TRACE)
+ fprintf(outputFile, "Gist is FALSE\n");
+ if (computeGist) {
+ nMemories = 0;
+ nGEQs = 0;
+ nEQs = 0;
+ resurrectSubs();
+ nGEQs = 0;
+ nEQs = 0;
+ int neweq = newEQ();
+ assert(neweq == 0);
+ eqnnzero(&EQs[neweq], nVars);
+ EQs[neweq].color = EQ_RED;
+ EQs[neweq].coef[0] = 1;
+ }
+ mayBeRed--;
+ return redFalse;
+ }
+
+ if (!computeGist && nMemories)
+ return redConstraints;
+ if (normalize() == normalize_false) {
+ if (TRACE)
+ fprintf(outputFile, "Gist is FALSE\n");
+ if (computeGist) {
+ nGEQs = 0;
+ nEQs = 0;
+ resurrectSubs();
+ nMemories = 0;
+ nGEQs = 0;
+ nEQs = 0;
+ int neweq = newEQ();
+ assert(neweq == 0);
+ eqnnzero(&EQs[neweq], nVars);
+ EQs[neweq].color = EQ_RED;
+ EQs[neweq].coef[0] = 1;
+ }
+ mayBeRed--;
+ return redFalse;
+ }
+
+ result = 0;
+ for (e = nGEQs - 1; e >= 0; e--) if (GEQs[e].color == EQ_RED) result = 1;
+ for (e = nEQs - 1; e >= 0; e--) if (EQs[e].color == EQ_RED) result = 1;
+ if (nMemories) result = 1;
+ if (!result) {
+ if (computeGist) {
+ nGEQs = 0;
+ nEQs = 0;
+ resurrectSubs();
+ nGEQs = 0;
+ nMemories = 0;
+ nEQs = 0;
+ }
+ mayBeRed--;
+ return noRed;
+ }
+
+ result = simplifyProblem(effort?1:0,1,0);
+#ifdef GIST_CHECK
+ if (!r1 && TRACE && result)
+ fprintf(outputFile, "Gist is False but not detected\n");
+#endif
+ if (!result) {
+ if (TRACE)
+ fprintf(outputFile, "Gist is FALSE\n");
+ if (computeGist) {
+ nGEQs = 0;
+ nEQs = 0;
+ resurrectSubs();
+ nGEQs = 0;
+ nEQs = 0;
+ int neweq = newEQ();
+ assert(neweq == 0);
+ nMemories = 0;
+ eqnnzero(&EQs[neweq], nVars);
+ EQs[neweq].color = EQ_RED;
+ EQs[neweq].coef[0] = 1;
+ }
+ mayBeRed--;
+ return redFalse;
+ }
+
+ freeRedEliminations();
+
+ result = 0;
+ for (e = nGEQs - 1; e >= 0; e--) if (GEQs[e].color == EQ_RED) result = 1;
+ for (e = nEQs - 1; e >= 0; e--) if (EQs[e].color == EQ_RED) result = 1;
+ if (nMemories) result = 1;
+ if (!result) {
+ if (computeGist) {
+ nGEQs = 0;
+ nEQs = 0;
+ resurrectSubs();
+ nGEQs = 0;
+ nMemories = 0;
+ nEQs = 0;
+ }
+ mayBeRed--;
+ return noRed;
+ }
+
+ if (effort && (computeGist || !nMemories)) {
+ if (TRACE)
+ fprintf(outputFile, "*** Doing potentially expensive elimination tests for red equations [\n");
+ quickRedKill(computeGist);
+ checkGistInvariant();
+ result = nMemories;
+ for (e = nGEQs - 1; e >= 0; e--) if (GEQs[e].color == EQ_RED) result++;
+ for (e = nEQs - 1; e >= 0; e--) if (EQs[e].color == EQ_RED) result++;
+ if (result && effort > 1 && (computeGist || !nMemories)) {
+ expensiveRedKill();
+ result = nMemories;
+ for (e = nGEQs-1; e >= 0; e--) if (GEQs[e].color == EQ_RED) result++;
+ for (e = nEQs-1; e >= 0; e--) if (EQs[e].color == EQ_RED) result++;
+ }
+
+ if (!result) {
+ if (TRACE)
+ fprintf(outputFile, "]******************** Redudant Red Equations eliminated!!\n");
+ if (computeGist) {
+ nGEQs = 0;
+ nEQs = 0;
+ resurrectSubs();
+ nGEQs = 0;
+ nMemories = 0;
+ nEQs = 0;
+ }
+ mayBeRed--;
+ return noRed;
+ }
+
+ if (TRACE) fprintf(outputFile, "]******************** Red Equations remain\n");
+ if (DEBUG) printProblem();
+ }
+
+ if (computeGist) {
+ resurrectSubs();
+ cleanoutWildcards();
+
+
+ // Restore saved modular equations into EQs without affecting the problem
+ if (nEQs+nModularEQs > allocEQs) {
+ allocEQs = padEQs(allocEQs, nEQs+nModularEQs);
+ eqn *new_eqs = new eqn[allocEQs];
+ for (int e = 0; e < nEQs; e++)
+ eqnncpy(&(new_eqs[e]), &(EQs[e]), nVars);
+ delete[] EQs;
+ EQs= new_eqs;
+ }
+
+ for (int e = 0; e < nModularEQs; e++) {
+ eqnncpy(&(EQs[nEQs+e]), &(ModularEQs[e]), old_nVars);
+ EQs[nEQs+e].color = EQ_RED;
+ Tuple<coef_t> t(safeVars);
+ for (int i = 1; i <= safeVars; i++)
+ t[i] = ModularEQs[e].coef[var[i]];
+ for (int i = 1; i <= safeVars; i++)
+ EQs[nEQs+e].coef[i] = t[i];
+ }
+
+
+ // Now simplify modular equations using Chinese remainder theorem -- by chun 12/10/2006
+ for (int e = 0; e < nEQs; e++)
+ if (EQs[e].color == EQ_RED) {
+ int wild_pos = -1;
+ for (int i = safeVars+1; i <= nVars; i++)
+ if (EQs[e].coef[i] != 0) {
+ wild_pos = i;
+ break;
+ }
+
+ if (wild_pos == -1)
+ continue;
+
+ for (int e2 = e+1; e2 < nEQs+nModularEQs; e2++)
+ if (EQs[e2].color == EQ_RED) {
+ int wild_pos2 = -1;
+ for (int i = safeVars+1; i <= ((e2<nEQs)?nVars:old_nVars); i++)
+ if (EQs[e2].coef[i] != 0) {
+ wild_pos2 = i;
+ break;
+ }
+
+ if (wild_pos2 == -1)
+ continue;
+
+ coef_t g = gcd(abs(EQs[e].coef[wild_pos]), abs(EQs[e2].coef[wild_pos2]));
+ coef_t g2 = 1;
+ coef_t g3;
+ EQs[e].color = EQs[e2].color = EQ_BLACK;
+ while ((g3 = factor(g)) != 1) {
+ coef_t gg = g2 * g3;
+ g = g/g3;
+
+ bool match = true;
+ coef_t c = EQs[e].coef[0];
+ coef_t c2 = EQs[e2].coef[0];
+ bool change_sign = false;
+ for (int i = 1; i <= safeVars; i++) {
+ coef_t coef = int_mod_hat(EQs[e].coef[i], gg);
+ coef_t coef2 = int_mod_hat(EQs[e2].coef[i], gg);
+
+ if (coef == 0 && coef2 == 0)
+ continue;
+
+ if (change_sign && coef == -coef2)
+ continue;
+
+ if (!change_sign) {
+ if (coef == coef2)
+ continue;
+ else if (coef == -coef2) {
+ change_sign = true;
+ continue;
+ }
+ }
+
+ if (coef != 0) {
+ coef_t t = query_variable_mod(i, gg/gcd(abs(coef), gg), EQ_RED, nModularEQs, old_nVars);
+ if (t == posInfinity) {
+ match = false;
+ break;
+ }
+
+ c += coef * t;
+ }
+ if (coef2 != 0) {
+ coef_t t = query_variable_mod(i, gg/gcd(abs(coef2), gg), EQ_RED, nModularEQs, old_nVars);
+ if (t == posInfinity) {
+ match = false;
+ break;
+ }
+
+ c2 += coef2 * t;
+ }
+ }
+ if ((change_sign && int_mod_hat(c, gg) != -int_mod_hat(c2, gg)) ||
+ (!change_sign && int_mod_hat(c, gg) != int_mod_hat(c2, gg)))
+ match = false;
+
+ if (match)
+ g2 = gg;
+ }
+ EQs[e].color = EQs[e2].color = EQ_RED;
+
+ if (g2 == 1)
+ continue;
+
+ if (g2 == abs(EQs[e].coef[wild_pos])) {
+ EQs[e].color = EQ_BLACK;
+ break;
+ }
+ else if (e2 < nEQs && g2 == abs(EQs[e2].coef[wild_pos2]))
+ EQs[e2].color = EQ_BLACK;
+ else {
+ coef_t g4 = abs(EQs[e].coef[wild_pos])/g2;
+ while (lcm(g2, g4) != abs(EQs[e].coef[wild_pos])) {
+ assert(lcm(g2, g4) < abs(EQs[e].coef[wild_pos]));
+ g4 *= abs(EQs[e].coef[wild_pos])/lcm(g2, g4);
+ }
+
+ for (int i = 0; i <= safeVars; i++)
+ EQs[e].coef[i] = int_mod_hat(EQs[e].coef[i], g4);
+ EQs[e].coef[wild_pos] = (EQs[e].coef[wild_pos]>0?1:-1)*g4;
+ }
+ }
+ }
+
+ deleteBlack();
+ }
+
+ setExternals();
+ mayBeRed--;
+ assert(nMemories == 0);
+ return redConstraints;
+}
+
+
+void Problem::convertEQstoGEQs(bool excludeStrides) {
+ int i;
+ int e;
+ if (DBUG)
+ fprintf(outputFile, "Converting all EQs to GEQs\n");
+ simplifyProblem(0,0,0);
+ for(e=0;e<nEQs;e++) {
+ bool isStride = 0;
+ int e2 = newGEQ();
+ if (excludeStrides)
+ for(i = safeVars+1; i <= nVars; i++)
+ isStride = isStride || (EQs[e].coef[i] != 0);
+ if (isStride) continue;
+ eqnncpy(&GEQs[e2], &EQs[e], nVars);
+ GEQs[e2].touched = 1;
+ e2 = newGEQ();
+ eqnncpy(&GEQs[e2], &EQs[e], nVars);
+ GEQs[e2].touched = 1;
+ for (i = 0; i <= nVars; i++)
+ GEQs[e2].coef[i] = -GEQs[e2].coef[i];
+ }
+ // If we have eliminated all EQs, can set nEQs to 0
+ // If some strides are left, we don't know the position of them in the EQs
+ // array, so decreasing nEQs might remove wrong EQs -- we just leave them
+ // all in. (could sort the EQs to move strides to the front, but too hard.)
+ if (!excludeStrides) nEQs=0;
+ if (DBUG)
+ printProblem();
+}
+
+
+void Problem::convertEQtoGEQs(int eq) {
+ int i;
+ if (DBUG)
+ fprintf(outputFile, "Converting EQ %d to GEQs\n",eq);
+ int e2 = newGEQ();
+ eqnncpy(&GEQs[e2], &EQs[eq], nVars);
+ GEQs[e2].touched = 1;
+ e2 = newGEQ();
+ eqnncpy(&GEQs[e2], &EQs[eq], nVars);
+ GEQs[e2].touched = 1;
+ for (i = 0; i <= nVars; i++)
+ GEQs[e2].coef[i] = -GEQs[e2].coef[i];
+ if (DBUG)
+ printProblem();
+}
+
+
+/*
+ * Calculate value of variable modulo integer from problem's equation
+ * set plus additional saved modular equations embedded in the same
+ * EQs array (hinted by nModularEQs) if available. If there is no
+ * solution, return posInfinity.
+ */
+coef_t Problem::query_variable_mod(int v, coef_t factor, int color, int nModularEQs, int nModularVars) const {
+ if (safeVars < v)
+ return posInfinity;
+
+ Tuple<bool> working_on(safeVars);
+ for (int i = 1; i <= safeVars; i++)
+ working_on[i] = false;
+
+ return query_variable_mod(v, factor, color, nModularEQs, nModularVars, working_on);
+}
+
+coef_t Problem::query_variable_mod(int v, coef_t factor, int color, int nModularEQs, int nModularVars, Tuple<bool> &working_on) const {
+ working_on[v] = true;
+
+ for (int e = 0; e < nEQs+nModularEQs; e++)
+ if (EQs[e].color == color) {
+ coef_t coef = int_mod_hat(EQs[e].coef[v], factor);
+ if (abs(coef) != 1)
+ continue;
+
+ bool wild_factored = true;
+ for (int i = safeVars+1; i <= ((e<nEQs)?nVars:nModularVars); i++)
+ if (int_mod_hat(EQs[e].coef[i], factor) != 0) {
+ wild_factored = false;
+ break;
+ }
+ if (!wild_factored)
+ continue;
+
+ coef_t result = 0;
+ for (int i = 1; i <= safeVars; i++)
+ if (i != v) {
+ coef_t p = int_mod_hat(EQs[e].coef[i], factor);
+
+ if (p == 0)
+ continue;
+
+ if (working_on[i] == true) {
+ result = posInfinity;
+ break;
+ }
+
+ coef_t q = query_variable_mod(i, factor, color, nModularEQs, nModularVars, working_on);
+ if (q == posInfinity) {
+ result = posInfinity;
+ break;
+ }
+ result += p*q;
+ }
+
+ if (result != posInfinity) {
+ result += EQs[e].coef[0];
+ if (coef == 1)
+ result = -result;
+ working_on[v] = false;
+
+ return int_mod_hat(result, factor);
+ }
+ }
+
+ working_on[v] = false;
+ return posInfinity;
+}
+
+
+
+#ifdef GIST_CHECK
+enum compareAnswer {apparentlyEqual, mightNotBeEqual, NotEqual};
+
+static compareAnswer checkEquiv(Problem *p1, Problem *p2) {
+ int r1,r2;
+
+ p1->check();
+ p2->check();
+ p1->resurrectSubs();
+ p2->resurrectSubs();
+ p1->check();
+ p2->check();
+ p1->putVariablesInStandardOrder();
+ p2->putVariablesInStandardOrder();
+ p1->check();
+ p2->check();
+ p1->ordered_elimination(0);
+ p2->ordered_elimination(0);
+ p1->check();
+ p2->check();
+ r1 = p1->simplifyProblem(1,1,0);
+ r2 = p2->simplifyProblem(1,1,0);
+ p1->check();
+ p2->check();
+
+ if (!r1 || !r2) {
+ if (r1 == r2) return apparentlyEqual;
+ return NotEqual;
+ }
+ if (p1->nVars != p2->nVars
+ || p1->nGEQs != p2->nGEQs
+ || p1->nSUBs != p2->nSUBs
+ || p1->checkSum() != p2->checkSum()) {
+ r1 = p1->simplifyProblem(0,1,1);
+ r2 = p2->simplifyProblem(0,1,1);
+ assert(r1 && r2);
+ p1->check();
+ p2->check();
+ if (p1->nVars != p2->nVars
+ || p1->nGEQs != p2->nGEQs
+ || p1->nSUBs != p2->nSUBs
+ || p1->checkSum() != p2->checkSum()) {
+ r1 = p1->simplifyProblem(0,1,2);
+ r2 = p2->simplifyProblem(0,1,2);
+ p1->check();
+ p2->check();
+ assert(r1 && r2);
+ if (p1->nVars != p2->nVars
+ || p1->nGEQs != p2->nGEQs
+ || p1->nSUBs != p2->nSUBs
+ || p1->checkSum() != p2->checkSum()) {
+ p1->check();
+ p2->check();
+ p1->resurrectSubs();
+ p2->resurrectSubs();
+ p1->check();
+ p2->check();
+ p1->putVariablesInStandardOrder();
+ p2->putVariablesInStandardOrder();
+ p1->check();
+ p2->check();
+ p1->ordered_elimination(0);
+ p2->ordered_elimination(0);
+ p1->check();
+ p2->check();
+ r1 = p1->simplifyProblem(1,1,0);
+ r2 = p2->simplifyProblem(1,1,0);
+ p1->check();
+ p2->check();
+ }
+ }
+ }
+
+ if (p1->nVars != p2->nVars
+ || p1->nSUBs != p2->nSUBs
+ || p1->nGEQs != p2->nGEQs
+ || p1->nSUBs != p2->nSUBs) return NotEqual;
+ if (p1->checkSum() != p2->checkSum()) return mightNotBeEqual;
+ return apparentlyEqual;
+}
+#endif
+
+void Problem::checkGistInvariant() const {
+#ifdef GIST_CHECK
+ Problem new_answer;
+ int r;
+
+ check();
+ fullAnswer.check();
+ context.check();
+
+ if (safeVars < nVars) {
+ if (DBUG) {
+ fprintf(outputFile,"Can't check gist invariant due to wildcards\n");
+ printProblem();
+ }
+ return;
+ }
+ if (DBUG) {
+ fprintf(outputFile,"Checking gist invariant on: [\n");
+ printProblem();
+ }
+
+ new_answer = *this;
+ new_answer->resurrectSubs();
+ new_answer->cleanoutWildcards();
+ if (DEBUG) {
+ fprintf(outputFile,"which is: \n");
+ printProblem();
+ }
+ deleteBlack(&new_answer);
+ turnRedBlack(&new_answer);
+ if (DEBUG) {
+ fprintf(outputFile,"Black version of answer: \n");
+ printProblem(&new_answer);
+ }
+ problem_merge(&new_answer,&context);
+
+ r = checkEquiv(&full_answer,&new_answer);
+ if (r != apparentlyEqual) {
+ fprintf(outputFile,"GIST INVARIANT REQUIRES MANUAL CHECK:[\n");
+ fprintf(outputFile,"Original problem:\n");
+ printProblem(&redProblem);
+
+ fprintf(outputFile,"Context:\n");
+ printProblem(&context);
+
+ fprintf(outputFile,"Computed gist:\n");
+ printProblem();
+
+ fprintf(outputFile,"Combined answer:\n");
+ printProblem(&full_answer);
+
+ fprintf(outputFile,"Context && red constraints:\n");
+ printProblem(&new_answer);
+ fprintf(outputFile,"]\n");
+ }
+
+ if (DBUG) {
+ fprintf(outputFile,"] Done checking gist invariant on\n");
+ }
+#endif
+}
+
+} // namespace
diff --git a/omegalib/omega/src/omega_core/oc_eq.cc b/omegalib/omega/src/omega_core/oc_eq.cc
new file mode 100644
index 0000000..dc595ea
--- /dev/null
+++ b/omegalib/omega/src/omega_core/oc_eq.cc
@@ -0,0 +1,653 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 the Omega Project Team
+ Copyright (C) 2005-2011 Chun Chen
+ All Rights Reserved.
+
+ Purpose:
+ Solve equalities.
+
+ Notes:
+
+ History:
+ *****************************************************************************/
+
+#include <omega/omega_core/oc_i.h>
+
+namespace omega {
+
+void Problem::simplifyStrideConstraints() {
+ int e, e2, i;
+ if (DBUG)
+ fprintf(outputFile, "Checking for stride constraints\n");
+ for (i = safeVars + 1; i <= nVars; i++) {
+ if (DBUG)
+ fprintf(outputFile, "checking %s\n", variable(i));
+ for (e = 0; e < nGEQs; e++)
+ if (GEQs[e].coef[i])
+ break;
+ if (e >= nGEQs) {
+ if (DBUG)
+ fprintf(outputFile, "%s passed GEQ test\n", variable(i));
+ e2 = -1;
+ for (e = 0; e < nEQs; e++)
+ if (EQs[e].coef[i]) {
+ if (e2 == -1)
+ e2 = e;
+ else {
+ e2 = -1;
+ break;
+ }
+ }
+ if (e2 >= 0) {
+ if (DBUG) {
+ fprintf(outputFile, "Found stride constraint: ");
+ printEQ(&EQs[e2]);
+ fprintf(outputFile, "\n");
+ }
+ /* Is a stride constraint */
+ coef_t g = abs(EQs[e2].coef[i]);
+ assert(g>0);
+ int j;
+ for (j = 0; j <= nVars; j++)
+ if (i != j)
+ EQs[e2].coef[j] = int_mod_hat(EQs[e2].coef[j], g);
+ }
+ }
+ }
+}
+
+void Problem::doMod(coef_t factor, int e, int j) {
+ /* Solve e = factor alpha for x_j and substitute */
+ int k;
+ eqn eq;
+ coef_t nFactor;
+
+ int alpha;
+
+ // if (j > safeVars) alpha = j;
+ // else
+ if (EQs[e].color) {
+ rememberRedConstraint(&EQs[e], redEQ, 0);
+ EQs[e].color = EQ_BLACK;
+ }
+ alpha = addNewUnprotectedWildcard();
+ eqnncpy(&eq, &EQs[e], nVars);
+ newVar = alpha;
+
+ if (DEBUG) {
+ fprintf(outputFile, "doing moding: ");
+ fprintf(outputFile, "Solve ");
+ printTerm(&eq, 1);
+ fprintf(outputFile, " = " coef_fmt " %s for %s and substitute\n",
+ factor, variable(alpha), variable(j));
+ }
+ for (k = nVars; k >= 0; k--)
+ eq.coef[k] = int_mod_hat(eq.coef[k], factor);
+ nFactor = eq.coef[j];
+ assert(nFactor == 1 || nFactor == -1);
+ eq.coef[alpha] = factor / nFactor;
+ if (DEBUG) {
+ fprintf(outputFile, "adjusted: ");
+ fprintf(outputFile, "Solve ");
+ printTerm(&eq, 1);
+ fprintf(outputFile, " = 0 for %s and substitute\n", variable(j));
+ }
+
+ eq.coef[j] = 0;
+ substitute(&eq, j, nFactor);
+ newVar = -1;
+ deleteVariable(j);
+ for (k = nVars; k >= 0; k--) {
+ assert(EQs[e].coef[k] % factor == 0);
+ EQs[e].coef[k] = EQs[e].coef[k] / factor;
+ }
+ if (DEBUG) {
+ fprintf(outputFile, "Mod-ing and normalizing produces:\n");
+ printProblem();
+ }
+}
+
+void Problem::substitute(eqn *sub, int i, coef_t c) {
+ int e, j;
+ coef_t k;
+ int recordSubstitution = (i <= safeVars && var[i] >= 0);
+
+ redType clr;
+ if (sub->color)
+ clr = redEQ;
+ else
+ clr = notRed;
+
+ assert(c == 1 || c == -1);
+
+ if (DBUG || doTrace) {
+ if (sub->color)
+ fprintf(outputFile, "RED SUBSTITUTION\n");
+ fprintf(outputFile, "substituting using %s := ", variable(i));
+ printTerm(sub, -c);
+ fprintf(outputFile, "\n");
+ printVars();
+ }
+#ifndef NDEBUG
+ if (i > safeVars && clr) {
+ bool unsafeSub = false;
+ for (e = nEQs - 1; e >= 0; e--)
+ if (!(EQs[e].color || !EQs[e].coef[i]))
+ unsafeSub = true;
+ for (e = nGEQs - 1; e >= 0; e--)
+ if (!(GEQs[e].color || !GEQs[e].coef[i]))
+ unsafeSub = true;
+ for (e = nSUBs - 1; e >= 0; e--)
+ if (SUBs[e].coef[i])
+ unsafeSub = true;
+ if (unsafeSub) {
+ fprintf(outputFile, "UNSAFE RED SUBSTITUTION\n");
+ fprintf(outputFile, "substituting using %s := ", variable(i));
+ printTerm(sub, -c);
+ fprintf(outputFile, "\n");
+ printProblem();
+ assert(0 && "UNSAFE RED SUBSTITUTION");
+ }
+ }
+#endif
+
+ for (e = nEQs - 1; e >= 0; e--) {
+ eqn *eq;
+ eq = &(EQs[e]);
+ k = eq->coef[i];
+ if (k != 0) {
+ k = check_mul(k, c); // Should be k = k/c, but same effect since abs(c) == 1
+ eq->coef[i] = 0;
+ for (j = nVars; j >= 0; j--) {
+ eq->coef[j] -= check_mul(sub->coef[j], k);
+ }
+ }
+ if (DEBUG) {
+ printEQ(eq);
+ fprintf(outputFile, "\n");
+ }
+ }
+ for (e = nGEQs - 1; e >= 0; e--) {
+ int zero;
+ eqn *eq;
+ eq = &(GEQs[e]);
+ k = eq->coef[i];
+ if (k != 0) {
+ k = check_mul(k, c); // Should be k = k/c, but same effect since abs(c) == 1
+ eq->touched = true;
+ eq->coef[i] = 0;
+ zero = 1;
+ for (j = nVars; j >= 0; j--) {
+ eq->coef[j] -= check_mul(sub->coef[j], k);
+ if (j > 0 && eq->coef[j])
+ zero = 0;
+ }
+ if (zero && clr != notRed && !eq->color) {
+ coef_t z = int_div(eq->coef[0], abs(k));
+ if (DBUG || doTrace) {
+ fprintf(outputFile,
+ "Black inequality matches red substitution\n");
+ if (z < 0)
+ fprintf(outputFile, "System is infeasible\n");
+ else if (z > 0)
+ fprintf(outputFile, "Black inequality is redundant\n");
+ else {
+ fprintf(outputFile,
+ "Black constraint partially implies red equality\n");
+ if (k < 0) {
+ fprintf(outputFile, "Black constraints tell us ");
+ assert(sub->coef[i] == 0);
+ sub->coef[i] = c;
+ printTerm(sub, 1);
+ sub->coef[i] = 0;
+ fprintf(outputFile, "<= 0\n");
+ } else {
+ fprintf(outputFile, "Black constraints tell us ");
+ assert(sub->coef[i] == 0);
+ sub->coef[i] = c;
+ printTerm(sub, 1);
+ sub->coef[i] = 0;
+ fprintf(outputFile, " >= 0\n");
+ }
+ }
+ }
+ if (z == 0) {
+ if (k < 0) {
+ if (clr == redEQ)
+ clr = redGEQ;
+ else if (clr == redLEQ)
+ clr = notRed;
+ } else {
+ if (clr == redEQ)
+ clr = redLEQ;
+ else if (clr == redGEQ)
+ clr = notRed;
+ }
+ }
+
+ }
+ }
+ if (DEBUG) {
+ printGEQ(eq);
+ fprintf(outputFile, "\n");
+ }
+ }
+ if (i <= safeVars && clr) {
+ assert(sub->coef[i] == 0);
+ sub->coef[i] = c;
+ rememberRedConstraint(sub, clr, 0);
+ sub->coef[i] = 0;
+ }
+
+ if (recordSubstitution) {
+ int s = nSUBs++;
+ int kk;
+ eqn *eq = &(SUBs[s]);
+ for (kk = nVars; kk >= 0; kk--)
+ eq->coef[kk] = check_mul(-c, (sub->coef[kk]));
+ eq->key = var[i];
+ if (DEBUG) {
+ fprintf(outputFile, "Recording substition as: ");
+ printSubstitution(s);
+ fprintf(outputFile, "\n");
+ }
+ }
+ if (DEBUG) {
+ fprintf(outputFile, "Ready to update subs\n");
+ if (sub->color)
+ fprintf(outputFile, "RED SUBSTITUTION\n");
+ fprintf(outputFile, "substituting using %s := ", variable(i));
+ printTerm(sub, -c);
+ fprintf(outputFile, "\n");
+ printVars();
+ }
+
+ for (e = nSUBs - 1; e >= 0; e--) {
+ eqn *eq = &(SUBs[e]);
+ k = eq->coef[i];
+ if (k != 0) {
+ k = check_mul(k, c); // Should be k = k/c, but same effect since abs(c) == 1
+ eq->coef[i] = 0;
+ for (j = nVars; j >= 0; j--) {
+ eq->coef[j] -= check_mul(sub->coef[j], k);
+ }
+ }
+ if (DEBUG) {
+ fprintf(outputFile, "updated sub (" coef_fmt "): ", c);
+ printSubstitution(e);
+ fprintf(outputFile, "\n");
+ }
+ }
+
+ if (DEBUG) {
+ fprintf(outputFile, "---\n\n");
+ printProblem();
+ fprintf(outputFile, "===\n\n");
+ }
+}
+
+
+void Problem::doElimination(int e, int i) {
+ if (DBUG || doTrace)
+ fprintf(outputFile, "eliminating variable %s\n", variable(i));
+
+ eqn sub;
+ eqnncpy(&sub, &EQs[e], nVars);
+ coef_t c = sub.coef[i];
+ sub.coef[i] = 0;
+
+ if (c == 1 || c == -1) {
+ substitute(&sub, i, c);
+ } else {
+ coef_t a = abs(c);
+ if (TRACE)
+ fprintf(outputFile,
+ "performing non-exact elimination, c = " coef_fmt "\n", c);
+ if (DBUG)
+ printProblem();
+ assert(inApproximateMode);
+
+ for (int e2 = nEQs - 1; e2 >= 0; e2--) {
+ eqn *eq = &(EQs[e2]);
+ coef_t k = eq->coef[i];
+ if (k != 0) {
+ coef_t l = lcm(abs(k), a);
+ coef_t scale1 = l / abs(k);
+ for (int j = nVars; j >= 0; j--)
+ eq->coef[j] = check_mul(eq->coef[j], scale1);
+ eq->coef[i] = 0;
+ coef_t scale2 = l / c;
+ if (k < 0)
+ scale2 = -scale2;
+ for (int j = nVars; j >= 0; j--)
+ eq->coef[j] -= check_mul(sub.coef[j], scale2);
+ eq->color |= sub.color;
+ }
+ }
+ for (int e2 = nGEQs - 1; e2 >= 0; e2--) {
+ eqn *eq = &(GEQs[e2]);
+ coef_t k = eq->coef[i];
+ if (k != 0) {
+ coef_t l = lcm(abs(k), a);
+ coef_t scale1 = l / abs(k);
+ for (int j = nVars; j >= 0; j--)
+ eq->coef[j] = check_mul(eq->coef[j], scale1);
+ eq->coef[i] = 0;
+ coef_t scale2 = l / c;
+ if (k < 0)
+ scale2 = -scale2;
+ for (int j = nVars; j >= 0; j--)
+ eq->coef[j] -= check_mul(sub.coef[j], scale2);
+ eq->color |= sub.color;
+ eq->touched = 1;
+ }
+ }
+ for (int e2 = nSUBs - 1; e2 >= 0; e2--)
+ if (SUBs[e2].coef[i]) {
+ eqn *eq = &(EQs[e2]);
+ assert(0);
+ // We can't handle this since we can't multiply
+ // the coefficient of the left-hand side
+ assert(!sub.color);
+ for (int j = nVars; j >= 0; j--)
+ eq->coef[j] = check_mul(eq->coef[j], a);
+ coef_t k = eq->coef[i];
+ eq->coef[i] = 0;
+ for (int j = nVars; j >= 0; j--)
+ eq->coef[j] -= check_mul(sub.coef[j], k / c);
+ }
+ }
+ deleteVariable(i);
+}
+
+int Problem::solveEQ() {
+ check();
+
+ // Reorder equations according to complexity.
+ {
+ int delay[nEQs];
+
+ for (int e = 0; e < nEQs; e++) {
+ delay[e] = 0;
+ if (EQs[e].color)
+ delay[e] += 8;
+ int nonunitWildCards = 0;
+ int unitWildCards = 0;
+ for (int i = nVars; i > safeVars; i--)
+ if (EQs[e].coef[i]) {
+ if (EQs[e].coef[i] == 1 || EQs[e].coef[i] == -1)
+ unitWildCards++;
+ else
+ nonunitWildCards++;
+ }
+ int unit = 0;
+ int nonUnit = 0;
+ for (int i = safeVars; i > 0; i--)
+ if (EQs[e].coef[i]) {
+ if (EQs[e].coef[i] == 1 || EQs[e].coef[i] == -1)
+ unit++;
+ else
+ nonUnit++;
+ }
+ if (unitWildCards == 1 && nonunitWildCards == 0)
+ delay[e] += 0;
+ else if (unitWildCards >= 1 && nonunitWildCards == 0)
+ delay[e] += 1;
+ else if (inApproximateMode && nonunitWildCards > 0)
+ delay[e] += 2;
+ else if (unit == 1 && nonUnit == 0 && nonunitWildCards == 0)
+ delay[e] += 3;
+ else if (unit > 1 && nonUnit == 0 && nonunitWildCards == 0)
+ delay[e] += 4;
+ else if (unit >= 1 && nonunitWildCards <= 1)
+ delay[e] += 5;
+ else
+ delay[e] += 6;
+ }
+
+ for (int e = 0; e < nEQs; e++) {
+ int e2, slowest;
+ slowest = e;
+ for (e2 = e + 1; e2 < nEQs; e2++)
+ if (delay[e2] > delay[slowest])
+ slowest = e2;
+ if (slowest != e) {
+ int tmp = delay[slowest];
+ delay[slowest] = delay[e];
+ delay[e] = tmp;
+ eqn eq;
+ eqnncpy(&eq, &EQs[slowest], nVars);
+ eqnncpy(&EQs[slowest], &EQs[e], nVars);
+ eqnncpy(&EQs[e], &eq, nVars);
+ }
+ }
+ }
+
+ // Eliminate all equations.
+ while (nEQs != 0) {
+ int e = nEQs - 1;
+ eqn *eq = &(EQs[e]);
+ coef_t g, g2;
+
+ assert(mayBeRed || !eq->color);
+
+ check();
+
+ // get gcd of coefficients of all unprotected variables
+ g2 = 0;
+ for (int i = nVars; i > safeVars; i--)
+ if (eq->coef[i] != 0) {
+ g2 = gcd(abs(eq->coef[i]), g2);
+ if (g2 == 1)
+ break;
+ }
+
+ // get gcd of coefficients of all variables
+ g = g2;
+ if (g != 1)
+ for (int i = safeVars; i >= 1; i--)
+ if (eq->coef[i] != 0) {
+ g = gcd(abs(eq->coef[i]), g);
+ if (g == 1)
+ break;
+ }
+
+ // approximate mode bypass integer modular test; in Farkas(),
+ // existential variable lambda's are rational numbers.
+ if (inApproximateMode && g2 != 0)
+ g = gcd(abs(eq->coef[0]), g);
+
+ // simple test to see if the equation is satisfiable
+ if (g == 0) {
+ if (eq->coef[0] != 0) {
+ return (false);
+ } else {
+ nEQs--;
+ continue;
+ }
+ } else if (abs(eq->coef[0]) % g != 0) {
+ return (false);
+ }
+
+ // set gcd of all coefficients to 1
+ if (g != 1) {
+ for (int i = nVars; i >= 0; i--)
+ eq->coef[i] /= g;
+ g2 = g2 / g;
+ }
+
+ // exact elimination of unit coefficient variable
+ if (g2 != 0) { // for constraint with unprotected variable
+ int i;
+ for (i = nVars; i > safeVars; i--)
+ if (abs(eq->coef[i]) == 1)
+ break;
+ if (i > safeVars) {
+ nEQs--;
+ doElimination(e, i);
+ continue;
+ }
+ } else { // for constraint without unprotected variable
+
+ // pick the unit coefficient variable with complex inequalites
+ // to eliminate, this will make inequalities tighter. e.g.
+ // {[t4,t6,t10]:exists (alpha: 0<=t6<=3 && t10=4alpha+t6 &&
+ // 64t4<=t10<=64t4+15)}
+ int unit_var;
+ int cost = -1;
+
+ for (int i = safeVars; i > 0; i--)
+
+ if (abs(eq->coef[i]) == 1) {
+ int cur_cost = 0;
+ for (int j = 0; j < nGEQs; j++)
+ if (GEQs[j].coef[i] != 0) {
+ for (int k = safeVars; k > 0; k--)
+ if (GEQs[j].coef[k] != 0) {
+ if (abs(GEQs[j].coef[k]) != 1){
+
+ cur_cost += 3;
+
+ }
+ else
+ cur_cost += 1;
+ }
+ }
+
+ if (cur_cost > cost) {
+ cost = cur_cost;
+ unit_var = i;
+ }
+
+ }
+
+ if (cost != -1) {
+ nEQs--;
+ doElimination(e, unit_var);
+ continue;
+ }
+
+
+ }
+
+ // check if there is an unprotected variable as wildcard
+ if (g2 > 0) {
+ int pos = 0;
+ coef_t g3;
+ for (int k = nVars; k > safeVars; k--)
+ if (eq->coef[k] != 0) {
+ int e2;
+ for (e2 = e - 1; e2 >= 0; e2--)
+ if (EQs[e2].coef[k])
+ break;
+ if (e2 >= 0)
+ continue;
+ for (e2 = nGEQs - 1; e2 >= 0; e2--)
+ if (GEQs[e2].coef[k])
+ break;
+ if (e2 >= 0)
+ continue;
+ for (e2 = nSUBs - 1; e2 >= 0; e2--)
+ if (SUBs[e2].coef[k])
+ break;
+ if (e2 >= 0)
+ continue;
+
+ if (pos == 0) {
+ g3 = abs(eq->coef[k]);
+ pos = k;
+ } else {
+ if (abs(eq->coef[k]) < g3) {
+ g3 = abs(eq->coef[k]);
+ pos = k;
+ }
+ }
+ }
+
+ if (pos != 0) {
+ bool change = false;
+ for (int k2 = nVars; k2 >= 0; k2--)
+ if (k2 != pos && eq->coef[k2] != 0) {
+ coef_t t = int_mod_hat(eq->coef[k2], g3);
+ if (t != eq->coef[k2]) {
+ eq->coef[k2] = t;
+ change = true;
+ }
+ }
+
+ // strength reduced, try this equation again
+ if (change) {
+ // nameWildcard(pos);
+ continue;
+ }
+ }
+ }
+
+ // insert new stride constraint
+ if (g2 > 1 && !(inApproximateMode && !inStridesAllowedMode)) {
+ int newvar = addNewProtectedWildcard();
+ int neweq = newEQ();
+ assert(neweq == e+1);
+ // we were working on highest-numbered EQ
+ eqnnzero(&EQs[neweq], nVars);
+ eqnncpy(&EQs[neweq], eq, safeVars);
+
+ for (int k = nVars; k >= 0; k--) {
+ EQs[neweq].coef[k] = int_mod_hat(EQs[neweq].coef[k], g2);
+ }
+ if (EQs[e].color)
+ rememberRedConstraint(&EQs[neweq], redStride, g2);
+ EQs[neweq].coef[newvar] = g2;
+ EQs[neweq].color = EQ_BLACK;
+ continue;
+ }
+
+ // inexact elimination of unprotected variable
+ if (g2 > 0 && inApproximateMode) {
+ int pos = 0;
+ for (int k = nVars; k > safeVars; k--)
+ if (eq->coef[k] != 0) {
+ pos = k;
+ break;
+ }
+ assert(pos > safeVars);
+
+ // special handling for wildcard used in breaking down
+ // diophantine equation
+ if (abs(eq->coef[pos]) > 1) {
+ int e2;
+ for (e2 = nSUBs - 1; e2 >= 0; e2--)
+ if (SUBs[e2].coef[pos])
+ break;
+ if (e2 >= 0) {
+ protectWildcard(pos);
+ continue;
+ }
+ }
+
+ nEQs--;
+ doElimination(e, pos);
+ continue;
+ }
+
+ // now solve linear diophantine equation using least remainder
+ // algorithm
+ {
+ coef_t factor = (posInfinity); // was MAXINT
+ int pos = 0;
+ for (int k = nVars; k > (g2 > 0 ? safeVars : 0); k--)
+ if (eq->coef[k] != 0 && factor > abs(eq->coef[k]) + 1) {
+ factor = abs(eq->coef[k]) + 1;
+ pos = k;
+ }
+ assert(pos > (g2>0?safeVars:0));
+ doMod(factor, e, pos);
+ continue;
+ }
+ }
+
+ assert(nEQs == 0);
+ return (OC_SOLVE_UNKNOWN);
+}
+
+} // namespace
diff --git a/omegalib/omega/src/omega_core/oc_exp_kill.cc b/omegalib/omega/src/omega_core/oc_exp_kill.cc
new file mode 100644
index 0000000..fdb2718
--- /dev/null
+++ b/omegalib/omega/src/omega_core/oc_exp_kill.cc
@@ -0,0 +1,297 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 the Omega Project Team
+ Copyright (C) 2005-2011 Chun Chen
+ All Rights Reserved.
+
+ Purpose:
+ Expensive inequality elimination.
+
+ Notes:
+
+ History:
+ 03/31/09 Use BoolSet, Chun Chen
+*****************************************************************************/
+
+#include <omega/omega_core/oc_i.h>
+#include <basic/BoolSet.h>
+#include <vector>
+
+namespace omega {
+
+int Problem::expensiveKill() {
+ int e;
+ if (TRACE) fprintf(outputFile,"Performing expensive kill tests: [\n");
+ if (DBUG) printProblem();
+ Problem tmpProblem;
+ int oldTrace = trace;
+ int constraintsRemoved = 0;
+
+ trace = 0;
+ conservative++;
+
+ for (e = nGEQs - 1; e >= 0; e--)
+ if (!GEQs[e].essential) {
+ if (DBUG) {
+ fprintf(outputFile, "checking equation %d to see if it is redundant: ", e);
+ printGEQ(&(GEQs[e]));
+ fprintf(outputFile, "\n");
+ }
+ tmpProblem = *this;
+ tmpProblem.negateGEQ(e);
+ tmpProblem.varsOfInterest = 0;
+ tmpProblem.nSUBs = 0;
+ tmpProblem.nMemories = 0;
+ tmpProblem.safeVars = 0;
+ tmpProblem.variablesFreed = 0;
+ tmpProblem.isTemporary = true;
+
+ if (!tmpProblem.solve(false)) {
+ if (DBUG)
+ fprintf(outputFile, "redundant!\n");
+ constraintsRemoved++;
+ deleteGEQ(e);
+ }
+ }
+
+ if (constraintsRemoved) {
+ if (TRACE) fprintf(outputFile,"%d Constraints removed!!\n",constraintsRemoved);
+ }
+
+ trace = oldTrace;
+ conservative--;
+ if (TRACE) fprintf(outputFile,"] expensive kill tests done\n");
+ return 1;
+}
+
+int Problem::expensiveRedKill() {
+ int e;
+ if (TRACE) fprintf(outputFile,"Performing expensive red kill tests: [\n");
+ Problem tmpProblem;
+ int oldTrace = trace;
+ int constraintsRemoved = 0;
+
+ trace = 0;
+ conservative++;
+
+ for (e = nGEQs - 1; e >= 0; e--)
+ if (!GEQs[e].essential && GEQs[e].color) {
+ if (DEBUG) {
+ fprintf(outputFile, "checking equation %d to see if it is redundant: ", e);
+ printGEQ(&(GEQs[e]));
+ fprintf(outputFile, "\n");
+ }
+ tmpProblem = *this;
+ tmpProblem.negateGEQ(e);
+ tmpProblem.varsOfInterest = 0;
+ tmpProblem.nSUBs = 0;
+ tmpProblem.nMemories = 0;
+ tmpProblem.safeVars = 0;
+ tmpProblem.variablesFreed = 0;
+ tmpProblem.isTemporary = true;
+ tmpProblem.turnRedBlack();
+ if (!tmpProblem.solve(false)) {
+ constraintsRemoved++;
+ deleteGEQ(e);
+ }
+ }
+
+ if (constraintsRemoved) {
+ if (TRACE) fprintf(outputFile,"%d Constraints removed!!\n",constraintsRemoved);
+ }
+
+ trace = oldTrace;
+ conservative--;
+ if (TRACE) fprintf(outputFile,"] expensive red kill tests done\n");
+ return 1;
+}
+
+
+int Problem::expensiveEqualityCheck() {
+ int e;
+ return 1;
+ if (TRACE) fprintf(outputFile,"Performing expensive equality tests: [\n");
+ Problem tmpProblem;
+ int oldTrace = trace;
+ int equalitiesFound = 0;
+
+ trace = 0;
+ conservative++;
+
+ for (e = nGEQs - 1; e >= 0; e--) {
+ if (DEBUG) {
+ fprintf(outputFile, "checking equation %d to see if it is an equality: ", e);
+ printGEQ(&(GEQs[e]));
+ fprintf(outputFile, "\n");
+ }
+ tmpProblem = *this;
+ tmpProblem.GEQs[e].coef[0]--;
+ tmpProblem.varsOfInterest = 0;
+ tmpProblem.nSUBs = 0;
+ tmpProblem.nMemories = 0;
+ tmpProblem.safeVars = 0;
+ tmpProblem.variablesFreed = 0;
+ tmpProblem.isTemporary = true;
+ if (!tmpProblem.solve(false)) {
+ int neweq = newEQ();
+ eqnncpy(&EQs[neweq], &GEQs[e], nVars);
+ equalitiesFound++;
+ addingEqualityConstraint(neweq);
+ }
+ }
+ if (equalitiesFound) {
+ if (TRACE) fprintf(outputFile,"%d Equalities found!!\n",equalitiesFound);
+ }
+
+ trace = oldTrace;
+ conservative--;
+ if (equalitiesFound) {
+ if (!solveEQ()) return 0;
+ if (!normalize()) return 0;
+ }
+ if (TRACE) fprintf(outputFile,"] expensive equality tests done\n");
+ return 1;
+}
+
+
+void Problem::quickRedKill(int computeGist) {
+ if (DBUG) {
+ fprintf(outputFile, "in quickRedKill: [\n");
+ printProblem();
+ }
+
+ noteEssential(0);
+ int moreToDo = chainKill(1,0);
+
+#ifdef NDEBUG
+ if (!moreToDo) {
+ if (DBUG) fprintf(outputFile, "] quickRedKill\n");
+ return;
+ }
+#endif
+
+ int isDead[nGEQs];
+ int deadCount = 0;
+ std::vector<BoolSet<> > P(nGEQs, BoolSet<>(nVars)), Z(nGEQs, BoolSet<>(nVars)), N(nGEQs, BoolSet<>(nVars));
+ BoolSet<> PP, PZ, PN; /* possible Positives, possible zeros & possible negatives */
+ BoolSet<> MZ; /* must zeros */
+
+ int equationsToKill = 0;
+ for (int e = nGEQs - 1; e >= 0; e--) {
+ isDead[e] = 0;
+ if (GEQs[e].color && !GEQs[e].essential) equationsToKill++;
+ if (GEQs[e].color && GEQs[e].essential && !computeGist)
+ if (!moreToDo) {
+ if (DBUG) fprintf(outputFile, "] quickRedKill\n");
+ return;
+ }
+ for (int i = nVars; i >= 1; i--) {
+ if (GEQs[e].coef[i] > 0)
+ P[e].set(i-1);
+ else if (GEQs[e].coef[i] < 0)
+ N[e].set(i-1);
+ else
+ Z[e].set(i-1);
+ }
+ }
+
+ if (!equationsToKill)
+ if (!moreToDo) {
+ if (DBUG) fprintf(outputFile, "] quickRedKill\n");
+ return;
+ }
+
+ for (int e = nGEQs - 1; e > 0; e--)
+ if (!isDead[e])
+ for (int e2 = e - 1; e2 >= 0; e2--)
+ if (!isDead[e2]) {
+ coef_t a = 0;
+ int i, j;
+ for (i = nVars; i > 1; i--) {
+ for (j = i - 1; j > 0; j--) {
+ a = (GEQs[e].coef[i] * GEQs[e2].coef[j] - GEQs[e2].coef[i] * GEQs[e].coef[j]);
+ if (a != 0)
+ goto foundPair;
+ }
+ }
+ continue;
+
+ foundPair:
+ if (DEBUG) {
+ fprintf(outputFile, "found two equations to combine, i = %s, ", variable(i));
+ fprintf(outputFile, "j = %s, alpha = " coef_fmt "\n", variable(j), a);
+ printGEQ(&(GEQs[e]));
+ fprintf(outputFile, "\n");
+ printGEQ(&(GEQs[e2]));
+ fprintf(outputFile, "\n");
+ }
+
+ MZ = (Z[e] & Z[e2]);
+ PZ = MZ | (P[e] & N[e2]) | (N[e] & P[e2]);
+ PP = P[e] | P[e2];
+ PN = N[e] | N[e2];
+
+ for (int e3 = nGEQs - 1; e3 >= 0; e3--)
+ if (e3 != e && e3 != e2 && GEQs[e3].color && !GEQs[e3].essential) {
+ coef_t alpha1, alpha2, alpha3;
+
+ if (!PZ.imply(Z[e3]) || MZ.imply(~Z[e3])) continue;
+ if (!PP.imply(P[e3]) || !PN.imply(N[e3])) continue;
+
+ if (a > 0) {
+ alpha1 = GEQs[e2].coef[j] * GEQs[e3].coef[i] - GEQs[e2].coef[i] * GEQs[e3].coef[j];
+ alpha2 = -(GEQs[e].coef[j] * GEQs[e3].coef[i] - GEQs[e].coef[i] * GEQs[e3].coef[j]);
+ alpha3 = a;
+ }
+ else {
+ alpha1 = -(GEQs[e2].coef[j] * GEQs[e3].coef[i] - GEQs[e2].coef[i] * GEQs[e3].coef[j]);
+ alpha2 = -(-(GEQs[e].coef[j] * GEQs[e3].coef[i] - GEQs[e].coef[i] * GEQs[e3].coef[j]));
+ alpha3 = -a;
+ }
+
+ if (alpha1 > 0 && alpha2 > 0) {
+ if (DEBUG) {
+ fprintf(outputFile, "alpha1 = " coef_fmt ", alpha2 = " coef_fmt "; comparing against: ", alpha1, alpha2);
+ printGEQ(&(GEQs[e3]));
+ fprintf(outputFile, "\n");
+ }
+ coef_t c;
+ int k;
+ for (k = nVars; k >= 0; k--) {
+ c = alpha1 * GEQs[e].coef[k] + alpha2 * GEQs[e2].coef[k];
+ if (DEBUG) {
+ if (k>0)
+ fprintf(outputFile, " %s: " coef_fmt ", " coef_fmt "\n", variable(k), c, alpha3 * GEQs[e3].coef[k]);
+ else fprintf(outputFile, " constant: " coef_fmt ", " coef_fmt "\n", c, alpha3 * GEQs[e3].coef[k]);
+ }
+ if (c != alpha3 * GEQs[e3].coef[k])
+ break;
+ }
+ if (k < 0 || (k == 0 && c < alpha3 * (GEQs[e3].coef[k]+1))) {
+ if (DEBUG) {
+ deadCount++;
+ fprintf(outputFile, "red equation#%d is dead (%d dead so far, %d remain)\n", e3, deadCount, nGEQs - deadCount);
+ printGEQ(&(GEQs[e]));
+ fprintf(outputFile, "\n");
+ printGEQ(&(GEQs[e2]));
+ fprintf(outputFile, "\n");
+ printGEQ(&(GEQs[e3]));
+ fprintf(outputFile, "\n");
+ assert(moreToDo);
+ }
+ isDead[e3] = 1;
+ }
+ }
+ }
+ }
+
+ for (int e = nGEQs - 1; e >= 0; e--)
+ if (isDead[e])
+ deleteGEQ(e);
+
+ if (DBUG) {
+ fprintf(outputFile,"] quickRedKill\n");
+ printProblem();
+ }
+}
+
+} // namespace
diff --git a/omegalib/omega/src/omega_core/oc_global.cc b/omegalib/omega/src/omega_core/oc_global.cc
new file mode 100644
index 0000000..17d8a0c
--- /dev/null
+++ b/omegalib/omega/src/omega_core/oc_global.cc
@@ -0,0 +1,45 @@
+#include <omega/omega_core/oc_i.h>
+
+namespace omega {
+
+const int Problem::min_alloc = 10;
+const int Problem::first_alloc_pad = 5;
+
+int omega_core_debug = 0; // 3: full debugging info
+
+int maxEQs = 100; // original 35, increased by chun
+int maxGEQs = 200; // original 70, increased by chun
+
+int newVar = -1;
+int findingImplicitEqualities = 0;
+int firstCheckForRedundantEquations = 0;
+int doItAgain;
+int conservative = 0;
+FILE *outputFile = stderr; /* printProblem writes its output to this file */
+char wildName[200][20];
+int nextWildcard = 0;
+int trace = 1;
+int depth = 0;
+int headerLevel;
+int inApproximateMode = 0;
+int inStridesAllowedMode = 0;
+int addingOuterEqualities = 0;
+int outerColor = 0;
+int reduceWithSubs = 1;
+int pleaseNoEqualitiesInSimplifiedProblems = 0;
+Problem *originalProblem = noProblem;
+int omegaInitialized = 0;
+int mayBeRed = 0;
+
+
+// Hash table is used to hash all inequalties for all problems. It
+// persists across problems for quick problem merging in case. When
+// the table is filled to 1/3 full, it is flushed and the filling
+// process starts all over again.
+int packing[maxVars];
+int hashVersion = 0;
+eqn hashMaster[hashTableSize];
+int fastLookup[maxKeys*2];
+int nextKey;
+
+} // namespace
diff --git a/omegalib/omega/src/omega_core/oc_print.cc b/omegalib/omega/src/omega_core/oc_print.cc
new file mode 100644
index 0000000..7934713
--- /dev/null
+++ b/omegalib/omega/src/omega_core/oc_print.cc
@@ -0,0 +1,686 @@
+#include <omega/omega_core/oc_i.h>
+
+namespace omega {
+
+int print_in_code_gen_style = 0;
+
+void Problem::initializeVariables() const {
+ Problem *p = (Problem *)this;
+ int i;
+ assert(!p->variablesInitialized);
+ for (i = p->nVars; i >= 0; i--)
+ p->forwardingAddress[i] = p->var[i] = i;
+ p->variablesInitialized = 1;
+}
+
+
+std::string Problem::print_term_to_string(const eqn *e, int c) const {
+ std::string s="";
+ int i;
+ int first;
+ int n = nVars;
+ int wentFirst = -1;
+ first = 1;
+ for (i = 1; i <= n; i++)
+ if (c * e->coef[i] > 0) {
+ first = 0;
+ wentFirst = i;
+
+ if (c * e->coef[i] == 1)
+ s+= variable(i);
+ else {
+ s += to_string(c * e->coef[i]);
+ if (print_in_code_gen_style) s += "*";
+ s += variable(i);
+ }
+ break;
+ }
+ for (i = 1; i <= n; i++)
+ if (i != wentFirst && c * e->coef[i] != 0) {
+ if (!first && c * e->coef[i] > 0)
+ s += "+";
+
+ first = 0;
+
+ if (c * e->coef[i] == 1)
+ s += variable(i);
+ else if (c * e->coef[i] == -1) {
+ s += "-"; s += variable(i);
+ }
+ else {
+ s += to_string(c * e->coef[i]);
+ if (print_in_code_gen_style) s += "*";
+ s += variable(i);
+ }
+ }
+ if (!first && c * e->coef[0] > 0)
+ s += "+";
+ if (first || c * e->coef[0] != 0)
+ s += to_string(c * e->coef[0]);
+ return s;
+}
+
+
+void Problem::printTerm(const eqn * e, int c) const {
+ std::string s = print_term_to_string(e, c);
+ fprintf(outputFile, "%s", s.c_str());
+}
+
+
+void Problem::printSub(int v) const {
+ std::string s = print_sub_to_string(v);
+ fprintf(outputFile, "%s", s.c_str());
+}
+
+
+std::string Problem::print_sub_to_string(int v) const {
+ std::string s;
+
+ if (v > 0)
+ s = variable(v);
+ else
+ s = print_term_to_string(&SUBs[-v-1], 1);
+ return s;
+}
+
+
+void Problem::clearSubs() {
+ nSUBs = 0;
+ nMemories = 0;
+}
+
+
+void Problem::printEqn(const eqn *e, int test, int extra) const {
+ char buf[maxVars * 12 + 180]; // original buf[maxVars * 12 + 80]
+
+ sprintEqn(buf, e, test, extra);
+ fprintf(outputFile, "%s", buf);
+}
+
+
+std::string Problem::printEqnToString(const eqn *e, int test, int extra) const {
+ char buf[maxVars * 12 + 180]; // original buf[maxVars * 12 + 80]
+ sprintEqn(buf, e, test, extra);
+ return std::string(buf);
+}
+
+
+void Problem::sprintEqn(char *str, const eqn *e, int test, int extra) const {
+ int i;
+ int first;
+ int n = nVars + extra;
+ int isLT;
+
+ isLT = test && e->coef[0] == -1;
+ if (isLT)
+ isLT = 1;
+#if 0
+ if (test) {
+ if (DEBUG && e->touched) {
+ sprintf(str, "!");
+ while (*str)
+ str++;
+ }
+ else if (DBUG && !e->touched && e->key != 0) {
+ sprintf(str, "%d: ", e->key);
+ while (*str)
+ str++;
+ }
+ }
+#endif
+ if (e->color) {
+ sprintf(str, "[");
+ while (*str)
+ str++;
+ }
+ first = 1;
+ for (i = isLT; i <= n; i++)
+ if (e->coef[i] < 0) {
+ if (!first) {
+ sprintf(str, "+");
+ while (*str)
+ str++;
+ }
+ else
+ first = 0;
+ if (i == 0) {
+ sprintf(str, coef_fmt, -e->coef[i]);
+ while (*str)
+ str++;
+ }
+ else if (e->coef[i] == -1) {
+ sprintf(str, "%s", variable(i));
+ while (*str)
+ str++;
+ }
+ else {
+ if (print_in_code_gen_style)
+ sprintf(str, coef_fmt "*%s", -e->coef[i], variable(i));
+ else sprintf(str, coef_fmt "%s", -e->coef[i], variable(i));
+ while (*str)
+ str++;
+ }
+ }
+ if (first) {
+ if (isLT) {
+ sprintf(str, "1");
+ isLT = 0;
+ }
+ else
+ sprintf(str, "0");
+ while (*str)
+ str++;
+ }
+ if (test == 0) {
+ if (print_in_code_gen_style) sprintf(str, " == ");
+ else sprintf(str, " = ");
+ while (*str)
+ str++;
+ }
+ else {
+ if (isLT)
+ sprintf(str, " < ");
+ else
+ sprintf(str, " <= ");
+ while (*str)
+ str++;
+ }
+
+ first = 1;
+ for (i = 0; i <= n; i++)
+ if (e->coef[i] > 0) {
+ if (!first) {
+ sprintf(str, "+");
+ while (*str)
+ str++;
+ }
+ else
+ first = 0;
+ if (i == 0) {
+ sprintf(str, coef_fmt , e->coef[i]);
+ while (*str)
+ str++;
+ }
+ else if (e->coef[i] == 1) {
+ sprintf(str, "%s", variable(i));
+ while (*str)
+ str++;
+ }
+ else {
+ if (print_in_code_gen_style)
+ sprintf(str, coef_fmt "*%s", e->coef[i], variable(i));
+ else
+ sprintf(str, coef_fmt "%s", e->coef[i], variable(i));
+ while (*str)
+ str++;
+ }
+ }
+ if (first) {
+ sprintf(str, "0");
+ while (*str)
+ str++;
+ }
+ if (e->color) {
+ sprintf(str, "]");
+ while (*str)
+ str++;
+ }
+}
+
+
+void Problem::printSubstitution(int s) const {
+ const eqn * eq = &(SUBs[s]);
+ assert(eq->key > 0);
+ fprintf(outputFile, "%s := ", orgVariable(eq->key));
+ printTerm(eq, 1);
+}
+
+
+void Problem::printVars(int /*debug*/) const {
+ int i;
+ fprintf(outputFile, "variables = ");
+ if (safeVars > 0)
+ fprintf(outputFile, "(");
+ for (i = 1; i <= nVars; i++) {
+ fprintf(outputFile, "%s", variable(i));
+ if (i == safeVars)
+ fprintf(outputFile, ")");
+ if (i < nVars)
+ fprintf(outputFile, ", ");
+ }
+ fprintf(outputFile, "\n");
+ /*
+ fprintf(outputFile, "forward addresses = ");
+ if (safeVars > 0)
+ fprintf(outputFile, "(");
+ for (i = 1; i <= nVars; i++)
+ {
+ int v = forwardingAddress[i];
+ if (v > 0) fprintf(outputFile, "%s", variable(i));
+ else fprintf(outputFile, "*");
+ if (i == safeVars)
+ fprintf(outputFile, ")");
+ if (i < nVars)
+ fprintf(outputFile, ", ");
+ };
+ fprintf(outputFile, "\n");
+ */
+}
+
+
+void printHeader() {
+ int i;
+ for(i=0; i<headerLevel; i++) {
+ fprintf(outputFile, ". ");
+ }
+}
+
+
+void Problem::printProblem(int debug) const {
+ int e;
+
+ if (!variablesInitialized)
+ initializeVariables();
+ if (debug) {
+ printHeader();
+ fprintf(outputFile, "#vars = %d, #EQ's = %d, #GEQ's = %d, # SUB's = %d, ofInterest = %d\n",
+ nVars,nEQs,nGEQs,nSUBs,varsOfInterest);
+ printHeader();
+ printVars(debug);
+ }
+ for (e = 0; e < nEQs; e++) {
+ printHeader();
+ printEQ(&EQs[e]);
+ fprintf(outputFile, "\n");
+ }
+ for (e = 0; e < nGEQs; e++) {
+ printHeader();
+ printGEQ(&GEQs[e]);
+ fprintf(outputFile, "\n");
+ }
+ for (e = 0; e < nSUBs; e++) {
+ printHeader();
+ printSubstitution(e);
+ fprintf(outputFile, "\n");
+ }
+
+ for (e = 0; e < nMemories; e++) {
+ int i;
+ printHeader();
+ switch(redMemory[e].kind) {
+ case notRed:
+ fprintf(outputFile,"notRed: ");
+ break;
+ case redGEQ:
+ fprintf(outputFile,"Red: 0 <= ");
+ break;
+ case redLEQ:
+ fprintf(outputFile,"Red ??: 0 >= ");
+ break;
+ case redEQ:
+ fprintf(outputFile,"Red: 0 == ");
+ break;
+ case redStride:
+ fprintf(outputFile,"Red stride " coef_fmt ": ", redMemory[e].stride);
+ break;
+ }
+ fprintf(outputFile," " coef_fmt, redMemory[e].constantTerm);
+ for(i=0;i< redMemory[e].length; i++)
+ if(redMemory[e].coef[i] >= 0)
+ fprintf(outputFile,"+" coef_fmt "%s", redMemory[e].coef[i], orgVariable(redMemory[e].var[i]));
+ else
+ fprintf(outputFile,"-" coef_fmt "%s", -redMemory[e].coef[i], orgVariable(redMemory[e].var[i]));
+ fprintf(outputFile, "\n");
+ }
+ fflush(outputFile);
+
+ CHECK_FOR_DUPLICATE_VARIABLE_NAMES;
+}
+
+
+void Problem::printRedEquations() const {
+ int e;
+
+ if (!variablesInitialized)
+ initializeVariables();
+ printVars(1);
+ for (e = 0; e < nEQs; e++) {
+ if (EQs[e].color == EQ_RED) {
+ printEQ(&EQs[e]);
+ fprintf(outputFile, "\n");
+ }
+ }
+ for (e = 0; e < nGEQs; e++) {
+ if (GEQs[e].color == EQ_RED) {
+ printGEQ(&GEQs[e]);
+ fprintf(outputFile, "\n");
+ }
+ }
+ for (e = 0; e < nSUBs; e++) {
+ if (SUBs[e].color) {
+ printSubstitution(e);
+ fprintf(outputFile, "\n");
+ }
+ }
+ fflush(outputFile);
+}
+
+
+int Problem::prettyPrintProblem() const {
+ std::string s = prettyPrintProblemToString();
+ fprintf(outputFile, "%s", s.c_str());
+ fflush(outputFile);
+ return 0;
+}
+
+
+std::string Problem::prettyPrintProblemToString() const {
+ std::string s="";
+ int e;
+ int v;
+ int live[maxmaxGEQs];
+ int v1, v2, v3;
+ int t, change;
+ int stuffPrinted = 0;
+ const char *connector = " && ";
+
+ typedef enum {
+ none, le, lt
+ } partialOrderType;
+
+ partialOrderType po[maxVars][maxVars];
+ int poE[maxVars][maxVars];
+ int lastLinks[maxVars];
+ int firstLinks[maxVars];
+ int chainLength[maxVars];
+ int chain[maxVars];
+ int varCount[maxVars];
+ int i, m, multiprint;
+
+
+ if (!variablesInitialized)
+ initializeVariables();
+
+ if (nVars > 0) {
+ for (e = 0; e < nEQs; e++) {
+ if (stuffPrinted)
+ s += connector;
+ stuffPrinted = 1;
+ s += print_EQ_to_string(&EQs[e]);
+ }
+
+ for (e = 0; e < nGEQs; e++) {
+ live[e] = true;
+ varCount[e] = 0;
+ for (v = 1; v <= nVars; v++)
+ if (GEQs[e].coef[v]) varCount[e]++;
+ }
+
+ if (!print_in_code_gen_style)
+ while (1) {
+ for (v = 1; v <= nVars; v++) {
+ lastLinks[v] = firstLinks[v] = 0;
+ chainLength[v] = 0;
+ for (v2 = 1; v2 <= nVars; v2++)
+ po[v][v2] = none;
+ }
+
+ for (e = 0; e < nGEQs; e++)
+ if (live[e] && varCount[e] <= 2) {
+ for (v = 1; v <= nVars; v++) {
+ if (GEQs[e].coef[v] == 1)
+ firstLinks[v]++;
+ else if (GEQs[e].coef[v] == -1)
+ lastLinks[v]++;
+ }
+
+ v1 = nVars;
+ while (v1 > 0 && GEQs[e].coef[v1] == 0)
+ v1--;
+ v2 = v1 - 1;
+ while (v2 > 0 && GEQs[e].coef[v2] == 0)
+ v2--;
+ v3 = v2 - 1;
+ while (v3 > 0 && GEQs[e].coef[v3] == 0)
+ v3--;
+
+ if (GEQs[e].coef[0] > 0 || GEQs[e].coef[0] < -1
+ || v2 <= 0 || v3 > 0
+ || GEQs[e].coef[v1] * GEQs[e].coef[v2] != -1) {
+ /* Not a partial order relation */
+
+ }
+ else {
+ if (GEQs[e].coef[v1] == 1) {
+ v3 = v2;
+ v2 = v1;
+ v1 = v3;
+ }
+ /* relation is v1 <= v2 or v1 < v2 */
+ po[v1][v2] = ((GEQs[e].coef[0] == 0) ? le : lt);
+ poE[v1][v2] = e;
+ }
+ }
+ for (v = 1; v <= nVars; v++)
+ chainLength[v] = lastLinks[v];
+
+ /*
+ * printf("\n\nPartial order:\n"); printf(" "); for (v1 = 1; v1 <= nVars; v1++)
+ * printf("%7s",variable(v1)); printf("\n"); for (v1 = 1; v1 <= nVars; v1++) { printf("%6s:
+ * ",variable(v1)); for (v2 = 1; v2 <= nVars; v2++) switch (po[v1][v2]) { case none: printf(" ");
+ * break; case le: printf(" <= "); break; case lt: printf(" < "); break; } printf("\n"); }
+ */
+
+
+ /* Just in case nVars <= 0 */
+ change = false;
+ for (t = 0; t < nVars; t++) {
+ change = false;
+ for (v1 = 1; v1 <= nVars; v1++)
+ for (v2 = 1; v2 <= nVars; v2++)
+ if (po[v1][v2] != none &&
+ chainLength[v1] <= chainLength[v2]) {
+ chainLength[v1] = chainLength[v2] + 1;
+ change = true;
+ }
+ }
+
+ if (change) {
+ /* caught in cycle */
+
+#if 0
+ printf("\n\nPartial order:\n"); printf(" ");
+ for (v1 = 1; v1 <= nVars; v1++) printf("%7s",variable(v1)); printf("\n");
+ for (v1 = 1; v1 <= nVars; v1++) {
+ printf("%6s: ",variable(v1));
+ for (v2 = 1; v2 <= nVars; v2++) switch (po[v1][v2]) {
+ case none: printf(" "); break;
+ case le: printf(" <= "); break;
+ case lt: printf(" < "); break;
+ }
+ printf("\n");
+ }
+
+ printProblem(1);
+#endif
+ break;
+ }
+
+ for (v1 = 1; v1 <= nVars; v1++)
+ if (chainLength[v1] == 0)
+ firstLinks[v1] = 0;
+
+ v = 1;
+ for (v1 = 2; v1 <= nVars; v1++)
+ if (chainLength[v1] + firstLinks[v1] > chainLength[v] + firstLinks[v])
+ v = v1;
+
+ if (chainLength[v] + firstLinks[v] == 0)
+ break;
+
+ if (stuffPrinted)
+ s += connector;
+ stuffPrinted = 1;
+ /* chain starts at v */
+ /* print firstLinks */
+ {
+ coef_t tmp;
+ int first;
+ first = 1;
+ for (e = 0; e < nGEQs; e++)
+ if (live[e] && GEQs[e].coef[v] == 1 && varCount[e] <= 2) {
+ if (!first)
+ s += ", ";
+ tmp = GEQs[e].coef[v];
+ ((Problem *)this)->
+ GEQs[e].coef[v] = 0;
+ s += print_term_to_string(&GEQs[e], -1);
+ ((Problem *)this)->
+ GEQs[e].coef[v] = tmp;
+ live[e] = false;
+ first = 0;
+ }
+ if (!first)
+ s += " <= ";
+ }
+
+
+ /* find chain */
+ chain[0] = v;
+ m = 1;
+ while (1) {
+ /* print chain */
+ for (v2 = 1; v2 <= nVars; v2++)
+ if (po[v][v2] && chainLength[v] == 1 + chainLength[v2])
+ break;
+ if (v2 > nVars)
+ break;
+ chain[m++] = v2;
+ v = v2;
+ }
+
+ s += variable(chain[0]);
+
+ multiprint = 0;
+ for (i = 1; i < m; i++) {
+ v = chain[i - 1];
+ v2 = chain[i];
+ if (po[v][v2] == le)
+ s += " <= ";
+ else
+ s += " < ";
+ s += variable(v2);
+ live[poE[v][v2]] = false;
+ if (!multiprint && i < m - 1)
+ for (v3 = 1; v3 <= nVars; v3++) {
+ if (v == v3 || v2 == v3)
+ continue;
+ if (po[v][v2] != po[v][v3])
+ continue;
+ if (po[v2][chain[i + 1]] != po[v3][chain[i + 1]])
+ continue;
+ s += ","; s += variable(v3);
+ live[poE[v][v3]] = false;
+ live[poE[v3][chain[i + 1]]] = false;
+ multiprint = 1;
+ }
+ else
+ multiprint = 0;
+ }
+
+ v = chain[m - 1];
+ /* print lastLinks */
+ {
+ coef_t tmp;
+ int first;
+ first = 1;
+ for (e = 0; e < nGEQs; e++)
+ if (live[e] && GEQs[e].coef[v] == -1 && varCount[e] <= 2) {
+ if (!first)
+ s += ", ";
+ else
+ s += " <= ";
+ tmp = GEQs[e].coef[v];
+ ((Problem *)this)->
+ GEQs[e].coef[v] = 0;
+ s += print_term_to_string(&GEQs[e], 1);
+ ((Problem *)this)->
+ GEQs[e].coef[v] = tmp;
+ live[e] = false;
+ first = 0;
+ }
+ }
+ }
+
+
+ for (e = 0; e < nGEQs; e++)
+ if (live[e]) {
+ if (stuffPrinted)
+ s += connector;
+ stuffPrinted = 1;
+ s += print_GEQ_to_string(&GEQs[e]);
+ }
+
+ for (e = 0; e < nSUBs; e++) {
+ const eqn * eq = &SUBs[e];
+ if (stuffPrinted)
+ s += connector;
+ stuffPrinted = 1;
+ if (eq->key > 0) {
+ s += orgVariable(eq->key); s += " := ";
+ }
+ else {
+ s += "#"; s += to_string(eq->key); s += " := ";
+ }
+ s += print_term_to_string(eq, 1);
+ }
+ }
+ return s;
+}
+
+
+int Problem::prettyPrintRedEquations() const {
+ int e, stuffPrinted = 0;
+ const char *connector = " && ";
+
+ if (!variablesInitialized)
+ initializeVariables();
+
+ for (e = 0; e < nEQs; e++) {
+ if (EQs[e].color == EQ_RED) {
+ if (stuffPrinted)
+ fprintf(outputFile, "%s", connector);
+ stuffPrinted = 1;
+ ((Problem *)this)->
+ EQs[e].color = EQ_BLACK;
+ printEQ(&EQs[e]);
+ ((Problem *)this)->
+ EQs[e].color = EQ_RED;
+ }
+ }
+ for (e = 0; e < nGEQs; e++) {
+ if (GEQs[e].color == EQ_RED) {
+ if (stuffPrinted)
+ fprintf(outputFile, "%s", connector);
+ stuffPrinted = 1;
+ ((Problem *)this)->
+ GEQs[e].color = EQ_BLACK;
+ printGEQ(&GEQs[e]);
+ ((Problem *)this)->
+ GEQs[e].color = EQ_RED;
+ }
+ }
+ for (e = 0; e < nSUBs; e++) {
+ if (SUBs[e].color) {
+ if (stuffPrinted)
+ fprintf(outputFile, "%s", connector);
+ stuffPrinted = 1;
+ printSubstitution(e);
+ }
+ }
+ fflush(outputFile);
+
+ return 0;
+}
+
+}
diff --git a/omegalib/omega/src/omega_core/oc_problems.cc b/omegalib/omega/src/omega_core/oc_problems.cc
new file mode 100644
index 0000000..8b6e04c
--- /dev/null
+++ b/omegalib/omega/src/omega_core/oc_problems.cc
@@ -0,0 +1,198 @@
+#include <omega/omega_core/oc_i.h>
+#include <basic/omega_error.h>
+
+namespace omega {
+
+Problem::~Problem() {
+ delete[] EQs;
+ delete[] GEQs;
+}
+
+
+void check_number_EQs(int n) {
+ if (n < 0) {
+ fprintf(stderr,"ERROR: nEQs < 0??\n");
+ exit(1);
+ }
+
+ if (n > maxmaxEQs) {
+ // clear global variables
+ inApproximateMode = 0;
+ outerColor = 0;
+
+ throw presburger_error("\nERROR:\n"
+ "An attempt was made to set the number of available equality constraints to " + to_string(n) + ".\n"
+ "The maximum number of equality constraints in a conjunction is " + to_string(maxmaxEQs) + ".\n"
+ "This limit can be changed by redefining maxmaxEQs in oc.h and recompiling.\n\n");
+
+ // fprintf(stderr, "\nERROR:\n");
+ // fprintf(stderr, "An attempt was made to set the number of available equality constraints to %d.\n", n);
+ // fprintf(stderr, "The maximum number of equality constraints in a conjunction is %d.\n", maxmaxEQs);
+ // fprintf(stderr, "This limit can be changed by redefining maxmaxEQs in oc.h and recompiling.\n\n");
+ // exit(2);
+ }
+}
+
+void check_number_GEQs(int n) {
+ if (n < 0) {
+ fprintf(stderr,"ERROR: nGEQs < 0??\n");
+ exit(1);
+ }
+
+ if (n > maxmaxGEQs) {
+ // clear global variables
+ inApproximateMode = 0;
+ outerColor = 0;
+
+ throw presburger_error("\nERROR:\n"
+ "An attempt was made to set the number of available inequality constraints to " + to_string(n) +".\n"
+ "The maximum number of inequality constraints in a conjunction is " + to_string(maxmaxGEQs) +".\n"
+ "This limit can be changed by redefining maxmaxGEQs in oc.h and recompiling.\n\n");
+
+ // fprintf(stderr, "\nERROR:\n");
+ // fprintf(stderr, "An attempt was made to set the number of available inequality constraints to %d.\n", n);
+ // fprintf(stderr, "The maximum number of inequality constraints in a conjunction is %d.\n", maxmaxGEQs);
+ // fprintf(stderr, "This limit can be changed by redefining maxmaxGEQs in oc.h and recompiling.\n\n");
+ // exit(2);
+ }
+}
+
+
+void check_number_EQs_GEQs(int e, int g) {
+ check_number_EQs(e);
+ check_number_GEQs(g);
+}
+
+
+Problem::Problem(int in_eqs, int in_geqs) {
+ check_number_EQs_GEQs(in_eqs, in_geqs);
+ allocEQs = padEQs(in_eqs);
+ allocGEQs = padGEQs(in_geqs);
+ assert(allocEQs > 0 && allocGEQs > 0);
+ EQs = new eqn[allocEQs];
+ GEQs = new eqn[allocGEQs];
+ nVars = 0;
+ hashVersion = omega::hashVersion;
+ variablesInitialized = 0;
+ variablesFreed = 0;
+ varsOfInterest = 0;
+ safeVars = 0;
+ nEQs = 0;
+ nGEQs = 0;
+ nSUBs = 0;
+ nMemories = 0;
+ isTemporary = false;
+}
+
+Problem::Problem(const Problem & p2) {
+ allocEQs = padEQs(p2.nEQs); // Don't over-allocate; p2 might have too many!
+ allocGEQs = padGEQs(p2.nGEQs);
+ assert(allocEQs > 0 && allocGEQs > 0);
+ EQs = new eqn[allocEQs];
+ GEQs = new eqn[allocGEQs];
+ int e, i;
+ nVars = p2.nVars;
+ hashVersion = p2.hashVersion;
+ variablesInitialized = p2.variablesInitialized;
+ variablesFreed = p2.variablesFreed;
+ varsOfInterest = p2.varsOfInterest;
+ safeVars = p2.safeVars;
+ nEQs = p2.nEQs;
+ isTemporary = p2.isTemporary;
+ //nSUBs = 0;
+ for (e = p2.nEQs - 1; e >= 0; e--)
+ eqnncpy(&(EQs[e]), &(p2.EQs[e]), p2.nVars);
+ nGEQs = p2.nGEQs;
+ for (e = p2.nGEQs - 1; e >= 0; e--)
+ eqnncpy(&(GEQs[e]), &(p2.GEQs[e]), p2.nVars);
+ for (i = 0; i <= p2.nVars; i++)
+ var[i] = p2.var[i];
+ for (i = 0; i <= maxVars; i++)
+ forwardingAddress[i] = p2.forwardingAddress[i];
+ //nMemories = 0;
+ get_var_name = p2.get_var_name;
+ getVarNameArgs = p2.getVarNameArgs;
+}
+
+Problem & Problem::operator=(const Problem & p2) {
+ if (this != &p2) {
+ if(allocEQs < p2.nEQs) {
+ delete[] EQs;
+ allocEQs = padEQs(p2.nEQs);
+ EQs = new eqn[allocEQs];
+ }
+ if(allocGEQs < p2.nGEQs) {
+ delete[] GEQs;
+ allocGEQs = padGEQs(p2.nGEQs);
+ GEQs = new eqn[allocGEQs];
+ }
+ int e, i;
+ nVars = p2.nVars;
+ hashVersion = p2.hashVersion;
+ variablesInitialized = p2.variablesInitialized;
+ variablesFreed = p2.variablesFreed;
+ varsOfInterest = p2.varsOfInterest;
+ safeVars = p2.safeVars;
+ nEQs = p2.nEQs;
+ isTemporary = p2.isTemporary;
+ //nSUBs = 0;
+ for (e = p2.nEQs - 1; e >= 0; e--)
+ eqnncpy(&(EQs[e]), &(p2.EQs[e]), p2.nVars);
+ nGEQs = p2.nGEQs;
+ for (e = p2.nGEQs - 1; e >= 0; e--)
+ eqnncpy(&(GEQs[e]), &(p2.GEQs[e]), p2.nVars);
+ for (i = 0; i <= p2.nVars; i++)
+ var[i] = p2.var[i];
+ for (i = 0; i <= maxVars; i++)
+ forwardingAddress[i] = p2.forwardingAddress[i];
+ //nMemories = 0;
+ get_var_name = p2.get_var_name;
+ getVarNameArgs = p2.getVarNameArgs;
+ }
+ return *this;
+}
+
+
+void Problem::zeroVariable(int i) {
+ int e;
+ for (e = nGEQs - 1; e >= 0; e--) GEQs[e].coef[i] = 0;
+ for (e = nEQs - 1; e >= 0; e--) EQs[e].coef[i] = 0;
+ for (e = nSUBs - 1; e >= 0; e--) SUBs[e].coef[i] = 0;
+}
+
+/* Functions for allocating EQ's and GEQ's */
+
+int Problem::newGEQ() {
+ if (++nGEQs > allocGEQs) {
+ check_number_GEQs(nGEQs);
+ allocGEQs = padGEQs(allocGEQs, nGEQs);
+ assert(allocGEQs >= nGEQs);
+ eqn *new_geqs = new eqn[allocGEQs];
+ for (int e = nGEQs - 2; e >= 0; e--)
+ eqnncpy(&(new_geqs[e]), &(GEQs[e]), nVars);
+ delete[] GEQs;
+ GEQs = new_geqs;
+ }
+// problem->GEQs[nGEQs-1].color = black;
+// eqnnzero(&problem->GEQs[nGEQs-1],problem->nVars);
+ return nGEQs-1;
+}
+
+int Problem::newEQ() {
+ if (++nEQs > allocEQs) {
+ check_number_EQs(nEQs);
+ allocEQs = padEQs(allocEQs, nEQs);
+ assert(allocEQs >= nEQs);
+ eqn *new_eqs = new eqn[allocEQs];
+ for (int e = nEQs - 2; e >= 0; e--)
+ eqnncpy(&(new_eqs[e]), &(EQs[e]), nVars);
+ delete[] EQs;
+ EQs = new_eqs;
+ }
+// Could do this here, but some calls to newEQ do a copy instead of a zero;
+// problem->EQs[nEQs-1].color = black;
+// eqnnzero(&problem->EQs[nEQs-1],problem->nVars);
+ return nEQs-1;
+}
+
+} // namespace
diff --git a/omegalib/omega/src/omega_core/oc_query.cc b/omegalib/omega/src/omega_core/oc_query.cc
new file mode 100644
index 0000000..528b297
--- /dev/null
+++ b/omegalib/omega/src/omega_core/oc_query.cc
@@ -0,0 +1,478 @@
+#include <omega/omega_core/oc_i.h>
+
+namespace omega {
+
+void Problem::unprotectVariable( int v) {
+ int e, j, i;
+ coef_t t;
+ i = forwardingAddress[v];
+ if (i < 0) {
+ i = -1 - i;
+ nSUBs--;
+ if (i < nSUBs) {
+ eqnncpy(&SUBs[i], &SUBs[nSUBs], nVars);
+ forwardingAddress[SUBs[i].key] = -i - 1;
+ }
+ }
+ else {
+ int bringToLife[maxVars];
+ int comingBack = 0;
+ int e2;
+ for (e = nSUBs - 1; e >= 0; e--)
+ if ((bringToLife[e] = (SUBs[e].coef[i] != 0)))
+ comingBack++;
+
+ for (e2 = nSUBs - 1; e2 >= 0; e2--)
+ if (bringToLife[e2]) {
+
+ nVars++;
+ safeVars++;
+ if (safeVars < nVars) {
+ for (e = nGEQs - 1; e >= 0; e--) {
+ GEQs[e].coef[nVars] = GEQs[e].coef[safeVars];
+ GEQs[e].coef[safeVars] = 0;
+ }
+ for (e = nEQs - 1; e >= 0; e--) {
+ EQs[e].coef[nVars] = EQs[e].coef[safeVars];
+ EQs[e].coef[safeVars] = 0;
+ }
+ for (e = nSUBs - 1; e >= 0; e--) {
+ SUBs[e].coef[nVars] = SUBs[e].coef[safeVars];
+ SUBs[e].coef[safeVars] = 0;
+ }
+ var[nVars] = var[safeVars];
+ forwardingAddress[var[nVars]] = nVars;
+ }
+ else {
+ for (e = nGEQs - 1; e >= 0; e--) {
+ GEQs[e].coef[safeVars] = 0;
+ }
+ for (e = nEQs - 1; e >= 0; e--) {
+ EQs[e].coef[safeVars] = 0;
+ }
+ for (e = nSUBs - 1; e >= 0; e--) {
+ SUBs[e].coef[safeVars] = 0;
+ }
+ }
+
+ var[safeVars] = SUBs[e2].key;
+ forwardingAddress[SUBs[e2].key] = safeVars;
+
+ int neweq = newEQ();
+ eqnncpy(&(EQs[neweq]), &(SUBs[e2]), nVars);
+ EQs[neweq].coef[safeVars] = -1;
+ if (e2 < nSUBs - 1)
+ eqnncpy(&(SUBs[e2]), &(SUBs[nSUBs - 1]), nVars);
+ nSUBs--;
+ }
+
+ if (i < safeVars) {
+ j = safeVars;
+ for (e = nSUBs - 1; e >= 0; e--) {
+ t = SUBs[e].coef[j];
+ SUBs[e].coef[j] = SUBs[e].coef[i];
+ SUBs[e].coef[i] = t;
+ }
+ for (e = nGEQs - 1; e >= 0; e--)
+ if (GEQs[e].coef[j] != GEQs[e].coef[i]) {
+ GEQs[e].touched = true;
+ t = GEQs[e].coef[j];
+ GEQs[e].coef[j] = GEQs[e].coef[i];
+ GEQs[e].coef[i] = t;
+ }
+ for (e = nEQs - 1; e >= 0; e--) {
+ t = EQs[e].coef[j];
+ EQs[e].coef[j] = EQs[e].coef[i];
+ EQs[e].coef[i] = t;
+ }
+ {
+ short t;
+ t = var[j];
+ var[j] = var[i];
+ var[i] = t;
+ }
+ forwardingAddress[var[i]] = i;
+ forwardingAddress[var[j]] = j;
+ }
+ safeVars--;
+ }
+ chainUnprotect();
+}
+
+void Problem::constrainVariableSign( int color, int i, int sign) {
+ int nV = nVars;
+ int e, k, j;
+
+ k = forwardingAddress[i];
+ if (k < 0) {
+ k = -1 - k;
+
+ if (sign != 0) {
+ e = newGEQ();
+ eqnncpy(&GEQs[e], &SUBs[k], nVars);
+ for (j = 0; j <= nV; j++)
+ GEQs[e].coef[j] *= sign;
+ GEQs[e].coef[0]--;
+ GEQs[e].touched = 1;
+ GEQs[e].color = color;
+ }
+ else {
+ e = newEQ();
+ eqnncpy(&EQs[e], &SUBs[k], nVars);
+ EQs[e].color = color;
+ }
+ }
+ else if (sign != 0) {
+ e = newGEQ();
+ eqnnzero(&GEQs[e], nVars);
+ GEQs[e].coef[k] = sign;
+ GEQs[e].coef[0] = -1;
+ GEQs[e].touched = 1;
+ GEQs[e].color = color;
+ }
+ else {
+ e = newEQ();
+ eqnnzero(&EQs[e], nVars);
+ EQs[e].coef[k] = 1;
+ EQs[e].color = color;
+ }
+ /*
+ unprotectVariable(i);
+ return (simplifyProblem(0,1,0));
+ */
+}
+
+void Problem::constrainVariableValue( int color, int i, int value) {
+ int e, k;
+
+ k = forwardingAddress[i];
+ if (k < 0) {
+ k = -1 - k;
+
+ e = newEQ();
+ eqnncpy(&EQs[e], &SUBs[k], nVars);
+ EQs[e].coef[0] -= value;
+
+ }
+ else {
+ e = newEQ();
+ eqnnzero(&EQs[e], nVars);
+ EQs[e].coef[k] = 1;
+ EQs[e].coef[0] = -value;
+ }
+ EQs[e].color = color;
+}
+
+// Analyze v1-v2
+void Problem:: query_difference(int v1, int v2, coef_t &lowerBound, coef_t &upperBound, bool &guaranteed) {
+ int nV = nVars;
+ int e,i,e2;
+
+ coef_t lb1,ub1;
+ coef_t lb2,ub2;
+ assert(nSUBs == 0);
+ lowerBound = negInfinity;
+ lb1 = lb2 = negInfinity;
+ upperBound = posInfinity;
+ ub1 = ub2 = posInfinity;
+ guaranteed = true;
+ for (e = nEQs - 1; e >= 0; e--) {
+ if (EQs[e].coef[v1] == 0 && EQs[e].coef[v2] == 0)
+ continue;
+ for(i=nV;i>0;i--)
+ if (EQs[e].coef[i] && i!=v1 && i != v2) {
+ break;
+ }
+ if (i != 0) {
+ if (i > safeVars) {
+ // check to see if this variable appears anywhere else
+ for(e2 = nEQs-1; e2>=0;e2--) if (e != e2 && EQs[e2].coef[i]) break;
+ if (e2 < 0)
+ for(e2 = nGEQs-1; e2>=0;e2--) if (e != e2 && GEQs[e2].coef[i]) break;
+ if (e2 < 0)
+ for(e2 = nSUBs-1; e2>=0;e2--) if (e != e2 && SUBs[e2].coef[i]) break;
+ if (e2 >= 0) guaranteed = false;
+ }
+ else guaranteed = false;
+ continue;
+ }
+ if (EQs[e].coef[v1]*EQs[e].coef[v2] == -1) {
+ // found exact difference
+ coef_t d = - EQs[e].coef[v1] * EQs[e].coef[0];
+ set_max(lowerBound, d);
+ set_min(upperBound, d);
+ guaranteed =true;
+ return;
+ }
+ else if (EQs[e].coef[v1] == 0)
+ lb2 = ub2 = -EQs[e].coef[0]/ EQs[e].coef[v2];
+ else if (EQs[e].coef[v2] == 0)
+ lb1 = ub1 = -EQs[e].coef[0]/ EQs[e].coef[v1];
+ else guaranteed = false;
+ }
+
+ bool isDead[maxmaxGEQs];
+
+ for (e = nGEQs - 1; e >= 0; e--) isDead[e] = false;
+ int tryAgain = 1;
+ while (tryAgain) {
+ tryAgain = 0;
+ for (i = nVars; i > 0;i--)
+ if (i!= v1 && i != v2) {
+ for (e = nGEQs - 1; e >= 0; e--)
+ if (!isDead[e] && GEQs[e].coef[i])
+ break;
+ if (e < 0)
+ e2 = e;
+ else if (GEQs[e].coef[i] > 0) {
+ for (e2 = e - 1; e2 >= 0; e2--)
+ if (!isDead[e2] && GEQs[e2].coef[i] < 0)
+ break;
+ }
+ else {
+ for (e2 = e - 1; e2 >= 0; e2--)
+ if (!isDead[e2] && GEQs[e2].coef[i] > 0)
+ break;
+ }
+ if (e2 < 0) {
+ int e3;
+ for (e3 = nSUBs - 1; e3 >= 0; e3--)
+ if (SUBs[e3].coef[i])
+ break;
+ if (e3 >= 0)
+ continue;
+ for (e3 = nEQs - 1; e3 >= 0; e3--)
+ if (EQs[e3].coef[i])
+ break;
+ if (e3 >= 0)
+ continue;
+ if (e >= 0) {
+ isDead[e] = true;
+ for (e--; e >= 0; e--)
+ if (GEQs[e].coef[i]) isDead[e] = true;
+ }
+ }
+ }
+ }
+
+ for (e = nGEQs - 1; e >= 0; e--)
+ if (!isDead[e]) {
+ if (GEQs[e].coef[v1] == 0 && GEQs[e].coef[v2] == 0)
+ continue;
+ for(i=nV;i>0;i--)
+ if (GEQs[e].coef[i] && i!=v1 && i != v2)
+ break;
+ if (i != 0) {
+ guaranteed = false;
+ continue;
+ }
+ if (GEQs[e].coef[v1]*GEQs[e].coef[v2] == -1) {
+ // found relative difference
+ if (GEQs[e].coef[v1] == 1) {
+ // v1 - v2 + c >= 0
+ set_max(lowerBound, - GEQs[e].coef[0]);
+ }
+ else {
+ // v2 - v1 + c >= 0
+ // c >= v1-v2
+ set_min(upperBound, GEQs[e].coef[0]);
+ }
+ }
+ else if (GEQs[e].coef[v1] == 0 && GEQs[e].coef[v2] > 0)
+ lb2 = -GEQs[e].coef[0]/ GEQs[e].coef[v2];
+ else if (GEQs[e].coef[v1] == 0 && GEQs[e].coef[v2] < 0)
+ ub2 = -GEQs[e].coef[0]/ GEQs[e].coef[v2];
+ else if (GEQs[e].coef[v2] == 0 && GEQs[e].coef[v1] > 0)
+ lb1 = -GEQs[e].coef[0]/ GEQs[e].coef[v1];
+ else if (GEQs[e].coef[v2] == 0 && GEQs[e].coef[v1] < 0)
+ ub1 = -GEQs[e].coef[0]/ GEQs[e].coef[v1];
+ else guaranteed = false;
+ }
+
+ // ub1-lb2 >= v1-v2 >= lb1-ub2
+
+ if (negInfinity < lb2 && ub1 < posInfinity) set_min(upperBound, ub1-lb2);
+ if (negInfinity < lb1 && ub2 < posInfinity) set_max(lowerBound, lb1-ub2);
+ if (lowerBound >= upperBound) guaranteed = 1;
+}
+
+
+int Problem::queryVariable(int i, coef_t *lowerBound, coef_t *upperBound) {
+ int nV = nVars;
+ int e, j;
+ int isSimple;
+ int coupled = false;
+ for(j=1;j<=safeVars;j++)
+ if (var[j] > 0)
+ assert(forwardingAddress[var[j]] == j);
+
+ assert(i > 0);
+ i = forwardingAddress[i];
+ assert(i != 0);
+
+ (*lowerBound) = negInfinity;
+ (*upperBound) = posInfinity;
+
+ if (i < 0) {
+ int easy = true;
+ i = -i - 1;
+ for (j = 1; j <= nV; j++)
+ if (SUBs[i].coef[j] != 0)
+ easy = false;
+ if (easy) {
+ *upperBound = *lowerBound = SUBs[i].coef[0];
+ return (false);
+ }
+ return (true);
+ }
+
+ for (e = nSUBs - 1; e >= 0; e--)
+ if (SUBs[e].coef[i] != 0)
+ coupled = true;
+
+ for (e = nEQs - 1; e >= 0; e--)
+ if (EQs[e].coef[i] != 0) {
+ isSimple = true;
+ for (j = 1; j <= nV; j++)
+ if (i != j && EQs[e].coef[j] != 0) {
+ isSimple = false;
+ coupled = true;
+ break;
+ }
+ if (!isSimple)
+ continue;
+ else {
+ *lowerBound = *upperBound = -EQs[e].coef[i] * EQs[e].coef[0];
+ return (false);
+ }
+ }
+ for (e = nGEQs - 1; e >= 0; e--)
+ if (GEQs[e].coef[i] != 0) {
+ if (GEQs[e].key == i) {
+ set_max(*lowerBound, -GEQs[e].coef[0]);
+ }
+ else if (GEQs[e].key == -i) {
+ set_min(*upperBound, GEQs[e].coef[0]);
+ }
+ else
+ coupled = true;
+ }
+ return (coupled);
+}
+
+int Problem::query_variable_bounds(int i, coef_t *l, coef_t *u) {
+ int coupled;
+ *l = negInfinity;
+ *u = posInfinity;
+ coupled = queryVariable(i, l, u);
+ if (!coupled || (nVars == 1 && forwardingAddress[i] == 1))
+ return 0;
+ if (abs(forwardingAddress[i]) == 1 && nVars + nSUBs == 2 && nEQs + nSUBs == 1) {
+ int couldBeZero;
+ queryCoupledVariable(i, l, u, &couldBeZero, negInfinity, posInfinity);
+ return 0;
+ }
+ return 1;
+}
+
+void Problem::queryCoupledVariable(int i, coef_t *l, coef_t *u, int *couldBeZero, coef_t lowerBound, coef_t upperBound) {
+ int e;
+ coef_t b1, b2;
+ const eqn *eqn;
+ coef_t sign;
+ int v;
+
+ if (abs(forwardingAddress[i]) != 1 || nVars + nSUBs != 2 || nEQs + nSUBs != 1) {
+ fprintf(outputFile, "queryCoupledVariablecalled with bad parameters\n");
+ printProblem();
+ exit(2);
+ }
+
+ if (forwardingAddress[i] == -1) {
+ eqn = &SUBs[0];
+ sign = 1;
+ v = 1;
+ }
+ else {
+ eqn = &EQs[0];
+ sign = -eqn->coef[1];
+ v = 2;
+ }
+
+ /* Variable i is defined in terms of variable v */
+
+ for (e = nGEQs - 1; e >= 0; e--)
+ if (GEQs[e].coef[v] != 0) {
+ if (GEQs[e].coef[v] == 1) {
+ set_max(lowerBound, -GEQs[e].coef[0]);
+ }
+ else {
+ set_min(upperBound, GEQs[e].coef[0]);
+ }
+ }
+ /* lowerBound and upperBound are bounds on the value of v */
+
+ if (lowerBound > upperBound) {
+ *l = posInfinity;
+ *u = negInfinity;
+ *couldBeZero = 0;
+ return;
+ }
+ if (lowerBound == negInfinity) {
+ if (eqn->coef[v] > 0)
+ b1 = sign * negInfinity;
+ else
+ b1 = -sign * negInfinity;
+ }
+ else
+ b1 = sign * (eqn->coef[0] + eqn->coef[v] * lowerBound);
+ if (upperBound == posInfinity) {
+ if (eqn->coef[v] > 0)
+ b2 = sign * posInfinity;
+ else
+ b2 = -sign * posInfinity;
+ }
+ else
+ b2 = sign * (eqn->coef[0] + eqn->coef[v] * upperBound);
+
+ /* b1 and b2 are bounds on the value of i (don't know which is upper bound) */
+ if (b1 <= b2) {
+ set_max(*l, b1);
+ set_min(*u, b2);
+ }
+ else {
+ set_max(*l, b2);
+ set_min(*u, b1);
+ }
+ *couldBeZero = *l <= 0 && 0 <= *u && int_mod(eqn->coef[0], abs(eqn->coef[v])) == 0;
+}
+
+
+int Problem::queryVariableSigns(int i, int dd_lt, int dd_eq, int dd_gt, coef_t lowerBound, coef_t upperBound, bool *distKnown, coef_t *dist) {
+ int result;
+ coef_t l, u;
+ int couldBeZero;
+
+ l = negInfinity;
+ u = posInfinity;
+
+ queryVariable(i, &l, &u);
+ queryCoupledVariable(i, &l, &u, &couldBeZero, lowerBound, upperBound);
+ result = 0;
+ if (l < 0)
+ result |= dd_gt;
+ if (u > 0)
+ result |= dd_lt;
+ if (couldBeZero)
+ result |= dd_eq;
+ if (l == u) {
+ *distKnown = 1;
+ *dist = l;
+ }
+ else {
+ *distKnown = 0;
+ }
+ return (result);
+}
+
+} // namespace
diff --git a/omegalib/omega/src/omega_core/oc_quick_kill.cc b/omegalib/omega/src/omega_core/oc_quick_kill.cc
new file mode 100644
index 0000000..1b988d4
--- /dev/null
+++ b/omegalib/omega/src/omega_core/oc_quick_kill.cc
@@ -0,0 +1,775 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 the Omega Project Team
+ Copyright (C) 2005-2011 Chun Chen
+ All Rights Reserved.
+
+ Purpose:
+ Quick inequality elimination.
+
+ Notes:
+
+ History:
+ 03/31/09 Use BoolSet, Chun Chen
+*****************************************************************************/
+
+#include <omega/omega_core/oc_i.h>
+#include <vector>
+#include <algorithm>
+#include <basic/BoolSet.h>
+
+namespace omega {
+
+int Problem::combineToTighten() {
+ int effort = min(12+5*(nVars-safeVars),23);
+
+ if (DBUG) {
+ fprintf(outputFile, "\nin combineToTighten (%d,%d):\n",effort,nGEQs);
+ printProblem();
+ fprintf(outputFile, "\n");
+ }
+ if (nGEQs > effort) {
+ if (TRACE) {
+ fprintf(outputFile, "too complicated to tighten\n");
+ }
+ return 1;
+ }
+
+ for(int e = 1; e < nGEQs; e++) {
+ for(int e2 = 0; e2 < e; e2++) {
+ coef_t g = 0;
+
+ bool has_wildcard = false;
+ bool has_wildcard2 = false;
+ for (int i = nVars; i > safeVars; i--) {
+ coef_t a = GEQs[e].coef[i];
+ coef_t b = GEQs[e2].coef[i];
+ g = gcd(g, abs(a+b));
+ if (a != 0)
+ has_wildcard = true;
+ if (b != 0)
+ has_wildcard2 = true;
+ }
+
+ coef_t c, c2;
+ if ((has_wildcard && !has_wildcard2) || (!has_wildcard && has_wildcard2))
+ c = 0;
+ else
+ c = -1;
+ for (int i = safeVars; i >= 1; i--) {
+ coef_t a = GEQs[e].coef[i];
+ coef_t b = GEQs[e2].coef[i];
+ if (a != 0 || b != 0) {
+ g = gcd(g, abs(a+b));
+
+ if (c < 0) {
+ if (g == 1)
+ break;
+ }
+ else if ((a>0 && b<0) || (a<0 && b>0)) {
+ if (c == 0) {
+ try {
+ coef_t prod = lcm(abs(a), abs(b));
+ c = prod/abs(a);
+ c2 = prod/abs(b);
+ }
+ catch (std::overflow_error) {
+ c = -1;
+ }
+ }
+ else {
+ if (c*a+c2*b != 0)
+ c = -1;
+ }
+ }
+ else {
+ c = -1;
+ }
+ }
+ }
+
+ bool done_unit_combine = false;
+ if (g > 1 && (GEQs[e].coef[0] + GEQs[e2].coef[0]) % g != 0) {
+ int e3 = newGEQ();
+ for(int i = nVars; i >= 1; i--) {
+ GEQs[e3].coef[i] = (GEQs[e].coef[i] + GEQs[e2].coef[i])/g;
+ }
+ GEQs[e3].coef[0] = int_div(GEQs[e].coef[0] + GEQs[e2].coef[0], g);
+ GEQs[e3].color = GEQs[e].color || GEQs[e2].color;
+ GEQs[e3].touched = 1;
+ if (DBUG) {
+ fprintf(outputFile, "Combined ");
+ printGEQ(&GEQs[e]);
+ fprintf(outputFile,"\n and ");
+ printGEQ(&GEQs[e2]);
+ fprintf(outputFile,"\n to get #%d: ",e3);
+ printGEQ(&GEQs[e3]);
+ fprintf(outputFile,"\n\n");
+ }
+
+ done_unit_combine = true;
+ if (nGEQs > effort+5 || nGEQs > maxmaxGEQs-10) goto doneCombining;
+ }
+
+ if (c > 0 && !(c == 1 && c2 == 1 && done_unit_combine)) {
+ bool still_has_wildcard = false;
+ coef_t p[nVars-safeVars];
+ for (int i = nVars; i > safeVars; i--) {
+ p[i-safeVars-1] = c * GEQs[e].coef[i] + c2 * GEQs[e2].coef[i];
+ if (p[i-safeVars-1] != 0)
+ still_has_wildcard = true;
+ }
+ if (still_has_wildcard) {
+ int e3 = newGEQ();
+ for(int i = nVars; i > safeVars; i--)
+ GEQs[e3].coef[i] = p[i-safeVars-1];
+ for (int i = safeVars; i > 0; i--)
+ GEQs[e3].coef[i] = 0;
+ GEQs[e3].coef[0] = c * GEQs[e].coef[0] + c2 * GEQs[e2].coef[0];
+ GEQs[e3].color = GEQs[e].color || GEQs[e2].color;
+ GEQs[e3].touched = 1;
+ if (DBUG) {
+ fprintf(outputFile, "Additionally combined ");
+ printGEQ(&GEQs[e]);
+ fprintf(outputFile,"\n and ");
+ printGEQ(&GEQs[e2]);
+ fprintf(outputFile,"\n to get #%d: ",e3);
+ printGEQ(&GEQs[e3]);
+ fprintf(outputFile,"\n\n");
+ }
+
+ if (nGEQs > effort+5 || nGEQs > maxmaxGEQs-10) goto doneCombining;
+ }
+ }
+ }
+ }
+
+doneCombining:
+ if (normalize() == normalize_false) return 0;
+ while (nEQs) {
+ if (!solveEQ()) return 0;
+ if (normalize() == normalize_false) return 0;
+ }
+ return 1;
+}
+
+
+void Problem::noteEssential(int onlyWildcards) {
+ for (int e = nGEQs - 1; e >= 0; e--) {
+ GEQs[e].essential = 0;
+ GEQs[e].varCount = 0;
+ }
+ if (onlyWildcards) {
+ for (int e = nGEQs - 1; e >= 0; e--) {
+ GEQs[e].essential = 1;
+ for (int i = nVars; i > safeVars; i--)
+ if (GEQs[e].coef[i] < -1 || GEQs[e].coef[i] > 1) {
+ GEQs[e].essential = 0;
+ break;
+ }
+ }
+ }
+ for (int i = nVars; i >= 1; i--) {
+ int onlyLB = -1;
+ int onlyUB = -1;
+ for (int e = nGEQs - 1; e >= 0; e--)
+ if (GEQs[e].coef[i] > 0) {
+ GEQs[e].varCount ++;
+ if (onlyLB == -1) onlyLB = e;
+ else onlyLB = -2;
+ }
+ else if (GEQs[e].coef[i] < 0) {
+ GEQs[e].varCount ++;
+ if (onlyUB == -1) onlyUB = e;
+ else onlyUB = -2;
+ }
+ if (onlyUB >= 0) {
+ if (DBUG) {
+ fprintf(outputFile,"only UB: ");
+ printGEQ(&GEQs[onlyUB]);
+ fprintf(outputFile,"\n");
+ }
+ GEQs[onlyUB].essential = 1;
+ }
+ if (onlyLB >= 0) {
+ if (DBUG) {
+ fprintf(outputFile,"only LB: ");
+ printGEQ(&GEQs[onlyLB]);
+ fprintf(outputFile,"\n");
+ }
+ GEQs[onlyLB].essential = 1;
+ }
+ }
+ for (int e = nGEQs - 1; e >= 0; e--)
+ if (!GEQs[e].essential && GEQs[e].varCount > 1) {
+ int i1,i2,i3;
+ for (i1 = nVars; i1 >= 1; i1--) if (GEQs[e].coef[i1]) break;
+ for (i2 = i1-1; i2 >= 1; i2--) if (GEQs[e].coef[i2]) break;
+ for (i3 = i2-1; i3 >= 1; i3--) if (GEQs[e].coef[i3]) break;
+ assert(i2 >= 1);
+ int e2;
+ for (e2 = nGEQs - 1; e2 >= 0; e2--)
+ if (e!=e2) {
+ coef_t crossProduct;
+ crossProduct = GEQs[e].coef[i1]*GEQs[e2].coef[i1];
+ crossProduct += GEQs[e].coef[i2]*GEQs[e2].coef[i2];
+ for (int i = i3; i >= 1; i--)
+ if (GEQs[e2].coef[i])
+ crossProduct += GEQs[e].coef[i]*GEQs[e2].coef[i];
+ if (crossProduct > 0) {
+ if (DBUG) fprintf(outputFile,"Cross product of %d and %d is " coef_fmt "\n", e, e2, crossProduct);
+ break;
+ }
+ }
+ if (e2 < 0) GEQs[e].essential = 1;
+ }
+ if (DBUG) {
+ fprintf(outputFile,"Computed essential equations\n");
+ fprintf(outputFile,"essential equations:\n");
+ for (int e = 0; e < nGEQs; e++)
+ if (GEQs[e].essential) {
+ printGEQ(&GEQs[e]);
+ fprintf(outputFile,"\n");
+ }
+ fprintf(outputFile,"potentially redundant equations:\n");
+ for (int e = 0; e < nGEQs; e++)
+ if (!GEQs[e].essential) {
+ printGEQ(&GEQs[e]);
+ fprintf(outputFile,"\n");
+ }
+ }
+}
+
+
+int Problem::findDifference(int e, int &v1, int &v2) {
+ // if 1 returned, eqn E is of form v1 -coef >= v2
+ for(v1=1;v1<=nVars;v1++)
+ if (GEQs[e].coef[v1]) break;
+ for(v2=v1+1;v2<=nVars;v2++)
+ if (GEQs[e].coef[v2]) break;
+ if (v2 > nVars) {
+ if (GEQs[e].coef[v1] == -1) {
+ v2 = v1;
+ v1 = 0;
+ return 1;
+ }
+ if (GEQs[e].coef[v1] == 1) {
+ v2 = 0;
+ return 1;
+ }
+ return 0;
+ }
+ if (GEQs[e].coef[v1] * GEQs[e].coef[v2] != -1) return 0;
+ if (GEQs[e].coef[v1] < 0) std::swap(v1,v2);
+ return 1;
+}
+
+
+namespace {
+ struct succListStruct {
+ int num;
+ int notEssential;
+ int var[maxVars];
+ coef_t diff[maxVars];
+ int eqn[maxVars];
+ };
+}
+
+
+int Problem::chainKill(int color, int onlyWildcards) {
+ int v1,v2,e;
+ int essentialPred[maxVars];
+ int redundant[maxmaxGEQs];
+ int inChain[maxVars];
+ int goodStartingPoint[maxVars];
+ int tryToEliminate[maxmaxGEQs];
+ int triedDoubleKill = 0;
+
+ succListStruct succ[maxVars];
+
+restart:
+
+ int anyToKill = 0;
+ int anyKilled = 0;
+ int canHandle = 0;
+
+ for(v1=0;v1<=nVars;v1++) {
+ succ[v1].num = 0;
+ succ[v1].notEssential = 0;
+ goodStartingPoint[v1] = 0;
+ inChain[v1] = -1;
+ essentialPred[v1] = 0;
+ }
+
+ int essentialEquations = 0;
+ for (e = 0; e < nGEQs; e++) {
+ redundant[e] = 0;
+ tryToEliminate[e] = !GEQs[e].essential;
+ if (GEQs[e].essential) essentialEquations++;
+ if (color && !GEQs[e].color) tryToEliminate[e] = 0;
+ }
+ if (essentialEquations == nGEQs) return 0;
+ if (2*essentialEquations < nVars) return 1;
+
+ for (e = 0; e < nGEQs; e++)
+ if (tryToEliminate[e] && GEQs[e].varCount <= 2 && findDifference(e,v1,v2)) {
+ assert(v1 == 0 || GEQs[e].coef[v1] == 1);
+ assert(v2 == 0 || GEQs[e].coef[v2] == -1);
+ succ[v2].notEssential++;
+ int s = succ[v2].num++;
+ succ[v2].eqn[s] = e;
+ succ[v2].var[s] = v1;
+ succ[v2].diff[s] = -GEQs[e].coef[0];
+ goodStartingPoint[v2] = 1;
+ anyToKill++;
+ canHandle++;
+ }
+ if (!anyToKill) {
+ return canHandle < nGEQs;
+ }
+ for (e = 0; e < nGEQs; e++)
+ if (!tryToEliminate[e] && GEQs[e].varCount <= 2 && findDifference(e,v1,v2)) {
+ assert(v1 == 0 || GEQs[e].coef[v1] == 1);
+ assert(v2 == 0 || GEQs[e].coef[v2] == -1);
+ int s = succ[v2].num++;
+ essentialPred[v1]++;
+ succ[v2].eqn[s] = e;
+ succ[v2].var[s] = v1;
+ succ[v2].diff[s] = -GEQs[e].coef[0];
+ canHandle++;
+ }
+
+
+ if (DBUG) {
+ int s;
+ fprintf(outputFile,"In chainkill: [\n");
+ for(v1 = 0;v1<=nVars;v1++) {
+ fprintf(outputFile,"#%d <= %s: ",essentialPred[v1],variable(v1));
+ for(s=0;s<succ[v1].notEssential;s++)
+ fprintf(outputFile," %s(" coef_fmt ") ",variable(succ[v1].var[s]), succ[v1].diff[s]);
+ for(;s<succ[v1].num;s++)
+ fprintf(outputFile," %s[" coef_fmt "] ",variable(succ[v1].var[s]), succ[v1].diff[s]);
+ fprintf(outputFile,"\n");
+ }
+ }
+
+ for(;v1<=nVars;v1++)
+ if (succ[v1].num == 1 && succ[v1].notEssential == 1) {
+ succ[v1].notEssential--;
+ essentialPred[succ[v1].var[succ[v1].notEssential]]++;
+ }
+
+ if (DBUG) fprintf(outputFile,"Trying quick double kill:\n");
+ int s1a,s1b,s2;
+ int v3;
+ for(v1 = 0;v1<=nVars;v1++)
+ for(s1a=0;s1a<succ[v1].notEssential;s1a++) {
+ v3 = succ[v1].var[s1a];
+ for(s1b=0;s1b<succ[v1].num;s1b++)
+ if (s1a != s1b) {
+ v2 = succ[v1].var[s1b];
+ for(s2=0;s2<succ[v2].num;s2++)
+ if (succ[v2].var[s2] == v3 && succ[v1].diff[s1b] + succ[v2].diff[s2] >= succ[v1].diff[s1a]) {
+ if (DBUG) {
+ fprintf(outputFile,"quick double kill: ");
+ printGEQ(&GEQs[succ[v1].eqn[s1a]]);
+ fprintf(outputFile,"\n");
+ }
+ redundant[succ[v1].eqn[s1a]] = 1;
+ anyKilled++;
+ anyToKill--;
+ goto nextVictim;
+ }
+ }
+ nextVictim: v1 = v1;
+ }
+ if (anyKilled) {
+ for (e = nGEQs-1; e >= 0;e--)
+ if (redundant[e]) {
+ if (DBUG) {
+ fprintf(outputFile,"Deleting ");
+ printGEQ(&GEQs[e]);
+ fprintf(outputFile,"\n");
+ }
+ deleteGEQ(e);
+ }
+
+ if (!anyToKill) return canHandle < nGEQs;
+ noteEssential(onlyWildcards);
+ triedDoubleKill = 1;
+ goto restart;
+ }
+
+ for(v1 = 0;v1<=nVars;v1++)
+ if (succ[v1].num == succ[v1].notEssential && succ[v1].notEssential > 0) {
+ succ[v1].notEssential--;
+ essentialPred[succ[v1].var[succ[v1].notEssential]]++;
+ }
+
+ while (1) {
+ int chainLength;
+ int chain[maxVars];
+ coef_t distance[maxVars];
+ // pick a place to start
+ for(v1 = 0;v1<=nVars;v1++)
+ if (essentialPred[v1] == 0 && succ[v1].num > succ[v1].notEssential)
+ break;
+ if (v1 > nVars)
+ for(v1 = 0;v1<=nVars;v1++)
+ if (goodStartingPoint[v1] && succ[v1].num > succ[v1].notEssential)
+ break;
+ if (v1 > nVars) break;
+
+ chainLength = 1;
+ chain[0] = v1;
+ distance[0] = 0;
+ inChain[v1] = 0;
+ int s;
+
+ while (succ[v1].num > succ[v1].notEssential) {
+ s = succ[v1].num-1;
+ if (inChain[succ[v1].var[s]] >= 0) {
+ // Found cycle, don't do anything with them yet
+ break;
+ }
+ succ[v1].num = s;
+
+ distance[chainLength]= distance[chainLength-1] + succ[v1].diff[s];
+ v1 = chain[chainLength] = succ[v1].var[s];
+ essentialPred[v1]--;
+ assert(essentialPred[v1] >= 0);
+ inChain[v1] = chainLength;
+ chainLength++;
+ }
+
+
+ int c;
+ if (DBUG) {
+ fprintf(outputFile,"Found chain: \n");
+ for (c = 0; c < chainLength; c++)
+ fprintf(outputFile,"%s:" coef_fmt " ",variable(chain[c]), distance[c]);
+ fprintf(outputFile,"\n");
+ }
+
+
+ for (c = 0; c < chainLength; c++) {
+ v1 = chain[c];
+ for(s=0;s<succ[v1].notEssential;s++) {
+ if (DBUG)
+ fprintf(outputFile,"checking for %s + " coef_fmt " <= %s \n", variable(v1), succ[v1].diff[s], variable(succ[v1].var[s]));
+ if (inChain[succ[v1].var[s]] > c+1) {
+ if (DBUG)
+ fprintf(outputFile,"%s + " coef_fmt " <= %s is in chain\n", variable(v1), distance[inChain[succ[v1].var[s]]]- distance[c], variable(succ[v1].var[s]));
+ if ( distance[inChain[succ[v1].var[s]]]- distance[c] >= succ[v1].diff[s]) {
+ if (DBUG)
+ fprintf(outputFile,"%s + " coef_fmt " <= %s is redundant\n", variable(v1),succ[v1].diff[s], variable(succ[v1].var[s]));
+ redundant[succ[v1].eqn[s]] = 1;
+ }
+ }
+ }
+ }
+ for (c = 0; c < chainLength; c++)
+ inChain[chain[c]] = -1;
+ }
+
+ for (e = nGEQs-1; e >= 0;e--)
+ if (redundant[e]) {
+ if (DBUG) {
+ fprintf(outputFile,"Deleting ");
+ printGEQ(&GEQs[e]);
+ fprintf(outputFile,"\n");
+ }
+ deleteGEQ(e);
+ anyKilled = 1;
+ }
+
+ if (anyKilled) noteEssential(onlyWildcards);
+
+ if (anyKilled && DBUG) {
+ fprintf(outputFile,"\nResult:\n");
+ printProblem();
+ }
+ if (DBUG) {
+ fprintf(outputFile,"] end chainkill\n");
+ printProblem();
+ }
+ return canHandle < nGEQs;
+}
+
+
+namespace {
+ struct varCountStruct {
+ int e;
+ int safeVarCount;
+ int wildVarCount;
+ varCountStruct(int e_, int count1_, int count2_) {
+ e = e_;
+ safeVarCount = count1_;
+ wildVarCount = count2_; }
+ };
+ bool operator<(const varCountStruct &a, const varCountStruct &b) {
+ if (a.wildVarCount < b.wildVarCount)
+ return true;
+ else if (a.wildVarCount > b.wildVarCount)
+ return false;
+ else
+ return a.safeVarCount < b.safeVarCount;
+ }
+}
+
+
+//
+// Deduct redundant inequalities by combination of any two inequalities.
+// Return value: 0 (no solution),
+// 1 (nothing killed),
+// 2 (some inequality killed).
+//
+int Problem::quickKill(int onlyWildcards, bool desperate) {
+ if (!onlyWildcards && !combineToTighten())
+ return 0;
+ noteEssential(onlyWildcards);
+ int moreToDo = chainKill(0, onlyWildcards);
+
+#ifdef NDEBUG
+ if (!moreToDo) return 1;
+#endif
+
+
+ if (!desperate && nGEQs > 256) { // original 60, increased by chun
+ if (TRACE) {
+ fprintf(outputFile, "%d inequalities are too complicated to quick kill\n", nGEQs);
+ }
+ return 1;
+ }
+
+ if (DBUG) {
+ fprintf(outputFile, "in eliminate Redudant:\n");
+ printProblem();
+ }
+
+ int isDead[nGEQs];
+ std::vector<varCountStruct> killOrder;
+ std::vector<BoolSet<> > P(nGEQs, BoolSet<>(nVars)), Z(nGEQs, BoolSet<>(nVars)), N(nGEQs, BoolSet<>(nVars));
+ BoolSet<> PP, PZ, PN; // possible Positives, possible zeros & possible negatives
+
+ for (int e = nGEQs - 1; e >= 0; e--) {
+ isDead[e] = 0;
+ int safeVarCount = 0;
+ int wildVarCount = 0;
+ for (int i = nVars; i >= 1; i--) {
+ if (GEQs[e].coef[i] == 0)
+ Z[e].set(i-1);
+ else {
+ if (i > safeVars)
+ wildVarCount++;
+ else
+ safeVarCount++;
+ if (GEQs[e].coef[i] < 0)
+ N[e].set(i-1);
+ else
+ P[e].set(i-1);
+ }
+ }
+
+ if (!GEQs[e].essential || wildVarCount > 0)
+ killOrder.push_back(varCountStruct(e, safeVarCount, wildVarCount));
+ }
+
+ sort(killOrder.begin(), killOrder.end());
+
+ if (DEBUG) {
+ fprintf(outputFile,"Prefered kill order:\n");
+ for (int e3I = killOrder.size()-1; e3I >= 0; e3I--) {
+ fprintf(outputFile,"%2d: ",nGEQs-1-e3I);
+ printGEQ(&GEQs[killOrder[e3I].e]);
+ fprintf(outputFile,"\n");
+ }
+ }
+
+ int e3U = killOrder.size()-1;
+ while (e3U >= 0) {
+ // each round of elimination is for inequalities of same complexity and rounds are at descending complexity order
+ int e3L = e3U-1;
+ for(; e3L >= 0; e3L--)
+ if (killOrder[e3L].safeVarCount+killOrder[e3L].wildVarCount != killOrder[e3U].safeVarCount + killOrder[e3U].wildVarCount)
+ break;
+
+ // check if e3 can be eliminated from combination of e1 and e2
+ for (int e1 = 0; e1 < nGEQs; e1++)
+ if (!isDead[e1])
+ for (int e2 = e1+1; e2 < nGEQs; e2++)
+ if (!isDead[e2]) {
+ coef_t alpha = 0;
+ int p, q;
+ for (p = nVars; p > 1; p--)
+ for (q = p - 1; q > 0; q--) {
+ try {
+ alpha = check_mul(GEQs[e1].coef[p], GEQs[e2].coef[q]) - check_mul(GEQs[e2].coef[p], GEQs[e1].coef[q]);
+ }
+ catch (std::overflow_error) {
+ continue;
+ }
+ if (alpha != 0)
+ goto foundPQ;
+ }
+ continue;
+
+ foundPQ:
+ PZ = (Z[e1] & Z[e2]) | (P[e1] & N[e2]) | (N[e1] & P[e2]);
+ PP = P[e1] | P[e2];
+ PN = N[e1] | N[e2];
+ if (DEBUG) {
+ fprintf(outputFile,"Considering combination of ");
+ printGEQ(&(GEQs[e1]));
+ fprintf(outputFile," and ");
+ printGEQ(&(GEQs[e2]));
+ fprintf(outputFile,"\n");
+ }
+
+ for (int e3I = e3U; e3I > e3L; e3I--) {
+ int e3 = killOrder[e3I].e;
+ if (!isDead[e3] && e3 != e1 && e3 != e2)
+ try {
+ coef_t alpha1, alpha2, alpha3;
+
+ if (!PZ.imply(Z[e3]))
+ goto nextE3;
+
+ alpha1 = check_mul(GEQs[e2].coef[q], GEQs[e3].coef[p]) - check_mul(GEQs[e2].coef[p], GEQs[e3].coef[q]);
+ alpha2 = -(check_mul(GEQs[e1].coef[q], GEQs[e3].coef[p]) - check_mul(GEQs[e1].coef[p], GEQs[e3].coef[q]));
+ alpha3 = alpha;
+
+ if (alpha1 < 0) {
+ alpha1 = -alpha1;
+ alpha2 = -alpha2;
+ alpha3 = -alpha3;
+ }
+ if (alpha1 == 0 || alpha2 <= 0)
+ goto nextE3;
+
+ {
+ coef_t g = gcd(gcd(alpha1, alpha2), abs(alpha3));
+ alpha1 /= g;
+ alpha2 /= g;
+ alpha3 /= g;
+ }
+
+ if (DEBUG) {
+ fprintf(outputFile, coef_fmt "e1 + " coef_fmt "e2 = " coef_fmt "e3: ",alpha1,alpha2,alpha3);
+ printGEQ(&(GEQs[e3]));
+ fprintf(outputFile,"\n");
+ }
+
+ if (alpha3 > 0) { // trying to prove e3 is redundant
+ if (!GEQs[e3].color && (GEQs[e1].color || GEQs[e2].color)) {
+ goto nextE3;
+ }
+ if (!PP.imply(P[e3]) | !PN.imply(N[e3]))
+ goto nextE3;
+
+ // verify alpha1*v1+alpha2*v2 = alpha3*v3
+ for (int k = nVars; k >= 1; k--)
+ if (check_mul(alpha3, GEQs[e3].coef[k]) != check_mul(alpha1, GEQs[e1].coef[k]) + check_mul(alpha2, GEQs[e2].coef[k]))
+ goto nextE3;
+
+ coef_t c = check_mul(alpha1, GEQs[e1].coef[0]) + check_mul(alpha2, GEQs[e2].coef[0]);
+ if (c < check_mul(alpha3, (GEQs[e3].coef[0] + 1))) {
+ if (DBUG) {
+ fprintf(outputFile, "found redundant inequality\n");
+ fprintf(outputFile, "alpha1, alpha2, alpha3 = " coef_fmt "," coef_fmt "," coef_fmt "\n", alpha1, alpha2, alpha3);
+ printGEQ(&(GEQs[e1]));
+ fprintf(outputFile, "\n");
+ printGEQ(&(GEQs[e2]));
+ fprintf(outputFile, "\n=> ");
+ printGEQ(&(GEQs[e3]));
+ fprintf(outputFile, "\n\n");
+ assert(moreToDo);
+ }
+
+ isDead[e3] = 1;
+ }
+ }
+ else { // trying to prove e3 <= 0 or e3 = 0
+ if (!PN.imply(P[e3]) | !PP.imply(N[e3]))
+ goto nextE3;
+
+ // verify alpha1*v1+alpha2*v2 = alpha3*v3
+ for (int k = nVars; k >= 1; k--)
+ if (check_mul(alpha3, GEQs[e3].coef[k]) != check_mul(alpha1, GEQs[e1].coef[k]) + check_mul(alpha2, GEQs[e2].coef[k]))
+ goto nextE3;
+
+ if (DEBUG) {
+ fprintf(outputFile,"All but constant term checked\n");
+ }
+ coef_t c = check_mul(alpha1, GEQs[e1].coef[0]) + check_mul(alpha2, GEQs[e2].coef[0]);
+ if (DEBUG) {
+ fprintf(outputFile,"All but constant term checked\n");
+ fprintf(outputFile,"Constant term is " coef_fmt " vs " coef_fmt "\n",
+ alpha3*GEQs[e3].coef[0],
+ alpha3*(GEQs[e3].coef[0]-1));
+ }
+ if (c < check_mul(alpha3, (GEQs[e3].coef[0]))) {
+ // we just proved e3 < 0, so no solutions exist
+ if (DBUG) {
+ fprintf(outputFile, "found implied over tight inequality\n");
+ fprintf(outputFile, "alpha1, alpha2, alpha3 = " coef_fmt "," coef_fmt "," coef_fmt "\n", alpha1, alpha2, -alpha3);
+ printGEQ(&(GEQs[e1]));
+ fprintf(outputFile, "\n");
+ printGEQ(&(GEQs[e2]));
+ fprintf(outputFile, "\n=> not ");
+ printGEQ(&(GEQs[e3]));
+ fprintf(outputFile, "\n\n");
+ }
+ return 0;
+ }
+ else if (!GEQs[e3].color && (GEQs[e1].color || GEQs[e2].color)) {
+ goto nextE3;
+ }
+ else if (c < check_mul(alpha3, (GEQs[e3].coef[0] - 1))) {
+ // we just proved e3 <= 0, so e3 = 0
+ if (DBUG) {
+ fprintf(outputFile, "found implied tight inequality\n");
+ fprintf(outputFile, "alpha1, alpha2, alpha3 = " coef_fmt "," coef_fmt "," coef_fmt "\n", alpha1, alpha2, -alpha3);
+ printGEQ(&(GEQs[e1]));
+ fprintf(outputFile, "\n");
+ printGEQ(&(GEQs[e2]));
+ fprintf(outputFile, "\n=> inverse ");
+ printGEQ(&(GEQs[e3]));
+ fprintf(outputFile, "\n\n");
+ }
+ int neweq = newEQ();
+ eqnncpy(&EQs[neweq], &GEQs[e3], nVars);
+ addingEqualityConstraint(neweq);
+ isDead[e3] = 1;
+ }
+ }
+ nextE3:;
+ }
+ catch (std::overflow_error) {
+ continue;
+ }
+ }
+ }
+
+ e3U = e3L;
+ }
+
+ bool anything_killed = false;
+ for (int e = nGEQs - 1; e >= 0; e--) {
+ if (isDead[e]) {
+ anything_killed = true;
+ deleteGEQ(e);
+ }
+ }
+
+ if (DBUG) {
+ fprintf(outputFile,"\nResult:\n");
+ printProblem();
+ }
+
+ if (anything_killed)
+ return 2;
+ else
+ return 1;
+}
+
+} // namespace
diff --git a/omegalib/omega/src/omega_core/oc_simple.cc b/omegalib/omega/src/omega_core/oc_simple.cc
new file mode 100644
index 0000000..0e492db
--- /dev/null
+++ b/omegalib/omega/src/omega_core/oc_simple.cc
@@ -0,0 +1,1373 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 the Omega Project Team
+ Copyright (C) 2005-2011 Chun Chen
+ All Rights Reserved.
+
+ Purpose:
+ Support functions for solving a problem.
+
+ Notes:
+
+ History:
+ 10/13/08 Complete back substitution process, Chun Chen.
+ 05/28/09 Extend normalize process to handle redundancy involving
+ wilddcards, Chun Chen
+*****************************************************************************/
+
+#include <omega/omega_core/oc_i.h>
+#include <basic/BoolSet.h>
+#include <algorithm>
+#include <vector>
+
+namespace omega {
+
+int checkIfSingleVar(eqn* e, int i) {
+ for (; i > 0; i--)
+ if (e->coef[i]) {
+ i--;
+ break;
+ }
+ for (; i > 0; i--)
+ if (e->coef[i])
+ break;
+ return (i == 0);
+}
+
+
+int singleVarGEQ(eqn* e) {
+ return !e->touched && e->key != 0 && -maxVars <= e->key && e->key <= maxVars;
+}
+
+
+void checkVars(int nVars) {
+ if (nVars > maxVars) {
+ fprintf(stderr, "\nERROR:\n");
+ fprintf(stderr, "An attempt was made to create a conjunction with %d variables.\n", nVars);
+ fprintf(stderr, "The current limit on variables in a single conjunction is %d.\n", maxVars);
+ fprintf(stderr, "This limit can be changed by changing the #define of maxVars in oc.h.\n\n");
+ exit(2);
+ }
+}
+
+
+void Problem::difficulty(int &numberNZs, coef_t &maxMinAbsCoef, coef_t &sumMinAbsCoef) const {
+ numberNZs=0;
+ maxMinAbsCoef=0;
+ sumMinAbsCoef=0;
+ for (int e = 0; e < nGEQs; e++) {
+ coef_t maxCoef = 0;
+ for(int i = 1;i <= nVars;i++)
+ if (GEQs[e].coef[i]!=0) {
+ coef_t a = abs(GEQs[e].coef[i]);
+ maxCoef = max(maxCoef,a);
+ numberNZs++;
+ }
+ coef_t nextCoef = 0;
+ for(int i = 1;i <= nVars;i++)
+ if (GEQs[e].coef[i]!=0) {
+ coef_t a = abs(GEQs[e].coef[i]);
+ if (a < maxCoef) nextCoef = max(nextCoef,a);
+ else if (a == maxCoef) maxCoef = 0x7fffffff;
+ }
+ maxMinAbsCoef = max(maxMinAbsCoef,nextCoef);
+ sumMinAbsCoef += nextCoef;
+ }
+
+ for (int e = 0; e < nEQs; e++) {
+ coef_t maxCoef = 0;
+ for(int i = 1;i <= nVars;i++)
+ if (EQs[e].coef[i]!=0) {
+ coef_t a = abs(EQs[e].coef[i]);
+ maxCoef = max(maxCoef,a);
+ numberNZs++;
+ }
+ coef_t nextCoef = 0;
+ for(int i = 1;i <= nVars;i++)
+ if (EQs[e].coef[i]!=0) {
+ coef_t a = abs(EQs[e].coef[i]);
+ if (a < maxCoef) nextCoef = max(nextCoef,a);
+ else if (a == maxCoef) maxCoef = 0x7fffffff;
+ }
+ maxMinAbsCoef = max(maxMinAbsCoef,nextCoef);
+ sumMinAbsCoef += nextCoef;
+ }
+}
+
+int Problem::countRedGEQs() const {
+ int result = 0;
+ for (int e = 0; e < nGEQs; e++)
+ if (GEQs[e].color == EQ_RED) result++;
+ return result;
+}
+
+int Problem::countRedEQs() const {
+ int result = 0;
+ for (int e = 0; e < nEQs; e++)
+ if (EQs[e].color == EQ_RED) result++;
+ return result;
+}
+
+int Problem::countRedEquations() const {
+ int result = 0;
+ for (int e = 0; e < nEQs; e++)
+ if (EQs[e].color == EQ_RED) {
+ int i;
+ for (i = nVars; i > 0; i--) if (EQs[e].coef[i]) break;
+ if (i == 0 && EQs[e].coef[0] != 0) return 0;
+ else result+=2;
+ }
+ for (int e = 0; e < nGEQs; e++)
+ if (GEQs[e].color == EQ_RED) result+=1;
+ for (int e = 0; e < nMemories; e++)
+ switch(redMemory[e].kind ) {
+ case redEQ:
+ case redStride:
+ e++;
+ case redLEQ:
+ case redGEQ:
+ e++;
+ case notRed:
+ ; /* avoid warning about notRed not handled */
+ }
+ return result;
+}
+
+void Problem::deleteBlack() {
+ int RedVar[maxVars];
+ for(int i = safeVars+1;i <= nVars;i++) RedVar[i] = 0;
+
+ assert(nSUBs == 0);
+
+ for (int e = nEQs-1; e >= 0; e--)
+ if (EQs[e].color != EQ_RED) {
+ eqnncpy(&EQs[e],&EQs[nEQs-1], nVars);
+ nEQs--;
+ }
+ else
+ for(int i = safeVars+1;i <= nVars;i++)
+ if (EQs[e].coef[i]) RedVar[i] = 1;
+
+ for (int e = nGEQs-1; e >= 0; e--)
+ if (GEQs[e].color != EQ_RED) {
+ eqnncpy(&GEQs[e],&GEQs[nGEQs-1], nVars);
+ nGEQs--;
+ }
+ else
+ for(int i = safeVars+1;i <= nVars;i++)
+ if (GEQs[e].coef[i]) RedVar[i] = 1;
+
+ assert(nSUBs == 0);
+
+ for(int i = nVars; i > safeVars;i--) {
+ if (!RedVar[i]) deleteVariable(i);
+ }
+}
+
+
+void Problem::deleteRed() {
+ int BlackVar[maxVars];
+ for(int i = safeVars+1;i <= nVars;i++) BlackVar[i] = 0;
+
+ assert(nSUBs == 0);
+ for (int e = nEQs-1; e >=0; e--)
+ if (EQs[e].color) {
+ eqnncpy(&EQs[e],&EQs[nEQs-1], nVars);
+ nEQs--;
+ }
+ else
+ for(int i = safeVars+1;i <= nVars;i++)
+ if (EQs[e].coef[i]) BlackVar[i] = 1;
+
+ for (int e = nGEQs-1; e >=0; e--)
+ if (GEQs[e].color) {
+ eqnncpy(&GEQs[e],&GEQs[nGEQs-1], nVars);
+ nGEQs--;
+ }
+ else
+ for(int i = safeVars+1;i <= nVars;i++)
+ if (GEQs[e].coef[i]) BlackVar[i] = 1;
+
+ assert(nSUBs == 0);
+
+ for(int i = nVars; i> safeVars;i--) {
+ if (!BlackVar[i]) deleteVariable(i);
+ }
+}
+
+
+void Problem::turnRedBlack() {
+ for (int e = nEQs-1; e >= 0; e--) EQs[e].color = 0;
+ for (int e = nGEQs-1; e >= 0; e--) GEQs[e].color = 0;
+}
+
+
+void Problem::useWildNames() {
+ for(int i = safeVars+1; i <= nVars; i++) nameWildcard(i);
+}
+
+
+void negateCoefficients(eqn* eqn, int nVars) {
+ for (int i = nVars; i >= 0; i--)
+ eqn-> coef[i] = -eqn->coef[i];
+ eqn->touched = true;
+}
+
+
+void Problem::negateGEQ(int e) {
+ negateCoefficients(&GEQs[e],nVars);
+ GEQs[e].coef[0]--;
+}
+
+
+void Problem:: deleteVariable(int i) {
+ if (i < safeVars) {
+ int j = safeVars;
+ for (int e = nGEQs - 1; e >= 0; e--) {
+ GEQs[e].touched = true;
+ GEQs[e].coef[i] = GEQs[e].coef[j];
+ GEQs[e].coef[j] = GEQs[e].coef[nVars];
+ }
+ for (int e = nEQs - 1; e >= 0; e--) {
+ EQs[e].coef[i] = EQs[e].coef[j];
+ EQs[e].coef[j] = EQs[e].coef[nVars];
+ }
+ for (int e = nSUBs - 1; e >= 0; e--) {
+ SUBs[e].coef[i] = SUBs[e].coef[j];
+ SUBs[e].coef[j] = SUBs[e].coef[nVars];
+ }
+ var[i] = var[j];
+ var[j] = var[nVars];
+ }
+ else if (i < nVars) {
+ for (int e = nGEQs - 1; e >= 0; e--)
+ if (GEQs[e].coef[nVars]) {
+ GEQs[e].coef[i] = GEQs[e].coef[nVars];
+ GEQs[e].touched = true;
+ }
+ for (int e = nEQs - 1; e >= 0; e--)
+ EQs[e].coef[i] = EQs[e].coef[nVars];
+ for (int e = nSUBs - 1; e >= 0; e--)
+ SUBs[e].coef[i] = SUBs[e].coef[nVars];
+ var[i] = var[nVars];
+ }
+ if (i <= safeVars)
+ safeVars--;
+ nVars--;
+}
+
+
+void Problem::setInternals() {
+ if (!variablesInitialized) {
+ initializeVariables();
+ }
+
+ var[0] = 0;
+ nextWildcard = 0;
+ for(int i = 1;i <= nVars;i++)
+ if (var[i] < 0)
+ var[i] = --nextWildcard;
+
+ assert(nextWildcard >= -maxWildcards);
+
+ CHECK_FOR_DUPLICATE_VARIABLE_NAMES;
+
+ int v = nSUBs;
+ for(int i = 1;i <= safeVars;i++) if (var[i] > 0) v++;
+ varsOfInterest = v;
+
+ if (nextKey * 3 > maxKeys) {
+ omega::hashVersion++;
+ nextKey = maxVars + 1;
+ for (int e = nGEQs - 1; e >= 0; e--)
+ GEQs[e].touched = true;
+ for (int i = 0; i < hashTableSize; i++)
+ hashMaster[i].touched = -1;
+ hashVersion = omega::hashVersion;
+ }
+ else if (hashVersion != omega::hashVersion) {
+ for (int e = nGEQs - 1; e >= 0; e--)
+ GEQs[e].touched = true;
+ hashVersion = omega::hashVersion;
+ }
+}
+
+
+void Problem::setExternals() {
+ for (int i = 1; i <= safeVars; i++)
+ forwardingAddress[var[i]] = i;
+ for (int i = 0; i < nSUBs; i++)
+ forwardingAddress[SUBs[i].key] = -i - 1;
+}
+
+
+void setOutputFile(FILE * file) {
+ /* sets the file to which printProblem should send its output to "file" */
+
+ outputFile = file;
+}
+
+
+void setPrintLevel(int level) {
+ /* Sets the nber of points printed before constraints in printProblem */
+ headerLevel = level;
+}
+
+
+void Problem::putVariablesInStandardOrder() {
+ for(int i = 1;i <= safeVars;i++) {
+ int b = i;
+ for(int j=i+1;j<=safeVars;j++) {
+ if (var[b] < var[j]) b = j;
+ }
+ if (b != i) swapVars(i,b);
+ }
+}
+
+
+void Problem::nameWildcard(int i) {
+ int j;
+ do {
+ --nextWildcard;
+ if (nextWildcard < -maxWildcards)
+ nextWildcard = -1;
+ var[i] = nextWildcard;
+ for(j = nVars; j > 0;j--) if (i!=j && var[j] == nextWildcard) break;
+ } while (j != 0);
+}
+
+
+int Problem::protectWildcard(int i) {
+ assert (i > safeVars);
+ if (i != safeVars+1) swapVars(i,safeVars+1);
+ safeVars++;
+ nameWildcard(safeVars);
+ return safeVars;
+}
+
+
+int Problem::addNewProtectedWildcard() {
+ int i = ++safeVars;
+ nVars++;
+ if (nVars != i) {
+ for (int e = nGEQs - 1; e >= 0; e--) {
+ if (GEQs[e].coef[i] != 0)
+ GEQs[e].touched = true;
+ GEQs[e].coef[nVars] = GEQs[e].coef[i];
+ }
+ for (int e = nEQs - 1; e >= 0; e--) {
+ EQs[e].coef[nVars] = EQs[e].coef[i];
+ }
+ for (int e = nSUBs - 1; e >= 0; e--) {
+ SUBs[e].coef[nVars] = SUBs[e].coef[i];
+ }
+ var[nVars] = var[i];
+ }
+ for (int e = nGEQs - 1; e >= 0; e--)
+ GEQs[e].coef[i] = 0;
+ for (int e = nEQs - 1; e >= 0; e--)
+ EQs[e].coef[i] = 0;
+ for (int e = nSUBs - 1; e >= 0; e--)
+ SUBs[e].coef[i] = 0;
+ nameWildcard(i);
+ return (i);
+}
+
+
+int Problem::addNewUnprotectedWildcard() {
+ int i = ++nVars;
+ for (int e = nGEQs - 1; e >= 0; e--) GEQs[e].coef[i] = 0;
+ for (int e = nEQs - 1; e >= 0; e--) EQs[e].coef[i] = 0;
+ for (int e = nSUBs - 1; e >= 0; e--) SUBs[e].coef[i] = 0;
+ nameWildcard(i);
+ return i;
+}
+
+
+void Problem::cleanoutWildcards() {
+ bool renormalize = false;
+
+ // substituting wildcard equality
+ for (int e = nEQs-1; e >= 0; e--) {
+ for (int i = nVars; i >= safeVars+1; i--)
+ if (EQs[e].coef[i] != 0) {
+ coef_t c = EQs[e].coef[i];
+ coef_t a = abs(c);
+
+ bool preserveThisConstraint = true;
+ for (int e2 = nEQs-1; e2 >= 0; e2--)
+ if (e2 != e && EQs[e2].coef[i] != 0 && EQs[e2].color >= EQs[e].color) {
+ preserveThisConstraint = preserveThisConstraint && (gcd(a,abs(EQs[e2].coef[i])) != 1);
+ coef_t k = lcm(a, abs(EQs[e2].coef[i]));
+ coef_t coef1 = (EQs[e2].coef[i]>0?1:-1) * k / c;
+ coef_t coef2 = k / abs(EQs[e2].coef[i]);
+ for (int j = nVars; j >= 0; j--)
+ EQs[e2].coef[j] = EQs[e2].coef[j] * coef2 - EQs[e].coef[j] * coef1;
+
+ coef_t g = 0;
+ for (int j = nVars; j >= 0; j--) {
+ g = gcd(abs(EQs[e2].coef[j]), g);
+ if (g == 1)
+ break;
+ }
+ if (g != 0 && g != 1)
+ for (int j = nVars; j >= 0; j--)
+ EQs[e2].coef[j] /= g;
+ }
+
+ for (int e2 = nGEQs-1; e2 >= 0; e2--)
+ if (GEQs[e2].coef[i] != 0 && GEQs[e2].color >= EQs[e].color) {
+ coef_t k = lcm(a, abs(GEQs[e2].coef[i]));
+ coef_t coef1 = (GEQs[e2].coef[i]>0?1:-1) * k / c;
+ coef_t coef2 = k / abs(GEQs[e2].coef[i]);
+ for (int j = nVars; j >= 0; j--)
+ GEQs[e2].coef[j] = GEQs[e2].coef[j] * coef2 - EQs[e].coef[j] * coef1;
+
+ GEQs[e2].touched = 1;
+ renormalize = true;
+ }
+
+ for (int e2 = nSUBs-1; e2 >= 0; e2--)
+ if (SUBs[e2].coef[i] != 0 && SUBs[e2].color >= EQs[e].color) {
+ coef_t k = lcm(a, abs(SUBs[e2].coef[i]));
+ coef_t coef1 = (SUBs[e2].coef[i]>0?1:-1) * k / c;
+ coef_t coef2 = k / abs(SUBs[e2].coef[i]);
+ for (int j = nVars; j >= 0; j--)
+ SUBs[e2].coef[j] = SUBs[e2].coef[j] * coef2 - EQs[e].coef[j] * coef1;
+
+ coef_t g = 0;
+ for (int j = nVars; j >= 0; j--) {
+ g = gcd(abs(SUBs[e2].coef[j]), g);
+ if (g == 1)
+ break;
+ }
+ if (g != 0 && g != 1)
+ for (int j = nVars; j >= 0; j--)
+ SUBs[e2].coef[j] /= g;
+ }
+
+ // remove redundent wildcard equality
+ if (!preserveThisConstraint) {
+ if (e < nEQs-1)
+ eqnncpy (&EQs[e], &EQs[nEQs-1], nVars);
+ nEQs--;
+ deleteVariable(i);
+ }
+
+ break;
+ }
+ }
+
+ // remove multi-wildcard equality in approximation mode
+ if (inApproximateMode)
+ for (int e = nEQs-1; e >= 0; e--)
+ for (int i = nVars; i >= safeVars+1; i--)
+ if (EQs[e].coef[i] != 0) {
+ int j = i-1;
+ for (; j >= safeVars+1; j--)
+ if (EQs[e].coef[j] != 0)
+ break;
+
+ if (j != safeVars) {
+ if (e < nEQs-1)
+ eqnncpy (&EQs[e], &EQs[nEQs-1], nVars);
+ nEQs--;
+ }
+
+ break;
+ }
+
+ if (renormalize)
+ normalize();
+}
+
+
+void Problem:: check() const {
+#ifndef NDEBUG
+ int v = nSUBs;
+ checkVars(nVars+1);
+ for(int i = 1; i <= safeVars; i++) if (var[i] > 0) v++;
+ assert(v == varsOfInterest);
+ for(int e = 0; e < nGEQs; e++) assert(GEQs[e].touched || GEQs[e].key != 0);
+ if(!mayBeRed) {
+ for(int e = 0; e < nEQs; e++) assert(!EQs[e].color);
+ for(int e = 0; e < nGEQs; e++) assert(!GEQs[e].color);
+ }
+ else
+ for(int i = safeVars+1; i <= nVars; i++) {
+ int isBlack = 0;
+ int isRed = 0;
+ for(int e = 0; e < nEQs; e++)
+ if (EQs[e].coef[i]) {
+ if (EQs[e].color) isRed = 1;
+ else isBlack = 1;
+ }
+ for(int e = 0; e < nGEQs; e++)
+ if (GEQs[e].coef[i]) {
+ if (GEQs[e].color) isRed = 1;
+ else isBlack = 1;
+ }
+ if (isBlack && isRed && 0) {
+ fprintf(outputFile,"Mixed Red and Black variable:\n");
+ printProblem();
+ }
+ }
+#endif
+}
+
+
+void Problem::rememberRedConstraint(eqn *e, redType type, coef_t stride) {
+ // Check if this is really a stride constraint
+ if (type == redEQ && newVar == nVars && e->coef[newVar]) {
+ type = redStride;
+ stride = e->coef[newVar];
+ }
+ // else for(int i = safeVars+1; i <= nVars; i++) assert(!e->coef[i]); // outdated -- by chun 10/30/2008
+
+ assert(type != notRed);
+ assert(type == redStride || stride == 0);
+
+ if (TRACE) {
+ fprintf(outputFile,"being asked to remember red constraint:\n");
+ switch(type) {
+ case notRed: fprintf(outputFile,"notRed: ");
+ break;
+ case redGEQ: fprintf(outputFile,"Red: 0 <= ");
+ break;
+ case redLEQ: fprintf(outputFile,"Red: 0 >= ");
+ break;
+ case redEQ: fprintf(outputFile,"Red: 0 == ");
+ break;
+ case redStride: fprintf(outputFile,"Red stride " coef_fmt ": ",stride);
+ break;
+ }
+ printTerm(e,1);
+ fprintf(outputFile,"\n");
+ printProblem();
+ fprintf(outputFile,"----\n");
+ }
+
+ // Convert redLEQ to redGEQ
+ eqn mem;
+ eqnncpy(&mem,e, nVars);
+ e = &mem;
+ if (type == redLEQ) {
+ for(int i = 0; i <= safeVars; i++)
+ e->coef[i] = -e->coef[i];
+ type = redGEQ;
+ }
+
+ // Prepare coefficient array for red constraint
+ bool has_wildcard = false;
+ coef_t coef[varsOfInterest-nextWildcard+1];
+ for (int i = 0; i <= varsOfInterest-nextWildcard; i++)
+ coef[i] = 0;
+ for (int i = 0; i <= safeVars; i++) {
+ if (var[i] < 0) {
+ if (e->coef[i] != 0) {
+ coef[varsOfInterest-var[i]] = e->coef[i];
+ has_wildcard = true;
+ }
+ }
+ else
+ coef[var[i]] = e->coef[i];
+ }
+
+ // Sophisticated back substituion for wildcards, use Gaussian elimination
+ // as a fallback if no simple equations available. -- by chun 10/13/2008
+ if (has_wildcard) {
+ // Find substitutions involving wildcard
+ coef_t *repl_subs[nSUBs];
+ int num_wild_in_repl_subs[nSUBs];
+ int num_repl_subs = 0;
+ for (int i = 0; i < nSUBs; i++) {
+ int t = 0;
+ for (int j = 1; j <= safeVars; j++) {
+ if (var[j] < 0 && SUBs[i].coef[j] != 0)
+ t++;
+ }
+ if (t > 0) {
+ repl_subs[num_repl_subs] = new coef_t[varsOfInterest-nextWildcard+1];
+ for (int j = 0; j <= varsOfInterest-nextWildcard; j++)
+ repl_subs[num_repl_subs][j] = 0;
+
+ for (int k = 0; k <= safeVars; k++)
+ repl_subs[num_repl_subs][(var[k]<0)?varsOfInterest-var[k]:var[k]] = SUBs[i].coef[k];
+ repl_subs[num_repl_subs][SUBs[i].key] = -1;
+ num_wild_in_repl_subs[num_repl_subs] = t;
+ num_repl_subs++;
+ }
+ }
+
+ int wild_solved[-nextWildcard+1];
+ bool has_unsolved = false;
+ for (int i = 1; i <= -nextWildcard; i++) {
+ int minimum_wild = 0;
+ int pos;
+ for (int j = 0; j < num_repl_subs; j++)
+ if (repl_subs[j][varsOfInterest+i] != 0 && (minimum_wild == 0 || num_wild_in_repl_subs[j] < minimum_wild)) {
+ minimum_wild = num_wild_in_repl_subs[j];
+ pos = j;
+ }
+
+ if (minimum_wild == 0) {
+ wild_solved[i] = -1;
+ if (coef[varsOfInterest+i] != 0) {
+ fprintf(outputFile,"No feasible back substitutions available\n");
+ printProblem();
+ exit(1);
+ }
+ }
+ else if (minimum_wild == 1)
+ wild_solved[i] = pos;
+ else {
+ wild_solved[i] = -1;
+ if (coef[varsOfInterest+i] != 0)
+ has_unsolved = true;
+ }
+ }
+
+ // Gaussian elimination
+ while (has_unsolved) {
+ for (int i = 0; i < num_repl_subs; i++)
+ if (num_wild_in_repl_subs[i] > 1) {
+ for (int j = 1; j <= -nextWildcard; j++) {
+ if (repl_subs[i][varsOfInterest+j] != 0 && wild_solved[j] >= 0) {
+ int s = wild_solved[j];
+ coef_t l = lcm(abs(repl_subs[i][varsOfInterest+j]), abs(repl_subs[s][varsOfInterest+j]));
+ coef_t scale_1 = l/abs(repl_subs[i][varsOfInterest+j]);
+ coef_t scale_2 = l/abs(repl_subs[s][varsOfInterest+j]);
+ int sign = ((repl_subs[i][varsOfInterest+j]>0)?1:-1) * ((repl_subs[s][varsOfInterest+j]>0)?1:-1);
+ for (int k = 0; k <= varsOfInterest-nextWildcard; k++)
+ repl_subs[i][k] = scale_1*repl_subs[i][k] - sign*scale_2*repl_subs[s][k];
+ num_wild_in_repl_subs[i]--;
+ }
+ }
+
+ if (num_wild_in_repl_subs[i] == 1) {
+ for (int j = 1; j <= -nextWildcard; j++)
+ if (repl_subs[i][varsOfInterest+j] != 0) {
+ assert(wild_solved[j]==-1);
+ wild_solved[j] = i;
+ break;
+ }
+ }
+ else if (num_wild_in_repl_subs[i] > 1) {
+ int pos = 0;
+ for (int j = 1; j <= -nextWildcard; j++)
+ if (repl_subs[i][varsOfInterest+j] != 0) {
+ pos = j;
+ break;
+ }
+ assert(pos > 0);
+
+ for (int j = i+1; j < num_repl_subs; j++)
+ if (repl_subs[j][varsOfInterest+pos] != 0) {
+ coef_t l = lcm(abs(repl_subs[i][varsOfInterest+pos]), abs(repl_subs[j][varsOfInterest+pos]));
+ coef_t scale_1 = l/abs(repl_subs[i][varsOfInterest+pos]);
+ coef_t scale_2 = l/abs(repl_subs[j][varsOfInterest+pos]);
+ int sign = ((repl_subs[i][varsOfInterest+pos]>0)?1:-1) * ((repl_subs[j][varsOfInterest+pos]>0)?1:-1);
+ for (int k = 0; k <= varsOfInterest-nextWildcard; k++)
+ repl_subs[j][k] = scale_2*repl_subs[j][k] - sign*scale_1*repl_subs[i][k];
+
+ num_wild_in_repl_subs[j] = 0;
+ int first_wild = 0;
+ for (int k = 1; k <= -nextWildcard; k++)
+ if (repl_subs[j][varsOfInterest+k] != 0) {
+ num_wild_in_repl_subs[j]++;
+ first_wild = k;
+ }
+
+ if (num_wild_in_repl_subs[j] == 1) {
+ if (wild_solved[first_wild] < 0)
+ wild_solved[first_wild] = j;
+ }
+ }
+ }
+ }
+
+ has_unsolved = false;
+ for (int i = 1; i <= -nextWildcard; i++)
+ if (coef[varsOfInterest+i] != 0 && wild_solved[i] < 0) {
+ has_unsolved = true;
+ break;
+ }
+ }
+
+ // Substitute all widecards in the red constraint
+ for (int i = 1; i <= -nextWildcard; i++) {
+ if (coef[varsOfInterest+i] != 0) {
+ int s = wild_solved[i];
+ assert(s >= 0);
+
+ coef_t l = lcm(abs(coef[varsOfInterest+i]), abs(repl_subs[s][varsOfInterest+i]));
+ coef_t scale_1 = l/abs(coef[varsOfInterest+i]);
+ coef_t scale_2 = l/abs(repl_subs[s][varsOfInterest+i]);
+ int sign = ((coef[varsOfInterest+i]>0)?1:-1) * ((repl_subs[s][varsOfInterest+i]>0)?1:-1);
+ for (int j = 0; j <= varsOfInterest-nextWildcard; j++)
+ coef[j] = scale_1*coef[j] - sign*scale_2*repl_subs[s][j];
+
+ if (scale_1 != 1)
+ stride *= scale_1;
+ }
+ }
+
+ for (int i = 0; i < num_repl_subs; i++)
+ delete []repl_subs[i];
+ }
+
+ // Ready to insert into redMemory
+ int m = nMemories++;
+ redMemory[m].length = 0;
+ redMemory[m].kind = type;
+ redMemory[m].constantTerm = coef[0];
+ for(int i = 1; i <= varsOfInterest; i++)
+ if (coef[i]) {
+ int j = redMemory[m].length++;
+ redMemory[m].coef[j] = coef[i];
+ redMemory[m].var[j] = i;
+ }
+ if (type == redStride) redMemory[m].stride = stride;
+ if (DBUG) {
+ fprintf(outputFile,"Red constraint remembered\n");
+ printProblem();
+ }
+}
+
+void Problem::recallRedMemories() {
+ if (nMemories) {
+ if (TRACE) {
+ fprintf(outputFile,"Recalling red memories\n");
+ printProblem();
+ }
+
+ eqn* e = 0;
+ for(int m = 0; m < nMemories; m++) {
+ switch(redMemory[m].kind) {
+ case redGEQ:
+ {
+ int temporary_eqn = newGEQ();
+ e = &GEQs[temporary_eqn];
+ eqnnzero(e, nVars);
+ e->touched = 1;
+ break;
+ }
+ case redEQ:
+ {
+ int temporary_eqn = newEQ();
+ e = &EQs[temporary_eqn];
+ eqnnzero(e, nVars);
+ break;
+ }
+ case redStride:
+ {
+ int temporary_eqn = newEQ();
+ e = &EQs[temporary_eqn];
+ eqnnzero(e, nVars);
+ int i = addNewUnprotectedWildcard();
+ e->coef[i] = -redMemory[m].stride;
+ break;
+ }
+ default:
+ assert(0);
+ }
+ e->color = EQ_RED;
+ e->coef[0] = redMemory[m].constantTerm;
+ for(int i = 0; i < redMemory[m].length; i++) {
+ int v = redMemory[m].var[i];
+ assert(var[forwardingAddress[v]] == v);
+ e->coef[forwardingAddress[v]] = redMemory[m].coef[i];
+ }
+ }
+
+ nMemories = 0;
+ if (TRACE) {
+ fprintf(outputFile,"Red memories recalled\n");
+ printProblem();
+ }
+ }
+}
+
+void Problem::swapVars(int i, int j) {
+ if (DEBUG) {
+ use_ugly_names++;
+ fprintf(outputFile, "Swapping %d and %d\n", i, j);
+ printProblem();
+ use_ugly_names--;
+ }
+ std::swap(var[i], var[j]);
+ for (int e = nGEQs - 1; e >= 0; e--)
+ if (GEQs[e].coef[i] != GEQs[e].coef[j]) {
+ GEQs[e].touched = true;
+ coef_t t = GEQs[e].coef[i];
+ GEQs[e].coef[i] = GEQs[e].coef[j];
+ GEQs[e].coef[j] = t;
+ }
+ for (int e = nEQs - 1; e >= 0; e--)
+ if (EQs[e].coef[i] != EQs[e].coef[j]) {
+ coef_t t = EQs[e].coef[i];
+ EQs[e].coef[i] = EQs[e].coef[j];
+ EQs[e].coef[j] = t;
+ }
+ for (int e = nSUBs - 1; e >= 0; e--)
+ if (SUBs[e].coef[i] != SUBs[e].coef[j]) {
+ coef_t t = SUBs[e].coef[i];
+ SUBs[e].coef[i] = SUBs[e].coef[j];
+ SUBs[e].coef[j] = t;
+ }
+ if (DEBUG) {
+ use_ugly_names++;
+ fprintf(outputFile, "Swapping complete \n");
+ printProblem();
+ fprintf(outputFile, "\n");
+ use_ugly_names--;
+ }
+}
+
+void Problem::addingEqualityConstraint(int e) {
+ if (addingOuterEqualities && originalProblem != noProblem &&
+ originalProblem != this && !conservative) {
+ int e2 = originalProblem->newEQ();
+ if (TRACE)
+ fprintf(outputFile, "adding equality constraint %d to outer problem\n", e2);
+ eqnnzero(&originalProblem->EQs[e2], originalProblem->nVars);
+ for (int i = nVars; i >= 1; i--) {
+ int j;
+ for (j = originalProblem->nVars; j >= 1; j--)
+ if (originalProblem->var[j] == var[i])
+ break;
+ if (j <= 0 || (outerColor && j > originalProblem->safeVars)) {
+ if (DBUG)
+ fprintf(outputFile, "retracting\n");
+ originalProblem->nEQs--;
+ return;
+ }
+ originalProblem->EQs[e2].coef[j] = EQs[e].coef[i];
+ }
+ originalProblem->EQs[e2].coef[0] = EQs[e].coef[0];
+
+ originalProblem->EQs[e2].color = outerColor;
+ if (DBUG)
+ originalProblem->printProblem();
+ }
+}
+
+
+// Initialize hash codes for inequalities, remove obvious redundancy.
+// Case 1:
+// a1*x1+a2*x2+...>=c (1)
+// a1*x2+a2*x2+...>=c' (2)
+// if c>=c' then (2) is redundant, and vice versa.
+//
+// case 2:
+// a1*x1+a2*x2+...>=c (1)
+// a1*x1+a2*x2+...<=c' (2)
+// if c=c' then add equality of (1) or (2),
+// if c>c' then no solution.
+//
+// Finally it calls extended normalize process which handles
+// wildcards in redundacy removal.
+normalizeReturnType Problem::normalize() {
+ int i, j;
+ bool coupledSubscripts = false;
+
+ check();
+
+ for (int e = 0; e < nGEQs; e++) {
+ if (!GEQs[e].touched) {
+ if (!singleVarGEQ(&GEQs[e]))
+ coupledSubscripts = true;
+ }
+ else { // normalize e
+ coef_t g;
+ int topVar;
+ int i0;
+ coef_t hashCode;
+
+ {
+ int *p = &packing[0];
+ for (int k = 1; k <= nVars; k++)
+ if (GEQs[e].coef[k]) {
+ *(p++) = k;
+ }
+ topVar = (p - &packing[0]) - 1;
+ }
+
+ if (topVar == -1) {
+ if (GEQs[e].coef[0] < 0) {
+ // e has no solution
+ return (normalize_false);
+ }
+ deleteGEQ(e);
+ e--;
+ continue;
+ }
+ else if (topVar == 0) {
+ int singleVar = packing[0];
+ g = GEQs[e].coef[singleVar];
+ if (g > 0) {
+ GEQs[e].coef[singleVar] = 1;
+ GEQs[e].key = singleVar;
+ }
+ else {
+ g = -g;
+ GEQs[e].coef[singleVar] = -1;
+ GEQs[e].key = -singleVar;
+ }
+ if (g > 1)
+ GEQs[e].coef[0] = int_div(GEQs[e].coef[0], g);
+ }
+ else {
+ coupledSubscripts = true;
+ i0 = topVar;
+ i = packing[i0--];
+ g = GEQs[e].coef[i];
+ hashCode = g * (i + 3);
+ if (g < 0)
+ g = -g;
+ for (; i0 >= 0; i0--) {
+ coef_t x;
+ i = packing[i0];
+ x = GEQs[e].coef[i];
+ hashCode = hashCode * keyMult * (i + 3) + x;
+ if (x < 0)
+ x = -x;
+ if (x == 1) {
+ g = 1;
+ i0--;
+ break;
+ }
+ else
+ g = gcd(x, g);
+ }
+ for (; i0 >= 0; i0--) {
+ coef_t x;
+ i = packing[i0];
+ x = GEQs[e].coef[i];
+ hashCode = hashCode * keyMult * (i + 3) + x;
+ }
+ if (g > 1) {
+ GEQs[e].coef[0] = int_div(GEQs[e].coef[0], g);
+ i0 = topVar;
+ i = packing[i0--];
+ GEQs[e].coef[i] = GEQs[e].coef[i] / g;
+ hashCode = GEQs[e].coef[i] * (i + 3);
+ for (; i0 >= 0; i0--) {
+ i = packing[i0];
+ GEQs[e].coef[i] = GEQs[e].coef[i] / g;
+ hashCode = hashCode * keyMult * (i + 3) + GEQs[e].coef[i];
+ }
+ }
+
+ {
+ coef_t g2 = abs(hashCode); // get e's hash code
+ j = static_cast<int>(g2 % static_cast<coef_t>(hashTableSize));
+ assert (g2 % (coef_t) hashTableSize == j);
+ while (1) {
+ eqn *proto = &(hashMaster[j]);
+ if (proto->touched == g2) {
+ if (proto->coef[0] == topVar) {
+ if (hashCode >= 0)
+ for (i0 = topVar; i0 >= 0; i0--) {
+ i = packing[i0];
+ if (GEQs[e].coef[i] != proto->coef[i])
+ break;
+ }
+ else
+ for (i0 = topVar; i0 >= 0; i0--) {
+ i = packing[i0];
+ if (GEQs[e].coef[i] != -proto->coef[i])
+ break;
+ }
+
+ if (i0 < 0) {
+ if (hashCode >= 0)
+ GEQs[e].key = proto->key;
+ else
+ GEQs[e].key = -proto->key;
+ break;
+ }
+ }
+ }
+ else if (proto->touched < 0) { //insert e into the empty entry in hash table
+ eqnnzero(proto, nVars);
+ if (hashCode >= 0)
+ for (i0 = topVar; i0 >= 0; i0--) {
+ i = packing[i0];
+ proto->coef[i] = GEQs[e].coef[i];
+ }
+ else
+ for (i0 = topVar; i0 >= 0; i0--) {
+ i = packing[i0];
+ proto->coef[i] = -GEQs[e].coef[i];
+ }
+ proto->coef[0] = topVar;
+ proto->touched = g2;
+ proto->key = nextKey++;
+
+ if (proto->key > maxKeys) {
+ fprintf(outputFile, "too many hash keys generated \n");
+ fflush(outputFile);
+ exit(2);
+ }
+ if (hashCode >= 0)
+ GEQs[e].key = proto->key;
+ else
+ GEQs[e].key = -proto->key;
+ break;
+ }
+ j = (j + 1) % hashTableSize;
+ }
+ }
+ }
+ }
+
+ GEQs[e].touched = false;
+
+ {
+ int eKey = GEQs[e].key;
+ int e2;
+ if (e > 0) {
+ e2 = fastLookup[maxKeys - eKey];
+ if (e2 >= 0 && e2 < e && GEQs[e2].key == -eKey) {
+ // confirm it is indeed a match -- by chun 10/29/2008
+ int k;
+ for (k = nVars; k >= 1; k--)
+ if (GEQs[e2].coef[k] != -GEQs[e].coef[k])
+ break;
+
+ if (k == 0) {
+ if (GEQs[e2].coef[0] < -GEQs[e].coef[0]) {
+ // there is no solution from e and e2
+ return (normalize_false);
+ }
+ else if (GEQs[e2].coef[0] == -GEQs[e].coef[0]) {
+ // reduce e and e2 to an equation
+ int neweq = newEQ();
+ eqnncpy(&EQs[neweq], &GEQs[e], nVars);
+ EQs[neweq].color = GEQs[e].color || GEQs[e2].color;
+ addingEqualityConstraint(neweq);
+ }
+ }
+ }
+
+ e2 = fastLookup[maxKeys + eKey];
+ if (e2 >= 0 && e2 < e && GEQs[e2].key == eKey) {
+ // confirm it is indeed a match -- by chun 10/29/2008
+ int k;
+ for (k = nVars; k >= 1; k--)
+ if (GEQs[e2].coef[k] != GEQs[e].coef[k])
+ break;
+
+ if (k == 0) {
+ if (GEQs[e2].coef[0] > GEQs[e].coef[0] ||
+ (GEQs[e2].coef[0] == GEQs[e].coef[0] && GEQs[e2].color)) {
+ // e2 is redundant
+ GEQs[e2].coef[0] = GEQs[e].coef[0];
+ GEQs[e2].color = GEQs[e].color;
+ deleteGEQ(e);
+ e--;
+ continue;
+ }
+ else {
+ // e is redundant
+ deleteGEQ(e);
+ e--;
+ continue;
+ }
+ }
+ }
+ }
+ fastLookup[maxKeys + eKey] = e;
+ }
+ }
+
+ // bypass entended normalization for temporary problem
+ if (!isTemporary && !inApproximateMode)
+ normalize_ext();
+
+ return coupledSubscripts ? normalize_coupled : normalize_uncoupled;
+}
+
+//
+// Extended normalize process, remove redundancy involving wildcards.
+// e.g.
+// exists alpha, beta:
+// v1+8*alpha<=v2<=15+8*alpha (1)
+// v1+8*beta<=v2<=15+8*beta (2)
+// if there are no other inequalities involving alpha or beta,
+// then either (1) or (2) is redundant. Such case can't be simplified
+// by fourier-motzkin algorithm due to special meanings of existentials.
+//
+void Problem::normalize_ext() {
+ std::vector<BoolSet<> > disjoint_wildcards(nVars-safeVars, BoolSet<>(nVars-safeVars));
+ std::vector<BoolSet<> > wildcards_in_inequality(nVars-safeVars, BoolSet<>(nGEQs));
+ for (int i = 0; i < nVars-safeVars; i++) {
+ disjoint_wildcards[i].set(i);
+ }
+
+ // create disjoint wildcard sets according to inequalities
+ for (int e = 0; e < nGEQs; e++) {
+ std::vector<BoolSet<> >::iterator first_set = disjoint_wildcards.end();
+ for (int i = 0; i < nVars-safeVars; i++)
+ if (GEQs[e].coef[i+safeVars+1] != 0) {
+ wildcards_in_inequality[i].set(e);
+
+ std::vector<BoolSet<> >::iterator cur_set = disjoint_wildcards.end();
+ for (std::vector<BoolSet<> >::iterator j = disjoint_wildcards.begin(); j != disjoint_wildcards.end(); j++)
+ if ((*j).get(i)) {
+ cur_set = j;
+ break;
+ }
+ assert(cur_set!=disjoint_wildcards.end());
+ if (first_set == disjoint_wildcards.end())
+ first_set = cur_set;
+ else if (first_set != cur_set) {
+ *first_set |= *cur_set;
+ disjoint_wildcards.erase(cur_set);
+ }
+ }
+ }
+
+ // do not consider wildcards appearing in equalities
+ for (int e = 0; e < nEQs; e++)
+ for (int i = 0; i < nVars-safeVars; i++)
+ if (EQs[e].coef[i+safeVars+1] != 0) {
+ for (std::vector<BoolSet<> >::iterator j = disjoint_wildcards.begin(); j != disjoint_wildcards.end(); j++)
+ if ((*j).get(i)) {
+ disjoint_wildcards.erase(j);
+ break;
+ }
+ }
+
+ // create disjoint inequality sets
+ std::vector<BoolSet<> > disjoint_inequalities(disjoint_wildcards.size());
+ for (size_t i = 0; i < disjoint_wildcards.size(); i++)
+ for (int j = 0; j < nVars-safeVars; j++)
+ if (disjoint_wildcards[i].get(j))
+ disjoint_inequalities[i] |= wildcards_in_inequality[j];
+
+ // hash the inequality again, this time separate wildcard variables from
+ // regular variables
+ coef_t hash_safe[nGEQs];
+ coef_t hash_wild[nGEQs];
+ for (int e = 0; e < nGEQs; e++) {
+ coef_t hashCode = 0;
+ for (int i = 1; i <= safeVars; i++)
+ if (GEQs[e].coef[i] != 0)
+ hashCode = hashCode * keyMult * (i+3) + GEQs[e].coef[i];
+ hash_safe[e] = hashCode;
+
+ hashCode = 0;
+ for (int i = safeVars+1; i <= nVars; i++)
+ if (GEQs[e].coef[i] != 0)
+ hashCode = hashCode * keyMult + GEQs[e].coef[i];
+ hash_wild[e] = hashCode;
+ }
+
+ // sort hash keys for each disjoint set
+ std::vector<std::vector<std::pair<int, std::pair<coef_t, coef_t> > > > disjoint_hash(disjoint_inequalities.size());
+ for (size_t i = 0; i < disjoint_inequalities.size(); i++)
+ for (int e = 0; e < nGEQs; e++)
+ if (disjoint_inequalities[i].get(e)) {
+ std::vector<std::pair<int, std::pair<coef_t, coef_t> > >::iterator j = disjoint_hash[i].begin();
+ for (; j != disjoint_hash[i].end(); j++)
+ if ((hash_safe[e] > (*j).second.first) ||
+ (hash_safe[e] == (*j).second.first && hash_wild[e] > (*j).second.second))
+ break;
+ disjoint_hash[i].insert(j, std::make_pair(e, std::make_pair(hash_safe[e], hash_wild[e])));
+ }
+
+ // test wildcard equivalance
+ std::vector<bool> is_dead(nGEQs, false);
+ for (size_t i = 0; i < disjoint_wildcards.size(); i++) {
+ if (disjoint_inequalities[i].num_elem() == 0)
+ continue;
+
+ for (size_t j = i+1; j < disjoint_wildcards.size(); j++) {
+ if (disjoint_wildcards[i].num_elem() != disjoint_wildcards[j].num_elem() ||
+ disjoint_hash[i].size() != disjoint_hash[j].size())
+ continue;
+
+ bool match = true;
+ for (size_t k = 0; k < disjoint_hash[i].size(); k++) {
+ if (disjoint_hash[i][k].second != disjoint_hash[j][k].second) {
+ match = false;
+ break;
+ }
+ }
+ if (!match)
+ continue;
+
+ // confirm same coefficients for regular variables
+ for (size_t k = 0; k < disjoint_hash[i].size(); k++) {
+ for (int p = 1; p <= safeVars; p++)
+ if (GEQs[disjoint_hash[i][k].first].coef[p] != GEQs[disjoint_hash[j][k].first].coef[p]) {
+ match = false;
+ break;
+ }
+ if (!match)
+ break;
+ }
+ if (!match)
+ continue;
+
+ // now try combinatory wildcard matching
+ std::vector<int> wild_map(nVars-safeVars, -1);
+ for (size_t k = 0; k < disjoint_hash[i].size(); k++) {
+ int e1 = disjoint_hash[i][k].first;
+ int e2 = disjoint_hash[j][k].first;
+
+ for (int p = 0; p < nVars-safeVars; p++)
+ if (GEQs[e1].coef[p+safeVars+1] != 0) {
+ if (wild_map[p] == -1) {
+ for (int q = 0; q < nVars-safeVars; q++)
+ if (wild_map[q] == -1 &&
+ GEQs[e2].coef[q+safeVars+1] == GEQs[e1].coef[p+safeVars+1]) {
+ wild_map[p] = q;
+ wild_map[q] = p;
+ break;
+ }
+ if (wild_map[p] == -1) {
+ match = false;
+ break;
+ }
+ }
+ else if (GEQs[e2].coef[wild_map[p]+safeVars+1] != GEQs[e1].coef[p+safeVars+1]) {
+ match = false;
+ break;
+ }
+ }
+ if (!match)
+ break;
+
+ for (int p = 0; p < nVars-safeVars; p++)
+ if (GEQs[e2].coef[p+safeVars+1] != 0 &&
+ (wild_map[p] == -1 || GEQs[e2].coef[p+safeVars+1] != GEQs[e1].coef[wild_map[p]+safeVars+1])) {
+ match = false;
+ break;
+ }
+ if (!match)
+ break;
+ }
+ if (!match)
+ continue;
+
+ // check constants
+ int dir = 0;
+ for (size_t k = 0; k < disjoint_hash[i].size(); k++) {
+ if (GEQs[disjoint_hash[i][k].first].coef[0] > GEQs[disjoint_hash[j][k].first].coef[0]) {
+ if (dir == 0)
+ dir = 1;
+ else if (dir == -1) {
+ match = false;
+ break;
+ }
+ }
+ else if (GEQs[disjoint_hash[i][k].first].coef[0] < GEQs[disjoint_hash[j][k].first].coef[0]) {
+ if (dir == 0)
+ dir = -1;
+ else if (dir == 1) {
+ match = false;
+ break;
+ }
+ }
+ }
+ if (!match)
+ continue;
+
+ // check redness
+ int red_dir = 0;
+ for (size_t k = 0; k < disjoint_hash[i].size(); k++) {
+ if (GEQs[disjoint_hash[i][k].first].color > GEQs[disjoint_hash[j][k].first].color) {
+ if (red_dir == 0)
+ red_dir = 1;
+ else if (red_dir == -1) {
+ match = false;
+ break;
+ }
+ }
+ else if (GEQs[disjoint_hash[i][k].first].color < GEQs[disjoint_hash[j][k].first].color) {
+ if (red_dir == 0)
+ red_dir = -1;
+ else if (red_dir == 1) {
+ match = false;
+ break;
+ }
+ }
+ }
+ if (!match)
+ continue;
+
+ // remove redundant inequalities
+ if (dir == 1 || (dir == 0 && red_dir == 1)) {
+ for (size_t k = 0; k < disjoint_hash[i].size(); k++) {
+ GEQs[disjoint_hash[i][k].first].coef[0] = GEQs[disjoint_hash[j][k].first].coef[0];
+ GEQs[disjoint_hash[i][k].first].color = GEQs[disjoint_hash[j][k].first].color;
+ is_dead[disjoint_hash[j][k].first] = true;
+ }
+ }
+ else {
+ for (size_t k = 0; k < disjoint_hash[i].size(); k++) {
+ is_dead[disjoint_hash[j][k].first] = true;
+ }
+ }
+ }
+ }
+
+ // eliminate dead inequalities
+ for (int e = nGEQs-1; e >= 0; e--)
+ if (is_dead[e]) {
+ deleteGEQ(e);
+ }
+}
+
+
+void initializeOmega(void) {
+ if (omegaInitialized)
+ return;
+
+// assert(sizeof(eqn)==sizeof(int)*(headerWords)+sizeof(coef_t)*(1+maxVars));
+ nextWildcard = 0;
+ nextKey = maxVars + 1;
+ for (int i = 0; i < hashTableSize; i++)
+ hashMaster[i].touched = -1;
+
+ sprintf(wildName[1], "__alpha");
+ sprintf(wildName[2], "__beta");
+ sprintf(wildName[3], "__gamma");
+ sprintf(wildName[4], "__delta");
+ sprintf(wildName[5], "__tau");
+ sprintf(wildName[6], "__sigma");
+ sprintf(wildName[7], "__chi");
+ sprintf(wildName[8], "__omega");
+ sprintf(wildName[9], "__pi");
+ sprintf(wildName[10], "__ni");
+ sprintf(wildName[11], "__Alpha");
+ sprintf(wildName[12], "__Beta");
+ sprintf(wildName[13], "__Gamma");
+ sprintf(wildName[14], "__Delta");
+ sprintf(wildName[15], "__Tau");
+ sprintf(wildName[16], "__Sigma");
+ sprintf(wildName[17], "__Chi");
+ sprintf(wildName[18], "__Omega");
+ sprintf(wildName[19], "__Pi");
+
+ omegaInitialized = 1;
+}
+
+//
+// This is experimental (I would say, clinical) fact:
+// If the code below is removed then simplifyProblem cycles.
+//
+class brainDammage {
+public:
+ brainDammage();
+};
+
+brainDammage::brainDammage() {
+ initializeOmega();
+}
+
+static brainDammage Podgorny;
+
+} // namespace
diff --git a/omegalib/omega/src/omega_core/oc_solve.cc b/omegalib/omega/src/omega_core/oc_solve.cc
new file mode 100644
index 0000000..c25b6d0
--- /dev/null
+++ b/omegalib/omega/src/omega_core/oc_solve.cc
@@ -0,0 +1,1378 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 the Omega Project Team
+ Copyright (C) 2005-2011 Chun Chen
+ All Rights Reserved.
+
+ Purpose:
+ Solve ineqalities.
+
+ Notes:
+
+ History:
+*****************************************************************************/
+
+#include <omega/omega_core/oc_i.h>
+
+namespace omega {
+
+static int solveDepth = 0;
+#define maxDead maxmaxGEQs
+
+int Problem::solve(int desiredResult) {
+ assert(omegaInitialized);
+ int result;
+
+ checkVars(nVars+1);
+ assert(nVars >= safeVars);
+ if (desiredResult != OC_SOLVE_SIMPLIFY)
+ safeVars = 0;
+
+ solveDepth++;
+ if (solveDepth > 50) {
+ fprintf(outputFile, "Solve depth = %d, inApprox = %d, aborting\n", solveDepth, inApproximateMode);
+ printProblem();
+ fflush(outputFile);
+
+ if (solveDepth > 60)
+ exit(2);
+ }
+
+ check();
+ do {
+ doItAgain = 0;
+ check();
+ if (solveEQ() == false) {
+ solveDepth--;
+ return (false);
+ }
+ check();
+ if (!nGEQs) {
+ result = true;
+ nVars = safeVars;
+ break;
+ }
+ else
+ result = solveGEQ(desiredResult);
+ check();
+ }
+ while (doItAgain && desiredResult == OC_SOLVE_SIMPLIFY);
+ solveDepth--;
+
+ return (result);
+}
+
+
+// Supporting functions of solveGEQ
+int Problem::smoothWeirdEquations() {
+ int e1, e2, e3, p, q, k;
+ coef_t alpha, alpha1, alpha2, alpha3;
+ coef_t c;
+ int v;
+ int result = 0;
+
+ for (e1 = nGEQs - 1; e1 >= 0; e1--)
+ if (!GEQs[e1].color) {
+ coef_t g = 999999;
+ for (v = nVars; v >= 1; v--)
+ if (GEQs[e1].coef[v] != 0 && abs(GEQs[e1].coef[v]) < g)
+ g = abs(GEQs[e1].coef[v]);
+ if (g > 20) {
+ e3 = newGEQ(); /* Create a scratch GEQ,not part of the prob.*/
+ nGEQs--;
+ for (v = nVars; v >= 1; v--)
+ GEQs[e3].coef[v] = int_div(6 * GEQs[e1].coef[v] + g / 2, g);
+ GEQs[e3].color = EQ_BLACK;
+ GEQs[e3].touched = 1;
+ GEQs[e3].coef[0] = 9997;
+ if (DBUG) {
+ fprintf(outputFile, "Checking to see if we can derive: ");
+ printGEQ(&GEQs[e3]);
+ fprintf(outputFile, "\n from: ");
+ printGEQ(&GEQs[e1]);
+ fprintf(outputFile, "\n");
+ }
+
+
+ for (e2 = nGEQs - 1; e2 >= 0; e2--)
+ if (e1 != e2 && !GEQs[e2].color) {
+ for (p = nVars; p > 1; p--) {
+ for (q = p - 1; q > 0; q--) {
+ alpha = check_mul(GEQs[e1].coef[p], GEQs[e2].coef[q]) - check_mul(GEQs[e2].coef[p], GEQs[e1].coef[q]);
+ if (alpha != 0)
+ goto foundPQ;
+ }
+ }
+ continue;
+
+ foundPQ:
+
+ alpha1 = check_mul(GEQs[e2].coef[q], GEQs[e3].coef[p]) - check_mul(GEQs[e2].coef[p], GEQs[e3].coef[q]);
+ alpha2 = -(check_mul(GEQs[e1].coef[q], GEQs[e3].coef[p]) - check_mul(GEQs[e1].coef[p], GEQs[e3].coef[q]));
+ alpha3 = alpha;
+
+ if (alpha1 * alpha2 <= 0)
+ continue;
+ if (alpha1 < 0) {
+ alpha1 = -alpha1;
+ alpha2 = -alpha2;
+ alpha3 = -alpha3;
+ }
+ if (alpha3 > 0) {
+ /* Trying to prove e3 is redundant */
+
+ /* verify alpha1*v1+alpha2*v2 = alpha3*v3 */
+ for (k = nVars; k >= 1; k--)
+ if (check_mul(alpha3, GEQs[e3].coef[k])
+ != check_mul(alpha1, GEQs[e1].coef[k]) + check_mul(alpha2, GEQs[e2].coef[k]))
+ goto nextE2;
+
+ c = check_mul(alpha1, GEQs[e1].coef[0]) + check_mul(alpha2, GEQs[e2].coef[0]);
+ if (c < check_mul(alpha3, (GEQs[e3].coef[0] + 1)))
+ GEQs[e3].coef[0] = int_div(c, alpha3);
+
+ }
+ nextE2:;
+ }
+ if (GEQs[e3].coef[0] < 9997) {
+ result++;
+#if !defined NDEBUG
+ int e4 =
+#endif
+ newGEQ();
+#if !defined NDEBUG
+ assert(e3 == e4);
+#endif
+ if (DBUG) {
+ fprintf(outputFile, "Smoothing wierd equations; adding:\n");
+ printGEQ(&GEQs[e3]);
+ fprintf(outputFile, "\nto:\n");
+ printProblem();
+ fprintf(outputFile, "\n\n");
+ }
+ }
+ }
+ }
+ return (result);
+}
+
+
+void Problem::analyzeElimination(
+ int &v,
+ int &darkConstraints,
+ int &darkShadowFeasible,
+ int &unit,
+ coef_t &parallelSplinters,
+ coef_t &disjointSplinters,
+ coef_t &lbSplinters,
+ coef_t &ubSplinters,
+ int &parallelLB) {
+
+ parallelSplinters = (posInfinity); // was MAXINT
+ disjointSplinters = 0;
+ lbSplinters = 0;
+ ubSplinters = 0;
+
+ darkConstraints = 0;
+ darkShadowFeasible = 1;
+ coef_t maxUBc = 0;
+ coef_t maxLBc = 0;
+ int e,e2;
+ unit = 0;
+ int exact = 1;
+
+ for (e = nGEQs - 1; e >= 0; e--) {
+ coef_t c = GEQs[e].coef[v];
+
+ if (c < 0) {
+ coef_t Lc, Uc, g, diff, grey;
+
+ set_max(maxUBc, -c);
+ Uc = -c;
+ for (e2 = nGEQs - 1; e2 >= 0; e2--)
+ if (GEQs[e2].coef[v] > 0) {
+ Lc = GEQs[e2].coef[v];
+ g = 0;
+ grey = (Lc - 1) * (Uc - 1);
+
+ for (int j = nVars; j >= 1; j--) {
+ coef_t diff = check_mul(Lc, GEQs[e].coef[j]) + check_mul(Uc, GEQs[e2].coef[j]);
+ if (diff < 0) diff = -diff;
+ g = gcd(g, diff);
+ if (g == 1)
+ break;
+ }
+ diff = check_mul(Lc, GEQs[e].coef[0]) + check_mul(Uc, GEQs[e2].coef[0]);
+ if (g == 0) {
+ if (diff < 0) {
+ /* Real shadow must be true */
+ /* otherwise we would have found it during */
+ /* check for opposing constraints */
+ fprintf(outputFile, "Found conflicting constraints ");
+ printGEQ(&GEQs[e]);
+ fprintf(outputFile," and ");
+ printGEQ(&GEQs[e2]);
+ fprintf(outputFile,"\nin\n");
+ printProblem();
+ assert(diff >= 0);
+ }
+ if (diff < grey) {
+ darkShadowFeasible = 0;
+ if (parallelSplinters > diff+1) {
+ parallelSplinters = diff + 1;
+ parallelLB = e2;
+ }
+ }
+ else {/* dark shadow is true, don't need to worry about this constraint pair */
+ }
+ }
+ else {
+ coef_t splinters= int_div(diff, g) - int_div(diff - grey, g);
+ if (splinters) exact = 0;
+ disjointSplinters += splinters;
+ if (g > 1) unit++;
+ darkConstraints++;
+ }
+ }
+ }
+ else if (c > 0) {
+ set_max(maxLBc, c);
+ } /* else
+ darkConstraints++; */
+ }
+
+ if (darkShadowFeasible) {
+ disjointSplinters++;
+ ubSplinters++;
+ lbSplinters++;
+ }
+ else disjointSplinters = (posInfinity); // was MAXINT
+
+
+ if (!darkShadowFeasible || !exact)
+ for (e = nGEQs - 1; e >= 0; e--) {
+ coef_t c = GEQs[e].coef[v];
+ if (c < -1) {
+ c = -c;
+ ubSplinters += 1+(check_mul(c, maxLBc) - c - maxLBc) / maxLBc;
+ }
+ else if (c > 1) {
+ lbSplinters += 1+ (check_mul(c, maxUBc) - c - maxUBc) / maxUBc;
+ }
+ }
+
+ if (DEBUG) {
+ fprintf(outputFile,"analyzing elimination of %s(%d)\n",variable(v),v);
+ if (darkShadowFeasible)
+ fprintf(outputFile," # dark constraints = %d\n", darkConstraints);
+ else
+ fprintf(outputFile," dark shadow obviously unfeasible\n");
+
+ fprintf(outputFile," " coef_fmt " LB splinters\n", lbSplinters);
+ fprintf(outputFile," " coef_fmt " UB splinters\n", ubSplinters);
+ if (disjointSplinters != (posInfinity))
+ fprintf(outputFile," " coef_fmt " disjoint splinters\n", disjointSplinters);
+ if (parallelSplinters != (posInfinity))
+ fprintf(outputFile," " coef_fmt " parallel splinters\n", parallelSplinters);
+ fprintf(outputFile, "\n");
+ fprintf(outputFile," %3d unit score \n", unit);
+ }
+}
+
+
+void Problem::partialElimination() {
+ if (DBUG) {
+ fprintf(outputFile, "Performing Partial elimination\n");
+ printProblem();
+ }
+ int fv;
+ if (0)
+ fv = 0;
+ else
+ fv = safeVars;
+ bool somethingHappened = false;
+ for (int i = nVars; i > fv; i--) {
+ bool isDead[maxmaxGEQs];
+ int e;
+ for (e = nGEQs-1; e >= 0; e--) isDead[e] = false;
+ int deadEqns[maxDead];
+ int numDead = 0;
+ for (int e1 = nGEQs-1; e1 >= 0; e1--)
+ if (abs(GEQs[e1].coef[i]) == 1) {
+ bool isGood = true;
+ for (int e2 = nGEQs-1; e2 >= 0; e2--)
+ if (check_mul(GEQs[e2].coef[i], GEQs[e1].coef[i]) < 0)
+ if (GEQs[e1].key != -GEQs[e2].key) {
+ coef_t Uc = abs(GEQs[e2].coef[i]);
+ for (int k = nVars; k > fv; k--)
+ if (GEQs[e2].coef[k] + check_mul(GEQs[e1].coef[k], Uc) != 0)
+ isGood = false;
+ }
+ if (isGood) {
+ somethingHappened = true;
+ for (int e2 = nGEQs-1; e2 >= 0; e2--)
+ if (check_mul(GEQs[e2].coef[i], GEQs[e1].coef[i]) < 0) {
+ if (GEQs[e1].key != -GEQs[e2].key) {
+ coef_t Uc = abs(GEQs[e2].coef[i]);
+ int new_eqn;
+ if (numDead == 0) {
+ new_eqn = newGEQ();
+ }
+ else {
+ new_eqn = deadEqns[--numDead];
+ }
+ isDead[new_eqn] = false;
+ if (DBUG) {
+ fprintf(outputFile,"Eliminating constraint on %s\n", variable(i));
+ fprintf(outputFile, "e1 = %d, e2 = %d, gen = %d\n", e1, e2, new_eqn);
+ printGEQ(&(GEQs[e1]));
+ fprintf(outputFile, "\n");
+ printGEQ(&(GEQs[e2]));
+ fprintf(outputFile, "\n");
+ }
+
+ for (int k = nVars; k >= 0; k--)
+ GEQs[new_eqn].coef[k] = GEQs[e2].coef[k] + check_mul(GEQs[e1].coef[k], Uc);
+ GEQs[new_eqn].touched = true;
+ GEQs[new_eqn].color = GEQs[e2].color | GEQs[e1].color;
+ if (DBUG) {
+ fprintf(outputFile, "give ");
+ printGEQ(&(GEQs[new_eqn]));
+ fprintf(outputFile, "\n");
+ }
+ assert(GEQs[new_eqn].coef[i] == 0);
+ }
+ }
+ deadEqns[numDead++] = e1;
+ isDead[e1] = true;
+ if (DEBUG)
+ fprintf(outputFile, "Killed %d\n", e1);
+ }
+ }
+ for (e = nGEQs - 1; e >= 0; e--)
+ if (isDead[e]) {
+ deleteGEQ(e);
+ }
+ }
+ if (somethingHappened && DBUG) {
+ fprintf(outputFile, "Result of Partial elimination\n");
+ printProblem();
+ }
+}
+
+
+int Problem:: solveGEQ(int desiredResult) {
+ int i, j, k, e;
+ int fv;
+ int result;
+ int coupledSubscripts;
+ int eliminateAgain;
+ int smoothed = 0;
+ int triedEliminatingRedundant = 0;
+ j = 0;
+
+ if (desiredResult != OC_SOLVE_SIMPLIFY) {
+ nSUBs = 0;
+ nMemories = 0;
+ safeVars = 0;
+ varsOfInterest = 0;
+ }
+
+solveGEQstart:
+ while (1) {
+ assert(desiredResult == OC_SOLVE_SIMPLIFY || nSUBs == 0);
+ check_number_GEQs(nGEQs);
+
+ if (DEBUG) {
+ fprintf(outputFile, "\nSolveGEQ(%d,%d):\n", desiredResult, pleaseNoEqualitiesInSimplifiedProblems);
+ printProblem();
+ fprintf(outputFile, "\n");
+ }
+
+#ifndef NDEBUG
+ for(e=0;e<nSUBs;e++)
+ for(i=safeVars+1;i<=nVars;i++)
+ assert(!SUBs[e].coef[i]);
+#endif
+
+ check();
+
+ if (nVars == 1) {
+ int uColor = EQ_BLACK;
+ int lColor = EQ_BLACK;
+ coef_t upperBound = posInfinity;
+ coef_t lowerBound = negInfinity;
+ for (e = nGEQs - 1; e >= 0; e--) {
+ coef_t a = GEQs[e].coef[1];
+ coef_t c = GEQs[e].coef[0];
+ /* our equation is ax + c >= 0, or ax >= -c, or c >= -ax */
+ if (a == 0) {
+ if (c < 0) {
+ if (TRACE)
+ fprintf(outputFile, "equations have no solution (G)\n");
+ return (false);
+ }
+ }
+ else if (a > 0) {
+ if (a != 1)
+ c = int_div(c, a);
+ if (lowerBound < -c || (lowerBound == -c && !isRed(&GEQs[e]))) {
+ lowerBound = -c;
+ lColor = GEQs[e].color;
+ }
+ }
+ else {
+ if (a != -1)
+ c = int_div(c, -a);
+ if (upperBound > c || (upperBound == c && !isRed(&GEQs[e]))) {
+ upperBound = c;
+ uColor = GEQs[e].color;
+ }
+ }
+ }
+ if (DEBUG)
+ fprintf(outputFile, "upper bound = " coef_fmt "\n", upperBound);
+ if (DEBUG)
+ fprintf(outputFile, "lower bound = " coef_fmt "\n", lowerBound);
+ if (lowerBound > upperBound) {
+ if (TRACE)
+ fprintf(outputFile, "equations have no solution (H)\n");
+ return (false);
+ }
+ if (desiredResult == OC_SOLVE_SIMPLIFY) {
+ nGEQs = 0;
+ if (safeVars == 1) {
+ if (lowerBound == upperBound && !uColor && !lColor) {
+ int e = newEQ();
+ assert(e == 0);
+ EQs[e].coef[0] = -lowerBound;
+ EQs[e].coef[1] = 1;
+ EQs[e].color = lColor | uColor;
+ return (solve(desiredResult));
+ }
+ else {
+ if (lowerBound > negInfinity) {
+ int e = newGEQ();
+ assert(e == 0);
+ GEQs[e].coef[0] = -lowerBound;
+ GEQs[e].coef[1] = 1;
+ GEQs[e].key = 1;
+ GEQs[e].color = lColor;
+ GEQs[e].touched = 0;
+ }
+ if (upperBound < posInfinity) {
+ int e = newGEQ();
+ GEQs[e].coef[0] = upperBound;
+ GEQs[e].coef[1] = -1;
+ GEQs[e].key = -1;
+ GEQs[e].color = uColor;
+ GEQs[e].touched = 0;
+ }
+ }
+ }
+ else
+ nVars = 0;
+ return (true);
+ }
+ if (originalProblem != noProblem && !lColor && !uColor && !conservative && lowerBound == upperBound) {
+ int e = newEQ();
+ assert(e == 0);
+ EQs[e].coef[0] = -lowerBound;
+ EQs[e].coef[1] = 1;
+ EQs[e].color = EQ_BLACK;
+ addingEqualityConstraint(0);
+ }
+ return (true);
+ }
+
+ if (!variablesFreed) {
+ variablesFreed = 1;
+ if (desiredResult != OC_SOLVE_SIMPLIFY)
+ freeEliminations(0);
+ else
+ freeEliminations(safeVars);
+ if (nVars == 1)
+ continue;
+ }
+
+
+ switch (normalize()) {
+ case normalize_false:
+ return (false);
+ break;
+ case normalize_coupled:
+ coupledSubscripts = true;
+ break;
+ case normalize_uncoupled:
+ coupledSubscripts = false;
+ break;
+ default:
+ coupledSubscripts = false;
+ assert(0 && "impossible case in SolveGEQ");
+ }
+
+
+ if ((doTrace && desiredResult == OC_SOLVE_SIMPLIFY) || DBUG) {
+ fprintf(outputFile, "\nafter normalization:\n");
+ printProblem();
+ fprintf(outputFile, "\n");
+ for(e=0;e<nGEQs;e++) assert(!GEQs[e].touched);
+ fprintf(outputFile, "eliminating variable using fourier-motzkin elimination\n");
+ }
+
+ // eliminating variable using fourier-motzkin elimination
+ do {
+ eliminateAgain = 0;
+
+ if (nEQs > 0)
+ return (solve(desiredResult));
+
+ if (!coupledSubscripts) {
+ if (safeVars == 0)
+ nGEQs = 0;
+ else
+ for (e = nGEQs - 1; e >= 0; e--)
+ if (GEQs[e].key > safeVars || -safeVars > GEQs[e].key)
+ deleteGEQ(e);
+ nVars = safeVars;
+ return (true);
+ }
+
+ if (desiredResult != OC_SOLVE_SIMPLIFY)
+ fv = 0;
+ else
+ fv = safeVars;
+
+ if (nVars == 0 || nGEQs == 0) {
+ nGEQs = 0;
+ if (desiredResult == OC_SOLVE_SIMPLIFY)
+ nVars = safeVars;
+ return (true);
+ }
+ if (desiredResult == OC_SOLVE_SIMPLIFY && nVars == safeVars) {
+ return (true);
+ }
+
+
+ if (nGEQs+6 > maxGEQs || nGEQs > 2 * nVars * nVars + 4 * nVars + 10) {
+ if (TRACE)
+ fprintf(outputFile, "TOO MANY EQUATIONS; %d equations, %d variables, ELIMINATING REDUNDANT ONES\n", nGEQs, nVars);
+ if (!quickKill(0,true))
+ return 0;
+ if (nEQs > 0)
+ return (solve(desiredResult));
+ if (TRACE)
+ fprintf(outputFile, "END ELIMINATION OF REDUNDANT EQUATIONS\n");
+ if (DBUG) printProblem();
+ }
+
+
+ {
+ int darkConstraints, darkShadowFeasible, unit, parallelLB;
+ coef_t parallelSplinters, disjointSplinters, lbSplinters, ubSplinters, splinters;
+ coef_t bestScore, score;
+ int bestVar;
+ int exact;
+ int Ue,Le;
+
+ if (desiredResult != OC_SOLVE_SIMPLIFY) fv = 0;
+ else fv = safeVars;
+
+ if (DEBUG) {
+ fprintf(outputFile,"Considering elimination possibilities[ \n");
+ printProblem();
+ }
+
+ analyzeGEQstart:
+ try {
+ bestScore = posInfinity;
+ bestVar = -1;
+ for (i = nVars; i != fv; i--) {
+ analyzeElimination(i, darkConstraints, darkShadowFeasible, unit, parallelSplinters, disjointSplinters, lbSplinters, ubSplinters, parallelLB);
+
+ score = min(min(parallelSplinters,disjointSplinters),
+ min(lbSplinters,ubSplinters));
+ exact = score == 1;
+ score = 10000*(score-1) + darkConstraints;
+ if (score >= posInfinity) // too big the score
+ score = posInfinity - 1;
+ score -= 3*unit;
+
+ if (score < bestScore) {
+ bestScore = score;
+ bestVar = i;
+ if (i > 4 && score < nGEQs) break;
+ }
+ }
+ assert(bestVar>=0);
+ exact = bestScore < 10000;
+ i = bestVar;
+ assert(i<=nVars);
+ analyzeElimination(i, darkConstraints, darkShadowFeasible, unit, parallelSplinters, disjointSplinters, lbSplinters, ubSplinters, parallelLB);
+ if (DEBUG) {
+ fprintf(outputFile,"] Choose to eliminate %s \n",variable(i));
+ }
+ splinters = lbSplinters;
+ if (splinters <= parallelSplinters)
+ parallelSplinters = posInfinity;
+ else splinters = parallelSplinters;
+ if (disjointSplinters == 1) splinters = 1;
+ exact = splinters == 1;
+ if (inApproximateMode) exact = 1;
+ }
+ catch (std::overflow_error) {
+ int result = quickKill(0, true);
+ if (result == 0)
+ return 0;
+ else if (result == 1)
+ return true;
+ else {
+ if (nEQs > 0)
+ return (solve(desiredResult));
+ triedEliminatingRedundant = 1;
+ goto analyzeGEQstart;
+ }
+ }
+
+ if (!triedEliminatingRedundant && darkConstraints > maxGEQs) {
+ if (TRACE)
+ fprintf(outputFile, "Elimination will create TOO MANY EQUATIONS; %d equations, %d variables, %d new constraints, ELIMINATING REDUNDANT ONES\n", nGEQs, nVars,darkConstraints);
+ if (!quickKill(0))
+ return 0;
+ if (nEQs > 0)
+ return (solve(desiredResult));
+ if (TRACE)
+ fprintf(outputFile, "END ELIMINATION OF REDUNDANT EQUATIONS\n");
+ if (DBUG) printProblem();
+
+ triedEliminatingRedundant = 1;
+ eliminateAgain = 1;
+ continue;
+ }
+
+ if (!exact && !triedEliminatingRedundant &&
+ safeVars > 0 && desiredResult == OC_SOLVE_SIMPLIFY) {
+ if (TRACE)
+ fprintf(outputFile, "Trying to produce exact elimination by finding redundant constraints [\n");
+ if (!quickKill(1)) return 0;
+ if (TRACE)
+ fprintf(outputFile, "]\n");
+ triedEliminatingRedundant = 1;
+ eliminateAgain = 1;
+ continue;
+ }
+ triedEliminatingRedundant = 0;
+
+ if (desiredResult == OC_SOLVE_SIMPLIFY && !exact) {
+ partialElimination();
+ switch (normalize()) {
+ case normalize_false:
+ return (false);
+ break;
+ case normalize_coupled:
+ case normalize_uncoupled:
+ break;
+ }
+ if (nEQs) return solveEQ();
+ if (DBUG) fprintf(outputFile,"Stopping short due to non-exact elimination\n");
+ return (true);
+ }
+
+ if ( desiredResult == OC_SOLVE_SIMPLIFY && darkConstraints > maxGEQs) {
+ if (DBUG) fprintf(outputFile,"Stopping short due to overflow of GEQs: %d\n", darkConstraints);
+ return (true);
+ }
+
+ if ((doTrace && desiredResult == OC_SOLVE_SIMPLIFY) || DBUG) {
+ fprintf(outputFile, "going to eliminate %s, (%d)\n", variable(i), i);
+ if (DEBUG)
+ printProblem();
+ fprintf(outputFile, "score = " coef_fmt "/" coef_fmt "\n", bestScore,splinters);
+ }
+
+ if (!exact && desiredResult == OC_SOLVE_SIMPLIFY && parallelSplinters == splinters) {
+ return parallelSplinter(parallelLB, parallelSplinters, desiredResult);
+ }
+
+ // smoothed = 0; // what a bug!!! -- by chun 6/10/2008
+
+ if (i != nVars) {
+ j = nVars;
+ swapVars(i,j);
+
+ i = j;
+ }
+ else if (DEBUG) {
+ printVars();
+ fprintf(outputFile, "No swap needed before eliminating %s(%d/%d)\n",variable(i),i,nVars);
+ for(j=1;j<=i;j++) fprintf(outputFile,"var #%d = %s(%x)\n",j,variable(j),var[j]);
+ printProblem();
+ }
+ nVars--;
+
+ if (exact) {
+ if (nVars == 1) {
+ coef_t upperBound = posInfinity;
+ coef_t lowerBound = negInfinity;
+ int ub_color = 0;
+ int lb_color = 0;
+ coef_t constantTerm, coefficient;
+ int topEqn = nGEQs - 1;
+ coef_t Lc;
+ for (Le = topEqn; Le >= 0; Le--)
+ if ((Lc = GEQs[Le].coef[i]) == 0) {
+ if (GEQs[Le].coef[1] == 1) {
+ constantTerm = -GEQs[Le].coef[0];
+ if (constantTerm > lowerBound || (constantTerm == lowerBound && !isRed(&GEQs[Le]))) {
+ lowerBound = constantTerm;
+ lb_color = GEQs[Le].color;
+ }
+ if (DEBUG) {
+ if (GEQs[Le].color == EQ_BLACK)
+ fprintf(outputFile, " :::=> %s >= " coef_fmt "\n", variable(1), constantTerm);
+ else
+ fprintf(outputFile, " :::=> [%s >= " coef_fmt "]\n", variable(1), constantTerm);
+ }
+ }
+ else {
+ constantTerm = GEQs[Le].coef[0];
+ if (constantTerm < upperBound || (constantTerm == upperBound && !isRed(&GEQs[Le]))) {
+ upperBound = constantTerm;
+ ub_color = GEQs[Le].color;
+ }
+ if (DEBUG) {
+ if (GEQs[Le].color == EQ_BLACK)
+ fprintf(outputFile, " :::=> %s <= " coef_fmt "\n", variable(1), constantTerm);
+ else
+ fprintf(outputFile, " :::=> [%s <= " coef_fmt "]\n", variable(1), constantTerm);
+ }
+ }
+ }
+ else if (Lc > 0) {
+ for (Ue = topEqn; Ue >= 0; Ue--)
+ if (GEQs[Ue].coef[i] < 0) {
+ if (GEQs[Le].key != -GEQs[Ue].key) {
+ coef_t Uc = -GEQs[Ue].coef[i];
+ coefficient = check_mul(GEQs[Ue].coef[1], Lc) + check_mul(GEQs[Le].coef[1], Uc);
+ constantTerm = check_mul(GEQs[Ue].coef[0], Lc) + check_mul(GEQs[Le].coef[0], Uc);
+ if (DEBUG) {
+ printGEQextra(&(GEQs[Ue]));
+ fprintf(outputFile, "\n");
+ printGEQextra(&(GEQs[Le]));
+ fprintf(outputFile, "\n");
+ }
+ if (coefficient > 0) {
+ constantTerm = -(int_div(constantTerm, coefficient));
+ /* assert(black == 0) */
+ if (constantTerm > lowerBound ||
+ (constantTerm == lowerBound &&
+ (desiredResult != OC_SOLVE_SIMPLIFY || (GEQs[Ue].color == EQ_BLACK && GEQs[Le].color == EQ_BLACK)))) {
+ lowerBound = constantTerm;
+ lb_color = GEQs[Ue].color || GEQs[Le].color;
+ }
+ if (DEBUG) {
+ if (GEQs[Ue].color || GEQs[Le].color)
+ fprintf(outputFile, " ::=> [%s >= " coef_fmt "]\n", variable(1), constantTerm);
+ else
+ fprintf(outputFile, " ::=> %s >= " coef_fmt "\n", variable(1), constantTerm);
+ }
+ }
+ else if (coefficient < 0) {
+ constantTerm = (int_div(constantTerm, -coefficient));
+ if (constantTerm < upperBound ||
+ (constantTerm == upperBound && GEQs[Ue].color == EQ_BLACK && GEQs[Le].color == EQ_BLACK)) {
+ upperBound = constantTerm;
+ ub_color = GEQs[Ue].color || GEQs[Le].color;
+ }
+ if (DEBUG) {
+ if (GEQs[Ue].color || GEQs[Le].color)
+ fprintf(outputFile, " ::=> [%s <= " coef_fmt "]\n", variable(1), constantTerm);
+ else
+ fprintf(outputFile, " ::=> %s <= " coef_fmt "\n", variable(1), constantTerm);
+ }
+ }
+ }
+ }
+ }
+ nGEQs = 0;
+ if (DEBUG)
+ fprintf(outputFile, " therefore, %c" coef_fmt " <= %c%s%c <= " coef_fmt "%c\n", lb_color ? '[' : ' ', lowerBound, (lb_color && !ub_color) ? ']' : ' ', variable(1), (!lb_color && ub_color) ? '[' : ' ', upperBound, ub_color ? ']' : ' ');
+ if (lowerBound > upperBound)
+ return (false);
+
+ if (upperBound == lowerBound) {
+ int e = newEQ();
+ assert(e == 0);
+ EQs[e].coef[1] = -1;
+ EQs[e].coef[0] = upperBound;
+ EQs[e].color = ub_color | lb_color;
+ addingEqualityConstraint(0);
+ }
+ else if (safeVars == 1) {
+ if (upperBound != posInfinity) {
+ int e = newGEQ();
+ assert(e == 0);
+ GEQs[e].coef[1] = -1;
+ GEQs[e].coef[0] = upperBound;
+ GEQs[e].color = ub_color;
+ GEQs[e].key = -1;
+ GEQs[e].touched = 0;
+ }
+ if (lowerBound != negInfinity) {
+ int e = newGEQ();
+ GEQs[e].coef[1] = 1;
+ GEQs[e].coef[0] = -lowerBound;
+ GEQs[e].color = lb_color;
+ GEQs[e].key = 1;
+ GEQs[e].touched = 0;
+ }
+ }
+ if (safeVars == 0)
+ nVars = 0;
+ return (true);
+ }
+ eliminateAgain = 1;
+
+ {
+ int deadEqns[maxDead];
+ int numDead = 0;
+ int topEqn = nGEQs - 1;
+ int lowerBoundCount = 0;
+ for (Le = topEqn; Le >= 0; Le--)
+ if (GEQs[Le].coef[i] > 0)
+ lowerBoundCount++;
+ if (DEBUG)
+ fprintf(outputFile, "lower bound count = %d\n", lowerBoundCount);
+ if (lowerBoundCount == 0) {
+ if (desiredResult != OC_SOLVE_SIMPLIFY) fv = 0;
+ else fv = safeVars;
+ nVars++;
+ freeEliminations(fv);
+ continue;
+ }
+ for (Le = topEqn; Le >= 0; Le--)
+ if (GEQs[Le].coef[i] > 0) {
+ coef_t Lc = GEQs[Le].coef[i];
+ for (Ue = topEqn; Ue >= 0; Ue--)
+ if (GEQs[Ue].coef[i] < 0) {
+ if (GEQs[Le].key != -GEQs[Ue].key) {
+ coef_t Uc = -GEQs[Ue].coef[i];
+ int e2;
+ if (numDead == 0) {
+ /*( Big kludge warning ) */
+ /* this code is still using location nVars+1 */
+ /* but newGEQ, if it reallocates, only copies*/
+ /* locations up to nVars. This fixes that. */
+ nVars++;
+ e2 = newGEQ();
+ nVars--;
+ }
+ else {
+ e2 = deadEqns[--numDead];
+ }
+ if (DEBUG)
+ fprintf(outputFile, "Le = %d, Ue = %d, gen = %d\n", Le, Ue, e2);
+ if (DEBUG) {
+ printGEQextra(&(GEQs[Le]));
+ fprintf(outputFile, "\n");
+ printGEQextra(&(GEQs[Ue]));
+ fprintf(outputFile, "\n");
+ }
+ eliminateAgain = 0;
+ coef_t g = gcd(Lc,Uc);
+ coef_t Lc_over_g = Lc/g;
+ coef_t Uc_over_g = Uc/g;
+
+ for (k = nVars; k >= 0; k--)
+ GEQs[e2].coef[k] =
+ check_mul(GEQs[Ue].coef[k], Lc_over_g) + check_mul(GEQs[Le].coef[k], Uc_over_g);
+
+ GEQs[e2].coef[nVars + 1] = 0;
+ GEQs[e2].touched = true;
+ GEQs[e2].color = GEQs[Ue].color | GEQs[Le].color;
+
+ if (DEBUG) {
+ printGEQ(&(GEQs[e2]));
+ fprintf(outputFile, "\n");
+ }
+ }
+ if (lowerBoundCount == 1) {
+ deadEqns[numDead++] = Ue;
+ if (DEBUG)
+ fprintf(outputFile, "Killed %d\n", Ue);
+ }
+ }
+ lowerBoundCount--;
+ deadEqns[numDead++] = Le;
+ if (DEBUG)
+ fprintf(outputFile, "Killed %d\n", Le);
+ }
+
+ {
+ int isDead[maxmaxGEQs];
+ for (e = nGEQs - 1; e >= 0; e--)
+ isDead[e] = false;
+ while (numDead > 0) {
+ e = deadEqns[--numDead];
+ isDead[e] = true;
+ }
+ for (e = nGEQs - 1; e >= 0; e--)
+ if (isDead[e]) {
+ nVars++;
+ deleteGEQ(e);
+ nVars--;
+ }
+ }
+ continue;
+ }
+ }
+ else {
+ Problem *rS, *iS;
+
+ rS = new Problem;
+ iS = new Problem;
+
+ iS->nVars = rS->nVars = nVars; // do this immed.; in case of reallocation, we
+ // need to know how much to copy
+ rS->get_var_name = get_var_name;
+ rS->getVarNameArgs = getVarNameArgs;
+ iS->get_var_name = get_var_name;
+ iS->getVarNameArgs = getVarNameArgs;
+
+ for (e = 0; e < nGEQs; e++)
+ if (GEQs[e].coef[i] == 0) {
+ int re2 = rS->newGEQ();
+ int ie2 = iS->newGEQ();
+ eqnncpy(&(rS->GEQs[re2]), &GEQs[e], nVars);
+ eqnncpy(&(iS->GEQs[ie2]), &GEQs[e], nVars);
+ if (DEBUG) {
+ int t;
+ fprintf(outputFile, "Copying (%d, " coef_fmt "): ", i, GEQs[e].coef[i]);
+ printGEQextra(&GEQs[e]);
+ fprintf(outputFile, "\n");
+ for (t = 0; t <= nVars + 1; t++)
+ fprintf(outputFile, coef_fmt " ", GEQs[e].coef[t]);
+ fprintf(outputFile, "\n");
+ }
+ }
+ for (Le = nGEQs - 1; Le >= 0; Le--)
+ if (GEQs[Le].coef[i] > 0) {
+ coef_t Lc = GEQs[Le].coef[i];
+ for (Ue = nGEQs - 1; Ue >= 0; Ue--)
+ if (GEQs[Ue].coef[i] < 0)
+ if (GEQs[Le].key != -GEQs[Ue].key) {
+ coef_t Uc = -GEQs[Ue].coef[i];
+ coef_t g = gcd(Lc,Uc);
+ coef_t Lc_over_g = Lc/g;
+ coef_t Uc_over_g = Uc/g;
+ int re2 = rS->newGEQ();
+ int ie2 = iS->newGEQ();
+ rS->GEQs[re2].touched = iS->GEQs[ie2].touched = true;
+ if (DEBUG) {
+ fprintf(outputFile, "---\n");
+ fprintf(outputFile, "Le(Lc) = %d(" coef_fmt "), Ue(Uc) = %d(" coef_fmt "), gen = %d\n", Le, Lc, Ue, Uc, ie2);
+ printGEQextra(&GEQs[Le]);
+ fprintf(outputFile, "\n");
+ printGEQextra(&GEQs[Ue]);
+ fprintf(outputFile, "\n");
+ }
+
+ if (Uc == Lc) {
+ for (k = nVars; k >= 0; k--)
+ iS->GEQs[ie2].coef[k] = rS->GEQs[re2].coef[k] =
+ GEQs[Ue].coef[k] + GEQs[Le].coef[k];
+ iS->GEQs[ie2].coef[0] -= (Uc - 1);
+ }
+ else {
+ for (k = nVars; k >= 0; k--)
+ iS->GEQs[ie2].coef[k] = rS->GEQs[re2].coef[k] =
+ check_mul(GEQs[Ue].coef[k], Lc_over_g) + check_mul(GEQs[Le].coef[k], Uc_over_g);
+ iS->GEQs[ie2].coef[0] -= check_mul(Uc_over_g-1, Lc_over_g-1);
+ }
+
+ iS->GEQs[ie2].color = rS->GEQs[re2].color
+ = GEQs[Ue].color || GEQs[Le].color;
+
+ if (DEBUG) {
+ printGEQ(&(rS->GEQs[re2]));
+ fprintf(outputFile, "\n");
+ }
+ // ie2 = iS->newGEQ();
+ // re2 = rS->newGEQ();
+ }
+
+ }
+ iS->variablesInitialized = rS->variablesInitialized = 1;
+ iS->nEQs = rS->nEQs = 0;
+ assert(desiredResult != OC_SOLVE_SIMPLIFY);
+ assert(nSUBs == 0);
+ iS->nSUBs = rS->nSUBs = nSUBs;
+ iS->safeVars = rS->safeVars = safeVars;
+ int t;
+ for (t = nVars; t >= 0; t--)
+ rS->var[t] = var[t];
+ for (t = nVars; t >= 0; t--)
+ iS->var[t] = var[t];
+ nVars++;
+ if (desiredResult != true) {
+ int t = trace;
+ if (TRACE)
+ fprintf(outputFile, "\nreal solution(%d):\n", depth);
+ depth++;
+ trace = 0;
+ if (originalProblem == noProblem) {
+ originalProblem = this;
+ result = rS->solveGEQ(false);
+ originalProblem = noProblem;
+ }
+ else
+ result = rS->solveGEQ(false);
+ trace = t;
+ depth--;
+ if (result == false) {
+ delete rS;
+ delete iS;
+ return (result);
+ }
+
+ if (nEQs > 0) {
+ /* An equality constraint must have been found */
+ delete rS;
+ delete iS;
+ return (solve(desiredResult));
+ }
+ }
+ if (desiredResult != false) {
+ if (darkShadowFeasible) {
+ if (TRACE)
+ fprintf(outputFile, "\ninteger solution(%d):\n", depth);
+ depth++;
+ conservative++;
+ result = iS->solveGEQ(desiredResult);
+ conservative--;
+ depth--;
+ if (result != false) {
+ delete rS;
+ delete iS;
+ return (result);
+ }
+ }
+ if (TRACE)
+ fprintf(outputFile, "have to do exact analysis\n");
+
+ {
+ coef_t worstLowerBoundConstant=1;
+ int lowerBounds = 0;
+ int lowerBound[maxmaxGEQs];
+ int smallest;
+ int t;
+ conservative++;
+ for (e = 0; e < nGEQs; e++)
+ if (GEQs[e].coef[i] < -1) {
+ set_max(worstLowerBoundConstant,
+ -GEQs[e].coef[i]);
+ }
+ else if (GEQs[e].coef[i] > 1)
+ lowerBound[lowerBounds++] = e;
+ /* sort array */
+ for (j = 0; j < lowerBounds; j++) {
+ smallest = j;
+ for (k = j + 1; k < lowerBounds; k++)
+ if (GEQs[lowerBound[smallest]].coef[i] > GEQs[lowerBound[k]].coef[i])
+ smallest = k;
+ t = lowerBound[smallest];
+ lowerBound[smallest] = lowerBound[j];
+ lowerBound[j] = t;
+ }
+ if (DEBUG) {
+ fprintf(outputFile, "lower bound coeeficients = ");
+ for (j = 0; j < lowerBounds; j++)
+ fprintf(outputFile, " " coef_fmt, GEQs[lowerBound[j]].coef[i]);
+ fprintf(outputFile, "\n");
+ }
+
+
+ for (j = 0; j < lowerBounds; j++) {
+ coef_t maxIncr;
+ coef_t c;
+ e = lowerBound[j];
+ maxIncr = (check_mul(GEQs[e].coef[i]-1, worstLowerBoundConstant-1) - 1) / worstLowerBoundConstant;
+
+ /* maxIncr += 2; */
+ if ((doTrace && desiredResult == OC_SOLVE_SIMPLIFY) || DBUG) {
+ fprintf(outputFile, "for equation ");
+ printGEQ(&GEQs[e]);
+ fprintf(outputFile, "\ntry decrements from 0 to " coef_fmt "\n", maxIncr);
+ printProblem();
+ }
+ if (maxIncr > 50) {
+ if (!smoothed && smoothWeirdEquations()) {
+ conservative--;
+ delete rS;
+ delete iS;
+ smoothed = 1;
+ goto solveGEQstart;
+ }
+ }
+ int neweq = newEQ();
+ assert(neweq == 0);
+ eqnncpy(&EQs[neweq], &GEQs[e], nVars);
+ /*
+ * if (GEQs[e].color) fprintf(outputFile,"warning: adding black equality constraint
+ * based on red inequality\n");
+ */
+ EQs[neweq].color = EQ_BLACK;
+ eqnnzero(&GEQs[e], nVars);
+ GEQs[e].touched = true;
+ for (c = maxIncr; c >= 0; c--) {
+ if (DBUG)
+ fprintf(outputFile, "trying next decrement of " coef_fmt "\n", maxIncr - c);
+ if (DBUG)
+ printProblem();
+ *rS = *this;
+ if (DEBUG)
+ rS->printProblem();
+ result = rS->solve(desiredResult);
+ if (result == true) {
+ delete rS;
+ delete iS;
+ conservative--;
+ return (true);
+ }
+ EQs[0].coef[0]--;
+ }
+ if (j + 1 < lowerBounds) {
+ nEQs = 0;
+ eqnncpy(&GEQs[e], &EQs[0], nVars);
+ GEQs[e].touched = 1;
+ GEQs[e].color = EQ_BLACK;
+ *rS = *this;
+ if (DEBUG)
+ fprintf(outputFile, "exhausted lower bound, checking if still feasible ");
+ result = rS->solve(false);
+ if (result == false)
+ break;
+ }
+ }
+ if ((doTrace && desiredResult == OC_SOLVE_SIMPLIFY) || DBUG)
+ fprintf(outputFile, "fall-off the end\n");
+ delete rS;
+ delete iS;
+
+ conservative--;
+ return (false);
+ }
+ }
+ delete rS;
+ delete iS;
+ }
+ return (OC_SOLVE_UNKNOWN);
+ }
+ }
+ while (eliminateAgain);
+ }
+}
+
+
+int Problem::parallelSplinter(int e, int diff, int desiredResult) {
+ Problem *tmpProblem;
+ int i;
+ if (DBUG) {
+ fprintf(outputFile, "Using parallel splintering\n");
+ printProblem();
+ }
+ tmpProblem = new Problem;
+ int neweq = newEQ();
+ assert(neweq == 0);
+ eqnncpy(&EQs[0], &GEQs[e], nVars);
+ for (i = 0; i <= diff; i++) {
+ *tmpProblem = * this;
+ tmpProblem->isTemporary = true;
+ if (DBUG) {
+ fprintf(outputFile, "Splinter # %i\n", i);
+ printProblem();
+ }
+ if (tmpProblem->solve(desiredResult)) {
+ delete tmpProblem;
+ return true;
+ }
+ EQs[0].coef[0]--;
+ }
+ delete tmpProblem;
+ return false;
+}
+
+
+int Problem::verifyProblem() {
+ int result;
+ int e;
+ int areRed;
+ check();
+ Problem tmpProblem(*this);
+ tmpProblem.varsOfInterest = 0;
+ tmpProblem.safeVars = 0;
+ tmpProblem.nSUBs = 0;
+ tmpProblem.nMemories = 0;
+ tmpProblem.isTemporary = true;
+ areRed = 0;
+ if (mayBeRed) {
+ for(e=0; e<nEQs; e++) if (EQs[e].color) areRed = 1;
+ for(e=0; e<nGEQs; e++) if (GEQs[e].color) areRed = 1;
+ if (areRed) tmpProblem.turnRedBlack();
+ }
+ originalProblem = this;
+ assert(!outerColor);
+ outerColor = areRed;
+ if (TRACE) {
+ fprintf(outputFile, "verifying problem: [\n");
+ printProblem();
+ }
+ tmpProblem.check();
+ tmpProblem.freeEliminations(0);
+ result = tmpProblem.solve(OC_SOLVE_UNKNOWN);
+ originalProblem = noProblem;
+ outerColor = 0;
+ if (TRACE) {
+ if (result)
+ fprintf(outputFile, "] verified problem\n");
+ else
+ fprintf(outputFile, "] disproved problem\n");
+ printProblem();
+ }
+ check();
+ return result;
+}
+
+
+void Problem:: freeEliminations(int fv) {
+ int tryAgain = 1;
+ int i, e, e2;
+ while (tryAgain) {
+ tryAgain = 0;
+ for (i = nVars; i > fv; i--) {
+ for (e = nGEQs - 1; e >= 0; e--)
+ if (GEQs[e].coef[i])
+ break;
+ if (e < 0)
+ e2 = e;
+ else if (GEQs[e].coef[i] > 0) {
+ for (e2 = e - 1; e2 >= 0; e2--)
+ if (GEQs[e2].coef[i] < 0)
+ break;
+ }
+ else {
+ for (e2 = e - 1; e2 >= 0; e2--)
+ if (GEQs[e2].coef[i] > 0)
+ break;
+ }
+ if (e2 < 0) {
+ int e3;
+ for (e3 = nSUBs - 1; e3 >= 0; e3--)
+ if (SUBs[e3].coef[i])
+ break;
+ if (e3 >= 0)
+ continue;
+ for (e3 = nEQs - 1; e3 >= 0; e3--)
+ if (EQs[e3].coef[i])
+ break;
+ if (e3 >= 0)
+ continue;
+ if (DBUG)
+ fprintf(outputFile, "a free elimination of %s (%d)\n", variable(i),e);
+ if (e >= 0) {
+ deleteGEQ(e);
+ for (e--; e >= 0; e--)
+ if (GEQs[e].coef[i]) {
+ deleteGEQ(e);
+ }
+ tryAgain = (i < nVars);
+ }
+ deleteVariable(i);
+ }
+ }
+ }
+
+ if (DEBUG) {
+ fprintf(outputFile, "\nafter free eliminations:\n");
+ printProblem();
+ fprintf(outputFile, "\n");
+ }
+}
+
+
+void Problem::freeRedEliminations() {
+ int tryAgain = 1;
+ int i, e, e2;
+ int isRedVar[maxVars];
+ int isDeadVar[maxVars];
+ int isDeadGEQ[maxmaxGEQs];
+ for (i = nVars; i > 0; i--) {
+ isRedVar[i] = 0;
+ isDeadVar[i] = 0;
+ }
+ for (e = nGEQs - 1; e >= 0; e--) {
+ isDeadGEQ[e] = 0;
+ if (GEQs[e].color)
+ for (i = nVars; i > 0; i--)
+ if (GEQs[e].coef[i] != 0)
+ isRedVar[i] = 1;
+ }
+
+ while (tryAgain) {
+ tryAgain = 0;
+ for (i = nVars; i > 0; i--)
+ if (!isRedVar[i] && !isDeadVar[i]) {
+ for (e = nGEQs - 1; e >= 0; e--)
+ if (!isDeadGEQ[e] && GEQs[e].coef[i])
+ break;
+ if (e < 0)
+ e2 = e;
+ else if (GEQs[e].coef[i] > 0) {
+ for (e2 = e - 1; e2 >= 0; e2--)
+ if (!isDeadGEQ[e2] && GEQs[e2].coef[i] < 0)
+ break;
+ }
+ else {
+ for (e2 = e - 1; e2 >= 0; e2--)
+ if (!isDeadGEQ[e2] && GEQs[e2].coef[i] > 0)
+ break;
+ }
+ if (e2 < 0) {
+ int e3;
+ for (e3 = nSUBs - 1; e3 >= 0; e3--)
+ if (SUBs[e3].coef[i])
+ break;
+ if (e3 >= 0)
+ continue;
+ for (e3 = nEQs - 1; e3 >= 0; e3--)
+ if (EQs[e3].coef[i])
+ break;
+ if (e3 >= 0)
+ continue;
+ if (DBUG)
+ fprintf(outputFile, "a free red elimination of %s\n", variable(i));
+ for (; e >= 0; e--)
+ if (GEQs[e].coef[i])
+ isDeadGEQ[e] = 1;
+ tryAgain = 1;
+ isDeadVar[i] = 1;
+ }
+ }
+ }
+
+ for (e = nGEQs - 1; e >= 0; e--)
+ if (isDeadGEQ[e])
+ deleteGEQ(e);
+
+ for (i = nVars; i > safeVars; i--)
+ if (isDeadVar[i])
+ deleteVariable(i);
+
+
+ if (DEBUG) {
+ fprintf(outputFile, "\nafter free red eliminations:\n");
+ printProblem();
+ fprintf(outputFile, "\n");
+ }
+}
+
+} // namespace
diff --git a/omegalib/omega/src/omega_core/oc_util.cc b/omegalib/omega/src/omega_core/oc_util.cc
new file mode 100644
index 0000000..a7d21be
--- /dev/null
+++ b/omegalib/omega/src/omega_core/oc_util.cc
@@ -0,0 +1,327 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 the Omega Project Team
+ Copyright (C) 2005-2011 Chun Chen
+ All Rights Reserved.
+
+ Purpose:
+
+ Notes:
+
+ History:
+*****************************************************************************/
+
+#include <omega/omega_core/oc_i.h>
+#include <algorithm>
+
+namespace omega {
+
+void Problem:: problem_merge(Problem &p2) {
+ int newLocation[maxVars];
+ int i,e2;
+
+ resurrectSubs();
+ p2.resurrectSubs();
+ setExternals();
+ p2.setExternals();
+
+ assert(safeVars == p2.safeVars);
+ if(DBUG) {
+ fprintf(outputFile,"Merging:\n");
+ printProblem();
+ fprintf(outputFile,"and\n");
+ p2.printProblem();
+ }
+ for(i=1; i<= p2.safeVars; i++) {
+ assert(p2.var[i] > 0) ;
+ newLocation[i] = forwardingAddress[p2.var[i]];
+ }
+ for(; i<= p2.nVars; i++) {
+ int j = ++(nVars);
+ newLocation[i] = j;
+ zeroVariable(j);
+ var[j] = -1;
+ }
+ newLocation[0] = 0;
+
+ for (e2 = p2.nEQs - 1; e2 >= 0; e2--) {
+ int e1 = newEQ();
+ eqnnzero(&(EQs[e1]), nVars);
+ for(i=0;i<=p2.nVars;i++)
+ EQs[e1].coef[newLocation[i]] = p2.EQs[e2].coef[i];
+ }
+ for (e2 = p2.nGEQs - 1; e2 >= 0; e2--) {
+ int e1 = newGEQ();
+ eqnnzero(&(GEQs[e1]), nVars);
+ GEQs[e1].touched = 1;
+ for(i=0;i<=p2.nVars;i++)
+ GEQs[e1].coef[newLocation[i]] = p2.GEQs[e2].coef[i];
+ }
+ int w = -1;
+ for (i = 1; i <= nVars; i++)
+ if (var[i] < 0) var[i] = w--;
+ if(DBUG) {
+ fprintf(outputFile,"to get:\n");
+ printProblem();
+ }
+}
+
+
+
+void Problem::chainUnprotect() {
+ int i, e;
+ int unprotect[maxVars];
+ int any = 0;
+ for (i = 1; i <= safeVars; i++) {
+ unprotect[i] = (var[i] < 0);
+ for (e = nSUBs - 1; e >= 0; e--)
+ if (SUBs[e].coef[i])
+ unprotect[i] = 0;
+ }
+ for (i = 1; i <= safeVars; i++) if (unprotect[i]) any=1;
+ if (!any) return;
+
+ if (DBUG) {
+ fprintf(outputFile, "Doing chain reaction unprotection\n");
+ printProblem();
+ for (i = 1; i <= safeVars; i++)
+ if (unprotect[i])
+ fprintf(outputFile, "unprotecting %s\n", variable(i));
+ }
+ for (i = 1; i <= safeVars; i++)
+ if (unprotect[i]) {
+ /* wild card */
+ if (i < safeVars) {
+ int j = safeVars;
+ std::swap(var[i], var[j]);
+ for (e = nGEQs - 1; e >= 0; e--) {
+ GEQs[e].touched = 1;
+ std::swap(GEQs[e].coef[i], GEQs[e].coef[j]);
+ }
+ for (e = nEQs - 1; e >= 0; e--)
+ std::swap(EQs[e].coef[i], EQs[e].coef[j]);
+ for (e = nSUBs - 1; e >= 0; e--)
+ std::swap(SUBs[e].coef[i], SUBs[e].coef[j]);
+ std::swap(unprotect[i], unprotect[j]);
+ i--;
+ }
+ safeVars--;
+ }
+ if (DBUG) {
+ fprintf(outputFile, "After chain reactions\n");
+ printProblem();
+ }
+}
+
+void Problem::resurrectSubs() {
+ if (nSUBs > 0 && !pleaseNoEqualitiesInSimplifiedProblems) {
+ int i, e, n, m,mbr;
+ mbr = 0;
+ for (e = nGEQs - 1; e >= 0; e--) if (GEQs[e].color) mbr=1;
+ for (e = nEQs - 1; e >= 0; e--) if (EQs[e].color) mbr=1;
+ if (nMemories) mbr = 1;
+
+ assert(!mbr || mayBeRed);
+
+ if (DBUG) {
+ fprintf(outputFile, "problem reduced, bringing variables back to life\n");
+ if(mbr && !mayBeRed) fprintf(outputFile, "Red equations we don't expect\n");
+ printProblem();
+ }
+ if (DBUG && nEQs > 0)
+ fprintf(outputFile,"This is wierd: problem has equalities\n");
+
+ for (i = 1; i <= safeVars; i++)
+ if (var[i] < 0) {
+ /* wild card */
+ if (i < safeVars) {
+ int j = safeVars;
+ std::swap(var[i], var[j]);
+ for (e = nGEQs - 1; e >= 0; e--) {
+ GEQs[e].touched = 1;
+ std::swap(GEQs[e].coef[i], GEQs[e].coef[j]);
+ }
+ for (e = nEQs - 1; e >= 0; e--)
+ std::swap(EQs[e].coef[i], EQs[e].coef[j]);
+ for (e = nSUBs - 1; e >= 0; e--)
+ std::swap(SUBs[e].coef[i], SUBs[e].coef[j]);
+ i--;
+ }
+ safeVars--;
+ }
+
+ m = nSUBs;
+ n = nVars;
+ if (n < safeVars + m)
+ n = safeVars + m;
+ for (e = nGEQs - 1; e >= 0; e--) {
+ if (singleVarGEQ(&GEQs[e])) {
+ i = abs(GEQs[e].key);
+ if (i >= safeVars + 1)
+ GEQs[e].key += (GEQs[e].key > 0 ? m : -m);
+ }
+ else {
+ GEQs[e].touched = true;
+ GEQs[e].key = 0;
+ }
+ }
+ for (i = nVars; i >= safeVars + 1; i--) {
+ var[i + m] = var[i];
+ for (e = nGEQs - 1; e >= 0; e--)
+ GEQs[e].coef[i + m] = GEQs[e].coef[i];
+ for (e = nEQs - 1; e >= 0; e--)
+ EQs[e].coef[i + m] = EQs[e].coef[i];
+ for (e = nSUBs - 1; e >= 0; e--)
+ SUBs[e].coef[i + m] = SUBs[e].coef[i];
+ }
+ for (i = safeVars + m; i >= safeVars + 1; i--) {
+ for (e = nGEQs - 1; e >= 0; e--) GEQs[e].coef[i] = 0;
+ for (e = nEQs - 1; e >= 0; e--) EQs[e].coef[i] = 0;
+ for (e = nSUBs - 1; e >= 0; e--) SUBs[e].coef[i] = 0;
+ }
+ nVars += m;
+ safeVars += m;
+ for (e = nSUBs - 1; e >= 0; e--)
+ var[safeVars -m + 1 + e] = SUBs[e].key;
+ for (i = 1; i <= safeVars; i++)
+ forwardingAddress[var[i]] = i;
+ if (DBUG) {
+ fprintf(outputFile,"Ready to wake substitutions\n");
+ printProblem();
+ }
+ for (e = nSUBs - 1; e >= 0; e--) {
+ int neweq = newEQ();
+ eqnncpy(&(EQs[neweq]), &(SUBs[e]), nVars);
+ EQs[neweq].coef[safeVars -m + 1 + e] = -1;
+ EQs[neweq].color = EQ_BLACK;
+ if (DBUG) {
+ fprintf(outputFile, "brought back: ");
+ printEQ(&EQs[neweq]);
+ fprintf(outputFile, "\n");
+ }
+ }
+ nSUBs = 0;
+
+ if (DBUG) {
+ fprintf(outputFile, "variables brought back to life\n");
+ printProblem();
+ }
+ }
+
+ coalesce();
+ recallRedMemories();
+ cleanoutWildcards();
+}
+
+
+void Problem::reverseProtectedVariables() {
+ int v1,v2,e,i;
+ coef_t t;
+ for (v1 = 1; v1 <= safeVars; v1++) {
+ v2 = safeVars+1-v1;
+ if (v2>=v1) break;
+ for(e=0;e<nEQs;e++) {
+ t = EQs[e].coef[v1];
+ EQs[e].coef[v1] = EQs[e].coef[v2];
+ EQs[e].coef[v2] = t;
+ }
+ for(e=0;e<nGEQs;e++) {
+ t = GEQs[e].coef[v1];
+ GEQs[e].coef[v1] = GEQs[e].coef[v2];
+ GEQs[e].coef[v2] = t;
+ GEQs[e].touched = 1;
+ }
+ for(e=0;e<nSUBs;e++) {
+ t = SUBs[e].coef[v1];
+ SUBs[e].coef[v1] = SUBs[e].coef[v2];
+ SUBs[e].coef[v2] = t;
+ }
+ }
+
+ for (i = 1; i <= safeVars; i++)
+ forwardingAddress[var[i]] = i;
+ for (i = 0; i < nSUBs; i++)
+ forwardingAddress[SUBs[i].key] = -i - 1;
+}
+
+void Problem::ordered_elimination(int symbolic) {
+ int i,j,e;
+ int isDead[maxmaxGEQs];
+ for(e=0;e<nEQs;e++) isDead[e] = 0;
+
+ if (!variablesInitialized) {
+ initializeVariables();
+ }
+
+ for(i=nVars;i>symbolic;i--)
+ for(e=0;e<nEQs;e++)
+ if (EQs[e].coef[i] == 1 || EQs[e].coef[i] == -1) {
+ for(j=nVars;j>i;j--) if (EQs[e].coef[j]) break;
+ if (i==j) {
+ doElimination(e, i);
+ isDead[e] = 1;
+ break;
+ }
+ }
+
+ for(e=nEQs-1;e>=0;e--)
+ if (isDead[e]) {
+ nEQs--;
+ if (e < nEQs) eqnncpy(&EQs[e], &EQs[nEQs], nVars);
+ }
+
+ for (i = 1; i <= safeVars; i++)
+ forwardingAddress[var[i]] = i;
+ for (i = 0; i < nSUBs; i++)
+ forwardingAddress[SUBs[i].key] = -i - 1;
+}
+
+
+coef_t Problem::checkSum() const {
+ coef_t cs;
+ int e;
+ cs = 0;
+ for(e=0;e<nGEQs;e++) {
+ coef_t c = GEQs[e].coef[0];
+ cs += c*c*c;
+ }
+ return cs;
+}
+
+
+void Problem::coalesce() {
+ int e, e2, colors;
+ int isDead[maxmaxGEQs];
+ int foundSomething = 0;
+
+
+ colors = 0;
+ for (e = 0; e < nGEQs; e++)
+ if (GEQs[e].color)
+ colors++;
+ if (colors < 2)
+ return;
+ for (e = 0; e < nGEQs; e++)
+ isDead[e] = 0;
+ for (e = 0; e < nGEQs; e++)
+ if (!GEQs[e].touched)
+ for (e2 = e + 1; e2 < nGEQs; e2++)
+ if (!GEQs[e2].touched && GEQs[e].key == -GEQs[e2].key
+ && GEQs[e].coef[0] == -GEQs[e2].coef[0]) {
+ int neweq = newEQ();
+ eqnncpy(&EQs[neweq], &GEQs[e], nVars);
+ EQs[neweq].color = GEQs[e].color || GEQs[e2].color;
+ foundSomething++;
+ isDead[e] = 1;
+ isDead[e2] = 1;
+ }
+ for (e = nGEQs - 1; e >= 0; e--)
+ if (isDead[e]) {
+ deleteGEQ(e);
+ }
+ if (DEBUG && foundSomething) {
+ fprintf(outputFile, "Coalesced GEQs into %d EQ's:\n", foundSomething);
+ printProblem();
+ }
+}
+
+} // namespace
diff --git a/omegalib/omega/src/pres_beaut.cc b/omegalib/omega/src/pres_beaut.cc
new file mode 100644
index 0000000..c23962a
--- /dev/null
+++ b/omegalib/omega/src/pres_beaut.cc
@@ -0,0 +1,235 @@
+#include <omega/pres_tree.h>
+#include <omega/pres_conj.h>
+#include <omega/Relation.h>
+#include <omega/omega_i.h>
+
+/////////////////////////
+// //
+// Beautify functions //
+// //
+/////////////////////////
+
+
+namespace omega {
+
+//
+// f & true = f
+// f | false = f
+// f1 & f2 & ... & fn = Conjunct(f1,f2,...,fn)
+//
+
+void Rel_Body::beautify() {
+ assert(children().length()==1);
+ set_parent(NULL,this);
+
+ skip_finalization_check++;
+ formula()->beautify();
+ Formula *child = formula();
+ if(child->node_type()==Op_And && child->children().empty()) {
+ remove_child(child);
+ delete child;
+ add_conjunct();
+ }
+ skip_finalization_check--;
+
+ if(pres_debug) {
+ fprintf(DebugFile, "\n=== Beautified TREE ===\n");
+ prefix_print(DebugFile);
+ }
+ assert(children().length()==1);
+}
+
+void Formula::beautify() {
+ // copy list of children, as they may be removed as we work
+ List<Formula*> kiddies = myChildren;
+
+ for(List_Iterator<Formula*> c(kiddies); c; c++)
+ (*c)->beautify();
+}
+
+void F_Exists::beautify() {
+ Formula::beautify();
+ assert(children().length()==1);
+
+ if(myLocals.empty()) {
+ // exists( : ***)
+ parent().remove_child(this);
+ parent().add_child(children().remove_front());
+ delete this;
+ }
+ else if (children()[1]->node_type() == Op_And && children()[1]->children().empty()) {
+ // exists(*** : TRUE) --chun 6/4/2008
+ parent().remove_child(this);
+ parent().add_child(children().remove_front());
+ delete this;
+ }
+ else {
+ Formula *child = children().front();
+ if(child->node_type() == Op_Conjunct || child->node_type() == Op_Exists) {
+ child->push_exists(myLocals);
+ parent().remove_child(this);
+ parent().add_child(child);
+ children().remove_front();
+ delete this;
+ }
+ }
+}
+
+void F_Forall::beautify() {
+ Formula::beautify();
+ assert(children().length()==1);
+
+ if(myLocals.empty()) {
+ parent().remove_child(this);
+ parent().add_child(children().remove_front());
+ delete this;
+ }
+}
+
+
+//
+// The Pix-free versions of beautify for And and Or are a bit
+// less efficient than the previous code, as we keep moving
+// things from one list to another, but they do not depend on
+// knowing that a Pix is valid after the list is updated, and
+// they can always be optimized later if necessary.
+//
+
+void F_Or::beautify() {
+ Formula::beautify();
+
+ List<Formula*> uglies, beauties;
+ uglies.join(children()); assert(children().empty());
+#if ! defined NDEBUG
+ foreach(c,Formula*,uglies,c->set_parent(0));
+#endif
+
+ while(!uglies.empty()) {
+ Formula *f = uglies.remove_front();
+ if(f->node_type()==Op_And && f->children().empty() ) {
+ // smth | true = true
+ foreach(c,Formula*,uglies,delete c);
+ foreach(c,Formula*,beauties,delete c);
+ parent().remove_child(this);
+ parent().add_and();
+ delete f;
+ delete this;
+ return;
+ }
+ else if(f->node_type()==Op_Or) {
+ // OR(f[1-m], OR(c[1-n])) = OR(f[1-m], c[1-n])
+#if ! defined NDEBUG
+ foreach(c,Formula*,f->children(),c->set_parent(0));
+#endif
+ uglies.join(f->children());
+ delete f;
+ }
+ else
+ beauties.prepend(f);
+ }
+
+ if(beauties.length()==1) {
+ beauties.front()->set_parent(&parent());
+ parent().remove_child(this);
+ parent().add_child(beauties.remove_front());
+ delete this;
+ }
+ else {
+ foreach(c,Formula*,beauties,(c->set_parent(this),
+ c->set_relation(relation())));
+ assert(children().empty());
+ children().join(beauties);
+ }
+}
+
+void F_And::beautify() {
+ Formula::beautify();
+
+ Conjunct *conj = NULL;
+
+ List<Formula*> uglies, beauties;
+ uglies.join(children()); assert(children().empty());
+#if ! defined NDEBUG
+ foreach(c,Formula*,uglies,c->set_parent(0));
+#endif
+
+ while(!uglies.empty()) {
+ Formula *f = uglies.remove_front();
+ if (f->node_type() == Op_Conjunct) {
+ if(conj==NULL)
+ conj = f->really_conjunct();
+ else {
+ Conjunct *conj1 = merge_conjs(conj, f->really_conjunct(), MERGE_REGULAR);
+ delete f;
+ delete conj;
+ conj = conj1;
+ }
+ }
+ else if(f->node_type()==Op_Or && f->children().empty()) {
+ // smth & false = false
+ foreach(c,Formula*,uglies,delete c);
+ foreach(c,Formula*,beauties,delete c);
+ parent().remove_child(this);
+ parent().add_or();
+ delete f;
+ delete conj;
+ delete this;
+ return;
+ }
+ else if(f->node_type()==Op_And) {
+ // AND(f[1-m], AND(c[1-n])) = AND(f[1-m], c[1-n])
+#if ! defined NDEBUG
+ foreach(c,Formula*,f->children(),c->set_parent(0));
+#endif
+ uglies.join(f->children());
+ delete f;
+ }
+ else
+ beauties.prepend(f);
+ }
+
+ if(conj!=NULL)
+ beauties.prepend(conj);
+
+ if(beauties.length()==1) {
+ beauties.front()->set_parent(&parent());
+ parent().remove_child(this);
+ parent().add_child(beauties.remove_front());
+ delete this;
+ }
+ else {
+ foreach(c,Formula*,beauties,(c->set_parent(this),
+ c->set_relation(relation())));
+ assert(children().empty());
+ children().join(beauties);
+ }
+}
+
+void F_Not::beautify() {
+ Formula::beautify();
+ assert(children().length()==1);
+ Formula *child = children().front();
+
+ if(child->node_type()==Op_And && child->children().empty()) {
+ // Not TRUE = FALSE
+ parent().remove_child(this);
+ parent().add_or();
+ delete this;
+ }
+ else if (child->node_type()==Op_Or && child->children().empty()) {
+ // Not FALSE = TRUE
+ parent().remove_child(this);
+ parent().add_and();
+ delete this;
+ }
+}
+
+void Conjunct::beautify() {
+ if(is_true()) {
+ parent().remove_child(this);
+ parent().add_and();
+ delete this;
+ }
+}
+
+} // namespace
diff --git a/omegalib/omega/src/pres_cnstr.cc b/omegalib/omega/src/pres_cnstr.cc
new file mode 100644
index 0000000..a8ebd15
--- /dev/null
+++ b/omegalib/omega/src/pres_cnstr.cc
@@ -0,0 +1,450 @@
+#include <omega/pres_cnstr.h>
+#include <omega/pres_conj.h>
+#include <omega/Relation.h>
+#include <omega/omega_i.h>
+
+namespace omega {
+
+Constraint_Handle::Constraint_Handle(Conjunct *_c, eqn **_eqns, int _e):
+ c(_c), eqns(_eqns), e(_e) {
+}
+
+GEQ_Handle::GEQ_Handle(Conjunct *_c, int _e):
+ Constraint_Handle(_c,&(_c->problem->GEQs),_e) {
+}
+
+bool Constraint_Handle::is_const(Variable_ID v) {
+ bool is_const=true;
+ for(Constr_Vars_Iter cvi(*this, false); cvi && is_const; cvi++)
+ is_const = ((*cvi).coef == 0 || ((*cvi).var == v && (*cvi).coef !=0));
+ return is_const;
+}
+
+bool Constraint_Handle::is_const_except_for_global(Variable_ID v){
+ bool is_const=true;
+ for(Constr_Vars_Iter cvi(*this, false); cvi && is_const; cvi++)
+ if((*cvi).var->kind() != Global_Var)
+ is_const = ((*cvi).coef == 0 || ((*cvi).var == v && (*cvi).coef !=0));
+ return is_const;
+}
+
+bool EQ_Handle::operator==(const Constraint_Handle &that) {
+ Constraint_Handle &e1=*this;
+ const Constraint_Handle &e2=that;
+ int sign = 0;
+ for(Constr_Vars_Iter cvi(e1, false); cvi; cvi++) {
+ coef_t c1 = (*cvi).coef;
+ coef_t c2 = e2.get_coef((*cvi).var);
+ if (sign == 0) sign = (c1*c2>=0?1:-1);
+ if (sign*c1 != c2) return false;
+ }
+ assert(sign != 0);
+ {
+ for(Constr_Vars_Iter cvi(e2, false); cvi; cvi++) {
+ coef_t c1 = e1.get_coef((*cvi).var);
+ coef_t c2 = (*cvi).coef;
+ if (sign*c1 != c2) return false;
+ }
+ }
+ return sign * e1.get_const() == e2.get_const();
+}
+
+bool GEQ_Handle::operator==(const Constraint_Handle &that) {
+ Constraint_Handle &e1=*this;
+ const Constraint_Handle &e2=that;
+ for(Constr_Vars_Iter cvi(e1, false); cvi; cvi++) {
+ coef_t c1 = (*cvi).coef;
+ coef_t c2 = e2.get_coef((*cvi).var);
+ if (c1 != c2) return false;
+ }
+ {
+ for(Constr_Vars_Iter cvi(e2, false); cvi; cvi++) {
+ coef_t c1 = e1.get_coef((*cvi).var);
+ coef_t c2 = (*cvi).coef;
+ if (c1 != c2) return false;
+ }
+ }
+ return e1.get_const() == e2.get_const();
+}
+
+
+
+
+void GEQ_Handle::negate() {
+ assert(! this->relation()->is_simplified());
+ int i;
+ for(i=1; i<=c->problem->nVars; i++) {
+ (*eqns)[e].coef[i] = -(*eqns)[e].coef[i];
+ }
+ (*eqns)[e].coef[0] = -(*eqns)[e].coef[0]-1;
+}
+
+bool Constraint_Handle::has_wildcards() const {
+ Constr_Vars_Iter C(*this, true);
+ if (C.live()) {
+ assert(C.curr_var()->kind() == Wildcard_Var);
+ assert(C.curr_coef() != 0);
+ return 1;
+ }
+ return 0;
+}
+
+int Constraint_Handle::max_tuple_pos() const {
+ int m = 0;
+ for( Constr_Vars_Iter C(*this, false); C.live() ; C.next()) {
+ switch (C.curr_var()->kind()) {
+ case Input_Var:
+ case Output_Var: {
+ int pos = C.curr_var()->get_position();
+ if (m < pos) m = pos;
+ break;
+ }
+ default:
+ ;
+ }
+ }
+ return m;
+}
+
+int Constraint_Handle::min_tuple_pos() const {
+ int m = 0;
+ for( Constr_Vars_Iter C(*this, false); C.live() ; C.next()) {
+ switch (C.curr_var()->kind()) {
+ case Input_Var:
+ case Output_Var: {
+ int pos = C.curr_var()->get_position();
+ if (m == 0 || m > pos) m = pos;
+ break;
+ }
+ default:
+ ;
+ }
+ }
+ return m;
+}
+
+
+EQ_Handle::EQ_Handle(Conjunct *_c, int _e): Constraint_Handle(_c,&(_c->problem->EQs),_e) {
+}
+
+//
+// Update functions.
+//
+void Constraint_Handle::update_coef(Variable_ID D, coef_t I) {
+ assert(! this->relation()->is_simplified());
+ assert(D != 0);
+ // The next two assertions are somewhat high-cost.
+#if !defined(NDEBUG)
+ // skip_set_checks++;
+ assert((D->kind() != Input_Var || D->get_position() <= this->relation()->n_inp()));
+ assert((D->kind() != Output_Var || D->get_position() <= this->relation()->n_out()));
+ // skip_set_checks--;
+#endif
+ int col = c->get_column(D);
+ (*eqns)[e].coef[col] += I;
+}
+
+void Constraint_Handle::update_const(coef_t I) {
+ assert(! this->relation()->is_simplified());
+ (*eqns)[e].coef[0] += I;
+}
+
+
+// update a coefficient of a variable that already exists in mappedvars
+
+void Constraint_Handle::update_coef_during_simplify(Variable_ID D, coef_t I) {
+ assert(D != 0);
+ int col = c->get_column(D);
+ (*eqns)[e].coef[col] += I;
+}
+
+void Constraint_Handle::update_const_during_simplify(coef_t I) {
+ (*eqns)[e].coef[0] += I;
+}
+
+//
+// Get functions.
+//
+
+coef_t Constraint_Handle::get_coef(Variable_ID v) const {
+ assert(this->relation()->is_simplified());
+ assert(v != 0);
+ int col = c->find_column(v);
+ if(col == 0) {
+ return 0;
+ }
+ else {
+ return (*eqns)[e].coef[col];
+ }
+}
+
+coef_t Constraint_Handle::get_coef_during_simplify(Variable_ID v) const {
+ assert(v != 0);
+ int col = c->find_column(v);
+ if(col == 0) {
+ return 0;
+ }
+ else {
+ return (*eqns)[e].coef[col];
+ }
+}
+
+coef_t Constraint_Handle::get_const() const {
+ assert(this->relation()->is_simplified());
+ return((*eqns)[e].coef[0]);
+}
+
+coef_t Constraint_Handle::get_const_during_simplify() const {
+ return((*eqns)[e].coef[0]);
+}
+
+Variable_ID Constraint_Handle::get_local(const Global_Var_ID G) {
+ return relation()->get_local(G);
+}
+
+Variable_ID Constraint_Handle::get_local(const Global_Var_ID G, Argument_Tuple of) {
+ return relation()->get_local(G, of);
+}
+
+void Constraint_Handle::finalize() {
+ c->n_open_constraints--;
+}
+
+void Constraint_Handle::multiply(int multiplier) {
+ int i;
+ assert(! this->relation()->is_simplified());
+ for(i=1; i<=c->problem->nVars; i++) {
+ (*eqns)[e].coef[i] = (*eqns)[e].coef[i] * multiplier;
+ }
+ (*eqns)[e].coef[0] = (*eqns)[e].coef[0] * multiplier;
+}
+
+Rel_Body *Constraint_Handle::relation() const {
+ return c->relation();
+}
+
+
+//
+// Variables of constraint iterator.
+//
+Constr_Vars_Iter::Constr_Vars_Iter(const Constraint_Handle &ch, bool _wild_only): eqns(ch.eqns), e(ch.e), prob(ch.c->problem), vars(ch.c->mappedVars), wild_only(_wild_only) {
+ assert(vars.size() == prob->nVars);
+ for(current=1; current<=prob->nVars; current++) {
+ if((*eqns)[e].coef[current]!=0 &&
+ (!wild_only || vars[current]->kind()==Wildcard_Var))
+ return;
+ }
+}
+
+int Constr_Vars_Iter::live() const {
+ return (current<=prob->nVars);
+}
+
+
+void Constr_Vars_Iter::operator++() { this->operator++(0); }
+
+void Constr_Vars_Iter::operator++(int) {
+ for(current++ ; current <=prob->nVars; current++)
+ if((*eqns)[e].coef[current]!=0 &&
+ (!wild_only || vars[current]->kind()==Wildcard_Var))
+ return;
+}
+
+
+Variable_ID Constr_Vars_Iter::curr_var() const {
+ assert(current <= prob->nVars);
+ return vars[current];
+}
+
+coef_t Constr_Vars_Iter::curr_coef() const {
+ assert(current <= prob->nVars);
+ return (*eqns)[e].coef[current];
+}
+
+Variable_Info Constr_Vars_Iter::operator*() const {
+ assert(current <= prob->nVars);
+ return Variable_Info(vars[current],(*eqns)[e].coef[current]);
+}
+
+//
+// Constraint iterator.
+//
+Constraint_Iterator Conjunct::constraints() {
+ return Constraint_Iterator(this);
+}
+
+Constraint_Iterator::Constraint_Iterator(Conjunct *_c): c(_c), current(0),
+ last(c->problem->nGEQs-1), eqns(&(c->problem->GEQs)) {
+ if(!this->live()) (*this)++; // switch to EQ's if no GEQs
+}
+
+int Constraint_Iterator::live() const {
+ return current <=last;
+}
+
+void Constraint_Iterator::operator++() {
+ this->operator++(0);
+}
+
+void Constraint_Iterator::operator++(int) {
+ if(++current > last)
+ if(eqns == &(c->problem->GEQs)) { // Switch to EQs
+ eqns = &(c->problem->EQs);
+ current = 0;
+ last = c->problem->nEQs-1;
+ }
+}
+
+Constraint_Handle Constraint_Iterator::operator*() {
+ assert((c && eqns && current <= last) && "Constraint_Iterator::operator*: bad call");
+ return Constraint_Handle(c,eqns,current);
+}
+
+Constraint_Handle Constraint_Iterator::operator*() const {
+ assert((c && eqns && current <= last) && "Constraint_Iterator::operator*: bad call");
+ return Constraint_Handle(c,eqns,current);
+}
+
+
+//
+// EQ iterator.
+//
+EQ_Iterator Conjunct::EQs() {
+ return EQ_Iterator(this);
+}
+
+EQ_Iterator::EQ_Iterator(Conjunct *_c) : c(_c) {
+ last = c->problem->nEQs-1;
+ current = 0;
+}
+
+int EQ_Iterator::live() const {
+ return current <= last;
+}
+
+void EQ_Iterator::operator++() {
+ this->operator++(0);
+}
+
+void EQ_Iterator::operator++(int) {
+ current++;
+}
+
+EQ_Handle EQ_Iterator::operator*() {
+ assert((c && current <= last) && "EQ_Iterator::operator*: bad call");
+ return EQ_Handle(c,current);
+}
+
+EQ_Handle EQ_Iterator::operator*() const {
+ assert((c && current <= last) && "EQ_Iterator::operator*: bad call");
+ return EQ_Handle(c,current);
+}
+
+
+//
+// GEQ iterator.
+//
+GEQ_Iterator Conjunct::GEQs() {
+ return GEQ_Iterator(this);
+}
+
+GEQ_Iterator::GEQ_Iterator(Conjunct *_c) : c(_c) {
+ last = c->problem->nGEQs-1;
+ current = 0;
+}
+
+int GEQ_Iterator::live() const {
+ return current <= last;
+}
+
+void GEQ_Iterator::operator++() {
+ this->operator++(0);
+}
+
+void GEQ_Iterator::operator++(int) {
+ current++;
+}
+
+
+GEQ_Handle GEQ_Iterator::operator*() {
+ assert((c && current <= last) && "GEQ_Iterator::operator*: bad call");
+ return GEQ_Handle(c,current);
+}
+
+GEQ_Handle GEQ_Iterator::operator*() const {
+ assert((c && current <= last) && "GEQ_Iterator::operator*: bad call");
+ return GEQ_Handle(c,current);
+}
+
+
+void copy_constraint(Constraint_Handle H, const Constraint_Handle initial) {
+ // skip_set_checks++;
+// assert(H.relation()->n_inp() == initial.relation()->n_inp());
+// assert(H.relation()->n_out() == initial.relation()->n_out());
+
+ H.update_const_during_simplify(initial.get_const_during_simplify());
+ if (H.relation() == initial.relation()) {
+ for( Constr_Vars_Iter C(initial, false); C.live() ; C.next()) {
+ assert(C.curr_var()->kind()!= Forall_Var &&
+ C.curr_var()->kind()!= Exists_Var);
+ if (C.curr_var()->kind()!= Wildcard_Var)
+ H.update_coef_during_simplify(C.curr_var(), C.curr_coef());
+ else
+ // Must add a new wildcard,
+ // since they can't be used outside local Conjunct
+ H.update_coef_during_simplify(H.c->declare(), C.curr_coef());
+ }
+ }
+ else {
+ Rel_Body *this_rel = H.relation();
+ for( Constr_Vars_Iter C(initial, false); C.live() ; C.next()) {
+ switch (C.curr_var()->kind()) {
+ case Forall_Var:
+ case Exists_Var:
+ assert(0 && "Can't copy quantified constraints across relations");
+ break;
+ case Wildcard_Var:
+ // for each wildcard var we see, create a new wildcard
+ // will lead to lots of wildcards, but Wayne likes it
+ // that way
+ {
+ H.update_coef_during_simplify(H.c->declare(), C.curr_coef());
+ break;
+ }
+ case Input_Var: //use variable_ID of corresponding position
+ {
+ int pos = C.curr_var()->get_position();
+ assert(this_rel->n_inp() >= pos);
+ Variable_ID V = this_rel->input_var(pos);
+ H.update_coef_during_simplify(V, C.curr_coef());
+ break;
+ }
+ case Output_Var: //use variable_ID of corresponding position
+ {
+ int pos = C.curr_var()->get_position();
+ assert(this_rel->n_out() >= pos);
+ Variable_ID V = this_rel->output_var(pos);
+ H.update_coef_during_simplify(V, C.curr_coef());
+ break;
+ }
+
+ case Global_Var: // get this Global's Var_ID in this relation
+ {
+ Variable_ID V;
+ Global_Var_ID G = C.curr_var()->get_global_var();
+ if (G->arity() == 0)
+ V = this_rel->get_local(G);
+ else
+ V = this_rel->get_local(G,C.curr_var()->function_of());
+ H.update_coef_during_simplify(V, C.curr_coef());
+ break;
+ }
+ default:
+ assert(0 && "copy_constraint: variable of impossible type");
+ }
+ }
+ }
+ // skip_set_checks--;
+}
+
+} // namespace
diff --git a/omegalib/omega/src/pres_col.cc b/omegalib/omega/src/pres_col.cc
new file mode 100644
index 0000000..1569116
--- /dev/null
+++ b/omegalib/omega/src/pres_col.cc
@@ -0,0 +1,104 @@
+#include <omega/pres_conj.h>
+#include <omega/RelBody.h>
+#include <omega/omega_i.h>
+
+namespace omega {
+
+//
+// Copy column fr_col of problem fp
+// to column to_col of problem tp.
+// Displacement for constraints in tp are start_EQ and start_GEQ.
+//
+void copy_column(Problem *tp, int to_col,
+ Problem *fp, int fr_col,
+ int start_EQ, int start_GEQ) {
+ checkVars(to_col);
+ assert(start_EQ + fp->nEQs <= tp->allocEQs);
+ assert(start_GEQ + fp->nGEQs <= tp->allocGEQs);
+
+ int i;
+ for(i=0; i<fp->nEQs; i++) {
+ tp->EQs[i+start_EQ].coef[to_col] = fp->EQs[i].coef[fr_col];
+ }
+ for(i=0; i<fp->nGEQs; i++) {
+ tp->GEQs[i+start_GEQ].coef[to_col] = fp->GEQs[i].coef[fr_col];
+ }
+}
+
+//
+// Zero column to_col of problem tp.
+// Displacement for constraints in to_conj are start_EQ and start_GEQ.
+// Number of constraints to zero are no_EQ and no_GEQ.
+//
+void zero_column(Problem *tp, int to_col,
+ int start_EQ, int start_GEQ,
+ int no_EQs, int no_GEQs) {
+ assert(start_EQ + no_EQs <= tp->allocEQs);
+ assert(start_GEQ + no_GEQs <= tp->allocGEQs);
+
+ int i;
+ for(i=0; i<no_EQs; i++) {
+ tp->EQs[i+start_EQ].coef[to_col] = 0;
+ }
+ for(i=0; i<no_GEQs; i++) {
+ tp->GEQs[i+start_GEQ].coef[to_col] = 0;
+ }
+}
+
+//
+// return column for D in conjunct
+//
+int Conjunct::get_column(Variable_ID D) {
+ int col = find_column(D);
+ if (col == 0) // if it does not already have a column assigned
+ col = map_to_column(D);
+ assert(col > 0); // Not substituted
+ return col;
+}
+
+//
+// Find column in conjunct.
+//
+int Conjunct::find_column(Variable_ID D) {
+ assert(D != 0);
+ int column = mappedVars.index(D);
+
+ // If it has been through the omega core (variablesInitialized),
+ // and it exists in the problem, check to see if it has been forwarded.
+ // This will likely only be the case if substitutions have been done;
+ // that won't arise in user code, only in print_with_subs and the
+ // Substitutions class.
+ if (problem->variablesInitialized && column > 0) {
+ assert(problem->forwardingAddress[column] != 0);
+ column = problem->forwardingAddress[column];
+ }
+ assert (column <= problem->nVars);
+ return column;
+}
+
+//
+// Create new column in conjunct.
+//
+int Conjunct::map_to_column(Variable_ID D) {
+ assert(D != 0);
+ // This heavy-duty assertion says that if you are trying to use a global
+ // var's local representative in a relation, that you have first told the
+ // relation that you are using it here. PUFS requires that we know
+ // all the function symbols that might be used in a relation.
+ // If one wanted to be less strict, one could just tell the relation
+ // that the global variable was being used.
+ assert(D->kind() != Global_Var ||
+ (relation()->has_local(D->get_global_var(), D->function_of())
+ && "Attempt to update global var without a local variable ID"));
+
+ cols_ordered = false; // extremely important
+ checkVars(problem->nVars+2);
+ int col = ++problem->nVars;
+ mappedVars.append(D);
+ problem->forwardingAddress[col] = col;
+ problem->var[col] = col;
+ zero_column(problem, col, 0, 0, problem->nEQs, problem->nGEQs);
+ return col;
+}
+
+} // namespace
diff --git a/omegalib/omega/src/pres_conj.cc b/omegalib/omega/src/pres_conj.cc
new file mode 100644
index 0000000..f3f458d
--- /dev/null
+++ b/omegalib/omega/src/pres_conj.cc
@@ -0,0 +1,1460 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 the Omega Project Team
+ Copyright (C) 2005-2011 Chun Chen
+ All Rights Reserved.
+
+ Purpose:
+ class Conjunct.
+
+ Notes:
+
+ History:
+*****************************************************************************/
+
+#include <omega/omega_core/oc.h>
+#include <omega/pres_conj.h>
+#include <omega/pres_cmpr.h>
+#include <omega/Relation.h>
+#include <omega/omega_i.h>
+#include <set>
+
+namespace omega {
+
+int NR_CONJUNCTS, MAX_CONJUNCTS;
+
+/*
+ * Make a new wildcard variable, return WC number.
+ * Should be static to this file, but must be a friend of conjunct.
+ */
+int new_WC(Conjunct *nc, Problem *) {
+ Variable_ID wc = nc->declare();
+ int wc_no = nc->map_to_column(wc);
+ return(wc_no);
+}
+
+
+const char* get_var_name(unsigned int col, void * void_conj) {
+#if defined PRINT_COLUMN_NUMBERS
+ static char scum[512];
+#endif
+ Conjunct *c = (Conjunct *) void_conj;
+ if (col == 0)
+ return 0;
+ Variable_ID v = c->mappedVars[col];
+ assert(v!=0);
+#if defined PRINT_COLUMN_NUMBERS
+ strcpy(scum, v->char_name());
+ sprintf(scum + strlen(scum), "(%d)", col);
+ return scum;
+#endif
+ return v->char_name();
+}
+
+void Conjunct::promise_that_ub_solutions_exist(Relation &R) {
+#ifndef NDEBUG
+ Relation verify=Relation(R, this);
+ assert(verify.is_upper_bound_satisfiable());
+#endif
+ verified = true;
+}
+
+
+int Conjunct::max_ufs_arity_of_set() {
+ int ma = 0, a;
+ for (Variable_ID_Iterator v(mappedVars); v; v++)
+ if ((*v)->kind() == Global_Var && (*v)->function_of() == Set_Tuple
+ && query_variable_used(*v)) {
+ a = (*v)->get_global_var()->arity();
+ if (a > ma)
+ ma = a;
+ }
+ return ma;
+}
+
+
+int Conjunct::max_ufs_arity_of_in() {
+ int ma = 0, a;
+ for (Variable_ID_Iterator v(mappedVars); v; v++)
+ if ((*v)->kind() == Global_Var && (*v)->function_of() == Input_Tuple
+ && query_variable_used(*v)) {
+ a = (*v)->get_global_var()->arity();
+ if (a > ma)
+ ma = a;
+ }
+ return ma;
+}
+
+
+int Conjunct::max_ufs_arity_of_out() {
+ int ma = 0, a;
+ for (Variable_ID_Iterator v(mappedVars); v; v++)
+ if ((*v)->kind() == Global_Var && (*v)->function_of() == Output_Tuple
+ && query_variable_used(*v)) {
+ a = (*v)->get_global_var()->arity();
+ if (a > ma)
+ ma = a;
+ }
+ return ma;
+}
+
+
+bool Conjunct::is_unknown() const {
+ assert(problem || comp_problem);
+ return !exact && ((problem && problem->nEQs==0 && problem->nGEQs==0) ||
+ (comp_problem && comp_problem->no_constraints()));
+}
+
+
+/*
+ * Remove black constraints from the problem.
+ * Make all the remaining red constraints black.
+ */
+void Conjunct::rm_color_constrs() {
+ int geqs = 0, eqs = 0;
+
+ possible_leading_0s = -1;
+ guaranteed_leading_0s = -1;
+ leading_dir = 0;
+
+ for(int i=0; i<problem->nGEQs; i++) {
+ if(problem->GEQs[i].color) {
+ if(geqs!=i)
+ eqnncpy(&problem->GEQs[geqs], &problem->GEQs[i], problem->nVars);
+ problem->GEQs[geqs].color = EQ_BLACK;
+ geqs++;
+ }
+ }
+ problem->nGEQs = geqs;
+
+ for(int i=0; i<problem->nEQs; i++) {
+ if(problem->EQs[i].color) {
+ if(eqs!=i)
+ eqnncpy(&problem->EQs[eqs], &problem->EQs[i], problem->nVars);
+ problem->EQs[eqs].color = EQ_BLACK;
+ eqs++;
+ }
+ }
+ problem->nEQs = eqs;
+}
+
+
+
+//
+// Conjunct constructors.
+//
+Conjunct::Conjunct() :
+ F_Declaration(NULL, NULL),
+ mappedVars(0),
+ n_open_constraints(0),
+ cols_ordered(false),
+ simplified(false),
+ verified(false),
+ guaranteed_leading_0s(-1),
+ possible_leading_0s(-1),
+ leading_dir(0),
+ exact(true),
+ r_constrs(0) {
+ NR_CONJUNCTS++;
+ if (NR_CONJUNCTS>MAX_CONJUNCTS) MAX_CONJUNCTS = NR_CONJUNCTS;
+ problem = new Problem;
+ comp_problem = NULL;
+ problem->get_var_name = get_var_name;
+ problem->getVarNameArgs = (void *) this;
+}
+
+
+Conjunct::Conjunct(Formula *f, Rel_Body *r) :
+ F_Declaration(f,r),
+ mappedVars(0),
+ n_open_constraints(0),
+ cols_ordered(false),
+ simplified(false),
+ verified(false),
+ guaranteed_leading_0s(-1),
+ possible_leading_0s(-1),
+ leading_dir(0),
+ exact(true),
+ r_constrs(0) {
+ NR_CONJUNCTS++;
+ if (NR_CONJUNCTS>MAX_CONJUNCTS) MAX_CONJUNCTS = NR_CONJUNCTS;
+ problem = new Problem;
+ comp_problem = NULL;
+ problem->get_var_name = get_var_name;
+ problem->getVarNameArgs = (void *) this ;
+}
+
+void internal_copy_conjunct(Conjunct* to, Conjunct* fr);
+
+//
+// Copy Conjunct.
+//
+Conjunct* Conjunct::copy_conj_diff_relation(Formula *parent, Rel_Body *rel_body) {
+ Conjunct *new_conj;
+ if(problem && comp_problem==NULL) {
+ new_conj = new Conjunct(parent, rel_body);
+ internal_copy_conjunct(new_conj, this);
+ }
+ else if (problem==NULL && comp_problem) {
+ /* copy compressed conjunct */
+ assert(0 && "copy compressed conjunct");
+ new_conj = 0;
+ }
+ else {
+ assert(0 && "problem == NULL");
+ new_conj = 0;
+ }
+ return new_conj;
+}
+
+
+void internal_copy_conjunct(Conjunct* to, Conjunct* fr) {
+ copy_conj_header(to, fr);
+
+ //
+ // We repeat part of what is done by copy_conj_header(to, fr) by
+ // calling Problem::operator=(const Problem &).
+ // copy_conj_header should go away, but there is some code that still needs
+ // it in negate_conj.
+ //
+ to->r_constrs = fr->r_constrs;
+ to->simplified = fr->simplified;
+ to->verified = fr->verified;
+ to->guaranteed_leading_0s = fr->guaranteed_leading_0s;
+ to->possible_leading_0s = fr->possible_leading_0s;
+ to->leading_dir = fr->leading_dir;
+ // the following duplicates some work of the "copy_conj_header" brain damage
+ *to->problem = *fr->problem;
+ to->problem->getVarNameArgs = (void *)to; // important
+}
+
+
+//
+// Copy Conjunct variable declarations
+// and problem parameters but not problem itself.
+//
+void copy_conj_header(Conjunct* to, Conjunct* fr) {
+ free_var_decls(to->myLocals); to->myLocals.clear();
+
+ copy_var_decls(to->myLocals, fr->myLocals);
+ to->mappedVars = fr->mappedVars;
+ to->remap();
+ reset_remap_field(fr->myLocals);
+
+ to->cols_ordered = fr->cols_ordered;
+ to->r_constrs = fr->r_constrs;
+ to->simplified = fr->simplified;
+ to->verified = fr->verified;
+ to->guaranteed_leading_0s = fr->guaranteed_leading_0s;
+ to->possible_leading_0s = fr->possible_leading_0s;
+ to->leading_dir = fr->leading_dir;
+ to->n_open_constraints = fr->n_open_constraints;
+ to->exact=fr->exact;
+
+ Problem *fp = fr->problem;
+ Problem *tp = to->problem;
+ tp->nVars = fp->nVars;
+ tp->safeVars = fp->safeVars;
+ tp->variablesInitialized = fp->variablesInitialized;
+ tp->variablesFreed = fp->variablesFreed;
+ for(int i=1; i<=maxVars; i++) { // only need nVars of var
+ tp->forwardingAddress[i] = fp->forwardingAddress[i];
+ tp->var[i] = fp->var[i];
+ }
+ to->problem->get_var_name = get_var_name;
+ to->problem->getVarNameArgs = (void *)to ;
+}
+
+
+void Conjunct::reverse_leading_dir_info() {
+ leading_dir *= -1;
+}
+
+
+void Conjunct::enforce_leading_info(int guaranteed, int possible, int dir) {
+ skip_finalization_check++;
+ guaranteed_leading_0s = guaranteed;
+
+ int d = min(relation()->n_inp(),relation()->n_out());
+
+ assert(0 <= guaranteed);
+ assert(guaranteed <= possible);
+ assert(possible <= d);
+
+ for(int i = 1; i <= guaranteed; i++) {
+ EQ_Handle e = add_EQ();
+ e.update_coef_during_simplify(input_var(i), -1);
+ e.update_coef_during_simplify(output_var(i), 1);
+ e.finalize();
+ }
+
+
+ if (guaranteed == possible && guaranteed >= 0 && possible+1 <= d && dir) {
+ GEQ_Handle g = add_GEQ();
+ if (dir > 0) {
+ g.update_coef_during_simplify(input_var(possible+1), -1);
+ g.update_coef_during_simplify(output_var(possible+1), 1);
+ }
+ else {
+ g.update_coef_during_simplify(input_var(possible+1), 1);
+ g.update_coef_during_simplify(output_var(possible+1), -1);
+ }
+ g.update_const_during_simplify(-1);
+ g.finalize();
+ possible_leading_0s = possible;
+ leading_dir = dir;
+ }
+ else {
+ possible_leading_0s = d;
+ leading_dir = 0;
+ }
+
+ skip_finalization_check--;
+#if ! defined NDEBUG
+ assert_leading_info();
+#endif
+}
+
+
+void Conjunct::invalidate_leading_info(int changed) {
+ if (changed == -1) {
+ guaranteed_leading_0s = possible_leading_0s = -1;
+ leading_dir = 0;
+ }
+ else {
+ int d = min(relation()->n_inp(), relation()->n_out());
+ assert(1 <= changed && changed <= d);
+ if (possible_leading_0s == changed -1) {
+ possible_leading_0s = d;
+ }
+ guaranteed_leading_0s = min(guaranteed_leading_0s,changed-1);
+ }
+#if ! defined NDEBUG
+ assert_leading_info();
+#endif
+}
+
+
+int Conjunct::leading_dir_valid_and_known() {
+ if (relation()->is_set()) {
+ return 0;
+ }
+ // if we know leading dir, we can rule out extra possible 0's
+ assert(leading_dir == 0 ||
+ possible_leading_0s == guaranteed_leading_0s);
+
+ return (possible_leading_0s == guaranteed_leading_0s &&
+ possible_leading_0s >= 0 &&
+ possible_leading_0s < min(relation()->n_inp(),relation()->n_out())
+ && leading_dir);
+}
+
+
+#if ! defined NDEBUG
+void Conjunct::assert_leading_info() {
+ if (relation()->is_set()) {
+ return;
+ }
+
+ int d = min(relation()->n_inp(), relation()->n_out());
+
+ if ( guaranteed_leading_0s == -1
+ && guaranteed_leading_0s == possible_leading_0s)
+ assert(leading_dir == 0);
+
+ if(leading_dir != 0 &&
+ possible_leading_0s != guaranteed_leading_0s) {
+ use_ugly_names++;
+ prefix_print(DebugFile);
+ use_ugly_names--;
+ }
+
+ assert(leading_dir == 0 || possible_leading_0s == guaranteed_leading_0s);
+
+ assert(possible_leading_0s <= d && guaranteed_leading_0s <= d);
+
+ assert(possible_leading_0s == -1 || guaranteed_leading_0s <= possible_leading_0s);
+
+ // check that there must be "guaranteed_leading_0s" 0s
+ int carried_level;
+ for (carried_level = 1; carried_level <= guaranteed_leading_0s; carried_level++) {
+ Variable_ID in = input_var(carried_level),
+ out = output_var(carried_level);
+ coef_t lb, ub;
+ bool guar;
+ query_difference(out, in, lb, ub, guar);
+ if (lb != 0 && ub != 0) {
+ // probably "query_difference" is just approximate
+ // add the negation of leading_dir and assert that
+ // the result is unsatisfiable;
+ // add in > out (in-out-1>=0) and assert unsatisfiable.
+
+ Conjunct *test = copy_conj_same_relation();
+ test->problem->turnRedBlack();
+ skip_finalization_check++;
+
+ GEQ_Handle g = test->add_GEQ();
+ g.update_coef_during_simplify(in, -1);
+ g.update_coef_during_simplify(out, 1);
+ g.update_const_during_simplify(-1);
+ g.finalize();
+ assert(!simplify_conj(test, true, 0, 0));
+ // test was deleted by simplify_conj, as it was FALSE
+
+ test = copy_conj_same_relation();
+ test->problem->turnRedBlack();
+ g = test->add_GEQ();
+ g.update_coef_during_simplify(in, 1);
+ g.update_coef_during_simplify(out, -1);
+ g.update_const_during_simplify(-1);
+ g.finalize();
+ assert(!simplify_conj(test, true, 0, 0));
+ // test was deleted by simplify_conj, as it was FALSE
+
+ skip_finalization_check--;
+ }
+ }
+
+ carried_level = possible_leading_0s+1;
+
+ // check that there can't be another
+ if (guaranteed_leading_0s == possible_leading_0s
+ && possible_leading_0s >= 0 &&
+ carried_level <= min(relation()->n_inp(), relation()->n_out())) {
+ Variable_ID in = input_var(carried_level),
+ out = output_var(carried_level);
+ coef_t lb, ub;
+ bool guar;
+ query_difference(out, in, lb, ub, guar);
+ if (lb <= 0 && ub >= 0) {
+ // probably "query_difference" is just approximate
+ // add a 0 and see if its satisfiable
+
+ Conjunct *test = copy_conj_same_relation();
+ test->problem->turnRedBlack();
+ skip_finalization_check++;
+
+ EQ_Handle e = test->add_EQ();
+ e.update_coef_during_simplify(in, -1);
+ e.update_coef_during_simplify(out, 1);
+ e.finalize();
+ assert(!simplify_conj(test, true, 0, 0));
+ // test was deleted by simplify_conj, as it was FALSE
+
+ skip_finalization_check--;
+ }
+ }
+
+ // check leading direction info
+ if (leading_dir_valid_and_known()) {
+ Variable_ID in = input_var(guaranteed_leading_0s+1),
+ out = output_var(guaranteed_leading_0s+1);
+ coef_t lb, ub;
+ bool guar;
+ query_difference(out, in, lb, ub, guar);
+ if ((leading_dir < 0 && ub >= 0) ||
+ (leading_dir > 0 && lb <= 0)) {
+ // probably "query_difference" is just approximate
+ // add the negation of leading_dir and assert that
+ // the result is unsatisfiable;
+ // eg for leading_dir = +1 (in must be < out),
+ // add in >= out (in-out>=0) and assert unsatisfiable.
+
+ Conjunct *test = copy_conj_same_relation();
+ test->problem->turnRedBlack();
+ skip_finalization_check++;
+
+ GEQ_Handle g = test->add_GEQ();
+ g.update_coef_during_simplify(in, leading_dir);
+ g.update_coef_during_simplify(out, -leading_dir);
+ g.finalize();
+
+ assert(!simplify_conj(test, true, 0, 0));
+ // test was deleted by simplify_conj, as it was FALSE
+
+ skip_finalization_check--;
+ }
+ }
+}
+#endif
+
+
+Variable_ID Conjunct::declare(Const_String s) {
+ return do_declare(s, Wildcard_Var);
+}
+
+Variable_ID Conjunct::declare() {
+ return do_declare(Const_String(), Wildcard_Var);
+}
+
+Variable_ID Conjunct::declare(Variable_ID v) {
+ return do_declare(v->base_name, Wildcard_Var);
+}
+
+Conjunct* Conjunct::really_conjunct() {
+ return this;
+}
+
+
+Variable_ID_Tuple* Conjunct::variables() {
+ return &mappedVars;
+}
+
+Stride_Handle Conjunct::add_stride(int step, int preserves_level) {
+ assert_not_finalized();
+ Variable_ID wild = declare();
+ int c;
+ c = problem->newEQ();
+ simplified = false;
+ verified = false;
+ if (! preserves_level) {
+ if (leading_dir == 0)
+ possible_leading_0s = -1;
+ // otherwise we must still have leading_dir, and thus no more 0's
+ }
+ problem->EQs[c].color = EQ_BLACK;
+ eqnnzero(&problem->EQs[c],problem->nVars);
+ n_open_constraints++;
+ EQ_Handle h = EQ_Handle(this, c);
+ h.update_coef(wild,step);
+ return h;
+}
+
+// This should only be used to copy constraints from simplified relations,
+// i.e. there are no quantified variables in c except wildcards.
+EQ_Handle Conjunct::add_EQ(const Constraint_Handle &c, int /*preserves_level, currently unused*/) {
+ EQ_Handle e = add_EQ();
+ copy_constraint(e,c);
+ return e;
+}
+
+
+EQ_Handle Conjunct::add_EQ(int preserves_level) {
+ assert_not_finalized();
+ int c;
+ c = problem->newEQ();
+ simplified = false;
+ verified = false;
+ if (!preserves_level) {
+ if (leading_dir == 0)
+ possible_leading_0s = -1;
+ // otherwise we must still have leading_dir, and thus no more 0's
+ }
+ problem->EQs[c].color = EQ_BLACK;
+ eqnnzero(&problem->EQs[c],problem->nVars);
+ n_open_constraints++;
+ return EQ_Handle(this, c);
+}
+
+
+// This should only be used to copy constraints from simplified relations,
+// i.e. there are no quantified variables in c except wildcards.
+GEQ_Handle Conjunct::add_GEQ(const Constraint_Handle &c, int /*preserves_level, currently unused */) {
+ GEQ_Handle g = add_GEQ();
+ copy_constraint(g,c);
+ return g;
+}
+
+
+GEQ_Handle Conjunct::add_GEQ(int preserves_level) {
+ assert_not_finalized();
+ int c;
+ c = problem->newGEQ();
+ simplified = false;
+ verified = false;
+ if (!preserves_level) {
+ if (leading_dir == 0)
+ possible_leading_0s = -1;
+ // otherwise we must still have leading_dir, and thus no more 0's
+ }
+ problem->GEQs[c].color = EQ_BLACK;
+ eqnnzero(&problem->GEQs[c],problem->nVars);
+ n_open_constraints++;
+ return GEQ_Handle(this, c);
+}
+
+
+Conjunct *Conjunct::find_available_conjunct() {
+ return this;
+}
+
+
+bool Conjunct::can_add_child() {
+ return false;
+}
+
+
+void Conjunct::combine_columns() {
+ int nvars = mappedVars.size(),i,j,k;
+
+ for(i=1; i<=nvars; i++)
+ for(j=i+1; j<=nvars; j++) {
+ // If they are the same, copy into the higher numbered column.
+ // That way we won't have problems with already-merged columns later
+ assert(i != j);
+ if(mappedVars[i] == mappedVars[j]) {
+ if (pres_debug)
+ fprintf(DebugFile, "combine_col:Actually combined %d,%d\n",
+ j,i);
+ for(k=0; k<problem->nEQs; k++)
+ problem->EQs[k].coef[j] += problem->EQs[k].coef[i];
+ for(k=0; k<problem->nGEQs; k++)
+ problem->GEQs[k].coef[j] += problem->GEQs[k].coef[i];
+ zero_column(problem, i, 0, 0, problem->nEQs, problem->nGEQs);
+ // Create a wildcard w/no constraints. temporary measure,
+ // so we don't have to shuffle columns
+ Variable_ID zero_var = declare();
+ mappedVars[i] = zero_var;
+ break;
+ }
+ }
+}
+
+
+void Conjunct::finalize() {
+// Debugging version of finalize; copy the conjunct and free the old one,
+// so that purify will catch accesses to finalized constraints
+// assert(n_open_constraints == 0);
+// Conjunct *C = this->copy();
+// parent().replace_child(this, C);
+// delete this;
+}
+
+Conjunct::~Conjunct() {
+ NR_CONJUNCTS--;
+ delete problem;
+ delete comp_problem;
+}
+
+
+//
+// Cost = # of terms in DNF when negated
+// or CantBeNegated if too bad (i.e. bad wildcards)
+// or AvoidNegating if it would be inexact
+//
+// Also check pres_legal_negations --
+// If set to any_negation, just return the number
+// If set to one_geq_or_stride, return CantBeNegated if c > 1
+// If set to one_geq_or_eq, return CantBeNegated if not a single geq or eq
+//
+
+int Conjunct::cost() {
+ int c;
+ int i;
+ int wc_no;
+ int wc_j = 0; // initialize to shut up the compiler
+
+ // cost 1 per GEQ, and if 1 GEQ has wildcards, +2 for each of them
+
+ c = problem->nGEQs;
+ for(i=0; i<problem->nGEQs; i++) {
+ wc_no = 0;
+ for(int j=1; j<=problem->nVars; j++) if(problem->GEQs[i].coef[j]!=0) {
+ Variable_ID v = mappedVars[j];
+ if(v->kind()==Wildcard_Var) {
+ wc_no++;
+ c+=2;
+ wc_j = j;
+ }
+ }
+ if (wc_no > 1) return CantBeNegated;
+ }
+
+ for(i=0; i<problem->nEQs; i++) {
+ wc_no = 0;
+ for(int j=1; j<=problem->nVars; j++) if(problem->EQs[i].coef[j]!=0) {
+ Variable_ID v = mappedVars[j];
+ if(v->kind()==Wildcard_Var) {
+ wc_no++;
+ wc_j = j;
+ }
+ }
+
+ if (wc_no == 0) // no wildcards
+ c+=2;
+ else if (wc_no == 1) { // one wildcard - maybe we can negate it
+ int i2;
+ for(i2=0; i2<problem->nEQs; i2++)
+ if(i != i2 && problem->EQs[i2].coef[wc_j]!=0) break;
+ if (i2 >= problem->nEQs) // Stride constraint
+ c++;
+ else // We are not ready to handle this
+ return CantBeNegated;
+ }
+ else // Multiple wildcards
+ return CantBeNegated;
+ }
+ if (!exact) return AvoidNegating;
+
+ if (pres_legal_negations == any_negation) {
+ return c;
+ }
+ else {
+ // single GEQ ok either way as long as no wildcards
+ // (we might be able to handle wildcards, but I haven't thought about it)
+ if (problem->nEQs==0 && problem->nGEQs<=1) {
+ if (c>1) { // the GEQ had a wildcard -- I'm not ready to go here.
+ if (pres_debug > 0) {
+ fprintf(DebugFile,
+ "Refusing to negate a GEQ with wildcard(s)"
+ " under restricted_negation; "
+ "It may be possible to fix this.\n");
+ }
+ return CantBeNegated;
+ }
+ return c;
+ }
+ else if (problem->nEQs==1 && problem->nGEQs==0) {
+ assert(c == 1 || c == 2);
+
+ if (pres_legal_negations == one_geq_or_stride) {
+ if (c == 1)
+ return c; // stride constraint is ok
+ else {
+ if (pres_debug > 0) {
+ fprintf(DebugFile, "Refusing to negate a non-stride EQ under current pres_legal_negations.\n");
+ }
+ return CantBeNegated;
+ }
+ }
+ else {
+ assert(pres_legal_negations == one_geq_or_eq);
+ return c;
+ }
+ }
+ else {
+ if (pres_debug > 0) {
+ fprintf(DebugFile, "Refusing to negate multiple constraints under current pres_legal_negations.\n");
+ }
+ return CantBeNegated;
+ }
+ }
+}
+
+
+//
+// Merge CONJ1 & CONJ2 -> CONJ.
+// Action: MERGE_REGULAR or MERGE_COMPOSE: regular merge.
+// MERGE_GIST make constraints from conj2 red, i.e.
+// Gist Conj2 given Conj1 (T.S. comment).
+// Reorder columns as we go.
+// Merge the columns for identical variables.
+// We assume we know nothing about the ordering of conj1, conj2.
+//
+// Does not consume its arguments
+//
+// Optional 4th argument gives the relation for the result - if
+// null, conj1 and conj2 must have the same relation, which will
+// be used for the result
+//
+// The only members of conj1 and conj2 that are used are: problem,
+// mappedVars and declare(), and the leading_0s/leading_dir members
+// and exact.
+//
+// NOTE: variables that are shared between conjuncts are necessarily
+// declared above, not here; so we can simply create columns for the
+// locals of each conj after doing the protected vars.
+//
+Conjunct* merge_conjs(Conjunct* conj1, Conjunct* conj2,
+ Merge_Action action, Rel_Body *body) {
+ // body must be set unless both conjuncts are from the same relation
+ assert(body || conj1->relation() == conj2->relation());
+
+ if (body == conj1->relation() && body == conj2->relation())
+ body = 0; // we test this later to see if there is a new body
+
+ Conjunct *conj3 = new Conjunct(NULL, body ? body : conj2->relation());
+ Problem *p1 = conj1->problem;
+ Problem *p2 = conj2->problem;
+ Problem *p3 = conj3->problem;
+ int i;
+
+ if (action != MERGE_COMPOSE) {
+ conj1->assert_leading_info();
+ conj2->assert_leading_info();
+ }
+
+ if(pres_debug>=2) {
+ use_ugly_names++;
+ fprintf(DebugFile, ">>> Merge conjuncts: Merging%s:\n",
+ (action == MERGE_GIST ? " for gist" :
+ (action == MERGE_COMPOSE ? " for composition" : "")));
+ conj1->prefix_print(DebugFile);
+ conj2->prefix_print(DebugFile);
+ fprintf(DebugFile, "\n");
+ use_ugly_names--;
+ }
+
+
+
+ switch(action) {
+ case MERGE_REGULAR:
+ case MERGE_COMPOSE:
+ conj3->exact=conj1->exact && conj2->exact;
+ break;
+ case MERGE_GIST:
+ conj3->exact=conj2->exact;
+ break;
+ }
+
+ if (action == MERGE_COMPOSE) {
+ conj3->guaranteed_leading_0s=min(conj1->guaranteed_leading_0s,
+ conj2->guaranteed_leading_0s);
+ conj3->possible_leading_0s=min((unsigned int) conj1->possible_leading_0s,
+ (unsigned int) conj2->possible_leading_0s);
+
+ assert( conj3->guaranteed_leading_0s <= conj3->possible_leading_0s);
+
+ // investigate leading_dir - not well tested code
+ if (conj1->guaranteed_leading_0s<0 || conj2->guaranteed_leading_0s<0) {
+ conj3->leading_dir = 0;
+ }
+ else if (conj1->guaranteed_leading_0s == conj2->guaranteed_leading_0s)
+ if (conj1->leading_dir == conj2->leading_dir)
+ conj3->leading_dir = conj1->leading_dir;
+ else
+ conj3->leading_dir = 0;
+ else if (conj1->guaranteed_leading_0s < conj2->guaranteed_leading_0s) {
+ conj3->leading_dir = conj1->leading_dir;
+ }
+ else { // (conj1->guaranteed_leading_0s > conj2->guaranteed_leading_0s)
+ conj3->leading_dir = conj2->leading_dir;
+ }
+
+ if (conj3->leading_dir == 0)
+ conj3->possible_leading_0s = min(conj3->relation()->n_inp(),
+ conj3->relation()->n_out());
+
+ assert(conj3->guaranteed_leading_0s <= conj3->possible_leading_0s);
+ assert(conj3->guaranteed_leading_0s == conj3->possible_leading_0s
+ || !conj3->leading_dir);
+ }
+ else if (!body) { // if body is set, who knows what leading 0's mean?
+ assert(action == MERGE_REGULAR || action == MERGE_GIST);
+
+ int feasable = 1;
+
+ int redAndBlackGuarLeadingZeros = max(conj1->guaranteed_leading_0s,
+ conj2->guaranteed_leading_0s);
+ if (action == MERGE_REGULAR)
+ conj3->guaranteed_leading_0s= redAndBlackGuarLeadingZeros;
+ else conj3->guaranteed_leading_0s=conj1->guaranteed_leading_0s;
+
+ conj3->possible_leading_0s=min((unsigned)conj1->possible_leading_0s,
+ (unsigned)conj2->possible_leading_0s);
+ if (conj3->possible_leading_0s < redAndBlackGuarLeadingZeros)
+ feasable = 0;
+ else if (conj3->guaranteed_leading_0s == -1
+ || conj3->possible_leading_0s > redAndBlackGuarLeadingZeros)
+ conj3->leading_dir = 0;
+ else {
+ if (conj1->guaranteed_leading_0s == conj2->guaranteed_leading_0s)
+ if (!conj1->leading_dir_valid_and_known())
+ conj3->leading_dir = conj2->leading_dir;
+ else if (!conj2->leading_dir_valid_and_known())
+ conj3->leading_dir = conj1->leading_dir;
+ else if (conj1->leading_dir * conj2->leading_dir > 0)
+ conj3->leading_dir = conj1->leading_dir; // 1,2 same dir
+ else
+ feasable = 0; // 1 and 2 go in opposite directions
+ else if (conj3->possible_leading_0s != conj3->guaranteed_leading_0s)
+ conj3->leading_dir = 0;
+ else if (conj1->guaranteed_leading_0s<conj2->guaranteed_leading_0s) {
+ assert(!conj1->leading_dir_valid_and_known());
+ conj3->leading_dir = conj2->leading_dir;
+ }
+ else {
+ assert(!conj2->leading_dir_valid_and_known());
+ conj3->leading_dir = conj1->leading_dir;
+ }
+ }
+
+ if (!feasable) {
+ if(pres_debug>=2)
+ fprintf(DebugFile, ">>> Merge conjuncts: quick check proves FALSE.\n");
+
+ // return 0 = 1
+
+ int e = p3->newEQ();
+ p3->EQs[e].color = EQ_BLACK;
+ p3->EQs[e].touched = 1;
+ p3->EQs[e].key = 0;
+ p3->EQs[e].coef[0] = 1;
+
+ // Make sure these don't blow later assertions
+ conj3->possible_leading_0s = conj3->guaranteed_leading_0s = -1;
+ conj3->leading_dir = 0;
+
+ return conj3;
+ }
+ }
+ else { // provided "body" argument but not composing, leading 0s meaningless
+ conj3->guaranteed_leading_0s = conj3->possible_leading_0s = -1;
+ conj3->leading_dir = 0;
+ }
+
+ // initialize omega stuff
+
+ for(i=0; i<p1->nGEQs+p2->nGEQs; i++) {
+ int e = p3->newGEQ();
+ assert(e == i);
+ p3->GEQs[e].color = EQ_BLACK;
+ p3->GEQs[e].touched = 1;
+ p3->GEQs[e].key = 0;
+ }
+ for(i=0; i<p1->nEQs+p2->nEQs; i++) {
+ int e = p3->newEQ();
+ assert(e == i);
+ p3->EQs[e].color = EQ_BLACK;
+ p3->EQs[e].touched = 1;
+ p3->EQs[e].key = 0;
+ }
+
+ assert(p3->nGEQs == p1->nGEQs + p2->nGEQs);
+ assert(p3->nEQs == p1->nEQs + p2->nEQs);
+
+ // flag constraints from second constraint as red, if necessary
+ if (action == MERGE_GIST) {
+ for(i=0; i<p2->nEQs; i++) {
+ p3->EQs[i+p1->nEQs].color = EQ_RED;
+ }
+ for(i=0; i<p2->nGEQs; i++) {
+ p3->GEQs[i+p1->nGEQs].color = EQ_RED;
+ }
+ }
+
+ // copy constant column
+ copy_column(p3, 0, p1, 0, 0, 0);
+ copy_column(p3, 0, p2, 0, p1->nEQs, p1->nGEQs);
+
+ // copy protected variables column from conj1
+ int new_col = 1;
+ Variable_Iterator VI(conj1->mappedVars);
+ for(i=1; VI; VI++, i++) {
+ Variable_ID v = *VI;
+ if(v->kind() != Wildcard_Var) {
+ conj3->mappedVars.append(v);
+ int fr_ix = i;
+ copy_column(p3, new_col, p1, fr_ix, 0, 0);
+ zero_column(p3, new_col, p1->nEQs, p1->nGEQs,
+ p2->nEQs, p2->nGEQs);
+ new_col++;
+ }
+ }
+
+ // copy protected variables column from conj2,
+ // checking if conj3 already has this variable from conj1
+ for(i=1; i <= conj2->mappedVars.size(); i++) {
+ Variable_ID v = conj2->mappedVars[i];
+ if(v->kind() != Wildcard_Var) {
+ int to_ix = conj3->mappedVars.index(v);
+ int fr_ix = i;
+ if(to_ix > 0) {
+ // use old column
+ copy_column(p3, to_ix, p2, fr_ix, p1->nEQs, p1->nGEQs);
+ }
+ else {
+ // create new column
+ conj3->mappedVars.append(v);
+ zero_column(p3, new_col, 0, 0, p1->nEQs, p1->nGEQs);
+ copy_column(p3, new_col, p2, fr_ix, p1->nEQs, p1->nGEQs);
+ new_col++;
+ }
+ }
+ }
+
+ p3->safeVars = new_col-1;
+
+ // copy wildcards from conj1
+ for(i=1; i <= conj1->mappedVars.size(); i++) {
+ Variable_ID v = conj1->mappedVars[i];
+ if(v->kind() == Wildcard_Var) {
+ Variable_ID nv = conj3->declare(v);
+ conj3->mappedVars.append(nv);
+ int fr_ix = i;
+ copy_column(p3, new_col, p1, fr_ix, 0, 0);
+ zero_column(p3, new_col, p1->nEQs, p1->nGEQs,
+ p2->nEQs, p2->nGEQs);
+ new_col++;
+ }
+ }
+
+ // copy wildcards from conj2
+ for(i=1; i <= conj2->mappedVars.size(); i++) {
+ Variable_ID v = conj2->mappedVars[i];
+ if(v->kind() == Wildcard_Var) {
+ Variable_ID nv = conj3->declare(v);
+ conj3->mappedVars.append(nv);
+ int fr_ix = i;
+ zero_column(p3, new_col, 0, 0, p1->nEQs, p1->nGEQs);
+ copy_column(p3, new_col, p2, fr_ix, p1->nEQs, p1->nGEQs);
+ new_col++;
+ }
+ }
+
+ p3->nVars = new_col-1;
+ checkVars(p3->nVars);
+ p3->variablesInitialized = 1;
+ for(i=1; i<=p3->nVars; i++)
+ p3->var[i] = p3->forwardingAddress[i] = i;
+
+ conj3->cols_ordered = true;
+ conj3->simplified = false;
+ conj3->verified = false;
+
+ if(pres_debug>=2) {
+ use_ugly_names++;
+ fprintf(DebugFile, ">>> Merge conjuncts: result is:\n");
+ conj3->prefix_print(DebugFile);
+ fprintf(DebugFile, "\n");
+ use_ugly_names--;
+ }
+
+ conj3->assert_leading_info();
+
+ return conj3;
+}
+
+
+
+
+//
+// Reorder variables by swapping.
+// cols_ordered is just a hint that thorough check needs to be done.
+// Sets _safeVars.
+//
+void Conjunct::reorder() {
+ if(!cols_ordered) {
+ int var_no = mappedVars.size();
+ int first_wild = 1;
+ int last_prot = var_no;
+ while(first_wild < last_prot) {
+ for(; first_wild<=var_no && mappedVars[first_wild]->kind()!=Wildcard_Var;
+ first_wild++) ;
+ for(; last_prot>=1 && mappedVars[last_prot]->kind()==Wildcard_Var;
+ last_prot--) ;
+ if(first_wild < last_prot) {
+ problem->swapVars(first_wild, last_prot);
+ problem->variablesInitialized = false;
+ Var_Decl *t = mappedVars[first_wild];
+ mappedVars[first_wild] = mappedVars[last_prot];
+ mappedVars[last_prot] = t;
+ if(pres_debug) {
+ fprintf(DebugFile, "<<<OrderConjCols>>>: swapped var-s %d and %d\n", first_wild, last_prot);
+ }
+ }
+ }
+
+ int safe_vars;
+ for(safe_vars=0;
+ safe_vars<var_no && mappedVars[safe_vars+1]->kind()!=Wildcard_Var;
+ safe_vars++) ;
+
+#if ! defined NDEBUG
+ for(int s = safe_vars ; s<var_no ; s++ ) {
+ assert(mappedVars[s+1]->kind() == Wildcard_Var);
+ }
+#endif
+
+ problem->safeVars = safe_vars;
+ cols_ordered = true;
+ }
+}
+
+
+
+// Wherever possible, move function symbols to input tuple.
+// This ensures that if in == out, red F(in) = x is redundant
+// with black F(out) = x
+
+void Conjunct::move_UFS_to_input() {
+ if (guaranteed_leading_0s > 0) {
+ std::set<Global_Var_ID> already_done;
+ int remapped = 0;
+ skip_finalization_check++;
+ Rel_Body *body = relation();
+
+ assert(body);
+
+ for (Variable_ID_Iterator func(*body->global_decls()); func; func++) {
+ Global_Var_ID f = (*func)->get_global_var();
+ if (f->arity() <= guaranteed_leading_0s)
+ if (already_done.find(f) == already_done.end() &&
+ body->has_local(f, Input_Tuple) &&
+ body->has_local(f, Output_Tuple)) {
+ already_done.insert(f);
+
+ // equatE f(in) = f(out)
+ Variable_ID f_in = body->get_local(f, Input_Tuple);
+ Variable_ID f_out = body->get_local(f, Output_Tuple);
+ if (f_in != f_out) {
+ EQ_Handle e = add_EQ(1);
+
+ e.update_coef_during_simplify(f_in, -1);
+ e.update_coef_during_simplify(f_out, 1);
+
+ f_out->remap = f_in;
+ remapped = 1;
+ }
+ }
+ }
+
+ if (remapped) {
+ remap();
+ combine_columns();
+ reset_remap_field(*body->global_decls());
+ remapped = 0;
+ }
+
+ skip_finalization_check--;
+ }
+}
+
+
+
+
+
+//
+// Simplify CONJ.
+// Return TRUE if there are solutions, FALSE -- no solutions.
+//
+int simplify_conj(Conjunct* conj, int ver_sim, int simplificationEffort, int color) {
+ if (conj->verified
+ && simplificationEffort <= conj->r_constrs
+ && (conj->simplified || simplificationEffort < 0)
+ && !color) {
+ if(pres_debug) {
+ fprintf(DebugFile, "$$$ Redundant simplify_conj ignored (%d,%d,%d)\n",ver_sim,simplificationEffort,color);
+ conj->prefix_print(DebugFile);
+ }
+ return 1;
+ }
+
+ if (simplificationEffort < 0) simplificationEffort = 0;
+ conj->move_UFS_to_input();
+ conj->reorder();
+
+ Problem *p = conj->problem;
+
+ use_ugly_names++;
+
+ int i;
+ for(i=0; i<p->nGEQs; i++) {
+ p->GEQs[i].touched = 1;
+ }
+ for(i=0; i<p->nEQs; i++) {
+ p->EQs[i].touched = 1;
+ }
+
+ if(pres_debug) {
+ fprintf(DebugFile, "$$$ simplify_conj (%d,%d,%d)[\n",ver_sim,simplificationEffort,color);
+ conj->prefix_print(DebugFile);
+ }
+
+ assert(conj->cols_ordered);
+
+ int ret_code;
+ assert(p == conj->problem);
+ if(!color) {
+ ret_code = conj->simplifyProblem(ver_sim && ! conj->verified,0,simplificationEffort);
+ }
+ else {
+ ret_code = conj->redSimplifyProblem(simplificationEffort,1);
+ ret_code = (ret_code==redFalse ? 0 : 1);
+ }
+ assert(p->nSUBs==0);
+
+ if(ret_code == 0) {
+ if(pres_debug)
+ fprintf(DebugFile, "] $$$ simplify_conj : false\n\n");
+ delete conj;
+ use_ugly_names--;
+ return(false);
+ }
+
+
+ //
+ // mappedVars is mapping from columns to Variable_IDs.
+ // Recompute mappedVars for problem returned from ip.c
+ //
+ Variable_ID_Tuple new_mapped(0); // This is expanded by "append"
+ for (i=1; i<=p->safeVars; i++) {
+ // what is now in column i used to be in column p->var[i]
+ Variable_ID v = conj->mappedVars[p->var[i]];
+ assert(v->kind() != Wildcard_Var);
+ new_mapped.append(v);
+ }
+
+ /* Redeclare all wildcards that weren't eliminated. */
+ free_var_decls(conj->myLocals); conj->myLocals.clear();
+
+ conj->mappedVars = new_mapped;
+ for (i = p->safeVars+1; i<=p->nVars; i++) {
+ Variable_ID v = conj->declare();
+ conj->mappedVars.append(v);
+ }
+
+ // reset var and forwarding address if desired.
+ p->variablesInitialized = 1;
+ for(i=1; i<=conj->problem->nVars; i++)
+ conj->problem->var[i] = conj->problem->forwardingAddress[i] = i;
+
+ if(pres_debug) {
+ fprintf(DebugFile, "] $$$ simplify_conj\n");
+ conj->prefix_print(DebugFile);
+ fprintf(DebugFile, "\n");
+ }
+
+
+ use_ugly_names--;
+ conj->simplified = true;
+ conj->setup_anonymous_wildcard_names();
+
+ return(true);
+}
+
+
+int Conjunct::rank() {
+ Conjunct *C = this->copy_conj_same_relation();
+ C->reorder();
+ C->ordered_elimination(C->relation()->global_decls()->size());
+ int C_rank = 0;
+ for(Variable_Iterator vi = C->mappedVars; vi; vi++)
+ if(C->find_column(*vi) > 0) C_rank++;
+ delete C;
+ return C_rank;
+
+}
+
+
+void Conjunct::query_difference(Variable_ID v1, Variable_ID v2, coef_t &lowerBound, coef_t &upperBound, bool &guaranteed) {
+ int c1 = get_column(v1);
+ int c2 = get_column(v2);
+ assert(c1 && c2);
+ problem->query_difference(c1, c2, lowerBound, upperBound, guaranteed);
+}
+
+
+void Conjunct::query_variable_bounds(Variable_ID v, coef_t &lowerBound, coef_t &upperBound) {
+ int c = get_column(v);
+ assert (c);
+ problem->query_variable_bounds(c, &lowerBound, &upperBound);
+}
+
+coef_t Conjunct::query_variable_mod(Variable_ID v, coef_t factor) {
+ int c = get_column(v);
+ assert(c);
+ return problem->query_variable_mod(c, factor);
+}
+
+bool Conjunct::query_variable_used(Variable_ID v) {
+ for (GEQ_Iterator g = GEQs(); g.live(); g.next()) {
+ if ((*g).get_coef(v)) return true;
+ }
+ for (EQ_Iterator e = EQs(); e.live(); e.next()) {
+ if ((*e).get_coef(v)) return true;
+ }
+ return false;
+}
+
+
+int Conjunct::simplifyProblem(int verify, int subs, int redundantElimination) {
+ if (verified) verify = 0;
+ int result = problem->simplifyProblem(verify, subs, redundantElimination);
+ if (result == false && !exact)
+ exact=true;
+ assert(!(verified && verify && result == false));
+ if (verify && result) verified = true;
+ else if (!result) verified = false;
+ return result;
+}
+
+
+// not as confident about this one as the previous:
+int Conjunct::redSimplifyProblem(int effort, int computeGist) {
+ redCheck result = problem->redSimplifyProblem(effort, computeGist);
+ if (result == redFalse && !exact)
+ exact=true;
+ return result;
+}
+
+
+//
+// Add given list of wildcards S to this Conjunct.
+// Clears argument. (That's very important, otherwise those var_id's get freed)
+// Push_exists takes responsibility for reusing or deleting Var_ID's;
+// here we reuse them. Must also empty out the Tuple when finished (joins).
+void Conjunct::push_exists(Variable_ID_Tuple &S) {
+ for(Tuple_Iterator<Variable_ID> VI(S); VI; VI++) {
+ (*VI)->var_kind = Wildcard_Var;
+ }
+ myLocals.join(S); // Sets S to be empty.
+ cols_ordered = false;
+ simplified = false;
+}
+
+
+Conjunct *Formula::add_conjunct() {
+ assert_not_finalized();
+ assert(can_add_child());
+ Conjunct *f = new Conjunct(this, myRelation);
+ myChildren.append(f);
+ return f;
+}
+
+// Compress/uncompress functions
+
+bool Conjunct::is_compressed() {
+ if(problem!=NULL && comp_problem==NULL) {
+ return false;
+ }
+ else if(problem==NULL && comp_problem!=NULL) {
+ return true;
+ }
+ else {
+ assert(0 && "Conjunct::is_compressed: bad conjunct");
+ return false;
+ }
+}
+
+
+void Conjunct::compress() {
+ if(!is_compressed()) { // compress
+ comp_problem = new Comp_Problem(problem);
+ delete problem;
+ problem = NULL;
+ }
+}
+
+
+void Conjunct::uncompress() {
+ if(is_compressed()) {
+ problem = comp_problem->UncompressProblem();
+ delete comp_problem;
+ comp_problem = NULL;
+ }
+}
+
+
+Comp_Problem::Comp_Problem(Problem *problem) :
+ _nVars(problem->nVars),
+ _safeVars(problem->safeVars),
+ _get_var_name(problem->get_var_name),
+ _getVarNameArgs(problem->getVarNameArgs),
+ eqs(&problem->EQs[0],problem->nEQs,problem->nVars),
+ geqs(&problem->GEQs[0],problem->nGEQs,problem->nVars) {
+}
+
+Comp_Constraints::Comp_Constraints(eqn *constrs, int no_constrs, int no_vars) :
+ n_constrs(no_constrs),
+ n_vars(no_vars) {
+ coefs = new coef_t[(n_vars+1)*n_constrs];
+ int e, v;
+ for(e=0; e<n_constrs; e++) {
+ for(v=0; v<=n_vars; v++) {
+ coefs[coef_index(e,v)] = constrs[e].coef[v];
+ }
+ }
+}
+
+
+Comp_Constraints::~Comp_Constraints() {
+ delete coefs;
+}
+
+
+Problem *Comp_Problem::UncompressProblem() {
+ Problem *p = new Problem(eqs.n_constraints(), geqs.n_constraints());
+ p->get_var_name = get_var_name;
+ p->getVarNameArgs = _getVarNameArgs;
+ p->nVars = _nVars;
+ p->safeVars = _safeVars;
+ for(int i=1; i<=p->nVars; i++) {
+ p->forwardingAddress[i] = i;
+ p->var[i] = i;
+ }
+ eqs.UncompressConstr(&p->EQs[0], p->nEQs);
+ geqs.UncompressConstr(&p->GEQs[0], p->nGEQs);
+ return p;
+}
+
+void Comp_Constraints::UncompressConstr(eqn *constrs, short &pn_constrs) {
+ int e, v;
+ for(e=0; e<n_constrs; e++) {
+ eqnnzero(&constrs[e], 0);
+ for(v=0; v<=n_vars; v++) {
+ constrs[e].coef[v] = coefs[coef_index(e,v)];
+ }
+ constrs[e].touched = 1;
+ }
+ pn_constrs = n_constrs;
+}
+
+
+void Conjunct::convertEQstoGEQs(bool excludeStrides) {
+ simplify_conj(this,true,1,EQ_BLACK); // don't remember why I want to comment this statement out with reason "will cause inconsistency between Conjunct::mappedVars and Problem::nVars", 06/09/2009 by chun
+ problem->convertEQstoGEQs(excludeStrides);
+}
+
+
+void Conjunct::calculate_dimensions(Relation &R, int &ndim_all, int &ndim_domain) {
+
+ Conjunct * c = this;
+ Relation rc=Relation(R, c);
+
+ if(relation_debug) {
+ fprintf(DebugFile,"{{{\nIn Conjunct::calculate_dimensions:\n");
+ rc.prefix_print(DebugFile);
+ }
+
+ rc=Approximate(rc);
+ Relation rd=rc;
+
+ if(relation_debug) {
+ fprintf(DebugFile,"Conjunct::calculate_dimensions: Approximated as:\n");
+ rc.prefix_print(DebugFile);
+ }
+
+ // skip_set_checks++;
+
+ Conjunct * rc_conj=rc.single_conjunct();
+ ndim_all=rc.n_inp()+rc.n_out();
+ ndim_all-=rc_conj->n_EQs();
+
+ rc = Project_On_Sym(rc);
+ rc.simplify();
+
+ if(relation_debug) {
+ fprintf(DebugFile, "Conjunct::calculate_dimensions: after project_on_sym\n");
+ rc.prefix_print(DebugFile);
+ }
+
+ int n_eq_sym = 1000;
+ for (DNF_Iterator s(rc.query_DNF()); s.live(); s.next())
+ n_eq_sym = min(n_eq_sym, s.curr()->n_EQs());
+ ndim_all+=n_eq_sym;
+ // skip_set_checks--;
+
+ if (R.is_set())
+ ndim_domain = ndim_all;
+ else {
+ /* get dimensions for the domain (broadcasting) */
+
+ rd=Domain(rd);
+ rd.simplify();
+
+ if(relation_debug) {
+ fprintf(DebugFile,"Domain is:\n");
+ rd.prefix_print(DebugFile);
+ }
+
+ rc_conj=rd.single_conjunct();
+ ndim_domain=rd.n_set()-rc_conj->n_EQs()+n_eq_sym;
+ }
+
+ if(relation_debug) {
+ fprintf(DebugFile,"n_eq_sym=%d \n",n_eq_sym);
+ fprintf(DebugFile,"Dimensions: all=%d domain=%d\n}}}\n", ndim_all,ndim_domain);
+ }
+}
+
+} // namespace
diff --git a/omegalib/omega/src/pres_decl.cc b/omegalib/omega/src/pres_decl.cc
new file mode 100644
index 0000000..f5ac312
--- /dev/null
+++ b/omegalib/omega/src/pres_decl.cc
@@ -0,0 +1,71 @@
+#include <omega/pres_decl.h>
+#include <omega/omega_i.h>
+
+namespace omega {
+
+//
+// Declare functions.
+//
+Variable_ID F_Declaration::do_declare(Const_String s, Var_Kind var_type) {
+ Variable_ID v;
+ assert(var_type != Global_Var);
+ if(!s.null()) {
+ v = new Var_Decl(s, var_type, 0);
+ }
+ else {
+ v = new Var_Decl(var_type, 0);
+ }
+ myLocals.append(v);
+ return v;
+}
+
+Variable_ID F_Declaration::declare(Const_String) {
+ assert(0); // must be declared in forall, exists, or conjunct
+ return(NULL);
+}
+
+Section<Variable_ID> F_Declaration::declare_tuple(int n) {
+ int first = myLocals.size()+1;
+
+ for (int i=1 ; i<=n; i++)
+ declare();
+
+ return Section<Variable_ID>(&myLocals, first, n);
+}
+
+
+void F_Declaration::finalize() {
+ assert(n_children() == 1);
+ Formula::finalize();
+}
+
+bool F_Declaration::can_add_child() {
+ return n_children() < 1;
+}
+
+
+F_Declaration::F_Declaration(Formula *p, Rel_Body *r):
+ Formula(p,r), myLocals(0) {
+}
+
+F_Declaration::F_Declaration(Formula *p, Rel_Body *r, Variable_ID_Tuple &S):
+ Formula(p,r), myLocals(S) {
+}
+
+//
+// Destruct declarative node.
+// Delete variableID's themselves if they are not global.
+//
+F_Declaration::~F_Declaration() {
+ free_var_decls(myLocals);
+}
+
+//Setup names for printing
+void F_Declaration::setup_anonymous_wildcard_names() {
+ for(Tuple_Iterator<Variable_ID> VI(myLocals); VI; VI++) {
+ Variable_ID v = *VI;
+ if (v->base_name.null()) v->instance = wildCardInstanceNumber++;
+ }
+}
+
+} // namespace
diff --git a/omegalib/omega/src/pres_dnf.cc b/omegalib/omega/src/pres_dnf.cc
new file mode 100644
index 0000000..c9fd7e6
--- /dev/null
+++ b/omegalib/omega/src/pres_dnf.cc
@@ -0,0 +1,1416 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 the Omega Project Team
+ Copyright (C) 2005-2011 Chun Chen
+ All Rights Reserved.
+
+ Purpose:
+ Functions for disjunctive normal form.
+
+ Notes:
+
+ History:
+*****************************************************************************/
+
+#include <basic/Bag.h>
+#include <omega/pres_dnf.h>
+#include <omega/pres_conj.h>
+#include <omega/pres_tree.h> /* all DNFize functions are here */
+#include <omega/Relation.h>
+#include <omega/omega_i.h>
+
+namespace omega {
+
+void DNF::remap() {
+ for(DNF_Iterator DI(this); DI.live(); DI.next()) {
+ Conjunct *C = DI.curr();
+ C->remap();
+ }
+}
+
+
+//
+// DNF1 & DNF2 -> DNF.
+// Free arguments.
+//
+DNF* DNF_and_DNF(DNF* dnf1, DNF* dnf2) {
+ DNF* new_dnf = new DNF;
+ for(DNF_Iterator p(dnf2); p.live(); p.next()) {
+ new_dnf->join_DNF(DNF_and_conj(dnf1, p.curr()));
+ }
+ delete dnf1;
+ delete dnf2;
+ if(new_dnf->length() > 1) {
+ new_dnf->simplify();
+ }
+
+ if(pres_debug) {
+ fprintf(DebugFile, "+++ DNF_and_DNF OUT +++\n");
+ new_dnf->prefix_print(DebugFile);
+ }
+ return(new_dnf);
+}
+
+
+/*
+ * Remove redundant conjuncts from given DNF.
+ * If (C1 => C2), remove C1.
+ * C1 => C2 is TRUE: when problem where C1 is Black and C2 is Red
+ * Blk Red : has no red constraints.
+ * It means that C1 is a subset of C2 and therefore C1 is redundant.
+ *
+ * Exception: C1 => UNKNOWN - leave them as they are
+ */
+void DNF::rm_redundant_conjs(int effort) {
+ if(is_definitely_false() || has_single_conjunct())
+ return;
+
+ use_ugly_names++;
+ // skip_set_checks++;
+
+ int count = 0;
+ for(DNF_Iterator p(this); p.live(); p.next()) count++;
+
+ if(pres_debug) {
+ int i = 0;
+ fprintf(DebugFile, "@@@ rm_redundant_conjs IN @@@[\n");
+ prefix_print(DebugFile);
+ for(DNF_Iterator p(this); p.live(); p.next())
+ fprintf(DebugFile, "#%d = %p\n", ++i, p.curr());
+ }
+
+ DNF_Iterator pdnext;
+ DNF_Iterator pdel(this);
+ for(; pdel.live(); pdel=pdnext) {
+ pdnext = pdel;
+ pdnext.next();
+ Conjunct *cdel = pdel.curr();
+ int del_min_leading_zeros = cdel->query_guaranteed_leading_0s();
+ int del_max_leading_zeros = cdel->query_possible_leading_0s();
+
+ for(DNF_Iterator p(this); p.live(); p.next()) {
+ Conjunct *c = p.curr();
+ if(c != cdel) {
+ int c_min_leading_zeros = cdel->query_guaranteed_leading_0s();
+ int c_max_leading_zeros = cdel->query_possible_leading_0s();
+ if(pres_debug)
+ fprintf(DebugFile, "@@@ rm_redundant_conjs @%p => @%p[\n", cdel, c);
+
+ if (c->is_inexact() && cdel->is_exact()) {
+ if (pres_debug)
+ fprintf(DebugFile, "]@@@ rm_redundant_conjs @@@ Exact Conj => Inexact Conj is not tested\n");
+ }
+ else if (del_min_leading_zeros >=0 && c_min_leading_zeros >= 0
+ && c_max_leading_zeros >= 0 && del_max_leading_zeros >=0
+ && (del_min_leading_zeros > c_max_leading_zeros
+ || c_min_leading_zeros > del_max_leading_zeros)) {
+ if (1 || pres_debug)
+ fprintf(DebugFile, "]@@@ not redundant due to leading zero info\n");
+ }
+ else {
+ Conjunct *cgist = merge_conjs(cdel, c, MERGE_GIST);
+
+ if (!cgist->redSimplifyProblem(effort,0)) {
+ if(pres_debug) {
+ fprintf(DebugFile, "]@@@ rm_redundant_conjs @@@ IMPLICATION TRUE @%p\n", cdel);
+ cdel->prefix_print (DebugFile);
+ fprintf(DebugFile, "=>\n");
+ c->prefix_print (DebugFile);
+ }
+ rm_conjunct(cdel);
+ delete cdel;
+ delete cgist;
+ break;
+ }
+ else {
+ if(pres_debug) {
+ fprintf(DebugFile, "]@@@ rm_redundant_conjs @@@ IMPLICATION FALSE @%p\n", cdel);
+ if(pres_debug > 1)
+ cgist->prefix_print(DebugFile);
+ }
+ delete cgist;
+ }
+ }
+ }
+ }
+ }
+
+ if(pres_debug) {
+ fprintf(DebugFile, "]@@@ rm_redundant_conjs OUT @@@\n");
+ prefix_print(DebugFile);
+ }
+ // skip_set_checks--;
+ use_ugly_names--;
+}
+
+
+/* Remove inexact conjuncts from given DNF if it contains UNKNOWN
+ * conjunct
+ */
+
+void DNF::rm_redundant_inexact_conjs() {
+ if (is_definitely_false() || has_single_conjunct())
+ return;
+
+ bool has_unknown=false;
+ bool has_inexact=false;
+
+ Conjunct * c_unknown = 0; // make compiler shut up
+ for (DNF_Iterator p(this); p.live(); p.next()) {
+ assert (p.curr()->problem!=NULL);
+ if (p.curr()->is_inexact()) {
+ if (p.curr()->is_unknown()) {
+ has_unknown=true;
+ c_unknown = p.curr();
+ }
+ else
+ has_inexact=true;
+ }
+ }
+
+ if (! has_unknown || ! has_inexact)
+ return;
+
+ use_ugly_names++;
+ // skip_set_checks++;
+
+ DNF_Iterator pdnext;
+ DNF_Iterator pdel(this);
+
+ for (; pdel.live(); pdel=pdnext) {
+ pdnext = pdel;
+ pdnext.next();
+ Conjunct * cdel=pdel.curr();
+ if (cdel->is_inexact() && cdel!=c_unknown) {
+ rm_conjunct(cdel);
+ delete cdel;
+ }
+ }
+
+ use_ugly_names--;
+ // skip_set_checks--;
+}
+
+
+
+//
+// DNF properties.
+//
+bool DNF::is_definitely_false() const {
+ return(conjList.empty());
+}
+
+bool DNF::is_definitely_true() const {
+ return(has_single_conjunct() && single_conjunct()->is_true());
+}
+
+int DNF::length() const {
+ return conjList.length();
+}
+
+Conjunct *DNF::single_conjunct() const {
+ assert(conjList.length()==1);
+ return(conjList.front());
+}
+
+bool DNF::has_single_conjunct() const {
+ return (conjList.length()==1);
+}
+
+Conjunct *DNF::rm_first_conjunct() {
+ if(conjList.empty()) {
+ return NULL;
+ }
+ else {
+ return conjList.remove_front();
+ }
+}
+
+
+//
+// Convert DNF to Formula and add it root.
+// Free this DNF.
+//
+void DNF::DNF_to_formula(Formula* root) {
+ Formula *new_or;
+ if (conjList.length()!=1) {
+ skip_finalization_check++;
+ new_or = root->add_or();
+ skip_finalization_check--;
+ }
+ else {
+ new_or = root;
+ }
+ while(!conjList.empty()) {
+ Conjunct *conj = conjList.remove_front();
+ new_or->add_child(conj);
+ }
+ delete this;
+}
+
+
+//
+// DNF functions.
+//
+DNF::DNF() : conjList() {
+}
+
+DNF::~DNF() {
+ // for(DNF_Iterator p(this); p.live(); p.next()) {
+ // if(p.curr() != NULL)
+ // delete p.curr();
+ // }
+ for(List_Iterator<Conjunct *> i(conjList); i.live(); i.next())
+ delete *i;
+}
+
+//
+// Copy DNF
+//
+DNF* DNF::copy(Rel_Body *rel_body) {
+ DNF *new_dnf = new DNF;
+ for(DNF_Iterator pd(this); pd.live(); pd.next()) {
+ Conjunct *conj = pd.curr();
+ if(conj)
+ new_dnf->add_conjunct(conj->copy_conj_diff_relation(rel_body,rel_body));
+ }
+ return(new_dnf);
+}
+
+//
+// Add Conjunct to DNF
+//
+void DNF::add_conjunct(Conjunct* conj) {
+ conjList.append(conj);
+}
+
+//
+// Add DNF to DNF.
+// The second DNF is reused.
+//
+void DNF::join_DNF(DNF* dnf) {
+ conjList.join(dnf->conjList);
+ delete dnf;
+}
+
+//
+// Remove conjunct from DNF.
+// Conjunct itself is not deleted.
+//
+void DNF::rm_conjunct(Conjunct *c) {
+ if(conjList.front() == c) {
+ conjList.remove_front();
+ }
+ else {
+ List_Iterator<Conjunct*> p, pp;
+ for(p=List_Iterator<Conjunct*> (conjList); p; p++) {
+ if((*p)==c) {
+ conjList.del_after(pp);
+ return;
+ }
+ pp = p;
+ }
+ assert(0 && "DNF::rm_conjunct: no such conjunct");
+ }
+}
+
+
+// remove (but don't delete) all conjuncts
+
+void DNF::clear() {
+ conjList.clear();
+}
+
+
+//
+// DNF & CONJ -> new DNF.
+// Don't touch arguments.
+//
+DNF* DNF_and_conj(DNF* dnf, Conjunct* conj) {
+ DNF* new_dnf = new DNF;
+ for(DNF_Iterator p(dnf); p.live(); p.next()) {
+ Conjunct* new_conj = merge_conjs(p.curr(), conj, MERGE_REGULAR);
+ new_dnf->add_conjunct(new_conj);
+ }
+ if(new_dnf->length() > 1) {
+ new_dnf->simplify();
+ }
+ return(new_dnf);
+}
+
+//
+// Compute C0 and not (C1 or C2 or ... CN).
+// Reuse/delete its arguments.
+//
+DNF* conj_and_not_dnf(Conjunct *positive_conjunct, DNF *neg_conjs, bool weak) {
+ DNF *ret_dnf = new DNF;
+ int recursive = 0;
+ use_ugly_names++;
+
+ if(pres_debug) {
+ fprintf(DebugFile, "conj_and_not_dnf [\n");
+ fprintf(DebugFile, "positive_conjunct:\n");
+ positive_conjunct->prefix_print(DebugFile);
+ fprintf(DebugFile, "neg_conjs:\n");
+ neg_conjs->prefix_print(DebugFile);
+ fprintf(DebugFile, "\n\n");
+ }
+
+ if (simplify_conj(positive_conjunct, true, false, EQ_BLACK) == false) {
+ positive_conjunct = NULL;
+ goto ReturnDNF;
+ }
+
+ /* Compute gists of negative conjuncts given positive conjunct */
+
+
+ int c0_updated;
+ c0_updated = true;
+ while(c0_updated) {
+ c0_updated = false;
+ for(DNF_Iterator p(neg_conjs); p.live(); p.next()) {
+ Conjunct *neg_conj = p.curr();
+ if(neg_conj==NULL) continue;
+ if (!positive_conjunct->is_exact()
+ && !neg_conj->is_exact()) {
+ // C1 and unknown & ~(C2 and unknown) = C1 and unknown
+ delete neg_conj;
+ p.curr_set(NULL);
+ continue;
+ }
+ Conjunct *cgist = merge_conjs(positive_conjunct, neg_conj, MERGE_GIST);
+ if(simplify_conj(cgist, false, true, EQ_RED) == false) {
+ // C1 & ~FALSE = C1
+ delete neg_conj;
+ p.curr_set(NULL);
+ }
+ else {
+ cgist->rm_color_constrs();
+ if(cgist->is_true()) {
+ // C1 & ~TRUE = FALSE
+ delete cgist;
+ goto ReturnDNF;
+ }
+ else {
+ if(cgist->cost()==1) { // single inequality
+ DNF *neg_dnf = negate_conj(cgist);
+ delete cgist;
+ Conjunct *conj =
+ merge_conjs(positive_conjunct, neg_dnf->single_conjunct(), MERGE_REGULAR);
+ delete positive_conjunct;
+ delete neg_dnf;
+ positive_conjunct = conj;
+ delete neg_conj;
+ p.curr_set(NULL);
+ if(!simplify_conj(positive_conjunct, false, false, EQ_BLACK)) {
+ positive_conjunct = NULL;
+ goto ReturnDNF;
+ }
+ c0_updated = true;
+ }
+ else {
+ delete neg_conj;
+ p.curr_set(cgist);
+ }
+ }
+ }
+ }
+ }
+
+ if(pres_debug) {
+ fprintf(DebugFile, "--- conj_and_not_dnf positive_conjunct NEW:\n");
+ positive_conjunct->prefix_print(DebugFile);
+ fprintf(DebugFile, "--- conj_and_not_dnf neg_conjs GISTS:\n");
+ neg_conjs->prefix_print(DebugFile);
+ fprintf(DebugFile, "--- conj_and_not_dnf ---\n\n");
+ }
+
+ /* Find minimal negative conjunct */
+ {
+ Conjunct *min_conj = NULL;
+ int min_cost = INT_MAX;
+ DNF_Iterator min_p;
+ int live_count = 0;
+ for(DNF_Iterator q(neg_conjs); q.live(); q.next()) {
+ Conjunct *neg_conj = q.curr();
+ if(neg_conj!=NULL) {
+ live_count++;
+ if(neg_conj->cost() < min_cost) {
+ min_conj = neg_conj;
+ min_cost = neg_conj->cost();
+ min_p = q;
+ }
+ }
+ }
+
+ /* Negate minimal conjunct, AND result with positive conjunct */
+ if(weak || min_conj==NULL) {
+ ret_dnf->add_conjunct(positive_conjunct);
+ positive_conjunct = NULL;
+ }
+ else if (min_cost == CantBeNegated) {
+ static int OMEGA_WHINGE = -1;
+ if (OMEGA_WHINGE < 0) {
+ OMEGA_WHINGE = getenv("OMEGA_WHINGE") ? atoi(getenv("OMEGA_WHINGE")) : 0;
+ }
+ if (OMEGA_WHINGE) {
+ fprintf(stderr, "Ignoring negative clause that can't be negated and generating inexact result\n");
+ if (!pres_debug) fprintf(DebugFile, "Ignoring negative clause that can't be negated and generating inexact result\n");
+ }
+
+ positive_conjunct->make_inexact();
+ ret_dnf->add_conjunct(positive_conjunct);
+ positive_conjunct = NULL;
+ if(pres_debug)
+ fprintf(DebugFile, "Ignoring negative clause that can't be negated and generating inexact upper bound\n");
+ }
+ else {
+ DNF *neg_dnf = negate_conj(min_conj);
+ delete min_conj;
+ min_p.curr_set(NULL);
+ DNF *new_pos = DNF_and_conj(neg_dnf, positive_conjunct);
+ delete neg_dnf;
+ delete positive_conjunct;
+ positive_conjunct = NULL;
+ // new_dnf->rm_redundant_conjs(2);
+ if(live_count>1) {
+ recursive = 1;
+ for(DNF_Iterator pd(new_pos); pd.live(); pd.next()) {
+ Conjunct *conj = pd.curr();
+ ret_dnf->join_DNF(conj_and_not_dnf(conj, neg_conjs->copy(conj->relation())));
+ pd.curr_set(NULL);
+ }
+ delete new_pos;
+ }
+ else {
+ ret_dnf->join_DNF(new_pos);
+ }
+ }
+ }
+
+ReturnDNF:;
+ delete positive_conjunct;
+ delete neg_conjs;
+
+ //if (recursive) ret_dnf->rm_redundant_conjs(1);
+
+ if(pres_debug) {
+ fprintf(DebugFile, "] conj_and_not_dnf RETURN:\n");
+ ret_dnf->prefix_print(DebugFile);
+ fprintf(DebugFile, "\n\n");
+ }
+ use_ugly_names--;
+ return ret_dnf;
+}
+
+/* first some functions for manipulating oc "problems" */
+
+static void EqnnZero(eqn *e, int s) {
+// memset((char*)e, 0, (headerWords+1+s)*sizeof(int));
+ e->key = 0;
+ e->touched = 0;
+ e->color = EQ_BLACK;
+ e->essential = 0;
+ e->varCount = 0;
+ for (int i = 0; i <= s; i++)
+ e->coef[i] = 0;
+}
+
+/*
+ * Make a new black equation in a given problem
+ */
+static int NewEquation(Problem *p) {
+ int e = p->newEQ();
+ EqnnZero(&p->EQs[e], p->nVars);
+ return e;
+}
+
+/*
+ * Make a new black inequality in a given problem
+ */
+static int NewInequality(Problem *p) {
+ int g = p->newGEQ();
+ EqnnZero(&p->GEQs[g], p->nVars);
+ return g;
+}
+
+//
+// ~CONJ -> DNF
+//
+DNF* negate_conj(Conjunct* conj) {
+ if(pres_debug) {
+ fprintf(DebugFile, "%%%%%% negate_conj IN %%%%%%\n");
+ conj->prefix_print(DebugFile);
+ fprintf(DebugFile, "\n");
+ }
+
+ DNF* new_dnf = new DNF;
+ Problem *p = conj->problem;
+ int i, j,k;
+
+ if (!conj->is_exact()) new_dnf->add_conjunct(conj->copy_conj_same_relation());
+
+ Conjunct* true_part = new Conjunct(NULL, conj->relation());
+ Problem *tp = true_part->problem;
+ copy_conj_header(true_part, conj);
+ true_part->invalidate_leading_info();
+ int *wildCard = new int[p->nGEQs];
+ int *handleIt = new int[p->nVars+1];
+ for(j=1; j<=p->nVars; j++) handleIt[j] = false;
+
+ for(i=0; i<p->nGEQs; i++) {
+ wildCard[i] = 0;
+ for(j=1; j<=p->nVars; j++) {
+ Variable_ID v = conj->mappedVars[j];
+ if(v->kind()==Wildcard_Var && p->GEQs[i].coef[j]!=0) {
+ assert(wildCard[i] == 0);
+ handleIt[j] = true;
+ if (p->GEQs[i].coef[j] > 0) wildCard[i] = j;
+ else wildCard[i] = -j;
+ }
+ }
+ }
+
+ for(i=0; i<p->nGEQs; i++) if (wildCard[i] == 0) {
+ /* ~(ax + by + c >= 0) = (-ax -by -c-1 >= 0) */
+ Conjunct* new_conj = true_part->copy_conj_same_relation();
+ Problem *np = new_conj->problem;
+ new_conj->exact=true;
+ int n_e = NewInequality(np);
+ int t_e = NewInequality(tp);
+ np->GEQs[n_e].coef[0] = -p->GEQs[i].coef[0]-1;
+ tp->GEQs[t_e].coef[0] = p->GEQs[i].coef[0];
+ for(j=1; j<=p->nVars; j++) {
+ Variable_ID v = conj->mappedVars[j];
+ if(v->kind()==Wildcard_Var && p->GEQs[i].coef[j]!=0) {
+ assert(0 && "negate_conj: wildcard in inequality");
+ }
+ np->GEQs[n_e].coef[j] = -p->GEQs[i].coef[j];
+ tp->GEQs[t_e].coef[j] = p->GEQs[i].coef[j];
+
+ }
+ assert(j-1 == p->nVars);
+ assert(j-1 == conj->mappedVars.size());
+ new_dnf->add_conjunct(new_conj);
+ }
+
+
+ for(i=0; i<p->nEQs; i++) {
+ int wc_no = 0;
+ int wc_j = 0; // make complier shut up
+ for(j=1; j<=p->nVars; j++) {
+ Variable_ID v = conj->mappedVars[j];
+ if(v->kind()==Wildcard_Var && p->EQs[i].coef[j]!=0) {
+ wc_no++;
+ wc_j = j;
+ }
+ }
+
+ if(wc_no!=0) {
+#if ! defined NDEBUG
+ int i2;
+ assert(!handleIt[wc_j]);
+ for(i2=0; i2<p->nEQs; i2++)
+ if(i != i2 && p->EQs[i2].coef[wc_j] != 0) break;
+ assert(i2 >= p->nEQs);
+#endif
+ assert(wc_no == 1 && "negate_conj: more than 1 wildcard in equality");
+
+ // === Negating equality with a wildcard for K>0 ===
+ // ~(exists v st expr + K v + C = 0) =
+ // (exists v st 1 <= - expr - K v - C <= K-1)
+
+ Conjunct *nc = true_part->copy_conj_same_relation();
+ Problem *np = nc->problem;
+ nc->exact=true;
+
+ // -K alpha = expr <==> K alpha = expr
+ if(p->EQs[i].coef[wc_j]<0)
+ p->EQs[i].coef[wc_j] = -p->EQs[i].coef[wc_j];
+
+ if(p->EQs[i].coef[wc_j]==2) {
+ // ~(exists v st expr +2v +C = 0) =
+ // (exists v st -expr -2v -C = 1)
+ // That is (expr +2v +C+1 = 0)
+ int e = NewEquation(np);
+ np->EQs[e].coef[0] = p->EQs[i].coef[0] +1;
+ for(j=1; j<=p->nVars; j++) {
+ np->EQs[e].coef[j] = p->EQs[i].coef[j];
+ }
+ }
+ else {
+ // -expr -Kv -C-1 >= 0
+ int e = NewInequality(np);
+ np->GEQs[e].coef[0] = -p->EQs[i].coef[0] -1;
+ for(j=1; j<=p->nVars; j++) {
+ np->GEQs[e].coef[j] = -p->EQs[i].coef[j];
+ }
+
+ // +expr +Kv +C+K-1 >= 0
+ e = NewInequality(np);
+ np->GEQs[e].coef[0] = p->EQs[i].coef[0] +p->EQs[i].coef[wc_j] -1;
+ for(j=1; j<=p->nVars; j++) {
+ np->GEQs[e].coef[j] = p->EQs[i].coef[j];
+ }
+ }
+
+ new_dnf->add_conjunct(nc);
+
+ }
+ else {
+ /* ~(ax + by + c = 0) = (-ax -by -c-1 >= 0) Or (ax + by + c -1 >= 0) */
+ Conjunct *nc1 = true_part->copy_conj_same_relation();
+ Conjunct *nc2 = true_part->copy_conj_same_relation();
+ Problem* np1 = nc1->problem;
+ Problem* np2 = nc2->problem;
+ nc1->invalidate_leading_info();
+ nc2->invalidate_leading_info();
+ nc1->exact=true;
+ nc2->exact=true;
+ int n_e1 = NewInequality(np1);
+ int n_e2 = NewInequality(np2);
+ np1->GEQs[n_e1].coef[0] = -p->EQs[i].coef[0]-1;
+ np2->GEQs[n_e2].coef[0] = p->EQs[i].coef[0]-1;
+ for(j=1; j<=p->nVars; j++) {
+ coef_t coef = p->EQs[i].coef[j];
+ np1->GEQs[n_e1].coef[j] = -coef;
+ np2->GEQs[n_e2].coef[j] = coef;
+ }
+ new_dnf->add_conjunct(nc1);
+ new_dnf->add_conjunct(nc2);
+ }
+ {
+ int e = NewEquation(tp);
+ tp->EQs[e].coef[0] = p->EQs[i].coef[0];
+ for(j=1; j<=p->nVars; j++)
+ tp->EQs[e].coef[j] = p->EQs[i].coef[j];
+ }
+ }
+
+ for(j=1; j<=p->nVars; j++)
+ if (handleIt[j]) {
+ for(i=0; i<p->nGEQs; i++)
+ if (wildCard[i] == j)
+ for(k=0; k<p->nGEQs; k++) if (wildCard[k] == -j){
+ // E_i <= c_i alpha
+ // c_k alpha <= E_k
+ // c_k E_i <= c_i c_k alpha <= c_i E_k
+ // c_k E_i <= c_i c_k floor (c_i E_k / c_i c_k)
+ // negating:
+ // c_k E_i > c_i c_k floor (c_i E_k / c_i c_k)
+ // c_k E_i > c_i c_k beta > c_i E_k - c_i c_k
+ // c_k E_i - 1 >= c_i c_k beta >= c_i E_k - c_i c_k + 1
+ Conjunct* new_conj = true_part->copy_conj_same_relation();
+ Problem *np = new_conj->problem;
+ coef_t c_k = - p->GEQs[k].coef[j];
+ coef_t c_i = p->GEQs[i].coef[j];
+ assert(c_k > 0);
+ assert(c_i > 0);
+ new_conj->exact=true;
+ int n_e = NewInequality(np);
+ // c_k E_i - 1 >= c_i c_k beta
+ int v;
+ for(v=0; v<=p->nVars; v++) {
+ np->GEQs[n_e].coef[v] = - c_k * p->GEQs[i].coef[v];
+ }
+ np->GEQs[n_e].coef[j] = -c_i * c_k;
+ np->GEQs[n_e].coef[0]--;
+
+ n_e = NewInequality(np);
+ // c_i c_k beta >= c_i E_k - c_i c_k + 1
+ // c_i c_k beta + c_i c_k -1 >= c_i E_k
+ for(v=0; v<=p->nVars; v++) {
+ np->GEQs[n_e].coef[v] = - c_i * p->GEQs[k].coef[v];
+ }
+ np->GEQs[n_e].coef[j] = c_i * c_k;
+ np->GEQs[n_e].coef[0] += c_i * c_k -1;
+
+ new_dnf->add_conjunct(new_conj);
+ }
+ }
+
+ if(pres_debug) {
+ fprintf(DebugFile, "%%%%%% negate_conj OUT %%%%%%\n");
+ new_dnf->prefix_print(DebugFile);
+ }
+ delete true_part;
+ delete[] wildCard;
+ delete[] handleIt;
+ return(new_dnf);
+}
+
+
+
+
+///////////////////////////////////////////////////////
+// DNFize formula -- this is the real simplification //
+// It also destroys the formula it simplifies //
+///////////////////////////////////////////////////////
+
+
+
+//
+// Try to separate positive and negative clauses below the AND,
+// letting us use the techniques described in Pugh & Wonnacott:
+// "An Exact Method for Value-Based Dependence Analysis"
+//
+
+
+DNF* F_And::DNFize() {
+ Conjunct *positive_conjunct = NULL;
+ DNF *neg_conjs = new DNF;
+ List<DNF*> pos_dnfs;
+ List_Iterator<DNF*> pos_dnf_i;
+ DNF *new_dnf = new DNF;
+ int JustReturnDNF = 0;
+
+ use_ugly_names++;
+
+ if(pres_debug) {
+ fprintf(DebugFile, "\nF_And:: DNFize [\n");
+ prefix_print(DebugFile);
+ }
+
+ if(children().empty()) {
+ Conjunct * c=new Conjunct(NULL, relation());
+ new_dnf->add_conjunct(c);
+ }
+ else {
+ while(!children().empty()) {
+ Formula* carg = children().remove_front();
+ if(carg->node_type()==Op_Not) {
+ // DNF1 & ~DNF2 -> DNF
+ DNF *dnf = carg->children().remove_front()->DNFize();
+ delete carg;
+ neg_conjs->join_DNF(dnf); // negative conjunct
+ }
+ else {
+ // DNF1 & DNF2 -> DNF
+ DNF *dnf = carg->DNFize();
+ int dl = dnf->length();
+ if(dl==0) {
+ // DNF & false -> false
+ delete this;
+ JustReturnDNF = 1;
+ break;
+ }
+ else if(dl==1) {
+ // positive conjunct
+ Conjunct *conj = dnf->rm_first_conjunct();
+ delete dnf;
+ if(positive_conjunct==NULL) {
+ positive_conjunct = conj;
+ }
+ else {
+ Conjunct *new_conj = merge_conjs(positive_conjunct, conj, MERGE_REGULAR);
+ delete conj;
+ delete positive_conjunct;
+ positive_conjunct = new_conj;
+ }
+ }
+ else {
+ // positive DNF
+ pos_dnfs.append(dnf);
+ }
+ }
+ }
+
+ if (!JustReturnDNF) {
+ Rel_Body * my_relation = relation();
+ delete this;
+
+ // If we have a positive_conjunct, it can serve as the 1st arg to
+ // conj_and_not_dnf. Otherwise, if pos_dnfs has one DNF,
+ // use each conjunct there for this purpose.
+ // Only pass "true" here if there is nothing else to try,
+ // as long as TRY_TO_AVOID_TRUE_AND_NOT_DNF is set.
+ //
+ // Perhaps we should even try to and multiple DNF's?
+
+ if (!positive_conjunct && pos_dnfs.length() == 1) {
+ if(pres_debug) {
+ fprintf(DebugFile, "--- F_AND::DNFize() Single pos_dnf:\n");
+ pos_dnfs[1]->prefix_print(DebugFile);
+ fprintf(DebugFile, "--- F_AND::DNFize() vs neg_conjs:\n");
+ neg_conjs->prefix_print(DebugFile);
+ }
+
+ DNF *real_neg_conjs = new DNF;
+ for (DNF_Iterator nc(neg_conjs); nc; nc++) {
+ if (simplify_conj((*nc), true, false, EQ_BLACK) != false)
+ real_neg_conjs->add_conjunct(*nc);
+ (*nc) = 0;
+ }
+ delete neg_conjs;
+ neg_conjs = real_neg_conjs;
+
+ for(DNF_Iterator pc(pos_dnfs[1]); pc; pc++) {
+ new_dnf->join_DNF(conj_and_not_dnf((*pc), neg_conjs->copy((*pc)->relation())));
+ (*pc) = 0;
+ }
+ }
+ else if(positive_conjunct==NULL && neg_conjs->is_definitely_false()) {
+ pos_dnf_i = List_Iterator<DNF*>(pos_dnfs);
+ delete new_dnf;
+ new_dnf = *pos_dnf_i;
+ *pos_dnf_i = NULL;
+ pos_dnf_i++;
+ for ( ; pos_dnf_i; pos_dnf_i++) {
+ DNF *pos_dnf = *pos_dnf_i;
+ new_dnf = DNF_and_DNF(new_dnf, pos_dnf);
+ *pos_dnf_i = NULL;
+ }
+ }
+ else {
+ if(positive_conjunct==NULL) {
+ static int OMEGA_WHINGE = -1;
+ if (OMEGA_WHINGE < 0) {
+ OMEGA_WHINGE = getenv("OMEGA_WHINGE") ? atoi(getenv("OMEGA_WHINGE")) : 0;
+ }
+
+ if (pres_debug || OMEGA_WHINGE) {
+ fprintf(DebugFile, "Uh-oh: F_AND::DNFize() resorting to TRUE and not DNF\n");
+ fprintf(DebugFile, "--- F_AND::DNFize() neg_conjs\n");
+ neg_conjs->prefix_print(DebugFile);
+ fprintf(DebugFile, "--- F_AND::DNFize() pos_dnfs:\n");
+ for (pos_dnf_i=List_Iterator<DNF*>(pos_dnfs); pos_dnf_i; pos_dnf_i++) {
+ (*pos_dnf_i)->prefix_print(DebugFile);
+ fprintf(DebugFile,"---- --\n");
+ }
+ }
+ if (OMEGA_WHINGE) {
+ fprintf(stderr, "Uh-oh: F_AND::DNFize() resorting to TRUE and not DNF\n");
+ fprintf(stderr, "--- F_AND::DNFize() neg_conjs\n");
+ neg_conjs->prefix_print(stderr);
+ fprintf(stderr, "--- F_AND::DNFize() pos_dnfs:\n");
+ for (pos_dnf_i=List_Iterator<DNF*>(pos_dnfs); pos_dnf_i; pos_dnf_i++) {
+ (*pos_dnf_i)->prefix_print(stderr);
+ fprintf(stderr,"---- --\n");
+ }
+ }
+ positive_conjunct = new Conjunct(NULL, my_relation);
+ }
+
+ if(!neg_conjs->is_definitely_false()) {
+ new_dnf->join_DNF(conj_and_not_dnf(positive_conjunct, neg_conjs));
+ neg_conjs = NULL;
+ }
+ else {
+ new_dnf->add_conjunct(positive_conjunct);
+ }
+ positive_conjunct = NULL;
+
+ //
+ // AND it with positive DNFs
+ //
+ if(pres_debug) {
+ fprintf(DebugFile, "--- F_AND::DNFize() pos_dnfs:\n");
+ for (pos_dnf_i=List_Iterator<DNF*>(pos_dnfs); pos_dnf_i; pos_dnf_i++)
+ (*pos_dnf_i)->prefix_print(DebugFile);
+ }
+ for (pos_dnf_i = List_Iterator<DNF*>(pos_dnfs); pos_dnf_i; pos_dnf_i++) {
+ DNF *pos_dnf = *pos_dnf_i;
+ new_dnf = DNF_and_DNF(new_dnf, pos_dnf);
+ *pos_dnf_i = NULL;
+ }
+ }
+ }
+ }
+
+ delete positive_conjunct;
+ delete neg_conjs;
+ for (pos_dnf_i = List_Iterator<DNF*>(pos_dnfs); pos_dnf_i; pos_dnf_i++)
+ delete *pos_dnf_i;
+
+ if(pres_debug) {
+ fprintf(DebugFile, "] F_AND::DNFize() OUT \n");
+ new_dnf->prefix_print(DebugFile);
+ }
+
+ use_ugly_names--;
+
+ return new_dnf;
+}
+
+//
+// ~ dnf = true ^ ~ dnf, so just call conj_and_not_dnf
+//
+
+DNF* F_Not::DNFize() {
+ Conjunct *positive_conjunct = new Conjunct(NULL, relation());
+ DNF *neg_conjs = children().remove_front()->DNFize();
+ delete this;
+ DNF *new_dnf = conj_and_not_dnf(positive_conjunct, neg_conjs);
+
+ if(pres_debug) {
+ fprintf(DebugFile, "=== F_NOT::DNFize() OUT ===\n");
+ new_dnf->prefix_print(DebugFile);
+ }
+ return new_dnf;
+}
+
+
+//
+// or is almost in DNF already:
+//
+
+DNF* F_Or::DNFize() {
+ DNF* new_dnf = new DNF;
+ bool empty_or=true;
+
+ while(!children().empty()) {
+ DNF* c_dnf = children().remove_front()->DNFize();
+ new_dnf->join_DNF(c_dnf);
+ empty_or=false;
+ }
+
+
+ delete this;
+
+ if(pres_debug) {
+ fprintf(DebugFile, "=== F_OR::DNFize() OUT ===\n");
+ new_dnf->prefix_print(DebugFile);
+ }
+ return(new_dnf);
+}
+
+
+//
+// exists x : (c1 v c2 v ...) --> (exists x : c1) v (exists x : c2) v ...
+//
+
+DNF* F_Exists::DNFize() {
+ DNF *dnf = children().remove_front()->DNFize();
+
+ for (DNF_Iterator pd(dnf); pd.live(); pd.next()) {
+ Conjunct *conj = pd.curr();
+
+ // can simply call localize_vars for DNF with a single conjunct
+ Variable_ID_Tuple locals_copy(myLocals.size());
+ copy_var_decls(locals_copy, myLocals);
+ conj->push_exists(locals_copy);
+ conj->remap();
+ reset_remap_field(myLocals);
+
+ conj->r_constrs = 0;
+ conj->simplified = false; // who knows
+ conj->cols_ordered = false;
+ }
+ delete this;
+
+ if(pres_debug) {
+ fprintf(DebugFile, "=== F_EXISTS::DNFize() OUT ===\n");
+ dnf->prefix_print(DebugFile);
+ }
+ return(dnf);
+}
+
+
+//
+// Single conjunct is already in DNF.
+//
+
+DNF* Conjunct::DNFize() {
+ assert(!is_compressed());
+ DNF *results = new DNF;
+
+ if (is_true()) {
+ simplified = true;
+ verified = true;
+ results->add_conjunct(this);
+ }
+ else {
+ results->add_conjunct(this);
+ }
+
+ return results;
+}
+
+
+//
+// Foralls should have been removed before we get to DNFize
+//
+
+DNF* F_Forall::DNFize() {
+ assert(0);
+ return(NULL);
+}
+
+void DNF::count_leading_0s() {
+ if (conjList.empty())
+ return;
+
+ for (DNF_Iterator conj(this); conj; conj++) {
+ (*conj)->count_leading_0s();
+ }
+}
+
+
+// return x s.t. forall conjuncts c, c has >= x leading 0s
+// if set, always returns -1; arg tells you if it's a set or relation.
+
+int DNF::query_guaranteed_leading_0s(int what_to_return_for_empty_dnf) {
+ count_leading_0s();
+ int result = what_to_return_for_empty_dnf; // if set, -1; if rel, 0
+ bool first = true;
+
+ for (DNF_Iterator conj(this); conj; conj++) {
+ int tmp = (*conj)->query_guaranteed_leading_0s();
+ assert(tmp >= 0 || ((*conj)->relation()->is_set() && tmp == -1));
+ if (first || tmp < result) result = tmp;
+ first = false;
+ }
+
+ return result;
+}
+
+// return x s.t. forall conjuncts c, c has <= x leading 0s
+// if no conjuncts, return the argument
+
+int DNF::query_possible_leading_0s(int n_input_and_output) {
+ count_leading_0s();
+ int result = n_input_and_output;
+ bool first = true;
+
+ for (DNF_Iterator conj(this); conj; conj++) {
+ int tmp = (*conj)->query_possible_leading_0s();
+ assert(tmp >= 0 || (tmp == -1 && (*conj)->relation()->is_set()));
+ if (first || tmp > result) result = tmp;
+ first = false;
+ }
+
+ return result;
+}
+
+
+// return 0 if we don't know, or +-1 if we do
+
+int DNF::query_leading_dir() {
+ count_leading_0s();
+ int result = 0;
+ bool first = true;
+
+ for (DNF_Iterator conj(this); conj; conj++) {
+ int glz = (*conj)->query_guaranteed_leading_0s();
+ int plz = (*conj)->query_possible_leading_0s();
+ int rlz = 0; // shut the compiler up
+ if (glz != plz)
+ return 0;
+
+ if (first) {
+ rlz = glz;
+ result = (*conj)->query_leading_dir();
+ first = false;
+ }
+ else
+ if (glz != rlz || result != (*conj)->query_leading_dir())
+ return 0;
+ }
+
+ return result;
+}
+
+void Conjunct::count_leading_0s() {
+ Rel_Body *body = relation();
+ int max_depth = min(body->n_inp(), body->n_out());
+ if(body->is_set()) {
+ assert(guaranteed_leading_0s == -1 && possible_leading_0s == -1);
+// guaranteed_leading_0s = possible_leading_0s = -1;
+ leading_dir = 0;
+ return;
+ }
+
+
+#if ! defined NDEBUG
+ assert_leading_info();
+#endif
+ if (guaranteed_leading_0s < 0) {
+ int L;
+ for (L=1; L <= max_depth; L++) {
+ Variable_ID in = body->input_var(L), out = body->output_var(L);
+ coef_t min, max;
+ bool guaranteed;
+
+ query_difference(out, in, min, max, guaranteed);
+ if (min < 0 || max > 0) {
+ if (min > 0 || max < 0) { // we know guaranteed & possible
+ guaranteed_leading_0s = possible_leading_0s = L-1;
+ if (min > 0) // We know its 0,..,0,+
+ leading_dir = 1;
+ else // We know its 0,..,0,-
+ leading_dir = -1;
+ return;
+ }
+ break;
+ }
+ }
+ guaranteed_leading_0s = L-1;
+ for ( ; L <= max_depth; L++) {
+ Variable_ID in = body->input_var(L),
+ out = body->output_var(L);
+ coef_t min, max;
+ bool guaranteed;
+
+ query_difference(out, in, min, max, guaranteed);
+
+ if (min > 0 || max < 0) break;
+ }
+ possible_leading_0s = L-1;
+ }
+#if ! defined NDEBUG
+ assert_leading_info();
+#endif
+}
+
+//
+// add level-carried DNF form out to level "level"
+//
+
+
+void DNF::make_level_carried_to(int level) {
+ count_leading_0s();
+ Rel_Body *body = 0; // make compiler shut up
+ if (length() > 0 && !(body = conjList.front()->relation())->is_set()) {
+ // LCDNF makes no sense otherwise
+ Relation tmp;
+#ifndef NDEBUG
+ tmp = Relation(*body,42);
+#endif
+
+ DNF *newstuff = new DNF;
+ int shared_depth = min(body->n_inp(), body->n_out());
+ int split_to = level >= 0 ? min(shared_depth,level) : shared_depth;
+
+ skip_finalization_check++;
+ EQ_Handle e;
+
+ for (DNF_Iterator conj(this); conj; conj++) {
+ assert(body = (*conj)->relation());
+ int leading_eqs;
+
+ bool is_guaranteed = (*conj)->verified;
+
+ for (leading_eqs=1; leading_eqs <= split_to; leading_eqs++) {
+ Variable_ID in = body->input_var(leading_eqs),
+ out = body->output_var(leading_eqs);
+ coef_t min, max;
+ bool guaranteed;
+
+ if (leading_eqs > (*conj)->possible_leading_0s &&
+ (*conj)->leading_dir_valid_and_known()) {
+ leading_eqs--;
+ break;
+ }
+
+ if (leading_eqs > (*conj)->guaranteed_leading_0s) {
+ (*conj)->query_difference(out, in, min, max, guaranteed);
+ if (min > 0 || max < 0) guaranteed = true;
+// fprintf(DebugFile,"Make level carried, %d <= diff%d <= %d (%d):\n",
+// min,leading_eqs,max,guaranteed);
+// use_ugly_names++;
+// (*conj)->prefix_print(DebugFile);
+// use_ugly_names--;
+ if (!guaranteed) is_guaranteed = false;
+ bool generateLTClause = min < 0;
+ bool generateGTClause = max > 0;
+ bool retainEQClause = (leading_eqs <= (*conj)->possible_leading_0s &&
+ min <= 0 && max >= 0);
+ if (!(generateLTClause || generateGTClause || retainEQClause)) {
+ // conjunct is infeasible
+ if (pres_debug) {
+ fprintf(DebugFile, "Conjunct discovered to be infeasible during make_level_carried_to(%d):\n", level);
+ (*conj)->prefix_print(DebugFile);
+ }
+#if ! defined NDEBUG
+ Conjunct *cpy = (*conj)->copy_conj_same_relation();
+ assert(!simplify_conj(cpy, true, 32767, 0));
+#endif
+ }
+
+ if (generateLTClause) {
+ Conjunct *lt;
+ if (!generateGTClause && !retainEQClause)
+ lt = *conj;
+ else
+ lt = (*conj)->copy_conj_same_relation();
+ if (max >= 0) {
+ GEQ_Handle l = lt->add_GEQ(); // out<in ==> in-out-1>=0
+ l.update_coef_during_simplify(in, 1);
+ l.update_coef_during_simplify(out, -1);
+ l.update_const_during_simplify(-1);
+ }
+ lt->guaranteed_leading_0s
+ = lt->possible_leading_0s = leading_eqs-1;
+ lt->leading_dir = -1;
+ if (is_guaranteed) {
+ /*
+ fprintf(DebugFile,"Promising solutions to: %d <= diff%d <= %d (%d):\n",
+ min,leading_eqs,max,guaranteed);
+ use_ugly_names++;
+ lt->prefix_print(DebugFile);
+ use_ugly_names--;
+ */
+ lt->promise_that_ub_solutions_exist(tmp);
+ }
+ else if (0) {
+ fprintf(DebugFile,"Can't guaranteed solutions to:\n");
+ use_ugly_names++;
+ lt->prefix_print(DebugFile);
+ use_ugly_names--;
+ }
+ if (generateGTClause || retainEQClause)
+ newstuff->add_conjunct(lt);
+ }
+
+ if (generateGTClause) {
+ Conjunct *gt;
+ if (retainEQClause) gt = (*conj)->copy_conj_same_relation();
+ else gt = *conj;
+ if (min <= 0) {
+ GEQ_Handle g = gt->add_GEQ(); // out>in ==> out-in-1>=0
+ g.update_coef_during_simplify(in, -1);
+ g.update_coef_during_simplify(out, 1);
+ g.update_const_during_simplify(-1);
+ }
+ gt->guaranteed_leading_0s =
+ gt->possible_leading_0s = leading_eqs-1;
+ gt->leading_dir = 1;
+ if (is_guaranteed) {
+ /*
+ fprintf(DebugFile,"Promising solutions to: %d <= diff%d <= %d (%d):\n",
+ min,leading_eqs,max,guaranteed);
+ use_ugly_names++;
+ gt->prefix_print(DebugFile);
+ use_ugly_names--;
+ */
+ gt->promise_that_ub_solutions_exist(tmp);
+ }
+ else if (0) {
+ fprintf(DebugFile,"Can't guaranteed solutions to:\n");
+ use_ugly_names++;
+ gt->prefix_print(DebugFile);
+ use_ugly_names--;
+ }
+ if (retainEQClause) newstuff->add_conjunct(gt);
+ }
+
+ if (retainEQClause) {
+ assert(min <= 0 && 0 <= max);
+
+ if (min < 0 || max > 0) {
+ e = (*conj)->add_EQ(1);
+ e.update_coef_during_simplify(in, -1);
+ e.update_coef_during_simplify(out, 1);
+ }
+
+ assert((*conj)->guaranteed_leading_0s == -1
+ || leading_eqs > (*conj)->guaranteed_leading_0s);
+ assert((*conj)->possible_leading_0s == -1
+ || leading_eqs <= (*conj)->possible_leading_0s);
+
+ (*conj)->guaranteed_leading_0s = leading_eqs;
+ }
+ else break;
+ }
+
+ {
+ Set<Global_Var_ID> already_done;
+ int remapped = 0;
+
+ assert((*conj)->guaranteed_leading_0s == -1
+ || leading_eqs <= (*conj)->guaranteed_leading_0s);
+
+ for (Variable_ID_Iterator func(*body->global_decls()); func; func++) {
+ Global_Var_ID f = (*func)->get_global_var();
+ if (!already_done.contains(f) &&
+ body->has_local(f, Input_Tuple) &&
+ body->has_local(f, Output_Tuple) &&
+ f->arity() == leading_eqs) {
+ already_done.insert(f);
+
+ // add f(in) = f(out), project one away
+ e = (*conj)->add_EQ(1);
+ Variable_ID f_in =body->get_local(f,Input_Tuple);
+ Variable_ID f_out =body->get_local(f,Output_Tuple);
+
+ e.update_coef_during_simplify(f_in, -1);
+ e.update_coef_during_simplify(f_out, 1);
+
+ f_out->remap = f_in;
+ remapped = 1;
+ is_guaranteed = false;
+ }
+ }
+
+ if (remapped) {
+ (*conj)->remap();
+ (*conj)->combine_columns();
+ reset_remap_field(*body->global_decls());
+ remapped = 0;
+ }
+ }
+ }
+ if (is_guaranteed)
+ (*conj)->promise_that_ub_solutions_exist(tmp);
+ else if (0) {
+ fprintf(DebugFile,"Can't guaranteed solutions to:\n");
+ use_ugly_names++;
+ (*conj)->prefix_print(DebugFile);
+ use_ugly_names--;
+ }
+ }
+
+ skip_finalization_check--;
+ join_DNF(newstuff);
+ }
+
+#if ! defined NDEBUG
+ for (DNF_Iterator c(this); c; c++)
+ (*c)->assert_leading_info();
+#endif
+
+ simplify();
+}
+
+void DNF::remove_inexact_conj() {
+ bool found_inexact=false;
+
+ do {
+ bool first=true;
+ found_inexact=false;
+ DNF_Iterator c_prev;
+ for (DNF_Iterator c(this); c; c++) {
+ if (!(*c)->is_exact()) { // remove it from the list
+ found_inexact=true;
+ delete (*c);
+ if (first)
+ conjList.del_front();
+ else
+ conjList.del_after(c_prev);
+ break;
+ }
+ else {
+ first=false;
+ c_prev=c;
+ }
+ }
+ }
+ while (found_inexact);
+}
+
+
+int s_rdt_constrs;
+
+//
+// Simplify all conjuncts in a DNF
+//
+void DNF::simplify() {
+ for (DNF_Iterator pd(this); pd.live(); ) {
+ Conjunct *conj = pd.curr();
+ pd.next();
+ if(s_rdt_constrs >= 0 && !simplify_conj(conj, true, s_rdt_constrs, EQ_BLACK)) {
+ rm_conjunct(conj);
+ }
+ }
+}
+
+} // namespace
diff --git a/omegalib/omega/src/pres_form.cc b/omegalib/omega/src/pres_form.cc
new file mode 100644
index 0000000..82b710b
--- /dev/null
+++ b/omegalib/omega/src/pres_form.cc
@@ -0,0 +1,147 @@
+#include <omega/pres_form.h>
+#include <omega/pres_tree.h>
+#include <omega/pres_conj.h>
+#include <omega/Relation.h>
+#include <omega/omega_i.h>
+
+namespace omega {
+
+//
+// Children and parents.
+//
+void Formula::remove_child(Formula *kid) {
+ assert(&kid->parent() == this);
+ if (myChildren.front() == kid)
+ myChildren.del_front();
+ else {
+ List_Iterator<Formula*> j,k;
+ for(j=List_Iterator<Formula*>(myChildren); *j != kid && j; k=j, j++)
+ ;
+
+ if (k)
+ myChildren.del_after(k);
+ else
+ assert(0 && "Child to be removed not found in child list");
+ }
+}
+
+
+void Formula::add_child(Formula *kid) {
+ assert(can_add_child());
+ myChildren.append(kid);
+ kid->myParent = this;
+ kid->myRelation = this->relation();
+}
+
+void Formula::replace_child(Formula *child, Formula* new_child) {
+ assert(&child->parent() == this);
+ for(List_Iterator<Formula *> LI(myChildren); LI; LI++)
+ if(*LI == child) {
+ *LI = new_child;
+ new_child->myParent = this;
+ new_child->myRelation = this->relation();
+ break;
+ }
+}
+
+void Formula::set_parent(Formula *parent, Rel_Body *reln) {
+ myParent = parent;
+ myRelation = reln;
+ for(List_Iterator<Formula*> c(myChildren); c; c++)
+ (*c)->set_parent(this,reln);
+}
+
+//
+// Function that sets myRelation pointers in a tree.
+//
+void Formula::set_relation(Rel_Body *r) {
+ myRelation = r;
+ for(List_Iterator<Formula *> FI(myChildren); FI; FI++)
+ (*FI)->set_relation(r);
+}
+
+
+//
+// Function that descends to conjuncts to merge columns
+//
+void Formula::combine_columns() {
+ foreach(child,Formula *,myChildren,child->combine_columns());
+}
+
+
+void Formula::finalize() {
+ for(List_Iterator<Formula*> c(children()); c; c++)
+ (*c)->finalize();
+}
+
+bool Formula::can_add_child() {
+ return true;
+}
+
+
+
+Conjunct *Formula::really_conjunct() {
+ assert(0 && "really_conjunct() called on something that wasn't");
+ return NULL;
+}
+
+Formula::Formula(Formula *p, Rel_Body *r): myParent(p), myRelation(r) {
+}
+
+
+void Formula::verify_tree() { // should be const
+#if ! defined NDEBUG
+ Any_Iterator<Formula*> c = myChildren.any_iterator();
+ for (; c; c++) {
+ assert((*c)->myParent==this);
+ assert((*c)->myRelation==this->myRelation);
+ (*c)->verify_tree();
+ }
+#endif
+}
+
+Formula *Formula::copy(Formula *, Rel_Body *) {
+ assert(0);
+ return NULL;
+}
+
+Formula::~Formula() {
+ for(List_Iterator<Formula*> c(myChildren); c; c++) {
+ delete *c;
+ }
+ myChildren.clear();
+}
+
+void Formula::assert_not_finalized() {
+ if (!skip_finalization_check) {
+ assert(! relation()->is_finalized());
+ assert(! relation()->is_shared());
+ }
+}
+
+void Formula::reverse_leading_dir_info() {
+ for(List_Iterator<Formula*> c(myChildren); c; c++)
+ (*c)->reverse_leading_dir_info();
+}
+
+void Formula::invalidate_leading_info(int changed) {
+ for(List_Iterator<Formula*> c(myChildren); c; c++)
+ (*c)->invalidate_leading_info(changed);
+}
+
+void Formula::enforce_leading_info(int guaranteed, int possible, int dir) {
+ for(List_Iterator<Formula*> c(myChildren); c; c++)
+ (*c)->enforce_leading_info(guaranteed, possible, dir);
+}
+
+//
+// Push_exists functions.
+// Push exists takes responsibility for the Variable_ID's in the Tuple.
+// It should:
+// * Re-use them, or
+// * Delete them.
+void Formula::push_exists(Variable_ID_Tuple &) {
+ assert(0);
+}
+
+} // namespace
diff --git a/omegalib/omega/src/pres_gen.cc b/omegalib/omega/src/pres_gen.cc
new file mode 100644
index 0000000..0f05d40
--- /dev/null
+++ b/omegalib/omega/src/pres_gen.cc
@@ -0,0 +1,45 @@
+#include <omega/pres_gen.h>
+
+namespace omega {
+
+int skip_finalization_check=0;
+// int skip_set_checks=0;
+
+int pres_debug=0 ;
+FILE *DebugFile=stderr; // This is the default; it's best to set it yourself.
+
+negation_control pres_legal_negations = any_negation;
+
+//
+// I/O utility functions.
+//
+// void PresErrAssert(const char *t) {
+// fprintf(stdout, "\nERROR: %s\n", t);
+// if(pres_debug) {
+// fprintf(DebugFile, "\nERROR: %s\n", t);
+// }
+// exit(1);
+// }
+
+
+
+//
+// Needed for gprof
+//
+#if defined PROFILE_MALLOCS
+void* operator new(size_t n) {
+ void *result = malloc (n < 1 ? 1 : n);
+ if (result)
+ return result;
+ else {
+ write(2,"Virtual memory exceeded in new\n",32);
+ return 0;
+ }
+}
+
+void operator delete (void* f) {
+ if (f) free(f);
+}
+#endif
+
+} // namespace
diff --git a/omegalib/omega/src/pres_logic.cc b/omegalib/omega/src/pres_logic.cc
new file mode 100644
index 0000000..8ee90f1
--- /dev/null
+++ b/omegalib/omega/src/pres_logic.cc
@@ -0,0 +1,226 @@
+#include <omega/pres_logic.h>
+#include <omega/pres_conj.h>
+#include <omega/pres_quant.h>
+#include <omega/omega_i.h>
+
+namespace omega {
+
+GEQ_Handle F_And::add_GEQ(int preserves_level) {
+ assert_not_finalized();
+ if (pos_conj == NULL || pos_conj->problem->nGEQs >= maxGEQs) {
+ pos_conj = NULL;
+ for(List_Iterator<Formula*> c(children()); c; c++) {
+ if ((*c)->node_type()==Op_Conjunct &&
+ ((*c)->really_conjunct())->problem->nGEQs < maxGEQs) {
+ pos_conj = (*c)->really_conjunct();
+ break;
+ }
+ }
+ if(!pos_conj) pos_conj = add_conjunct();// FERD -- set level if preserved?
+ }
+ return pos_conj->add_GEQ(preserves_level);
+}
+
+
+EQ_Handle F_And::add_EQ(int preserves_level) {
+ assert_not_finalized();
+ if (pos_conj == NULL || pos_conj->problem->nEQs >= maxEQs) {
+ pos_conj = NULL;
+ for(List_Iterator<Formula*> c(children()); c; c++) {
+ if ((*c)->node_type()==Op_Conjunct &&
+ ((*c)->really_conjunct())->problem->nEQs < maxEQs) {
+ pos_conj = (*c)->really_conjunct();
+ break;
+ }
+ }
+ if(!pos_conj) pos_conj = add_conjunct();//FERD-set level info if preserved?
+ }
+ return pos_conj->add_EQ(preserves_level);
+}
+
+Stride_Handle F_And::add_stride(int step, int preserves_level) {
+ assert_not_finalized();
+ if (pos_conj == NULL || pos_conj->problem->nEQs >= maxEQs) {
+ pos_conj = NULL;
+ for(List_Iterator<Formula*> c(children()); c; c++) {
+ if ((*c)->node_type()==Op_Conjunct &&
+ ((*c)->really_conjunct())->problem->nEQs < maxEQs) {
+ pos_conj = (*c)->really_conjunct();
+ break;
+ }
+ }
+ if(!pos_conj) pos_conj = add_conjunct(); // FERD -set level if preserved?
+ }
+ return pos_conj->add_stride(step, preserves_level);
+}
+
+GEQ_Handle F_And::add_GEQ(const Constraint_Handle &constraint, int preserves_level) {
+ assert_not_finalized();
+ if (pos_conj == NULL || pos_conj->problem->nGEQs >= maxGEQs) {
+ pos_conj = NULL;
+ for(List_Iterator<Formula*> c(children()); c; c++) {
+ if ((*c)->node_type()==Op_Conjunct &&
+ ((*c)->really_conjunct())->problem->nGEQs < maxGEQs) {
+ pos_conj = (*c)->really_conjunct();
+ break;
+ }
+ }
+ if(!pos_conj) pos_conj = add_conjunct();// FERD -- set level if preserved?
+ }
+ return pos_conj->add_GEQ(constraint, preserves_level);
+}
+
+
+EQ_Handle F_And::add_EQ(const Constraint_Handle &constraint, int preserves_level) {
+ assert_not_finalized();
+ if (pos_conj == NULL || pos_conj->problem->nEQs >= maxEQs) {
+ pos_conj = NULL;
+ for(List_Iterator<Formula*> c(children()); c; c++) {
+ if ((*c)->node_type()==Op_Conjunct &&
+ ((*c)->really_conjunct())->problem->nEQs < maxEQs) {
+ pos_conj = (*c)->really_conjunct();
+ break;
+ }
+ }
+ if(!pos_conj) pos_conj = add_conjunct();//FERD-set level info if preserved?
+ }
+ return pos_conj->add_EQ(constraint,preserves_level);
+}
+
+
+void F_And::add_unknown() {
+ assert_not_finalized();
+ if (pos_conj == NULL) {
+ for (List_Iterator<Formula*> c(children()); c; c++) {
+ if ((*c)->node_type()==Op_Conjunct) {
+ pos_conj = (*c)->really_conjunct();
+ break;
+ }
+ }
+ if(!pos_conj) pos_conj = add_conjunct(); // FERD - set level if preseved?
+ }
+ pos_conj->make_inexact();
+}
+
+Conjunct *F_Or::find_available_conjunct() {
+ return 0;
+}
+
+Conjunct *F_Not::find_available_conjunct() {
+ return 0;
+}
+
+Conjunct *F_And::find_available_conjunct() {
+ for(List_Iterator<Formula*> child(children()); child; child++) {
+ Conjunct *c = (*child)->find_available_conjunct();
+ if (c) return c;
+ }
+ return 0;
+}
+
+
+void F_Not::finalize() {
+ assert(n_children() == 1);
+ Formula::finalize();
+}
+
+bool F_Not::can_add_child() {
+ return n_children() < 1;
+}
+
+F_And *F_And::and_with() {
+ assert_not_finalized();
+ assert(can_add_child());
+ return this;
+}
+
+F_And::F_And(Formula *p, Rel_Body *r): Formula(p,r), pos_conj(NULL) {
+}
+
+F_Or::F_Or(Formula *p, Rel_Body *r): Formula(p,r){
+}
+
+F_Not::F_Not(Formula *p, Rel_Body *r): Formula(p,r){
+}
+
+Formula *F_And::copy(Formula *parent, Rel_Body *reln) {
+ F_And *f = new F_And(parent, reln);
+ for(List_Iterator<Formula*> c(children()); c; c++)
+ f->children().append((*c)->copy(f,reln));
+ return f;
+}
+
+Formula *F_Or::copy(Formula *parent, Rel_Body *reln) {
+ F_Or *f = new F_Or(parent, reln);
+ for(List_Iterator<Formula*> c(children()); c; c++)
+ f->children().append((*c)->copy(f,reln));
+ return f;
+}
+
+Formula *F_Not::copy(Formula *parent, Rel_Body *reln) {
+ F_Not *f = new F_Not(parent, reln);
+ for(List_Iterator<Formula*> c(children()); c; c++)
+ f->children().append((*c)->copy(f,reln));
+ return f;
+}
+
+//
+// Create F_Exists nodes below this F_Or.
+// Copy list S to each of the created nodes.
+// Push_exists takes responsibility for reusing or deleting Var_ID's;
+// here we delete them. Must also empty out the Tuple when finished.
+void F_Or::push_exists(Variable_ID_Tuple &S) {
+ List<Formula*> mc;
+ mc.join(children());
+
+ while(!mc.empty()) {
+ Formula *f = mc.remove_front();
+ F_Exists *e = add_exists();
+
+ copy_var_decls(e->myLocals, S);
+ f->remap();
+ reset_remap_field(S);
+
+ e->add_child(f);
+ }
+ // Since these are not reused, they have to be deleted
+ for(Tuple_Iterator<Variable_ID> VI(S); VI; VI++) {
+ assert((*VI)->kind() == Exists_Var);
+ delete *VI;
+ }
+ S.clear();
+}
+
+void F_Exists::push_exists(Variable_ID_Tuple &S) {
+ myLocals.join(S);
+}
+
+F_Not *Formula::add_not() {
+ assert_not_finalized();
+ assert(can_add_child());
+ F_Not *f = new F_Not(this, myRelation);
+ myChildren.append(f);
+ return f;
+}
+
+F_And *Formula::add_and() {
+ assert_not_finalized();
+ assert(can_add_child());
+ F_And *f = new F_And(this, myRelation);
+ myChildren.append(f);
+ return f;
+}
+
+F_And *Formula::and_with() {
+ return add_and();
+}
+
+F_Or *Formula::add_or() {
+ assert_not_finalized();
+ assert(can_add_child());
+ F_Or *f = new F_Or(this, myRelation);
+ myChildren.append(f);
+ return f;
+}
+
+} // namespace
diff --git a/omegalib/omega/src/pres_print.cc b/omegalib/omega/src/pres_print.cc
new file mode 100644
index 0000000..4f2cd0d
--- /dev/null
+++ b/omegalib/omega/src/pres_print.cc
@@ -0,0 +1,908 @@
+#include <omega/pres_gen.h>
+#include <omega/pres_var.h>
+#include <omega/pres_tree.h>
+#include <omega/pres_conj.h>
+#include <omega/Relation.h>
+#include <basic/Bag.h>
+#include <omega/omega_i.h>
+#include <omega/omega_core/oc.h>
+
+namespace omega {
+
+////////////////////////////////////////
+// //
+// Print functions. //
+// //
+////////////////////////////////////////
+
+void Conjunct::reorder_for_print(bool reverseOrder, int first_pass_input, int first_pass_output, bool sort) {
+ Conjunct *C2 = copy_conj_same_relation();
+ Variable_ID_Tuple newpos(0),wcvars(0),gvars(0);
+
+// We reorder the original Variable_ID's into the newpos list; later, we
+// copy from their original column (using find_column) to the new one.
+ int n = mappedVars.size();
+ int i;
+ // there may be more inp/outp vars than maxVars; must do dynamically
+ // skip_set_checks++;
+ Tuple<bool> input_used(myRelation->n_inp());
+ Tuple<bool> output_used(myRelation->n_out());
+ for(i=1; i<=myRelation->n_inp();i++) input_used[i] = false;
+ for(i=1; i<=myRelation->n_out();i++) output_used[i] = false;
+ for(i=1; i<=n;i++) {
+ if (mappedVars[i]->kind() == Input_Var)
+ input_used[mappedVars[i]->get_position()] = true;
+ else if (mappedVars[i]->kind() == Output_Var)
+ output_used[mappedVars[i]->get_position()] = true;
+ else if(mappedVars[i]->kind() == Global_Var)
+ gvars.append(mappedVars[i]);
+ }
+
+
+ if(sort)
+ for(i=1; i<=gvars.size();i++)
+ for(int j=1; j <= gvars.size(); j++)
+ if(gvars[j]->get_global_var()->base_name()
+ < gvars[j+1]->get_global_var()->base_name()) {
+ Variable_ID t = gvars[j]; gvars[j] = gvars[j+1]; gvars[j+1] = t;
+ }
+
+ newpos.join(gvars);
+
+ if(!reverseOrder) {
+ for(i=1; i<=min(myRelation->n_inp(),first_pass_input);i++)
+ if (input_used[i]) newpos.append(input_vars[i]);
+ for(i=1; i<=min(myRelation->n_out(),first_pass_output);i++)
+ if (output_used[i]) newpos.append(output_vars[i]);
+ for(i=max(1,first_pass_input+1); i<=myRelation->n_inp();i++)
+ if (input_used[i]) newpos.append(input_vars[i]);
+ for(i=max(1,first_pass_output+1); i<=myRelation->n_out();i++)
+ if (output_used[i]) newpos.append(output_vars[i]);
+ }
+ else {
+ for(i=1; i<=min(myRelation->n_out(),first_pass_output);i++)
+ if (output_used[i]) newpos.append(output_vars[i]);
+ for(i=1; i<=min(myRelation->n_inp(),first_pass_input);i++)
+ if (input_used[i]) newpos.append(input_vars[i]);
+ for(i=max(1,first_pass_output+1); i<=myRelation->n_out();i++)
+ if (output_used[i]) newpos.append(output_vars[i]);
+ for(i=max(1,first_pass_input+1); i<=myRelation->n_inp();i++)
+ if (input_used[i]) newpos.append(input_vars[i]);
+ }
+
+
+ for(i=1; i<=n;i++)
+ if (mappedVars[i]->kind() == Wildcard_Var)
+ wcvars.append(mappedVars[i]);
+
+ if(sort)
+ for(i=1; i<=gvars.size();i++)
+ for(int j=1; j <= gvars.size(); j++)
+ if(gvars[j]->name() < gvars[j+1]->name()) {
+ Variable_ID t = gvars[j]; gvars[j] = gvars[j+1]; gvars[j+1] = t;
+ }
+
+ newpos.join(wcvars);
+
+ assert(problem->nVars == newpos.size()); // i.e. no other variable types
+
+ // Copy coef columns into new order. Constant column is unchanged.
+ for(int e=0; e<problem->nGEQs; e++) problem->GEQs[e].touched = 1;
+
+ for(i=1; i<=problem->nVars; i++) {
+ int col = find_column(newpos[i]); // Find column in original conj.
+ assert(col != 0);
+ copy_column(problem, i, // Copy it from orig. column in the copy.
+ C2->problem, col, 0, 0);
+ problem->var[i] = i;
+ }
+ for(i=1; i<=problem->nVars; i++)
+ problem->forwardingAddress[i] = i;
+
+ mappedVars = newpos;
+ delete C2;
+ // skip_set_checks--;
+}
+
+void Rel_Body::print_with_subs(FILE *output_file, bool printSym, bool newline) {
+ std::string s = this->print_with_subs_to_string(printSym, newline);
+ fprintf(output_file, "%s", s.c_str());
+}
+
+void Rel_Body::print_with_subs() {
+ this->print_with_subs(stdout, 0, 1);
+}
+
+static std::string tryToPrintVarToStringWithDiv(Conjunct *C, Variable_ID v) {
+ std::string s;
+ bool seen = false;
+// This assumes that there is one EQ involving v, that v cannot be
+// substituted and hence has a non-unit coefficient.
+ for(EQ_Iterator e(C); e; e++) {
+ if ((*e).get_coef(v) != 0) {
+ assert(!seen); // This asserts just one EQ with v
+ coef_t v_coef = (*e).get_coef(v);
+ int v_sign = v_coef > 0 ? 1 : -1;
+ v_coef *= v_sign;
+ int sign_adj = -v_sign;
+
+ s += "intDiv(";
+ bool first=true;
+ for(Constr_Vars_Iter i(*e,false); i; i++) {
+ if ((*i).var != v && (*i).coef != 0) {
+ coef_t this_coef = sign_adj*(*i).coef;
+ if(!first && this_coef > 0)
+ s+= "+";
+ if (this_coef == 1)
+ s += (*i).var->name();
+ else if (this_coef == -1) {
+ s += "-"; s += (*i).var->name();
+ }
+ else {
+ s += to_string(this_coef) + "*" + (*i).var->name();
+ }
+ first = false;
+ }
+ }
+ coef_t the_const = (*e).get_const()* sign_adj;
+ if (the_const > 0 && !first)
+ s+= "+";
+ if (the_const != 0)
+ s += to_string(the_const);
+ s += "," + to_string(v_coef) + ")";
+ seen = true;
+ }
+ }
+ return s;
+}
+
+
+// This function prints the output tuple of a relation with each one as a
+// function of the input variables.
+// This will fail or look goofy if the outputs are not affine functions of
+// the inputs.
+// BIG WARNING: Call this only from the codegen stuff, since it assumes things
+// about coefficients
+std::string Rel_Body::print_outputs_with_subs_to_string() {
+ // Rel_Body S(this),Q(this);
+ Rel_Body *S = this->clone();
+ Rel_Body *Q = this->clone();
+ S->setup_names();
+ Conjunct *C = S->single_conjunct();
+ Conjunct *D = Q->single_conjunct(); // ordered_elimination futzes with conj
+ std::string s; // = "[";
+ C->reorder_for_print();
+ C->ordered_elimination(S->global_decls()->length());
+ // Print output names with substitutions in them
+ for(int i=1; i<=S->n_out(); i++) {
+ std::string t;
+ int col = C->find_column(output_vars[i]);
+ if (col != 0)
+ t = C->print_sub_to_string(col);
+ if (col == 0 || t == output_vars[i]->name()) // no sub found
+ // Assume you can't get a unit coefficient on v, must use div
+ t = tryToPrintVarToStringWithDiv(D, output_vars[i]);
+ s += t;
+ if (i < S->n_out()) s += ",";
+ }
+ // s += "] ";
+ delete S;
+ delete Q;
+ return s;
+}
+
+std::string Rel_Body::print_outputs_with_subs_to_string(int i) {
+ // Rel_Body S(this),Q(this);
+ Rel_Body *S = this->clone();
+ Rel_Body *Q = this->clone();
+ S->setup_names();
+ Conjunct *C = S->single_conjunct();
+ Conjunct *D = Q->single_conjunct(); // ordered_elimination futzes with conj
+ std::string s;
+ C->reorder_for_print();
+ C->ordered_elimination(S->global_decls()->length());
+ // Print output names with substitutions in them
+ {
+ std::string t;
+ int col = C->find_column(output_vars[i]);
+ if (col != 0)
+ t = C->print_sub_to_string(col);
+ if (col == 0 || t == output_vars[i]->name()) // no sub found?
+ t = tryToPrintVarToStringWithDiv(D, output_vars[i]);
+ // should check for failure
+ s += t;
+ }
+ delete S;
+ delete Q;
+ return s;
+}
+
+std::string Rel_Body::print_with_subs_to_string(bool printSym, bool newline) {
+ std::string s="";
+
+ if (pres_debug) {
+ fprintf(DebugFile,"print_with_subs_to_string:\n");
+ prefix_print(DebugFile);
+ }
+
+ int anythingPrinted = 0;
+
+ if (this->is_null()) {
+ s = "NULL Rel_Body\n";
+ return s;
+ }
+
+ // Rel_Body R(this);
+ Rel_Body *R = this->clone();
+ bool firstRelation = true;
+
+ for(DNF_Iterator DI(R->query_DNF()); DI.live(); DI.next()) {
+ Rel_Body S(R, DI.curr());
+ Conjunct *C = S.single_conjunct();
+ if(!simplify_conj(C, true, 4, EQ_BLACK)) continue;
+
+ S.setup_names();
+
+ if(! firstRelation) {
+ s += " union";
+ if (newline) s += "\n ";
+ }
+ else
+ firstRelation = false;
+
+ anythingPrinted = 1;
+
+ C->reorder_for_print(false,C->max_ufs_arity_of_in(),
+ C->max_ufs_arity_of_out());
+ C->ordered_elimination(S.Symbolic.length()
+ +C->max_ufs_arity_of_in()
+ +C->max_ufs_arity_of_out());
+// assert(C->problem->variablesInitialized);
+
+ if (pres_debug) S.prefix_print(DebugFile);
+
+ /* Do actual printing of Conjunct C as a relation */
+ s += "{";
+
+ if (!Symbolic.empty()) {
+ if (printSym) s += "Sym=[";
+ for (Variable_ID_Iterator Sym_I = S.Symbolic; Sym_I;)
+ {
+ if (printSym)
+ s += (*Sym_I)->name();
+ Sym_I++;
+ if (printSym && Sym_I) s+= ",";
+ }
+ if (printSym) s += "] ";
+ }
+
+ int i, col;
+
+ if (S.number_input != 0) {
+ s += "[";
+ // Print input names with substitutions in them
+ for(i=1; i<=S.number_input; i++) {
+ col = C->find_column(input_vars[i]);
+ if (col != 0)
+ s += C->problem->print_sub_to_string(col);
+ else
+ s += input_vars[i]->name();
+ if (i<S.number_input) s += ",";
+ }
+ s += "]";
+ }
+
+ if (! S.is_set())
+ s += " -> ";
+
+ if (S.number_output != 0) {
+ s += "[";
+
+ // Print output names with substitutions in them
+ for(i=1; i<=S.number_output; i++) {
+ col = C->find_column(output_vars[i]);
+ if (col != 0)
+ s += C->problem->print_sub_to_string(col);
+ else
+ s += output_vars[i]->name();
+ if (i < S.number_output) s += ",";
+ }
+ s += "] ";
+ }
+
+ if (C->is_unknown()) {
+ if (S.number_input != 0 || S.number_output != 0)
+ s += ":";
+ s += " UNKNOWN";
+ }
+ else {
+ // Empty conj means TRUE, so don't print colon
+ if (C->problem->nEQs != 0 || C->problem->nGEQs != 0) {
+ C->problem->clearSubs();
+ if (S.number_input != 0 || S.number_output != 0)
+ s += ":";
+ s += " ";
+ s += C->print_to_string(false);
+ }
+ else {
+ if (S.number_input == 0 && S.number_output == 0)
+ s += " TRUE ";
+ }
+ }
+
+ s += "}";
+ }
+
+ if (!anythingPrinted) {
+ R->setup_names();
+ s = "{";
+ s += R->print_variables_to_string(printSym);
+ if (R->number_input != 0 || R->number_output != 0)
+ s += " :";
+ s += " FALSE }";
+ if (newline) s += "\n";
+
+ delete R;
+ return s;
+ }
+
+ if (newline) s += "\n";
+
+ delete R;
+ return s;
+}
+
+
+void print_var_addrs(std::string &s, Variable_ID v) {
+ if(pres_debug>=2) {
+ char ss[20];
+ sprintf(ss, "(%p,%p)", v, v->remap);
+ s += ss;
+ }
+}
+
+std::string Rel_Body::print_variables_to_string(bool printSym) {
+ std::string s="";
+
+ if (! Symbolic.empty()) {
+ if (printSym) s += " Sym=[";
+ for (Variable_ID_Iterator Sym_I(Symbolic); Sym_I; ) {
+ if (printSym) s += (*Sym_I)->name();
+ print_var_addrs(s, *Sym_I);
+ Sym_I++;
+ if (printSym && Sym_I) s += ",";
+ }
+ if (printSym) s += "] ";
+ }
+ int i;
+
+ if (number_input) {
+ s += "[";
+ for (i=1;i<=number_input;i++) {
+ s += input_vars[i]->name();
+ print_var_addrs(s, input_vars[i]);
+ if(i < number_input) s += ",";
+ }
+ s += "] ";
+ }
+
+ if (number_output) {
+ s += "-> [";
+ for (i=1;i<=number_output;i++) {
+ s += output_vars[i]->name();
+ print_var_addrs(s, output_vars[i]);
+ if(i < number_output) s += ",";
+ }
+ s += "] ";
+ }
+
+ return s;
+}
+
+
+int F_Declaration::priority() {
+ return 3;
+}
+
+int Formula::priority () {
+ return 0;
+}
+
+int F_Or::priority() {
+ return 0;
+}
+
+int F_And::priority() {
+ return 1;
+}
+
+int Conjunct::priority() {
+ return 1;
+}
+
+int F_Not::priority() {
+ return 2;
+}
+
+
+//
+// print() functions
+//
+void Formula::print(FILE *output_file) {
+ if(myChildren.empty()) {
+ if(node_type()==Op_Relation || node_type()==Op_Or)
+ fprintf(output_file, "FALSE");
+ else if(node_type()==Op_And)
+ fprintf(output_file, "TRUE");
+ else {
+ assert(0);
+ }
+ }
+
+ for(List_Iterator<Formula*> c(myChildren); c;) {
+ if (node_type() == Op_Exists || node_type() == Op_Forall
+ || (*c)->priority() < priority())
+ fprintf(output_file, "( ");
+ (*c)->print(output_file);
+ if (node_type() == Op_Exists || node_type() == Op_Forall
+ || (*c)->priority() < priority())
+ fprintf(output_file, " )");
+ c++;
+ if(c.live())
+ print_separator(output_file);
+ }
+}
+
+std::string Rel_Body::print_formula_to_string() {
+ std::string s;
+ setup_names();
+ for(DNF_Iterator DI(query_DNF()); DI.live();) {
+
+ s += (*DI)->print_to_string(1);
+ DI.next();
+ if (DI.live()) s += " && ";
+ if (pres_debug) fprintf(DebugFile,"Partial print to string: %s\n",
+ s.c_str());
+ }
+ return s;
+}
+
+void Rel_Body::print(FILE *output_file, bool printSym) {
+ if (this->is_null()) {
+ fprintf(output_file, "NULL Rel_Body\n");
+ return;
+ }
+
+ setup_names();
+
+ fprintf(output_file, "{");
+
+ std::string s = print_variables_to_string(printSym);
+ fprintf(output_file, "%s", s.c_str());
+
+ fprintf(output_file, ": ");
+
+ if(simplified_DNF==NULL) {
+ Formula::print(output_file);
+ }
+ else {
+ assert(children().empty());
+ simplified_DNF->print(output_file);
+ }
+
+ fprintf(output_file, " }\n");
+}
+
+void Rel_Body::print() {
+ this->print(stdout);
+}
+
+void F_Not::print(FILE *output_file) {
+ fprintf(output_file, " not ");
+ Formula::print(output_file);
+}
+
+void F_And::print_separator(FILE *output_file) {
+ fprintf(output_file, " and ");
+}
+
+void Conjunct::print(FILE *output_file) {
+ std::string s = print_to_string(true);
+ fprintf(output_file, "%s", s.c_str());
+}
+
+std::string Conjunct::print_to_string(int true_printed) {
+ std::string s="";
+
+ int num = myLocals.size();
+ if(num) {
+ s += "exists ( ";
+ int i;
+ for (i = 1; i <= num; i++) {
+ Variable_ID v = myLocals[i];
+ s += v->char_name();
+ if(i < num) s += ",";
+ }
+ if (true_printed || !(is_true())) s += " : ";
+ }
+
+ if(is_true()) {
+ s += true_printed ? "TRUE" : "";
+ }
+ else {
+ if (is_unknown())
+ s += "UNKNOWN";
+ else {
+ s += problem->prettyPrintProblemToString();
+ if (!exact)
+ s += " && UNKNOWN";
+ }
+ }
+
+
+ if (num) s += ")";
+ return s;
+}
+
+void F_Or::print_separator(FILE *output_file) {
+ fprintf(output_file, " or ");
+}
+
+void F_Declaration::print(FILE *output_file) {
+ std::string s="";
+ for(Variable_ID_Iterator VI(myLocals); VI; ) {
+ s += (*VI)->name();
+ VI++;
+ if(VI) s += ",";
+ }
+ fprintf(output_file, "( %s : ", s.c_str());
+ Formula::print(output_file);
+ fprintf(output_file, ")");
+}
+
+void F_Forall::print(FILE *output_file) {
+ fprintf(output_file, "forall ");
+ F_Declaration::print(output_file);
+}
+
+void F_Exists::print(FILE *output_file) {
+ fprintf(output_file, "exists ");
+ F_Declaration::print(output_file);
+}
+
+void Formula::print_separator(FILE *) {
+ assert(0); // should never be called, it's only for derived classes
+}
+
+//
+// Setup names in formula.
+//
+
+typedef Set<Global_Var_ID> g_set;
+void Rel_Body::setup_names() {
+ int i;
+
+
+ if (use_ugly_names) return;
+
+ if (pres_debug>=2)
+ fprintf(DebugFile,"Setting up names for 0x%p\n", this);
+
+ for(i=1; i<=number_input; i++) {
+ input_vars[i]->base_name = In_Names[i];
+ }
+ for(i=1; i<=number_output; i++) {
+ output_vars[i]->base_name = Out_Names[i];
+ }
+
+ g_set gbls;
+
+ wildCardInstanceNumber = 0;
+
+ for(i=1; i<= Symbolic.size(); i++) {
+ gbls.insert(Symbolic[i]->get_global_var());
+ }
+
+ foreach(g,Global_Var_ID,gbls,
+ g->instance = g->base_name()++);
+
+ for(i=1; i<=number_input; i++) {
+ if (!input_vars[i]->base_name.null())
+ input_vars[i]->instance = input_vars[i]->base_name++;
+ }
+ for(i=1; i<=number_output; i++) {
+ if (!output_vars[i]->base_name.null())
+ output_vars[i]->instance = output_vars[i]->base_name++;
+ }
+
+ if (simplified_DNF != NULL) // It is simplified
+ simplified_DNF->setup_names();
+ else // not simplified
+ Formula::setup_names();
+
+ for(i=1; i<=number_output; i++) {
+ if (!output_vars[i]->base_name.null())
+ output_vars[i]->base_name--;
+ }
+ for(i=1; i<=number_input; i++) {
+ if (!input_vars[i]->base_name.null())
+ input_vars[i]->base_name--;
+ }
+ foreach(g,Global_Var_ID,gbls, g->base_name()--);
+}
+
+void Formula::setup_names() {
+ if (pres_debug>=2)
+ fprintf(DebugFile,"Setting up names for formula 0x%p\n", this);
+
+ for(List_Iterator<Formula*> c(myChildren); c; c++)
+ (*c)->setup_names();
+}
+
+void DNF::setup_names() {
+ if (pres_debug>=2)
+ fprintf(DebugFile,"Setting up names for DNF 0x%p\n", this);
+
+ for(DNF_Iterator DI(this); DI.live(); DI.next())
+ DI.curr()->setup_names();
+}
+
+
+void F_Declaration::setup_names() {
+ if (pres_debug>=2)
+ fprintf(DebugFile,"Setting up names for Declaration 0x%p\n", this);
+
+ // Allow re-use of wc names in other scopes
+ int savedWildCardInstanceNumber = wildCardInstanceNumber;
+
+ for(Tuple_Iterator<Variable_ID> VI(myLocals); VI; VI++) {
+ Variable_ID v = *VI;
+ if (!v->base_name.null()) v->instance = v->base_name++;
+ else v->instance = wildCardInstanceNumber++;
+ }
+
+ for(List_Iterator<Formula*> c(children()); c; c++)
+ (*c)->setup_names();
+
+ for(Tuple_Iterator<Variable_ID> VI2(myLocals); VI2; VI2++) {
+ Variable_ID v = *VI2;
+ if (!v->base_name.null()) v->base_name--;
+ }
+ wildCardInstanceNumber = savedWildCardInstanceNumber;
+}
+
+
+//
+// Prefix_print functions.
+// Print Formula Tree, used in debugging.
+//
+static int level = 0;
+
+void Formula::prefix_print(FILE *output_file, int debug) {
+ for(List_Iterator<Formula*> c(children()); c; c++)
+ (*c)->prefix_print(output_file, debug);
+ level--;
+}
+
+
+void Rel_Body::prefix_print() {
+ this->prefix_print(stdout, 1);
+}
+
+void Rel_Body::prefix_print(FILE *output_file, int debug) {
+ int old_use_ugly_names = use_ugly_names;
+ use_ugly_names = 0;
+
+ setup_names();
+
+ level = 0;
+ if(pres_debug>=2) fprintf(output_file, "(@%p)", this);
+ fprintf(output_file, is_set() ? "SET: " : "RELATION: ");
+ std::string s = print_variables_to_string(true);
+ fprintf(output_file, "%s\n", s.c_str());
+
+ if(simplified_DNF==NULL) {
+ Formula::prefix_print(output_file, debug);
+ } else {
+ assert(children().empty());
+ simplified_DNF->prefix_print(output_file, debug, true);
+ }
+ fprintf(output_file, "\n");
+ use_ugly_names = old_use_ugly_names;
+}
+
+
+void F_Forall::prefix_print(FILE *output_file, int debug) {
+ Formula::print_head(output_file);
+ fprintf(output_file, "forall [");
+ F_Declaration::prefix_print(output_file, debug);
+ for (Variable_ID_Iterator VI(myLocals); VI; VI++)
+ assert((*VI)->kind() == Forall_Var);
+
+}
+
+void F_Exists::prefix_print(FILE *output_file, int debug) {
+ Formula::print_head(output_file);
+ if(pres_debug>=2) fprintf(output_file, "(@%p)", this);
+ fprintf(output_file, "exists [");
+ F_Declaration::prefix_print(output_file, debug);
+ for (Variable_ID_Iterator VI(myLocals); VI; VI++)
+ assert((*VI)->kind() == Exists_Var);
+}
+
+void F_Declaration::prefix_print(FILE *output_file, int debug) {
+ std::string s = "";
+ for (Variable_ID_Iterator VI(myLocals); VI; ) {
+ s += (*VI)->name();
+ print_var_addrs(s, *VI);
+ VI++;
+ if(VI) s += ",";
+ }
+ s += "]\n";
+ fprintf(output_file, "%s", s.c_str());
+ Formula::prefix_print(output_file, debug);
+}
+
+void F_Or::prefix_print(FILE *output_file, int debug) {
+ Formula::print_head(output_file);
+ fprintf(output_file, "or\n");
+ Formula::prefix_print(output_file, debug);
+}
+
+void F_And::prefix_print(FILE *output_file, int debug) {
+ Formula::print_head(output_file);
+ fprintf(output_file, "and\n");
+ Formula::prefix_print(output_file, debug);
+}
+
+void F_Not::prefix_print(FILE *output_file, int debug) {
+ Formula::print_head(output_file);
+ fprintf(output_file, "not\n");
+ Formula::prefix_print(output_file, debug);
+}
+
+void Conjunct::prefix_print(FILE *output_file, int debug) {
+ static char dir_glyphs[] = { '-', '?', '+' };
+
+ if (debug) {
+ Formula::print_head(output_file);
+ if(pres_debug>=2) fprintf(output_file, "(@%p)", this);
+ fprintf(output_file, "%s CONJUNCT, ", exact ? "EXACT" : "INEXACT");
+ if (simplified) fprintf(output_file, "simplified, ");
+ if (verified) fprintf(output_file, "verified, ");
+ if (possible_leading_0s != -1 && guaranteed_leading_0s != -1)
+ assert (guaranteed_leading_0s <= possible_leading_0s);
+ if (guaranteed_leading_0s != -1 && guaranteed_leading_0s == possible_leading_0s)
+ fprintf(output_file,"# leading 0's = %d,", possible_leading_0s);
+ else if (possible_leading_0s != -1 || guaranteed_leading_0s != -1) {
+ if (guaranteed_leading_0s != -1)
+ fprintf(output_file,"%d <= ",guaranteed_leading_0s);
+ fprintf(output_file,"#O's");
+ if (possible_leading_0s != -1)
+ fprintf(output_file," <= %d",possible_leading_0s);
+ fprintf(output_file,", ");
+ }
+ if (dir_glyphs[leading_dir+1] != '?')
+ fprintf(output_file," first = %c, ", dir_glyphs[leading_dir+1]);
+ fprintf(output_file,"myLocals=[");
+ std::string s="";
+ for (Variable_ID_Iterator VI(myLocals); VI; ) {
+ assert( (*VI)->kind() == Wildcard_Var);
+ s += (*VI)->name();
+ print_var_addrs(s, *VI);
+ VI++;
+ if(VI) s += ",";
+ }
+ s += "] mappedVars=[";
+ for(Variable_ID_Iterator MVI(mappedVars); MVI; ) {
+ s += (*MVI)->name();
+ print_var_addrs(s, *MVI);
+ MVI++;
+ if(MVI) s += ",";
+ }
+ fprintf(output_file, "%s]\n", s.c_str());
+ }
+ else
+ level++;
+
+ setOutputFile(output_file);
+ setPrintLevel(level+1);
+ problem->printProblem(debug);
+ setPrintLevel(0);
+ Formula::prefix_print(output_file, debug);
+}
+
+void Formula::print_head(FILE *output_file) {
+ level++;
+ int i;
+ for(i=0; i<level; i++) {
+ fprintf(output_file, ". ");
+ }
+}
+
+//
+// Print DNF.
+//
+void DNF::print(FILE *out_file) {
+ DNF_Iterator p(this);
+ if (!p.live())
+ fprintf(out_file, "FALSE");
+ else
+ for(; p.live(); ) {
+ p.curr()->print(out_file);
+ p.next();
+ if(p.live())
+ fprintf(out_file, " or ");
+ }
+}
+
+void DNF::prefix_print(FILE *out_file, int debug, bool parent_names_setup) {
+ wildCardInstanceNumber = 0;
+ Variable_ID_Tuple all_vars;
+ if(!use_ugly_names && !parent_names_setup) {
+ // We need to manually set up all of the input,output, and symbolic
+ // variables, since during simplification, a dnf's conjuncts may not
+ // be listed as part of a relation, or perhaps as part of different
+ // relations (?) (grr).
+ for(DNF_Iterator p0(this); p0.live(); p0.next()) {
+ for(Variable_Iterator vi((*p0)->mappedVars); vi; vi++)
+ if((*vi)->kind() != Wildcard_Var && all_vars.index(*vi) == 0)
+ all_vars.append(*vi);
+ (*p0)->setup_names();
+ }
+ foreach(v,Variable_ID,all_vars,
+ if (!v->base_name.null()) v->instance = v->base_name++;
+ else v->instance = wildCardInstanceNumber++;
+ );
+ }
+
+ int i = 1;
+ level = 0;
+ for(DNF_Iterator p(this); p.live(); p.next(), i++) {
+ fprintf(out_file, "#%d ", i);
+ if(*p == NULL)
+ fprintf(out_file, "(NULL)\n");
+ else
+ (*p)->prefix_print(out_file, debug);
+ }
+
+ foreach(v,Variable_ID,all_vars,if (!v->base_name.null()) v->base_name--);
+
+ fprintf(out_file, "\n");
+}
+
+std::string Constraint_Handle::print_to_string() const {
+ assert(0);
+ return "FOO";
+}
+
+std::string EQ_Handle::print_to_string() const {
+ relation()->setup_names();
+ std::string s = c->print_EQ_to_string(e);
+ return s;
+}
+
+std::string GEQ_Handle::print_to_string() const {
+ relation()->setup_names();
+ std::string s = c->print_GEQ_to_string(e);
+ return s;
+}
+
+std::string Constraint_Handle::print_term_to_string() const {
+ assert(0);
+ return "FOO";
+}
+
+std::string EQ_Handle::print_term_to_string() const {
+ relation()->setup_names();
+ std::string s = c->print_EQ_term_to_string(e);
+ return s;
+}
+
+std::string GEQ_Handle::print_term_to_string() const {
+ relation()->setup_names();
+ std::string s = c->print_GEQ_term_to_string(e);
+ return s;
+}
+
+}
diff --git a/omegalib/omega/src/pres_quant.cc b/omegalib/omega/src/pres_quant.cc
new file mode 100644
index 0000000..5483bad
--- /dev/null
+++ b/omegalib/omega/src/pres_quant.cc
@@ -0,0 +1,95 @@
+#include <omega/pres_quant.h>
+#include <omega/omega_i.h>
+
+namespace omega {
+
+F_Forall::F_Forall(Formula *p, Rel_Body *r): F_Declaration(p,r) {
+}
+
+F_Exists::F_Exists(Formula *p, Rel_Body *r): F_Declaration(p,r) {
+}
+
+F_Exists::F_Exists(Formula *p, Rel_Body *r, Variable_ID_Tuple &S): F_Declaration(p,r,S) {
+}
+
+
+Formula *F_Forall::copy(Formula *parent, Rel_Body *reln) {
+ F_Forall *f = new F_Forall(parent, reln);
+ copy_var_decls(f->myLocals, myLocals);
+ for(List_Iterator<Formula*> c(children()); c; c++)
+ f->children().append((*c)->copy(f,reln));
+ reset_remap_field(myLocals);
+ return f;
+}
+
+Formula *F_Exists::copy(Formula *parent, Rel_Body *reln) {
+ F_Exists *f = new F_Exists(parent, reln);
+ copy_var_decls(f->myLocals, myLocals);
+ for(List_Iterator<Formula*> c(children()); c; c++)
+ f->children().append((*c)->copy(f,reln));
+ reset_remap_field(myLocals);
+ return f;
+}
+
+Variable_ID F_Forall::declare(Const_String s) {
+ return do_declare(s, Forall_Var);
+}
+
+Variable_ID F_Forall::declare() {
+ return do_declare(Const_String(), Forall_Var);
+}
+
+Variable_ID F_Forall::declare(Variable_ID v) {
+ return do_declare(v->base_name, Forall_Var);
+}
+
+
+Variable_ID F_Exists::declare(Const_String s) {
+ return do_declare(s, Exists_Var);
+}
+
+Variable_ID F_Exists::declare() {
+ return do_declare(Const_String(), Exists_Var);
+}
+
+Variable_ID F_Exists::declare(Variable_ID v) {
+ return do_declare(v->base_name, Exists_Var);
+}
+
+Conjunct *F_Forall::find_available_conjunct() {
+ return 0;
+}
+
+Conjunct *F_Exists::find_available_conjunct() {
+ assert(children().length() == 1 || children().length() == 0);
+ if (children().length() == 0)
+ return 0;
+ else
+ return children().front()->find_available_conjunct();
+}
+
+F_Exists *Formula::add_exists() {
+ assert_not_finalized();
+ assert(can_add_child());
+ F_Exists *f = new F_Exists(this, myRelation);
+ myChildren.append(f);
+ return f;
+}
+
+F_Exists *Formula::add_exists(Variable_ID_Tuple &S) {
+ assert_not_finalized();
+ assert(can_add_child());
+ F_Exists *f = new F_Exists(this, myRelation, S);
+ myChildren.append(f);
+ return f;
+}
+
+F_Forall *Formula::add_forall() {
+ assert_not_finalized();
+ assert(can_add_child());
+ F_Forall *f = new F_Forall(this, myRelation);
+ myChildren.append(f);
+ return f;
+}
+
+} // namespace
diff --git a/omegalib/omega/src/pres_rear.cc b/omegalib/omega/src/pres_rear.cc
new file mode 100644
index 0000000..508959d
--- /dev/null
+++ b/omegalib/omega/src/pres_rear.cc
@@ -0,0 +1,131 @@
+#include <omega/pres_tree.h>
+#include <omega/pres_conj.h>
+#include <omega/Relation.h>
+#include <omega/omega_i.h>
+
+namespace omega {
+
+/////////////////////////
+// //
+// Rearrange functions //
+// //
+/////////////////////////
+
+//
+// Rules:
+// ~ (f1 | f2 | ... | fn) = ~f1 & ~f2 & ... & fn
+// ~ ~ f = f
+// Forall v: f = ~ (Exists v: ~ f)
+// Exists v: (f1 | ... | fn) = (Exists v: f1) | ... | (Exists v: fn)
+//
+
+void Rel_Body::rearrange() {
+ assert(children().length()==1);
+
+ skip_finalization_check++;
+ formula()->rearrange();
+ skip_finalization_check--;
+
+ if(pres_debug) {
+ fprintf(DebugFile, "\n=== Rearranged TREE ===\n");
+ prefix_print(DebugFile);
+ }
+}
+
+void Formula::rearrange() {
+ // copy list of children, as they may be removed as we work
+ List<Formula*> kiddies = myChildren;
+
+ for(List_Iterator<Formula*> c(kiddies); c; c++)
+ (*c)->rearrange();
+}
+
+//
+// Push nots down the tree until quantifier or conjunct, rearrange kids
+//
+void F_Not::rearrange() {
+ Formula *child = children().front();
+ Formula *new_child, *f;
+
+ switch(child->node_type()) {
+ case Op_Or:
+ parent().remove_child(this);
+ new_child = parent().add_and();
+ while(!child->children().empty()) {
+ f = child->children().remove_front();
+ F_Not *new_not = new_child->add_not();
+ new_not->add_child(f);
+ }
+ delete this;
+ break;
+//case Op_And:
+// parent().remove_child(this);
+// new_child = parent().add_or();
+// while(!child->myChildren.empty()) {
+// f = child->myChildren.remove_front();
+// F_Not *new_not = new_child->add_not();
+// new_not->add_child(f);
+// }
+// delete this;
+// break;
+ case Op_Not:
+ parent().remove_child(this);
+ f = child->children().remove_front();
+ parent().add_child(f);
+ delete this;
+ f->rearrange();
+ return;
+ default:
+ new_child = child;
+ break;
+ }
+
+ new_child->rearrange();
+}
+
+//
+// Convert a universal quantifier to "not exists not".
+// Forall v: f = ~ (Exists v: ~ f)
+//
+void F_Forall::rearrange() {
+ Formula &p = parent();
+ p.remove_child(this);
+
+ F_Not *topnot = p.add_not();
+ F_Exists *exist = topnot->add_exists();
+ for (Variable_ID_Iterator VI(myLocals); VI; VI++)
+ (*VI)->set_kind(Exists_Var);
+ exist->myLocals.join(myLocals);
+
+ F_Not *botnot = exist->add_not();
+ Formula *f = children().remove_front();
+ botnot->add_child(f);
+
+ delete this;
+
+ botnot->rearrange();
+}
+
+//
+// Exists v: (f1 | ... | fn) = (Exists v: f1) | ... | (Exists v: fn)
+//
+void F_Exists::rearrange() {
+ Formula* child = children().front();
+ switch(child->node_type()) {
+ case Op_Or:
+ case Op_Conjunct:
+ case Op_Exists:
+ child->push_exists(myLocals);
+ parent().remove_child(this);
+ parent().add_child(child);
+ children().remove_front();
+ delete this;
+ break;
+ default:
+ break;
+ }
+
+ child->rearrange();
+}
+
+} // namespace
diff --git a/omegalib/omega/src/pres_subs.cc b/omegalib/omega/src/pres_subs.cc
new file mode 100644
index 0000000..9854b09
--- /dev/null
+++ b/omegalib/omega/src/pres_subs.cc
@@ -0,0 +1,131 @@
+#include <omega/pres_subs.h>
+
+namespace omega {
+
+Substitutions::Substitutions(Relation &input_R, Conjunct *input_c) {
+ int i;
+ r = new Relation(input_R,input_c);
+ c = r->single_conjunct();
+ c->reorder_for_print();
+ c->ordered_elimination(r->global_decls()->length());
+ int num_subs = c->problem->nSUBs;
+ subs = new eqn[num_subs];
+ for(i = 0; i < num_subs; i++)
+ subs[i] = SUBs[i];
+ subbed_vars.reallocate(num_subs);
+ /* Go through and categorize variables as:
+ 1) substituted, 2) not substituted, 3) wildcard
+ Safevars number of variables were not able to be substituted.
+ nVars number of total variables, including wildcards.
+ nSUBs is the number of substitutions.
+ nSUBs + nVars == the number of variables that went in.
+ Then reset var and forwardingAddress arrays in the problem,
+ so that they will correctly refer to the reconstructed
+ mappedVars. */
+ Variable_ID_Tuple unsubbed_vars(c->problem->safeVars);
+ for(i = 1; i <= c->mappedVars.size(); i++)
+ if(c->mappedVars[i]->kind() != Wildcard_Var) {
+ int addr = c->problem->forwardingAddress[i];
+ assert(addr == c->find_column(c->mappedVars[i]) && addr != 0);
+ if(addr < 0) {
+ assert(-addr <= subbed_vars.size());
+ subbed_vars[-addr] = c->mappedVars[i];
+ }
+ else {
+ assert(addr <= unsubbed_vars.size());
+ unsubbed_vars[addr] = c->mappedVars[i];
+ }
+ }
+ else {
+ // Here we don't redeclare wildcards, just re-use them.
+ unsubbed_vars.append(c->mappedVars[i]);
+ }
+ assert(unsubbed_vars.size() + subbed_vars.size() == c->mappedVars.size());
+ c->mappedVars = unsubbed_vars; /* These are the variables that remain */
+
+ for(int col = 1; col <= c->problem->nVars; col++) {
+ c->problem->var[col] = col;
+ c->problem->forwardingAddress[col] = col;
+ }
+}
+
+Substitutions::~Substitutions() {
+ delete [] subs;
+ delete r;
+}
+
+bool Substitutions::substituted(Variable_ID v) {
+ return (subbed_vars.index(v) > 0);
+}
+
+Sub_Handle Substitutions::get_sub(Variable_ID v) {
+ assert(substituted(v) && "No substitution for variable");
+ return Sub_Handle(this,subbed_vars.index(v)-1,v);
+}
+
+bool Substitutions::sub_involves(Variable_ID v, Var_Kind kind) {
+ assert(substituted(v));
+ for(Constr_Vars_Iter i = get_sub(v); i; i++)
+ if ((*i).var->kind() == kind)
+ return true;
+ return false;
+}
+
+
+//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+
+int Sub_Iterator::live() const {
+ return current <= last;
+}
+
+void Sub_Iterator::operator++() { this->operator++(0); }
+
+void Sub_Iterator::operator++(int) {
+ current++;
+}
+
+Sub_Handle Sub_Iterator::operator*() {
+ assert(s && current <= last && "Sub_Iterator::operator*: bad call");
+ return Sub_Handle(s,current,s->subbed_vars[current+1]);
+}
+
+Sub_Handle Sub_Iterator::operator*() const {
+ assert(s && current <= last && "Sub_Iterator::operator*: bad call");
+ return Sub_Handle(s,current,s->subbed_vars[current+1]);
+}
+
+
+//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+
+
+Sub_Handle::Sub_Handle(Substitutions *_s, int _e, Variable_ID _v) :
+Constraint_Handle(_s->c,&(_s->subs),_e), v(_v) {}
+
+std::string Sub_Handle::print_to_string() const {
+ relation()->setup_names();
+ return v->name() + " = " + this->print_term_to_string();
+}
+
+std::string Sub_Handle::print_term_to_string() const {
+ /* The horrible truth is that print_term_to_string is a member
+ function of Conjunct, (and then Problem below it) but uses
+ nothing from there but the names, so you can pass it a pointer to
+ an equation that isn't even part of the conjunct. */
+ relation()->setup_names();
+ return c->print_term_to_string(&((*eqns)[e]));
+}
+
+
+/*
+ String Sub_Handle::print_to_string() const {
+ return c->problem->print_EQ_to_string(&((*eqns)[e]));
+ }
+
+ String Sub_Handle::print_term_to_string() const {
+ return c->print_term_to_string(&(*eqns[e]));
+ }
+*/
+
+} // namespace
diff --git a/omegalib/omega/src/pres_var.cc b/omegalib/omega/src/pres_var.cc
new file mode 100644
index 0000000..0ec406f
--- /dev/null
+++ b/omegalib/omega/src/pres_var.cc
@@ -0,0 +1,459 @@
+#include <omega/pres_var.h>
+#include <omega/pres_tree.h>
+#include <omega/pres_conj.h>
+#include <omega/omega_i.h>
+
+namespace omega {
+
+int wildCardInstanceNumber;
+
+const int Global_Input_Output_Tuple::initial_allocation = 10;
+
+// Declare named Variable
+Var_Decl::Var_Decl(Const_String name, Var_Kind vkind, int pos):
+ base_name(name),
+ instance(999),
+ remap(this),
+ var_kind(vkind),
+ position(pos),
+ global_var(NULL),
+ of((Argument_Tuple) 0) {
+ assert(((vkind==Input_Var || vkind==Output_Var) && pos>0) || pos==0);
+}
+
+// Declare unnamed variable
+Var_Decl::Var_Decl(Var_Kind vkind, int pos):
+ instance(999),
+ remap(this),
+ var_kind(vkind),
+ position(pos),
+ global_var(NULL),
+ of((Argument_Tuple) 0) {
+ assert(((vkind==Input_Var || vkind==Output_Var) && pos>0) || pos==0);
+}
+
+// Copy variable declaration
+Var_Decl::Var_Decl(Variable_ID v):
+ base_name(v->base_name),
+ instance(v->instance),
+ remap(this),
+ var_kind(v->var_kind),
+ position(v->position),
+ global_var(v->global_var),
+ of(v->of) {
+}
+
+Var_Decl::Var_Decl(Const_String name, Global_Var_ID v):
+ base_name(name),
+ instance(999),
+ remap(this),
+ var_kind(Global_Var),
+ position(0),
+ global_var(v),
+ of((Argument_Tuple) 0) {
+ assert(v->arity() == 0);
+}
+
+Var_Decl::Var_Decl(Const_String name, Global_Var_ID v, Argument_Tuple function_of):
+ base_name(name),
+ instance(999),
+ remap(this),
+ var_kind(Global_Var),
+ position(0),
+ global_var(v),
+ of(function_of) {
+}
+
+int Var_Decl::get_position() {
+ assert((var_kind == Input_Var || var_kind == Output_Var) && "Var_Decl::get_position: bad var_kind");
+ return(position);
+}
+
+Global_Var_ID Var_Decl::get_global_var() {
+ assert(var_kind == Global_Var && "Var_Decl::get_global_var: bad var_kind");
+ return(global_var);
+}
+
+Argument_Tuple Var_Decl::function_of() {
+ assert(var_kind == Global_Var);
+ return(of);
+}
+
+
+Omega_Var *Global_Var_Decl::really_omega_var() {
+ assert(0);
+ return(NULL);
+}
+
+Coef_Var_Decl *Global_Var_Decl::really_coef_var() {
+ assert(0);
+ return(NULL);
+}
+
+//
+// Variable name.
+//
+
+const int N_greek_letters = 19;
+
+char greek_letters[19][10] = {
+ "alpha" , "beta" , "gamma" , "delta" , "tau" , "sigma" , "chi" ,
+ "omega" , "pi" , "ni" , "Alpha" , "Beta" , "Gamma" , "Delta" ,
+ "Tau" , "Sigma" , "Chi" , "Omega" , "Pi"
+};
+
+const int numBuffers = 50;
+const int bufferSize = 90;
+char nameBuffers[numBuffers][bufferSize];
+int nextBuffer = 0;
+
+int use_ugly_names = 0;
+
+const char *Var_Decl::char_name() {
+ char *s = nameBuffers[nextBuffer++];
+ char *start = s;
+ if (nextBuffer >= numBuffers) nextBuffer = 0;
+ int primes;
+
+ if (use_ugly_names)
+ primes = 0;
+ else
+ primes = instance;
+
+ switch(var_kind) {
+ case Input_Var:
+ if (!use_ugly_names && !base_name.null())
+ sprintf(s,"%s",(const char *)base_name);
+ else {
+ primes = 0;
+ sprintf(s,"In_%d",position);
+ }
+ break;
+ case Output_Var:
+ if (!use_ugly_names && !base_name.null())
+ sprintf(s,"%s",(const char *)base_name);
+ else {
+ primes = 0;
+ sprintf(s,"Out_%d",position);
+ }
+ break;
+ case Global_Var:
+ assert(!base_name.null());
+ if (use_ugly_names)
+ sprintf(s,"%s@%p",(const char *)base_name, this);
+ else {
+ sprintf(s,"%s",(const char *)base_name);
+ primes = get_global_var()->instance;
+ }
+ break;
+ default:
+ if (use_ugly_names) {
+ if (!base_name.null())
+ sprintf(s,"%s@%p",(const char *)base_name, this);
+ else
+ sprintf(s,"?@%p", this);
+ }
+ else if (!base_name.null()) sprintf(s,"%s",(const char *)base_name);
+ else {
+ assert(instance < 999);
+ sprintf(s,"%s",
+ greek_letters[instance % N_greek_letters]);
+ primes = instance/N_greek_letters;
+ }
+ break;
+ }
+
+ while (*s) s++;
+ int i;
+ assert(primes < 999);
+ for(i=1; i<= primes; i++) *s++ = '\'';
+ *s = '\0';
+ if (var_kind == Global_Var) {
+ int a = get_global_var()->arity();
+ if (a) {
+ if (use_ugly_names) {
+ static const char *arg_names[4] = { "???", "In", "Out", "In == Out" };
+ sprintf(s, "(%s[1#%d])", arg_names[function_of()], a);
+ }
+ else {
+ int f_of = function_of();
+ assert(f_of == Input_Tuple || f_of == Output_Tuple);
+ *s++ = '(';
+ for(i = 1;i<=a;i++) {
+ if (f_of == Input_Tuple)
+ sprintf(s,"%s",(const char *)input_vars[i]->char_name());
+ else
+ sprintf(s,"%s",(const char *)output_vars[i]->char_name());
+ while (*s) s++;
+ if (i<a) *s++ = ',';
+ }
+ *s++ = ')';
+ *s++ = 0;
+ }
+ }
+ }
+
+ assert(s < start+bufferSize);
+ return start;
+}
+
+std::string Var_Decl::name() {
+ return char_name();
+}
+
+//
+// Copy variable declarations.
+//
+void copy_var_decls(Variable_ID_Tuple &new_vl, Variable_ID_Tuple &vl) {
+ if (new_vl.size() < vl.size()) {
+ new_vl.reallocate(vl.size());
+ }
+ for(int p=1; p<=vl.size(); p++) {
+ Variable_ID v = vl[p];
+ if(v->kind()==Global_Var) {
+ new_vl[p] = v;
+ v->remap = v;
+ }
+ else {
+ new_vl[p] = new Var_Decl(vl[p]);
+ v->remap = new_vl[p];
+ }
+ }
+}
+
+//
+// Name a variable.
+//
+void Var_Decl::name_variable(char *newname) {
+ base_name = newname;
+}
+
+
+static Const_String coef_var_name(int i, int v) {
+ char s[100];
+ sprintf(s, "c_%d_%d", i, v);
+ return Const_String(s);
+}
+
+
+//
+// Global variables stuff.
+//
+Global_Var_Decl::Global_Var_Decl(Const_String baseName):
+ loc_rep1(baseName, this, Input_Tuple),
+ loc_rep2(baseName, this, Output_Tuple) {
+}
+
+Global_Kind Global_Var_Decl::kind() const {
+ assert(0);
+ return Coef_Var;
+}
+
+Coef_Var_Decl::Coef_Var_Decl(int id, int var):
+ Global_Var_Decl(coef_var_name(id, var)) {
+ i = id;
+ v = var;
+}
+
+Coef_Var_Decl *Coef_Var_Decl::really_coef_var() {
+ return this;
+}
+
+int Coef_Var_Decl::stmt() const {
+ return i;
+}
+
+int Coef_Var_Decl::var() const {
+ return v;
+}
+
+Global_Kind Coef_Var_Decl::kind() const {
+ return Coef_Var;
+}
+
+Free_Var_Decl::Free_Var_Decl(Const_String name):
+ Global_Var_Decl(name), _arity(0) {
+}
+
+Free_Var_Decl::Free_Var_Decl(Const_String name, int arity):
+ Global_Var_Decl(name), _arity(arity) {
+}
+
+int Free_Var_Decl::arity() const {
+ return _arity;
+}
+
+Global_Kind Free_Var_Decl::kind() const {
+ return Free_Var;
+}
+
+
+//
+// Delete variable from variable list. Does not preserve order
+//
+bool rm_variable(Variable_ID_Tuple &vl, Variable_ID v) {
+ int n = vl.size();
+ int i;
+ for(i = 1; i<n; i++) if (vl[i] == v) break;
+ if (i>n) return 0;
+ vl[i] = vl[n];
+ vl.delete_last();
+ return 1;
+}
+
+
+//
+// Destroy variable declarations.
+//
+void free_var_decls(Variable_ID_Tuple &c) {
+ for(Variable_ID_Iterator p = c; p; p++) {
+ Variable_ID v = *p;
+ if(v->kind()!=Global_Var) {
+ delete v;
+ }
+ }
+}
+
+
+Variable_ID input_var(int nth) {
+ assert(1 <= nth && nth <= input_vars.size());
+ return input_vars[nth];
+}
+
+Variable_ID output_var(int nth) {
+ assert(1<= nth && nth <= output_vars.size());
+ return output_vars[nth];
+}
+
+Variable_ID set_var(int nth) {
+ assert(1 <= nth && set_vars.size());
+ return input_vars[nth];
+}
+
+
+//
+// Remap mappedVars in all conjuncts of formula.
+// Uses the remap field of the Var_Decl.
+//
+void Formula::remap() {
+ for(List_Iterator<Formula*> c(children()); c; c++)
+ (*c)->remap();
+}
+
+void Conjunct::remap() {
+ for(Variable_Iterator VI(mappedVars); VI; VI++) {
+ Variable_ID v = *VI;
+ *VI = v->remap;
+ }
+ cols_ordered = false;
+}
+
+// Function to reset the remap field of a Variable_ID
+void reset_remap_field(Variable_ID v) {
+ v->remap = v;
+}
+
+// Function to reset the remap fields of a Variable_ID_Seq
+void reset_remap_field(Sequence<Variable_ID> &T) {
+ for(Any_Iterator<Variable_ID> VI(T.any_iterator()); VI; VI++) {
+ Variable_ID v = *VI;
+ v->remap = v;
+ }
+}
+
+// Function to reset the remap fields of a Variable_ID_Tuple,
+// more efficiently
+void reset_remap_field(Variable_ID_Tuple &T) {
+ for(Variable_Iterator VI(T); VI; VI++) {
+ Variable_ID v = *VI;
+ v->remap = v;
+ }
+}
+
+void reset_remap_field(Sequence<Variable_ID> &T, int var_no) {
+ int i=1;
+ for(Any_Iterator<Variable_ID> VI(T.any_iterator()); i <= var_no && VI; VI++) {
+ Variable_ID v = *VI;
+ v->remap = v;
+ i++;
+ }
+}
+
+void reset_remap_field(Variable_ID_Tuple &T, int var_no) {
+ int i=1;
+ for(Variable_Iterator VI(T); i <= var_no && VI; VI++) {
+ Variable_ID v = *VI;
+ v->remap = v;
+ i++;
+ }
+}
+
+
+// Global input and output variable tuples.
+// These Tuples must be initialized as more in/out vars are needed.
+//Variable_ID_Tuple input_vars(0);
+//Variable_ID_Tuple output_vars(0);
+//Variable_ID_Tuple& set_vars = input_vars;
+Global_Input_Output_Tuple input_vars(Input_Var);
+Global_Input_Output_Tuple output_vars(Output_Var);
+Global_Input_Output_Tuple &set_vars = input_vars;
+
+////////////////////////////////////////
+// //
+// Variable and Declaration functions //
+// //
+////////////////////////////////////////
+
+//
+// Constructors and properties.
+//
+
+
+// Allocate ten variables initially. Most applications won't require more.
+Global_Input_Output_Tuple::Global_Input_Output_Tuple(Var_Kind in_my_kind, int init):
+ my_kind(in_my_kind) {
+ for (int i=1; i<=(init == -1? initial_allocation: max(0,init)); i++)
+ this->append(new Var_Decl(Const_String(), my_kind, i));
+}
+
+Global_Input_Output_Tuple::~Global_Input_Output_Tuple() {
+ for (int i=1; i<=size(); i++)
+ delete data[i-1];
+}
+
+Variable_ID & Global_Input_Output_Tuple::operator[](int index) {
+ assert(index > 0);
+ while(size() < index)
+ this->append(new Var_Decl(Const_String(), my_kind, size()+1));
+ return data[index-1];
+}
+
+const Variable_ID & Global_Input_Output_Tuple::operator[](int index) const {
+ assert(index > 0);
+ Global_Input_Output_Tuple *unconst_this = (Global_Input_Output_Tuple *) this;
+ while(size() < index)
+ unconst_this->append(new Var_Decl(Const_String(), my_kind, size()+1));
+ return data[index-1];
+}
+
+Variable_ID Var_Decl::UF_owner() {
+ Variable_ID v = this;
+ while (v->remap != v) v = v->remap;
+ return v;
+}
+
+void Var_Decl::UF_union(Variable_ID b) {
+ Variable_ID a = this;
+ while (a->remap != a) {
+ Variable_ID tmp = a->remap;
+ a->remap = tmp->remap;
+ a = tmp;
+ }
+ while (b->remap != a) {
+ Variable_ID tmp = b->remap;
+ b->remap = a;
+ b = tmp;
+ }
+}
+
+} // namespace
diff --git a/omegalib/omega/src/reach.cc b/omegalib/omega/src/reach.cc
new file mode 100644
index 0000000..bde785c
--- /dev/null
+++ b/omegalib/omega/src/reach.cc
@@ -0,0 +1,211 @@
+#include <omega.h>
+#include <omega/Relations.h>
+#include <basic/Dynamic_Array.h>
+#include <omega/reach.h>
+
+namespace omega {
+
+typedef Dynamic_Array1<Relation> Rel_Array1;
+typedef Dynamic_Array2<Relation> Rel_Array2;
+
+// This is from parallelism.c, modified
+
+static void closure_rel(Rel_Array2 &trans, int i, int k, int j) {
+ Relation tik;
+
+ if (trans[k][k].is_upper_bound_satisfiable()) {
+ Relation tkk = TransitiveClosure(copy(trans[k][k]));
+ tkk.simplify(2,4);
+ tik = Composition(tkk, copy(trans[i][k]));
+ tik.simplify(2,4);
+ tik = Union(copy(trans[i][k]), tik);
+ tik.simplify(2,4);
+ }
+ else {
+ tik = trans[i][k];
+ }
+ Relation fresh;
+ Relation tkj = trans[k][j];
+ fresh = Composition(tkj, tik);
+ fresh.simplify(2,4);
+ trans[i][j] = Union(trans[i][j], fresh);
+ trans[i][j].simplify(2,4);
+
+#if 0
+ fprintf(DebugFile, "%d -> %d -> %d\n", i, k, j);
+ trans[i][j].print_with_subs(DebugFile);
+#endif
+}
+
+
+static void close_rels(Rel_Array2 &trans,int n_nodes) {
+ for (int k=1; k<=n_nodes; k++)
+ for (int i=1; i<=n_nodes; i++)
+ if (trans[i][k].is_upper_bound_satisfiable())
+ for (int j=1; j<=n_nodes; j++)
+ if (trans[k][j].is_upper_bound_satisfiable())
+ closure_rel(trans, i, k, j);
+}
+
+
+void dump_rels(Rel_Array2 &a, reachable_information *reachable_info) {
+ int i,j;
+ int n_nodes = reachable_info->node_names.size();
+ for(i = 1; i <= n_nodes; i++)
+ for(j = 1; j <= n_nodes; j++) {
+ fprintf(stderr,"t[%s][%s] = ",
+ (reachable_info->node_names[i]).c_str(),
+ (reachable_info->node_names[j]).c_str());
+ a[i][j].print_with_subs(stderr);
+ }
+}
+
+
+void dump_sets(Rel_Array1 &a, reachable_information *reachable_info) {
+ int i;
+ int n_nodes = reachable_info->node_names.size();
+ for(i = 1; i <= n_nodes; i++) {
+ fprintf(stderr,"r[%s] = ", (reachable_info->node_names[i]).c_str());
+ a[i].print_with_subs(stderr);
+ }
+}
+
+
+
+Rel_Array1 *Reachable_Nodes(reachable_information *reachable_info) {
+ Tuple<std::string> &node_names = reachable_info->node_names;
+ Tuple<int> &arity = reachable_info->node_arity;
+ Rel_Array2 &transitions = reachable_info->transitions;
+ Rel_Array1 &start_nodes = reachable_info->start_nodes;
+
+ int n_nodes = node_names.size(),i,j;
+
+#define DUMP_INITIAL 1
+#define DUMP_CLOSED 1
+
+ if(DUMP_INITIAL && relation_debug){
+ fprintf(stderr,"Initially:\n");
+ dump_rels(transitions, reachable_info);
+ }
+
+ close_rels(transitions,n_nodes);
+
+ if(DUMP_CLOSED && relation_debug) {
+ fprintf(stderr,"Closed:\n");
+ dump_rels(transitions, reachable_info);
+ }
+
+ Rel_Array1 *finalp =
+ new Rel_Array1("node");
+ Rel_Array1 &final = *finalp;
+ final.resize(n_nodes+1);
+ for (i=1; i<=n_nodes; i++)
+ final[i] = Relation::False(arity[i]);
+
+ for(i = 1; i <= n_nodes; i++)
+ for(j = 1; j <= n_nodes; j++)
+ if(start_nodes[i].is_upper_bound_satisfiable())
+ final[j] = Union(final[j],
+ Composition(copy(transitions[i][j]),
+ copy(start_nodes[i])));
+ return finalp;
+}
+
+static void compute_initially_reachable(Rel_Array1 &r,
+ Rel_Array1 &start_nodes,
+ Rel_Array2 &,
+ Rel_Array2 &closed,
+ Rel_Array1 &end_nodes,
+ int n_nodes, Tuple<int> &arity){
+ for(int n = 1; n <= n_nodes; n++)
+ r[n] = Relation::False(arity[n]);
+
+ for(int i = 1; i <= n_nodes; i++)
+ for(int j = 1; j <= n_nodes; j++)
+ r[i] = Union(r[i],
+ Range(Restrict_Domain(
+ Restrict_Range(copy(closed[j][i]),
+ copy(end_nodes[i])),
+ copy(start_nodes[j]))));
+}
+
+
+static bool iterate(Rel_Array1 &r, Rel_Array2 &, Rel_Array2 &closed,
+ Rel_Array1 &, int n_nodes) {
+ bool changed;
+
+ changed = false;
+ for(int j = 1; j <= n_nodes; j++) {
+ for(int i = 1; i <= n_nodes; i++) {
+ /* look for additional steps from interesting states */
+ Relation new_rj = Range(Restrict_Domain(copy(closed[i][j]),
+ copy(r[i])));
+ if(!Must_Be_Subset(copy(new_rj),copy(r[j]))) {
+ r[j] = Union(r[j],new_rj);
+ r[j].simplify(2,2);
+ changed = true;
+ }
+ }
+ }
+ return changed;
+}
+
+
+
+
+Rel_Array1 *I_Reachable_Nodes(reachable_information *reachable_info) {
+ bool changed;
+
+ Tuple<std::string> &node_names = reachable_info->node_names;
+ int n_nodes = node_names.size();
+ Tuple<int> &arity = reachable_info->node_arity;
+ Rel_Array2 &transitions = reachable_info->transitions;
+ Rel_Array1 &start_nodes = reachable_info->start_nodes;
+ Rel_Array2 closed("node number","node number");
+ closed.resize(n_nodes+1,n_nodes+1); // abuse of dynamic arrays
+ Rel_Array1 *rp = new Rel_Array1("node number");
+ Rel_Array1 &r = *rp;
+ r.resize(n_nodes+1); // abuse of dynamic arrays
+
+ int i,j;
+
+ Rel_Array1 end_nodes("Hi!");
+ end_nodes.resize(n_nodes+1); // for future use
+ for(int n = 1; n <= n_nodes; n++) end_nodes[n] = Relation::True(arity[n]);
+
+ for(j = 1; j <= n_nodes; j++) {
+ closed[j][j] = TransitiveClosure(copy(transitions[j][j]));
+ for(i = 1; i <= n_nodes; i++)
+ if (i != j)
+ closed[i][j] = transitions[i][j];
+ }
+
+ compute_initially_reachable(r,start_nodes,transitions,closed,end_nodes,
+ n_nodes,arity);
+
+#define DUMP_INITIAL 1
+#define DUMP_CLOSED 1
+
+ if(DUMP_INITIAL && relation_debug > 1) {
+ fprintf(stderr,"Closed:\n");
+ dump_rels(closed, reachable_info);
+ }
+ if(DUMP_INITIAL && relation_debug) {
+ fprintf(stderr,"start nodes:\n");
+ dump_sets(start_nodes, reachable_info);
+ fprintf(stderr,"Initially reachable:\n");
+ dump_sets(r, reachable_info);
+ }
+
+ changed = true;
+ int iterations = 0, max_iterations = 1000;
+ while(changed && iterations < max_iterations) {
+ changed = iterate(r,transitions,closed,start_nodes,n_nodes);
+ iterations++;
+ }
+ if(relation_debug)
+ fprintf(stdout,"[Iterations to convergence: %d]\n",iterations);
+ return rp;
+}
+
+} // namespace