From 210f77d2c32f14d2e99577fd3c9842bb19d47e50 Mon Sep 17 00:00:00 2001
From: Tuowen Zhao <ztuowen@gmail.com>
Date: Mon, 19 Sep 2016 21:14:58 +0000
Subject: Moved most modules into lib

---
 CMakeLists.txt                                     |   82 +-
 LICENSE.omega                                      |  705 +++++
 chill/CMakeLists.txt                               |   74 -
 chill/include/chill_error.hh                       |   24 -
 chill/include/chill_run_util.hh                    |   29 -
 chill/include/chilldebug.h                         |   15 -
 chill/include/chillmodule.hh                       |   17 -
 chill/include/dep.hh                               |   94 -
 chill/include/graph.hh                             |  328 ---
 chill/include/ir_code.hh                           |  289 --
 chill/include/ir_rose.hh                           |  267 --
 chill/include/ir_rose_utils.hh                     |   19 -
 chill/include/irtools.hh                           |   48 -
 chill/include/loop.hh                              |  200 --
 chill/include/omegatools.hh                        |   93 -
 chill/src/chill_run.cc                             |   89 -
 chill/src/chill_run_util.cc                        |  120 -
 chill/src/chillmodule.cc                           |  795 ------
 chill/src/dep.cc                                   |  567 ----
 chill/src/ir_rose.cc                               | 1756 ------------
 chill/src/ir_rose_utils.cc                         |   67 -
 chill/src/irtools.cc                               |  279 --
 chill/src/loop.cc                                  | 1859 -------------
 chill/src/loop_basic.cc                            | 1538 -----------
 chill/src/loop_datacopy.cc                         | 2166 ---------------
 chill/src/loop_extra.cc                            |  224 --
 chill/src/loop_tile.cc                             |  630 -----
 chill/src/loop_unroll.cc                           | 1166 --------
 chill/src/omegatools.cc                            | 1185 --------
 chill/src/parse_expr.ll                            |   24 -
 chill/src/parse_expr.yy                            |   85 -
 include/chill_error.hh                             |   24 +
 include/chill_run_util.hh                          |   29 +
 include/chilldebug.h                               |   15 +
 include/chillmodule.hh                             |   17 +
 include/dep.hh                                     |   94 +
 include/graph.hh                                   |  328 +++
 include/ir_code.hh                                 |  289 ++
 include/ir_rose.hh                                 |  267 ++
 include/ir_rose_utils.hh                           |   19 +
 include/irtools.hh                                 |   48 +
 include/loop.hh                                    |  200 ++
 include/omegatools.hh                              |   93 +
 lib/codegen/CMakeLists.txt                         |   24 +
 lib/codegen/include/code_gen/CG.h                  |  118 +
 lib/codegen/include/code_gen/CG_outputBuilder.h    |  161 ++
 lib/codegen/include/code_gen/CG_outputRepr.h       |   33 +
 lib/codegen/include/code_gen/CG_stringBuilder.h    |   44 +
 lib/codegen/include/code_gen/CG_stringRepr.h       |   43 +
 lib/codegen/include/code_gen/CG_utils.h            |   45 +
 lib/codegen/include/code_gen/code_gen.h            |   47 +
 lib/codegen/include/code_gen/codegen.h             |   48 +
 lib/codegen/include/code_gen/codegen_error.h       |   15 +
 lib/codegen/include/code_gen/output_repr.h         |   46 +
 lib/codegen/src/CG.cc                              | 1163 ++++++++
 lib/codegen/src/CG_stringBuilder.cc                |  487 ++++
 lib/codegen/src/CG_utils.cc                        | 1735 ++++++++++++
 lib/codegen/src/codegen.cc                         |  378 +++
 lib/omega/CMakeLists.txt                           |   71 +
 lib/omega/doc/interface.pdf                        |  Bin 0 -> 276190 bytes
 lib/omega/include/basic/Bag.h                      |  405 +++
 lib/omega/include/basic/BoolSet.h                  |  641 +++++
 lib/omega/include/basic/Collection.h               |   43 +
 lib/omega/include/basic/Collections.h              |   12 +
 lib/omega/include/basic/ConstString.h              |   57 +
 lib/omega/include/basic/DynamicArray.h             |  318 +++
 lib/omega/include/basic/Iterator.h                 |  129 +
 lib/omega/include/basic/Link.h                     |   97 +
 lib/omega/include/basic/List.h                     |  233 ++
 lib/omega/include/basic/Map.h                      |  127 +
 lib/omega/include/basic/Section.h                  |  138 +
 lib/omega/include/basic/SimpleList.h               |  194 ++
 lib/omega/include/basic/Tuple.h                    |  336 +++
 lib/omega/include/basic/omega_error.h              |   14 +
 lib/omega/include/basic/util.h                     |  263 ++
 lib/omega/include/omega.h                          |   71 +
 lib/omega/include/omega/RelBody.h                  |  165 ++
 lib/omega/include/omega/Rel_map.h                  |  161 ++
 lib/omega/include/omega/Relation.h                 |  299 ++
 lib/omega/include/omega/Relations.h                |   88 +
 lib/omega/include/omega/closure.h                  |   31 +
 lib/omega/include/omega/evac.h                     |   15 +
 lib/omega/include/omega/farkas.h                   |   19 +
 lib/omega/include/omega/hull.h                     |   89 +
 lib/omega/include/omega/omega_core/debugging.h     |   30 +
 lib/omega/include/omega/omega_core/oc.h            |  350 +++
 lib/omega/include/omega/omega_core/oc_i.h          |   79 +
 lib/omega/include/omega/omega_i.h                  |   30 +
 lib/omega/include/omega/pres_cmpr.h                |   49 +
 lib/omega/include/omega/pres_cnstr.h               |  192 ++
 lib/omega/include/omega/pres_conj.h                |  299 ++
 lib/omega/include/omega/pres_decl.h                |   55 +
 lib/omega/include/omega/pres_dnf.h                 |   87 +
 lib/omega/include/omega/pres_form.h                |  112 +
 lib/omega/include/omega/pres_gen.h                 |  192 ++
 lib/omega/include/omega/pres_logic.h               |   90 +
 lib/omega/include/omega/pres_quant.h               |   63 +
 lib/omega/include/omega/pres_subs.h                |   88 +
 lib/omega/include/omega/pres_tree.h                |   15 +
 lib/omega/include/omega/pres_var.h                 |  230 ++
 lib/omega/include/omega/reach.h                    |   23 +
 lib/omega/src/RelBody.cc                           |  906 ++++++
 lib/omega/src/RelVar.cc                            |   71 +
 lib/omega/src/Relation.cc                          |  279 ++
 lib/omega/src/Relations.cc                         | 2882 ++++++++++++++++++++
 lib/omega/src/basic/ConstString.cc                 |  134 +
 lib/omega/src/basic/Link.cc                        |   41 +
 lib/omega/src/closure.cc                           | 2100 ++++++++++++++
 lib/omega/src/evac.cc                              |  339 +++
 lib/omega/src/farkas.cc                            |  480 ++++
 lib/omega/src/hull_legacy.cc                       | 1484 ++++++++++
 lib/omega/src/hull_simple.cc                       | 1013 +++++++
 lib/omega/src/omega_core/oc.cc                     |  754 +++++
 lib/omega/src/omega_core/oc_eq.cc                  |  653 +++++
 lib/omega/src/omega_core/oc_exp_kill.cc            |  297 ++
 lib/omega/src/omega_core/oc_global.cc              |   45 +
 lib/omega/src/omega_core/oc_print.cc               |  686 +++++
 lib/omega/src/omega_core/oc_problems.cc            |  198 ++
 lib/omega/src/omega_core/oc_query.cc               |  478 ++++
 lib/omega/src/omega_core/oc_quick_kill.cc          |  775 ++++++
 lib/omega/src/omega_core/oc_simple.cc              | 1373 ++++++++++
 lib/omega/src/omega_core/oc_solve.cc               | 1378 ++++++++++
 lib/omega/src/omega_core/oc_util.cc                |  327 +++
 lib/omega/src/pres_beaut.cc                        |  235 ++
 lib/omega/src/pres_cnstr.cc                        |  450 +++
 lib/omega/src/pres_col.cc                          |  104 +
 lib/omega/src/pres_conj.cc                         | 1460 ++++++++++
 lib/omega/src/pres_decl.cc                         |   71 +
 lib/omega/src/pres_dnf.cc                          | 1416 ++++++++++
 lib/omega/src/pres_form.cc                         |  147 +
 lib/omega/src/pres_gen.cc                          |   45 +
 lib/omega/src/pres_logic.cc                        |  226 ++
 lib/omega/src/pres_print.cc                        |  908 ++++++
 lib/omega/src/pres_quant.cc                        |   95 +
 lib/omega/src/pres_rear.cc                         |  131 +
 lib/omega/src/pres_subs.cc                         |  131 +
 lib/omega/src/pres_var.cc                          |  459 ++++
 lib/omega/src/reach.cc                             |  211 ++
 lib/rosecg/CMakeLists.txt                          |   18 +
 lib/rosecg/include/CG_roseBuilder.h                |  108 +
 lib/rosecg/include/CG_roseRepr.h                   |   46 +
 lib/rosecg/include/rose_attributes.h               |   91 +
 lib/rosecg/src/CG_roseBuilder.cc                   | 1093 ++++++++
 lib/rosecg/src/CG_roseRepr.cc                      |  125 +
 lib/rosecg/src/rose_attributes.cc                  |  183 ++
 omegalib/CMakeLists.txt                            |   14 -
 omegalib/LICENSE                                   |  705 -----
 omegalib/codegen/CMakeLists.txt                    |   30 -
 omegalib/codegen/include/code_gen/CG.h             |  118 -
 .../codegen/include/code_gen/CG_outputBuilder.h    |  161 --
 omegalib/codegen/include/code_gen/CG_outputRepr.h  |   33 -
 omegalib/codegen/include/code_gen/CG_roseBuilder.h |  108 -
 omegalib/codegen/include/code_gen/CG_roseRepr.h    |   46 -
 .../codegen/include/code_gen/CG_stringBuilder.h    |   44 -
 omegalib/codegen/include/code_gen/CG_stringRepr.h  |   43 -
 omegalib/codegen/include/code_gen/CG_utils.h       |   45 -
 omegalib/codegen/include/code_gen/code_gen.h       |   47 -
 omegalib/codegen/include/code_gen/codegen.h        |   48 -
 omegalib/codegen/include/code_gen/codegen_error.h  |   15 -
 omegalib/codegen/include/code_gen/output_repr.h    |   46 -
 .../codegen/include/code_gen/rose_attributes.h     |   91 -
 omegalib/codegen/src/CG.cc                         | 1163 --------
 omegalib/codegen/src/CG_roseBuilder.cc             | 1093 --------
 omegalib/codegen/src/CG_roseRepr.cc                |  125 -
 omegalib/codegen/src/CG_stringBuilder.cc           |  487 ----
 omegalib/codegen/src/CG_utils.cc                   | 1735 ------------
 omegalib/codegen/src/codegen.cc                    |  378 ---
 omegalib/codegen/src/rose_attributes.cc            |  183 --
 omegalib/doc/calculator.pdf                        |  Bin 108062 -> 0 bytes
 omegalib/doc/interface.pdf                         |  Bin 276190 -> 0 bytes
 omegalib/omega/CMakeLists.txt                      |   69 -
 omegalib/omega/doc/interface.pdf                   |  Bin 276190 -> 0 bytes
 omegalib/omega/include/basic/Bag.h                 |  405 ---
 omegalib/omega/include/basic/BoolSet.h             |  641 -----
 omegalib/omega/include/basic/Collection.h          |   43 -
 omegalib/omega/include/basic/Collections.h         |   12 -
 omegalib/omega/include/basic/ConstString.h         |   57 -
 omegalib/omega/include/basic/DynamicArray.h        |  318 ---
 omegalib/omega/include/basic/Iterator.h            |  129 -
 omegalib/omega/include/basic/Link.h                |   97 -
 omegalib/omega/include/basic/List.h                |  233 --
 omegalib/omega/include/basic/Map.h                 |  127 -
 omegalib/omega/include/basic/Section.h             |  138 -
 omegalib/omega/include/basic/SimpleList.h          |  194 --
 omegalib/omega/include/basic/Tuple.h               |  336 ---
 omegalib/omega/include/basic/omega_error.h         |   14 -
 omegalib/omega/include/basic/util.h                |  263 --
 omegalib/omega/include/omega.h                     |   71 -
 omegalib/omega/include/omega/RelBody.h             |  165 --
 omegalib/omega/include/omega/Rel_map.h             |  161 --
 omegalib/omega/include/omega/Relation.h            |  299 --
 omegalib/omega/include/omega/Relations.h           |   88 -
 omegalib/omega/include/omega/closure.h             |   31 -
 omegalib/omega/include/omega/evac.h                |   15 -
 omegalib/omega/include/omega/farkas.h              |   19 -
 omegalib/omega/include/omega/hull.h                |   89 -
 .../omega/include/omega/omega_core/debugging.h     |   30 -
 omegalib/omega/include/omega/omega_core/oc.h       |  350 ---
 omegalib/omega/include/omega/omega_core/oc_i.h     |   79 -
 omegalib/omega/include/omega/omega_i.h             |   30 -
 omegalib/omega/include/omega/pres_cmpr.h           |   49 -
 omegalib/omega/include/omega/pres_cnstr.h          |  192 --
 omegalib/omega/include/omega/pres_conj.h           |  299 --
 omegalib/omega/include/omega/pres_decl.h           |   55 -
 omegalib/omega/include/omega/pres_dnf.h            |   87 -
 omegalib/omega/include/omega/pres_form.h           |  112 -
 omegalib/omega/include/omega/pres_gen.h            |  192 --
 omegalib/omega/include/omega/pres_logic.h          |   90 -
 omegalib/omega/include/omega/pres_quant.h          |   63 -
 omegalib/omega/include/omega/pres_subs.h           |   88 -
 omegalib/omega/include/omega/pres_tree.h           |   15 -
 omegalib/omega/include/omega/pres_var.h            |  230 --
 omegalib/omega/include/omega/reach.h               |   23 -
 omegalib/omega/src/RelBody.cc                      |  906 ------
 omegalib/omega/src/RelVar.cc                       |   71 -
 omegalib/omega/src/Relation.cc                     |  279 --
 omegalib/omega/src/Relations.cc                    | 2882 --------------------
 omegalib/omega/src/basic/ConstString.cc            |  134 -
 omegalib/omega/src/basic/Link.cc                   |   41 -
 omegalib/omega/src/closure.cc                      | 2100 --------------
 omegalib/omega/src/evac.cc                         |  339 ---
 omegalib/omega/src/farkas.cc                       |  480 ----
 omegalib/omega/src/hull_legacy.cc                  | 1484 ----------
 omegalib/omega/src/hull_simple.cc                  | 1013 -------
 omegalib/omega/src/omega_core/oc.cc                |  754 -----
 omegalib/omega/src/omega_core/oc_eq.cc             |  653 -----
 omegalib/omega/src/omega_core/oc_exp_kill.cc       |  297 --
 omegalib/omega/src/omega_core/oc_global.cc         |   45 -
 omegalib/omega/src/omega_core/oc_print.cc          |  686 -----
 omegalib/omega/src/omega_core/oc_problems.cc       |  198 --
 omegalib/omega/src/omega_core/oc_query.cc          |  478 ----
 omegalib/omega/src/omega_core/oc_quick_kill.cc     |  775 ------
 omegalib/omega/src/omega_core/oc_simple.cc         | 1373 ----------
 omegalib/omega/src/omega_core/oc_solve.cc          | 1378 ----------
 omegalib/omega/src/omega_core/oc_util.cc           |  327 ---
 omegalib/omega/src/pres_beaut.cc                   |  235 --
 omegalib/omega/src/pres_cnstr.cc                   |  450 ---
 omegalib/omega/src/pres_col.cc                     |  104 -
 omegalib/omega/src/pres_conj.cc                    | 1460 ----------
 omegalib/omega/src/pres_decl.cc                    |   71 -
 omegalib/omega/src/pres_dnf.cc                     | 1416 ----------
 omegalib/omega/src/pres_form.cc                    |  147 -
 omegalib/omega/src/pres_gen.cc                     |   45 -
 omegalib/omega/src/pres_logic.cc                   |  226 --
 omegalib/omega/src/pres_print.cc                   |  908 ------
 omegalib/omega/src/pres_quant.cc                   |   95 -
 omegalib/omega/src/pres_rear.cc                    |  131 -
 omegalib/omega/src/pres_subs.cc                    |  131 -
 omegalib/omega/src/pres_var.cc                     |  459 ----
 omegalib/omega/src/reach.cc                        |  211 --
 src/chill_run.cc                                   |   89 +
 src/chill_run_util.cc                              |  120 +
 src/chillmodule.cc                                 |  795 ++++++
 src/dep.cc                                         |  567 ++++
 src/ir_rose.cc                                     | 1756 ++++++++++++
 src/ir_rose_utils.cc                               |   67 +
 src/irtools.cc                                     |  279 ++
 src/loop.cc                                        | 1859 +++++++++++++
 src/loop_basic.cc                                  | 1538 +++++++++++
 src/loop_datacopy.cc                               | 2166 +++++++++++++++
 src/loop_extra.cc                                  |  224 ++
 src/loop_tile.cc                                   |  630 +++++
 src/loop_unroll.cc                                 | 1166 ++++++++
 src/omegatools.cc                                  | 1185 ++++++++
 src/parse_expr.ll                                  |   24 +
 src/parse_expr.yy                                  |   85 +
 266 files changed, 49587 insertions(+), 49591 deletions(-)
 create mode 100644 LICENSE.omega
 delete mode 100644 chill/CMakeLists.txt
 delete mode 100644 chill/include/chill_error.hh
 delete mode 100644 chill/include/chill_run_util.hh
 delete mode 100644 chill/include/chilldebug.h
 delete mode 100644 chill/include/chillmodule.hh
 delete mode 100644 chill/include/dep.hh
 delete mode 100644 chill/include/graph.hh
 delete mode 100644 chill/include/ir_code.hh
 delete mode 100644 chill/include/ir_rose.hh
 delete mode 100644 chill/include/ir_rose_utils.hh
 delete mode 100644 chill/include/irtools.hh
 delete mode 100644 chill/include/loop.hh
 delete mode 100644 chill/include/omegatools.hh
 delete mode 100644 chill/src/chill_run.cc
 delete mode 100644 chill/src/chill_run_util.cc
 delete mode 100644 chill/src/chillmodule.cc
 delete mode 100644 chill/src/dep.cc
 delete mode 100644 chill/src/ir_rose.cc
 delete mode 100644 chill/src/ir_rose_utils.cc
 delete mode 100644 chill/src/irtools.cc
 delete mode 100644 chill/src/loop.cc
 delete mode 100644 chill/src/loop_basic.cc
 delete mode 100644 chill/src/loop_datacopy.cc
 delete mode 100644 chill/src/loop_extra.cc
 delete mode 100644 chill/src/loop_tile.cc
 delete mode 100644 chill/src/loop_unroll.cc
 delete mode 100644 chill/src/omegatools.cc
 delete mode 100644 chill/src/parse_expr.ll
 delete mode 100644 chill/src/parse_expr.yy
 create mode 100644 include/chill_error.hh
 create mode 100644 include/chill_run_util.hh
 create mode 100644 include/chilldebug.h
 create mode 100644 include/chillmodule.hh
 create mode 100644 include/dep.hh
 create mode 100644 include/graph.hh
 create mode 100644 include/ir_code.hh
 create mode 100644 include/ir_rose.hh
 create mode 100644 include/ir_rose_utils.hh
 create mode 100644 include/irtools.hh
 create mode 100644 include/loop.hh
 create mode 100644 include/omegatools.hh
 create mode 100644 lib/codegen/CMakeLists.txt
 create mode 100644 lib/codegen/include/code_gen/CG.h
 create mode 100644 lib/codegen/include/code_gen/CG_outputBuilder.h
 create mode 100644 lib/codegen/include/code_gen/CG_outputRepr.h
 create mode 100644 lib/codegen/include/code_gen/CG_stringBuilder.h
 create mode 100644 lib/codegen/include/code_gen/CG_stringRepr.h
 create mode 100755 lib/codegen/include/code_gen/CG_utils.h
 create mode 100644 lib/codegen/include/code_gen/code_gen.h
 create mode 100755 lib/codegen/include/code_gen/codegen.h
 create mode 100755 lib/codegen/include/code_gen/codegen_error.h
 create mode 100644 lib/codegen/include/code_gen/output_repr.h
 create mode 100644 lib/codegen/src/CG.cc
 create mode 100644 lib/codegen/src/CG_stringBuilder.cc
 create mode 100755 lib/codegen/src/CG_utils.cc
 create mode 100755 lib/codegen/src/codegen.cc
 create mode 100644 lib/omega/CMakeLists.txt
 create mode 100644 lib/omega/doc/interface.pdf
 create mode 100644 lib/omega/include/basic/Bag.h
 create mode 100755 lib/omega/include/basic/BoolSet.h
 create mode 100644 lib/omega/include/basic/Collection.h
 create mode 100644 lib/omega/include/basic/Collections.h
 create mode 100644 lib/omega/include/basic/ConstString.h
 create mode 100644 lib/omega/include/basic/DynamicArray.h
 create mode 100644 lib/omega/include/basic/Iterator.h
 create mode 100644 lib/omega/include/basic/Link.h
 create mode 100644 lib/omega/include/basic/List.h
 create mode 100644 lib/omega/include/basic/Map.h
 create mode 100644 lib/omega/include/basic/Section.h
 create mode 100644 lib/omega/include/basic/SimpleList.h
 create mode 100644 lib/omega/include/basic/Tuple.h
 create mode 100644 lib/omega/include/basic/omega_error.h
 create mode 100644 lib/omega/include/basic/util.h
 create mode 100644 lib/omega/include/omega.h
 create mode 100644 lib/omega/include/omega/RelBody.h
 create mode 100644 lib/omega/include/omega/Rel_map.h
 create mode 100644 lib/omega/include/omega/Relation.h
 create mode 100644 lib/omega/include/omega/Relations.h
 create mode 100644 lib/omega/include/omega/closure.h
 create mode 100644 lib/omega/include/omega/evac.h
 create mode 100644 lib/omega/include/omega/farkas.h
 create mode 100644 lib/omega/include/omega/hull.h
 create mode 100644 lib/omega/include/omega/omega_core/debugging.h
 create mode 100644 lib/omega/include/omega/omega_core/oc.h
 create mode 100644 lib/omega/include/omega/omega_core/oc_i.h
 create mode 100644 lib/omega/include/omega/omega_i.h
 create mode 100644 lib/omega/include/omega/pres_cmpr.h
 create mode 100644 lib/omega/include/omega/pres_cnstr.h
 create mode 100644 lib/omega/include/omega/pres_conj.h
 create mode 100644 lib/omega/include/omega/pres_decl.h
 create mode 100644 lib/omega/include/omega/pres_dnf.h
 create mode 100644 lib/omega/include/omega/pres_form.h
 create mode 100644 lib/omega/include/omega/pres_gen.h
 create mode 100644 lib/omega/include/omega/pres_logic.h
 create mode 100644 lib/omega/include/omega/pres_quant.h
 create mode 100644 lib/omega/include/omega/pres_subs.h
 create mode 100644 lib/omega/include/omega/pres_tree.h
 create mode 100644 lib/omega/include/omega/pres_var.h
 create mode 100644 lib/omega/include/omega/reach.h
 create mode 100644 lib/omega/src/RelBody.cc
 create mode 100644 lib/omega/src/RelVar.cc
 create mode 100644 lib/omega/src/Relation.cc
 create mode 100644 lib/omega/src/Relations.cc
 create mode 100644 lib/omega/src/basic/ConstString.cc
 create mode 100644 lib/omega/src/basic/Link.cc
 create mode 100644 lib/omega/src/closure.cc
 create mode 100644 lib/omega/src/evac.cc
 create mode 100644 lib/omega/src/farkas.cc
 create mode 100755 lib/omega/src/hull_legacy.cc
 create mode 100755 lib/omega/src/hull_simple.cc
 create mode 100644 lib/omega/src/omega_core/oc.cc
 create mode 100644 lib/omega/src/omega_core/oc_eq.cc
 create mode 100644 lib/omega/src/omega_core/oc_exp_kill.cc
 create mode 100644 lib/omega/src/omega_core/oc_global.cc
 create mode 100644 lib/omega/src/omega_core/oc_print.cc
 create mode 100644 lib/omega/src/omega_core/oc_problems.cc
 create mode 100644 lib/omega/src/omega_core/oc_query.cc
 create mode 100644 lib/omega/src/omega_core/oc_quick_kill.cc
 create mode 100644 lib/omega/src/omega_core/oc_simple.cc
 create mode 100644 lib/omega/src/omega_core/oc_solve.cc
 create mode 100644 lib/omega/src/omega_core/oc_util.cc
 create mode 100644 lib/omega/src/pres_beaut.cc
 create mode 100644 lib/omega/src/pres_cnstr.cc
 create mode 100644 lib/omega/src/pres_col.cc
 create mode 100644 lib/omega/src/pres_conj.cc
 create mode 100644 lib/omega/src/pres_decl.cc
 create mode 100644 lib/omega/src/pres_dnf.cc
 create mode 100644 lib/omega/src/pres_form.cc
 create mode 100644 lib/omega/src/pres_gen.cc
 create mode 100644 lib/omega/src/pres_logic.cc
 create mode 100644 lib/omega/src/pres_print.cc
 create mode 100644 lib/omega/src/pres_quant.cc
 create mode 100644 lib/omega/src/pres_rear.cc
 create mode 100644 lib/omega/src/pres_subs.cc
 create mode 100644 lib/omega/src/pres_var.cc
 create mode 100644 lib/omega/src/reach.cc
 create mode 100644 lib/rosecg/CMakeLists.txt
 create mode 100644 lib/rosecg/include/CG_roseBuilder.h
 create mode 100644 lib/rosecg/include/CG_roseRepr.h
 create mode 100644 lib/rosecg/include/rose_attributes.h
 create mode 100644 lib/rosecg/src/CG_roseBuilder.cc
 create mode 100644 lib/rosecg/src/CG_roseRepr.cc
 create mode 100644 lib/rosecg/src/rose_attributes.cc
 delete mode 100644 omegalib/CMakeLists.txt
 delete mode 100644 omegalib/LICENSE
 delete mode 100644 omegalib/codegen/CMakeLists.txt
 delete mode 100644 omegalib/codegen/include/code_gen/CG.h
 delete mode 100644 omegalib/codegen/include/code_gen/CG_outputBuilder.h
 delete mode 100644 omegalib/codegen/include/code_gen/CG_outputRepr.h
 delete mode 100644 omegalib/codegen/include/code_gen/CG_roseBuilder.h
 delete mode 100644 omegalib/codegen/include/code_gen/CG_roseRepr.h
 delete mode 100644 omegalib/codegen/include/code_gen/CG_stringBuilder.h
 delete mode 100644 omegalib/codegen/include/code_gen/CG_stringRepr.h
 delete mode 100755 omegalib/codegen/include/code_gen/CG_utils.h
 delete mode 100644 omegalib/codegen/include/code_gen/code_gen.h
 delete mode 100755 omegalib/codegen/include/code_gen/codegen.h
 delete mode 100755 omegalib/codegen/include/code_gen/codegen_error.h
 delete mode 100644 omegalib/codegen/include/code_gen/output_repr.h
 delete mode 100644 omegalib/codegen/include/code_gen/rose_attributes.h
 delete mode 100644 omegalib/codegen/src/CG.cc
 delete mode 100644 omegalib/codegen/src/CG_roseBuilder.cc
 delete mode 100644 omegalib/codegen/src/CG_roseRepr.cc
 delete mode 100644 omegalib/codegen/src/CG_stringBuilder.cc
 delete mode 100755 omegalib/codegen/src/CG_utils.cc
 delete mode 100755 omegalib/codegen/src/codegen.cc
 delete mode 100644 omegalib/codegen/src/rose_attributes.cc
 delete mode 100755 omegalib/doc/calculator.pdf
 delete mode 100755 omegalib/doc/interface.pdf
 delete mode 100644 omegalib/omega/CMakeLists.txt
 delete mode 100644 omegalib/omega/doc/interface.pdf
 delete mode 100644 omegalib/omega/include/basic/Bag.h
 delete mode 100755 omegalib/omega/include/basic/BoolSet.h
 delete mode 100644 omegalib/omega/include/basic/Collection.h
 delete mode 100644 omegalib/omega/include/basic/Collections.h
 delete mode 100644 omegalib/omega/include/basic/ConstString.h
 delete mode 100644 omegalib/omega/include/basic/DynamicArray.h
 delete mode 100644 omegalib/omega/include/basic/Iterator.h
 delete mode 100644 omegalib/omega/include/basic/Link.h
 delete mode 100644 omegalib/omega/include/basic/List.h
 delete mode 100644 omegalib/omega/include/basic/Map.h
 delete mode 100644 omegalib/omega/include/basic/Section.h
 delete mode 100644 omegalib/omega/include/basic/SimpleList.h
 delete mode 100644 omegalib/omega/include/basic/Tuple.h
 delete mode 100644 omegalib/omega/include/basic/omega_error.h
 delete mode 100644 omegalib/omega/include/basic/util.h
 delete mode 100644 omegalib/omega/include/omega.h
 delete mode 100644 omegalib/omega/include/omega/RelBody.h
 delete mode 100644 omegalib/omega/include/omega/Rel_map.h
 delete mode 100644 omegalib/omega/include/omega/Relation.h
 delete mode 100644 omegalib/omega/include/omega/Relations.h
 delete mode 100644 omegalib/omega/include/omega/closure.h
 delete mode 100644 omegalib/omega/include/omega/evac.h
 delete mode 100644 omegalib/omega/include/omega/farkas.h
 delete mode 100644 omegalib/omega/include/omega/hull.h
 delete mode 100644 omegalib/omega/include/omega/omega_core/debugging.h
 delete mode 100644 omegalib/omega/include/omega/omega_core/oc.h
 delete mode 100644 omegalib/omega/include/omega/omega_core/oc_i.h
 delete mode 100644 omegalib/omega/include/omega/omega_i.h
 delete mode 100644 omegalib/omega/include/omega/pres_cmpr.h
 delete mode 100644 omegalib/omega/include/omega/pres_cnstr.h
 delete mode 100644 omegalib/omega/include/omega/pres_conj.h
 delete mode 100644 omegalib/omega/include/omega/pres_decl.h
 delete mode 100644 omegalib/omega/include/omega/pres_dnf.h
 delete mode 100644 omegalib/omega/include/omega/pres_form.h
 delete mode 100644 omegalib/omega/include/omega/pres_gen.h
 delete mode 100644 omegalib/omega/include/omega/pres_logic.h
 delete mode 100644 omegalib/omega/include/omega/pres_quant.h
 delete mode 100644 omegalib/omega/include/omega/pres_subs.h
 delete mode 100644 omegalib/omega/include/omega/pres_tree.h
 delete mode 100644 omegalib/omega/include/omega/pres_var.h
 delete mode 100644 omegalib/omega/include/omega/reach.h
 delete mode 100644 omegalib/omega/src/RelBody.cc
 delete mode 100644 omegalib/omega/src/RelVar.cc
 delete mode 100644 omegalib/omega/src/Relation.cc
 delete mode 100644 omegalib/omega/src/Relations.cc
 delete mode 100644 omegalib/omega/src/basic/ConstString.cc
 delete mode 100644 omegalib/omega/src/basic/Link.cc
 delete mode 100644 omegalib/omega/src/closure.cc
 delete mode 100644 omegalib/omega/src/evac.cc
 delete mode 100644 omegalib/omega/src/farkas.cc
 delete mode 100755 omegalib/omega/src/hull_legacy.cc
 delete mode 100755 omegalib/omega/src/hull_simple.cc
 delete mode 100644 omegalib/omega/src/omega_core/oc.cc
 delete mode 100644 omegalib/omega/src/omega_core/oc_eq.cc
 delete mode 100644 omegalib/omega/src/omega_core/oc_exp_kill.cc
 delete mode 100644 omegalib/omega/src/omega_core/oc_global.cc
 delete mode 100644 omegalib/omega/src/omega_core/oc_print.cc
 delete mode 100644 omegalib/omega/src/omega_core/oc_problems.cc
 delete mode 100644 omegalib/omega/src/omega_core/oc_query.cc
 delete mode 100644 omegalib/omega/src/omega_core/oc_quick_kill.cc
 delete mode 100644 omegalib/omega/src/omega_core/oc_simple.cc
 delete mode 100644 omegalib/omega/src/omega_core/oc_solve.cc
 delete mode 100644 omegalib/omega/src/omega_core/oc_util.cc
 delete mode 100644 omegalib/omega/src/pres_beaut.cc
 delete mode 100644 omegalib/omega/src/pres_cnstr.cc
 delete mode 100644 omegalib/omega/src/pres_col.cc
 delete mode 100644 omegalib/omega/src/pres_conj.cc
 delete mode 100644 omegalib/omega/src/pres_decl.cc
 delete mode 100644 omegalib/omega/src/pres_dnf.cc
 delete mode 100644 omegalib/omega/src/pres_form.cc
 delete mode 100644 omegalib/omega/src/pres_gen.cc
 delete mode 100644 omegalib/omega/src/pres_logic.cc
 delete mode 100644 omegalib/omega/src/pres_print.cc
 delete mode 100644 omegalib/omega/src/pres_quant.cc
 delete mode 100644 omegalib/omega/src/pres_rear.cc
 delete mode 100644 omegalib/omega/src/pres_subs.cc
 delete mode 100644 omegalib/omega/src/pres_var.cc
 delete mode 100644 omegalib/omega/src/reach.cc
 create mode 100644 src/chill_run.cc
 create mode 100644 src/chill_run_util.cc
 create mode 100644 src/chillmodule.cc
 create mode 100644 src/dep.cc
 create mode 100644 src/ir_rose.cc
 create mode 100644 src/ir_rose_utils.cc
 create mode 100644 src/irtools.cc
 create mode 100644 src/loop.cc
 create mode 100644 src/loop_basic.cc
 create mode 100644 src/loop_datacopy.cc
 create mode 100644 src/loop_extra.cc
 create mode 100644 src/loop_tile.cc
 create mode 100644 src/loop_unroll.cc
 create mode 100644 src/omegatools.cc
 create mode 100644 src/parse_expr.ll
 create mode 100644 src/parse_expr.yy

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6cb54d7..229a99d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,12 +9,82 @@ if (NOT DEFINED BOOSTHOME)
     message( FATAL_ERROR "BOOSTHOME is not set, try use -DBOOSTHOME" )
 endif()
 
-add_subdirectory(chill)
-add_subdirectory(doc)
+find_package(PythonLibs 2.7 REQUIRED)
+find_package(BISON)
+find_package(FLEX)
+
+FLEX_TARGET(ExprScanner src/parse_expr.ll ${CMAKE_CURRENT_BINARY_DIR}/parse_expr.yy.cc COMPILE_FLAGS
+    "--header-file=${CMAKE_CURRENT_BINARY_DIR}/parse_expr.ll.hh") # Hack to avoid generating header in root
+BISON_TARGET(ExprParser src/parse_expr.yy ${CMAKE_CURRENT_BINARY_DIR}/parse_expr.tab.cc COMPILE_FLAGS "-t -d")
+ADD_FLEX_BISON_DEPENDENCY(ExprScanner ExprParser)
+
+string(TIMESTAMP build_date "\\\"%m/%d/%Y\\\"")
+
+set(CORE_LIBS 
+    m rose rt util omega codegen rosecg dl 
+    boost_date_time boost_filesystem boost_program_options
+    boost_regex boost_system boost_wave boost_iostreams)
+
+set(CORE_SRC
+    src/dep.cc
+    src/irtools.cc
+    src/loop.cc
+    src/loop_basic.cc
+    src/loop_datacopy.cc
+    src/loop_extra.cc
+    src/loop_tile.cc
+    src/loop_unroll.cc
+    src/omegatools.cc
+    )
+
+set(IR_CHILL_SRC
+    src/ir_rose.cc
+    src/ir_rose_utils.cc
+    )
+
+set(PYTHON_SRC
+    src/chill_run.cc
+    src/chill_run_util.cc
+    src/chillmodule.cc
+    ${FLEX_ExprScanner_OUTPUTS}
+    ${BISON_ExprParser_OUTPUTS}
+    )
+
+set(COMMON_FLAGS "-DCHILL_BUILD_DATE=\"${build_date}\" -DCHILL_BUILD_VERSION=\"\\\"${CHILL_VERSION}\\\"\"")
 
-if (NOT DEFINED OMEGAHOME)
-    message( WARNING "OMEGAHOME is not set, use bundled omegalib")
-    add_subdirectory(omegalib)
+set(CMAKE_CXX_FLAGS "${COMMON_FLAGS} ${CMAKE_CXX_FLAGS}")
+
+if (DEFINED OMEGAHOME)
+    link_directories(${OMEGAHOME}/lib)
+    set(OMEGA_INC ${OMEGAHOME}/include)
 else()
-    message( WARNING "OMEGAHOME set to ${OMEGAHOME}, use prebuilt omegalib")
+    set(OMEGA_INC 
+        ${CMAKE_CURRENT_SOURCE_DIR}/lib/omega/include
+        ${CMAKE_CURRENT_SOURCE_DIR}/lib/codegen/include
+        )
 endif()
+
+link_directories(${ROSEHOME}/lib ${BOOSTOME}/lib)
+
+include_directories(
+    include
+    lib/rosecg/include
+    ${OMEGA_INC}
+    ${ROSEHOME}/include
+    ${ROSEHOME}/include/rose
+    ${BOOSTHOME}/include
+    ${CMAKE_CURRENT_BINARY_DIR}
+    ${PYTHON_INCLUDE_DIRS})
+
+add_executable(chill ${CORE_SRC} ${PYTHON_SRC} ${IR_CHILL_SRC})
+target_link_libraries(chill ${CORE_LIBS} ${PYTHON_LIBRARY})
+add_dependencies(chill omega codegen rosecg)
+
+install(TARGETS chill
+        RUNTIME DESTINATION bin)
+
+add_subdirectory(lib/omega)
+add_subdirectory(lib/codegen)
+add_subdirectory(lib/rosecg)
+
+add_subdirectory(doc)
diff --git a/LICENSE.omega b/LICENSE.omega
new file mode 100644
index 0000000..f0fbe69
--- /dev/null
+++ b/LICENSE.omega
@@ -0,0 +1,705 @@
+Omega+ and CodeGen+
+Copyright (C) 2005-2011 Chun Chen
+All rights reserved.
+
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+
+==============================================================================
+
+The Omega Project
+Copyright (C) 1994-2000 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
diff --git a/chill/CMakeLists.txt b/chill/CMakeLists.txt
deleted file mode 100644
index 6f58597..0000000
--- a/chill/CMakeLists.txt
+++ /dev/null
@@ -1,74 +0,0 @@
-find_package(PythonLibs 2.7 REQUIRED)
-find_package(BISON)
-find_package(FLEX)
-
-FLEX_TARGET(ExprScanner src/parse_expr.ll ${CMAKE_CURRENT_BINARY_DIR}/parse_expr.yy.cc COMPILE_FLAGS
-    "--header-file=${CMAKE_CURRENT_BINARY_DIR}/parse_expr.ll.hh") # Hack to avoid generating header in root
-BISON_TARGET(ExprParser src/parse_expr.yy ${CMAKE_CURRENT_BINARY_DIR}/parse_expr.tab.cc COMPILE_FLAGS "-t -d")
-ADD_FLEX_BISON_DEPENDENCY(ExprScanner ExprParser)
-
-string(TIMESTAMP build_date "\\\"%m/%d/%Y\\\"")
-
-set(CORE_LIBS 
-    m rose rt util omega codegen dl 
-    boost_date_time boost_filesystem boost_program_options
-    boost_regex boost_system boost_wave boost_iostreams)
-
-set(CORE_SRC
-    src/dep.cc
-    src/irtools.cc
-    src/loop.cc
-    src/loop_basic.cc
-    src/loop_datacopy.cc
-    src/loop_extra.cc
-    src/loop_tile.cc
-    src/loop_unroll.cc
-    src/omegatools.cc
-    )
-
-set(IR_CHILL_SRC
-    src/ir_rose.cc
-    src/ir_rose_utils.cc
-    )
-
-set(PYTHON_SRC
-    src/chill_run.cc
-    src/chill_run_util.cc
-    src/chillmodule.cc
-    ${FLEX_ExprScanner_OUTPUTS}
-    ${BISON_ExprParser_OUTPUTS}
-    )
-
-set(COMMON_FLAGS "-DCHILL_BUILD_DATE=\"${build_date}\" -DCHILL_BUILD_VERSION=\"\\\"${CHILL_VERSION}\\\"\"")
-
-set(CMAKE_CXX_FLAGS "${COMMON_FLAGS} ${CMAKE_CXX_FLAGS}")
-
-if (DEFINED OMEGAHOME)
-    link_directories(${OMEGAHOME}/lib)
-    set(OMEGA_INC ${OMEGAHOME}/include)
-else()
-    set(OMEGA_INC 
-        ${PROJECT_SOURCE_DIR}/omegalib/omega/include
-        ${PROJECT_SOURCE_DIR}/omegalib/codegen/include)
-endif()
-
-link_directories(${ROSEHOME}/lib ${BOOSTOME}/lib)
-
-include_directories(
-    include
-    ${OMEGA_INC}
-    ${ROSEHOME}/include
-    ${ROSEHOME}/include/rose
-    ${BOOSTHOME}/include
-    ${CMAKE_CURRENT_BINARY_DIR}
-    ${PYTHON_INCLUDE_DIRS})
-
-add_executable(chill ${CORE_SRC} ${PYTHON_SRC} ${IR_CHILL_SRC})
-target_link_libraries(chill ${CORE_LIBS} ${PYTHON_LIBRARY})
-
-if (NOT DEFINED OMEGAHOME)
-    add_dependencies(chill omega codegen)
-endif()
-
-install(TARGETS chill
-        RUNTIME DESTINATION bin)
diff --git a/chill/include/chill_error.hh b/chill/include/chill_error.hh
deleted file mode 100644
index 88e49fc..0000000
--- a/chill/include/chill_error.hh
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef CHILL_ERROR_HH
-#define CHILL_ERROR_HH
-
-/*!
- * \file
- * \brief CHiLL runtime exceptions
- */
-
-//! for loop transformation problem
-struct loop_error: public std::runtime_error {
-  loop_error(const std::string &msg): std::runtime_error(msg){}
-};
-
-//! for generic compiler intermediate code handling problem
-struct ir_error: public std::runtime_error {
-  ir_error(const std::string &msg): std::runtime_error(msg){}
-};
-
-//! for specific for expression to preburger math translation problem
-struct ir_exp_error: public ir_error {
-  ir_exp_error(const std::string &msg): ir_error(msg){}
-};
-
-#endif
diff --git a/chill/include/chill_run_util.hh b/chill/include/chill_run_util.hh
deleted file mode 100644
index 8df5871..0000000
--- a/chill/include/chill_run_util.hh
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef CHILL_RUN_UTIL_HH
-#define CHILL_RUN_UTIL_HH
-
-#include <vector>
-#include <map>
-#include <string>
-
-typedef std::map<std::string, int>               simap_t;
-typedef std::vector<std::map<std::string, int> > simap_vec_t;
-
-// in chill_run_util.cc
-simap_vec_t* make_prog(simap_vec_t* cond);
-simap_vec_t* make_cond_gt(simap_t* lhs, simap_t* rhs);
-simap_vec_t* make_cond_lt(simap_t* lhs, simap_t* rhs);
-simap_vec_t* make_cond_ge(simap_t* lhs, simap_t* rhs);
-simap_vec_t* make_cond_le(simap_t* lhs, simap_t* rhs);
-simap_vec_t* make_cond_eq(simap_t* lhs, simap_t* rhs);
-simap_t* make_cond_item_add(simap_t* lhs, simap_t* rhs);
-simap_t* make_cond_item_sub(simap_t* lhs, simap_t* rhs);
-simap_t* make_cond_item_mul(simap_t* lhs, simap_t* rhs);
-simap_t* make_cond_item_neg(simap_t* expr);
-simap_t* make_cond_item_number(int n);
-simap_t* make_cond_item_variable(const char* var);
-simap_t* make_cond_item_level(int n);
-
-// in parse_expr.yy
-simap_vec_t* parse_relation_vector(const char* expr);
-
-#endif
diff --git a/chill/include/chilldebug.h b/chill/include/chilldebug.h
deleted file mode 100644
index 865f1f6..0000000
--- a/chill/include/chilldebug.h
+++ /dev/null
@@ -1,15 +0,0 @@
-
-// a central place to turn on debugging messages
-
-// enable the next line to get lots of output 
-//#define DEBUGCHILL
-#ifndef DEBUGCHILL_H
-#define DEBUGCHILL_H
-
-#ifdef DEBUGCHILL 
-#define DEBUG_PRINT(args...) fprintf(stderr, args )
-#else
-#define DEBUG_PRINT(args...) do {} while(0) /* Don't do anything  */
-#endif
-
-#endif
diff --git a/chill/include/chillmodule.hh b/chill/include/chillmodule.hh
deleted file mode 100644
index e83119f..0000000
--- a/chill/include/chillmodule.hh
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef CHILLMODULE_HH
-#define CHILLMODULE_HH
-
-/*!
- * \file
- * \brief chill interface to python
- */
-
-#include <Python.h>
-
-void finalize_loop(int loop_num_start, int loop_num_end);
-int get_loop_num_start();
-int get_loop_num_end();
-//! pass C methods to python
-PyMODINIT_FUNC initchill();
-
-#endif
diff --git a/chill/include/dep.hh b/chill/include/dep.hh
deleted file mode 100644
index 6c535ce..0000000
--- a/chill/include/dep.hh
+++ /dev/null
@@ -1,94 +0,0 @@
-#ifndef DEP_HH
-#define DEP_HH
-
-/*!
- * \file 
- * \brief Data dependence vector and graph.
- *
- * All dependence vectors are normalized, i.e., the first non-zero distance
- * must be positve. Thus the correct dependence meaning can be given based on
- * source/destination pair's read/write type. Suppose for a dependence vector
- * 1, 0~5, -3), we want to permute the first and the second dimension,
- * the result would be two dependence vectors (0, 1, -3) and (1~5, 1, -3).
- * All operations on dependence vectors are non-destructive, i.e., new
- * dependence vectors are returned.
- */
-
-#include <omega.h>
-#include "graph.hh"
-#include "ir_code.hh"
-#include "chill_error.hh"
-
-enum DependenceType { DEP_W2R, DEP_R2W, DEP_W2W, DEP_R2R, DEP_CONTROL, DEP_UNKNOWN };
-
-class DependenceVector;
-typedef std::vector<DependenceVector> DependenceList;
-
-struct DependenceVector {
-  DependenceType type;
-  IR_Symbol *sym;
- 
-  bool is_reduction; //!< used to identify a class of flow dependence
-                     //!< that can be broken
-  std::vector<omega::coef_t> lbounds;
-  std::vector<omega::coef_t> ubounds;
-  
-  bool quasi;
-  bool is_scalar_dependence;
-  DependenceVector() {
-    type = DEP_UNKNOWN;
-    sym = NULL;
-    is_reduction = false;
-    quasi = false;
-    is_scalar_dependence = false;
-  }
-  DependenceVector(const DependenceVector &that);
-  ~DependenceVector() {delete sym;}
-  DependenceVector &operator=(const DependenceVector &that);
-  
-  bool is_data_dependence() const;
-  bool is_control_dependence() const;
-  bool has_negative_been_carried_at(int dim) const;
-  bool has_been_carried_at(int dim) const;
-  bool has_been_carried_before(int dim) const;
-  
-  // TODO the following functions will be cleaned up or removed later
-  bool isZero() const;
-  bool isPositive() const;
-  bool isNegative() const;
-  bool isAllPositive() const;
-  bool isAllNegative() const;
-  bool isZero(int dim) const;
-  bool hasPositive(int dim) const;
-  bool hasNegative(int dim) const;
-  bool isCarried(int dim, omega::coef_t distance = posInfinity) const;
-  bool canPermute(const std::vector<int> &pi) const;
-  
-  std::vector<DependenceVector> normalize() const;
-  std::vector<DependenceVector> permute(const std::vector<int> &pi) const;
-  DependenceVector reverse() const;
-  DependenceType getType() const;
-  friend std::ostream& operator<<(std::ostream &os, const DependenceVector &d);
-};
-
-
-
-class DependenceGraph: public Graph<Empty, DependenceVector> {
-  
-protected:
-  int num_dim_;
-  
-public:
-  DependenceGraph(int n) { num_dim_ = n; }
-  DependenceGraph() { num_dim_ = 0; }
-  ~DependenceGraph() {}
-  int num_dim() const { return num_dim_; }
-  DependenceGraph permute(const std::vector<int> &pi,
-                          const std::set<int> &active = std::set<int>()) const;
-  DependenceGraph subspace(int dim) const;
-  bool isPositive() const;
-  bool hasPositive(int dim) const;
-  bool hasNegative(int dim) const;
-};
-
-#endif
diff --git a/chill/include/graph.hh b/chill/include/graph.hh
deleted file mode 100644
index 211444a..0000000
--- a/chill/include/graph.hh
+++ /dev/null
@@ -1,328 +0,0 @@
-/*****************************************************************************
- Copyright (C) 2008 University of Southern California
- Copyright (C) 2010 University of Utah
- All Rights Reserved.
-
- Purpose:
-   Graph<VertexType, EdgeType> template class supports topological sort
- with return result observing strongly connected component.
-
- Notes:
-   The result of topologically sorting a graph V={1,2,3,4} and E={1->2, 1->3,
- 2->3, 3->2, 3->4} is ({1}, {2,3}, {4}).
- 
- History:
-   01/2006 Created by Chun Chen.
-   07/2010 add a new topological order, -chun
-*****************************************************************************/
-
-#ifndef GRAPH_HH
-#define GRAPH_HH
-
-/*!
- * \file
- * \brief  Graph<VertexType, EdgeType> template class supports topological sort
- *
- * The result of topologically sorting a graph V={1,2,3,4} and E={1->2, 1->3,
- * 2->3, 3->2, 3->4} is ({1}, {2,3}, {4}).
- */
-
-#include <set>
-#include <vector>
-#include <map>
-#include <iostream>
-#include <stack>
-#include <algorithm>
-#include <assert.h>
-
-struct Empty {
-  Empty() {};
-  bool operator<(const Empty &) const { return true; };
-  bool operator==(const Empty &) const { return false; };
-  friend std::ostream& operator<<(std::ostream &os, const Empty &) { return os; };
-};
-
-namespace {
-  enum GraphColorType {WHITE, GREY, BLACK};
-}
-
-template<typename VertexType, typename EdgeType> struct Graph;
-template<typename VertexType, typename EdgeType> std::ostream& operator<<(std::ostream &os, const Graph<VertexType, EdgeType> &g);
-
-template<typename VertexType = Empty, typename EdgeType = Empty>
-struct Graph {
-  typedef std::map<int, std::vector<EdgeType> > EdgeList;
-  typedef std::vector<std::pair<VertexType, EdgeList> > VertexList;
-
-  VertexList vertex;
-  bool directed;
-
-  Graph(bool directed = true);
-  
-  int vertexCount() const;
-  int edgeCount() const;
-  bool isEmpty() const;
-  bool isDirected() const;
-  int insert(const VertexType &v = VertexType());
-  void connect(int v1, int v2, const EdgeType &e = EdgeType());
-  void connect(int v1, int v2, const std::vector<EdgeType> &e);
-  void disconnect(int v1, int v2);
-  bool hasEdge(int v1, int v2) const;
-  std::vector<EdgeType> getEdge(int v1, int v2) const;
-  
-  //! Topological sort
-  /*! This topological sort does handle SCC in graph. */
-  std::vector<std::set<int> > topoSort() const;
-  //! Topological sort
-  /*! This topological sort does not handle SCC in graph. */
-  std::vector<std::set<int> > packed_topoSort() const;
-
-  void dump() {
-    std::cout << *this;
-  }
-  
-  friend std::ostream& operator<< <>(std::ostream &os, const Graph<VertexType, EdgeType> &g);
-};
-
-template<typename VertexType, typename EdgeType>
-std::ostream& operator<<(std::ostream &os, const Graph<VertexType, EdgeType> &g) {
-  for (int i = 0; i < g.vertex.size(); i++)
-    for (typename Graph<VertexType,EdgeType>::EdgeList::const_iterator j = g.vertex[i].second.begin(); j != g.vertex[i].second.end(); j++) {
-	os << "s" << i << "->" << "s" << j->first << ":";
-      for (typename std::vector<EdgeType>::const_iterator k = j->second.begin(); k != j->second.end(); k++)
-        os << " " << *k;
-      os << std::endl;
-    }
-
-  return os;
-}
-
-
-template<typename VertexType, typename EdgeType>
-Graph<VertexType, EdgeType>::Graph(bool directed_):
-  directed(directed_) {
-}
-
-template<typename VertexType, typename EdgeType>
-int Graph<VertexType, EdgeType>::vertexCount() const {
-  return vertex.size();
-}
-
-template<typename VertexType, typename EdgeType>
-int Graph<VertexType, EdgeType>::edgeCount() const {
-  int result = 0;
-
-  for (int i = 0; i < vertex.size(); i++)
-    for (typename EdgeList::const_iterator j = vertex[i].second.begin(); j != vertex[i].second.end(); j++)
-      result += j->second.size();
-
-  if (!directed)
-    result = result/2;
-  
-  return result;
-}
-
-template<typename VertexType, typename EdgeType>
-bool Graph<VertexType, EdgeType>::isEmpty() const {
-  return vertex.size() == 0;
-}
-
-template<typename VertexType, typename EdgeType>
-bool Graph<VertexType, EdgeType>::isDirected() const {
-  return directed;
-}
-
-template<typename VertexType, typename EdgeType>
-int Graph<VertexType, EdgeType>::insert(const VertexType & v) {
-  for (int i = 0; i < vertex.size(); i++)
-    if (vertex[i].first == v)
-      return i;
-
-  vertex.push_back(std::make_pair(v, EdgeList()));
-  return vertex.size() - 1;
-}
-  
-  
-template<typename VertexType, typename EdgeType>
-void Graph<VertexType, EdgeType>::connect(int v1, int v2, const EdgeType &e)  {
-  assert(v1 < vertex.size() && v2 < vertex.size());
-
-  vertex[v1].second[v2].push_back(e);;
-  if (!directed)
-    vertex[v2].second[v1].push_back(e);
-}
-
-template<typename VertexType, typename EdgeType>
-void Graph<VertexType, EdgeType>::connect(int v1, int v2, const std::vector<EdgeType> &e)  {
-  assert(v1 < vertex.size() && v2 < vertex.size());
-
-  if (e.size() == 0)
-    return;
-  
-  copy(e.begin(), e.end(), back_inserter(vertex[v1].second[v2]));
-  if (!directed)
-    copy(e.begin(), e.end(), back_inserter(vertex[v2].second[v1]));
-}
-
-template<typename VertexType, typename EdgeType>
-void Graph<VertexType, EdgeType>::disconnect(int v1, int v2)  {
-  assert(v1 < vertex.size() && v2 < vertex.size());
-
-  vertex[v1].second.erase(v2);
-  if (!directed)
-    vertex[v2].second.erase(v1);
-}
-
-template<typename VertexType, typename EdgeType>
-bool Graph<VertexType,EdgeType>::hasEdge(int v1, int v2) const {
-  return vertex[v1].second.find(v2) != vertex[v1].second.end();
-}
-
-template<typename VertexType, typename EdgeType>
-std::vector<EdgeType> Graph<VertexType,EdgeType>::getEdge(int v1, int v2) const {
-  if (!hasEdge(v1, v2))
-    return std::vector<EdgeType>();
-
-  return vertex[v1].second.find(v2)->second;
-}
-
-template<typename VertexType, typename EdgeType>
-std::vector<std::set<int> > Graph<VertexType, EdgeType>::topoSort() const {
-  const int n = vertex.size();
-  std::vector<GraphColorType> color(n, WHITE);
-  std::stack<int> S;
-
-  std::vector<int> order(n);
-  int c = n;
-  
-  // first DFS
-  for (int i = n-1; i >= 0; i--)
-    if (color[i] == WHITE) {
-      S.push(i);
-      while (!S.empty()) {
-        int v = S.top();
-
-        if (color[v] == WHITE) {
-          for (typename EdgeList::const_iterator j = vertex[v].second.begin(); j != vertex[v].second.end(); j++)
-            if (color[j->first] == WHITE)
-              S.push(j->first);
-
-          color[v] = GREY;
-        }
-        else if (color[v] == GREY) {
-          color[v] = BLACK;
-          S.pop();
-          order[--c] = v;
-        }
-        else {
-          S.pop();
-        }
-      }
-    }
-
-  // transpose edge
-  std::vector<std::set<int> > edgeT(n);
-  for (int i = 0; i < n; i++)
-    for (typename EdgeList::const_iterator j = vertex[i].second.begin(); j != vertex[i].second.end(); j++)
-      edgeT[j->first].insert(i);
-  
-  // second DFS in transposed graph starting from last finished vertex
-  fill(color.begin(), color.end(), WHITE);
-  std::vector<std::set<int> > result;
-  for (int i = 0; i < n; i++)
-    if (color[order[i]] == WHITE) {
-      std::set<int> s;
-      
-      S.push(order[i]);
-      while (!S.empty()) {
-        int v = S.top();
-      
-        if(color[v] == WHITE) {
-          for (std::set<int>::const_iterator j = edgeT[v].begin(); j != edgeT[v].end(); j++)
-            if (color[*j] == WHITE)
-              S.push(*j);
-
-          color[v] = GREY;
-        }
-        else if (color[v] == GREY) {
-          color[v] = BLACK;
-          S.pop();
-          s.insert(v);
-        }
-        else {
-          S.pop();
-        }
-      }
-
-      result.push_back(s);
-    }
-
-  return result;
-}
-
-template<typename VertexType, typename EdgeType>
-std::vector<std::set<int> > Graph<VertexType, EdgeType>::packed_topoSort() const {
-  const int n = vertex.size();
-  std::vector<GraphColorType> color(n, WHITE);
-  std::stack<int> S;
-
-  std::vector<bool> is_root(n, false);
-  std::vector<std::set<int> > edges(n);
-  
-  // first DFS
-  for (int i = n-1; i >= 0; i--)
-    if (color[i] == WHITE) {
-      S.push(i);
-      is_root[i] = true;
-      while (!S.empty()) {
-        int v = S.top();
-
-        if (color[v] == WHITE) {
-          for (typename EdgeList::const_iterator j = vertex[v].second.begin(); j != vertex[v].second.end(); j++)
-            if (color[j->first] == WHITE) {
-              S.push(j->first);
-              edges[v].insert(j->first);
-            }
-            else if (color[j->first] == BLACK) {
-              if (is_root[j->first]) {
-                is_root[j->first] = false;
-                edges[v].insert(j->first);
-              }
-            }
-
-          color[v] = GREY;
-        }
-        else if (color[v] == GREY) {
-          color[v] = BLACK;
-          S.pop();
-        }
-        else {
-          S.pop();
-        }
-      }
-    }
-
-
-  // second BFS in DFS tree starting from roots
-  std::vector<std::set<int> > result;
-  std::set<int> s;
-  for (int i = 0; i < n; i++)
-    if (is_root[i])
-      s.insert(i);
-  if (s.size() != 0) {
-    result.push_back(s);
-    while (true) {
-      std::set<int> s;
-      for (std::set<int>::iterator i = result[result.size()-1].begin(); i != result[result.size()-1].end(); i++)
-        s.insert(edges[*i].begin(), edges[*i].end());
-      if (s.size() != 0)
-        result.push_back(s);
-      else
-        break;
-    }
-  }
-
-  return result;
-}
-
-#endif
diff --git a/chill/include/ir_code.hh b/chill/include/ir_code.hh
deleted file mode 100644
index d695474..0000000
--- a/chill/include/ir_code.hh
+++ /dev/null
@@ -1,289 +0,0 @@
-/*****************************************************************************
- Copyright (C) 2009-2010 University of Utah
- All Rights Reserved.
-
- Purpose:
-   CHiLL's compiler intermediate representation interface that extends
- Omega's builder interface to accomodate compiler analyses and
- extra code generation.
-.
- Notes:
-   Unlike CG_outputRepr, IR_Symbol,IR_Ref and IR_Control are place holders
- to the underlying code, thus deleting or duplicating them does not affect
- the actual code.  Similar to Omega builder's memory allocation strategy,
- all non-const pointer parameters of CG_outputRepr/IR_Symbol/IR_Ref/IR_Control
- are destroyed after the call.
-
- History:
-   02/2009 Created by Chun Chen.
-   06/2010 Add IR_Control interface, by chun.  
-*****************************************************************************/
-
-#ifndef IR_CODE_HH
-#define IR_CODE_HH
-
-/*!
- * \file
- * \brief CHiLL's compiler intermediate representation interface that extends Omega's builder interface to accomodate compiler analyses and extra code generation.
- * 
- * Unlike CG_outputRepr, IR_Symbol,IR_Ref and IR_Control are place holders 
- * to the underlying code, thus deleting or duplicating them does not affect
- * the actual code.  Similar to Omega builder's memory allocation strategy,
- * all non-const pointer parameters of CG_outputRepr/IR_Symbol/IR_Ref/IR_Control
- * are destroyed after the call.
- */
-
-
-#include <code_gen/CG_outputRepr.h>
-#include <code_gen/CG_outputBuilder.h>
-#include <vector>
-
-enum IR_OPERATION_TYPE    {IR_OP_CONSTANT, IR_OP_VARIABLE,
-                           IR_OP_PLUS, IR_OP_MINUS, IR_OP_MULTIPLY, IR_OP_DIVIDE,
-                           IR_OP_POSITIVE, IR_OP_NEGATIVE,
-                           IR_OP_MIN, IR_OP_MAX,
-                           IR_OP_ASSIGNMENT,
-                           IR_OP_NULL, IR_OP_UNKNOWN};
-enum IR_CONTROL_TYPE      {IR_CONTROL_LOOP, IR_CONTROL_IF, IR_CONTROL_WHILE, IR_CONTROL_BLOCK};
-enum IR_CONSTANT_TYPE     {IR_CONSTANT_INT, IR_CONSTANT_FLOAT,
-                           IR_CONSTANT_UNKNOWN};
-enum IR_CONDITION_TYPE    {IR_COND_LT, IR_COND_LE,
-                           IR_COND_GT, IR_COND_GE,
-                           IR_COND_EQ, IR_COND_NE,
-                           IR_COND_UNKNOWN};
-enum IR_ARRAY_LAYOUT_TYPE {IR_ARRAY_LAYOUT_ROW_MAJOR,
-                           IR_ARRAY_LAYOUT_COLUMN_MAJOR,
-                           IR_ARRAY_LAYOUT_SPACE_FILLING};
-
-class IR_Code;
-
-
-//! Base abstract class for scalar and array symbols.
-/*! This is a place holder for related declaration in IR code.*/
-struct IR_Symbol {
-  const IR_Code *ir_;
-  
-  virtual ~IR_Symbol() {/* ir_ is not the responsibility of this object */}
-  virtual int n_dim() const = 0;
-  virtual std::string name() const = 0;
-  virtual bool operator==(const IR_Symbol &that) const = 0;
-  virtual bool operator!=(const IR_Symbol &that) const {return !(*this == that);}
-  virtual IR_Symbol *clone() const = 0;  /* shallow copy */
-};
-
-
-struct IR_ScalarSymbol: public IR_Symbol {
-  virtual ~IR_ScalarSymbol() {}
-  int n_dim() const {return 0;}
-  virtual int size() const = 0;
-};
-
-
-struct IR_ArraySymbol: public IR_Symbol {
-  virtual ~IR_ArraySymbol() {}
-  virtual int elem_size() const = 0;
-  virtual omega::CG_outputRepr *size(int dim) const = 0;
-  virtual IR_ARRAY_LAYOUT_TYPE layout_type() const = 0;
-};
-
-
-//! Base abstract class for scalar and array references.  
-/*! This is a place holder for related code in IR code. */
-struct IR_Ref {
-  const IR_Code *ir_;
-  
-  virtual ~IR_Ref() {/* ir_ is not the responsibility of this object */}
-  virtual int n_dim() const = 0;
-  virtual bool is_write() const = 0;
-  virtual std::string name() const = 0;
-  virtual bool operator==(const IR_Ref &that) const = 0;
-  virtual bool operator!=(const IR_Ref &that) const {return !(*this == that);}
-  virtual omega::CG_outputRepr *convert() = 0;
-  //! shallow copy
-  virtual IR_Ref *clone() const = 0;
-};
-
-
-struct IR_ConstantRef: public IR_Ref {
-  IR_CONSTANT_TYPE type_;
-
-  virtual ~IR_ConstantRef() {}
-  int n_dim() const {return 0;}
-  bool is_write() const {return false;}
-  std::string name() const {return std::string();}
-  virtual bool is_integer() const {return type_ == IR_CONSTANT_INT;}
-  virtual omega::coef_t integer() const = 0;
-};
-  
-
-struct IR_ScalarRef: public IR_Ref {
-  virtual ~IR_ScalarRef() {}
-  int n_dim() const {return 0;}
-  virtual IR_ScalarSymbol *symbol() const = 0;
-  std::string name() const {
-    IR_ScalarSymbol *sym = symbol();
-    std::string s = sym->name();
-    delete sym;
-    return s;
-  }
-  virtual int size() const {
-    IR_ScalarSymbol *sym = symbol();
-    int s = sym->size();
-    delete sym;
-    return s;
-  }
-};
-
-
-struct IR_ArrayRef: public IR_Ref {
-  virtual ~IR_ArrayRef() {}
-  int n_dim() const {
-    IR_ArraySymbol *sym = symbol();
-    int n = sym->n_dim();
-    delete sym;
-    return n;
-  }
-  virtual omega::CG_outputRepr *index(int dim) const = 0;
-  virtual IR_ArraySymbol *symbol() const = 0;
-  std::string name() const {
-    IR_ArraySymbol *sym = symbol();
-    std::string s = sym->name();
-    delete sym;
-    return s;
-  }
-  virtual int elem_size() const {
-    IR_ArraySymbol *sym = symbol();
-    int s = sym->elem_size();
-    delete sym;
-    return s;
-  }
-  virtual IR_ARRAY_LAYOUT_TYPE layout_type() const {
-    IR_ArraySymbol *sym = symbol();
-    IR_ARRAY_LAYOUT_TYPE t = sym->layout_type();
-    delete sym;
-    return t;
-  }
-};
-
-
-struct IR_Block;
-
-//! Base abstract class for code structures.  
-/*!  
- * This is a place holder for the actual structure in the IR code.  
- * However, in cases that original source code may be transformed during 
- * loop initialization such as converting a while loop to a for loop or 
- * reconstructing the loop from low level IR code, the helper loop class (NOT
- * IMPLEMENTED) must contain the transformed code that needs to be 
- * freed when out of service. 
- */
-struct IR_Control {
-  const IR_Code *ir_;
-
-  virtual ~IR_Control() {/* ir_ is not the responsibility of this object */}
-  virtual IR_CONTROL_TYPE type() const = 0;
-  virtual IR_Block *convert() = 0;
-  //! shallow copy
-  virtual IR_Control *clone() const = 0;
-};
-
-
-struct IR_Loop: public IR_Control {  
-  virtual ~IR_Loop() {}
-  virtual IR_ScalarSymbol *index() const = 0;
-  virtual omega::CG_outputRepr *lower_bound() const = 0;
-  virtual omega::CG_outputRepr *upper_bound() const = 0;
-  virtual IR_CONDITION_TYPE stop_cond() const = 0;
-  virtual IR_Block *body() const = 0;
-  virtual int step_size() const = 0;
-  IR_CONTROL_TYPE type() const { return IR_CONTROL_LOOP; }
-};
-
-
-struct IR_Block: public IR_Control {
-  virtual ~IR_Block() {}
-  virtual omega::CG_outputRepr *extract() const = 0;
-  IR_Block *convert() {return this;}
-  IR_CONTROL_TYPE type() const { return IR_CONTROL_BLOCK; }
-  virtual omega::CG_outputRepr *original() const = 0;
-};
-
-
-struct IR_If: public IR_Control {
-  virtual ~IR_If() {}
-  virtual omega::CG_outputRepr *condition() const = 0;
-  virtual IR_Block *then_body() const = 0;
-  virtual IR_Block *else_body() const = 0;
-  IR_CONTROL_TYPE type() const { return IR_CONTROL_IF; }
-};
-
-
-  
-struct IR_While: public IR_Control {
-  // NOT IMPLEMENTED
-};
-
-
-//! Abstract class for compiler IR.
-class IR_Code {
-protected:
-  omega::CG_outputBuilder *ocg_;
-  omega::CG_outputRepr *init_code_;
-  omega::CG_outputRepr *cleanup_code_;
-
-public:
-  IR_Code() {ocg_ = NULL; init_code_ = cleanup_code_ = NULL;}
-  virtual ~IR_Code() { delete ocg_; delete init_code_; delete cleanup_code_; } 
-  /* the content of init and cleanup code have already been released in derived classes */
-  
-  /*! 
-   * \param memory_type is for differentiating the location of 
-   *    where the new memory is allocated. this is useful for 
-   *    processors with heterogeneous memory hierarchy.
-   */
-  virtual IR_ScalarSymbol *CreateScalarSymbol(const IR_Symbol *sym, int memory_type) = 0;
-  virtual IR_ArraySymbol *CreateArraySymbol(const IR_Symbol *sym, std::vector<omega::CG_outputRepr *> &size, int memory_type) = 0;
-  
-  virtual IR_ScalarRef *CreateScalarRef(const IR_ScalarSymbol *sym) = 0;
-  virtual IR_ArrayRef *CreateArrayRef(const IR_ArraySymbol *sym, std::vector<omega::CG_outputRepr *> &index) = 0;
-  virtual int ArrayIndexStartAt() {return 0;}
-
-  /*! 
-   * Array references should be returned in their accessing order.
-   *
-   * ~~~
-   * e.g. s1: A[i] = A[i-1]
-   *      s2: B[C[i]] = D[i] + E[i]
-   * return A[i-1], A[i], D[i], E[i], C[i], B[C[i]] in this order.
-   * ~~~
-   */
-  virtual std::vector<IR_ArrayRef *> FindArrayRef(const omega::CG_outputRepr *repr) const = 0;
-  virtual std::vector<IR_ScalarRef *> FindScalarRef(const omega::CG_outputRepr *repr) const = 0;
-
-  /*!
-   * If there is no sub structure interesting inside the block, return empty,
-   * so we know when to stop looking inside.
-   */
-  virtual std::vector<IR_Control *> FindOneLevelControlStructure(const IR_Block *block) const = 0;
-
-  /*! 
-   * All controls must be in the same block, at the same level and in
-   * contiguous lexical order as appeared in parameter vector.
-   */
-  virtual IR_Block *MergeNeighboringControlStructures(const std::vector<IR_Control *> &controls) const = 0;
-  
-  virtual IR_Block *GetCode() const = 0;
-  virtual void ReplaceCode(IR_Control *old, omega::CG_outputRepr *repr) = 0;
-  virtual void ReplaceExpression(IR_Ref *old, omega::CG_outputRepr *repr) = 0;
-  
-  virtual IR_OPERATION_TYPE QueryExpOperation(const omega::CG_outputRepr *repr) const = 0;
-  virtual IR_CONDITION_TYPE QueryBooleanExpOperation(const omega::CG_outputRepr *repr) const = 0;
-  virtual std::vector<omega::CG_outputRepr *> QueryExpOperand(const omega::CG_outputRepr *repr) const = 0;
-  virtual IR_Ref *Repr2Ref(const omega::CG_outputRepr *repr) const = 0;
-  
-  //! Codegen Omega code builder interface
-  omega::CG_outputBuilder *builder() const {return ocg_;}
-
-};
-
-#endif  
diff --git a/chill/include/ir_rose.hh b/chill/include/ir_rose.hh
deleted file mode 100644
index 03ea50d..0000000
--- a/chill/include/ir_rose.hh
+++ /dev/null
@@ -1,267 +0,0 @@
-#ifndef IR_ROSE_HH
-#define IR_ROSE_HH
-
-/*!
- * \file
- * \brief CHiLL's rose interface.
- */
-
-#include <omega.h>
-#include "ir_code.hh"
-#include "ir_rose_utils.hh"
-#include <AstInterface_ROSE.h>
-#include "chill_error.hh"
-#include "staticSingleAssignment.h"
-#include "VariableRenaming.h"
-#include "ssaUnfilteredCfg.h"
-#include "virtualCFG.h"
-#include <omega.h>
-
-struct IR_roseScalarSymbol: public IR_ScalarSymbol {
-  SgVariableSymbol* vs_;
-  
-  IR_roseScalarSymbol(const IR_Code *ir, SgVariableSymbol *vs) {
-    ir_ = ir;
-    vs_ = vs;
-  }
-  
-  std::string name() const;
-  int size() const;
-  bool operator==(const IR_Symbol &that) const;
-  IR_Symbol *clone() const;
-};
-
-struct IR_roseArraySymbol: public IR_ArraySymbol {
-  
-  SgVariableSymbol* vs_;
-  
-  IR_roseArraySymbol(const IR_Code *ir, SgVariableSymbol* vs) {
-    ir_ = ir;
-    vs_ = vs;
-  }
-  std::string name() const;
-  int elem_size() const;
-  int n_dim() const;
-  omega::CG_outputRepr *size(int dim) const;
-  bool operator==(const IR_Symbol &that) const;
-  IR_ARRAY_LAYOUT_TYPE layout_type() const;
-  IR_Symbol *clone() const;
-  
-};
-
-struct IR_roseConstantRef: public IR_ConstantRef {
-  union {
-    omega::coef_t i_;
-    double f_;
-  };
-  
-  IR_roseConstantRef(const IR_Code *ir, omega::coef_t i) {
-    ir_ = ir;
-    type_ = IR_CONSTANT_INT;
-    i_ = i;
-  }
-  IR_roseConstantRef(const IR_Code *ir, double f) {
-    ir_ = ir;
-    type_ = IR_CONSTANT_FLOAT;
-    f_ = f;
-  }
-  omega::coef_t integer() const {
-    assert(is_integer());
-    return i_;
-  }
-  bool operator==(const IR_Ref &that) const;
-  omega::CG_outputRepr *convert();
-  IR_Ref *clone() const;
-  
-};
-
-struct IR_roseScalarRef: public IR_ScalarRef {
-  SgAssignOp *ins_pos_;
-  int op_pos_; // -1 means destination operand, otherwise source operand
-  SgVarRefExp *vs_;
-  int is_write_;
-  IR_roseScalarRef(const IR_Code *ir, SgVarRefExp *sym) {
-    ir_ = ir;
-    ins_pos_ = isSgAssignOp(sym->get_parent());
-    op_pos_ = 0;
-    if (ins_pos_ != NULL)
-      if (sym == isSgVarRefExp(ins_pos_->get_lhs_operand()))
-        op_pos_ = -1;
-    
-    vs_ = sym;
-  }
-  IR_roseScalarRef(const IR_Code *ir, SgVarRefExp *ins, int pos) {
-    ir_ = ir;
-    /*  ins_pos_ = ins;
-        op_pos_ = pos;
-        SgExpression* op;
-        if (pos == -1)
-        op = ins->get_lhs_operand();
-        else
-        op = ins->get_rhs_operand();
-        
-    */
-    
-    is_write_ = pos;
-    
-    /*  if (vs_ == NULL || pos > 0)
-        throw ir_error(
-        "Src operand not a variable or more than one src operand!!");
-    */
-    
-    vs_ = ins;
-    
-  }
-  bool is_write() const;
-  IR_ScalarSymbol *symbol() const;
-  bool operator==(const IR_Ref &that) const;
-  omega::CG_outputRepr *convert();
-  IR_Ref *clone() const;
-};
-
-struct IR_roseArrayRef: public IR_ArrayRef {
-  
-  SgPntrArrRefExp *ia_;
-  
-  int is_write_;
-  IR_roseArrayRef(const IR_Code *ir, SgPntrArrRefExp *ia, int write) {
-    ir_ = ir;
-    ia_ = ia;
-    is_write_ = write;
-  }
-  bool is_write() const;
-  omega::CG_outputRepr *index(int dim) const;
-  IR_ArraySymbol *symbol() const;
-  bool operator==(const IR_Ref &that) const;
-  omega::CG_outputRepr *convert();
-  IR_Ref *clone() const;
-};
-
-struct IR_roseLoop: public IR_Loop {
-  SgNode *tf_;
-  
-  IR_roseLoop(const IR_Code *ir, SgNode *tf) {
-    ir_ = ir;
-    tf_ = tf;
-  }
-  
-  IR_ScalarSymbol *index() const;
-  omega::CG_outputRepr *lower_bound() const;
-  omega::CG_outputRepr *upper_bound() const;
-  IR_CONDITION_TYPE stop_cond() const;
-  IR_Block *body() const;
-  IR_Block *convert();
-  int step_size() const;
-  IR_Control *clone() const;
-};
-
-struct IR_roseBlock: public IR_Block {
-  SgNode* tnl_;
-  SgNode *start_, *end_;
-  
-  IR_roseBlock(const IR_Code *ir, SgNode *tnl, SgNode *start, SgNode *end) {
-    ir_ = ir;
-    tnl_ = tnl;
-    start_ = start;
-    end_ = end;
-  }
-  
-  IR_roseBlock(const IR_Code *ir, SgNode *tnl) {
-    ir_ = ir;
-    tnl_ = tnl;
-    start_ = tnl_->get_traversalSuccessorByIndex(0);
-    end_ = tnl_->get_traversalSuccessorByIndex(
-      (tnl_->get_numberOfTraversalSuccessors()) - 1);
-  }
-  omega::CG_outputRepr *extract() const;
-  omega::CG_outputRepr *original() const;
-  IR_Control *clone() const;
-};
-
-struct IR_roseIf: public IR_If {
-  SgNode *ti_;
-  
-  IR_roseIf(const IR_Code *ir, SgNode *ti) {
-    ir_ = ir;
-    ti_ = ti;
-  }
-  ~IR_roseIf() {
-  }
-  omega::CG_outputRepr *condition() const;
-  IR_Block *then_body() const;
-  IR_Block *else_body() const;
-  IR_Block *convert();
-  IR_Control *clone() const;
-};
-
-class IR_roseCode_Global_Init {
-private:
-  static IR_roseCode_Global_Init *pinstance;
-public:
-  SgProject* project;
-  static IR_roseCode_Global_Init *Instance(char** argv);
-};
-
-class IR_roseCode: public IR_Code {
-protected:
-  SgSourceFile* file;
-  SgGlobal *root;
-  SgGlobal *firstScope;
-  SgSymbolTable* symtab_;
-  SgSymbolTable* symtab2_;
-  SgSymbolTable* symtab3_;
-  SgDeclarationStatementPtrList::iterator p;
-  SgFunctionDeclaration *func;
-  bool is_fortran_;
-  int i_;
-  StaticSingleAssignment *ssa_for_scalar;
-  ssa_unfiltered_cfg::SSA_UnfilteredCfg *main_ssa;
-  VariableRenaming *varRenaming_for_scalar;
-public:
-  IR_roseCode(const char *filename, const char* proc_name);
-  ~IR_roseCode();
-  
-  IR_ScalarSymbol *CreateScalarSymbol(const IR_Symbol *sym, int memory_type =
-                                      0);
-  IR_ArraySymbol *CreateArraySymbol(const IR_Symbol *sym,
-                                    std::vector<omega::CG_outputRepr *> &size, int memory_type = 0);
-  IR_ScalarRef *CreateScalarRef(const IR_ScalarSymbol *sym);
-  IR_ArrayRef *CreateArrayRef(const IR_ArraySymbol *sym,
-                              std::vector<omega::CG_outputRepr *> &index);
-  int ArrayIndexStartAt() {
-    if (is_fortran_)
-      return 1;
-    else
-      return 0;
-  }
-  
-  void populateLists(SgNode* tnl_1, SgStatementPtrList* list_1,
-                     SgStatementPtrList& output_list_1);
-  void populateScalars(const omega::CG_outputRepr *repr1,
-                       std::map<SgVarRefExp*, IR_ScalarRef*> &read_scalars_1,
-                       std::map<SgVarRefExp*, IR_ScalarRef*> &write_scalars_1,
-                       std::set<std::string> &indices, std::vector<std::string> &index);
-  std::vector<IR_ArrayRef *> FindArrayRef(
-    const omega::CG_outputRepr *repr) const;
-  std::vector<IR_ScalarRef *> FindScalarRef(
-    const omega::CG_outputRepr *repr) const;
-  std::vector<IR_Control *> FindOneLevelControlStructure(
-    const IR_Block *block) const;
-  IR_Block *MergeNeighboringControlStructures(
-    const std::vector<IR_Control *> &controls) const;
-  IR_Block *GetCode() const;
-  void ReplaceCode(IR_Control *old, omega::CG_outputRepr *repr);
-  void ReplaceExpression(IR_Ref *old, omega::CG_outputRepr *repr);
-  
-  IR_OPERATION_TYPE QueryExpOperation(const omega::CG_outputRepr *repr) const;
-  IR_CONDITION_TYPE QueryBooleanExpOperation(
-    const omega::CG_outputRepr *repr) const;
-  std::vector<omega::CG_outputRepr *> QueryExpOperand(
-    const omega::CG_outputRepr *repr) const;
-  IR_Ref *Repr2Ref(const omega::CG_outputRepr *) const;
-  void finalizeRose();
-  friend class IR_roseArraySymbol;
-  friend class IR_roseArrayRef;
-};
-
-#endif
diff --git a/chill/include/ir_rose_utils.hh b/chill/include/ir_rose_utils.hh
deleted file mode 100644
index 350aa24..0000000
--- a/chill/include/ir_rose_utils.hh
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef IR_ROSE_UTILS_HH
-#define IR_ROSE_UTILS_HH
-
-/*!
- * \file
- * \brief ROSE interface utilities
- */
-#include <vector>
-#include <rose.h>
-#include <sageBuilder.h>
-
-std::vector<SgForStatement *> find_deepest_loops(SgNode *tnl);
-std::vector<SgForStatement *> find_loops(SgNode *tnl);
-
-SgNode* loop_body_at_level(SgNode* tnl, int level);
-SgNode* loop_body_at_level(SgForStatement* loop, int level);
-void swap_node_for_node_list(SgNode* tn, SgNode* new_tnl);
-
-#endif
diff --git a/chill/include/irtools.hh b/chill/include/irtools.hh
deleted file mode 100644
index a3b552a..0000000
--- a/chill/include/irtools.hh
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef IRTOOLS_HH
-#define IRTOOLS_HH
-
-/*!
- * \file
- * \brief Useful tools to analyze code in compiler IR format.
- */
-
-#include <vector>
-#include <omega.h>
-#include <code_gen/CG_outputRepr.h>
-#include "ir_code.hh"
-#include "dep.hh"
-
-//! It is used to initialize a loop.
-struct ir_tree_node {
-  IR_Control *content;
-  ir_tree_node *parent;
-  std::vector<ir_tree_node *> children;
-/*! 
- * * For a loop node, payload is its mapped iteration space dimension. 
- * * For a simple block node, payload is its mapped statement number. 
- * * Normal if-else is splitted into two nodes
- *   * the one with odd payload represents then-part and
- *   * the one with even payload represents else-part.
- */
-  int payload;
-  
-  ~ir_tree_node() {
-    for (int i = 0; i < children.size(); i++)
-      delete children[i];
-    delete content;
-  }
-};
-
-std::vector<ir_tree_node *> build_ir_tree(IR_Control *control,
-                                          ir_tree_node *parent = NULL);
-std::vector<ir_tree_node *> extract_ir_stmts(
-  const std::vector<ir_tree_node *> &ir_tree);
-bool is_dependence_valid(ir_tree_node *src_node, ir_tree_node *dst_node,
-                         const DependenceVector &dv, bool before);
-std::pair<std::vector<DependenceVector>, std::vector<DependenceVector> > test_data_dependences(
-  IR_Code *ir, const omega::CG_outputRepr *repr1,
-  const omega::Relation &IS1, const omega::CG_outputRepr *repr2,
-  const omega::Relation &IS2, std::vector<omega::Free_Var_Decl*> &freevar,
-  std::vector<std::string> index, int i, int j);
-
-#endif
diff --git a/chill/include/loop.hh b/chill/include/loop.hh
deleted file mode 100644
index 9620489..0000000
--- a/chill/include/loop.hh
+++ /dev/null
@@ -1,200 +0,0 @@
-#ifndef LOOP_HH
-#define LOOP_HH
-
-/*!
- * \file 
- * \brief Core loop transformation functionality.
- *
- * "level" (starting from 1) means loop level and it corresponds to "dim"
- * (starting from 0) in transformed iteration space [c_1,l_1,c_2,l_2,....,
- * c_n,l_n,c_(n+1)], e.g., l_2 is loop level 2 in generated code, dim 3
- * in transformed iteration space, and variable 4 in Omega relation.
- * All c's are constant numbers only and they will not show up as actual loops.
- * 
- * Formula:
- *
- * ~~~
- *   dim = 2*level - 1
- *   var = dim + 1
- * ~~~
- */
- 
-
-#include <omega.h>
-#include <code_gen/codegen.h>
-#include <code_gen/CG.h>
-#include <vector>
-#include <map>
-#include <set>
-#include "dep.hh"
-#include "ir_code.hh"
-#include "irtools.hh"
-
-class IR_Code;
-
-enum TilingMethodType { StridedTile, CountedTile };
-enum LoopLevelType { LoopLevelOriginal, LoopLevelTile, LoopLevelUnknown };
-
-
-//! Describes properties of each loop level of a statement. 
-struct LoopLevel {
-  LoopLevelType type;
-/*! 
- * For LoopLevelOriginal means iteration space dimension 
- * For LoopLevelTile means tiled loop level. Special value -1 for
- * LoopLevelTile means purely derived loop. For dependence dimension
- * payloads, the values must be in an increasing order.
- */
-  int payload;  
-/*!
- * Used by code generation to support
- * multi-level parallelization (default 0 means sequential loop under
- * the current parallelization level).
- */
-  int parallel_level;
-};
-
-struct Statement {
-  omega::CG_outputRepr *code;
-  omega::Relation IS;
-  omega::Relation xform;
-  std::vector<LoopLevel> loop_level;
-  ir_tree_node *ir_stmt_node;
-  //protonu--temporarily putting this back here
-  //omega::Tuple<int> nonSplitLevels;
-  //end--protonu.
-};
-
-
-class Loop {
-protected:
-  int tmp_loop_var_name_counter;
-  static const std::string tmp_loop_var_name_prefix;
-  int overflow_var_name_counter;
-  static const std::string overflow_var_name_prefix;
-  std::vector<int> stmt_nesting_level_;
-  std::vector<std::string> index;
-  std::map<int, omega::CG_outputRepr *> replace;
-  
-public:
-  IR_Code *ir;
-  std::vector<omega::Free_Var_Decl*> freevar;
-  std::vector<Statement> stmt;
-  std::vector<ir_tree_node *> ir_stmt;
-  std::vector<ir_tree_node *> ir_tree;
-  DependenceGraph dep;
-  int num_dep_dim;
-  omega::Relation known;
-  omega::CG_outputRepr *init_code;
-  omega::CG_outputRepr *cleanup_code;
-  std::map<int, std::vector<omega::Free_Var_Decl *> > overflow;
-  
-  
-protected:
-  mutable omega::CodeGen *last_compute_cg_;
-  mutable omega::CG_result *last_compute_cgr_;
-  mutable int last_compute_effort_;
-  
-protected:
-  bool init_loop(std::vector<ir_tree_node *> &ir_tree, std::vector<ir_tree_node *> &ir_stmt);
-  int get_dep_dim_of(int stmt, int level) const;
-  int get_last_dep_dim_before(int stmt, int level) const;
-  std::vector<omega::Relation> getNewIS() const;
-  omega::Relation getNewIS(int stmt_num) const;
-  std::vector<int> getLexicalOrder(int stmt_num) const;
-  int getLexicalOrder(int stmt_num, int level) const;
-  std::set<int> getStatements(const std::vector<int> &lex, int dim) const;
-  void shiftLexicalOrder(const std::vector<int> &lex, int dim, int amount);
-  void setLexicalOrder(int dim, const std::set<int> &active, int starting_order = 0, std::vector< std::vector<std::string> >idxNames= std::vector< std::vector<std::string> >());
-  void apply_xform(int stmt_num);
-  void apply_xform(std::set<int> &active);
-  void apply_xform();
-  std::set<int> getSubLoopNest(int stmt_num, int level) const;
-  
-  
-public:
-  Loop() { ir = NULL; tmp_loop_var_name_counter = 1; init_code = NULL; }
-  Loop(const IR_Control *control);
-  ~Loop();
-  
-  omega::CG_outputRepr *getCode(int effort = 1) const;
-  void printCode(int effort = 1) const;
-  void addKnown(const omega::Relation &cond);
-  void print_internal_loop_structure() const;
-  bool isInitialized() const;
-  int num_statement() const { return stmt.size(); }
-  void printIterationSpace() const;
-  void printDependenceGraph() const;
-  void removeDependence(int stmt_num_from, int stmt_num_to);
-  void dump() const;
-  
-  std::vector<std::set <int > > sort_by_same_loops(std::set<int > active, int level);
-  //
-  //! legacy unimodular transformations for perfectly nested loops
-  /*!
-   * e.g. \f$M*(i,j)^T = (i',j')^T or M*(i,j,1)^T = (i',j')^T\f$
-   */
-  bool nonsingular(const std::vector<std::vector<int> > &M);
-  
-  /*!
-   * \defgroup hltrans High-level loop transformations
-   * @{
-   */
-  void permute(const std::set<int> &active, const std::vector<int> &pi);
-  void permute(int stmt_num, int level, const std::vector<int> &pi);
-  void permute(const std::vector<int> &pi);
-  void original();
-  
-  void tile(int stmt_num, int level, int tile_size, int outer_level = 1, TilingMethodType method = StridedTile, int alignment_offset = 0, int alignment_multiple = 1);
-  std::set<int> split(int stmt_num, int level, const omega::Relation &cond);
-  std::set<int> unroll(int stmt_num, int level, int unroll_amount, std::vector< std::vector<std::string> >idxNames= std::vector< std::vector<std::string> >(), int cleanup_split_level = 0);
-  
-  bool datacopy(const std::vector<std::pair<int, std::vector<int> > > &array_ref_nums, int level, bool allow_extra_read = false, int fastest_changing_dimension = -1, int padding_stride = 1, int padding_alignment = 4, int memory_type = 0);
-  bool datacopy(int stmt_num, int level, const std::string &array_name, bool allow_extra_read = false, int fastest_changing_dimension = -1, int padding_stride = 1, int padding_alignment = 4, int memory_type = 0);
-  bool datacopy_privatized(int stmt_num, int level, const std::string &array_name, const std::vector<int> &privatized_levels, bool allow_extra_read = false, int fastest_changing_dimension = -1, int padding_stride = 1, int padding_alignment = 1, int memory_type = 0);
-  bool datacopy_privatized(const std::vector<std::pair<int, std::vector<int> > > &array_ref_nums, int level, const std::vector<int> &privatized_levels, bool allow_extra_read = false, int fastest_changing_dimension = -1, int padding_stride = 1, int padding_alignment = 1, int memory_type = 0);
-  bool datacopy_privatized(const std::vector<std::pair<int, std::vector<IR_ArrayRef *> > > &stmt_refs, int level, const std::vector<int> &privatized_levels, bool allow_extra_read, int fastest_changing_dimension, int padding_stride, int padding_alignment, int memory_type = 0);
-  
-  
-  Graph<std::set<int>, bool> construct_induced_graph_at_level(std::vector<std::set<int> > s, DependenceGraph dep, int dep_dim);
-  std::vector<std::set<int> > typed_fusion(Graph<std::set<int>, bool> g);
-  void fuse(const std::set<int> &stmt_nums, int level);
-  void distribute(const std::set<int> &stmt_nums, int level);
-  void skew(const std::set<int> &stmt_nums, int level, const std::vector<int> &skew_amount);
-  void shift(const std::set<int> &stmt_nums, int level, int shift_amount);
-  void scale(const std::set<int> &stmt_nums, int level, int scale_amount);
-  void reverse(const std::set<int> &stmt_nums, int level);
-  void peel(int stmt_num, int level, int peel_amount = 1);
-  /*!
-   * \defgroup hlfancy fancy loop transformations
-   * @{
-   */
-  void modular_shift(int stmt_num, int level, int shift_amount) {}
-  void diagonal_map(int stmt_num, const std::pair<int, int> &levels, int offset) {}
-  void modular_partition(int stmt_num, int level, int stride) {}
-  /*! @} */
-  
-  /*! 
-   * \defgroup hlderived derived loop transformations
-   * @{
-   */
-
-  void shift_to(int stmt_num, int level, int absolute_position);
-  std::set<int> unroll_extra(int stmt_num, int level, int unroll_amount, int cleanup_split_level = 0);
-  bool is_dependence_valid_based_on_lex_order(int i, int j,
-			const DependenceVector &dv, bool before);
-  /*! @} */
-
-  /*! 
-   * \defgroup hlother other public operations
-   * @{
-   */
-  void pragma(int stmt_num, int level, const std::string &pragmaText);
-  void prefetch(int stmt_num, int level, const std::string &arrName, int hint);
-  /*! @} */
-
-  /*! @} */
-};
-
-
-#endif
diff --git a/chill/include/omegatools.hh b/chill/include/omegatools.hh
deleted file mode 100644
index b51b2bd..0000000
--- a/chill/include/omegatools.hh
+++ /dev/null
@@ -1,93 +0,0 @@
-#ifndef OMEGATOOLS_HH
-#define OMEGATOOLS_HH
-
-/*!
- * \file
- * \brief Useful tools involving Omega manipulation.
- */
-
-#include <string>
-#include <omega.h>
-#include "dep.hh"
-#include "ir_code.hh"
-
-std::string tmp_e();
-
-//! Convert expression tree to omega relation.
-/*!
- * \param destroy shallow deallocation of "repr", not freeing the actual code inside.
- */
-void exp2formula(IR_Code *ir, omega::Relation &r, omega::F_And *f_root,
-                 std::vector<omega::Free_Var_Decl *> &freevars,
-                 omega::CG_outputRepr *repr, omega::Variable_ID lhs, char side,
-                 IR_CONDITION_TYPE rel, bool destroy);
-
-//! Build dependence relation for two array references.
-omega::Relation arrays2relation(IR_Code *ir, std::vector<omega::Free_Var_Decl*> &freevars,
-                                const IR_ArrayRef *ref_src, const omega::Relation &IS_w,
-                                const IR_ArrayRef *ref_dst, const omega::Relation &IS_r);
-//! Convert array dependence relation into set of dependence vectors
-/*!
- * assuming ref_w is lexicographically before ref_r in the source code.
- */
-std::pair<std::vector<DependenceVector>, std::vector<DependenceVector> > relation2dependences(
-  const IR_ArrayRef *ref_src, const IR_ArrayRef *ref_dst, const omega::Relation &r);
-
-//! Convert a boolean expression to omega relation.  
-/*!
- * \param destroy shallow deallocation of "repr", not freeing the actual code inside.
- */
-void exp2constraint(IR_Code *ir, omega::Relation &r, omega::F_And *f_root,
-                    std::vector<omega::Free_Var_Decl *> &freevars,
-                    omega::CG_outputRepr *repr, bool destroy);
-
-bool is_single_iteration(const omega::Relation &r, int dim);
-//!  Set/get the value of a variable which is know to be constant.
-void assign_const(omega::Relation &r, int dim, int val);
-
-int get_const(const omega::Relation &r, int dim, omega::Var_Kind type);
-
-//! Find the position index variable in a Relation by name.
-omega::Variable_ID find_index(omega::Relation &r, const std::string &s, char side);
-
-//! Generate mapping relation for permuation.
-omega::Relation permute_relation(const std::vector<int> &pi);
-
-omega::Relation get_loop_bound(const omega::Relation &r, int dim);
-
-//!  Determine whether the loop (starting from 0) in the iteration space has only one iteration.
-bool is_single_loop_iteration(const omega::Relation &r, int level, const omega::Relation &known);
-//! Get the bound for a specific loop.
-omega::Relation get_loop_bound(const omega::Relation &r, int level, const omega::Relation &known);
-omega::Relation get_max_loop_bound(const std::vector<omega::Relation> &r, int dim);
-omega::Relation get_min_loop_bound(const std::vector<omega::Relation> &r, int dim);
-
-//! Add strident to a loop.
-/*!
- * Issues:
- *
- * * Don't work with relations with multiple disjuncts.
- * * Omega's dealing with max lower bound is awkward.
- */
-void add_loop_stride(omega::Relation &r, const omega::Relation &bound, int dim, int stride);
-bool is_inner_loop_depend_on_level(const omega::Relation &r, int level, const omega::Relation &known);
-/*!
- * Suppose loop dim is i. Replace i with i+adjustment in loop bounds.
- *
- * ~~~
- * do i = 1, n
- *   do j = i, n
- * ~~~
- *  
- *  after call with dim = 0 and adjustment = 1:
- *
- * ~~~
- * do i = 1, n
- *   do j = i+1, n
- * ~~~
- */
-omega::Relation adjust_loop_bound(const omega::Relation &r, int level, int adjustment);
-
-enum LexicalOrderType {LEX_MATCH, LEX_BEFORE, LEX_AFTER, LEX_UNKNOWN};
-
-#endif
diff --git a/chill/src/chill_run.cc b/chill/src/chill_run.cc
deleted file mode 100644
index 4eafe65..0000000
--- a/chill/src/chill_run.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-#include "chilldebug.h"
-
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-
-#include "loop.hh"
-#include <omega.h>
-#include "ir_code.hh"
-#include "ir_rose.hh"
-
-#include "chillmodule.hh" // Python wrapper functions for CHiLL
-
-//---
-// CHiLL globals
-//---
-Loop *myloop = NULL;
-IR_Code *ir_code = NULL;
-bool repl_stop = false;
-bool is_interactive = false;
-
-std::vector<IR_Control *> ir_controls;
-std::vector<int> loops;
-
-//---
-// CHiLL program main
-// Initialize state and run script or interactive mode
-//---
-int main( int argc, char* argv[] )
-{
-  DEBUG_PRINT("%s  main()\n", argv[0]);
-  if (argc > 2) {
-    fprintf(stderr, "Usage: %s [script_file]\n", argv[0]);
-    exit(-1);
-  }
-  
-  int fail = 0;
-  
-  // Create PYTHON interpreter
-  /* Pass argv[0] to the Python interpreter */
-  Py_SetProgramName(argv[0]);
-  
-  /* Initialize the Python interpreter.  Required. */
-  Py_Initialize();
-  
-  /* Add a static module */
-  initchill();
-  
-  if (argc == 2) {
-    FILE* f = fopen(argv[1], "r");
-    if(!f){
-      printf("can't open script file \"%s\"\n", argv[1]);
-      exit(-1);
-    }
-    PyRun_SimpleFile(f, argv[1]);
-    fclose(f);
-  }
-  if (argc == 1) {
-    //---
-    // Run a CHiLL interpreter
-    //---
-    printf("CHiLL v" CHILL_BUILD_VERSION " (built on " CHILL_BUILD_DATE ")\n");
-    printf("Copyright (C) 2008 University of Southern California\n");
-    printf("Copyright (C) 2009-2012 University of Utah\n");
-    //is_interactive = true; // let the lua interpreter know.
-    fflush(stdout);
-    // TODO: read lines of python code.
-    //Not sure if we should set fail from interactive mode
-    printf("CHiLL ending...\n");
-    fflush(stdout);
-  }
-
-  //printf("DONE with PyRun_SimpleString()\n");
-  
-  if (!fail && ir_code != NULL && myloop != NULL && myloop->stmt.size() != 0 && !myloop->stmt[0].xform.is_null()) {
-    int lnum_start;
-    int lnum_end;
-    lnum_start = get_loop_num_start();
-    lnum_end = get_loop_num_end();
-    DEBUG_PRINT("calling ROSE code gen?    loop num %d\n", lnum);
-    finalize_loop(lnum_start, lnum_end);
-    ((IR_roseCode*)(ir_code))->finalizeRose();
-    delete ir_code;
-  }
-  Py_Finalize();
-  return 0;
-}
diff --git a/chill/src/chill_run_util.cc b/chill/src/chill_run_util.cc
deleted file mode 100644
index 29568e7..0000000
--- a/chill/src/chill_run_util.cc
+++ /dev/null
@@ -1,120 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include "chill_run_util.hh"
-
-static std::string to_string(int ival) {
-  char buffer[4];
-  sprintf(buffer, "%d", ival);
-  return std::string(buffer);
-}
-
-simap_vec_t* make_prog(simap_vec_t* cond) {
-  return cond;
-}
-
-simap_vec_t* make_cond_gt(simap_t* lhs, simap_t* rhs) {
-  simap_vec_t* nvec = new simap_vec_t();
-  for(simap_t::iterator it = rhs->begin(); it != rhs->end(); it++)
-    (*lhs)[it->first] -= it->second;
-  (*lhs)[to_string(0)] -= 1;
-  nvec->push_back(*lhs);
-  delete rhs;
-  delete lhs;
-  return nvec;
-}
-
-simap_vec_t* make_cond_lt(simap_t* lhs, simap_t* rhs) {
-  return make_cond_gt(rhs, lhs);
-}
-
-simap_vec_t* make_cond_ge(simap_t* lhs, simap_t* rhs) {
-  simap_vec_t* nvec = new simap_vec_t();
-  for(simap_t::iterator it = rhs->begin(); it != rhs->end(); it++)
-    (*lhs)[it->first] -= it->second;
-  nvec->push_back(*lhs);
-  delete rhs;
-  delete lhs;
-  return nvec;
-}
-
-simap_vec_t* make_cond_le(simap_t* lhs, simap_t* rhs) {
-  return make_cond_ge(rhs, lhs);
-}
-
-simap_vec_t* make_cond_eq(simap_t* lhs, simap_t* rhs) {
-  simap_vec_t* nvec = new simap_vec_t();
-  for(simap_t::iterator it = lhs->begin(); it != lhs->end(); it++)
-    (*rhs)[it->first] -= it->second;
-  nvec->push_back(*rhs);
-  for(simap_t::iterator it = rhs->begin(); it != rhs->end(); it++)
-    it->second = -it->second;
-  nvec->push_back(*rhs);
-  delete rhs;
-  delete lhs;
-  return nvec;
-}
-
-simap_t* make_cond_item_add(simap_t* lhs, simap_t* rhs) {
-  for(simap_t::iterator it = lhs->begin(); it != lhs->end(); it++)
-    (*rhs)[it->first] += it->second;
-  delete lhs;
-  return rhs;
-}
-
-simap_t* make_cond_item_sub(simap_t* lhs, simap_t* rhs) {
-  for(simap_t::iterator it = lhs->begin(); it != lhs->end(); it++)
-    (*rhs)[it->first] -= it->second;
-  delete lhs;
-  return rhs;
-}
-
-simap_t* make_cond_item_mul(simap_t* lhs, simap_t* rhs) {
-  (*lhs)[to_string(0)] += 0;
-  (*rhs)[to_string(0)] += 0;
-  if(rhs->size() == 1) {
-    int t = (*rhs)[to_string(0)];
-    for(simap_t::iterator it = lhs->begin(); it != lhs->end(); it++)
-      it->second *= t;
-    delete rhs;
-    return lhs;
-  }
-  else if(rhs->size() == 1) {
-    int t = (*lhs)[to_string(0)];
-    for(simap_t::iterator it = rhs->begin(); it != rhs->end(); it++)
-      it->second *= t;
-    delete lhs;
-    return rhs;
-  }
-  else {
-    fprintf(stderr, "require Presburger formula");
-    delete lhs;
-    delete rhs;
-    // exit(2); <-- this may be a boost feature
-  }
-}
-
-simap_t* make_cond_item_neg(simap_t* expr) {
-  for (simap_t::iterator it = expr->begin(); it != expr->end(); it++) {
-    it->second = -(it->second);
-  }
-  return expr;
-}
-
-simap_t* make_cond_item_number(int n) {
-  simap_t* nmap = new simap_t();
-  (*nmap)[to_string(0)] = n;
-  return nmap;
-}
-
-simap_t* make_cond_item_variable(const char* var) {
-  simap_t* nmap = new simap_t();
-  (*nmap)[std::string(var)] = 1;
-  return nmap;
-}
-
-simap_t* make_cond_item_level(int n) {
-  simap_t* nmap = new simap_t();
-  (*nmap)[to_string(n)] = 1;
-  return nmap;
-}
-
diff --git a/chill/src/chillmodule.cc b/chill/src/chillmodule.cc
deleted file mode 100644
index 0e41f88..0000000
--- a/chill/src/chillmodule.cc
+++ /dev/null
@@ -1,795 +0,0 @@
-#include "chilldebug.h"
-
-#include "chill_run_util.hh"
-
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <omega.h>
-#include "loop.hh"
-#include "ir_code.hh"
-#include "ir_rose.hh"
-
-#include "chillmodule.hh"
-
-using namespace omega;
-
-extern Loop *myloop;
-extern IR_Code *ir_code;
-extern bool is_interactive;
-extern bool repl_stop;
-
-std::string procedure_name;
-std::string source_filename;
-
-int loop_start_num;
-int loop_end_num;
-
-extern std::vector<IR_Control *> ir_controls;
-extern std::vector<int> loops;
-
-// ----------------------- //
-// CHiLL support functions //
-// ----------------------- //
-// not sure yet if this actually needs to be exposed to the python interface
-// these four functions are here to maintain similarity to the Lua interface
-int get_loop_num_start() {
-  return loop_start_num;
-}
-
-int get_loop_num_end() {
-  return loop_end_num;
-}
-
-static void set_loop_num_start(int start_num) {
-  loop_start_num = start_num;
-}
-
-static void set_loop_num_end(int end_num) {
-  loop_end_num = end_num;
-}
-
-// TODO: finalize_loop(int,int) and init_loop(int,int) are identical to thier Lua counterparts.
-// consider integrating them
-
-void finalize_loop(int loop_num_start, int loop_num_end) {
-  if (loop_num_start == loop_num_end) {
-    ir_code->ReplaceCode(ir_controls[loops[loop_num_start]], myloop->getCode());
-    ir_controls[loops[loop_num_start]] = NULL;
-  }
-  else {
-    std::vector<IR_Control *> parm;
-    for (int i = loops[loop_num_start]; i <= loops[loop_num_end]; i++)
-      parm.push_back(ir_controls[i]);
-    IR_Block *block = ir_code->MergeNeighboringControlStructures(parm);
-    ir_code->ReplaceCode(block, myloop->getCode());
-    for (int i = loops[loop_num_start]; i <= loops[loop_num_end]; i++) {
-      delete ir_controls[i];
-      ir_controls[i] = NULL;
-    }
-  }
-  delete myloop;
-}
-void finalize_loop() {
-  int loop_num_start = get_loop_num_start();
-  int loop_num_end = get_loop_num_end();
-  finalize_loop(loop_num_start, loop_num_end);
-}
-static void init_loop(int loop_num_start, int loop_num_end) {
-  if (source_filename.empty()) {
-    fprintf(stderr, "source file not set when initializing the loop");
-    if (!is_interactive)
-      exit(2);
-  }
-  else {
-    if (ir_code == NULL) {
-      if (procedure_name.empty())
-        procedure_name = "main";
-        
-      ir_code = new IR_roseCode(source_filename.c_str(), procedure_name.c_str());
-          
-      IR_Block *block = ir_code->GetCode();
-      ir_controls = ir_code->FindOneLevelControlStructure(block);
-      for (int i = 0; i < ir_controls.size(); i++) {
-        if (ir_controls[i]->type() == IR_CONTROL_LOOP)
-          loops.push_back(i);
-      }
-      delete block;
-    }
-    if (myloop != NULL && myloop->isInitialized()) {
-       finalize_loop();
-    }
-  }
-  set_loop_num_start(loop_num_start);
-  set_loop_num_end(loop_num_end);
-  if (loop_num_end < loop_num_start) {
-    fprintf(stderr, "the last loop must be after the start loop");
-    if (!is_interactive)
-      exit(2);
-  }              
-  if (loop_num_end >= loops.size()) {
-    fprintf(stderr, "loop %d does not exist", loop_num_end);
-    if (!is_interactive)
-      exit(2);
-  }
-  std::vector<IR_Control *> parm;
-  for (int i = loops[loop_num_start]; i <= loops[loop_num_end]; i++) {
-    if (ir_controls[i] == NULL) {
-      fprintf(stderr, "loop has already been processed");
-      if (!is_interactive)
-        exit(2);
-    }
-    parm.push_back(ir_controls[i]);
-  }
-  IR_Block *block = ir_code->MergeNeighboringControlStructures(parm);
-  myloop = new Loop(block);
-  delete block;  
-  //if (is_interactive) printf("%s ", PROMPT_STRING);
-}
-
-// ----------------------- //
-// Python support funcions //
-// ----------------------- //
-
-// -- CHiLL support -- //
-static void strict_arg_num(PyObject* args, int arg_num, const char* fname = NULL) {
-  int arg_given = PyTuple_Size(args);
-  char msg[128];
-  if(arg_num != arg_given) {
-    if(fname)
-      sprintf(msg, "%s: expected %i arguments, was given %i.", fname, arg_num, arg_given);
-    else
-      sprintf(msg, "Expected %i argumets, was given %i.", arg_num, arg_given);
-    throw std::runtime_error(msg);
-  }
-}
-
-static int strict_arg_range(PyObject* args, int arg_min, int arg_max, const char* fname = NULL) {
-  int arg_given = PyTuple_Size(args);
-  char msg[128];
-  if(arg_given < arg_min || arg_given > arg_max) {
-    if(fname)
-      sprintf(msg, "%s: expected %i to %i arguments, was given %i.", fname, arg_min, arg_max, arg_given);
-    else
-      sprintf(msg, "Expected %i to %i, argumets, was given %i.", arg_min, arg_max, arg_given);
-    throw std::runtime_error(msg);
-  }
-  return arg_given;
-}
-
-static int intArg(PyObject* args, int index, int dval = 0) {
-  if(PyTuple_Size(args) <= index)
-    return dval; 
-  int ival;
-  PyObject *item = PyTuple_GetItem(args, index); 
-  Py_INCREF(item);
-  if (PyInt_Check(item)) ival = PyInt_AsLong(item);
-  else {
-    fprintf(stderr, "argument at index %i is not an int\n", index);
-    exit(-1);
-  }
-  return ival;
-}
-
-static std::string strArg(PyObject* args, int index, const char* dval = NULL) {
-  if(PyTuple_Size(args) <= index)
-    return dval;
-  std::string strval;
-  PyObject *item = PyTuple_GetItem(args, index); 
-  Py_INCREF(item);
-  if (PyString_Check(item)) strval = strdup(PyString_AsString(item));
-  else {
-    fprintf(stderr, "argument at index %i is not an string\n", index);
-    exit(-1);
-  }
-  return strval;
-}
-
-static bool boolArg(PyObject* args, int index, bool dval = false) {
-  if(PyTuple_Size(args) <= index)
-    return dval;
-  bool bval;
-  PyObject* item = PyTuple_GetItem(args, index);
-  Py_INCREF(item);
-  return (bool)PyObject_IsTrue(item);
-}
-
-static bool tostringintmapvector(PyObject* args, int index, std::vector<std::map<std::string,int> >& vec) {
-  if(PyTuple_Size(args) <= index)
-    return false;
-  PyObject* seq = PyTuple_GetItem(args, index);
-  //TODO: Typecheck
-  int seq_len = PyList_Size(seq);
-  for(int i = 0; i < seq_len; i++) {
-    std::map<std::string,int> map;
-    PyObject* dict = PyList_GetItem(seq, i);
-    PyObject* keys = PyDict_Keys(dict);
-    //TODO: Typecheck
-    int dict_len = PyList_Size(keys);
-    for(int j = 0; j < dict_len; j++) {
-      PyObject* key = PyList_GetItem(keys, j);
-      PyObject* value = PyDict_GetItem(dict, key);
-      std::string str_key = strdup(PyString_AsString(key));
-      int int_value = PyInt_AsLong(value);
-      map[str_key] = int_value;
-    }
-    vec.push_back(map);
-  }
-  return true;
-}
-
-static bool tointvector(PyObject* seq, std::vector<int>& vec) {
-  //TODO: Typecheck
-  int seq_len = PyList_Size(seq);
-  for(int i = 0; i < seq_len; i++) {
-    PyObject* item = PyList_GetItem(seq, i);
-    vec.push_back(PyInt_AsLong(item));
-  }
-  return true;
-}
-
-static bool tointvector(PyObject* args, int index, std::vector<int>& vec) {
-  if(PyTuple_Size(args) <= index)
-    return false;
-  PyObject* seq = PyTuple_GetItem(args, index);
-  return tointvector(seq, vec);
-}
-
-static bool tointset(PyObject* args, int index, std::set<int>& set) {
-  if(PyTuple_Size(args) <= index)
-    return false;
-  PyObject* seq = PyTuple_GetItem(args, index);
-  //TODO: Typecheck
-  int seq_len = PyList_Size(seq);
-  for(int i = 0; i < seq_len; i++) {
-    PyObject* item = PyList_GetItem(seq, i);
-    set.insert(PyInt_AsLong(item));
-  }
-  return true;
-}
-static bool tointmatrix(PyObject* args, int index, std::vector<std::vector<int> >& mat) {
-  if(PyTuple_Size(args) <= index)
-    return false;
-  PyObject* seq_one = PyTuple_GetItem(args, index);
-  int seq_one_len = PyList_Size(seq_one);
-  for(int i = 0; i < seq_one_len; i++) {
-    std::vector<int> vec;
-    PyObject* seq_two = PyList_GetItem(seq_one, i);
-    int seq_two_len = PyList_Size(seq_two);
-    for(int j = 0; j < seq_two_len; j++) {
-      PyObject* item = PyList_GetItem(seq_two, j);
-      vec.push_back(PyInt_AsLong(item));
-    }
-    mat.push_back(vec);
-  }
-  return true;
-}
-
-// ------------------------- //
-// CHiLL interface functions //
-// ------------------------- //
-
-static PyObject* chill_source(PyObject* self, PyObject* args) {
-  strict_arg_num(args, 1, "source");
-  source_filename = strArg(args, 0);
-  Py_RETURN_NONE;
-}
-
-static PyObject* chill_procedure(PyObject* self, PyObject* args) {
-  if(!procedure_name.empty()) {
-    fprintf(stderr, "only one procedure can be handled in a script");
-    if(!is_interactive)
-      exit(2);
-  }
-  procedure_name = strArg(args, 0);
-  Py_RETURN_NONE;
-}
-
-static PyObject* chill_loop(PyObject* self, PyObject* args) {
-  // loop (n)
-  // loop (n:m)
-  
-  int nargs = PyTuple_Size(args);
-  int start_num;
-  int end_num;
-  if(nargs == 1) {
-    start_num = intArg(args, 0);
-    end_num = start_num;
-  }
-  else if(nargs == 2) {
-    start_num = intArg(args, 0);
-    end_num = intArg(args, 1);
-  }
-  else {
-    fprintf(stderr, "loop takes one or two arguments");
-    if(!is_interactive)
-      exit(2);
-  }
-  set_loop_num_start(start_num);
-  set_loop_num_end(end_num);
-  init_loop(start_num, end_num);
-  Py_RETURN_NONE;
-}
-
-static PyObject* chill_print_code(PyObject* self, PyObject* args) {
-  strict_arg_num(args, 0, "print_code");
-  myloop->printCode();
-  printf("\n");
-  Py_RETURN_NONE;
-}
-
-static PyObject* chill_print_dep(PyObject* self, PyObject* args) {
-  strict_arg_num(args, 0, "print_dep");
-  myloop->printDependenceGraph();
-  Py_RETURN_NONE;
-}
-
-static PyObject* chill_print_space(PyObject* self, PyObject* args) {
-  strict_arg_num(args, 0, "print_space");
-  myloop->printIterationSpace();
-  Py_RETURN_NONE;
-}
-
-static PyObject* chill_exit(PyObject* self, PyObject* args) {
-  strict_arg_num(args, 0, "exit");
-  repl_stop = true;
-  Py_RETURN_NONE;
-}
-
-static void add_known(std::string cond_expr) {
-  int num_dim = myloop->known.n_set();
-  std::vector<std::map<std::string, int> >* cond;
-  // TODO since we are using python, change this!
-  cond = parse_relation_vector(cond_expr.c_str());
-  
-  Relation rel(num_dim);
-  F_And *f_root = rel.add_and();
-  for (int j = 0; j < cond->size(); j++) {
-    GEQ_Handle h = f_root->add_GEQ();
-    for (std::map<std::string, int>::iterator it = (*cond)[j].begin(); it != (*cond)[j].end(); it++) {
-      try {
-        int dim = from_string<int>(it->first);
-        if (dim == 0)
-          h.update_const(it->second);
-        else
-          throw std::invalid_argument("only symbolic variables are allowed in known condition");
-      }
-      catch (std::ios::failure e) {
-        Free_Var_Decl *g = NULL;
-        for (unsigned i = 0; i < myloop->freevar.size(); i++) {
-          std::string name = myloop->freevar[i]->base_name();
-          if (name == it->first) {
-            g = myloop->freevar[i];
-            break;
-          }
-        }
-        if (g == NULL)
-          throw std::invalid_argument("symbolic variable " + it->first + " not found");
-        else
-          h.update_coef(rel.get_local(g), it->second);
-      }
-    }
-  }
-  myloop->addKnown(rel);
-}
-
-static PyObject* chill_known(PyObject* self, PyObject* args) {
-  strict_arg_num(args, 1, "known");
-  if (PyList_Check(PyTuple_GetItem(args, 0))) {
-    PyObject* list = PyTuple_GetItem(args, 0);
-    for (int i = 0; i < PyList_Size(list); i++) {
-      add_known(std::string(PyString_AsString(PyList_GetItem(list, i))));
-    }
-  }
-  else {
-    add_known(strArg(args, 0));
-  }
-  Py_RETURN_NONE;
-}
-
-static PyObject* chill_remove_dep(PyObject* self, PyObject* args) {
-  strict_arg_num(args, 0, "remove_dep");
-  int from = intArg(args, 0);
-  int to = intArg(args, 1);
-  myloop->removeDependence(from, to);
-  Py_RETURN_NONE;
-}
-
-static PyObject* chill_original(PyObject* self, PyObject* args) {
-  strict_arg_num(args, 0, "original");
-  myloop->original();
-  Py_RETURN_NONE;
-}
-
-static PyObject* chill_permute(PyObject* self, PyObject* args) {
-  int nargs = strict_arg_range(args, 1, 3, "permute");
-  if((nargs < 1) || (nargs > 3))
-    throw std::runtime_error("incorrect number of arguments in permute");
-  if(nargs == 1) {
-    // premute ( vector )
-     std::vector<int> pi;
-    if(!tointvector(args, 0, pi))
-      throw std::runtime_error("first arg in permute(pi) must be an int vector");
-    myloop->permute(pi);
-  }
-  else if (nargs == 2) {
-    // permute ( set, vector )
-    std::set<int> active;
-    std::vector<int> pi;
-    if(!tointset(args, 0, active))
-      throw std::runtime_error("the first argument in permute(active, pi) must be an int set");
-    if(!tointvector(args, 1, pi))
-      throw std::runtime_error("the second argument in permute(active, pi) must be an int vector");
-     myloop->permute(active, pi);
-  }
-  else if (nargs == 3) {
-    int stmt_num = intArg(args, 1);
-    int level = intArg(args, 2);
-    std::vector<int> pi;
-    if(!tointvector(args, 3, pi))
-      throw std::runtime_error("the third argument in permute(stmt_num, level, pi) must be an int vector");
-    myloop->permute(stmt_num, level, pi);
-  }
-  Py_RETURN_NONE;
-}
-
-static PyObject* chill_pragma(PyObject* self, PyObject* args) {
-  strict_arg_num(args, 3, "pragma");
-  int stmt_num = intArg(args, 1);
-  int level = intArg(args, 1);
-  std::string pragmaText = strArg(args, 2);
-  myloop->pragma(stmt_num, level, pragmaText);
-  Py_RETURN_NONE;
-}
-
-static PyObject* chill_prefetch(PyObject* self, PyObject* args) {
-  strict_arg_num(args, 3, "prefetch");
-  int stmt_num = intArg(args, 0);
-  int level = intArg(args, 1);
-  std::string prefetchText = strArg(args, 2);
-  int hint = intArg(args, 3);
-  myloop->prefetch(stmt_num, level, prefetchText, hint);
-  Py_RETURN_NONE;
-}
-
-static PyObject* chill_tile(PyObject* self, PyObject* args) {
-  int nargs = strict_arg_range(args, 3, 7, "tile");
-  int stmt_num = intArg(args, 0);
-  int level = intArg(args, 1);
-  int tile_size = intArg(args, 2);
-  if(nargs == 3) {
-    myloop->tile(stmt_num, level, tile_size);
-  }
-  else if(nargs >= 4) {
-    int outer_level = intArg(args, 3);
-    if(nargs >= 5) {
-      TilingMethodType method = StridedTile;
-      int imethod = intArg(args, 4, 2); //< don't know if a default value is needed
-      // check method input against expected values
-      if (imethod == 0)
-        method = StridedTile;
-      else if (imethod == 1)
-        method = CountedTile;
-      else
-        throw std::runtime_error("5th argument must be either strided or counted");
-      if(nargs >= 6) {
-        int alignment_offset = intArg(args, 5);
-        if(nargs == 7) {
-          int alignment_multiple = intArg(args, 6, 1);
-          myloop->tile(stmt_num, level, tile_size, outer_level, method, alignment_offset, alignment_multiple);
-        }
-        if(nargs == 6)
-          myloop->tile(stmt_num, level, tile_size, outer_level, method, alignment_offset);
-      }
-      if(nargs == 5)
-        myloop->tile(stmt_num, level, tile_size, outer_level, method);
-    }
-  if(nargs == 4)
-    myloop->tile(stmt_num, level, tile_size, outer_level);
-  }
-  Py_RETURN_NONE;
-}
-
-static void chill_datacopy_vec(PyObject* args) {
-  // Overload 1: bool datacopy(
-  //    const std::vector<std::pair<int, std::vector<int> > > &array_ref_nums,
-  //    int level,
-  //    bool allow_extra_read = false,
-  //    int fastest_changing_dimension = -1,
-  //    int padding_stride = 1,
-  //    int padding_alignment = 4,
-  //    int memory_type = 0);
-  std::vector<std::pair<int, std::vector<int> > > array_ref_nums;
-  // expect list(tuple(int,list(int)))
-  // or dict(int,list(int))
-  if(PyList_CheckExact(PyTuple_GetItem(args, 0))) {
-    PyObject* list = PyTuple_GetItem(args, 0);
-    for(int i = 0; i < PyList_Size(list); i ++) {
-      PyObject* tup = PyList_GetItem(list, i);
-      int index = PyLong_AsLong(PyTuple_GetItem(tup, 0));
-      std::vector<int> vec;
-      tointvector(PyTuple_GetItem(tup, 1), vec);
-      array_ref_nums.push_back(std::pair<int, std::vector<int> >(index, vec));
-    }
-  }
-  else if(PyList_CheckExact(PyTuple_GetItem(args, 0))) {
-    PyObject* dict = PyTuple_GetItem(args, 0);
-    PyObject* klist = PyDict_Keys(dict);
-    for(int ki = 0; ki < PyList_Size(klist); ki++) {
-      PyObject* index = PyList_GetItem(klist, ki);
-      std::vector<int> vec;
-      tointvector(PyDict_GetItem(dict,index), vec);
-      array_ref_nums.push_back(std::pair<int, std::vector<int> >(PyLong_AsLong(index), vec));
-    }
-    Py_DECREF(klist);
-  }
-  else {
-    //TODO: this should never happen
-  }
-  int level = intArg(args, 1);
-  bool allow_extra_read = boolArg(args, 2, false);
-  int fastest_changing_dimension = intArg(args, 3, -1);
-  int padding_stride = intArg(args, 4, 1);
-  int padding_alignment = intArg(args, 5, 4);
-  int memory_type = intArg(args, 6, 0);
-  myloop->datacopy(array_ref_nums, level, allow_extra_read, fastest_changing_dimension, padding_stride, padding_alignment, memory_type);
-}
-
-static void chill_datacopy_int(PyObject* args) {
-  int stmt_num = intArg(args, 0);
-  int level = intArg(args, 1);
-  std::string array_name = strArg(args,2,0);
-  bool allow_extra_read = boolArg(args,3,false);
-  int fastest_changing_dimension = intArg(args, 4, -1);
-  int padding_stride = intArg(args, 5, 1);
-  int padding_alignment = intArg(args, 6, 4);
-  int memory_type = intArg(args, 7, 0);
-  myloop->datacopy(stmt_num, level, array_name, allow_extra_read, fastest_changing_dimension, padding_stride, padding_alignment, memory_type);
-}
-
-static PyObject* chill_datacopy(PyObject* self, PyObject* args) {
-  // Overload 2: bool datacopy(int stmt_num, int level, const std::string &array_name, bool allow_extra_read = false, int fastest_changing_dimension = -1, int padding_stride = 1, int padding_alignment = 4, int memory_type = 0);
-  int nargs = strict_arg_range(args, 3, 7, "datacopy");
-  if(PyList_CheckExact(PyTuple_GetItem(args,0)) || PyDict_CheckExact(PyTuple_GetItem(args, 0))) {
-    chill_datacopy_vec(args);
-  }
-  else {
-    chill_datacopy_int(args);
-  }
-  Py_RETURN_NONE;
-}
-
-static PyObject* chill_datacopy_privatized(PyObject* self, PyObject* args) {
-  //  bool datacopy_privatized(int stmt_num, int level, const std::string &array_name, const std::vector<int> &privatized_levels, bool allow_extra_read = false, int fastest_changing_dimension = -1, int padding_stride = 1, int padding_alignment = 1, int memory_type = 0);
-  int nargs = strict_arg_range(args, 4, 9, "datacopy_privatized");
-  int stmt_num = intArg(args, 0);
-  int level = intArg(args, 1);
-  std::string array_name = strArg(args, 2);
-  std::vector<int> privatized_levels;
-  tointvector(args, 3, privatized_levels);
-  bool allow_extra_read = boolArg(args, 4, false);
-  int fastest_changing_dimension = intArg(args, 5, -1);
-  int padding_stride = intArg(args, 6, 1);
-  int padding_alignment = intArg(args, 7, 1);
-  int memory_type = intArg(args, 8);
-  myloop->datacopy_privatized(stmt_num, level, array_name, privatized_levels, allow_extra_read, fastest_changing_dimension, padding_stride, padding_alignment, memory_type);
-  Py_RETURN_NONE;
-}
-
-static PyObject* chill_unroll(PyObject* self, PyObject* args) {
-  int nargs = strict_arg_range(args, 3, 4, "unroll");
-  //std::set<int> unroll(int stmt_num, int level, int unroll_amount, std::vector< std::vector<std::string> >idxNames= std::vector< std::vector<std::string> >(), int cleanup_split_level = 0);
-  int stmt_num = intArg(args, 0);
-  int level = intArg(args, 1);
-  int unroll_amount = intArg(args, 2);
-  std::vector< std::vector<std::string> > idxNames = std::vector< std::vector<std::string> >();
-  int cleanup_split_level = intArg(args, 3);
-  myloop->unroll(stmt_num, level, unroll_amount, idxNames, cleanup_split_level);
-  Py_RETURN_NONE;
-}
-  
-static PyObject* chill_unroll_extra(PyObject* self, PyObject* args) {
-  int nargs = strict_arg_range(args, 3, 4, "unroll_extra");
-  int stmt_num = intArg(args, 0);
-  int level = intArg(args, 1);
-  int unroll_amount = intArg(args, 2);
-  int cleanup_split_level = intArg(args, 3, 0);
-  myloop->unroll_extra(stmt_num, level, unroll_amount, cleanup_split_level); 
-  Py_RETURN_NONE;
-}
-  
-static PyObject* chill_split(PyObject* self, PyObject* args) {
-  strict_arg_num(args, 3, "split");
-  int stmt_num = intArg(args, 0);
-  int level = intArg(args, 1);
-  int num_dim = myloop->stmt[stmt_num].xform.n_out();
-  
-  std::vector<std::map<std::string, int> >* cond;
-  std::string cond_expr = strArg(args, 2);
-  cond = parse_relation_vector(cond_expr.c_str());
-  
-  Relation rel((num_dim-1)/2);
-  F_And *f_root = rel.add_and();
-  for (int j = 0; j < cond->size(); j++) {
-    GEQ_Handle h = f_root->add_GEQ();
-    for (std::map<std::string, int>::iterator it = (*cond)[j].begin(); it != (*cond)[j].end(); it++) {
-      try {
-        int dim = from_string<int>(it->first);
-        if (dim == 0)
-          h.update_const(it->second);
-        else {
-          if (dim > (num_dim-1)/2)
-            throw std::invalid_argument("invalid loop level " + to_string(dim) + " in split condition");
-          h.update_coef(rel.set_var(dim), it->second);
-        }
-      }
-      catch (std::ios::failure e) {
-        Free_Var_Decl *g = NULL;
-        for (unsigned i = 0; i < myloop->freevar.size(); i++) {
-          std::string name = myloop->freevar[i]->base_name();
-          if (name == it->first) {
-            g = myloop->freevar[i];
-            break;
-          }
-        }
-        if (g == NULL)
-          throw std::invalid_argument("unrecognized variable " + to_string(it->first.c_str()));
-        h.update_coef(rel.get_local(g), it->second);
-      }
-    }
-  }
-  myloop->split(stmt_num,level,rel);
-  Py_RETURN_NONE;
-}
-
-static PyObject* chill_nonsingular(PyObject* self, PyObject* args) {
-  std::vector< std::vector<int> > mat;
-  tointmatrix(args, 0, mat);
-  myloop->nonsingular(mat);
-  Py_RETURN_NONE;
-}
-
-static PyObject* chill_skew(PyObject* self, PyObject* args) {
-  std::set<int> stmt_nums;
-  std::vector<int> skew_amounts;
-  int level = intArg(args, 1);
-  tointset(args, 0, stmt_nums);
-  tointvector(args, 2, skew_amounts);
-  myloop->skew(stmt_nums, level, skew_amounts);
-  Py_RETURN_NONE;
-}
-
-static PyObject* chill_scale(PyObject* self, PyObject* args) {
-  strict_arg_num(args, 3);
-  std::set<int> stmt_nums;
-  int level = intArg(args, 1);
-  int scale_amount = intArg(args, 2);
-  tointset(args, 0, stmt_nums);
-  myloop->scale(stmt_nums, level, scale_amount);
-  Py_RETURN_NONE;
-}
-
-static PyObject* chill_reverse(PyObject* self, PyObject* args) {
-  strict_arg_num(args, 2);
-  std::set<int> stmt_nums;
-  int level = intArg(args, 1);
-  tointset(args, 0, stmt_nums);
-  myloop->reverse(stmt_nums, level);
-  Py_RETURN_NONE;
-}
-
-static PyObject* chill_shift(PyObject* self, PyObject* args) {
-  strict_arg_num(args, 3);
-  std::set<int> stmt_nums;
-  int level = intArg(args, 1);
-  int shift_amount = intArg(args, 2);
-  tointset(args, 0, stmt_nums);
-  myloop->shift(stmt_nums, level, shift_amount);
-  Py_RETURN_NONE;
-}
-
-static PyObject* chill_shift_to(PyObject* self, PyObject* args) {
-  strict_arg_num(args, 3);
-  int stmt_num = intArg(args, 0);
-  int level = intArg(args, 1);
-  int absolute_pos = intArg(args, 2);
-  myloop->shift_to(stmt_num, level, absolute_pos);
-  Py_RETURN_NONE;
-}
-
-static PyObject* chill_peel(PyObject* self, PyObject* args) {
-  strict_arg_range(args, 2, 3);
-  int stmt_num = intArg(args, 0);
-  int level = intArg(args, 1);
-  int amount = intArg(args, 2);
-  myloop->peel(stmt_num, level, amount);
-  Py_RETURN_NONE;
-}
-
-static PyObject* chill_fuse(PyObject* self, PyObject* args) {
-  strict_arg_num(args, 2);
-  std::set<int> stmt_nums;
-  int level = intArg(args, 1);
-  tointset(args, 0, stmt_nums);
-  myloop->fuse(stmt_nums, level);
-  Py_RETURN_NONE;
-}
-
-static PyObject* chill_distribute(PyObject* self, PyObject* args) {
-  strict_arg_num(args, 2);
-  std::set<int> stmts;
-  int level = intArg(args, 1);
-  tointset(args, 0, stmts);
-  myloop->distribute(stmts, level);
-  Py_RETURN_NONE;
-}
-
-static PyObject *
-chill_num_statements(PyObject *self, PyObject *args)  
-{
-  //DEBUG_PRINT("\nC chill_num_statements() called from python\n"); 
-  int num = myloop->stmt.size();
-  //DEBUG_PRINT("C num_statement() = %d\n", num); 
-  return Py_BuildValue( "i", num ); // BEWARE "d" is DOUBLE, not int
-}
-
-static PyMethodDef ChillMethods[] = { 
-  
-  //python name           C routine                  parameter passing comment
-  {"source",              chill_source,                    METH_VARARGS,     "set source file for chill script"},
-  {"procedure",           chill_procedure,                 METH_VARARGS,     "set the name of the procedure"},
-  {"loop",                chill_loop,                      METH_VARARGS,     "indicate which loop to optimize"},
-  {"print_code",          chill_print_code,                METH_VARARGS,     "print generated code"},
-  {"print_dep",           chill_print_dep,                 METH_VARARGS,     "print the dependencies graph"},
-  {"print_space",         chill_print_space,               METH_VARARGS,     "print space"},
-  {"exit",                chill_exit,                      METH_VARARGS,     "exit the interactive consule"},
-  {"known",               chill_known,                     METH_VARARGS,     "knwon"},
-  {"remove_dep",          chill_remove_dep,                METH_VARARGS,     "remove dependency i suppose"},
-  {"original",            chill_original,                  METH_VARARGS,     "original"},
-  {"permute",             chill_permute,                   METH_VARARGS,     "permute"},
-  {"pragma",              chill_pragma,                    METH_VARARGS,     "pragma"},
-  {"prefetch",            chill_prefetch,                  METH_VARARGS,     "prefetch"},
-  {"tile",                chill_tile,                      METH_VARARGS,     "tile"},
-  {"datacopy",            chill_datacopy,                  METH_VARARGS,     "datacopy"},
-  {"datacopy_privitized", chill_datacopy_privatized,       METH_VARARGS,     "datacopy_privatized"},
-  {"unroll",              chill_unroll,                    METH_VARARGS,     "unroll"},
-  {"unroll_extra",        chill_unroll_extra,              METH_VARARGS,     "unroll_extra"},
-  {"split",               chill_split,                     METH_VARARGS,     "split"},
-  {"nonsingular",         chill_nonsingular,               METH_VARARGS,     "nonsingular"},
-  {"skew",                chill_skew,                      METH_VARARGS,     "skew"},
-  {"scale",               chill_scale,                     METH_VARARGS,     "scale"},
-  {"reverse",             chill_reverse,                   METH_VARARGS,     "reverse"},
-  {"shift",               chill_shift,                     METH_VARARGS,     "shift"},
-  {"shift_to",            chill_shift_to,                  METH_VARARGS,     "shift_to"},
-  {"peel",                chill_peel,                      METH_VARARGS,     "peel"},
-  {"fuse",                chill_fuse,                      METH_VARARGS,     "fuse"},
-  {"distribute",          chill_distribute,                METH_VARARGS,     "distribute"},
-  {"num_statements",      chill_num_statements,            METH_VARARGS,     "number of statements in the current loop"},
-  {NULL, NULL, 0, NULL}
-};
-
-static void register_globals(PyObject* m) {
-  // Preset globals
-  PyModule_AddStringConstant(m, "VERSION", CHILL_BUILD_VERSION);
-  PyModule_AddStringConstant(m, "dest", "C");
-  PyModule_AddStringConstant(m, "C", "C");
-  // Tile method
-  PyModule_AddIntConstant(m, "strided", 0);
-  PyModule_AddIntConstant(m, "counted", 1);
-  // Memory mode
-  PyModule_AddIntConstant(m, "global", 0);
-  PyModule_AddIntConstant(m, "shared", 1);
-  PyModule_AddIntConstant(m, "textured", 2);
-  // Bool flags
-  PyModule_AddIntConstant(m, "sync", 1);
-} 
-
-PyMODINIT_FUNC
-initchill(void)    // pass C methods to python 
-{
-  DEBUG_PRINT("in C, initchill() to set up C methods to be called from python\n");
-  PyObject* m = Py_InitModule("chill", ChillMethods);
-  register_globals(m);
-}
diff --git a/chill/src/dep.cc b/chill/src/dep.cc
deleted file mode 100644
index a675d03..0000000
--- a/chill/src/dep.cc
+++ /dev/null
@@ -1,567 +0,0 @@
-/*****************************************************************************
- Copyright (C) 2008 University of Southern California
- Copyright (C) 2009-2010 University of Utah
- All Rights Reserved.
-
- Purpose:
- Data dependence vector and graph.
-
- Notes:
- All dependence vectors are normalized, i.e., the first non-zero distance
- must be positve. Thus the correct dependence meaning can be given based on
- source/destination pair's read/write type. Suppose for a dependence vector
- 1, 0~5, -3), we want to permute the first and the second dimension,
- the result would be two dependence vectors (0, 1, -3) and (1~5, 1, -3).
- All operations on dependence vectors are non-destructive, i.e., new
- dependence vectors are returned.
-
- History:
- 01/2006 Created by Chun Chen.
- 03/2009 Use IR_Ref interface in source and destination arrays -chun
-*****************************************************************************/
-
-#include "dep.hh"
-
-//-----------------------------------------------------------------------------
-// Class: DependeceVector
-//-----------------------------------------------------------------------------
-
-std::ostream& operator<<(std::ostream &os, const DependenceVector &d) {
-  if (d.sym != NULL) {
-    os << d.sym->name();
-    os << ':';
-    if (d.quasi)
-      os << "_quasi";
-    
-  }
-  
-  switch (d.type) {
-  case DEP_W2R:
-    os << "true";
-    if (d.is_reduction)
-      os << "_reduction";
-    break;
-  case DEP_R2W:
-    os << "anti";
-    break;
-  case DEP_W2W:
-    os << "output";
-    break;
-  case DEP_R2R:
-    os << "input";
-    break;
-  case DEP_CONTROL:
-    os << "control";
-    break;
-  default:
-    os << "unknown";
-    break;
-  }
-  
-  os << '(';
-  
-  for (int i = 0; i < d.lbounds.size(); i++) {
-    omega::coef_t lbound = d.lbounds[i];
-    omega::coef_t ubound = d.ubounds[i];
-    
-    if (lbound == ubound)
-      os << lbound;
-    else {
-      if (lbound == -posInfinity)
-        if (ubound == posInfinity)
-          os << '*';
-        else {
-          if (ubound == -1)
-            os << '-';
-          else
-            os << ubound << '-';
-        }
-      else if (ubound == posInfinity) {
-        if (lbound == 1)
-          os << '+';
-        else
-          os << lbound << '+';
-      } else
-        os << lbound << '~' << ubound;
-    }
-    
-    if (i < d.lbounds.size() - 1)
-      os << ", ";
-  }
-  
-  os << ')';
-  
-  return os;
-}
-
-// DependenceVector::DependenceVector(int size):
-//   lbounds(std::vector<coef_t>(size, 0)),
-//   ubounds(std::vector<coef_t>(size, 0)) {
-//   src = NULL;
-//   dst = NULL;
-// }
-
-DependenceVector::DependenceVector(const DependenceVector &that) {
-  if (that.sym != NULL)
-    this->sym = that.sym->clone();
-  else
-    this->sym = NULL;
-  this->type = that.type;
-  this->lbounds = that.lbounds;
-  this->ubounds = that.ubounds;
-  quasi = that.quasi;
-  is_scalar_dependence = that.is_scalar_dependence;
-  is_reduction = that.is_reduction;
-}
-
-DependenceVector &DependenceVector::operator=(const DependenceVector &that) {
-  if (this != &that) {
-    delete this->sym;
-    if (that.sym != NULL)
-      this->sym = that.sym->clone();
-    else
-      this->sym = NULL;
-    this->type = that.type;
-    this->lbounds = that.lbounds;
-    this->ubounds = that.ubounds;
-    quasi = that.quasi;
-    is_scalar_dependence = that.is_scalar_dependence;
-    is_reduction = that.is_reduction;
-  }
-  return *this;
-}
-DependenceType DependenceVector::getType() const {
-  return type;
-}
-
-bool DependenceVector::is_data_dependence() const {
-  if (type == DEP_W2R || type == DEP_R2W || type == DEP_W2W
-      || type == DEP_R2R)
-    return true;
-  else
-    return false;
-}
-
-bool DependenceVector::is_control_dependence() const {
-  if (type == DEP_CONTROL)
-    return true;
-  else
-    return false;
-}
-
-bool DependenceVector::has_negative_been_carried_at(int dim) const {
-  if (!is_data_dependence())
-    throw std::invalid_argument("only works for data dependences");
-  
-  if (dim < 0 || dim >= lbounds.size())
-    return false;
-  
-  for (int i = 0; i < dim; i++)
-    if (lbounds[i] > 0 || ubounds[i] < 0)
-      return false;
-  
-  if (lbounds[dim] < 0)
-    return true;
-  else
-    return false;
-}
-
-
-bool DependenceVector::has_been_carried_at(int dim) const {
-  if (!is_data_dependence())
-    throw std::invalid_argument("only works for data dependences");
-  
-  if (dim < 0 || dim >= lbounds.size())
-    return false;
-  
-  for (int i = 0; i < dim; i++)
-    if (lbounds[i] > 0 || ubounds[i] < 0)
-      return false;
-  
-  if ((lbounds[dim] != 0)  || (ubounds[dim] !=0))
-    return true;
-  
-  return false;
-}
-
-bool DependenceVector::has_been_carried_before(int dim) const {
-  if (!is_data_dependence())
-    throw std::invalid_argument("only works for data dependences");
-  
-  if (dim < 0)
-    return false;
-  if (dim > lbounds.size())
-    dim = lbounds.size();
-  
-  for (int i = 0; i < dim; i++) {
-    if (lbounds[i] > 0)
-      return true;
-    if (ubounds[i] < 0)
-      return true;
-  }
-  
-  return false;
-}
-
-bool DependenceVector::isZero() const {
-  return isZero(lbounds.size() - 1);
-}
-
-bool DependenceVector::isZero(int dim) const {
-  if (dim >= lbounds.size())
-    throw std::invalid_argument("invalid dependence dimension");
-  
-  for (int i = 0; i <= dim; i++)
-    if (lbounds[i] != 0 || ubounds[i] != 0)
-      return false;
-  
-  return true;
-}
-
-bool DependenceVector::isPositive() const {
-  for (int i = 0; i < lbounds.size(); i++)
-    if (lbounds[i] != 0 || ubounds[i] != 0) {
-      if (lbounds[i] < 0)
-        return false;
-      else if (lbounds[i] > 0)
-        return true;
-    }
-  
-  return false;
-}
-
-bool DependenceVector::isNegative() const {
-  for (int i = 0; i < lbounds.size(); i++)
-    if (lbounds[i] != 0 || ubounds[i] != 0) {
-      if (ubounds[i] > 0)
-        return false;
-      else if (ubounds[i] < 0)
-        return true;
-    }
-  
-  return false;
-}
-
-bool DependenceVector::isAllPositive() const {
-  for (int i = 0; i < lbounds.size(); i++)
-    if (lbounds[i] < 0)
-      return false;
-  
-  return true;
-}
-
-bool DependenceVector::isAllNegative() const {
-  for (int i = 0; i < ubounds.size(); i++)
-    if (ubounds[i] > 0)
-      return false;
-  
-  return true;
-}
-
-bool DependenceVector::hasPositive(int dim) const {
-  if (dim >= lbounds.size())
-    throw std::invalid_argument("invalid dependence dimension");
-  
-  if (lbounds[dim] > 0)
-    //av: changed from ubounds to lbounds may have side effects
-    return true;
-  else
-    return false;
-}
-
-bool DependenceVector::hasNegative(int dim) const {
-  if (dim >= lbounds.size())
-    throw std::invalid_argument("invalid dependence dimension");
-  
-  if (ubounds[dim] < 0)
-    //av: changed from lbounds to ubounds may have side effects
-    return true;
-  else
-    return false;
-}
-
-bool DependenceVector::isCarried(int dim, omega::coef_t distance) const {
-  if (distance <= 0)
-    throw std::invalid_argument("invalid dependence distance size");
-  
-  if (dim > lbounds.size())
-    dim = lbounds.size();
-  
-  for (int i = 0; i < dim; i++)
-    if (lbounds[i] > 0)
-      return false;
-    else if (ubounds[i] < 0)
-      return false;
-  
-  if (dim >= lbounds.size())
-    return true;
-  
-  if (lbounds[dim] > distance)
-    return false;
-  else if (ubounds[dim] < -distance)
-    return false;
-  
-  return true;
-}
-
-bool DependenceVector::canPermute(const std::vector<int> &pi) const {
-  if (pi.size() != lbounds.size())
-    throw std::invalid_argument(
-      "permute dimensionality do not match dependence space");
-  
-  for (int i = 0; i < pi.size(); i++) {
-    if (lbounds[pi[i]] > 0)
-      return true;
-    else if (lbounds[pi[i]] < 0)
-      return false;
-  }
-  
-  return true;
-}
-
-std::vector<DependenceVector> DependenceVector::normalize() const {
-  std::vector<DependenceVector> result;
-  
-  DependenceVector dv(*this);
-  for (int i = 0; i < dv.lbounds.size(); i++) {
-    if (dv.lbounds[i] < 0 && dv.ubounds[i] >= 0) {
-      omega::coef_t t = dv.ubounds[i];
-      dv.ubounds[i] = -1;
-      result.push_back(dv);
-      dv.lbounds[i] = 0;
-      dv.ubounds[i] = t;
-    }
-    if (dv.lbounds[i] == 0 && dv.ubounds[i] > 0) {
-      dv.lbounds[i] = 1;
-      result.push_back(dv);
-      dv.lbounds[i] = 0;
-      dv.ubounds[i] = 0;
-    }
-    if (dv.lbounds[i] == 0 && dv.ubounds[i] == 0)
-      continue;
-    else
-      break;
-  }
-  
-  result.push_back(dv);
-  return result;
-}
-
-std::vector<DependenceVector> DependenceVector::permute(
-  const std::vector<int> &pi) const {
-  if (pi.size() != lbounds.size())
-    throw std::invalid_argument(
-      "permute dimensionality do not match dependence space");
-  
-  const int n = lbounds.size();
-  
-  DependenceVector dv(*this);
-  for (int i = 0; i < n; i++) {
-    dv.lbounds[i] = lbounds[pi[i]];
-    dv.ubounds[i] = ubounds[pi[i]];
-  }
-  
-  int violated = 0;
-  
-  for (int i = 0; i < n; i++) {
-    if (dv.lbounds[i] > 0)
-      break;
-    else if (dv.lbounds[i] < 0)
-      violated = 1;
-  }
-  
-  if (((violated == 1) && !quasi) && !is_scalar_dependence) {
-    throw ir_error("dependence violation");
-    
-  }
-  
-  return dv.normalize();
-}
-
-DependenceVector DependenceVector::reverse() const {
-  const int n = lbounds.size();
-  
-  DependenceVector dv(*this);
-  switch (type) {
-  case DEP_W2R:
-    dv.type = DEP_R2W;
-    break;
-  case DEP_R2W:
-    dv.type = DEP_W2R;
-    break;
-  default:
-    dv.type = type;
-  }
-  
-  for (int i = 0; i < n; i++) {
-    dv.lbounds[i] = -ubounds[i];
-    dv.ubounds[i] = -lbounds[i];
-  }
-  dv.quasi = true;
-  
-  return dv;
-}
-
-// std::vector<DependenceVector> DependenceVector::matrix(const std::vector<std::vector<int> > &M) const {
-//   if (M.size() != lbounds.size())
-//     throw std::invalid_argument("(non)unimodular transformation dimensionality does not match dependence space");
-
-//   const int n = lbounds.size();
-//   DependenceVector dv;
-//   if (sym != NULL)
-//     dv.sym = sym->clone();
-//   else
-//     dv.sym = NULL;
-//   dv.type = type;
-
-//   for (int i = 0; i < n; i++) {
-//     assert(M[i].size() == n+1 || M[i].size() == n);
-
-//     omega::coef_t lb, ub;
-//     if (M[i].size() == n+1)
-//       lb = ub = M[i][n];
-//     else
-//       lb = ub = 0;
-
-//     for (int j = 0; j < n; j++) {
-//       int c = M[i][j];
-//       if (c == 0)
-//         continue;
-
-//       if (c > 0) {
-//         if (lbounds[j] == -posInfinity)
-//           lb = -posInfinity;
-//         else if (lb != -posInfinity)
-//           lb += c * lbounds[j];
-//         if (ubounds[j] == posInfinity)
-//           ub = posInfinity;
-//         else if (ub != posInfinity)
-//           ub += c * ubounds[j];
-//       }
-//       else {
-//         if (ubounds[j] == posInfinity)
-//           lb = -posInfinity;
-//         else if (lb != -posInfinity)
-//           lb += c * ubounds[j];
-//         if (lbounds[j] == -posInfinity)
-//           ub = posInfinity;
-//         else if (ub != posInfinity)
-//           ub += c * lbounds[j];
-//       }
-//     }
-//     dv.lbounds.push_back(lb);
-//     dv.ubounds.push_back(ub);
-//   }
-//   dv.is_reduction = is_reduction;
-
-//   return dv.normalize();
-// }
-
-//-----------------------------------------------------------------------------
-// Class: DependenceGraph
-//-----------------------------------------------------------------------------
-
-DependenceGraph DependenceGraph::permute(const std::vector<int> &pi,
-                                         const std::set<int> &active) const {
-  DependenceGraph g;
-  
-  for (int i = 0; i < vertex.size(); i++)
-    g.insert(vertex[i].first);
-  
-  for (int i = 0; i < vertex.size(); i++)
-    for (EdgeList::const_iterator j = vertex[i].second.begin();
-         j != vertex[i].second.end(); j++) {
-      if (active.empty()
-          || (active.find(i) != active.end()
-              && active.find(j->first) != active.end())) {
-        for (int k = 0; k < j->second.size(); k++) {
-          std::vector<DependenceVector> dv = j->second[k].permute(pi);
-          g.connect(i, j->first, dv);
-        }
-      } else if (active.find(i) == active.end()
-                 && active.find(j->first) == active.end()) {
-        std::vector<DependenceVector> dv = j->second;
-        g.connect(i, j->first, dv);
-      } else {
-        std::vector<DependenceVector> dv = j->second;
-        for (int k = 0; k < dv.size(); k++)
-          for (int d = 0; d < pi.size(); d++)
-            if (pi[d] != d) {
-              dv[k].lbounds[d] = -posInfinity;
-              dv[k].ubounds[d] = posInfinity;
-            }
-        g.connect(i, j->first, dv);
-      }
-    }
-  
-  return g;
-}
-
-// DependenceGraph DependenceGraph::matrix(const std::vector<std::vector<int> > &M) const {
-//   DependenceGraph g;
-
-//   for (int i = 0; i < vertex.size(); i++)
-//     g.insert(vertex[i].first);
-
-//   for (int i = 0; i < vertex.size(); i++)
-//     for (EdgeList::const_iterator j = vertex[i].second.begin(); j != vertex[i].second.end(); j++)
-//       for (int k = 0; k < j->second.size(); k++)
-//         g.connect(i, j->first, j->second[k].matrix(M));
-
-//   return g;
-// }
-
-DependenceGraph DependenceGraph::subspace(int dim) const {
-  DependenceGraph g;
-  
-  for (int i = 0; i < vertex.size(); i++)
-    g.insert(vertex[i].first);
-  
-  for (int i = 0; i < vertex.size(); i++)
-    for (EdgeList::const_iterator j = vertex[i].second.begin();
-         j != vertex[i].second.end(); j++)
-      
-      for (int k = 0; k < j->second.size(); k++) {
-        if(j->second[k].type != DEP_CONTROL){
-          if (j->second[k].isCarried(dim))
-            g.connect(i, j->first, j->second[k]);
-        }else
-          g.connect(i, j->first, j->second[k]);
-        
-      }
-  
-  return g;
-}
-
-bool DependenceGraph::isPositive() const {
-  for (int i = 0; i < vertex.size(); i++)
-    for (EdgeList::const_iterator j = vertex[i].second.begin();
-         j != vertex[i].second.end(); j++)
-      for (int k = 0; k < j->second.size(); k++)
-        if (!j->second[k].isPositive())
-          return false;
-  
-  return true;
-}
-
-bool DependenceGraph::hasPositive(int dim) const {
-  for (int i = 0; i < vertex.size(); i++)
-    for (EdgeList::const_iterator j = vertex[i].second.begin();
-         j != vertex[i].second.end(); j++)
-      for (int k = 0; k < j->second.size(); k++)
-        if (!j->second[k].hasPositive(dim))
-          return false;
-  
-  return true;
-}
-
-bool DependenceGraph::hasNegative(int dim) const {
-  for (int i = 0; i < vertex.size(); i++)
-    for (EdgeList::const_iterator j = vertex[i].second.begin();
-         j != vertex[i].second.end(); j++)
-      for (int k = 0; k < j->second.size(); k++)
-        if (!j->second[k].hasNegative(dim))
-          return false;
-  
-  return true;
-}
diff --git a/chill/src/ir_rose.cc b/chill/src/ir_rose.cc
deleted file mode 100644
index 27930e6..0000000
--- a/chill/src/ir_rose.cc
+++ /dev/null
@@ -1,1756 +0,0 @@
-/*****************************************************************************
- Copyright (C) 2009-2010 University of Utah
- All Rights Reserved.
-
- Purpose:
- CHiLL's rose interface.
-
- Notes:
- Array supports mixed pointer and array type in a single declaration.
-
- History:
- 02/23/2009 Created by Chun Chen.
-*****************************************************************************/
-#include <string>
-#include "ir_rose.hh"
-#include "ir_rose_utils.hh"
-#include <code_gen/rose_attributes.h>
-#include <code_gen/CG_roseRepr.h>
-#include <code_gen/CG_roseBuilder.h>
-
-using namespace SageBuilder;
-using namespace SageInterface;
-using namespace omega;
-// ----------------------------------------------------------------------------
-// Class: IR_roseScalarSymbol
-// ----------------------------------------------------------------------------
-
-std::string IR_roseScalarSymbol::name() const {
-  return vs_->get_name().getString();
-}
-
-int IR_roseScalarSymbol::size() const {
-  return (vs_->get_type()->memoryUsage()) / (vs_->get_type()->numberOfNodes());
-}
-
-bool IR_roseScalarSymbol::operator==(const IR_Symbol &that) const {
-  if (typeid(*this) != typeid(that))
-    return false;
-  
-  const IR_roseScalarSymbol *l_that =
-    static_cast<const IR_roseScalarSymbol *>(&that);
-  return this->vs_ == l_that->vs_;
-}
-
-IR_Symbol *IR_roseScalarSymbol::clone() const {
-  return NULL;
-}
-
-// ----------------------------------------------------------------------------
-// Class: IR_roseArraySymbol
-// ----------------------------------------------------------------------------
-
-std::string IR_roseArraySymbol::name() const {
-  return (vs_->get_declaration()->get_name().getString());
-}
-
-int IR_roseArraySymbol::elem_size() const {
-  
-  SgType *tn = vs_->get_type();
-  SgType* arrType;
-  
-  int elemsize;
-  
-  if (arrType = isSgArrayType(tn)) {
-    while (isSgArrayType(arrType)) {
-      arrType = arrType->findBaseType();
-    }
-  } else if (arrType = isSgPointerType(tn)) {
-    while (isSgPointerType(arrType)) {
-      arrType = arrType->findBaseType();
-    }
-  }
-  
-  elemsize = (int) arrType->memoryUsage() / arrType->numberOfNodes();
-  return elemsize;
-}
-
-int IR_roseArraySymbol::n_dim() const {
-  int dim = 0;
-  SgType* arrType = isSgArrayType(vs_->get_type());
-  SgType* ptrType = isSgPointerType(vs_->get_type());
-  if (arrType != NULL) {
-    while (isSgArrayType(arrType)) {
-      arrType = isSgArrayType(arrType)->get_base_type();
-      dim++;
-    }
-  } else if (ptrType != NULL) {
-    while (isSgPointerType(ptrType)) {
-      ptrType = isSgPointerType(ptrType)->get_base_type();
-      dim++;
-    }
-  }
-
-  // Manu:: fortran support
-  if (static_cast<const IR_roseCode *>(ir_)->is_fortran_) {
-
-	  if (arrType != NULL) {
-		  dim = 0;
-		  SgExprListExp * dimList = isSgArrayType(vs_->get_type())->get_dim_info();
-		  SgExpressionPtrList::iterator it = dimList->get_expressions().begin();
-		  for(;it != dimList->get_expressions().end(); it++) {
-		    dim++;
-		  }
-	  } else if (ptrType != NULL) {
-		  //std::cout << "pntrType \n";
-		  ; // not sure if this case will happen
-	  }
-  }
-
-  return dim;
-}
-
-omega::CG_outputRepr *IR_roseArraySymbol::size(int dim) const {
-  
-  SgArrayType* arrType = isSgArrayType(vs_->get_type());
-  // SgExprListExp* dimList = arrType->get_dim_info();
-  int count = 0;
-  SgExpression* expr;
-  SgType* pntrType = isSgPointerType(vs_->get_type());
-  
-  if (arrType != NULL) {
-    SgExprListExp* dimList = arrType->get_dim_info();
-    if (!static_cast<const IR_roseCode *>(ir_)->is_fortran_) {
-      SgExpressionPtrList::iterator it =
-        dimList->get_expressions().begin();
-      
-      while ((it != dimList->get_expressions().end()) && (count < dim)) {
-        it++;
-        count++;
-      }
-      
-      expr = *it;
-    } else {
-      SgExpressionPtrList::reverse_iterator i =
-        dimList->get_expressions().rbegin();
-      for (; (i != dimList->get_expressions().rend()) && (count < dim);
-           i++) {
-        
-        count++;
-      }
-      
-      expr = *i;
-    }
-  } else if (pntrType != NULL) {
-    
-    while (count < dim) {
-      pntrType = (isSgPointerType(pntrType))->get_base_type();
-      count++;
-    }
-    if (isSgPointerType(pntrType))
-      expr = new SgExpression;
-  }
-  
-  if (!expr)
-    throw ir_error("Index variable is NULL!!");
-  
-  // Manu :: debug
-  std::cout << "---------- size :: " << isSgNode(expr)->unparseToString().c_str() << "\n";
-
-  return new omega::CG_roseRepr(expr);
-  
-}
-
-IR_ARRAY_LAYOUT_TYPE IR_roseArraySymbol::layout_type() const {
-  if (static_cast<const IR_roseCode *>(ir_)->is_fortran_)
-    return IR_ARRAY_LAYOUT_COLUMN_MAJOR;
-  else
-    return IR_ARRAY_LAYOUT_ROW_MAJOR;
-  
-}
-
-bool IR_roseArraySymbol::operator==(const IR_Symbol &that) const {
-  
-  if (typeid(*this) != typeid(that))
-    return false;
-  
-  const IR_roseArraySymbol *l_that =
-    static_cast<const IR_roseArraySymbol *>(&that);
-  return this->vs_ == l_that->vs_;
-  
-}
-
-IR_Symbol *IR_roseArraySymbol::clone() const {
-  return new IR_roseArraySymbol(ir_, vs_);
-}
-
-// ----------------------------------------------------------------------------
-// Class: IR_roseConstantRef
-// ----------------------------------------------------------------------------
-
-bool IR_roseConstantRef::operator==(const IR_Ref &that) const {
-  
-  if (typeid(*this) != typeid(that))
-    return false;
-  
-  const IR_roseConstantRef *l_that =
-    static_cast<const IR_roseConstantRef *>(&that);
-  
-  if (this->type_ != l_that->type_)
-    return false;
-  
-  if (this->type_ == IR_CONSTANT_INT)
-    return this->i_ == l_that->i_;
-  else
-    return this->f_ == l_that->f_;
-  
-}
-
-omega::CG_outputRepr *IR_roseConstantRef::convert() {
-  if (type_ == IR_CONSTANT_INT) {
-    omega::CG_roseRepr *result = new omega::CG_roseRepr(
-      isSgExpression(buildIntVal(static_cast<int>(i_))));
-    delete this;
-    return result;
-  } else
-    throw ir_error("constant type not supported");
-  
-}
-
-IR_Ref *IR_roseConstantRef::clone() const {
-  if (type_ == IR_CONSTANT_INT)
-    return new IR_roseConstantRef(ir_, i_);
-  else if (type_ == IR_CONSTANT_FLOAT)
-    return new IR_roseConstantRef(ir_, f_);
-  else
-    throw ir_error("constant type not supported");
-  
-}
-
-// ----------------------------------------------------------------------------
-// Class: IR_roseScalarRef
-// ----------------------------------------------------------------------------
-
-bool IR_roseScalarRef::is_write() const {
-  if (is_write_ == 1)
-    return true;
-  
-  return false;
-}
-
-IR_ScalarSymbol *IR_roseScalarRef::symbol() const {
-  return new IR_roseScalarSymbol(ir_, vs_->get_symbol());
-}
-
-bool IR_roseScalarRef::operator==(const IR_Ref &that) const {
-  if (typeid(*this) != typeid(that))
-    return false;
-  
-  const IR_roseScalarRef *l_that =
-    static_cast<const IR_roseScalarRef *>(&that);
-  
-  if (this->ins_pos_ == NULL)
-    return this->vs_ == l_that->vs_;
-  else
-    return this->ins_pos_ == l_that->ins_pos_
-      && this->op_pos_ == l_that->op_pos_;
-}
-
-omega::CG_outputRepr *IR_roseScalarRef::convert() {
-  omega::CG_roseRepr *result = new omega::CG_roseRepr(isSgExpression(vs_));
-  delete this;
-  return result;
-  
-}
-
-IR_Ref * IR_roseScalarRef::clone() const {
-  return new IR_roseScalarRef(ir_, vs_, this->is_write_);
-}
-
-// ----------------------------------------------------------------------------
-// Class: IR_roseArrayRef
-// ----------------------------------------------------------------------------
-
-bool IR_roseArrayRef::is_write() const {
-  SgAssignOp* assignment;
-  
-  if (is_write_ == 1 || is_write_ == 0)
-    return is_write_;
-  if (assignment = isSgAssignOp(ia_->get_parent())) {
-    if (assignment->get_lhs_operand() == ia_)
-      return true;
-  } else if (SgExprStatement* expr_stmt = isSgExprStatement(
-               ia_->get_parent())) {
-    SgExpression* exp = expr_stmt->get_expression();
-    
-    if (exp) {
-      if (assignment = isSgAssignOp(exp)) {
-        if (assignment->get_lhs_operand() == ia_)
-          return true;
-        
-      }
-    }
-    
-  }
-  return false;
-}
-
-omega::CG_outputRepr *IR_roseArrayRef::index(int dim) const {
-  
-  SgExpression *current = isSgExpression(ia_);
-  SgExpression* expr;
-  int count = 0;
-  
-  while (isSgPntrArrRefExp(current)) {
-    current = isSgPntrArrRefExp(current)->get_lhs_operand();
-    count++;
-  }
-  
-  current = ia_;
-  
-  while (count > dim) {
-    expr = isSgPntrArrRefExp(current)->get_rhs_operand();
-    current = isSgPntrArrRefExp(current)->get_lhs_operand();
-    count--;
-  }
-
-  // Manu:: fortran support
-  if (static_cast<const IR_roseCode *>(ir_)->is_fortran_) {
-	  expr = isSgPntrArrRefExp(ia_)->get_rhs_operand();
-	  count = 0;
-	  if (isSgExprListExp(expr)) {
-		  SgExpressionPtrList::iterator indexList = isSgExprListExp(expr)->get_expressions().begin();
-		  while (count < dim) {
-			  indexList++;
-			  count++;
-		  }
-		  expr = isSgExpression(*indexList);
-	  }
-  }
-
-  if (!expr)
-    throw ir_error("Index variable is NULL!!");
-
-
-  omega::CG_roseRepr* ind = new omega::CG_roseRepr(expr);
-  
-  return ind->clone();
-  
-}
-
-IR_ArraySymbol *IR_roseArrayRef::symbol() const {
-  
-  SgExpression *current = isSgExpression(ia_);
-  
-  SgVarRefExp* base;
-  SgVariableSymbol *arrSymbol;
-  while (isSgPntrArrRefExp(current) || isSgUnaryOp(current)) {
-    if (isSgPntrArrRefExp(current))
-      current = isSgPntrArrRefExp(current)->get_lhs_operand();
-    else if (isSgUnaryOp(current))
-      /* To handle support for addressof operator and pointer dereference
-       * both of which are unary ops
-       */
-      current = isSgUnaryOp(current)->get_operand();
-  }
-  if (base = isSgVarRefExp(current)) {
-    arrSymbol = (SgVariableSymbol*) (base->get_symbol());
-    std::string x = arrSymbol->get_name().getString();
-  } else
-    throw ir_error("Array Symbol is not a variable?!");
-  
-  return new IR_roseArraySymbol(ir_, arrSymbol);
-  
-}
-
-bool IR_roseArrayRef::operator==(const IR_Ref &that) const {
-  if (typeid(*this) != typeid(that))
-    return false;
-  
-  const IR_roseArrayRef *l_that = static_cast<const IR_roseArrayRef *>(&that);
-  
-  return this->ia_ == l_that->ia_;
-}
-
-omega::CG_outputRepr *IR_roseArrayRef::convert() {
-  omega::CG_roseRepr *temp = new omega::CG_roseRepr(
-    isSgExpression(this->ia_));
-  omega::CG_outputRepr *result = temp->clone();
-//  delete this;   // Commented by Manu
-  return result;
-}
-
-IR_Ref *IR_roseArrayRef::clone() const {
-  return new IR_roseArrayRef(ir_, ia_, is_write_);
-}
-
-// ----------------------------------------------------------------------------
-// Class: IR_roseLoop
-// ----------------------------------------------------------------------------
-
-IR_ScalarSymbol *IR_roseLoop::index() const {
-  SgForStatement *tf = isSgForStatement(tf_);
-  SgFortranDo *tfortran = isSgFortranDo(tf_);
-  SgVariableSymbol* vs = NULL;
-  if (tf) {
-    SgForInitStatement* list = tf->get_for_init_stmt();
-    SgStatementPtrList& initStatements = list->get_init_stmt();
-    SgStatementPtrList::const_iterator j = initStatements.begin();
-    
-    if (SgExprStatement *expr = isSgExprStatement(*j))
-      if (SgAssignOp* op = isSgAssignOp(expr->get_expression()))
-        if (SgVarRefExp* var_ref = isSgVarRefExp(op->get_lhs_operand()))
-          vs = var_ref->get_symbol();
-  } else if (tfortran) {
-    SgExpression* init = tfortran->get_initialization();
-    
-    if (SgAssignOp* op = isSgAssignOp(init))
-      if (SgVarRefExp* var_ref = isSgVarRefExp(op->get_lhs_operand()))
-        vs = var_ref->get_symbol();
-    
-  }
-  
-  if (vs == NULL)
-    throw ir_error("Index variable is NULL!!");
-  
-  return new IR_roseScalarSymbol(ir_, vs);
-}
-
-omega::CG_outputRepr *IR_roseLoop::lower_bound() const {
-  SgForStatement *tf = isSgForStatement(tf_);
-  SgFortranDo *tfortran = isSgFortranDo(tf_);
-  
-  SgExpression* lowerBound = NULL;
-  
-  if (tf) {
-    SgForInitStatement* list = tf->get_for_init_stmt();
-    SgStatementPtrList& initStatements = list->get_init_stmt();
-    SgStatementPtrList::const_iterator j = initStatements.begin();
-    
-    if (SgExprStatement *expr = isSgExprStatement(*j))
-      if (SgAssignOp* op = isSgAssignOp(expr->get_expression())) {
-        lowerBound = op->get_rhs_operand();
-        //Rose sometimes introduces an unnecessary cast which is a unary op
-        if (isSgUnaryOp(lowerBound))
-          lowerBound = isSgUnaryOp(lowerBound)->get_operand();
-        
-      }
-  } else if (tfortran) {
-    SgExpression* init = tfortran->get_initialization();
-    
-    if (SgAssignOp* op = isSgAssignOp(init))
-      lowerBound = op->get_rhs_operand();
-  }
-  
-  if (lowerBound == NULL)
-    throw ir_error("Lower Bound is NULL!!");
-  
-  return new omega::CG_roseRepr(lowerBound);
-}
-
-omega::CG_outputRepr *IR_roseLoop::upper_bound() const {
-  SgForStatement *tf = isSgForStatement(tf_);
-  SgFortranDo *tfortran = isSgFortranDo(tf_);
-  SgExpression* upperBound = NULL;
-  if (tf) {
-    SgBinaryOp* test_expr = isSgBinaryOp(tf->get_test_expr());
-    if (test_expr == NULL)
-      throw ir_error("Test Expression is NULL!!");
-    
-    upperBound = test_expr->get_rhs_operand();
-    //Rose sometimes introduces an unnecessary cast which is a unary op
-    if (isSgUnaryOp(upperBound))
-      upperBound = isSgUnaryOp(upperBound)->get_operand();
-    if (upperBound == NULL)
-      throw ir_error("Upper Bound is NULL!!");
-  } else if (tfortran) {
-    
-    upperBound = tfortran->get_bound();
-    
-  }
-  
-  return new omega::CG_roseRepr(upperBound);
-  
-}
-
-IR_CONDITION_TYPE IR_roseLoop::stop_cond() const {
-  SgForStatement *tf = isSgForStatement(tf_);
-  SgFortranDo *tfortran = isSgFortranDo(tf_);
-  
-  if (tf) {
-    SgExpression* stopCond = NULL;
-    SgExpression* test_expr = tf->get_test_expr();
-    
-    if (isSgLessThanOp(test_expr))
-      return IR_COND_LT;
-    else if (isSgLessOrEqualOp(test_expr))
-      return IR_COND_LE;
-    else if (isSgGreaterThanOp(test_expr))
-      return IR_COND_GT;
-    else if (isSgGreaterOrEqualOp(test_expr))
-      return IR_COND_GE;
-    
-    else
-      throw ir_error("loop stop condition unsupported");
-  } else if (tfortran) {
-    SgExpression* increment = tfortran->get_increment();
-    if (!isSgNullExpression(increment)) {
-      if (isSgMinusOp(increment)
-          && !isSgBinaryOp(isSgMinusOp(increment)->get_operand()))
-        return IR_COND_GE;
-      else
-        return IR_COND_LE;
-    } else {
-    	return IR_COND_LE; // Manu:: if increment is not present, assume it to be 1. Just a workaround, not sure if it will be correct for all cases.
-      SgExpression* lowerBound = NULL;
-      SgExpression* upperBound = NULL;
-      SgExpression* init = tfortran->get_initialization();
-      SgIntVal* ub;
-      SgIntVal* lb;
-      if (SgAssignOp* op = isSgAssignOp(init))
-        lowerBound = op->get_rhs_operand();
-      
-      upperBound = tfortran->get_bound();
-      
-      if ((upperBound != NULL) && (lowerBound != NULL)) {
-        
-        if ((ub = isSgIntVal(isSgValueExp(upperBound))) && (lb =
-                                                            isSgIntVal(isSgValueExp(lowerBound)))) {
-          if (ub->get_value() > lb->get_value())
-            return IR_COND_LE;
-          else
-            return IR_COND_GE;
-        } else
-          throw ir_error("loop stop condition unsupported");
-        
-      } else
-        throw ir_error("malformed fortran loop bounds!!");
-      
-    }
-  }
-  
-}
-
-IR_Block *IR_roseLoop::body() const {
-  SgForStatement *tf = isSgForStatement(tf_);
-  SgFortranDo *tfortran = isSgFortranDo(tf_);
-  SgNode* loop_body = NULL;
-  SgStatement* body_statements = NULL;
-  
-  if (tf) {
-    body_statements = tf->get_loop_body();
-  } else if (tfortran) {
-    body_statements = isSgStatement(tfortran->get_body());
-    
-  }
-  
-  loop_body = isSgNode(body_statements);
-  
-  SgStatementPtrList list;
-  if (isSgBasicBlock(loop_body)) {
-    list = isSgBasicBlock(loop_body)->get_statements();
-    
-    if (list.size() == 1)
-      loop_body = isSgNode(*(list.begin()));
-  }
-  
-  if (loop_body == NULL)
-    throw ir_error("for loop body is NULL!!");
-  
-  return new IR_roseBlock(ir_, loop_body);
-}
-
-int IR_roseLoop::step_size() const {
-  
-  SgForStatement *tf = isSgForStatement(tf_);
-  SgFortranDo *tfortran = isSgFortranDo(tf_);
-  
-  if (tf) {
-    SgExpression *increment = tf->get_increment();
-    
-    if (isSgPlusPlusOp(increment))
-      return 1;
-    if (isSgMinusMinusOp(increment))
-      return -1;
-    else if (SgAssignOp* assignment = isSgAssignOp(increment)) {
-      SgBinaryOp* stepsize = isSgBinaryOp(assignment->get_lhs_operand());
-      if (stepsize == NULL)
-        throw ir_error("Step size expression is NULL!!");
-      SgIntVal* step = isSgIntVal(stepsize->get_lhs_operand());
-      return step->get_value();
-    } else if (SgBinaryOp* inc = isSgPlusAssignOp(increment)) {
-      SgIntVal* step = isSgIntVal(inc->get_rhs_operand());
-      return (step->get_value());
-    } else if (SgBinaryOp * inc = isSgMinusAssignOp(increment)) {
-      SgIntVal* step = isSgIntVal(inc->get_rhs_operand());
-      return -(step->get_value());
-    } else if (SgBinaryOp * inc = isSgCompoundAssignOp(increment)) {
-      SgIntVal* step = isSgIntVal(inc->get_rhs_operand());
-      return (step->get_value());
-    }
-    
-  } else if (tfortran) {
-    
-    SgExpression* increment = tfortran->get_increment();
-    
-    if (!isSgNullExpression(increment)) {
-      if (isSgMinusOp(increment)) {
-        if (SgValueExp *inc = isSgValueExp(
-              isSgMinusOp(increment)->get_operand()))
-          if (isSgIntVal(inc))
-            return -(isSgIntVal(inc)->get_value());
-      } else {
-        if (SgValueExp* inc = isSgValueExp(increment))
-          if (isSgIntVal(inc))
-            return isSgIntVal(inc)->get_value();
-      }
-    } else {
-    	return 1; // Manu:: if increment is not present, assume it to be 1. Just a workaround, not sure if it will be correct for all cases.
-      SgExpression* lowerBound = NULL;
-      SgExpression* upperBound = NULL;
-      SgExpression* init = tfortran->get_initialization();
-      SgIntVal* ub;
-      SgIntVal* lb;
-      if (SgAssignOp* op = isSgAssignOp(init))
-        lowerBound = op->get_rhs_operand();
-      
-      upperBound = tfortran->get_bound();
-      
-      if ((upperBound != NULL) && (lowerBound != NULL)) {
-        
-        if ((ub = isSgIntVal(isSgValueExp(upperBound))) && (lb =
-                                                            isSgIntVal(isSgValueExp(lowerBound)))) {
-          if (ub->get_value() > lb->get_value())
-            return 1;
-          else
-            return -1;
-        } else
-          throw ir_error("loop stop condition unsupported");
-        
-      } else
-        throw ir_error("loop stop condition unsupported");
-      
-    }
-    
-  }
-  
-}
-
-IR_Block *IR_roseLoop::convert() {
-  const IR_Code *ir = ir_;
-  SgNode *tnl = isSgNode(tf_);
-  delete this;
-  return new IR_roseBlock(ir, tnl);
-}
-
-IR_Control *IR_roseLoop::clone() const {
-  
-  return new IR_roseLoop(ir_, tf_);
-  
-}
-
-// ----------------------------------------------------------------------------
-// Class: IR_roseBlock
-// ----------------------------------------------------------------------------
-
-omega::CG_outputRepr *IR_roseBlock::original() const {
-  
-  omega::CG_outputRepr * tnl;
-  
-  if (isSgBasicBlock(tnl_)) {
-    
-    SgStatementPtrList *bb = new SgStatementPtrList();
-    SgStatementPtrList::iterator it;
-    for (it = (isSgBasicBlock(tnl_)->get_statements()).begin();
-         it != (isSgBasicBlock(tnl_)->get_statements()).end()
-           && (*it != start_); it++)
-      ;
-    
-    if (it != (isSgBasicBlock(tnl_)->get_statements()).end()) {
-      for (; it != (isSgBasicBlock(tnl_)->get_statements()).end(); it++) {
-        bb->push_back(*it);
-        if ((*it) == end_)
-          break;
-      }
-    }
-    tnl = new omega::CG_roseRepr(bb);
-
-  } else {
-
-    tnl = new omega::CG_roseRepr(tnl_);
-
-  }
-  
-  return tnl;
-  
-}
-omega::CG_outputRepr *IR_roseBlock::extract() const {
-  
-  std::string x = tnl_->unparseToString();
-  
-  omega::CG_roseRepr * tnl;
-  
-  omega::CG_outputRepr* block;
-  
-  if (isSgBasicBlock(tnl_)) {
-    
-    SgStatementPtrList *bb = new SgStatementPtrList();
-    SgStatementPtrList::iterator it;
-    for (it = (isSgBasicBlock(tnl_)->get_statements()).begin();
-         it != (isSgBasicBlock(tnl_)->get_statements()).end()
-           && (*it != start_); it++)
-      ;
-    
-    if (it != (isSgBasicBlock(tnl_)->get_statements()).end()) {
-      for (; it != (isSgBasicBlock(tnl_)->get_statements()).end(); it++) {
-        bb->push_back(*it);
-        if ((*it) == end_)
-          break;
-      }
-    }
-    tnl = new omega::CG_roseRepr(bb);
-    block = tnl->clone();
-    
-  } else {
-    tnl = new omega::CG_roseRepr(tnl_);
-    
-    block = tnl->clone();
-  }
-  
-  delete tnl;
-  return block;
-}
-
-IR_Control *IR_roseBlock::clone() const {
-  return new IR_roseBlock(ir_, tnl_, start_, end_);
-  
-}
-// ----------------------------------------------------------------------------
-// Class: IR_roseIf
-// ----------------------------------------------------------------------------
-omega::CG_outputRepr *IR_roseIf::condition() const {
-  SgNode *tnl = isSgNode(isSgIfStmt(ti_)->get_conditional());
-  SgExpression* exp = NULL;
-  if (SgExprStatement* stmt = isSgExprStatement(tnl))
-    exp = stmt->get_expression();
-  if (exp == NULL)
-    return new omega::CG_roseRepr(tnl);
-  else
-    return new omega::CG_roseRepr(exp);
-}
-
-IR_Block *IR_roseIf::then_body() const {
-  SgNode *tnl = isSgNode(isSgIfStmt(ti_)->get_true_body());
-  
-  if (tnl == NULL)
-    return NULL;
-  
-  return new IR_roseBlock(ir_, tnl);
-}
-
-IR_Block *IR_roseIf::else_body() const {
-  SgNode *tnl = isSgNode(isSgIfStmt(ti_)->get_false_body());
-  
-  if (tnl == NULL)
-    return NULL;
-  
-  return new IR_roseBlock(ir_, tnl);
-}
-
-IR_Block *IR_roseIf::convert() {
-  const IR_Code *ir = ir_;
-  delete this;
-  return new IR_roseBlock(ir, ti_);
-}
-
-IR_Control *IR_roseIf::clone() const {
-  return new IR_roseIf(ir_, ti_);
-}
-
-// -----------------------------------------------------------y-----------------
-// Class: IR_roseCode_Global_Init
-// ----------------------------------------------------------------------------
-
-IR_roseCode_Global_Init *IR_roseCode_Global_Init::pinstance = 0;
-
-IR_roseCode_Global_Init * IR_roseCode_Global_Init::Instance(char** argv) {
-  if (pinstance == 0) {
-    pinstance = new IR_roseCode_Global_Init;
-    pinstance->project = frontend(2, argv);
-    
-  }
-  return pinstance;
-}
-
-// ----------------------------------------------------------------------------
-// Class: IR_roseCode
-// ----------------------------------------------------------------------------
-
-IR_roseCode::IR_roseCode(const char *filename, const char* proc_name) :
-  IR_Code() {
-  
-  SgProject* project;
-  
-  char* argv[2];
-  int counter = 0;
-  argv[0] = (char*) malloc(5 * sizeof(char));
-  argv[1] = (char*) malloc((strlen(filename) + 1) * sizeof(char));
-  strcpy(argv[0], "rose");
-  strcpy(argv[1], filename);
-  
-  project = (IR_roseCode_Global_Init::Instance(argv))->project;
-  firstScope = getFirstGlobalScope(project);
-  SgFilePtrList& file_list = project->get_fileList();
-  
-  for (SgFilePtrList::iterator it = file_list.begin(); it != file_list.end();
-       it++) {
-    file = isSgSourceFile(*it);
-    if (file->get_outputLanguage() == SgFile::e_Fortran_output_language)
-      is_fortran_ = true;
-    else
-      is_fortran_ = false;
-
-    root = file->get_globalScope();
-
-    if (!is_fortran_) { // Manu:: this macro should not be created if the input code is in fortran
-    	buildCpreprocessorDefineDeclaration(root,
-                                        "#define __rose_lt(x,y) ((x)<(y)?(x):(y))",
-                                        PreprocessingInfo::before);
-    	buildCpreprocessorDefineDeclaration(root,
-                                        "#define __rose_gt(x,y) ((x)>(y)?(x):(y))",
-                                        PreprocessingInfo::before);
-    }
-    
-    symtab_ = isSgScopeStatement(root)->get_symbol_table();
-    SgDeclarationStatementPtrList& declList = root->get_declarations();
-    
-    p = declList.begin();
-
-    while (p != declList.end()) {
-      func = isSgFunctionDeclaration(*p);
-      if (func) {
-        if (!strcmp((func->get_name().getString()).c_str(), proc_name))
-          break;
-        
-      }
-      p++;
-      counter++;
-    }
-    if (p != declList.end())
-      break;
-    
-  }
-  
-  symtab2_ = func->get_definition()->get_symbol_table();
-  symtab3_ = func->get_definition()->get_body()->get_symbol_table();
-  // Manu:: added is_fortran_ parameter
-  // TODO Substitute it with a better builder
-  ocg_ = new omega::CG_roseBuilder(is_fortran_, root, firstScope,
-                                   func->get_definition()->get_symbol_table(),
-                                   func->get_definition()->get_body()->get_symbol_table(),
-                                   isSgNode(func->get_definition()->get_body()));
-  
-  i_ = 0; /*i_ handling may need revision */
-  
-  free(argv[1]);
-  free(argv[0]);
-  
-}
-
-IR_roseCode::~IR_roseCode() {
-}
-
-void IR_roseCode::finalizeRose() {
-  SgProject* project = (IR_roseCode_Global_Init::Instance(NULL))->project;
-  project->unparse();
-}
-
-IR_ScalarSymbol *IR_roseCode::CreateScalarSymbol(const IR_Symbol *sym, int) {
-  char str1[14];
-  if (typeid(*sym) == typeid(IR_roseScalarSymbol)) {
-    SgType *tn =
-      static_cast<const IR_roseScalarSymbol *>(sym)->vs_->get_type();
-    sprintf(str1, "newVariable%i", i_);
-    SgVariableDeclaration* defn = buildVariableDeclaration(str1, tn);
-    i_++;
-    
-    SgInitializedNamePtrList& variables = defn->get_variables();
-    SgInitializedNamePtrList::const_iterator i = variables.begin();
-    SgInitializedName* initializedName = *i;
-    SgVariableSymbol* vs = new SgVariableSymbol(initializedName);
-    
-    prependStatement(defn,
-                     isSgScopeStatement(func->get_definition()->get_body()));
-    vs->set_parent(symtab_);
-    symtab_->insert(str1, vs);
-    
-    if (vs == NULL)
-      throw ir_error("in CreateScalarSymbol: vs is NULL!!");
-    
-    return new IR_roseScalarSymbol(this, vs);
-  } else if (typeid(*sym) == typeid(IR_roseArraySymbol)) {
-    SgType *tn1 =
-      static_cast<const IR_roseArraySymbol *>(sym)->vs_->get_type();
-    while (isSgArrayType(tn1) || isSgPointerType(tn1)) {
-      if (isSgArrayType(tn1))
-        tn1 = isSgArrayType(tn1)->get_base_type();
-      else if (isSgPointerType(tn1))
-        tn1 = isSgPointerType(tn1)->get_base_type();
-      else
-        throw ir_error(
-          "in CreateScalarSymbol: symbol not an array nor a pointer!");
-    }
-    
-    sprintf(str1, "newVariable%i", i_);
-    i_++;
-    
-    SgVariableDeclaration* defn1 = buildVariableDeclaration(str1, tn1);
-    SgInitializedNamePtrList& variables1 = defn1->get_variables();
-    
-    SgInitializedNamePtrList::const_iterator i1 = variables1.begin();
-    SgInitializedName* initializedName1 = *i1;
-    
-    SgVariableSymbol *vs1 = new SgVariableSymbol(initializedName1);
-    prependStatement(defn1,
-                     isSgScopeStatement(func->get_definition()->get_body()));
-    
-    vs1->set_parent(symtab_);
-    symtab_->insert(str1, vs1);
-    
-    if (vs1 == NULL)
-      throw ir_error("in CreateScalarSymbol: vs1 is NULL!!");
-    
-    return new IR_roseScalarSymbol(this, vs1);
-  } else
-    throw std::bad_typeid();
-  
-}
-
-IR_ArraySymbol *IR_roseCode::CreateArraySymbol(const IR_Symbol *sym,
-                                               std::vector<omega::CG_outputRepr *> &size, int) {
-  SgType *tn;
-  char str1[14];
-  
-  if (typeid(*sym) == typeid(IR_roseScalarSymbol)) {
-    tn = static_cast<const IR_roseScalarSymbol *>(sym)->vs_->get_type();
-  } else if (typeid(*sym) == typeid(IR_roseArraySymbol)) {
-    tn = static_cast<const IR_roseArraySymbol *>(sym)->vs_->get_type();
-    while (isSgArrayType(tn) || isSgPointerType(tn)) {
-      if (isSgArrayType(tn))
-        tn = isSgArrayType(tn)->get_base_type();
-      else if (isSgPointerType(tn))
-        tn = isSgPointerType(tn)->get_base_type();
-      else
-        throw ir_error(
-          "in CreateScalarSymbol: symbol not an array nor a pointer!");
-    }
-  } else
-    throw std::bad_typeid();
-
-  
-  // Manu:: Fortran support
-  std::vector<SgExpression *>exprs;
-  SgExprListExp *exprLstExp;
-  SgExpression* sizeExpression = new SgNullExpression();
-  SgArrayType* arrayType = new SgArrayType(tn,sizeExpression);
-  sizeExpression->set_parent(arrayType);
-
-  if (!is_fortran_) {
-	  for (int i = size.size() - 1; i >= 0; i--) {
-		tn = buildArrayType(tn,static_cast<omega::CG_roseRepr *>(size[i])->GetExpression());
-	  }
-  } else { // Manu:: required for fortran support
-	  for (int i = size.size() - 1; i >= 0; i--) {
-		exprs.push_back(static_cast<omega::CG_roseRepr *>(size[i])->GetExpression());
-	  }
-  }
-
-  if (is_fortran_) {
-	  exprLstExp = buildExprListExp(exprs);
-	  arrayType->set_dim_info(exprLstExp);
- 	  exprLstExp->set_parent(arrayType);
- 	  arrayType->set_rank(exprLstExp->get_expressions().size());
-  }
-
-  static int rose_array_counter = 1;
-  SgVariableDeclaration* defn2;
-  std::string s;
-  if (!is_fortran_) {
-	  s = std::string("_P") + omega::to_string(rose_array_counter++);
-	  defn2 = buildVariableDeclaration(const_cast<char *>(s.c_str()), tn);
-  } else {// Manu:: fortran support
-	  s = std::string("f_P") + omega::to_string(rose_array_counter++);
-	  defn2 = buildVariableDeclaration(const_cast<char *>(s.c_str()), arrayType);
-  }
-
-
-  SgInitializedNamePtrList& variables2 = defn2->get_variables();
-  
-  SgInitializedNamePtrList::const_iterator i2 = variables2.begin();
-  SgInitializedName* initializedName2 = *i2;
-  SgVariableSymbol *vs = new SgVariableSymbol(initializedName2);
-  
-  prependStatement(defn2,
-                   isSgScopeStatement(func->get_definition()->get_body()));
-  
-  vs->set_parent(symtab_);
-  symtab_->insert(SgName(s.c_str()), vs);
-  
-  return new IR_roseArraySymbol(this, vs);
-}
-
-IR_ScalarRef *IR_roseCode::CreateScalarRef(const IR_ScalarSymbol *sym) {
-  return new IR_roseScalarRef(this,
-                              buildVarRefExp(static_cast<const IR_roseScalarSymbol *>(sym)->vs_));
-  
-}
-
-IR_ArrayRef *IR_roseCode::CreateArrayRef(const IR_ArraySymbol *sym,
-                                         std::vector<omega::CG_outputRepr *> &index) {
-  
-  int t;
-  
-  if (sym->n_dim() != index.size())
-    throw std::invalid_argument("incorrect array symbol dimensionality");
-  
-  const IR_roseArraySymbol *l_sym =
-    static_cast<const IR_roseArraySymbol *>(sym);
-  
-  SgVariableSymbol *vs = l_sym->vs_;
-  SgExpression* ia1 = buildVarRefExp(vs);
-  
-
-
-  if (is_fortran_) { // Manu:: fortran support
-	  std::vector<SgExpression *>exprs;
-	  for (int i = 0 ; i < index.size(); i++) {
-		exprs.push_back(static_cast<omega::CG_roseRepr *>(index[i])->GetExpression());
-	  }
-	  SgExprListExp *exprLstExp;
-	  exprLstExp = buildExprListExp(exprs);
-	  ia1 = buildPntrArrRefExp(ia1,exprLstExp);
-  } else {
-     for (int i = 0; i < index.size(); i++) {
-
-        ia1 = buildPntrArrRefExp(ia1,
-                             static_cast<omega::CG_roseRepr *>(index[i])->GetExpression());
-    
-     }
-  }
-  
-  SgPntrArrRefExp *ia = isSgPntrArrRefExp(ia1);
-  
-  return new IR_roseArrayRef(this, ia, -1);
-  
-}
-
-std::vector<IR_ScalarRef *> IR_roseCode::FindScalarRef(
-  const omega::CG_outputRepr *repr) const {
-  std::vector<IR_ScalarRef *> scalars;
-  SgNode *tnl = static_cast<const omega::CG_roseRepr *>(repr)->GetCode();
-  SgStatementPtrList *list =
-    static_cast<const omega::CG_roseRepr *>(repr)->GetList();
-  SgStatement* stmt;
-  SgExpression * exp;
-  
-  if (list != NULL) {
-    for (SgStatementPtrList::iterator it = (*list).begin();
-         it != (*list).end(); it++) {
-      omega::CG_roseRepr *r = new omega::CG_roseRepr(isSgNode(*it));
-      std::vector<IR_ScalarRef *> a = FindScalarRef(r);
-      delete r;
-      std::copy(a.begin(), a.end(), back_inserter(scalars));
-    }
-  }
-  
-  else if (tnl != NULL) {
-    if (stmt = isSgStatement(tnl)) {
-      if (isSgBasicBlock(stmt)) {
-        SgStatementPtrList& stmts =
-          isSgBasicBlock(stmt)->get_statements();
-        for (int i = 0; i < stmts.size(); i++) {
-          omega::CG_roseRepr *r = new omega::CG_roseRepr(
-            isSgNode(stmts[i]));
-          std::vector<IR_ScalarRef *> a = FindScalarRef(r);
-          delete r;
-          std::copy(a.begin(), a.end(), back_inserter(scalars));
-        }
-        
-      } else if (isSgForStatement(stmt)) {
-        
-        SgForStatement *tnf = isSgForStatement(stmt);
-        omega::CG_roseRepr *r = new omega::CG_roseRepr(
-          isSgStatement(tnf->get_loop_body()));
-        std::vector<IR_ScalarRef *> a = FindScalarRef(r);
-        delete r;
-        std::copy(a.begin(), a.end(), back_inserter(scalars));
-      } else if (isSgFortranDo(stmt)) {
-        SgFortranDo *tfortran = isSgFortranDo(stmt);
-        omega::CG_roseRepr *r = new omega::CG_roseRepr(
-          isSgStatement(tfortran->get_body()));
-        std::vector<IR_ScalarRef *> a = FindScalarRef(r);
-        delete r;
-        std::copy(a.begin(), a.end(), back_inserter(scalars));
-      } else if (isSgIfStmt(stmt)) {
-        SgIfStmt* tni = isSgIfStmt(stmt);
-        omega::CG_roseRepr *r = new omega::CG_roseRepr(
-          isSgNode(tni->get_conditional()));
-        std::vector<IR_ScalarRef *> a = FindScalarRef(r);
-        delete r;
-        std::copy(a.begin(), a.end(), back_inserter(scalars));
-        r = new omega::CG_roseRepr(isSgNode(tni->get_true_body()));
-        a = FindScalarRef(r);
-        delete r;
-        std::copy(a.begin(), a.end(), back_inserter(scalars));
-        r = new omega::CG_roseRepr(isSgNode(tni->get_false_body()));
-        a = FindScalarRef(r);
-        delete r;
-        std::copy(a.begin(), a.end(), back_inserter(scalars));
-      } else if (isSgExprStatement(stmt)) {
-        omega::CG_roseRepr *r = new omega::CG_roseRepr(
-          isSgExpression(
-            isSgExprStatement(stmt)->get_expression()));
-        std::vector<IR_ScalarRef *> a = FindScalarRef(r);
-        delete r;
-        std::copy(a.begin(), a.end(), back_inserter(scalars));
-        
-      }
-    }
-  } else {
-    SgExpression* op =
-      static_cast<const omega::CG_roseRepr *>(repr)->GetExpression();
-    if (isSgVarRefExp(op)
-        && (!isSgArrayType(isSgVarRefExp(op)->get_type()))) {
-      if (SgBinaryOp* op_ = isSgBinaryOp(
-            isSgVarRefExp(op)->get_parent())) {
-        if (SgCompoundAssignOp *op__ = isSgCompoundAssignOp(op_)) {
-          if (isSgCompoundAssignOp(op_)->get_lhs_operand()
-              == isSgVarRefExp(op)) {
-            scalars.push_back(
-              new IR_roseScalarRef(this, isSgVarRefExp(op),
-                                   1));
-            scalars.push_back(
-              new IR_roseScalarRef(this, isSgVarRefExp(op),
-                                   0));
-          }
-        }
-      } else if (SgAssignOp* assmt = isSgAssignOp(
-                   isSgVarRefExp(op)->get_parent())) {
-        
-        if (assmt->get_lhs_operand() == isSgVarRefExp(op))
-          scalars.push_back(
-            new IR_roseScalarRef(this, isSgVarRefExp(op), 1));
-      } else if (SgAssignOp * assmt = isSgAssignOp(
-                   isSgVarRefExp(op)->get_parent())) {
-        
-        if (assmt->get_rhs_operand() == isSgVarRefExp(op))
-          scalars.push_back(
-            new IR_roseScalarRef(this, isSgVarRefExp(op), 0));
-      } else
-        scalars.push_back(
-          new IR_roseScalarRef(this, isSgVarRefExp(op), 0));
-    } else if (isSgAssignOp(op)) {
-      omega::CG_roseRepr *r1 = new omega::CG_roseRepr(
-        isSgAssignOp(op)->get_lhs_operand());
-      std::vector<IR_ScalarRef *> a1 = FindScalarRef(r1);
-      delete r1;
-      std::copy(a1.begin(), a1.end(), back_inserter(scalars));
-      omega::CG_roseRepr *r2 = new omega::CG_roseRepr(
-        isSgAssignOp(op)->get_rhs_operand());
-      std::vector<IR_ScalarRef *> a2 = FindScalarRef(r2);
-      delete r2;
-      std::copy(a2.begin(), a2.end(), back_inserter(scalars));
-      
-    } else if (isSgBinaryOp(op)) {
-      omega::CG_roseRepr *r1 = new omega::CG_roseRepr(
-        isSgBinaryOp(op)->get_lhs_operand());
-      std::vector<IR_ScalarRef *> a1 = FindScalarRef(r1);
-      delete r1;
-      std::copy(a1.begin(), a1.end(), back_inserter(scalars));
-      omega::CG_roseRepr *r2 = new omega::CG_roseRepr(
-        isSgBinaryOp(op)->get_rhs_operand());
-      std::vector<IR_ScalarRef *> a2 = FindScalarRef(r2);
-      delete r2;
-      std::copy(a2.begin(), a2.end(), back_inserter(scalars));
-    } else if (isSgUnaryOp(op)) {
-      omega::CG_roseRepr *r1 = new omega::CG_roseRepr(
-        isSgUnaryOp(op)->get_operand());
-      std::vector<IR_ScalarRef *> a1 = FindScalarRef(r1);
-      delete r1;
-      std::copy(a1.begin(), a1.end(), back_inserter(scalars));
-    }
-    
-  }
-  return scalars;
-  
-}
-
-std::vector<IR_ArrayRef *> IR_roseCode::FindArrayRef(
-  const omega::CG_outputRepr *repr) const {
-  std::vector<IR_ArrayRef *> arrays;
-  SgNode *tnl = static_cast<const omega::CG_roseRepr *>(repr)->GetCode();
-  SgStatementPtrList* list =
-    static_cast<const omega::CG_roseRepr *>(repr)->GetList();
-  SgStatement* stmt;
-  SgExpression * exp;
-  
-  if (list != NULL) {
-    for (SgStatementPtrList::iterator it = (*list).begin();
-         it != (*list).end(); it++) {
-      omega::CG_roseRepr *r = new omega::CG_roseRepr(isSgNode(*it));
-      std::vector<IR_ArrayRef *> a = FindArrayRef(r);
-      delete r;
-      std::copy(a.begin(), a.end(), back_inserter(arrays));
-    }
-  } else if (tnl != NULL) {
-    if (stmt = isSgStatement(tnl)) {
-      if (isSgBasicBlock(stmt)) {
-        SgStatementPtrList& stmts =
-          isSgBasicBlock(stmt)->get_statements();
-        for (int i = 0; i < stmts.size(); i++) {
-          omega::CG_roseRepr *r = new omega::CG_roseRepr(
-            isSgNode(stmts[i]));
-          std::vector<IR_ArrayRef *> a = FindArrayRef(r);
-          delete r;
-          std::copy(a.begin(), a.end(), back_inserter(arrays));
-        }
-        
-      } else if (isSgForStatement(stmt)) {
-        
-        SgForStatement *tnf = isSgForStatement(stmt);
-        omega::CG_roseRepr *r = new omega::CG_roseRepr(
-          isSgStatement(tnf->get_loop_body()));
-        std::vector<IR_ArrayRef *> a = FindArrayRef(r);
-        delete r;
-        std::copy(a.begin(), a.end(), back_inserter(arrays));
-      } else if (isSgFortranDo(stmt)) {
-        SgFortranDo *tfortran = isSgFortranDo(stmt);
-        omega::CG_roseRepr *r = new omega::CG_roseRepr(
-          isSgStatement(tfortran->get_body()));
-        std::vector<IR_ArrayRef *> a = FindArrayRef(r);
-        delete r;
-        std::copy(a.begin(), a.end(), back_inserter(arrays));
-      } else if (isSgIfStmt(stmt)) {
-        SgIfStmt* tni = isSgIfStmt(stmt);
-        omega::CG_roseRepr *r = new omega::CG_roseRepr(
-          isSgNode(tni->get_conditional()));
-        std::vector<IR_ArrayRef *> a = FindArrayRef(r);
-        delete r;
-        std::copy(a.begin(), a.end(), back_inserter(arrays));
-        r = new omega::CG_roseRepr(isSgNode(tni->get_true_body()));
-        a = FindArrayRef(r);
-        delete r;
-        std::copy(a.begin(), a.end(), back_inserter(arrays));
-        r = new omega::CG_roseRepr(isSgNode(tni->get_false_body()));
-        a = FindArrayRef(r);
-        delete r;
-        std::copy(a.begin(), a.end(), back_inserter(arrays));
-      } else if (isSgExprStatement(stmt)) {
-        omega::CG_roseRepr *r = new omega::CG_roseRepr(
-          isSgExpression(
-            isSgExprStatement(stmt)->get_expression()));
-        std::vector<IR_ArrayRef *> a = FindArrayRef(r);
-        delete r;
-        std::copy(a.begin(), a.end(), back_inserter(arrays));
-        
-      }
-    }
-  } else {
-    SgExpression* op =
-      static_cast<const omega::CG_roseRepr *>(repr)->GetExpression();
-    if (isSgPntrArrRefExp(op)) {
-      
-      SgVarRefExp* base;
-      SgExpression* op2;
-      if (isSgCompoundAssignOp(isSgPntrArrRefExp(op)->get_parent())) {
-        IR_roseArrayRef *ref1 = new IR_roseArrayRef(this,
-                                                    isSgPntrArrRefExp(op), 0);
-        arrays.push_back(ref1);
-        IR_roseArrayRef *ref2 = new IR_roseArrayRef(this,
-                                                    isSgPntrArrRefExp(op), 1);
-        arrays.push_back(ref2);
-      } else {
-        IR_roseArrayRef *ref3 = new IR_roseArrayRef(this,
-                                                    isSgPntrArrRefExp(op), -1);
-        arrays.push_back(ref3);
-        
-        while (isSgPntrArrRefExp(op)) {
-          op2 = isSgPntrArrRefExp(op)->get_rhs_operand();
-          op = isSgPntrArrRefExp(op)->get_lhs_operand();
-          omega::CG_roseRepr *r = new omega::CG_roseRepr(op2);
-          std::vector<IR_ArrayRef *> a = FindArrayRef(r);
-          delete r;
-          std::copy(a.begin(), a.end(), back_inserter(arrays));
-          
-        }
-      }
-    } else if (isSgAssignOp(op)) {
-      omega::CG_roseRepr *r1 = new omega::CG_roseRepr(
-        isSgAssignOp(op)->get_lhs_operand());
-      std::vector<IR_ArrayRef *> a1 = FindArrayRef(r1);
-      delete r1;
-      std::copy(a1.begin(), a1.end(), back_inserter(arrays));
-      omega::CG_roseRepr *r2 = new omega::CG_roseRepr(
-        isSgAssignOp(op)->get_rhs_operand());
-      std::vector<IR_ArrayRef *> a2 = FindArrayRef(r2);
-      delete r2;
-      std::copy(a2.begin(), a2.end(), back_inserter(arrays));
-      
-    } else if (isSgBinaryOp(op)) {
-      omega::CG_roseRepr *r1 = new omega::CG_roseRepr(
-        isSgBinaryOp(op)->get_lhs_operand());
-      std::vector<IR_ArrayRef *> a1 = FindArrayRef(r1);
-      delete r1;
-      std::copy(a1.begin(), a1.end(), back_inserter(arrays));
-      omega::CG_roseRepr *r2 = new omega::CG_roseRepr(
-        isSgBinaryOp(op)->get_rhs_operand());
-      std::vector<IR_ArrayRef *> a2 = FindArrayRef(r2);
-      delete r2;
-      std::copy(a2.begin(), a2.end(), back_inserter(arrays));
-    } else if (isSgUnaryOp(op)) {
-      omega::CG_roseRepr *r1 = new omega::CG_roseRepr(
-        isSgUnaryOp(op)->get_operand());
-      std::vector<IR_ArrayRef *> a1 = FindArrayRef(r1);
-      delete r1;
-      std::copy(a1.begin(), a1.end(), back_inserter(arrays));
-    }
-    
-  }
-  return arrays;
-}
-
-std::vector<IR_Control *> IR_roseCode::FindOneLevelControlStructure(
-  const IR_Block *block) const {
-
-  std::vector<IR_Control *> controls;
-  int i;
-  int j;
-  int begin;
-  int end;
-  SgNode* tnl_ =
-    ((static_cast<IR_roseBlock *>(const_cast<IR_Block *>(block)))->tnl_);
-  
-  if (isSgForStatement(tnl_))
-    controls.push_back(new IR_roseLoop(this, tnl_));
-  else if (isSgFortranDo(tnl_))
-	  controls.push_back(new IR_roseLoop(this, tnl_));
-  else if (isSgIfStmt(tnl_))
-    controls.push_back(new IR_roseIf(this, tnl_));
-  
-  else if (isSgBasicBlock(tnl_)) {
-    
-    SgStatementPtrList& stmts = isSgBasicBlock(tnl_)->get_statements();
-    
-    for (i = 0; i < stmts.size(); i++) {
-      if (isSgNode(stmts[i])
-          == ((static_cast<IR_roseBlock *>(const_cast<IR_Block *>(block)))->start_))
-        begin = i;
-      if (isSgNode(stmts[i])
-          == ((static_cast<IR_roseBlock *>(const_cast<IR_Block *>(block)))->end_))
-        end = i;
-    }
-    
-    SgNode* start = NULL;
-    SgNode* prev = NULL;
-    for (i = begin; i <= end; i++) {
-      if (isSgForStatement(stmts[i]) || isSgFortranDo(stmts[i])) {
-        if (start != NULL) {
-          controls.push_back(
-            new IR_roseBlock(this,
-                             (static_cast<IR_roseBlock *>(const_cast<IR_Block *>(block)))->tnl_,
-                             start, prev));
-          start = NULL;
-        }
-        controls.push_back(new IR_roseLoop(this, isSgNode(stmts[i])));
-      } else if (isSgIfStmt(stmts[i])) {
-        if (start != NULL) {
-          controls.push_back(
-            new IR_roseBlock(this,
-                             (static_cast<IR_roseBlock *>(const_cast<IR_Block *>(block)))->tnl_,
-                             start, prev));
-          start = NULL;
-        }
-        controls.push_back(new IR_roseIf(this, isSgNode(stmts[i])));
-        
-      } else if (start == NULL)
-        start = isSgNode(stmts[i]);
-      
-      prev = isSgNode(stmts[i]);
-    }
-    
-    if ((start != NULL) && (start != isSgNode(stmts[begin])))
-      controls.push_back(
-        new IR_roseBlock(this,
-                         (static_cast<IR_roseBlock *>(const_cast<IR_Block *>(block)))->tnl_,
-                         start, prev));
-  }
-  
-  return controls;
-  
-}
-
-IR_Block *IR_roseCode::MergeNeighboringControlStructures(
-  const std::vector<IR_Control *> &controls) const {
-  if (controls.size() == 0)
-    return NULL;
-  
-  SgNode *tnl = NULL;
-  SgNode *start, *end;
-  for (int i = 0; i < controls.size(); i++) {
-    switch (controls[i]->type()) {
-    case IR_CONTROL_LOOP: {
-      SgNode *tf = static_cast<IR_roseLoop *>(controls[i])->tf_;
-      if (tnl == NULL) {
-        tnl = tf->get_parent();
-        start = end = tf;
-      } else {
-        if (tnl != tf->get_parent())
-          throw ir_error("controls to merge not at the same level");
-        end = tf;
-      }
-      break;
-    }
-    case IR_CONTROL_BLOCK: {
-      if (tnl == NULL) {
-        tnl = static_cast<IR_roseBlock *>(controls[0])->tnl_;
-        start = static_cast<IR_roseBlock *>(controls[0])->start_;
-        end = static_cast<IR_roseBlock *>(controls[0])->end_;
-      } else {
-        if (tnl != static_cast<IR_roseBlock *>(controls[0])->tnl_)
-          throw ir_error("controls to merge not at the same level");
-        end = static_cast<IR_roseBlock *>(controls[0])->end_;
-      }
-      break;
-    }
-    default:
-      throw ir_error("unrecognized control to merge");
-    }
-  }
-  
-  return new IR_roseBlock(controls[0]->ir_, tnl, start, end);
-}
-
-IR_Block *IR_roseCode::GetCode() const {
-  SgFunctionDefinition* def = NULL;
-  SgBasicBlock* block = NULL;
-  if (func != 0) {
-    if (def = func->get_definition()) {
-      if (block = def->get_body())
-        return new IR_roseBlock(this,
-                                func->get_definition()->get_body());
-    }
-  }
-  
-  return NULL;
-  
-}
-
-void IR_roseCode::ReplaceCode(IR_Control *old, omega::CG_outputRepr *repr) {
-  /*    SgStatementPtrList *tnl =
-        static_cast<omega::CG_roseRepr *>(repr)->GetList();
-        SgNode *tf_old;
-  */
-  SgStatementPtrList *tnl =
-    static_cast<omega::CG_roseRepr *>(repr)->GetList();
-  SgNode* node_ = static_cast<omega::CG_roseRepr *>(repr)->GetCode();
-  SgNode * tf_old;
-  
-  /* May need future revision it tnl has more than one statement */
-  
-  switch (old->type()) {
-    
-  case IR_CONTROL_LOOP:
-    tf_old = static_cast<IR_roseLoop *>(old)->tf_;
-    break;
-  case IR_CONTROL_BLOCK:
-    tf_old = static_cast<IR_roseBlock *>(old)->start_;
-    break;
-    
-  default:
-    throw ir_error("control structure to be replaced not supported");
-    break;
-  }
-  
-  std::string y = tf_old->unparseToString();
-  SgStatement *s = isSgStatement(tf_old);
-  if (s != 0) {
-    SgStatement *p = isSgStatement(tf_old->get_parent());
-    
-    if (p != 0) {
-      SgStatement* temp = s;
-      if (tnl != NULL) {
-        SgStatementPtrList::iterator it = (*tnl).begin();
-        p->insert_statement(temp, *it, true);
-        temp = *it;
-        p->remove_statement(s);
-        it++;
-        for (; it != (*tnl).end(); it++) {
-          p->insert_statement(temp, *it, false);
-          temp = *it;
-        }
-      } else if (node_ != NULL) {
-        if (!isSgStatement(node_))
-          throw ir_error("Replacing Code not a statement!");
-        else {
-          SgStatement* replace_ = isSgStatement(node_);
-          p->insert_statement(s, replace_, true);
-          p->remove_statement(s);
-          
-        }
-      } else {
-        throw ir_error("Replacing Code not a statement!");
-      }
-    } else
-      throw ir_error("Replacing Code not a statement!");
-  } else
-    throw ir_error("Replacing Code not a statement!");
-  
-  delete old;
-  delete repr;
-  /* May need future revision it tnl has more than one statement */
-  /*
-    switch (old->type()) {
-    
-    case IR_CONTROL_LOOP:
-    tf_old = static_cast<IR_roseLoop *>(old)->tf_;
-    break;
-    case IR_CONTROL_BLOCK:
-    tf_old = static_cast<IR_roseBlock *>(old)->start_;
-    break;
-    
-    default:
-    throw ir_error("control structure to be replaced not supported");
-    break;
-    }
-    
-    // std::string y = tf_old->unparseToString();
-    SgStatement *s = isSgStatement(tf_old);
-    if (s != 0) {
-    SgStatement *p = isSgStatement(tf_old->get_parent());
-    
-    if (p != 0) {
-    //      SgStatement* it2 = isSgStatement(tnl);
-    
-    //   if(it2 != NULL){
-    p->replace_statement(s, *tnl);
-    //   }
-    //   else {
-    //          throw ir_error("Replacing Code not a statement!");
-    //      }
-    } else
-    throw ir_error("Replacing Code not a statement!");
-    } else
-    throw ir_error("Replacing Code not a statement!");
-    //  y = tnl->unparseToString();
-    delete old;
-    delete repr;
-  */
-}
-
-void IR_roseCode::ReplaceExpression(IR_Ref *old, omega::CG_outputRepr *repr) {
-  
-  SgExpression* op = static_cast<omega::CG_roseRepr *>(repr)->GetExpression();
-  
-  if (typeid(*old) == typeid(IR_roseArrayRef)) {
-    SgPntrArrRefExp* ia_orig = static_cast<IR_roseArrayRef *>(old)->ia_;
-    SgExpression* parent = isSgExpression(isSgNode(ia_orig)->get_parent());
-    std::string x = isSgNode(op)->unparseToString();
-    std::string y = isSgNode(ia_orig)->unparseToString();
-    if (parent != NULL) {
-      std::string z = isSgNode(parent)->unparseToString();
-      parent->replace_expression(ia_orig, op);
-      isSgNode(op)->set_parent(isSgNode(parent));
-      
-      /* if(isSgBinaryOp(parent))
-         {
-         if(isSgBinaryOp(parent)->get_lhs_operand() == ia_orig){
-         isSgBinaryOp(parent)->set_lhs_operand(op);   
-         }else if(isSgBinaryOp(parent)->get_rhs_operand() == ia_orig){
-         isSgBinaryOp(parent)->set_rhs_operand(op); 
-         
-         
-         } 
-         else
-         parent->replace_expression(ia_orig, op);
-      */
-    } else {
-      SgStatement* parent_stmt = isSgStatement(
-        isSgNode(ia_orig)->get_parent());
-      if (parent_stmt != NULL)
-        parent_stmt->replace_expression(ia_orig, op);
-      else
-        throw ir_error(
-          "ReplaceExpression: parent neither expression nor statement");
-    }
-  } else
-    throw ir_error("replacing a scalar variable not implemented");
-  
-  delete old;
-}
-
-IR_OPERATION_TYPE IR_roseCode::QueryExpOperation(
-  const omega::CG_outputRepr *repr) const {
-  SgExpression* op =
-    static_cast<const omega::CG_roseRepr *>(repr)->GetExpression();
-  
-  if (isSgValueExp(op))
-    return IR_OP_CONSTANT;
-  else if (isSgVarRefExp(op) || isSgPntrArrRefExp(op))
-    return IR_OP_VARIABLE;
-  else if (isSgAssignOp(op) || isSgCompoundAssignOp(op))
-    return IR_OP_ASSIGNMENT;
-  else if (isSgAddOp(op))
-    return IR_OP_PLUS;
-  else if (isSgSubtractOp(op))
-    return IR_OP_MINUS;
-  else if (isSgMultiplyOp(op))
-    return IR_OP_MULTIPLY;
-  else if (isSgDivideOp(op))
-    return IR_OP_DIVIDE;
-  else if (isSgMinusOp(op))
-    return IR_OP_NEGATIVE;
-  else if (isSgConditionalExp(op)) {
-    SgExpression* cond = isSgConditionalExp(op)->get_conditional_exp();
-    if (isSgGreaterThanOp(cond))
-      return IR_OP_MAX;
-    else if (isSgLessThanOp(cond))
-      return IR_OP_MIN;
-  } else if (isSgUnaryAddOp(op))
-    return IR_OP_POSITIVE;
-  else if (isSgNullExpression(op))
-    return IR_OP_NULL;
-  else
-    return IR_OP_UNKNOWN;
-}
-
-IR_CONDITION_TYPE IR_roseCode::QueryBooleanExpOperation(
-  const omega::CG_outputRepr *repr) const {
-  SgExpression* op2 =
-    static_cast<const omega::CG_roseRepr *>(repr)->GetExpression();
-  SgNode* op;
-  
-  if (op2 == NULL) {
-    op = static_cast<const omega::CG_roseRepr *>(repr)->GetCode();
-    
-    if (op != NULL) {
-      if (isSgExprStatement(op))
-        op2 = isSgExprStatement(op)->get_expression();
-      else
-        return IR_COND_UNKNOWN;
-    } else
-      return IR_COND_UNKNOWN;
-  }
-  
-  if (isSgEqualityOp(op2))
-    return IR_COND_EQ;
-  else if (isSgNotEqualOp(op2))
-    return IR_COND_NE;
-  else if (isSgLessThanOp(op2))
-    return IR_COND_LT;
-  else if (isSgLessOrEqualOp(op2))
-    return IR_COND_LE;
-  else if (isSgGreaterThanOp(op2))
-    return IR_COND_GT;
-  else if (isSgGreaterOrEqualOp(op2))
-    return IR_COND_GE;
-  
-  return IR_COND_UNKNOWN;
-  
-}
-
-std::vector<omega::CG_outputRepr *> IR_roseCode::QueryExpOperand(
-  const omega::CG_outputRepr *repr) const {
-  std::vector<omega::CG_outputRepr *> v;
-  SgExpression* op1;
-  SgExpression* op2;
-  SgExpression* op =
-    static_cast<const omega::CG_roseRepr *>(repr)->GetExpression();
-  omega::CG_roseRepr *repr1;
-  
-  if (isSgValueExp(op) || isSgVarRefExp(op)) {
-    omega::CG_roseRepr *repr = new omega::CG_roseRepr(op);
-    v.push_back(repr);
-  } else if (isSgAssignOp(op)) {
-    op1 = isSgAssignOp(op)->get_rhs_operand();
-    repr1 = new omega::CG_roseRepr(op1);
-    v.push_back(repr1);
-    /*may be a problem as assignOp is a binaryop destop might be needed */
-  } else if (isSgMinusOp(op)) {
-    op1 = isSgMinusOp(op)->get_operand();
-    repr1 = new omega::CG_roseRepr(op1);
-    v.push_back(repr1);
-  } else if (isSgUnaryAddOp(op)) {
-    op1 = isSgUnaryAddOp(op)->get_operand();
-    repr1 = new omega::CG_roseRepr(op1);
-    v.push_back(repr1);
-  } else if ((isSgAddOp(op) || isSgSubtractOp(op))
-             || (isSgMultiplyOp(op) || isSgDivideOp(op))) {
-    op1 = isSgBinaryOp(op)->get_lhs_operand();
-    repr1 = new omega::CG_roseRepr(op1);
-    v.push_back(repr1);
-    
-    op2 = isSgBinaryOp(op)->get_rhs_operand();
-    repr1 = new omega::CG_roseRepr(op2);
-    v.push_back(repr1);
-  } else if (isSgConditionalExp(op)) {
-    SgExpression* cond = isSgConditionalExp(op)->get_conditional_exp();
-    op1 = isSgBinaryOp(cond)->get_lhs_operand();
-    repr1 = new omega::CG_roseRepr(op1);
-    v.push_back(repr1);
-    
-    op2 = isSgBinaryOp(cond)->get_rhs_operand();
-    repr1 = new omega::CG_roseRepr(op2);
-    v.push_back(repr1);
-  } else if (isSgCompoundAssignOp(op)) {
-    SgExpression* cond = isSgCompoundAssignOp(op);
-    op1 = isSgBinaryOp(cond)->get_lhs_operand();
-    repr1 = new omega::CG_roseRepr(op1);
-    v.push_back(repr1);
-    
-    op2 = isSgBinaryOp(cond)->get_rhs_operand();
-    repr1 = new omega::CG_roseRepr(op2);
-    v.push_back(repr1);
-    
-  } else if (isSgBinaryOp(op)) {
-    
-    op1 = isSgBinaryOp(op)->get_lhs_operand();
-    repr1 = new omega::CG_roseRepr(op1);
-    v.push_back(repr1);
-    
-    op2 = isSgBinaryOp(op)->get_rhs_operand();
-    repr1 = new omega::CG_roseRepr(op2);
-    v.push_back(repr1);
-  }
-  
-  else
-    throw ir_error("operation not supported");
-  
-  return v;
-}
-
-IR_Ref *IR_roseCode::Repr2Ref(const omega::CG_outputRepr *repr) const {
-  SgExpression* op =
-    static_cast<const omega::CG_roseRepr *>(repr)->GetExpression();
-  
-  if (SgValueExp* im = isSgValueExp(op)) {
-    if (isSgIntVal(im))
-      return new IR_roseConstantRef(this,
-                                    static_cast<omega::coef_t>(isSgIntVal(im)->get_value()));
-    else if (isSgUnsignedIntVal(im))
-      return new IR_roseConstantRef(this,
-                                    static_cast<omega::coef_t>(isSgUnsignedIntVal(im)->get_value()));
-    else if (isSgLongIntVal(im))
-      return new IR_roseConstantRef(this,
-                                    static_cast<omega::coef_t>(isSgLongIntVal(im)->get_value()));
-    else if (isSgFloatVal(im))
-      return new IR_roseConstantRef(this, isSgFloatVal(im)->get_value());
-    else
-      assert(0);
-    
-  } else if (isSgVarRefExp(op))
-    return new IR_roseScalarRef(this, isSgVarRefExp(op));
-  else
-    assert(0);
-  
-}
-
diff --git a/chill/src/ir_rose_utils.cc b/chill/src/ir_rose_utils.cc
deleted file mode 100644
index 64b0891..0000000
--- a/chill/src/ir_rose_utils.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-/*****************************************************************************
- Copyright (C) 2008 University of Southern California
- Copyright (C) 2009 University of Utah
- All Rights Reserved.
-
- Purpose:
-   ROSE interface utilities.
-
- Notes:
-
- Update history:
-   01/2006 created by Chun Chen
-*****************************************************************************/
-
-#include "ir_rose_utils.hh"
-
-
-
-std::vector<SgForStatement *> find_loops(SgNode *tnl) {
-  std::vector<SgForStatement *> result;
- 
-  SgStatementPtrList& blockStatements = isSgBasicBlock(tnl)->get_statements();
-  for(SgStatementPtrList::const_iterator j = blockStatements.begin(); j != blockStatements.end(); j++)
-    if(isSgForStatement(*j))
-      result.push_back(isSgForStatement(*j));
-  
-  return result;
-}
-
-std::vector<SgForStatement *> find_deepest_loops(SgStatementPtrList& tnl) {
-  
-  std::vector<SgForStatement *> loops;
-  
-  
-  
-  for(SgStatementPtrList::const_iterator j = tnl.begin(); j != tnl.end(); j++)
-  {
-    std::vector<SgForStatement *> t = find_deepest_loops(isSgNode(*j));
-    if (t.size() > loops.size())
-      loops = t;
-  }       
-  
-  
-  
-  return loops;
-  
-}
-
-std::vector<SgForStatement *> find_deepest_loops(SgNode *tn) {
-  if (isSgForStatement(tn)) {
-    std::vector<SgForStatement *> loops;
-    
-    SgForStatement *tnf = static_cast<SgForStatement*>(tn);
-    loops.insert(loops.end(), tnf);
-    std::vector<SgForStatement*> t = find_deepest_loops(isSgNode(tnf->get_loop_body()));
-    std::copy(t.begin(), t.end(), std::back_inserter(loops));
-    
-    return loops;
-  }
-  else if (isSgBasicBlock(tn)) {
-    SgBasicBlock *tnb = static_cast<SgBasicBlock*>(tn);
-    return find_deepest_loops(tnb->get_statements());
-  }
-  else 
-    return std::vector<SgForStatement *>();               
-}
-
diff --git a/chill/src/irtools.cc b/chill/src/irtools.cc
deleted file mode 100644
index 4ab6c85..0000000
--- a/chill/src/irtools.cc
+++ /dev/null
@@ -1,279 +0,0 @@
-/*****************************************************************************
- Copyright (C) 2010 University of Utah
- All Rights Reserved.
-
- Purpose:
-   Useful tools to analyze code in compiler IR format.
-
- Notes:
-
- History:
-   06/2010 Created by Chun Chen.
-*****************************************************************************/
-
-#include <iostream>
-#include <code_gen/CG_outputBuilder.h>
-#include "irtools.hh"
-#include "omegatools.hh"
-#include "chill_error.hh"
-
-using namespace omega;
-
-// Build IR tree from the source code.  Block type node can only be
-// leaf, i.e., there is no further structures inside a block allowed.
-std::vector<ir_tree_node *> build_ir_tree(IR_Control *control, ir_tree_node *parent) {
-  std::vector<ir_tree_node *> result;
-  
-  switch (control->type()) {
-  case IR_CONTROL_BLOCK: {
-    std::vector<IR_Control *> controls = control->ir_->FindOneLevelControlStructure(static_cast<IR_Block *>(control));
-    if (controls.size() == 0) {
-      ir_tree_node *node = new ir_tree_node;
-      node->content = control;
-      node->parent = parent;
-      node->payload = -1;
-      result.push_back(node);
-    }
-    else {
-      delete control;
-      for (int i = 0; i < controls.size(); i++)
-        switch (controls[i]->type()) {
-        case IR_CONTROL_BLOCK: {
-          std::vector<ir_tree_node *> t = build_ir_tree(controls[i], parent);
-          result.insert(result.end(), t.begin(), t.end());
-          break;
-        }
-        case IR_CONTROL_LOOP: {
-          ir_tree_node *node = new ir_tree_node;
-          node->content = controls[i];
-          node->parent = parent;
-          node->children = build_ir_tree(static_cast<IR_Loop *>(controls[i])->body(), node);
-          node->payload = -1;
-          result.push_back(node);
-          break;
-        }
-        case IR_CONTROL_IF: {
-          static int unique_if_identifier = 0;
-          
-          IR_Block *block = static_cast<IR_If *>(controls[i])->then_body();
-          if (block != NULL) {
-            ir_tree_node *node = new ir_tree_node;
-            node->content = controls[i];
-            node->parent = parent;
-            node->children = build_ir_tree(block, node);
-            node->payload = unique_if_identifier+1;
-            result.push_back(node);
-          }
-          
-          
-          block = static_cast<IR_If *>(controls[i])->else_body();
-          if ( block != NULL) {
-            ir_tree_node *node = new ir_tree_node;
-            node->content = controls[i]->clone();
-            node->parent = parent;
-            node->children = build_ir_tree(block, node);
-            node->payload = unique_if_identifier;
-            result.push_back(node);
-          }
-          
-          unique_if_identifier += 2;
-          break;
-        }
-        default:
-          ir_tree_node *node = new ir_tree_node;
-          node->content = controls[i];
-          node->parent = parent;
-          node->payload = -1;
-          result.push_back(node);
-          break;
-        }
-    }
-    break;
-  }
-  case IR_CONTROL_LOOP: {
-    ir_tree_node *node = new ir_tree_node;
-    node->content = control;
-    node->parent = parent;
-    node->children = build_ir_tree(static_cast<const IR_Loop *>(control)->body(), node);
-    node->payload = -1;
-    result.push_back(node);
-    break;
-  }
-  default:
-    ir_tree_node *node = new ir_tree_node;
-    node->content = control;
-    node->parent = parent;
-    node->payload = -1;
-    result.push_back(node);
-    break;
-  }
-  
-  return result;
-}
-
-
-// Extract statements from IR tree. Statements returned are ordered in
-// lexical order in the source code.
-std::vector<ir_tree_node *> extract_ir_stmts(const std::vector<ir_tree_node *> &ir_tree) {
-  std::vector<ir_tree_node *> result;
-  for (int i = 0; i < ir_tree.size(); i++)
-    switch (ir_tree[i]->content->type()) {
-    case IR_CONTROL_BLOCK:
-      result.push_back(ir_tree[i]);
-      break;
-    case IR_CONTROL_LOOP: {
-      // clear loop payload from previous unsuccessful initialization process
-      ir_tree[i]->payload = -1;
-      
-      std::vector<ir_tree_node *> t = extract_ir_stmts(ir_tree[i]->children);
-      result.insert(result.end(), t.begin(), t.end());
-      break;
-    }      
-    case IR_CONTROL_IF: {
-      std::vector<ir_tree_node *> t = extract_ir_stmts(ir_tree[i]->children);
-      result.insert(result.end(), t.begin(), t.end());
-      break;
-    }
-    default:
-      throw std::invalid_argument("invalid ir tree");
-    }
-  
-  return result;
-}
-
-
-bool is_dependence_valid(ir_tree_node *src_node, ir_tree_node *dst_node,
-                         const DependenceVector &dv, bool before) {
-  std::set<ir_tree_node *> loop_nodes;
-  ir_tree_node *itn = src_node;
-  
-  if (!dv.is_scalar_dependence) {
-    while (itn->parent != NULL) {
-      itn = itn->parent;
-      if (itn->content->type() == IR_CONTROL_LOOP)
-        loop_nodes.insert(itn);
-    }
-    
-    int last_dim = -1;
-    itn = dst_node;
-    while (itn->parent != NULL) {
-      itn = itn->parent;
-      if (itn->content->type() == IR_CONTROL_LOOP
-          && loop_nodes.find(itn) != loop_nodes.end()
-          && itn->payload > last_dim)
-        last_dim = itn->payload;
-    }
-    
-    if (last_dim == -1)
-      return true;
-    
-    for (int i = 0; i <= last_dim; i++) {
-      if (dv.lbounds[i] > 0)
-        return true;
-      else if (dv.lbounds[i] < 0)
-        return false;
-    }
-    
-    if (before)
-      return true;
-    else
-      return false;
-  }
-  
-  return true;
-  
-}
-
-
-
-// Test data dependences between two statements. The first statement
-// in parameter must be lexically before the second statement in
-// parameter.  Returned dependences are all lexicographically
-// positive. The first vector in returned pair is dependences from the
-// first statement to the second statement and the second vector in
-// returned pair is in reverse order.
-std::pair<std::vector<DependenceVector>, std::vector<DependenceVector> > test_data_dependences(
-  IR_Code *ir, const CG_outputRepr *repr1, const Relation &IS1,
-  const CG_outputRepr *repr2, const Relation &IS2,
-  std::vector<Free_Var_Decl*> &freevar, std::vector<std::string> index,
-  int i, int j) {
-  std::pair<std::vector<DependenceVector>, std::vector<DependenceVector> > result;
-  
-  if (repr1 == repr2) {
-    std::vector<IR_ArrayRef *> access = ir->FindArrayRef(repr1);
-    
-    for (int i = 0; i < access.size(); i++) {
-      IR_ArrayRef *a = access[i];
-      IR_ArraySymbol *sym_a = a->symbol();
-      for (int j = i; j < access.size(); j++) {
-        IR_ArrayRef *b = access[j];
-        IR_ArraySymbol *sym_b = b->symbol();
-        
-        if (*sym_a == *sym_b && (a->is_write() || b->is_write())) {
-          Relation r = arrays2relation(ir, freevar, a, IS1, b, IS2);
-          std::pair<std::vector<DependenceVector>,
-            std::vector<DependenceVector> > dv =
-            relation2dependences(a, b, r);
-          result.first.insert(result.first.end(), dv.first.begin(),
-                              dv.first.end());
-          result.second.insert(result.second.end(), dv.second.begin(),
-                               dv.second.end());
-        }
-        delete sym_b;
-      }
-      delete sym_a;
-      
-    }
-    
-    for (int i = 0; i < access.size(); i++)
-      delete access[i];
-  } else {
-    std::vector<IR_ArrayRef *> access1 = ir->FindArrayRef(repr1);
-    std::vector<IR_ArrayRef *> access2 = ir->FindArrayRef(repr2);
-    
-    for (int i = 0; i < access1.size(); i++) {
-      IR_ArrayRef *a = access1[i];
-      IR_ArraySymbol *sym_a = a->symbol();
-      
-      for (int j = 0; j < access2.size(); j++) {
-        IR_ArrayRef *b = access2[j];
-        IR_ArraySymbol *sym_b = b->symbol();
-        if (*sym_a == *sym_b && (a->is_write() || b->is_write())) {
-          Relation r = arrays2relation(ir, freevar, a, IS1, b, IS2);
-          std::pair<std::vector<DependenceVector>,
-            std::vector<DependenceVector> > dv =
-            relation2dependences(a, b, r);
-          
-          result.first.insert(result.first.end(), dv.first.begin(),
-                              dv.first.end());
-          result.second.insert(result.second.end(), dv.second.begin(),
-                               dv.second.end());
-        }
-        delete sym_b;
-      }
-      delete sym_a;
-    }
-    
-    for (int i = 0; i < access1.size(); i++)
-      delete access1[i];
-    for (int i = 0; i < access2.size(); i++)
-      delete access2[i];
-  }
-  /*std::pair<std::vector<DependenceVector>,
-    std::vector<DependenceVector> > dv =
-    ir->FindScalarDeps(repr1, repr2, index, i, j);
-    
-    
-    result.first.insert(result.first.end(), dv.first.begin(),
-    dv.first.end());
-    result.second.insert(result.second.end(), dv.second.begin(),
-    dv.second.end());*/
-  /*result.first.insert(result.first.end(), dv.first.begin(),
-    dv.first.end());
-    result.second.insert(result.second.end(), dv.second.begin(),
-    dv.second.end());
-  */
-  
-  return result;
-}
-
diff --git a/chill/src/loop.cc b/chill/src/loop.cc
deleted file mode 100644
index f187a50..0000000
--- a/chill/src/loop.cc
+++ /dev/null
@@ -1,1859 +0,0 @@
-/*****************************************************************************
- Copyright (C) 2008 University of Southern California
- Copyright (C) 2009-2010 University of Utah
- All Rights Reserved.
-
- Purpose:
- Core loop transformation functionality.
-
- Notes:
- "level" (starting from 1) means loop level and it corresponds to "dim"
- (starting from 0) in transformed iteration space [c_1,l_1,c_2,l_2,....,
- c_n,l_n,c_(n+1)], e.g., l_2 is loop level 2 in generated code, dim 3
- in transformed iteration space, and variable 4 in Omega relation.
- All c's are constant numbers only and they will not show up as actual loops.
- Formula:
- dim = 2*level - 1
- var = dim + 1
-
- History:
- 10/2005 Created by Chun Chen.
- 09/2009 Expand tile functionality, -chun
- 10/2009 Initialize unfusible loop nest without bailing out, -chun
-*****************************************************************************/
-
-#include <limits.h>
-#include <math.h>
-#include <code_gen/codegen.h>
-#include <code_gen/CG_utils.h>
-#include <iostream>
-#include <algorithm>
-#include <map>
-#include "loop.hh"
-#include "omegatools.hh"
-#include "irtools.hh"
-#include "chill_error.hh"
-#include <string.h>
-#include <list>
-using namespace omega;
-
-const std::string Loop::tmp_loop_var_name_prefix = std::string("chill_t"); // Manu:: In fortran, first character of a variable name must be a letter, so this change
-const std::string Loop::overflow_var_name_prefix = std::string("over");
-
-//-----------------------------------------------------------------------------
-// Class Loop
-//-----------------------------------------------------------------------------
-// --begin Anand: Added from CHiLL 0.2
-
-bool Loop::isInitialized() const {
-  return stmt.size() != 0 && !stmt[0].xform.is_null();
-}
-
-//--end Anand: added from CHiLL 0.2
-
-bool Loop::init_loop(std::vector<ir_tree_node *> &ir_tree,
-                     std::vector<ir_tree_node *> &ir_stmt) {
-
-  ir_stmt = extract_ir_stmts(ir_tree);
-  stmt_nesting_level_.resize(ir_stmt.size());
-  std::vector<int> stmt_nesting_level(ir_stmt.size());
-  for (int i = 0; i < ir_stmt.size(); i++) {
-    ir_stmt[i]->payload = i;
-    int t = 0;
-    ir_tree_node *itn = ir_stmt[i];
-    while (itn->parent != NULL) {
-      itn = itn->parent;
-      if (itn->content->type() == IR_CONTROL_LOOP)
-        t++;
-    }
-    stmt_nesting_level_[i] = t;
-    stmt_nesting_level[i] = t;
-  }
-  
-  stmt = std::vector<Statement>(ir_stmt.size());
-  int n_dim = -1;
-  int max_loc;
-  //std::vector<std::string> index;
-  for (int i = 0; i < ir_stmt.size(); i++) {
-    int max_nesting_level = -1;
-    int loc;
-    for (int j = 0; j < ir_stmt.size(); j++)
-      if (stmt_nesting_level[j] > max_nesting_level) {
-        max_nesting_level = stmt_nesting_level[j];
-        loc = j;
-      }
-    
-    // most deeply nested statement acting as a reference point
-    if (n_dim == -1) {
-      n_dim = max_nesting_level;
-      max_loc = loc;
-      
-      index = std::vector<std::string>(n_dim);
-      
-      ir_tree_node *itn = ir_stmt[loc];
-      int cur_dim = n_dim - 1;
-      while (itn->parent != NULL) {
-        itn = itn->parent;
-        if (itn->content->type() == IR_CONTROL_LOOP) {
-          index[cur_dim] =
-            static_cast<IR_Loop *>(itn->content)->index()->name();
-          itn->payload = cur_dim--;
-        }
-      }
-    }
-    
-    // align loops by names, temporary solution
-    ir_tree_node *itn = ir_stmt[loc];
-    int depth = stmt_nesting_level_[loc] - 1;
-    /*   while (itn->parent != NULL) {
-         itn = itn->parent;
-         if (itn->content->type() == IR_CONTROL_LOOP && itn->payload == -1) {
-         std::string name = static_cast<IR_Loop *>(itn->content)->index()->name();
-         for (int j = 0; j < n_dim; j++)
-         if (index[j] == name) {
-         itn->payload = j;
-         break;
-         }
-         if (itn->payload == -1)
-         throw loop_error("no complex alignment yet");
-         }
-         }
-    */
-    for (int t = depth; t >= 0; t--) {
-      int y = t;
-      ir_tree_node *itn = ir_stmt[loc];
-      
-      while ((itn->parent != NULL) && (y >= 0)) {
-        itn = itn->parent;
-        if (itn->content->type() == IR_CONTROL_LOOP)
-          y--;
-      }
-      
-      if (itn->content->type() == IR_CONTROL_LOOP && itn->payload == -1) {
-        CG_outputBuilder *ocg = ir->builder();
-        
-        itn->payload = depth - t;
-        
-        CG_outputRepr *code =
-          static_cast<IR_Block *>(ir_stmt[loc]->content)->extract();
-        
-        std::vector<CG_outputRepr *> index_expr;
-        std::vector<std::string> old_index;
-        CG_outputRepr *repl = ocg->CreateIdent(index[itn->payload]);
-        index_expr.push_back(repl);
-        old_index.push_back(
-          static_cast<IR_Loop *>(itn->content)->index()->name());
-        code = ocg->CreateSubstitutedStmt(0, code, old_index,
-                                          index_expr);
-        
-        replace.insert(std::pair<int, CG_outputRepr*>(loc, code));
-        //stmt[loc].code = code;
-        
-      }
-    }
-    
-    // set relation variable names
-    Relation r(n_dim);
-    F_And *f_root = r.add_and();
-    itn = ir_stmt[loc];
-    int temp_depth = depth;
-    while (itn->parent != NULL) {
-      
-      itn = itn->parent;
-      if (itn->content->type() == IR_CONTROL_LOOP) {
-        r.name_set_var(itn->payload + 1, index[temp_depth]);
-        
-        temp_depth--;
-      }
-      //static_cast<IR_Loop *>(itn->content)->index()->name());
-    }
-    
-    /*while (itn->parent != NULL) {
-      itn = itn->parent;
-      if (itn->content->type() == IR_CONTROL_LOOP)
-      r.name_set_var(itn->payload+1, static_cast<IR_Loop *>(itn->content)->index()->name());
-      }*/
-    
-    // extract information from loop/if structures
-    std::vector<bool> processed(n_dim, false);
-    std::vector<std::string> vars_to_be_reversed;
-    itn = ir_stmt[loc];
-    while (itn->parent != NULL) {
-      itn = itn->parent;
-      
-      switch (itn->content->type()) {
-      case IR_CONTROL_LOOP: {
-        IR_Loop *lp = static_cast<IR_Loop *>(itn->content);
-        Variable_ID v = r.set_var(itn->payload + 1);
-        int c;
-        
-        try {
-          c = lp->step_size();
-          if (c > 0) {
-            CG_outputRepr *lb = lp->lower_bound();
-            exp2formula(ir, r, f_root, freevar, lb, v, 's',
-                        IR_COND_GE, true);
-            CG_outputRepr *ub = lp->upper_bound();
-            IR_CONDITION_TYPE cond = lp->stop_cond();
-            if (cond == IR_COND_LT || cond == IR_COND_LE)
-              exp2formula(ir, r, f_root, freevar, ub, v, 's',
-                          cond, true);
-            else
-              throw ir_error("loop condition not supported");
-            
-          } else if (c < 0) {
-            CG_outputBuilder *ocg = ir->builder();
-            CG_outputRepr *lb = lp->lower_bound();
-            lb = ocg->CreateMinus(NULL, lb);
-            exp2formula(ir, r, f_root, freevar, lb, v, 's',
-                        IR_COND_GE, true);
-            CG_outputRepr *ub = lp->upper_bound();
-            ub = ocg->CreateMinus(NULL, ub);
-            IR_CONDITION_TYPE cond = lp->stop_cond();
-            if (cond == IR_COND_GE)
-              exp2formula(ir, r, f_root, freevar, ub, v, 's',
-                          IR_COND_LE, true);
-            else if (cond == IR_COND_GT)
-              exp2formula(ir, r, f_root, freevar, ub, v, 's',
-                          IR_COND_LT, true);
-            else
-              throw ir_error("loop condition not supported");
-            
-            vars_to_be_reversed.push_back(lp->index()->name());
-          } else
-            throw ir_error("loop step size zero");
-        } catch (const ir_error &e) {
-          for (int i = 0; i < itn->children.size(); i++)
-            delete itn->children[i];
-          itn->children = std::vector<ir_tree_node *>();
-          itn->content = itn->content->convert();
-          return false;
-        }
-        
-        if (abs(c) != 1) {
-          F_Exists *f_exists = f_root->add_exists();
-          Variable_ID e = f_exists->declare();
-          F_And *f_and = f_exists->add_and();
-          Stride_Handle h = f_and->add_stride(abs(c));
-          if (c > 0)
-            h.update_coef(e, 1);
-          else
-            h.update_coef(e, -1);
-          h.update_coef(v, -1);
-          CG_outputRepr *lb = lp->lower_bound();
-          exp2formula(ir, r, f_and, freevar, lb, e, 's', IR_COND_EQ,
-                      true);
-        }
-        
-        processed[itn->payload] = true;
-        break;
-      }
-      case IR_CONTROL_IF: {
-        CG_outputRepr *cond =
-          static_cast<IR_If *>(itn->content)->condition();
-        try {
-          if (itn->payload % 2 == 1)
-            exp2constraint(ir, r, f_root, freevar, cond, true);
-          else {
-            F_Not *f_not = f_root->add_not();
-            F_And *f_and = f_not->add_and();
-            exp2constraint(ir, r, f_and, freevar, cond, true);
-          }
-        } catch (const ir_error &e) {
-          std::vector<ir_tree_node *> *t;
-          if (itn->parent == NULL)
-            t = &ir_tree;
-          else
-            t = &(itn->parent->children);
-          int id = itn->payload;
-          int i = t->size() - 1;
-          while (i >= 0) {
-            if ((*t)[i] == itn) {
-              for (int j = 0; j < itn->children.size(); j++)
-                delete itn->children[j];
-              itn->children = std::vector<ir_tree_node *>();
-              itn->content = itn->content->convert();
-            } else if ((*t)[i]->payload >> 1 == id >> 1) {
-              delete (*t)[i];
-              t->erase(t->begin() + i);
-            }
-            i--;
-          }
-          return false;
-        }
-        
-        break;
-      }
-      default:
-        for (int i = 0; i < itn->children.size(); i++)
-          delete itn->children[i];
-        itn->children = std::vector<ir_tree_node *>();
-        itn->content = itn->content->convert();
-        return false;
-      }
-    }
-    
-    // add information for missing loops
-    for (int j = 0; j < n_dim; j++)
-      if (!processed[j]) {
-        ir_tree_node *itn = ir_stmt[max_loc];
-        while (itn->parent != NULL) {
-          itn = itn->parent;
-          if (itn->content->type() == IR_CONTROL_LOOP
-              && itn->payload == j)
-            break;
-        }
-        
-        Variable_ID v = r.set_var(j + 1);
-        if (loc < max_loc) {
-          
-          CG_outputBuilder *ocg = ir->builder();
-          
-          CG_outputRepr *lb =
-            static_cast<IR_Loop *>(itn->content)->lower_bound();
-          
-          exp2formula(ir, r, f_root, freevar, lb, v, 's', IR_COND_EQ,
-                      false);
-          
-          /*    if (ir->QueryExpOperation(
-                static_cast<IR_Loop *>(itn->content)->lower_bound())
-                == IR_OP_VARIABLE) {
-                IR_ScalarRef *ref =
-                static_cast<IR_ScalarRef *>(ir->Repr2Ref(
-                static_cast<IR_Loop *>(itn->content)->lower_bound()));
-                std::string name_ = ref->name();
-                
-                for (int i = 0; i < index.size(); i++)
-                if (index[i] == name_) {
-                exp2formula(ir, r, f_root, freevar, lb, v, 's',
-                IR_COND_GE, false);
-                
-                CG_outputRepr *ub =
-                static_cast<IR_Loop *>(itn->content)->upper_bound();
-                IR_CONDITION_TYPE cond =
-                static_cast<IR_Loop *>(itn->content)->stop_cond();
-                if (cond == IR_COND_LT || cond == IR_COND_LE)
-                exp2formula(ir, r, f_root, freevar, ub, v,
-                's', cond, false);
-                
-                
-                
-                }
-                
-                }
-          */
-          
-        } else { // loc > max_loc
-          
-          CG_outputBuilder *ocg = ir->builder();
-          CG_outputRepr *ub =
-            static_cast<IR_Loop *>(itn->content)->upper_bound();
-          
-          exp2formula(ir, r, f_root, freevar, ub, v, 's', IR_COND_EQ,
-                      false);
-          /*if (ir->QueryExpOperation(
-            static_cast<IR_Loop *>(itn->content)->upper_bound())
-            == IR_OP_VARIABLE) {
-            IR_ScalarRef *ref =
-            static_cast<IR_ScalarRef *>(ir->Repr2Ref(
-            static_cast<IR_Loop *>(itn->content)->upper_bound()));
-            std::string name_ = ref->name();
-            
-            for (int i = 0; i < index.size(); i++)
-            if (index[i] == name_) {
-            
-            CG_outputRepr *lb =
-            static_cast<IR_Loop *>(itn->content)->lower_bound();
-            
-            exp2formula(ir, r, f_root, freevar, lb, v, 's',
-            IR_COND_GE, false);
-            
-            CG_outputRepr *ub =
-            static_cast<IR_Loop *>(itn->content)->upper_bound();
-            IR_CONDITION_TYPE cond =
-            static_cast<IR_Loop *>(itn->content)->stop_cond();
-            if (cond == IR_COND_LT || cond == IR_COND_LE)
-            exp2formula(ir, r, f_root, freevar, ub, v,
-            's', cond, false);
-            
-            
-            }
-            }
-          */
-        }
-      }
-    
-    r.setup_names();
-    r.simplify();
-    
-    // insert the statement
-    CG_outputBuilder *ocg = ir->builder();
-    std::vector<CG_outputRepr *> reverse_expr;
-    for (int j = 1; j <= vars_to_be_reversed.size(); j++) {
-      CG_outputRepr *repl = ocg->CreateIdent(vars_to_be_reversed[j]);
-      repl = ocg->CreateMinus(NULL, repl);
-      reverse_expr.push_back(repl);
-    }
-    CG_outputRepr *code =
-      static_cast<IR_Block *>(ir_stmt[loc]->content)->extract();
-    code = ocg->CreateSubstitutedStmt(0, code, vars_to_be_reversed,
-                                      reverse_expr);
-    stmt[loc].code = code;
-    stmt[loc].IS = r;
-    stmt[loc].loop_level = std::vector<LoopLevel>(n_dim);
-    stmt[loc].ir_stmt_node = ir_stmt[loc];
-    for (int i = 0; i < n_dim; i++) {
-      stmt[loc].loop_level[i].type = LoopLevelOriginal;
-      stmt[loc].loop_level[i].payload = i;
-      stmt[loc].loop_level[i].parallel_level = 0;
-    }
-    
-    stmt_nesting_level[loc] = -1;
-  }
-  
-  return true;
-}
-
-Loop::Loop(const IR_Control *control) {
-
-  last_compute_cgr_ = NULL;
-  last_compute_cg_ = NULL;
-  
-  ir = const_cast<IR_Code *>(control->ir_);
-  init_code = NULL;
-  cleanup_code = NULL;
-  tmp_loop_var_name_counter = 1;
-  overflow_var_name_counter = 1;
-  known = Relation::True(0);
-  
-  ir_tree = build_ir_tree(control->clone(), NULL);
-  //    std::vector<ir_tree_node *> ir_stmt;
-  
-  while (!init_loop(ir_tree, ir_stmt)) {
-  }
-
-  
-  
-  for (int i = 0; i < stmt.size(); i++) {
-    std::map<int, CG_outputRepr*>::iterator it = replace.find(i);
-    
-    if (it != replace.end())
-      stmt[i].code = it->second;
-    else
-      stmt[i].code = stmt[i].code;
-  }
-  
-  if (stmt.size() != 0)
-    dep = DependenceGraph(stmt[0].IS.n_set());
-  else
-    dep = DependenceGraph(0);
-  // init the dependence graph
-  for (int i = 0; i < stmt.size(); i++)
-    dep.insert();
-  
-  for (int i = 0; i < stmt.size(); i++)
-    for (int j = i; j < stmt.size(); j++) {
-      std::pair<std::vector<DependenceVector>,
-        std::vector<DependenceVector> > dv = test_data_dependences(
-          ir, stmt[i].code, stmt[i].IS, stmt[j].code, stmt[j].IS,
-          freevar, index, stmt_nesting_level_[i],
-          stmt_nesting_level_[j]);
-      
-      for (int k = 0; k < dv.first.size(); k++) {
-        if (is_dependence_valid(ir_stmt[i], ir_stmt[j], dv.first[k],
-                                true))
-          dep.connect(i, j, dv.first[k]);
-        else {
-          dep.connect(j, i, dv.first[k].reverse());
-        }
-        
-      }
-      for (int k = 0; k < dv.second.size(); k++)
-        if (is_dependence_valid(ir_stmt[j], ir_stmt[i], dv.second[k],
-                                false))
-          dep.connect(j, i, dv.second[k]);
-        else {
-          dep.connect(i, j, dv.second[k].reverse());
-        }
-      // std::pair<std::vector<DependenceVector>,
-      //                std::vector<DependenceVector> > dv_ = test_data_dependences(
-      
-    }
-  
-
-
-  // init dumb transformation relations e.g. [i, j] -> [ 0, i, 0, j, 0]
-  for (int i = 0; i < stmt.size(); i++) {
-    int n = stmt[i].IS.n_set();
-    stmt[i].xform = Relation(n, 2 * n + 1);
-    F_And *f_root = stmt[i].xform.add_and();
-    
-    for (int j = 1; j <= n; j++) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(stmt[i].xform.output_var(2 * j), 1);
-      h.update_coef(stmt[i].xform.input_var(j), -1);
-    }
-    
-    for (int j = 1; j <= 2 * n + 1; j += 2) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(stmt[i].xform.output_var(j), 1);
-    }
-    stmt[i].xform.simplify();
-  }
-  
-  if (stmt.size() != 0)
-    num_dep_dim = stmt[0].IS.n_set();
-  else
-    num_dep_dim = 0;
-  // debug
-  /*for (int i = 0; i < stmt.size(); i++) {
-    std::cout << i << ": ";
-    //stmt[i].xform.print();
-    stmt[i].IS.print();
-    std::cout << std::endl;
-    
-    }*/
-  //end debug
-}
-
-Loop::~Loop() {
-  
-  delete last_compute_cgr_;
-  delete last_compute_cg_;
-  
-  for (int i = 0; i < stmt.size(); i++)
-    if (stmt[i].code != NULL) {
-      stmt[i].code->clear();
-      delete stmt[i].code;
-    }
-  
-  for (int i = 0; i < ir_tree.size(); i++)
-    delete ir_tree[i];
-  
-  if (init_code != NULL) {
-    init_code->clear();
-    delete init_code;
-  }
-  if (cleanup_code != NULL) {
-    cleanup_code->clear();
-    delete cleanup_code;
-  }
-}
-
-int Loop::get_dep_dim_of(int stmt_num, int level) const {
-  if (stmt_num < 0 || stmt_num >= stmt.size())
-    throw std::invalid_argument("invaid statement " + to_string(stmt_num));
-  
-  if (level < 1 || level > stmt[stmt_num].loop_level.size())
-    return -1;
-  
-  int trip_count = 0;
-  while (true) {
-    switch (stmt[stmt_num].loop_level[level - 1].type) {
-    case LoopLevelOriginal:
-      return stmt[stmt_num].loop_level[level - 1].payload;
-    case LoopLevelTile:
-      level = stmt[stmt_num].loop_level[level - 1].payload;
-      if (level < 1)
-        return -1;
-      if (level > stmt[stmt_num].loop_level.size())
-        throw loop_error(
-          "incorrect loop level information for statement "
-          + to_string(stmt_num));
-      break;
-    default:
-      throw loop_error(
-        "unknown loop level information for statement "
-        + to_string(stmt_num));
-    }
-    trip_count++;
-    if (trip_count >= stmt[stmt_num].loop_level.size())
-      throw loop_error(
-        "incorrect loop level information for statement "
-        + to_string(stmt_num));
-  }
-}
-
-int Loop::get_last_dep_dim_before(int stmt_num, int level) const {
-  if (stmt_num < 0 || stmt_num >= stmt.size())
-    throw std::invalid_argument("invaid statement " + to_string(stmt_num));
-  
-  if (level < 1)
-    return -1;
-  if (level > stmt[stmt_num].loop_level.size())
-    level = stmt[stmt_num].loop_level.size() + 1;
-  
-  for (int i = level - 1; i >= 1; i--)
-    if (stmt[stmt_num].loop_level[i - 1].type == LoopLevelOriginal)
-      return stmt[stmt_num].loop_level[i - 1].payload;
-  
-  return -1;
-}
-
-void Loop::print_internal_loop_structure() const {
-  for (int i = 0; i < stmt.size(); i++) {
-    std::vector<int> lex = getLexicalOrder(i);
-    std::cout << "s" << i + 1 << ": ";
-    for (int j = 0; j < stmt[i].loop_level.size(); j++) {
-      if (2 * j < lex.size())
-        std::cout << lex[2 * j];
-      switch (stmt[i].loop_level[j].type) {
-      case LoopLevelOriginal:
-        std::cout << "(dim:" << stmt[i].loop_level[j].payload << ")";
-        break;
-      case LoopLevelTile:
-        std::cout << "(tile:" << stmt[i].loop_level[j].payload << ")";
-        break;
-      default:
-        std::cout << "(unknown)";
-      }
-      std::cout << ' ';
-    }
-    for (int j = 2 * stmt[i].loop_level.size(); j < lex.size(); j += 2) {
-      std::cout << lex[j];
-      if (j != lex.size() - 1)
-        std::cout << ' ';
-    }
-    std::cout << std::endl;
-  }
-}
-
-CG_outputRepr *Loop::getCode(int effort) const {
-  const int m = stmt.size();
-  if (m == 0)
-    return NULL;
-  const int n = stmt[0].xform.n_out();
-  
-  if (last_compute_cg_ == NULL) {
-    std::vector<Relation> IS(m);
-    std::vector<Relation> xforms(m);
-    for (int i = 0; i < m; i++) {
-      IS[i] = stmt[i].IS;
-      xforms[i] = stmt[i].xform;
-    }
-    Relation known = Extend_Set(copy(this->known), n - this->known.n_set());
-    
-    last_compute_cg_ = new CodeGen(xforms, IS, known);
-    delete last_compute_cgr_;
-    last_compute_cgr_ = NULL;
-  }
-  
-  if (last_compute_cgr_ == NULL || last_compute_effort_ != effort) {
-    delete last_compute_cgr_;
-    last_compute_cgr_ = last_compute_cg_->buildAST(effort);
-    last_compute_effort_ = effort;
-  }
-  
-  std::vector<CG_outputRepr *> stmts(m);
-  for (int i = 0; i < m; i++)
-    stmts[i] = stmt[i].code;
-  CG_outputBuilder *ocg = ir->builder();
-  CG_outputRepr *repr = last_compute_cgr_->printRepr(ocg, stmts);
-  
-  if (init_code != NULL)
-    repr = ocg->StmtListAppend(init_code->clone(), repr);
-  if (cleanup_code != NULL)
-    repr = ocg->StmtListAppend(repr, cleanup_code->clone());
-  
-  return repr;
-}
-
-void Loop::printCode(int effort) const {
-  const int m = stmt.size();
-  if (m == 0)
-    return;
-  const int n = stmt[0].xform.n_out();
-  
-  if (last_compute_cg_ == NULL) {
-    std::vector<Relation> IS(m);
-    std::vector<Relation> xforms(m);
-    for (int i = 0; i < m; i++) {
-      IS[i] = stmt[i].IS;
-      xforms[i] = stmt[i].xform;
-    }
-    Relation known = Extend_Set(copy(this->known), n - this->known.n_set());
-    
-    last_compute_cg_ = new CodeGen(xforms, IS, known);
-    delete last_compute_cgr_;
-    last_compute_cgr_ = NULL;
-  }
-  
-  if (last_compute_cgr_ == NULL || last_compute_effort_ != effort) {
-    delete last_compute_cgr_;
-    last_compute_cgr_ = last_compute_cg_->buildAST(effort);
-    last_compute_effort_ = effort;
-  }
-  
-  std::string repr = last_compute_cgr_->printString();
-  std::cout << repr << std::endl;
-}
-
-void Loop::printIterationSpace() const {
-  for (int i = 0; i < stmt.size(); i++) {
-    std::cout << "s" << i << ": ";
-    Relation r = getNewIS(i);
-    for (int j = 1; j <= r.n_inp(); j++)
-      r.name_input_var(j, CodeGen::loop_var_name_prefix + to_string(j));
-    r.setup_names();
-    r.print();
-  }
-}
-
-void Loop::printDependenceGraph() const {
-  if (dep.edgeCount() == 0)
-    std::cout << "no dependence exists" << std::endl;
-  else {
-    std::cout << "dependence graph:" << std::endl;
-    std::cout << dep;
-  }
-}
-
-Relation Loop::getNewIS(int stmt_num) const {
-  Relation result;
-  
-  if (stmt[stmt_num].xform.is_null()) {
-    Relation known = Extend_Set(copy(this->known),
-                                stmt[stmt_num].IS.n_set() - this->known.n_set());
-    result = Intersection(copy(stmt[stmt_num].IS), known);
-  } else {
-    Relation known = Extend_Set(copy(this->known),
-                                stmt[stmt_num].xform.n_out() - this->known.n_set());
-    result = Intersection(
-      Range(
-        Restrict_Domain(copy(stmt[stmt_num].xform),
-                        copy(stmt[stmt_num].IS))), known);
-  }
-  
-  result.simplify(2, 4);
-  
-  return result;
-}
-
-std::vector<Relation> Loop::getNewIS() const {
-  const int m = stmt.size();
-  
-  std::vector<Relation> new_IS(m);
-  for (int i = 0; i < m; i++)
-    new_IS[i] = getNewIS(i);
-  
-  return new_IS;
-}
-
-void Loop::pragma(int stmt_num, int level, const std::string &pragmaText) {
-	// check sanity of parameters
-	if(stmt_num < 0)
-		throw std::invalid_argument("invalid statement " + to_string(stmt_num));
-	
-	CG_outputBuilder *ocg = ir->builder();
-	CG_outputRepr *code = stmt[stmt_num].code;
-	ocg->CreatePragmaAttribute(code, level, pragmaText);
-}
-
-void Loop::prefetch(int stmt_num, int level, const std::string &arrName, int hint) {
-	// check sanity of parameters
-	if(stmt_num < 0)
-		throw std::invalid_argument("invalid statement " + to_string(stmt_num));
-
-	CG_outputBuilder *ocg = ir->builder();
-	CG_outputRepr *code = stmt[stmt_num].code;
-	ocg->CreatePrefetchAttribute(code, level, arrName, hint);
-}
-
-std::vector<int> Loop::getLexicalOrder(int stmt_num) const {
-  assert(stmt_num < stmt.size());
-  
-  const int n = stmt[stmt_num].xform.n_out();
-  std::vector<int> lex(n, 0);
-  
-  for (int i = 0; i < n; i += 2)
-    lex[i] = get_const(stmt[stmt_num].xform, i, Output_Var);
-  
-  return lex;
-}
-
-// find the sub loop nest specified by stmt_num and level,
-// only iteration space satisfiable statements returned.
-std::set<int> Loop::getSubLoopNest(int stmt_num, int level) const {
-  assert(stmt_num >= 0 && stmt_num < stmt.size());
-  assert(level > 0 && level <= stmt[stmt_num].loop_level.size());
-  
-  std::set<int> working;
-  for (int i = 0; i < stmt.size(); i++)
-    if (const_cast<Loop *>(this)->stmt[i].IS.is_upper_bound_satisfiable()
-        && stmt[i].loop_level.size() >= level)
-      working.insert(i);
-  
-  for (int i = 1; i <= level; i++) {
-    int a = getLexicalOrder(stmt_num, i);
-    for (std::set<int>::iterator j = working.begin(); j != working.end();) {
-      int b = getLexicalOrder(*j, i);
-      if (b != a)
-        working.erase(j++);
-      else
-        ++j;
-    }
-  }
-  
-  return working;
-}
-
-int Loop::getLexicalOrder(int stmt_num, int level) const {
-  assert(stmt_num >= 0 && stmt_num < stmt.size());
-  assert(level > 0 && level <= stmt[stmt_num].loop_level.size()+1);
-  
-  Relation &r = const_cast<Loop *>(this)->stmt[stmt_num].xform;
-  for (EQ_Iterator e(r.single_conjunct()->EQs()); e; e++)
-    if (abs((*e).get_coef(r.output_var(2 * level - 1))) == 1) {
-      bool is_const = true;
-      for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
-        if (cvi.curr_var() != r.output_var(2 * level - 1)) {
-          is_const = false;
-          break;
-        }
-      if (is_const) {
-        int t = static_cast<int>((*e).get_const());
-        return (*e).get_coef(r.output_var(2 * level - 1)) > 0 ? -t : t;
-      }
-    }
-  
-  throw loop_error(
-    "can't find lexical order for statement " + to_string(stmt_num)
-    + "'s loop level " + to_string(level));
-}
-
-std::set<int> Loop::getStatements(const std::vector<int> &lex, int dim) const {
-  const int m = stmt.size();
-  
-  std::set<int> same_loops;
-  for (int i = 0; i < m; i++) {
-    if (dim < 0)
-      same_loops.insert(i);
-    else {
-      std::vector<int> a_lex = getLexicalOrder(i);
-      int j;
-      for (j = 0; j <= dim; j += 2)
-        if (lex[j] != a_lex[j])
-          break;
-      if (j > dim)
-        same_loops.insert(i);
-    }
-    
-  }
-  
-  return same_loops;
-}
-
-void Loop::shiftLexicalOrder(const std::vector<int> &lex, int dim, int amount) {
-  const int m = stmt.size();
-  
-  if (amount == 0)
-    return;
-  
-  for (int i = 0; i < m; i++) {
-    std::vector<int> lex2 = getLexicalOrder(i);
-    
-    bool need_shift = true;
-    
-    for (int j = 0; j < dim; j++)
-      if (lex2[j] != lex[j]) {
-        need_shift = false;
-        break;
-      }
-    
-    if (!need_shift)
-      continue;
-    
-    if (amount > 0) {
-      if (lex2[dim] < lex[dim])
-        continue;
-    } else if (amount < 0) {
-      if (lex2[dim] > lex[dim])
-        continue;
-    }
-    
-    assign_const(stmt[i].xform, dim, lex2[dim] + amount);
-  }
-}
-
-std::vector<std::set<int> > Loop::sort_by_same_loops(std::set<int> active,
-                                                     int level) {
-  
-  std::set<int> not_nested_at_this_level;
-  std::map<ir_tree_node*, std::set<int> > sorted_by_loop;
-  std::map<int, std::set<int> > sorted_by_lex_order;
-  std::vector<std::set<int> > to_return;
-  bool lex_order_already_set = false;
-  for (std::set<int>::iterator it = active.begin(); it != active.end();
-       it++) {
-    
-    if (stmt[*it].ir_stmt_node == NULL)
-      lex_order_already_set = true;
-  }
-  
-  if (lex_order_already_set) {
-    
-    for (std::set<int>::iterator it = active.begin(); it != active.end();
-         it++) {
-      std::map<int, std::set<int> >::iterator it2 =
-        sorted_by_lex_order.find(
-          get_const(stmt[*it].xform, 2 * (level - 1),
-                    Output_Var));
-      
-      if (it2 != sorted_by_lex_order.end())
-        it2->second.insert(*it);
-      else {
-        
-        std::set<int> to_insert;
-        
-        to_insert.insert(*it);
-        
-        sorted_by_lex_order.insert(
-          std::pair<int, std::set<int> >(
-            get_const(stmt[*it].xform, 2 * (level - 1),
-                      Output_Var), to_insert));
-        
-      }
-      
-    }
-    
-    for (std::map<int, std::set<int> >::iterator it2 =
-           sorted_by_lex_order.begin(); it2 != sorted_by_lex_order.end();
-         it2++)
-      to_return.push_back(it2->second);
-    
-  } else {
-    
-    for (std::set<int>::iterator it = active.begin(); it != active.end();
-         it++) {
-      
-      ir_tree_node* itn = stmt[*it].ir_stmt_node;
-      itn = itn->parent;
-      while ((itn != NULL) && (itn->payload != level - 1))
-        itn = itn->parent;
-      
-      if (itn == NULL)
-        not_nested_at_this_level.insert(*it);
-      else {
-        std::map<ir_tree_node*, std::set<int> >::iterator it2 =
-          sorted_by_loop.find(itn);
-        
-        if (it2 != sorted_by_loop.end())
-          it2->second.insert(*it);
-        else {
-          std::set<int> to_insert;
-          
-          to_insert.insert(*it);
-          
-          sorted_by_loop.insert(
-            std::pair<ir_tree_node*, std::set<int> >(itn,
-                                                     to_insert));
-          
-        }
-        
-      }
-      
-    }
-    if (not_nested_at_this_level.size() > 0) {
-      for (std::set<int>::iterator it = not_nested_at_this_level.begin();
-           it != not_nested_at_this_level.end(); it++) {
-        std::set<int> temp;
-        temp.insert(*it);
-        to_return.push_back(temp);
-        
-      }
-    }
-    for (std::map<ir_tree_node*, std::set<int> >::iterator it2 =
-           sorted_by_loop.begin(); it2 != sorted_by_loop.end(); it2++)
-      to_return.push_back(it2->second);
-  }
-  return to_return;
-}
-
-void update_successors(int n, int node_num[], int cant_fuse_with[],
-                       Graph<std::set<int>, bool> &g, std::list<int> &work_list) {
-  
-  std::set<int> disconnect;
-  for (Graph<std::set<int>, bool>::EdgeList::iterator i =
-         g.vertex[n].second.begin(); i != g.vertex[n].second.end(); i++) {
-    int m = i->first;
-    
-    if (node_num[m] != -1)
-      throw loop_error("Graph input for fusion has cycles not a DAG!!");
-    
-    std::vector<bool> check_ = g.getEdge(n, m);
-    
-    bool has_bad_edge_path = false;
-    for (int i = 0; i < check_.size(); i++)
-      if (!check_[i]) {
-        has_bad_edge_path = true;
-        break;
-      }
-    if (has_bad_edge_path)
-      cant_fuse_with[m] = std::max(cant_fuse_with[m], node_num[n]);
-    else
-      cant_fuse_with[m] = std::max(cant_fuse_with[m], cant_fuse_with[n]);
-    disconnect.insert(m);
-  }
-  
-  
-  for (std::set<int>::iterator i = disconnect.begin(); i != disconnect.end();
-       i++) {
-    g.disconnect(n, *i);
-    
-    bool no_incoming_edges = true;
-    for (int j = 0; j < g.vertex.size(); j++)
-      if (j != *i)
-        if (g.hasEdge(j, *i)) {
-          no_incoming_edges = false;
-          break;
-        }
-    
-    
-    if (no_incoming_edges)
-      work_list.push_back(*i);
-  }
-  
-}
-
-Graph<std::set<int>, bool> Loop::construct_induced_graph_at_level(
-  std::vector<std::set<int> > s, DependenceGraph dep, int dep_dim) {
-  Graph<std::set<int>, bool> g;
-  
-  for (int i = 0; i < s.size(); i++)
-    g.insert(s[i]);
-  
-  for (int i = 0; i < s.size(); i++) {
-    
-    for (int j = i + 1; j < s.size(); j++) {
-      bool has_true_edge_i_to_j = false;
-      bool has_true_edge_j_to_i = false;
-      bool is_connected_i_to_j = false;
-      bool is_connected_j_to_i = false;
-      for (std::set<int>::iterator ii = s[i].begin(); ii != s[i].end();
-           ii++) {
-        
-        for (std::set<int>::iterator jj = s[j].begin();
-             jj != s[j].end(); jj++) {
-          
-          std::vector<DependenceVector> dvs = dep.getEdge(*ii, *jj);
-          for (int k = 0; k < dvs.size(); k++)
-            if (dvs[k].is_control_dependence()
-                || (dvs[k].is_data_dependence()
-                    && dvs[k].has_been_carried_at(dep_dim))) {
-              
-              if (dvs[k].is_data_dependence()
-                  && dvs[k].has_negative_been_carried_at(
-                    dep_dim)) {
-                //g.connect(i, j, false);
-                is_connected_i_to_j = true;
-                break;
-              } else {
-                //g.connect(i, j, true);
-                
-                has_true_edge_i_to_j = true;
-                //break
-              }
-            }
-          
-          //if (is_connected)
-          
-          //    break;
-          //        if (has_true_edge_i_to_j && !is_connected_i_to_j)
-          //                g.connect(i, j, true);
-          dvs = dep.getEdge(*jj, *ii);
-          for (int k = 0; k < dvs.size(); k++)
-            if (dvs[k].is_control_dependence()
-                || (dvs[k].is_data_dependence()
-                    && dvs[k].has_been_carried_at(dep_dim))) {
-              
-              if (is_connected_i_to_j || has_true_edge_i_to_j)
-                throw loop_error(
-                  "Graph input for fusion has cycles not a DAG!!");
-              
-              if (dvs[k].is_data_dependence()
-                  && dvs[k].has_negative_been_carried_at(
-                    dep_dim)) {
-                //g.connect(i, j, false);
-                is_connected_j_to_i = true;
-                break;
-              } else {
-                //g.connect(i, j, true);
-                
-                has_true_edge_j_to_i = true;
-                //break;
-              }
-            }
-          
-          //    if (is_connected)
-          //break;
-          //    if (is_connected)
-          //break;
-        }
-        
-        
-        //if (is_connected)
-        //  break;
-      }
-      
-      
-      if (is_connected_i_to_j)
-        g.connect(i, j, false);
-      else if (has_true_edge_i_to_j)
-        g.connect(i, j, true);
-      
-      if (is_connected_j_to_i)
-        g.connect(j, i, false);
-      else if (has_true_edge_j_to_i)
-        g.connect(j, i, true);
-      
-      
-    }
-  }
-  return g;
-}
-
-std::vector<std::set<int> > Loop::typed_fusion(Graph<std::set<int>, bool> g) {
-  
-  bool roots[g.vertex.size()];
-  
-  for (int i = 0; i < g.vertex.size(); i++)
-    roots[i] = true;
-  
-  for (int i = 0; i < g.vertex.size(); i++)
-    for (int j = i + 1; j < g.vertex.size(); j++) {
-      
-      if (g.hasEdge(i, j))
-        roots[j] = false;
-      
-      if (g.hasEdge(j, i))
-        roots[i] = false;
-      
-    }
-  
-  std::list<int> work_list;
-  int cant_fuse_with[g.vertex.size()];
-  std::vector<std::set<int> > s;
-  //Each Fused set's representative node
-  
-  int node_to_fused_nodes[g.vertex.size()];
-  int node_num[g.vertex.size()];
-  for (int i = 0; i < g.vertex.size(); i++) {
-    if (roots[i] == true)
-      work_list.push_back(i);
-    cant_fuse_with[i] = 0;
-    node_to_fused_nodes[i] = 0;
-    node_num[i] = -1;
-  }
-  // topological sort according to chun's permute algorithm
-  //   std::vector<std::set<int> > s = g.topoSort();
-  std::vector<std::set<int> > s2 = g.topoSort();
-  if (work_list.empty() || (s2.size() != g.vertex.size())) {
-    
-    std::cout << s2.size() << "\t" << g.vertex.size() << std::endl;
-    throw loop_error("Input for fusion not a DAG!!");
-    
-    
-  }
-  int fused_nodes_counter = 0;
-  while (!work_list.empty()) {
-    int n = work_list.front();
-    //int n_ = g.vertex[n].first;
-    work_list.pop_front();
-    int node;
-    if (cant_fuse_with[n] == 0)
-      node = 0;
-    else
-      node = cant_fuse_with[n];
-    
-    if ((fused_nodes_counter != 0) && (node != fused_nodes_counter)) {
-      int rep_node = node_to_fused_nodes[node];
-      node_num[n] = node_num[rep_node];
-      
-      try {
-        update_successors(n, node_num, cant_fuse_with, g, work_list);
-      } catch (const loop_error &e) {
-        
-        throw loop_error(
-          "statements cannot be fused together due to negative dependence");
-        
-        
-      }
-      for (std::set<int>::iterator it = g.vertex[n].first.begin();
-           it != g.vertex[n].first.end(); it++)
-        s[node].insert(*it);
-    } else {
-      //std::set<int> new_node;
-      //new_node.insert(n_);
-      s.push_back(g.vertex[n].first);
-      node_to_fused_nodes[node] = n;
-      node_num[n] = ++node;
-      try {
-        update_successors(n, node_num, cant_fuse_with, g, work_list);
-      } catch (const loop_error &e) {
-        
-        throw loop_error(
-          "statements cannot be fused together due to negative dependence");
-        
-        
-      }
-      fused_nodes_counter++;
-    }
-  }
-  
-  return s;
-}
-
-void Loop::setLexicalOrder(int dim, const std::set<int> &active,
-                           int starting_order, std::vector<std::vector<std::string> > idxNames) {
-  if (active.size() == 0)
-    return;
-  
-  // check for sanity of parameters
-  if (dim < 0 || dim % 2 != 0)
-    throw std::invalid_argument(
-      "invalid constant loop level to set lexicographical order");
-  std::vector<int> lex;
-  int ref_stmt_num;
-  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++) {
-    if ((*i) < 0 || (*i) >= stmt.size())
-      throw std::invalid_argument(
-        "invalid statement number " + to_string(*i));
-    if (dim >= stmt[*i].xform.n_out())
-      throw std::invalid_argument(
-        "invalid constant loop level to set lexicographical order");
-    if (i == active.begin()) {
-      lex = getLexicalOrder(*i);
-      ref_stmt_num = *i;
-    } else {
-      std::vector<int> lex2 = getLexicalOrder(*i);
-      for (int j = 0; j < dim; j += 2)
-        if (lex[j] != lex2[j])
-          throw std::invalid_argument(
-            "statements are not in the same sub loop nest");
-    }
-  }
-  
-  // sepearate statements by current loop level types
-  int level = (dim + 2) / 2;
-  std::map<std::pair<LoopLevelType, int>, std::set<int> > active_by_level_type;
-  std::set<int> active_by_no_level;
-  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++) {
-    if (level > stmt[*i].loop_level.size())
-      active_by_no_level.insert(*i);
-    else
-      active_by_level_type[std::make_pair(
-          stmt[*i].loop_level[level - 1].type,
-          stmt[*i].loop_level[level - 1].payload)].insert(*i);
-  }
-  
-  // further separate statements due to control dependences
-  std::vector<std::set<int> > active_by_level_type_splitted;
-  for (std::map<std::pair<LoopLevelType, int>, std::set<int> >::iterator i =
-         active_by_level_type.begin(); i != active_by_level_type.end(); i++)
-    active_by_level_type_splitted.push_back(i->second);
-  for (std::set<int>::iterator i = active_by_no_level.begin();
-       i != active_by_no_level.end(); i++)
-    for (int j = active_by_level_type_splitted.size() - 1; j >= 0; j--) {
-      std::set<int> controlled, not_controlled;
-      for (std::set<int>::iterator k =
-             active_by_level_type_splitted[j].begin();
-           k != active_by_level_type_splitted[j].end(); k++) {
-        std::vector<DependenceVector> dvs = dep.getEdge(*i, *k);
-        bool is_controlled = false;
-        for (int kk = 0; kk < dvs.size(); kk++)
-          if (dvs[kk].type = DEP_CONTROL) {
-            is_controlled = true;
-            break;
-          }
-        if (is_controlled)
-          controlled.insert(*k);
-        else
-          not_controlled.insert(*k);
-      }
-      if (controlled.size() != 0 && not_controlled.size() != 0) {
-        active_by_level_type_splitted.erase(
-          active_by_level_type_splitted.begin() + j);
-        active_by_level_type_splitted.push_back(controlled);
-        active_by_level_type_splitted.push_back(not_controlled);
-      }
-    }
-  
-  // set lexical order separating loops with different loop types first
-  if (active_by_level_type_splitted.size() + active_by_no_level.size() > 1) {
-    int dep_dim = get_last_dep_dim_before(ref_stmt_num, level) + 1;
-    
-    Graph<std::set<int>, Empty> g;
-    for (std::vector<std::set<int> >::iterator i =
-           active_by_level_type_splitted.begin();
-         i != active_by_level_type_splitted.end(); i++)
-      g.insert(*i);
-    for (std::set<int>::iterator i = active_by_no_level.begin();
-         i != active_by_no_level.end(); i++) {
-      std::set<int> t;
-      t.insert(*i);
-      g.insert(t);
-    }
-    for (int i = 0; i < g.vertex.size(); i++)
-      for (int j = i + 1; j < g.vertex.size(); j++) {
-        bool connected = false;
-        for (std::set<int>::iterator ii = g.vertex[i].first.begin();
-             ii != g.vertex[i].first.end(); ii++) {
-          for (std::set<int>::iterator jj = g.vertex[j].first.begin();
-               jj != g.vertex[j].first.end(); jj++) {
-            std::vector<DependenceVector> dvs = dep.getEdge(*ii,
-                                                            *jj);
-            for (int k = 0; k < dvs.size(); k++)
-              if (dvs[k].is_control_dependence()
-                  || (dvs[k].is_data_dependence()
-                      && !dvs[k].has_been_carried_before(
-                        dep_dim))) {
-                g.connect(i, j);
-                connected = true;
-                break;
-              }
-            if (connected)
-              break;
-          }
-          if (connected)
-            break;
-        }
-        connected = false;
-        for (std::set<int>::iterator ii = g.vertex[i].first.begin();
-             ii != g.vertex[i].first.end(); ii++) {
-          for (std::set<int>::iterator jj = g.vertex[j].first.begin();
-               jj != g.vertex[j].first.end(); jj++) {
-            std::vector<DependenceVector> dvs = dep.getEdge(*jj,
-                                                            *ii);
-            // find the sub loop nest specified by stmt_num and level,
-            // only iteration space satisfiable statements returned.
-            for (int k = 0; k < dvs.size(); k++)
-              if (dvs[k].is_control_dependence()
-                  || (dvs[k].is_data_dependence()
-                      && !dvs[k].has_been_carried_before(
-                        dep_dim))) {
-                g.connect(j, i);
-                connected = true;
-                break;
-              }
-            if (connected)
-              break;
-          }
-          if (connected)
-            break;
-        }
-      }
-    
-    std::vector<std::set<int> > s = g.topoSort();
-    if (s.size() != g.vertex.size())
-      throw loop_error(
-        "cannot separate statements with different loop types at loop level "
-        + to_string(level));
-    
-    // assign lexical order
-    int order = starting_order;
-    for (int i = 0; i < s.size(); i++) {
-      std::set<int> &cur_scc = g.vertex[*(s[i].begin())].first;
-      int sz = cur_scc.size();
-      if (sz == 1) {
-        int cur_stmt = *(cur_scc.begin());
-        assign_const(stmt[cur_stmt].xform, dim, order);
-        for (int j = dim + 2; j < stmt[cur_stmt].xform.n_out(); j += 2)
-          assign_const(stmt[cur_stmt].xform, j, 0);
-        order++;
-      } else {
-        setLexicalOrder(dim, cur_scc, order, idxNames);
-        order += sz;
-      }
-    }
-  }
-  // set lexical order seperating single iteration statements and loops
-  else {
-    std::set<int> true_singles;
-    std::set<int> nonsingles;
-    std::map<coef_t, std::set<int> > fake_singles;
-    std::set<int> fake_singles_;
-    
-    // sort out statements that do not require loops
-    for (std::set<int>::iterator i = active.begin(); i != active.end();
-         i++) {
-      Relation cur_IS = getNewIS(*i);
-      if (is_single_iteration(cur_IS, dim + 1)) {
-        bool is_all_single = true;
-        for (int j = dim + 3; j < stmt[*i].xform.n_out(); j += 2)
-          if (!is_single_iteration(cur_IS, j)) {
-            is_all_single = false;
-            break;
-          }
-        if (is_all_single)
-          true_singles.insert(*i);
-        else {
-          fake_singles_.insert(*i);
-          try {
-            fake_singles[get_const(cur_IS, dim + 1, Set_Var)].insert(
-              *i);
-          } catch (const std::exception &e) {
-            fake_singles[posInfinity].insert(*i);
-          }
-        }
-      } else
-        nonsingles.insert(*i);
-    }
-    
-    
-    // split nonsingles forcibly according to negative dependences present (loop unfusible)
-    int dep_dim = get_dep_dim_of(ref_stmt_num, level);
-    
-    if (dim < stmt[ref_stmt_num].xform.n_out() - 1) {
-      
-      bool dummy_level_found = false;
-      
-      std::vector<std::set<int> > s;
-      
-      s = sort_by_same_loops(active, level);
-      bool further_levels_exist = false;
-      
-      if (!idxNames.empty())
-        if (level <= idxNames[ref_stmt_num].size())
-          if (idxNames[ref_stmt_num][level - 1].length() == 0) {
-            //  && s.size() == 1) {
-            int order1 = 0;
-            dummy_level_found = true;
-            
-            for (int i = level; i < idxNames[ref_stmt_num].size();
-                 i++)
-              if (idxNames[ref_stmt_num][i].length() > 0)
-                further_levels_exist = true;
-            
-          }
-      
-      //if (!dummy_level_found) {
-      
-      if (s.size() > 1) {
-        
-        Graph<std::set<int>, bool> g = construct_induced_graph_at_level(
-          s, dep, dep_dim);
-        s = typed_fusion(g);
-      }
-      int order = 0;
-      for (int i = 0; i < s.size(); i++) {
-        
-        for (std::set<int>::iterator it = s[i].begin();
-             it != s[i].end(); it++)
-          assign_const(stmt[*it].xform, dim, order);
-        
-        if ((dim + 2) <= (stmt[ref_stmt_num].xform.n_out() - 1))
-          setLexicalOrder(dim + 2, s[i], order, idxNames);
-        
-        order++;
-      }
-      //}
-      /*    else {
-            
-            int order1 = 0;
-            int order = 0;
-            for (std::set<int>::iterator i = active.begin();
-            i != active.end(); i++) {
-            if (!further_levels_exist)
-            assign_const(stmt[*i].xform, dim, order1++);
-            else
-            assign_const(stmt[*i].xform, dim, order1);
-            
-            }
-            
-            if ((dim + 2) <= (stmt[ref_stmt_num].xform.n_out() - 1) && further_levels_exist)
-            setLexicalOrder(dim + 2, active, order, idxNames);
-            }
-      */
-    } else {
-      int dummy_order = 0;
-      for (std::set<int>::iterator i = active.begin(); i != active.end();
-           i++)
-        assign_const(stmt[*i].xform, dim, dummy_order++);
-    }
-    /*for (int i = 0; i < g2.vertex.size(); i++)
-      for (int j = i+1; j < g2.vertex.size(); j++) {
-      std::vector<DependenceVector> dvs = dep.getEdge(g2.vertex[i].first, g2.vertex[j].first);
-      for (int k = 0; k < dvs.size(); k++)
-      if (dvs[k].is_control_dependence() ||
-      (dvs[k].is_data_dependence() && dvs[k].has_negative_been_carried_at(dep_dim))) {
-      g2.connect(i, j);
-      break;
-      }
-      dvs = dep.getEdge(g2.vertex[j].first, g2.vertex[i].first);
-      for (int k = 0; k < dvs.size(); k++)
-      if (dvs[k].is_control_dependence() ||
-      (dvs[k].is_data_dependence() && dvs[k].has_negative_been_carried_at(dep_dim))) {
-      g2.connect(j, i);
-      break;
-      }
-      }
-      
-      std::vector<std::set<int> > s2 = g2.packed_topoSort();
-      
-      std::vector<std::set<int> > splitted_nonsingles;
-      for (int i = 0; i < s2.size(); i++) {
-      std::set<int> cur_scc;
-      for (std::set<int>::iterator j = s2[i].begin(); j != s2[i].end(); j++)
-      cur_scc.insert(g2.vertex[*j].first);
-      splitted_nonsingles.push_back(cur_scc);
-      }
-    */
-    //convert to dependence graph for grouped statements
-    //dep_dim = get_last_dep_dim_before(ref_stmt_num, level) + 1;
-    /*int order = 0;
-      for (std::set<int>::iterator j = active.begin(); j != active.end();
-      j++) {
-      std::set<int> continuous;
-      std::cout<< active.size()<<std::endl;
-      while (nonsingles.find(*j) != nonsingles.end() && j != active.end()) {
-      continuous.insert(*j);
-      j++;
-      }
-      
-      printf("continuous size is %d\n", continuous.size());
-      
-      
-      
-      if (continuous.size() > 0) {
-      std::vector<std::set<int> > s = typed_fusion(continuous, dep,
-      dep_dim);
-      
-      for (int i = 0; i < s.size(); i++) {
-      for (std::set<int>::iterator l = s[i].begin();
-      l != s[i].end(); l++) {
-      assign_const(stmt[*l].xform, dim + 2, order);
-      setLexicalOrder(dim + 2, s[i]);
-      }
-      order++;
-      }
-      }
-      
-      if (j != active.end()) {
-      assign_const(stmt[*j].xform, dim + 2, order);
-      
-      for (int k = dim + 4; k < stmt[*j].xform.n_out(); k += 2)
-      assign_const(stmt[*j].xform, k, 0);
-      order++;
-      }
-      
-      if( j == active.end())
-      break;
-      }
-    */
-    
-    
-    // assign lexical order
-    /*int order = starting_order;
-      for (int i = 0; i < s.size(); i++) {
-      // translate each SCC into original statements
-      std::set<int> cur_scc;
-      for (std::set<int>::iterator j = s[i].begin(); j != s[i].end(); j++)
-      copy(s[i].begin(), s[i].end(),
-      inserter(cur_scc, cur_scc.begin()));
-      
-      // now assign the constant
-      for (std::set<int>::iterator j = cur_scc.begin();
-      j != cur_scc.end(); j++)
-      assign_const(stmt[*j].xform, dim, order);
-      
-      if (cur_scc.size() > 1)
-      setLexicalOrder(dim + 2, cur_scc);
-      else if (cur_scc.size() == 1) {
-      int cur_stmt = *(cur_scc.begin());
-      for (int j = dim + 2; j < stmt[cur_stmt].xform.n_out(); j += 2)
-      assign_const(stmt[cur_stmt].xform, j, 0);
-      }
-      
-      if (cur_scc.size() > 0)
-      order++;
-      }
-    */
-  }
-}
-
-void Loop::apply_xform() {
-  std::set<int> active;
-  for (int i = 0; i < stmt.size(); i++)
-    active.insert(i);
-  apply_xform(active);
-}
-
-void Loop::apply_xform(int stmt_num) {
-  std::set<int> active;
-  active.insert(stmt_num);
-  apply_xform(active);
-}
-
-void Loop::apply_xform(std::set<int> &active) {
-  int max_n = 0;
-  
-  CG_outputBuilder *ocg = ir->builder();
-  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++) {
-    int n = stmt[*i].loop_level.size();
-    if (n > max_n)
-      max_n = n;
-    
-    std::vector<int> lex = getLexicalOrder(*i);
-    
-    Relation mapping(2 * n + 1, n);
-    F_And *f_root = mapping.add_and();
-    for (int j = 1; j <= n; j++) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(mapping.output_var(j), 1);
-      h.update_coef(mapping.input_var(2 * j), -1);
-    }
-    mapping = Composition(mapping, stmt[*i].xform);
-    mapping.simplify();
-    
-    // match omega input/output variables to variable names in the code
-    for (int j = 1; j <= stmt[*i].IS.n_set(); j++)
-      mapping.name_input_var(j, stmt[*i].IS.set_var(j)->name());
-    for (int j = 1; j <= n; j++)
-      mapping.name_output_var(j,
-                              tmp_loop_var_name_prefix
-                              + to_string(tmp_loop_var_name_counter + j - 1));
-    mapping.setup_names();
-    
-    Relation known = Extend_Set(copy(this->known),
-                                mapping.n_out() - this->known.n_set());
-    //stmt[*i].code = outputStatement(ocg, stmt[*i].code, 0, mapping, known, std::vector<CG_outputRepr *>(mapping.n_out(), NULL));
-    std::vector<std::string> loop_vars;
-    for (int j = 1; j <= stmt[*i].IS.n_set(); j++)
-      loop_vars.push_back(stmt[*i].IS.set_var(j)->name());
-    std::vector<CG_outputRepr *> subs = output_substitutions(ocg,
-                                                             Inverse(copy(mapping)),
-                                                             std::vector<std::pair<CG_outputRepr *, int> >(mapping.n_out(),
-                                                                                                           std::make_pair(static_cast<CG_outputRepr *>(NULL), 0)));
-    stmt[*i].code = ocg->CreateSubstitutedStmt(0, stmt[*i].code, loop_vars,
-                                               subs);
-    stmt[*i].IS = Range(Restrict_Domain(mapping, stmt[*i].IS));
-    stmt[*i].IS.simplify();
-    
-    // replace original transformation relation with straight 1-1 mapping
-    mapping = Relation(n, 2 * n + 1);
-    f_root = mapping.add_and();
-    for (int j = 1; j <= n; j++) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(mapping.output_var(2 * j), 1);
-      h.update_coef(mapping.input_var(j), -1);
-    }
-    for (int j = 1; j <= 2 * n + 1; j += 2) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(mapping.output_var(j), 1);
-      h.update_const(-lex[j - 1]);
-    }
-    stmt[*i].xform = mapping;
-  }
-  
-  tmp_loop_var_name_counter += max_n;
-}
-
-void Loop::addKnown(const Relation &cond) {
-  
-  // invalidate saved codegen computation
-  delete last_compute_cgr_;
-  last_compute_cgr_ = NULL;
-  delete last_compute_cg_;
-  last_compute_cg_ = NULL;
-  
-  int n1 = this->known.n_set();
-  
-  Relation r = copy(cond);
-  int n2 = r.n_set();
-  
-  if (n1 < n2)
-    this->known = Extend_Set(this->known, n2 - n1);
-  else if (n1 > n2)
-    r = Extend_Set(r, n1 - n2);
-  
-  this->known = Intersection(this->known, r);
-}
-
-void Loop::removeDependence(int stmt_num_from, int stmt_num_to) {
-  // check for sanity of parameters
-  if (stmt_num_from >= stmt.size())
-    throw std::invalid_argument(
-      "invalid statement number " + to_string(stmt_num_from));
-  if (stmt_num_to >= stmt.size())
-    throw std::invalid_argument(
-      "invalid statement number " + to_string(stmt_num_to));
-  
-  dep.disconnect(stmt_num_from, stmt_num_to);
-}
-
-void Loop::dump() const {
-  for (int i = 0; i < stmt.size(); i++) {
-    std::vector<int> lex = getLexicalOrder(i);
-    std::cout << "s" << i + 1 << ": ";
-    for (int j = 0; j < stmt[i].loop_level.size(); j++) {
-      if (2 * j < lex.size())
-        std::cout << lex[2 * j];
-      switch (stmt[i].loop_level[j].type) {
-      case LoopLevelOriginal:
-        std::cout << "(dim:" << stmt[i].loop_level[j].payload << ")";
-        break;
-      case LoopLevelTile:
-        std::cout << "(tile:" << stmt[i].loop_level[j].payload << ")";
-        break;
-      default:
-        std::cout << "(unknown)";
-      }
-      std::cout << ' ';
-    }
-    for (int j = 2 * stmt[i].loop_level.size(); j < lex.size(); j += 2) {
-      std::cout << lex[j];
-      if (j != lex.size() - 1)
-        std::cout << ' ';
-    }
-    std::cout << std::endl;
-  }
-}
-
-bool Loop::nonsingular(const std::vector<std::vector<int> > &T) {
-  if (stmt.size() == 0)
-    return true;
-  
-  // check for sanity of parameters
-  for (int i = 0; i < stmt.size(); i++) {
-    if (stmt[i].loop_level.size() != num_dep_dim)
-      throw std::invalid_argument(
-        "nonsingular loop transformations must be applied to original perfect loop nest");
-    for (int j = 0; j < stmt[i].loop_level.size(); j++)
-      if (stmt[i].loop_level[j].type != LoopLevelOriginal)
-        throw std::invalid_argument(
-          "nonsingular loop transformations must be applied to original perfect loop nest");
-  }
-  if (T.size() != num_dep_dim)
-    throw std::invalid_argument("invalid transformation matrix");
-  for (int i = 0; i < stmt.size(); i++)
-    if (T[i].size() != num_dep_dim + 1 && T[i].size() != num_dep_dim)
-      throw std::invalid_argument("invalid transformation matrix");
-  // invalidate saved codegen computation
-  delete last_compute_cgr_;
-  last_compute_cgr_ = NULL;
-  delete last_compute_cg_;
-  last_compute_cg_ = NULL;
-  // build relation from matrix
-  Relation mapping(2 * num_dep_dim + 1, 2 * num_dep_dim + 1);
-  F_And *f_root = mapping.add_and();
-  for (int i = 0; i < num_dep_dim; i++) {
-    EQ_Handle h = f_root->add_EQ();
-    h.update_coef(mapping.output_var(2 * (i + 1)), -1);
-    for (int j = 0; j < num_dep_dim; j++)
-      if (T[i][j] != 0)
-        h.update_coef(mapping.input_var(2 * (j + 1)), T[i][j]);
-    if (T[i].size() == num_dep_dim + 1)
-      h.update_const(T[i][num_dep_dim]);
-  }
-  for (int i = 1; i <= 2 * num_dep_dim + 1; i += 2) {
-    EQ_Handle h = f_root->add_EQ();
-    h.update_coef(mapping.output_var(i), -1);
-    h.update_coef(mapping.input_var(i), 1);
-  }
-  
-  // update transformation relations
-  for (int i = 0; i < stmt.size(); i++)
-    stmt[i].xform = Composition(copy(mapping), stmt[i].xform);
-  
-  // update dependence graph
-  for (int i = 0; i < dep.vertex.size(); i++)
-    for (DependenceGraph::EdgeList::iterator j =
-           dep.vertex[i].second.begin(); j != dep.vertex[i].second.end();
-         j++) {
-      std::vector<DependenceVector> dvs = j->second;
-      for (int k = 0; k < dvs.size(); k++) {
-        DependenceVector &dv = dvs[k];
-        switch (dv.type) {
-        case DEP_W2R:
-        case DEP_R2W:
-        case DEP_W2W:
-        case DEP_R2R: {
-          std::vector<coef_t> lbounds(num_dep_dim), ubounds(
-            num_dep_dim);
-          for (int p = 0; p < num_dep_dim; p++) {
-            coef_t lb = 0;
-            coef_t ub = 0;
-            for (int q = 0; q < num_dep_dim; q++) {
-              if (T[p][q] > 0) {
-                if (lb == -posInfinity
-                    || dv.lbounds[q] == -posInfinity)
-                  lb = -posInfinity;
-                else
-                  lb += T[p][q] * dv.lbounds[q];
-                if (ub == posInfinity
-                    || dv.ubounds[q] == posInfinity)
-                  ub = posInfinity;
-                else
-                  ub += T[p][q] * dv.ubounds[q];
-              } else if (T[p][q] < 0) {
-                if (lb == -posInfinity
-                    || dv.ubounds[q] == posInfinity)
-                  lb = -posInfinity;
-                else
-                  lb += T[p][q] * dv.ubounds[q];
-                if (ub == posInfinity
-                    || dv.lbounds[q] == -posInfinity)
-                  ub = posInfinity;
-                else
-                  ub += T[p][q] * dv.lbounds[q];
-              }
-            }
-            if (T[p].size() == num_dep_dim + 1) {
-              if (lb != -posInfinity)
-                lb += T[p][num_dep_dim];
-              if (ub != posInfinity)
-                ub += T[p][num_dep_dim];
-            }
-            lbounds[p] = lb;
-            ubounds[p] = ub;
-          }
-          dv.lbounds = lbounds;
-          dv.ubounds = ubounds;
-          
-          break;
-        }
-        default:
-          ;
-        }
-      }
-      j->second = dvs;
-    }
-  
-  // set constant loop values
-  std::set<int> active;
-  for (int i = 0; i < stmt.size(); i++)
-    active.insert(i);
-  setLexicalOrder(0, active);
-  
-  return true;
-}
-
-
-bool Loop::is_dependence_valid_based_on_lex_order(int i, int j,
-                                                  const DependenceVector &dv, bool before) {
-  std::vector<int> lex_i = getLexicalOrder(i);
-  std::vector<int> lex_j = getLexicalOrder(j);
-  int last_dim;
-  if (!dv.is_scalar_dependence) {
-    for (last_dim = 0;
-         last_dim < lex_i.size() && (lex_i[last_dim] == lex_j[last_dim]);
-         last_dim++)
-      ;
-    last_dim = last_dim / 2;
-    if (last_dim == 0)
-      return true;
-    
-    for (int i = 0; i < last_dim; i++) {
-      if (dv.lbounds[i] > 0)
-        return true;
-      else if (dv.lbounds[i] < 0)
-        return false;
-    }
-  }
-  if (before)
-    return true;
-  
-  return false;
-  
-}
-
diff --git a/chill/src/loop_basic.cc b/chill/src/loop_basic.cc
deleted file mode 100644
index f5234b9..0000000
--- a/chill/src/loop_basic.cc
+++ /dev/null
@@ -1,1538 +0,0 @@
-/*
- * loop_basic.cc
- *
- *  Created on: Nov 12, 2012
- *      Author: anand
- */
-
-#include "loop.hh"
-#include "chill_error.hh"
-#include <omega.h>
-#include "omegatools.hh"
-#include <string.h>
-
-using namespace omega;
-
-void Loop::permute(const std::vector<int> &pi) {
-  std::set<int> active;
-  for (int i = 0; i < stmt.size(); i++)
-    active.insert(i);
-  
-  permute(active, pi);
-}
-
-void Loop::original() {
-  std::set<int> active;
-  for (int i = 0; i < stmt.size(); i++)
-    active.insert(i);
-  setLexicalOrder(0, active);
-}
-void Loop::permute(int stmt_num, int level, const std::vector<int> &pi) {
-  // check for sanity of parameters
-  int starting_order;
-  if (stmt_num < 0 || stmt_num >= stmt.size())
-    throw std::invalid_argument(
-      "invalid statement number " + to_string(stmt_num));
-  std::set<int> active;
-  if (level < 0 || level > stmt[stmt_num].loop_level.size())
-    throw std::invalid_argument("invalid loop level " + to_string(level));
-  else if (level == 0) {
-    for (int i = 0; i < stmt.size(); i++)
-      active.insert(i);
-    level = 1;
-    starting_order = 0;
-  } else {
-    std::vector<int> lex = getLexicalOrder(stmt_num);
-    active = getStatements(lex, 2 * level - 2);
-    starting_order = lex[2 * level - 2];
-    lex[2 * level - 2]++;
-    shiftLexicalOrder(lex, 2 * level - 2, active.size() - 1);
-  }
-  std::vector<int> pi_inverse(pi.size(), 0);
-  for (int i = 0; i < pi.size(); i++) {
-    if (pi[i] >= level + pi.size() || pi[i] < level
-        || pi_inverse[pi[i] - level] != 0)
-      throw std::invalid_argument("invalid permuation");
-    pi_inverse[pi[i] - level] = level + i;
-  }
-  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++)
-    if (level + pi.size() - 1 > stmt[*i].loop_level.size())
-      throw std::invalid_argument(
-        "invalid permutation for statement " + to_string(*i));
-  
-  // invalidate saved codegen computation
-  delete last_compute_cgr_;
-  last_compute_cgr_ = NULL;
-  delete last_compute_cg_;
-  last_compute_cg_ = NULL;
-  
-  // Update transformation relations
-  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++) {
-    int n = stmt[*i].xform.n_out();
-    Relation mapping(n, n);
-    F_And *f_root = mapping.add_and();
-    for (int j = 1; j <= 2 * level - 2; j++) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(mapping.output_var(j), 1);
-      h.update_coef(mapping.input_var(j), -1);
-    }
-    for (int j = level; j <= level + pi.size() - 1; j++) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(mapping.output_var(2 * j), 1);
-      h.update_coef(mapping.input_var(2 * pi[j - level]), -1);
-    }
-    for (int j = level; j <= level + pi.size() - 1; j++) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(mapping.output_var(2 * j - 1), 1);
-      h.update_coef(mapping.input_var(2 * j - 1), -1);
-    }
-    for (int j = 2 * (level + pi.size() - 1) + 1; j <= n; j++) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(mapping.output_var(j), 1);
-      h.update_coef(mapping.input_var(j), -1);
-    }
-    stmt[*i].xform = Composition(mapping, stmt[*i].xform);
-    stmt[*i].xform.simplify();
-  }
-  
-  // get the permuation for dependence vectors
-  std::vector<int> t;
-  for (int i = 0; i < pi.size(); i++)
-    if (stmt[stmt_num].loop_level[pi[i] - 1].type == LoopLevelOriginal)
-      t.push_back(stmt[stmt_num].loop_level[pi[i] - 1].payload);
-  int max_dep_dim = -1;
-  int min_dep_dim = dep.num_dim();
-  for (int i = 0; i < t.size(); i++) {
-    if (t[i] > max_dep_dim)
-      max_dep_dim = t[i];
-    if (t[i] < min_dep_dim)
-      min_dep_dim = t[i];
-  }
-  if (min_dep_dim > max_dep_dim)
-    return;
-  if (max_dep_dim - min_dep_dim + 1 != t.size())
-    throw loop_error("cannot update the dependence graph after permuation");
-  std::vector<int> dep_pi(dep.num_dim());
-  for (int i = 0; i < min_dep_dim; i++)
-    dep_pi[i] = i;
-  for (int i = min_dep_dim; i <= max_dep_dim; i++)
-    dep_pi[i] = t[i - min_dep_dim];
-  for (int i = max_dep_dim + 1; i < dep.num_dim(); i++)
-    dep_pi[i] = i;
-  
-  dep.permute(dep_pi, active);
-  
-  // update the dependence graph
-  DependenceGraph g(dep.num_dim());
-  for (int i = 0; i < dep.vertex.size(); i++)
-    g.insert();
-  for (int i = 0; i < dep.vertex.size(); i++)
-    for (DependenceGraph::EdgeList::iterator j =
-           dep.vertex[i].second.begin(); j != dep.vertex[i].second.end();
-         j++) {
-      if ((active.find(i) != active.end()
-           && active.find(j->first) != active.end())) {
-        std::vector<DependenceVector> dv = j->second;
-        for (int k = 0; k < dv.size(); k++) {
-          switch (dv[k].type) {
-          case DEP_W2R:
-          case DEP_R2W:
-          case DEP_W2W:
-          case DEP_R2R: {
-            std::vector<coef_t> lbounds(dep.num_dim());
-            std::vector<coef_t> ubounds(dep.num_dim());
-            for (int d = 0; d < dep.num_dim(); d++) {
-              lbounds[d] = dv[k].lbounds[dep_pi[d]];
-              ubounds[d] = dv[k].ubounds[dep_pi[d]];
-            }
-            dv[k].lbounds = lbounds;
-            dv[k].ubounds = ubounds;
-            break;
-          }
-          case DEP_CONTROL: {
-            break;
-          }
-          default:
-            throw loop_error("unknown dependence type");
-          }
-        }
-        g.connect(i, j->first, dv);
-      } else if (active.find(i) == active.end()
-                 && active.find(j->first) == active.end()) {
-        std::vector<DependenceVector> dv = j->second;
-        g.connect(i, j->first, dv);
-      } else {
-        std::vector<DependenceVector> dv = j->second;
-        for (int k = 0; k < dv.size(); k++)
-          switch (dv[k].type) {
-          case DEP_W2R:
-          case DEP_R2W:
-          case DEP_W2W:
-          case DEP_R2R: {
-            for (int d = 0; d < dep.num_dim(); d++)
-              if (dep_pi[d] != d) {
-                dv[k].lbounds[d] = -posInfinity;
-                dv[k].ubounds[d] = posInfinity;
-              }
-            break;
-          }
-          case DEP_CONTROL:
-            break;
-          default:
-            throw loop_error("unknown dependence type");
-          }
-        g.connect(i, j->first, dv);
-      }
-    }
-  dep = g;
-  
-  // update loop level information
-  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++) {
-    int cur_dep_dim = min_dep_dim;
-    std::vector<LoopLevel> new_loop_level(stmt[*i].loop_level.size());
-    for (int j = 1; j <= stmt[*i].loop_level.size(); j++)
-      if (j >= level && j < level + pi.size()) {
-        switch (stmt[*i].loop_level[pi_inverse[j - level] - 1].type) {
-        case LoopLevelOriginal:
-          new_loop_level[j - 1].type = LoopLevelOriginal;
-          new_loop_level[j - 1].payload = cur_dep_dim++;
-          new_loop_level[j - 1].parallel_level =
-            stmt[*i].loop_level[pi_inverse[j - level] - 1].parallel_level;
-          break;
-        case LoopLevelTile: {
-          new_loop_level[j - 1].type = LoopLevelTile;
-          int ref_level = stmt[*i].loop_level[pi_inverse[j - level]
-                                              - 1].payload;
-          if (ref_level >= level && ref_level < level + pi.size())
-            new_loop_level[j - 1].payload = pi_inverse[ref_level
-                                                       - level];
-          else
-            new_loop_level[j - 1].payload = ref_level;
-          new_loop_level[j - 1].parallel_level = stmt[*i].loop_level[j
-                                                                     - 1].parallel_level;
-          break;
-        }
-        default:
-          throw loop_error(
-            "unknown loop level information for statement "
-            + to_string(*i));
-        }
-      } else {
-        switch (stmt[*i].loop_level[j - 1].type) {
-        case LoopLevelOriginal:
-          new_loop_level[j - 1].type = LoopLevelOriginal;
-          new_loop_level[j - 1].payload =
-            stmt[*i].loop_level[j - 1].payload;
-          new_loop_level[j - 1].parallel_level = stmt[*i].loop_level[j
-                                                                     - 1].parallel_level;
-          break;
-        case LoopLevelTile: {
-          new_loop_level[j - 1].type = LoopLevelTile;
-          int ref_level = stmt[*i].loop_level[j - 1].payload;
-          if (ref_level >= level && ref_level < level + pi.size())
-            new_loop_level[j - 1].payload = pi_inverse[ref_level
-                                                       - level];
-          else
-            new_loop_level[j - 1].payload = ref_level;
-          new_loop_level[j - 1].parallel_level = stmt[*i].loop_level[j
-                                                                     - 1].parallel_level;
-          break;
-        }
-        default:
-          throw loop_error(
-            "unknown loop level information for statement "
-            + to_string(*i));
-        }
-      }
-    stmt[*i].loop_level = new_loop_level;
-  }
-  
-  setLexicalOrder(2 * level - 2, active, starting_order);
-}
-void Loop::permute(const std::set<int> &active, const std::vector<int> &pi) {
-  if (active.size() == 0 || pi.size() == 0)
-    return;
-  
-  // check for sanity of parameters
-  int level = pi[0];
-  for (int i = 1; i < pi.size(); i++)
-    if (pi[i] < level)
-      level = pi[i];
-  if (level < 1)
-    throw std::invalid_argument("invalid permuation");
-  std::vector<int> reverse_pi(pi.size(), 0);
-  for (int i = 0; i < pi.size(); i++)
-    if (pi[i] >= level + pi.size())
-      throw std::invalid_argument("invalid permutation");
-    else
-      reverse_pi[pi[i] - level] = i + level;
-  for (int i = 0; i < reverse_pi.size(); i++)
-    if (reverse_pi[i] == 0)
-      throw std::invalid_argument("invalid permuation");
-  int ref_stmt_num;
-  std::vector<int> lex;
-  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++) {
-    if (*i < 0 || *i >= stmt.size())
-      throw std::invalid_argument("invalid statement " + to_string(*i));
-    if (i == active.begin()) {
-      ref_stmt_num = *i;
-      lex = getLexicalOrder(*i);
-    } else {
-      if (level + pi.size() - 1 > stmt[*i].loop_level.size())
-        throw std::invalid_argument("invalid permuation");
-      std::vector<int> lex2 = getLexicalOrder(*i);
-      for (int j = 0; j < 2 * level - 3; j += 2)
-        if (lex[j] != lex2[j])
-          throw std::invalid_argument(
-            "statements to permute must be in the same subloop");
-      for (int j = 0; j < pi.size(); j++)
-        if (!(stmt[*i].loop_level[level + j - 1].type
-              == stmt[ref_stmt_num].loop_level[level + j - 1].type
-              && stmt[*i].loop_level[level + j - 1].payload
-              == stmt[ref_stmt_num].loop_level[level + j - 1].payload))
-          throw std::invalid_argument(
-            "permuted loops must have the same loop level types");
-    }
-  }
-  // invalidate saved codegen computation
-  delete last_compute_cgr_;
-  last_compute_cgr_ = NULL;
-  delete last_compute_cg_;
-  last_compute_cg_ = NULL;
-  
-  // Update transformation relations
-  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++) {
-    int n = stmt[*i].xform.n_out();
-    Relation mapping(n, n);
-    F_And *f_root = mapping.add_and();
-    for (int j = 1; j <= n; j += 2) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(mapping.output_var(j), 1);
-      h.update_coef(mapping.input_var(j), -1);
-    }
-    for (int j = 0; j < pi.size(); j++) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(mapping.output_var(2 * (level + j)), 1);
-      h.update_coef(mapping.input_var(2 * pi[j]), -1);
-    }
-    for (int j = 1; j < level; j++) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(mapping.output_var(2 * j), 1);
-      h.update_coef(mapping.input_var(2 * j), -1);
-    }
-    for (int j = level + pi.size(); j <= stmt[*i].loop_level.size(); j++) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(mapping.output_var(2 * j), 1);
-      h.update_coef(mapping.input_var(2 * j), -1);
-    }
-    
-    stmt[*i].xform = Composition(mapping, stmt[*i].xform);
-    stmt[*i].xform.simplify();
-  }
-  
-  // get the permuation for dependence vectors
-  std::vector<int> t;
-  for (int i = 0; i < pi.size(); i++)
-    if (stmt[ref_stmt_num].loop_level[pi[i] - 1].type == LoopLevelOriginal)
-      t.push_back(stmt[ref_stmt_num].loop_level[pi[i] - 1].payload);
-  int max_dep_dim = -1;
-  int min_dep_dim = num_dep_dim;
-  for (int i = 0; i < t.size(); i++) {
-    if (t[i] > max_dep_dim)
-      max_dep_dim = t[i];
-    if (t[i] < min_dep_dim)
-      min_dep_dim = t[i];
-  }
-  if (min_dep_dim > max_dep_dim)
-    return;
-  if (max_dep_dim - min_dep_dim + 1 != t.size())
-    throw loop_error("cannot update the dependence graph after permuation");
-  std::vector<int> dep_pi(num_dep_dim);
-  for (int i = 0; i < min_dep_dim; i++)
-    dep_pi[i] = i;
-  for (int i = min_dep_dim; i <= max_dep_dim; i++)
-    dep_pi[i] = t[i - min_dep_dim];
-  for (int i = max_dep_dim + 1; i < num_dep_dim; i++)
-    dep_pi[i] = i;
-  
-  dep.permute(dep_pi, active);
-  
-  // update the dependence graph
-  DependenceGraph g(dep.num_dim());
-  for (int i = 0; i < dep.vertex.size(); i++)
-    g.insert();
-  for (int i = 0; i < dep.vertex.size(); i++)
-    for (DependenceGraph::EdgeList::iterator j =
-           dep.vertex[i].second.begin(); j != dep.vertex[i].second.end();
-         j++) {         //
-      if ((active.find(i) != active.end()
-           && active.find(j->first) != active.end())) {
-        std::vector<DependenceVector> dv = j->second;
-        for (int k = 0; k < dv.size(); k++) {
-          switch (dv[k].type) {
-          case DEP_W2R:
-          case DEP_R2W:
-          case DEP_W2W:
-          case DEP_R2R: {
-            std::vector<coef_t> lbounds(num_dep_dim);
-            std::vector<coef_t> ubounds(num_dep_dim);
-            for (int d = 0; d < num_dep_dim; d++) {
-              lbounds[d] = dv[k].lbounds[dep_pi[d]];
-              ubounds[d] = dv[k].ubounds[dep_pi[d]];
-            }
-            dv[k].lbounds = lbounds;
-            dv[k].ubounds = ubounds;
-            break;
-          }
-          case DEP_CONTROL: {
-            break;
-          }
-          default:
-            throw loop_error("unknown dependence type");
-          }
-        }
-        g.connect(i, j->first, dv);
-      } else if (active.find(i) == active.end()
-                 && active.find(j->first) == active.end()) {
-        std::vector<DependenceVector> dv = j->second;
-        g.connect(i, j->first, dv);
-      } else {
-        std::vector<DependenceVector> dv = j->second;
-        for (int k = 0; k < dv.size(); k++)
-          switch (dv[k].type) {
-          case DEP_W2R:
-          case DEP_R2W:
-          case DEP_W2W:
-          case DEP_R2R: {
-            for (int d = 0; d < num_dep_dim; d++)
-              if (dep_pi[d] != d) {
-                dv[k].lbounds[d] = -posInfinity;
-                dv[k].ubounds[d] = posInfinity;
-              }
-            break;
-          }
-          case DEP_CONTROL:
-            break;
-          default:
-            throw loop_error("unknown dependence type");
-          }
-        g.connect(i, j->first, dv);
-      }
-    }
-  dep = g;
-  
-  // update loop level information
-  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++) {
-    int cur_dep_dim = min_dep_dim;
-    std::vector<LoopLevel> new_loop_level(stmt[*i].loop_level.size());
-    for (int j = 1; j <= stmt[*i].loop_level.size(); j++)
-      if (j >= level && j < level + pi.size()) {
-        switch (stmt[*i].loop_level[reverse_pi[j - level] - 1].type) {
-        case LoopLevelOriginal:
-          new_loop_level[j - 1].type = LoopLevelOriginal;
-          new_loop_level[j - 1].payload = cur_dep_dim++;
-          new_loop_level[j - 1].parallel_level =
-            stmt[*i].loop_level[reverse_pi[j - level] - 1].parallel_level;
-          break;
-        case LoopLevelTile: {
-          new_loop_level[j - 1].type = LoopLevelTile;
-          int ref_level = stmt[*i].loop_level[reverse_pi[j - level]
-                                              - 1].payload;
-          if (ref_level >= level && ref_level < level + pi.size())
-            new_loop_level[j - 1].payload = reverse_pi[ref_level
-                                                       - level];
-          else
-            new_loop_level[j - 1].payload = ref_level;
-          new_loop_level[j - 1].parallel_level =
-            stmt[*i].loop_level[reverse_pi[j - level] - 1].parallel_level;
-          break;
-        }
-        default:
-          throw loop_error(
-            "unknown loop level information for statement "
-            + to_string(*i));
-        }
-      } else {
-        switch (stmt[*i].loop_level[j - 1].type) {
-        case LoopLevelOriginal:
-          new_loop_level[j - 1].type = LoopLevelOriginal;
-          new_loop_level[j - 1].payload =
-            stmt[*i].loop_level[j - 1].payload;
-          new_loop_level[j - 1].parallel_level = stmt[*i].loop_level[j
-                                                                     - 1].parallel_level;
-          break;
-        case LoopLevelTile: {
-          new_loop_level[j - 1].type = LoopLevelTile;
-          int ref_level = stmt[*i].loop_level[j - 1].payload;
-          if (ref_level >= level && ref_level < level + pi.size())
-            new_loop_level[j - 1].payload = reverse_pi[ref_level
-                                                       - level];
-          else
-            new_loop_level[j - 1].payload = ref_level;
-          new_loop_level[j - 1].parallel_level = stmt[*i].loop_level[j
-                                                                     - 1].parallel_level;
-          break;
-        }
-        default:
-          throw loop_error(
-            "unknown loop level information for statement "
-            + to_string(*i));
-        }
-      }
-    stmt[*i].loop_level = new_loop_level;
-  }
-  
-  setLexicalOrder(2 * level - 2, active);
-}
-
-std::set<int> Loop::split(int stmt_num, int level, const Relation &cond) {
-  // check for sanity of parameters
-  if (stmt_num < 0 || stmt_num >= stmt.size())
-    throw std::invalid_argument("invalid statement " + to_string(stmt_num));
-  if (level <= 0 || level > stmt[stmt_num].loop_level.size())
-    throw std::invalid_argument("invalid loop level " + to_string(level));
-  
-  std::set<int> result;
-  int dim = 2 * level - 1;
-  std::vector<int> lex = getLexicalOrder(stmt_num);
-  std::set<int> same_loop = getStatements(lex, dim - 1);
-  
-  Relation cond2 = copy(cond);
-  cond2.simplify();
-  cond2 = EQs_to_GEQs(cond2);
-  Conjunct *c = cond2.single_conjunct();
-  int cur_lex = lex[dim - 1];
-  
-  for (GEQ_Iterator gi(c->GEQs()); gi; gi++) {
-    int max_level = (*gi).max_tuple_pos();
-    Relation single_cond(max_level);
-    single_cond.and_with_GEQ(*gi);
-    
-    // TODO: should decide where to place newly created statements with
-    // complementary split condition from dependence graph.
-    bool place_after;
-    if (max_level == 0)
-      place_after = true;
-    else if ((*gi).get_coef(cond2.set_var(max_level)) < 0)
-      place_after = true;
-    else
-      place_after = false;
-    
-    bool temp_place_after;      // = place_after;
-    bool assigned = false;
-    int part1_to_part2;
-    int part2_to_part1;
-    // original statements with split condition,
-    // new statements with complement of split condition
-    int old_num_stmt = stmt.size();
-    std::map<int, int> what_stmt_num;
-    apply_xform(same_loop);
-    for (std::set<int>::iterator i = same_loop.begin();
-         i != same_loop.end(); i++) {
-      int n = stmt[*i].IS.n_set();
-      Relation part1, part2;
-      if (max_level > n) {
-        part1 = copy(stmt[*i].IS);
-        part2 = Relation::False(0);
-      } else {
-        part1 = Intersection(copy(stmt[*i].IS),
-                             Extend_Set(copy(single_cond), n - max_level));
-        part2 = Intersection(copy(stmt[*i].IS),
-                             Extend_Set(Complement(copy(single_cond)),
-                                        n - max_level));
-      }
-      
-      //split dependence check
-      
-      if (max_level > level) {
-        
-        DNF_Iterator di1(stmt[*i].IS.query_DNF());
-        DNF_Iterator di2(part1.query_DNF());
-        for (; di1 && di2; di1++, di2++) {
-          //printf("In next conjunct,\n");
-          EQ_Iterator ei1 = (*di1)->EQs();
-          EQ_Iterator ei2 = (*di2)->EQs();
-          for (; ei1 && ei2; ei1++, ei2++) {
-            //printf(" In next equality constraint,\n");
-            Constr_Vars_Iter cvi1(*ei1);
-            Constr_Vars_Iter cvi2(*ei2);
-            int dimension = (*cvi1).var->get_position();
-            int same = 0;
-            bool identical = false;
-            if (identical = !strcmp((*cvi1).var->char_name(),
-                                    (*cvi2).var->char_name())) {
-              
-              for (; cvi1 && cvi2; cvi1++, cvi2++) {
-                
-                if (((*cvi1).coef != (*cvi2).coef
-                     || (*ei1).get_const()
-                     != (*ei2).get_const())
-                    || (strcmp((*cvi1).var->char_name(),
-                               (*cvi2).var->char_name()))) {
-                  
-                  same++;
-                }
-              }
-            }
-            if ((same != 0) || !identical) {
-              
-              dimension = dimension - 1;
-              
-              while (stmt[*i].loop_level[dimension].type
-                     == LoopLevelTile)
-                dimension =
-                  stmt[*i].loop_level[dimension].payload;
-              
-              dimension = stmt[*i].loop_level[dimension].payload;
-              
-              for (int i = 0; i < stmt.size(); i++) {
-                std::vector<std::pair<int, DependenceVector> > D;
-                for (DependenceGraph::EdgeList::iterator j =
-                       dep.vertex[i].second.begin();
-                     j != dep.vertex[i].second.end(); j++) {
-                  for (int k = 0; k < j->second.size(); k++) {
-                    DependenceVector dv = j->second[k];
-                    if (dv.type != DEP_CONTROL)
-                      if (dv.hasNegative(dimension)
-                          && !dv.quasi)
-                        throw loop_error(
-                          "loop error: Split is illegal, dependence violation!");
-                    
-                  }
-                }
-              }
-              
-            }
-            
-            GEQ_Iterator gi1 = (*di1)->GEQs();
-            GEQ_Iterator gi2 = (*di2)->GEQs();
-            
-            for (; gi1 && gi2; gi++, gi2++) {
-              
-              Constr_Vars_Iter cvi1(*gi1);
-              Constr_Vars_Iter cvi2(*gi2);
-              int dimension = (*cvi1).var->get_position();
-              int same = 0;
-              bool identical = false;
-              if (identical = !strcmp((*cvi1).var->char_name(),
-                                      (*cvi2).var->char_name())) {
-                
-                for (; cvi1 && cvi2; cvi1++, cvi2++) {
-                  
-                  if (((*cvi1).coef != (*cvi2).coef
-                       || (*gi1).get_const()
-                       != (*gi2).get_const())
-                      || (strcmp((*cvi1).var->char_name(),
-                                 (*cvi2).var->char_name()))) {
-                    
-                    same++;
-                  }
-                }
-              }
-              if ((same != 0) || !identical) {
-                dimension = dimension - 1;
-                
-                while (stmt[*i].loop_level[dimension].type
-                       == LoopLevelTile)
-                  stmt[*i].loop_level[dimension].payload;
-                
-                dimension =
-                  stmt[*i].loop_level[dimension].payload;
-                
-                for (int i = 0; i < stmt.size(); i++) {
-                  std::vector<std::pair<int, DependenceVector> > D;
-                  for (DependenceGraph::EdgeList::iterator j =
-                         dep.vertex[i].second.begin();
-                       j != dep.vertex[i].second.end();
-                       j++) {
-                    for (int k = 0; k < j->second.size();
-                         k++) {
-                      DependenceVector dv = j->second[k];
-                      if (dv.type != DEP_CONTROL)
-                        if (dv.hasNegative(dimension)
-                            && !dv.quasi)
-                          
-                          throw loop_error(
-                            "loop error: Split is illegal, dependence violation!");
-                      
-                    }
-                  }
-                }
-                
-              }
-              
-            }
-            
-          }
-          
-        }
-        
-        DNF_Iterator di3(stmt[*i].IS.query_DNF());
-        DNF_Iterator di4(part2.query_DNF());        //
-        for (; di3 && di4; di3++, di4++) {
-          EQ_Iterator ei1 = (*di3)->EQs();
-          EQ_Iterator ei2 = (*di4)->EQs();
-          for (; ei1 && ei2; ei1++, ei2++) {
-            Constr_Vars_Iter cvi1(*ei1);
-            Constr_Vars_Iter cvi2(*ei2);
-            int dimension = (*cvi1).var->get_position();
-            int same = 0;
-            bool identical = false;
-            if (identical = !strcmp((*cvi1).var->char_name(),
-                                    (*cvi2).var->char_name())) {
-              
-              for (; cvi1 && cvi2; cvi1++, cvi2++) {
-                
-                if (((*cvi1).coef != (*cvi2).coef
-                     || (*ei1).get_const()
-                     != (*ei2).get_const())
-                    || (strcmp((*cvi1).var->char_name(),
-                               (*cvi2).var->char_name()))) {
-                  
-                  same++;
-                }
-              }
-            }
-            if ((same != 0) || !identical) {
-              dimension = dimension - 1;
-              
-              while (stmt[*i].loop_level[dimension].type
-                     == LoopLevelTile)
-                stmt[*i].loop_level[dimension].payload;
-              
-              dimension = stmt[*i].loop_level[dimension].payload;
-              
-              for (int i = 0; i < stmt.size(); i++) {
-                std::vector<std::pair<int, DependenceVector> > D;
-                for (DependenceGraph::EdgeList::iterator j =
-                       dep.vertex[i].second.begin();
-                     j != dep.vertex[i].second.end(); j++) {
-                  for (int k = 0; k < j->second.size(); k++) {
-                    DependenceVector dv = j->second[k];
-                    if (dv.type != DEP_CONTROL)
-                      if (dv.hasNegative(dimension)
-                          && !dv.quasi)
-                        
-                        throw loop_error(
-                          "loop error: Split is illegal, dependence violation!");
-                    
-                  }
-                }
-              }
-              
-            }
-            
-          }
-          GEQ_Iterator gi1 = (*di3)->GEQs();
-          GEQ_Iterator gi2 = (*di4)->GEQs();
-          
-          for (; gi1 && gi2; gi++, gi2++) {
-            Constr_Vars_Iter cvi1(*gi1);
-            Constr_Vars_Iter cvi2(*gi2);
-            int dimension = (*cvi1).var->get_position();
-            int same = 0;
-            bool identical = false;
-            if (identical = !strcmp((*cvi1).var->char_name(),
-                                    (*cvi2).var->char_name())) {
-              
-              for (; cvi1 && cvi2; cvi1++, cvi2++) {
-                
-                if (((*cvi1).coef != (*cvi2).coef
-                     || (*gi1).get_const()
-                     != (*gi2).get_const())
-                    || (strcmp((*cvi1).var->char_name(),
-                               (*cvi2).var->char_name()))) {
-                  
-                  same++;
-                }
-              }
-            }
-            if ((same != 0) || !identical) {
-              dimension = dimension - 1;
-              
-              while (stmt[*i].loop_level[dimension].type        //
-                     == LoopLevelTile)
-                stmt[*i].loop_level[dimension].payload;
-              
-              dimension = stmt[*i].loop_level[dimension].payload;
-              
-              for (int i = 0; i < stmt.size(); i++) {
-                std::vector<std::pair<int, DependenceVector> > D;
-                for (DependenceGraph::EdgeList::iterator j =
-                       dep.vertex[i].second.begin();
-                     j != dep.vertex[i].second.end(); j++) {
-                  for (int k = 0; k < j->second.size(); k++) {
-                    DependenceVector dv = j->second[k];
-                    if (dv.type != DEP_CONTROL)
-                      if (dv.hasNegative(dimension)
-                          && !dv.quasi)
-                        
-                        throw loop_error(
-                          "loop error: Split is illegal, dependence violation!");
-                    
-                  }
-                }
-              }
-              
-            }
-            
-          }
-          
-        }
-        
-      }
-      
-      stmt[*i].IS = part1;
-      
-      if (Intersection(copy(part2),
-                       Extend_Set(copy(this->known), n - this->known.n_set())).is_upper_bound_satisfiable()) {
-        Statement new_stmt;
-        new_stmt.code = stmt[*i].code->clone();
-        new_stmt.IS = part2;
-        new_stmt.xform = copy(stmt[*i].xform);
-        new_stmt.ir_stmt_node = NULL;
-        new_stmt.loop_level = stmt[*i].loop_level;
-        
-        stmt_nesting_level_.push_back(stmt_nesting_level_[*i]);
-        
-        /*std::pair<std::vector<DependenceVector>,
-          std::vector<DependenceVector> > dv =
-          test_data_dependences(ir, stmt[*i].code, part1,
-          stmt[*i].code, part2, freevar, index,
-          stmt_nesting_level_[*i],
-          stmt_nesting_level_[stmt.size() - 1]);
-          
-          
-          
-          
-          for (int k = 0; k < dv.first.size(); k++)
-          part1_to_part2++;
-          if (part1_to_part2 > 0 && part2_to_part1 > 0)
-          throw loop_error(
-          "loop error: Aborting, split resulted in impossible dependence cycle!");
-          
-          for (int k = 0; k < dv.second.size(); k++)
-          part2_to_part1++;
-          
-          
-          
-          if (part1_to_part2 > 0 && part2_to_part1 > 0)
-          throw loop_error(
-          "loop error: Aborting, split resulted in impossible dependence cycle!");
-          
-          
-          
-          if (part2_to_part1 > 0){
-          temp_place_after = false;
-          assigned = true;
-          
-          }else if (part1_to_part2 > 0){
-          temp_place_after = true;
-          
-          assigned = true;
-          }
-          
-        */
-        
-        if (place_after)
-          assign_const(new_stmt.xform, dim - 1, cur_lex + 1);
-        else
-          assign_const(new_stmt.xform, dim - 1, cur_lex - 1);
-        
-        stmt.push_back(new_stmt);
-        dep.insert();
-        what_stmt_num[*i] = stmt.size() - 1;
-        if (*i == stmt_num)
-          result.insert(stmt.size() - 1);
-      }
-      
-    }
-    // make adjacent lexical number available for new statements
-    if (place_after) {
-      lex[dim - 1] = cur_lex + 1;
-      shiftLexicalOrder(lex, dim - 1, 1);
-    } else {
-      lex[dim - 1] = cur_lex - 1;
-      shiftLexicalOrder(lex, dim - 1, -1);
-    }
-    // update dependence graph
-    int dep_dim = get_dep_dim_of(stmt_num, level);
-    for (int i = 0; i < old_num_stmt; i++) {
-      std::vector<std::pair<int, std::vector<DependenceVector> > > D;
-      
-      for (DependenceGraph::EdgeList::iterator j =
-             dep.vertex[i].second.begin();
-           j != dep.vertex[i].second.end(); j++) {
-        if (same_loop.find(i) != same_loop.end()) {
-          if (same_loop.find(j->first) != same_loop.end()) {
-            if (what_stmt_num.find(i) != what_stmt_num.end()
-                && what_stmt_num.find(j->first)
-                != what_stmt_num.end())
-              dep.connect(what_stmt_num[i],
-                          what_stmt_num[j->first], j->second);
-            if (place_after
-                && what_stmt_num.find(j->first)
-                != what_stmt_num.end()) {
-              std::vector<DependenceVector> dvs;
-              for (int k = 0; k < j->second.size(); k++) {
-                DependenceVector dv = j->second[k];
-                if (dv.is_data_dependence() && dep_dim != -1) {
-                  dv.lbounds[dep_dim] = -posInfinity;
-                  dv.ubounds[dep_dim] = posInfinity;
-                }
-                dvs.push_back(dv);
-              }
-              if (dvs.size() > 0)
-                D.push_back(
-                  std::make_pair(what_stmt_num[j->first],
-                                 dvs));
-            } else if (!place_after
-                       && what_stmt_num.find(i)
-                       != what_stmt_num.end()) {
-              std::vector<DependenceVector> dvs;
-              for (int k = 0; k < j->second.size(); k++) {
-                DependenceVector dv = j->second[k];
-                if (dv.is_data_dependence() && dep_dim != -1) {
-                  dv.lbounds[dep_dim] = -posInfinity;
-                  dv.ubounds[dep_dim] = posInfinity;
-                }
-                dvs.push_back(dv);
-              }
-              if (dvs.size() > 0)
-                dep.connect(what_stmt_num[i], j->first, dvs);
-              
-            }
-          } else {
-            if (what_stmt_num.find(i) != what_stmt_num.end())
-              dep.connect(what_stmt_num[i], j->first, j->second);
-          }
-        } else if (same_loop.find(j->first) != same_loop.end()) {
-          if (what_stmt_num.find(j->first) != what_stmt_num.end())
-            D.push_back(
-              std::make_pair(what_stmt_num[j->first],
-                             j->second));
-        }
-      }
-      
-      for (int j = 0; j < D.size(); j++)
-        dep.connect(i, D[j].first, D[j].second);
-    }
-    
-  }
-  
-  return result;
-}
-
-void Loop::skew(const std::set<int> &stmt_nums, int level,
-                const std::vector<int> &skew_amount) {
-  if (stmt_nums.size() == 0)
-    return;
-  
-  // check for sanity of parameters
-  int ref_stmt_num = *(stmt_nums.begin());
-  for (std::set<int>::const_iterator i = stmt_nums.begin();
-       i != stmt_nums.end(); i++) {
-    if (*i < 0 || *i >= stmt.size())
-      throw std::invalid_argument(
-        "invalid statement number " + to_string(*i));
-    if (level < 1 || level > stmt[*i].loop_level.size())
-      throw std::invalid_argument(
-        "invalid loop level " + to_string(level));
-    for (int j = stmt[*i].loop_level.size(); j < skew_amount.size(); j++)
-      if (skew_amount[j] != 0)
-        throw std::invalid_argument("invalid skewing formula");
-  }
-  
-  // invalidate saved codegen computation
-  delete last_compute_cgr_;
-  last_compute_cgr_ = NULL;
-  delete last_compute_cg_;
-  last_compute_cg_ = NULL;
-  
-  // set trasformation relations
-  for (std::set<int>::const_iterator i = stmt_nums.begin();
-       i != stmt_nums.end(); i++) {
-    int n = stmt[*i].xform.n_out();
-    Relation r(n, n);
-    F_And *f_root = r.add_and();
-    for (int j = 1; j <= n; j++)
-      if (j != 2 * level) {
-        EQ_Handle h = f_root->add_EQ();
-        h.update_coef(r.input_var(j), 1);
-        h.update_coef(r.output_var(j), -1);
-      }
-    EQ_Handle h = f_root->add_EQ();
-    h.update_coef(r.output_var(2 * level), -1);
-    for (int j = 0; j < skew_amount.size(); j++)
-      if (skew_amount[j] != 0)
-        h.update_coef(r.input_var(2 * (j + 1)), skew_amount[j]);
-    
-    stmt[*i].xform = Composition(r, stmt[*i].xform);
-    stmt[*i].xform.simplify();
-  }
-  
-  // update dependence graph
-  if (stmt[ref_stmt_num].loop_level[level - 1].type == LoopLevelOriginal) {
-    int dep_dim = stmt[ref_stmt_num].loop_level[level - 1].payload;
-    for (std::set<int>::const_iterator i = stmt_nums.begin();
-         i != stmt_nums.end(); i++)
-      for (DependenceGraph::EdgeList::iterator j =
-             dep.vertex[*i].second.begin();
-           j != dep.vertex[*i].second.end(); j++)
-        if (stmt_nums.find(j->first) != stmt_nums.end()) {
-          // dependence between skewed statements
-          std::vector<DependenceVector> dvs = j->second;
-          for (int k = 0; k < dvs.size(); k++) {
-            DependenceVector &dv = dvs[k];
-            if (dv.is_data_dependence()) {
-              coef_t lb = 0;
-              coef_t ub = 0;
-              for (int kk = 0; kk < skew_amount.size(); kk++) {
-                int cur_dep_dim = get_dep_dim_of(*i, kk + 1);
-                if (skew_amount[kk] > 0) {
-                  if (lb != -posInfinity
-                      && stmt[*i].loop_level[kk].type
-                      == LoopLevelOriginal
-                      && dv.lbounds[cur_dep_dim]
-                      != -posInfinity)
-                    lb += skew_amount[kk]
-                      * dv.lbounds[cur_dep_dim];
-                  else {
-                    if (cur_dep_dim != -1
-                        && !(dv.lbounds[cur_dep_dim]
-                             == 0
-                             && dv.ubounds[cur_dep_dim]
-                             == 0))
-                      lb = -posInfinity;
-                  }
-                  if (ub != posInfinity
-                      && stmt[*i].loop_level[kk].type
-                      == LoopLevelOriginal
-                      && dv.ubounds[cur_dep_dim]
-                      != posInfinity)
-                    ub += skew_amount[kk]
-                      * dv.ubounds[cur_dep_dim];
-                  else {
-                    if (cur_dep_dim != -1
-                        && !(dv.lbounds[cur_dep_dim]
-                             == 0
-                             && dv.ubounds[cur_dep_dim]
-                             == 0))
-                      ub = posInfinity;
-                  }
-                } else if (skew_amount[kk] < 0) {
-                  if (lb != -posInfinity
-                      && stmt[*i].loop_level[kk].type
-                      == LoopLevelOriginal
-                      && dv.ubounds[cur_dep_dim]
-                      != posInfinity)
-                    lb += skew_amount[kk]
-                      * dv.ubounds[cur_dep_dim];
-                  else {
-                    if (cur_dep_dim != -1
-                        && !(dv.lbounds[cur_dep_dim]
-                             == 0
-                             && dv.ubounds[cur_dep_dim]
-                             == 0))
-                      lb = -posInfinity;
-                  }
-                  if (ub != posInfinity
-                      && stmt[*i].loop_level[kk].type
-                      == LoopLevelOriginal
-                      && dv.lbounds[cur_dep_dim]
-                      != -posInfinity)
-                    ub += skew_amount[kk]
-                      * dv.lbounds[cur_dep_dim];
-                  else {
-                    if (cur_dep_dim != -1
-                        && !(dv.lbounds[cur_dep_dim]
-                             == 0
-                             && dv.ubounds[cur_dep_dim]
-                             == 0))
-                      ub = posInfinity;
-                  }
-                }
-              }
-              dv.lbounds[dep_dim] = lb;
-              dv.ubounds[dep_dim] = ub;
-              if ((dv.isCarried(dep_dim)
-                   && dv.hasPositive(dep_dim)) && dv.quasi)
-                dv.quasi = false;
-              
-              if ((dv.isCarried(dep_dim)
-                   && dv.hasNegative(dep_dim)) && !dv.quasi)
-                throw loop_error(
-                  "loop error: Skewing is illegal, dependence violation!");
-              dv.lbounds[dep_dim] = lb;
-              dv.ubounds[dep_dim] = ub;
-              if ((dv.isCarried(dep_dim)
-                   && dv.hasPositive(dep_dim)) && dv.quasi)
-                dv.quasi = false;
-              
-              if ((dv.isCarried(dep_dim)
-                   && dv.hasNegative(dep_dim)) && !dv.quasi)
-                throw loop_error(
-                  "loop error: Skewing is illegal, dependence violation!");
-            }
-          }
-          j->second = dvs;
-        } else {
-          // dependence from skewed statement to unskewed statement becomes jumbled,
-          // put distance value at skewed dimension to unknown
-          std::vector<DependenceVector> dvs = j->second;
-          for (int k = 0; k < dvs.size(); k++) {
-            DependenceVector &dv = dvs[k];
-            if (dv.is_data_dependence()) {
-              dv.lbounds[dep_dim] = -posInfinity;
-              dv.ubounds[dep_dim] = posInfinity;
-            }
-          }
-          j->second = dvs;
-        }
-    for (int i = 0; i < dep.vertex.size(); i++)
-      if (stmt_nums.find(i) == stmt_nums.end())
-        for (DependenceGraph::EdgeList::iterator j =
-               dep.vertex[i].second.begin();
-             j != dep.vertex[i].second.end(); j++)
-          if (stmt_nums.find(j->first) != stmt_nums.end()) {
-            // dependence from unskewed statement to skewed statement becomes jumbled,
-            // put distance value at skewed dimension to unknown
-            std::vector<DependenceVector> dvs = j->second;
-            for (int k = 0; k < dvs.size(); k++) {
-              DependenceVector &dv = dvs[k];
-              if (dv.is_data_dependence()) {
-                dv.lbounds[dep_dim] = -posInfinity;
-                dv.ubounds[dep_dim] = posInfinity;
-              }
-            }
-            j->second = dvs;
-          }
-  }
-}
-
-
-void Loop::shift(const std::set<int> &stmt_nums, int level, int shift_amount) {
-  if (stmt_nums.size() == 0)
-    return;
-  
-  // check for sanity of parameters
-  int ref_stmt_num = *(stmt_nums.begin());
-  for (std::set<int>::const_iterator i = stmt_nums.begin();
-       i != stmt_nums.end(); i++) {
-    if (*i < 0 || *i >= stmt.size())
-      throw std::invalid_argument(
-        "invalid statement number " + to_string(*i));
-    if (level < 1 || level > stmt[*i].loop_level.size())
-      throw std::invalid_argument(
-        "invalid loop level " + to_string(level));
-  }
-  
-  // do nothing
-  if (shift_amount == 0)
-    return;
-  
-  // invalidate saved codegen computation
-  delete last_compute_cgr_;
-  last_compute_cgr_ = NULL;
-  delete last_compute_cg_;
-  last_compute_cg_ = NULL;
-  
-  // set trasformation relations
-  for (std::set<int>::const_iterator i = stmt_nums.begin();
-       i != stmt_nums.end(); i++) {
-    int n = stmt[*i].xform.n_out();
-    
-    Relation r(n, n);
-    F_And *f_root = r.add_and();
-    for (int j = 1; j <= n; j++) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(r.input_var(j), 1);
-      h.update_coef(r.output_var(j), -1);
-      if (j == 2 * level)
-        h.update_const(shift_amount);
-    }
-    
-    stmt[*i].xform = Composition(r, stmt[*i].xform);
-    stmt[*i].xform.simplify();
-  }
-  
-  // update dependence graph
-  if (stmt[ref_stmt_num].loop_level[level - 1].type == LoopLevelOriginal) {
-    int dep_dim = stmt[ref_stmt_num].loop_level[level - 1].payload;
-    for (std::set<int>::const_iterator i = stmt_nums.begin();
-         i != stmt_nums.end(); i++)
-      for (DependenceGraph::EdgeList::iterator j =
-             dep.vertex[*i].second.begin();
-           j != dep.vertex[*i].second.end(); j++)
-        if (stmt_nums.find(j->first) == stmt_nums.end()) {
-          // dependence from shifted statement to unshifted statement
-          std::vector<DependenceVector> dvs = j->second;
-          for (int k = 0; k < dvs.size(); k++) {
-            DependenceVector &dv = dvs[k];
-            if (dv.is_data_dependence()) {
-              if (dv.lbounds[dep_dim] != -posInfinity)
-                dv.lbounds[dep_dim] -= shift_amount;
-              if (dv.ubounds[dep_dim] != posInfinity)
-                dv.ubounds[dep_dim] -= shift_amount;
-            }
-          }
-          j->second = dvs;
-        }
-    for (int i = 0; i < dep.vertex.size(); i++)
-      if (stmt_nums.find(i) == stmt_nums.end())
-        for (DependenceGraph::EdgeList::iterator j =
-               dep.vertex[i].second.begin();
-             j != dep.vertex[i].second.end(); j++)
-          if (stmt_nums.find(j->first) != stmt_nums.end()) {
-            // dependence from unshifted statement to shifted statement
-            std::vector<DependenceVector> dvs = j->second;
-            for (int k = 0; k < dvs.size(); k++) {
-              DependenceVector &dv = dvs[k];
-              if (dv.is_data_dependence()) {
-                if (dv.lbounds[dep_dim] != -posInfinity)
-                  dv.lbounds[dep_dim] += shift_amount;
-                if (dv.ubounds[dep_dim] != posInfinity)
-                  dv.ubounds[dep_dim] += shift_amount;
-              }
-            }
-            j->second = dvs;
-          }
-  }
-}
-
-void Loop::scale(const std::set<int> &stmt_nums, int level, int scale_amount) {
-  std::vector<int> skew_amount(level, 0);
-  skew_amount[level - 1] = scale_amount;
-  skew(stmt_nums, level, skew_amount);
-}
-
-void Loop::reverse(const std::set<int> &stmt_nums, int level) {
-  scale(stmt_nums, level, -1);
-}
-
-void Loop::fuse(const std::set<int> &stmt_nums, int level) {
-  if (stmt_nums.size() == 0 || stmt_nums.size() == 1)
-    return;
-  
-  // invalidate saved codegen computation
-  delete last_compute_cgr_;
-  last_compute_cgr_ = NULL;
-  delete last_compute_cg_;
-  last_compute_cg_ = NULL;
-  
-  int dim = 2 * level - 1;
-  // check for sanity of parameters
-  std::vector<int> ref_lex;
-  int ref_stmt_num;
-  for (std::set<int>::const_iterator i = stmt_nums.begin();
-       i != stmt_nums.end(); i++) {
-    if (*i < 0 || *i >= stmt.size())
-      throw std::invalid_argument(
-        "invalid statement number " + to_string(*i));
-    if (level <= 0
-        || (level > (stmt[*i].xform.n_out() - 1) / 2
-            || level > stmt[*i].loop_level.size()))
-      throw std::invalid_argument(
-        "invalid loop level " + to_string(level));
-    if (ref_lex.size() == 0) {
-      ref_lex = getLexicalOrder(*i);
-      ref_stmt_num = *i;
-    } else {
-      std::vector<int> lex = getLexicalOrder(*i);
-      for (int j = 0; j < dim - 1; j += 2)
-        if (lex[j] != ref_lex[j])
-          throw std::invalid_argument(
-            "statements for fusion must be in the same level-"
-            + to_string(level - 1) + " subloop");
-    }
-  }
-  
-  // collect lexicographical order values from to-be-fused statements
-  std::set<int> lex_values;
-  for (std::set<int>::const_iterator i = stmt_nums.begin();
-       i != stmt_nums.end(); i++) {
-    std::vector<int> lex = getLexicalOrder(*i);
-    lex_values.insert(lex[dim - 1]);
-  }
-  if (lex_values.size() == 1)
-    return;
-  // negative dependence would prevent fusion
-  
-  int dep_dim = get_dep_dim_of(ref_stmt_num, level);
-  
-  for (std::set<int>::iterator i = lex_values.begin(); i != lex_values.end();
-       i++) {
-    ref_lex[dim - 1] = *i;
-    std::set<int> a = getStatements(ref_lex, dim - 1);
-    std::set<int>::iterator j = i;
-    j++;
-    for (; j != lex_values.end(); j++) {
-      ref_lex[dim - 1] = *j;
-      std::set<int> b = getStatements(ref_lex, dim - 1);
-      for (std::set<int>::iterator ii = a.begin(); ii != a.end(); ii++)
-        for (std::set<int>::iterator jj = b.begin(); jj != b.end();
-             jj++) {
-          std::vector<DependenceVector> dvs;
-          dvs = dep.getEdge(*ii, *jj);
-          for (int k = 0; k < dvs.size(); k++)
-            if (dvs[k].isCarried(dep_dim)
-                && dvs[k].hasNegative(dep_dim))
-              throw loop_error(
-                "loop error: statements " + to_string(*ii)
-                + " and " + to_string(*jj)
-                + " cannot be fused together due to negative dependence");
-          dvs = dep.getEdge(*jj, *ii);
-          for (int k = 0; k < dvs.size(); k++)
-            if (dvs[k].isCarried(dep_dim)
-                && dvs[k].hasNegative(dep_dim))
-              throw loop_error(
-                "loop error: statements " + to_string(*jj)
-                + " and " + to_string(*ii)
-                + " cannot be fused together due to negative dependence");
-        }
-    }
-  }
-  
-  std::set<int> same_loop = getStatements(ref_lex, dim - 3);
-  
-  std::vector<std::set<int> > s = sort_by_same_loops(same_loop, level);
-  
-  std::set<int> s1;
-  std::set<int> s2;
-  std::set<int> s4;
-  std::vector<std::set<int> > s3;
-  for (std::set<int>::iterator kk = stmt_nums.begin(); kk != stmt_nums.end();
-       kk++)
-    for (int i = 0; i < s.size(); i++)
-      if (s[i].find(*kk) != s[i].end()) {
-        s1.insert(s[i].begin(), s[i].end());
-        s2.insert(i);
-      }
-  
-  s3.push_back(s1);
-  for (int i = 0; i < s.size(); i++)
-    if (s2.find(i) == s2.end()) {
-      s3.push_back(s[i]);
-      s4.insert(s[i].begin(), s[i].end());
-    }
-  try {
-    std::vector<std::set<int> > s5;
-    s5.push_back(s1);
-    s5.push_back(s4);
-    
-    //Dependence Check for Ordering Constraint
-    //Graph<std::set<int>, bool> dummy = construct_induced_graph_at_level(s5,
-    //      dep, dep_dim);
-    
-    Graph<std::set<int>, bool> g = construct_induced_graph_at_level(s3, dep,
-                                                                    dep_dim);
-    
-    s = typed_fusion(g);
-  } catch (const loop_error &e) {
-    
-    throw loop_error(
-      "statements cannot be fused together due to negative dependence");
-    
-  }
-  
-  if (s3.size() == s.size()) {
-    int order = 0;
-    for (int i = 0; i < s.size(); i++) {
-      
-      for (std::set<int>::iterator it = s[i].begin(); it != s[i].end();
-           it++) {
-        
-        assign_const(stmt[*it].xform, 2 * level - 2, order);
-        
-      }
-      
-      order++;
-    }
-  } else if (s3.size() > s.size()) {
-    
-    int order = 0;
-    for (int j = 0; j < s.size(); j++) {
-      std::set<int>::iterator it3;
-      for (it3 = s1.begin(); it3 != s1.end(); it3++) {
-        if (s[j].find(*it3) != s[j].end())
-          break;
-      }
-      if (it3 != s1.end()) {
-        for (std::set<int>::iterator it = s1.begin(); it != s1.end();
-             it++)
-          assign_const(stmt[*it].xform, 2 * level - 2, order);
-        
-        order++;
-        
-      }
-      
-      for (int i = 0; i < s3.size(); i++) {
-        std::set<int>::iterator it2;
-        
-        for (it2 = s3[i].begin(); it2 != s3[i].end(); it2++) {
-          if (s[j].find(*it2) != s[j].end())
-            break;
-        }
-        
-        if (it2 != s3[i].end()) {
-          for (std::set<int>::iterator it = s3[i].begin();
-               it != s3[i].end(); it++)
-            assign_const(stmt[*it].xform, 2 * level - 2, order);
-          
-          order++;
-          
-        }
-      }
-    }
-    
-  } else
-    throw loop_error("Typed Fusion Error");
-  
-}
-
-
-
-void Loop::distribute(const std::set<int> &stmt_nums, int level) {
-  if (stmt_nums.size() == 0 || stmt_nums.size() == 1)
-    return;
-  
-  // invalidate saved codegen computation
-  delete last_compute_cgr_;
-  last_compute_cgr_ = NULL;
-  delete last_compute_cg_;
-  last_compute_cg_ = NULL;
-  int dim = 2 * level - 1;
-  int ref_stmt_num;
-  // check for sanity of parameters
-  std::vector<int> ref_lex;
-  for (std::set<int>::const_iterator i = stmt_nums.begin();
-       i != stmt_nums.end(); i++) {
-    if (*i < 0 || *i >= stmt.size())
-      throw std::invalid_argument(
-        "invalid statement number " + to_string(*i));
-    if (level < 1
-        || (level > (stmt[*i].xform.n_out() - 1) / 2
-            || level > stmt[*i].loop_level.size()))
-      throw std::invalid_argument(
-        "invalid loop level " + to_string(level));
-    if (ref_lex.size() == 0) {
-      ref_lex = getLexicalOrder(*i);
-      ref_stmt_num = *i;
-    } else {
-      std::vector<int> lex = getLexicalOrder(*i);
-      for (int j = 0; j <= dim - 1; j += 2)
-        if (lex[j] != ref_lex[j])
-          throw std::invalid_argument(
-            "statements for distribution must be in the same level-"
-            + to_string(level) + " subloop");
-    }
-  }
-  // find SCC in the to-be-distributed loop
-  int dep_dim = get_dep_dim_of(ref_stmt_num, level);
-  std::set<int> same_loop = getStatements(ref_lex, dim - 1);
-  Graph<int, Empty> g;
-  for (std::set<int>::iterator i = same_loop.begin(); i != same_loop.end();
-       i++)
-    g.insert(*i);
-  for (int i = 0; i < g.vertex.size(); i++)
-    for (int j = i + 1; j < g.vertex.size(); j++) {
-      std::vector<DependenceVector> dvs;
-      dvs = dep.getEdge(g.vertex[i].first, g.vertex[j].first);
-      for (int k = 0; k < dvs.size(); k++)
-        if (dvs[k].isCarried(dep_dim)) {
-          g.connect(i, j);
-          break;
-        }
-      dvs = dep.getEdge(g.vertex[j].first, g.vertex[i].first);
-      for (int k = 0; k < dvs.size(); k++)
-        if (dvs[k].isCarried(dep_dim)) {
-          g.connect(j, i);
-          break;
-        }
-    }
-  std::vector<std::set<int> > s = g.topoSort();
-  // find statements that cannot be distributed due to dependence cycle
-  Graph<std::set<int>, Empty> g2;
-  for (int i = 0; i < s.size(); i++) {
-    std::set<int> t;
-    for (std::set<int>::iterator j = s[i].begin(); j != s[i].end(); j++)
-      if (stmt_nums.find(g.vertex[*j].first) != stmt_nums.end())
-        t.insert(g.vertex[*j].first);
-    if (!t.empty())
-      g2.insert(t);
-  }
-  for (int i = 0; i < g2.vertex.size(); i++)
-    for (int j = i + 1; j < g2.vertex.size(); j++)
-      for (std::set<int>::iterator ii = g2.vertex[i].first.begin();
-           ii != g2.vertex[i].first.end(); ii++)
-        for (std::set<int>::iterator jj = g2.vertex[j].first.begin();
-             jj != g2.vertex[j].first.end(); jj++) {
-          std::vector<DependenceVector> dvs;
-          dvs = dep.getEdge(*ii, *jj);
-          for (int k = 0; k < dvs.size(); k++)
-            if (dvs[k].isCarried(dep_dim)) {
-              g2.connect(i, j);
-              break;
-            }
-          dvs = dep.getEdge(*jj, *ii);
-          for (int k = 0; k < dvs.size(); k++)
-            if (dvs[k].isCarried(dep_dim)) {
-              g2.connect(j, i);
-              break;
-            }
-        }
-  std::vector<std::set<int> > s2 = g2.topoSort();
-  // nothing to distribute
-  if (s2.size() == 1)
-    throw loop_error(
-      "loop error: no statement can be distributed due to dependence cycle");
-  std::vector<std::set<int> > s3;
-  for (int i = 0; i < s2.size(); i++) {
-    std::set<int> t;
-    for (std::set<int>::iterator j = s2[i].begin(); j != s2[i].end(); j++)
-      std::set_union(t.begin(), t.end(), g2.vertex[*j].first.begin(),
-                     g2.vertex[*j].first.end(), inserter(t, t.begin()));
-    s3.push_back(t);
-  }
-  // associate other affected statements with the right distributed statements
-  for (std::set<int>::iterator i = same_loop.begin(); i != same_loop.end();
-       i++)
-    if (stmt_nums.find(*i) == stmt_nums.end()) {
-      bool is_inserted = false;
-      int potential_insertion_point = 0;
-      for (int j = 0; j < s3.size(); j++) {
-        for (std::set<int>::iterator k = s3[j].begin();
-             k != s3[j].end(); k++) {
-          std::vector<DependenceVector> dvs;
-          dvs = dep.getEdge(*i, *k);
-          for (int kk = 0; kk < dvs.size(); kk++)
-            if (dvs[kk].isCarried(dep_dim)) {
-              s3[j].insert(*i);
-              is_inserted = true;
-              break;
-            }
-          dvs = dep.getEdge(*k, *i);
-          for (int kk = 0; kk < dvs.size(); kk++)
-            if (dvs[kk].isCarried(dep_dim))
-              potential_insertion_point = j;
-        }
-        if (is_inserted)
-          break;
-      }
-      if (!is_inserted)
-        s3[potential_insertion_point].insert(*i);
-    }
-  // set lexicographical order after distribution
-  int order = ref_lex[dim - 1];
-  shiftLexicalOrder(ref_lex, dim - 1, s3.size() - 1);
-  for (std::vector<std::set<int> >::iterator i = s3.begin(); i != s3.end();
-       i++) {
-    for (std::set<int>::iterator j = (*i).begin(); j != (*i).end(); j++)
-      assign_const(stmt[*j].xform, dim - 1, order);
-    order++;
-  }
-  // no need to update dependence graph
-  ;
-  return;
-}
-
diff --git a/chill/src/loop_datacopy.cc b/chill/src/loop_datacopy.cc
deleted file mode 100644
index 8d11b0a..0000000
--- a/chill/src/loop_datacopy.cc
+++ /dev/null
@@ -1,2166 +0,0 @@
-/*****************************************************************************
- Copyright (C) 2008 University of Southern California
- Copyright (C) 2009-2010 University of Utah
- All Rights Reserved.
-
- Purpose:
-   Various data copy schemes.
-
- Notes:
-
- History:
-   02/20/09 Created by Chun Chen by splitting original datacopy from loop.cc
-*****************************************************************************/
-
-#include <code_gen/codegen.h>
-#include <code_gen/CG_utils.h>
-#include "loop.hh"
-#include "omegatools.hh"
-#include "ir_code.hh"
-#include "chill_error.hh"
-
-using namespace omega;
-
-//
-// data copy function by referring arrays by numbers.
-// e.g. A[i] = A[i-1] + B[i]
-//      parameter array_ref_num=[0,2] means to copy data touched by A[i-1] and A[i]
-//
-bool Loop::datacopy(const std::vector<std::pair<int, std::vector<int> > > &array_ref_nums, int level,
-                    bool allow_extra_read, int fastest_changing_dimension, int padding_stride, int padding_alignment, int memory_type) {
-  // check for sanity of parameters
-  std::set<int> same_loop;
-  for (int i = 0; i < array_ref_nums.size(); i++) {
-    int stmt_num = array_ref_nums[i].first;
-    if (stmt_num < 0 || stmt_num >= stmt.size())
-      throw std::invalid_argument("invalid statement number " + to_string(stmt_num));
-    if (level <= 0 || level > stmt[stmt_num].loop_level.size())
-      throw std::invalid_argument("invalid loop level " + to_string(level));
-    if (i == 0) {
-      std::vector<int> lex = getLexicalOrder(stmt_num);
-      same_loop = getStatements(lex, 2*level-2);
-    }
-    else if (same_loop.find(stmt_num) == same_loop.end())
-      throw std::invalid_argument("array references for data copy must be located in the same subloop");
-  }
-  
-  // convert array reference numbering scheme to actual array references
-  std::vector<std::pair<int, std::vector<IR_ArrayRef *> > > selected_refs;
-  for (int i = 0; i < array_ref_nums.size(); i++) {
-    if (array_ref_nums[i].second.size() == 0)
-      continue;
-    
-    int stmt_num = array_ref_nums[i].first;
-    selected_refs.push_back(std::make_pair(stmt_num, std::vector<IR_ArrayRef *>()));
-    std::vector<IR_ArrayRef *> refs = ir->FindArrayRef(stmt[stmt_num].code);
-    std::vector<bool> selected(refs.size(), false);
-    for (int j = 0; j < array_ref_nums[i].second.size(); j++) {
-      int ref_num = array_ref_nums[i].second[j];
-      if (ref_num < 0 || ref_num >= refs.size()) {
-        for (int k = 0; k < refs.size(); k++)
-          delete refs[k];
-        throw std::invalid_argument("invalid array reference number " + to_string(ref_num) + " in statement " + to_string(stmt_num));
-      }
-      selected_refs[selected_refs.size()-1].second.push_back(refs[ref_num]);
-      selected[ref_num] = true;
-    }
-    for (int j = 0; j < refs.size(); j++)
-      if (!selected[j])
-        delete refs[j];
-  }
-  if (selected_refs.size() == 0)
-    throw std::invalid_argument("found no array references to copy");
-  
-  // do the copy
-  return datacopy_privatized(selected_refs, level, std::vector<int>(), allow_extra_read, fastest_changing_dimension, padding_stride, padding_alignment, memory_type);
-}
-
-//
-// data copy function by referring arrays by name.
-// e.g. A[i] = A[i-1] + B[i]
-//      parameter array_name=A means to copy data touched by A[i-1] and A[i]
-//
-bool Loop::datacopy(int stmt_num, int level, const std::string &array_name,
-                    bool allow_extra_read, int fastest_changing_dimension, int padding_stride, int padding_alignment, int memory_type) {
-  // check for sanity of parameters
-  if (stmt_num < 0 || stmt_num >= stmt.size())
-    throw std::invalid_argument("invalid statement number " + to_string(stmt_num));
-  if (level <= 0 || level > stmt[stmt_num].loop_level.size())
-    throw std::invalid_argument("invalid loop level " + to_string(level));
-  
-  // collect array references by name
-  std::vector<int> lex = getLexicalOrder(stmt_num);
-  int dim = 2*level - 1;
-  std::set<int> same_loop = getStatements(lex, dim-1);
-  
-  std::vector<std::pair<int, std::vector<IR_ArrayRef *> > > selected_refs;
-  for (std::set<int>::iterator i = same_loop.begin(); i != same_loop.end(); i++) {
-    std::vector<IR_ArrayRef *> t;
-    std::vector<IR_ArrayRef *> refs = ir->FindArrayRef(stmt[*i].code);  
-    for (int j = 0; j < refs.size(); j++)
-      if (refs[j]->name() == array_name)
-        t.push_back(refs[j]);
-      else
-        delete refs[j];
-    if (t.size() != 0)
-      selected_refs.push_back(std::make_pair(*i, t)); 
-  }
-  if (selected_refs.size() == 0)
-    throw std::invalid_argument("found no array references with name " + to_string(array_name) + " to copy");
-  
-  // do the copy
-  return datacopy_privatized(selected_refs, level, std::vector<int>(), allow_extra_read, fastest_changing_dimension, padding_stride, padding_alignment, memory_type);
-}
-
-
-bool Loop::datacopy_privatized(int stmt_num, int level, const std::string &array_name, const std::vector<int> &privatized_levels,
-                               bool allow_extra_read, int fastest_changing_dimension, int padding_stride, int padding_alignment, int memory_type) {
-  // check for sanity of parameters
-  if (stmt_num < 0 || stmt_num >= stmt.size())
-    throw std::invalid_argument("invalid statement number " + to_string(stmt_num));
-  if (level <= 0 || level > stmt[stmt_num].loop_level.size())
-    throw std::invalid_argument("invalid loop level " + to_string(level));
-  
-  // collect array references by name
-  std::vector<int> lex = getLexicalOrder(stmt_num);
-  int dim = 2*level - 1;
-  std::set<int> same_loop = getStatements(lex, dim-1);
-  
-  std::vector<std::pair<int, std::vector<IR_ArrayRef *> > > selected_refs;
-  for (std::set<int>::iterator i = same_loop.begin(); i != same_loop.end(); i++) {
-    selected_refs.push_back(std::make_pair(*i, std::vector<IR_ArrayRef *>()));
-    
-    std::vector<IR_ArrayRef *> refs = ir->FindArrayRef(stmt[*i].code);  
-    for (int j = 0; j < refs.size(); j++)
-      if (refs[j]->name() == array_name)
-        selected_refs[selected_refs.size()-1].second.push_back(refs[j]);
-      else
-        delete refs[j];
-  }
-  if (selected_refs.size() == 0)
-    throw std::invalid_argument("found no array references with name " + to_string(array_name) + " to copy");
-  
-  // do the copy
-  return datacopy_privatized(selected_refs, level, privatized_levels, allow_extra_read, fastest_changing_dimension, padding_stride, padding_alignment, memory_type);
-}
-
-
-bool Loop::datacopy_privatized(const std::vector<std::pair<int, std::vector<int> > > &array_ref_nums, int level, const std::vector<int> &privatized_levels, bool allow_extra_read, int fastest_changing_dimension, int padding_stride, int padding_alignment, int memory_type) {
-  // check for sanity of parameters
-  std::set<int> same_loop;
-  for (int i = 0; i < array_ref_nums.size(); i++) {
-    int stmt_num = array_ref_nums[i].first;
-    if (stmt_num < 0 || stmt_num >= stmt.size())
-      throw std::invalid_argument("invalid statement number " + to_string(stmt_num));
-    if (level <= 0 || level > stmt[stmt_num].loop_level.size())
-      throw std::invalid_argument("invalid loop level " + to_string(level));
-    if (i == 0) {
-      std::vector<int> lex = getLexicalOrder(stmt_num);
-      same_loop = getStatements(lex, 2*level-2);
-    }
-    else if (same_loop.find(stmt_num) == same_loop.end())
-      throw std::invalid_argument("array references for data copy must be located in the same subloop");
-  }
-  
-  // convert array reference numbering scheme to actual array references
-  std::vector<std::pair<int, std::vector<IR_ArrayRef *> > > selected_refs;
-  for (int i = 0; i < array_ref_nums.size(); i++) {
-    if (array_ref_nums[i].second.size() == 0)
-      continue;
-    
-    int stmt_num = array_ref_nums[i].first;
-    selected_refs.push_back(std::make_pair(stmt_num, std::vector<IR_ArrayRef *>()));
-    std::vector<IR_ArrayRef *> refs = ir->FindArrayRef(stmt[stmt_num].code);
-    std::vector<bool> selected(refs.size(), false);
-    for (int j = 0; j < array_ref_nums[i].second.size(); j++) {
-      int ref_num = array_ref_nums[i].second[j];
-      if (ref_num < 0 || ref_num >= refs.size()) {
-        for (int k = 0; k < refs.size(); k++)
-          delete refs[k];
-        throw std::invalid_argument("invalid array reference number " + to_string(ref_num) + " in statement " + to_string(stmt_num));
-      }
-      selected_refs[selected_refs.size()-1].second.push_back(refs[ref_num]);
-      selected[ref_num] = true;
-    }
-    for (int j = 0; j < refs.size(); j++)
-      if (!selected[j])
-        delete refs[j];
-  }
-  if (selected_refs.size() == 0)
-    throw std::invalid_argument("found no array references to copy");
-  
-  // do the copy
-  return datacopy_privatized(selected_refs, level, privatized_levels, allow_extra_read, fastest_changing_dimension, padding_stride, padding_alignment, memory_type);
-}
-
-
-//
-// Implement low level datacopy function with lots of options.
-//
-/*bool Loop::datacopy_privatized(const std::vector<std::pair<int, std::vector<IR_ArrayRef *> > > &stmt_refs, int level,
-  const std::vector<int> &privatized_levels,
-  bool allow_extra_read, int fastest_changing_dimension,
-  int padding_stride, int padding_alignment, int memory_type) {
-  if (stmt_refs.size() == 0)
-  return true;
-  
-  // check for sanity of parameters
-  IR_ArraySymbol *sym = NULL;
-  std::vector<int> lex;
-  std::set<int> active;
-  if (level <= 0)
-  throw std::invalid_argument("invalid loop level " + to_string(level));
-  for (int i = 0; i < privatized_levels.size(); i++) {
-  if (i == 0) {
-  if (privatized_levels[i] < level)
-  throw std::invalid_argument("privatized loop levels must be no less than level " + to_string(level));
-  }
-  else if (privatized_levels[i] <= privatized_levels[i-1])
-  throw std::invalid_argument("privatized loop levels must be in ascending order");
-  }
-  for (int i = 0; i < stmt_refs.size(); i++) {
-  int stmt_num = stmt_refs[i].first;
-  active.insert(stmt_num);
-  if (stmt_num < 0 || stmt_num >= stmt.size())
-  throw std::invalid_argument("invalid statement number " + to_string(stmt_num));
-  if (privatized_levels.size() != 0) {
-  if (privatized_levels[privatized_levels.size()-1] > stmt[stmt_num].loop_level.size())
-  throw std::invalid_argument("invalid loop level " + to_string(privatized_levels[privatized_levels.size()-1]) + " for statement " + to_string(stmt_num));
-  }
-  else {
-  if (level > stmt[stmt_num].loop_level.size())
-  throw std::invalid_argument("invalid loop level " + to_string(level) + " for statement " + to_string(stmt_num));
-  }
-  for (int j = 0; j < stmt_refs[i].second.size(); j++) {
-  if (sym == NULL) {
-  sym = stmt_refs[i].second[j]->symbol();
-  lex = getLexicalOrder(stmt_num);
-  }
-  else {
-  IR_ArraySymbol *t = stmt_refs[i].second[j]->symbol();
-  if (t->name() != sym->name()) {
-  delete t;
-  delete sym;
-  throw std::invalid_argument("try to copy data from different arrays");
-  }
-  delete t;
-  }
-  }
-  }
-  if (!(fastest_changing_dimension >= -1 && fastest_changing_dimension < sym->n_dim()))
-  throw std::invalid_argument("invalid fastest changing dimension for the array to be copied");
-  if (padding_stride < 0)
-  throw std::invalid_argument("invalid temporary array stride requirement");
-  if (padding_alignment == -1 || padding_alignment == 0)
-  throw std::invalid_argument("invalid temporary array alignment requirement");
-  
-  int dim = 2*level - 1;
-  int n_dim = sym->n_dim();
-  
-  if (fastest_changing_dimension == -1)
-  switch (sym->layout_type()) {
-  case IR_ARRAY_LAYOUT_ROW_MAJOR:
-  fastest_changing_dimension = n_dim - 1;
-  break;
-  case IR_ARRAY_LAYOUT_COLUMN_MAJOR:
-  fastest_changing_dimension = 0;
-  break;
-  default:
-  throw loop_error("unsupported array layout");
-  }
-  
-  
-  // build iteration spaces for all reads and for all writes separately
-  apply_xform(active);
-  bool has_write_refs = false;
-  bool has_read_refs = false;
-  Relation wo_copy_is = Relation::False(level-1+privatized_levels.size()+n_dim);
-  Relation ro_copy_is = Relation::False(level-1+privatized_levels.size()+n_dim);
-  for (int i = 0; i < stmt_refs.size(); i++) {
-  int stmt_num = stmt_refs[i].first;
-  
-  for (int j = 0; j < stmt_refs[i].second.size(); j++) {
-  Relation mapping(stmt[stmt_num].IS.n_set(), level-1+privatized_levels.size()+n_dim);
-  for (int k = 1; k <= mapping.n_inp(); k++)
-  mapping.name_input_var(k, stmt[stmt_num].IS.set_var(k)->name());
-  mapping.setup_names();
-  F_And *f_root = mapping.add_and();
-  for (int k = 1; k <= level-1; k++) {
-  EQ_Handle h = f_root->add_EQ();
-  h.update_coef(mapping.input_var(k), 1);
-  h.update_coef(mapping.output_var(k), -1);
-  }
-  for (int k = 0; k < privatized_levels.size(); k++) {
-  EQ_Handle h = f_root->add_EQ();
-  h.update_coef(mapping.input_var(privatized_levels[k]), 1);
-  h.update_coef(mapping.output_var(level+k), -1);
-  }
-  for (int k = 0; k < n_dim; k++) {
-  CG_outputRepr *repr = stmt_refs[i].second[j]->index(k);
-  exp2formula(ir, mapping, f_root, freevar, repr, mapping.output_var(level-1+privatized_levels.size()+k+1), 'w', IR_COND_EQ, false);
-  repr->clear();
-  delete repr;
-  }
-  Relation r = Range(Restrict_Domain(mapping, Intersection(copy(stmt[stmt_num].IS), Extend_Set(copy(this->known), stmt[stmt_num].IS.n_set() - this->known.n_set()))));
-  if (stmt_refs[i].second[j]->is_write()) {
-  has_write_refs = true;
-  wo_copy_is = Union(wo_copy_is, r);
-  wo_copy_is.simplify(2, 4);
-  }
-  else {
-  has_read_refs = true;
-  //protonu--removing the next line for now
-  ro_copy_is = Union(ro_copy_is, r);
-  ro_copy_is.simplify(2, 4);
-  //ro_copy_is = ConvexRepresentation(Union(ro_copy_is, r));
-  
-  }
-  }
-  }
-  
-  if (allow_extra_read) {
-  Relation t = DecoupledConvexHull(copy(ro_copy_is));
-  if (t.number_of_conjuncts() > 1)
-  ro_copy_is = RectHull(ro_copy_is);
-  else
-  ro_copy_is = t;
-  }
-  else {
-  Relation t = ConvexRepresentation(copy(ro_copy_is));
-  if (t.number_of_conjuncts() > 1)
-  ro_copy_is = RectHull(ro_copy_is);
-  else
-  ro_copy_is = t;
-  }
-  wo_copy_is = ConvexRepresentation(wo_copy_is);
-  
-  if (allow_extra_read) {
-  Tuple<Relation> Rs;
-  Tuple<int> active;
-  for (DNF_Iterator di(ro_copy_is.query_DNF()); di; di++) {
-  Rs.append(Relation(ro_copy_is, di.curr()));
-  active.append(1);
-  }
-  Relation the_gcs = Relation::True(ro_copy_is.n_set());
-  for (int i = level-1+privatized_levels.size()+1; i <= level-1+privatized_levels.size()+n_dim; i++) {
-  Relation r = greatest_common_step(Rs, active, i, Relation::Null());
-  the_gcs = Intersection(the_gcs, r);
-  }
-  
-  ro_copy_is = Approximate(ro_copy_is);
-  ro_copy_is = ConvexRepresentation(ro_copy_is);
-  ro_copy_is = Intersection(ro_copy_is, the_gcs);
-  ro_copy_is.simplify();
-  }
-  
-  
-  
-  for (int i = 1; i < level; i++) {
-  std::string s = stmt[*active.begin()].IS.input_var(i)->name();
-  wo_copy_is.name_set_var(i, s);
-  ro_copy_is.name_set_var(i, s);
-  }
-  for (int i = 0; i < privatized_levels.size(); i++) {
-  std::string s = stmt[*active.begin()].IS.input_var(privatized_levels[i])->name();
-  wo_copy_is.name_set_var(level+i, s);
-  ro_copy_is.name_set_var(level+i, s);
-  }
-  for (int i = level+privatized_levels.size(); i < level+privatized_levels.size()+n_dim; i++) {
-  std::string s = tmp_loop_var_name_prefix + to_string(tmp_loop_var_name_counter+i-level-privatized_levels.size());
-  wo_copy_is.name_set_var(i, s);
-  ro_copy_is.name_set_var(i, s);
-  }
-  tmp_loop_var_name_counter += n_dim;
-  
-  //protonu--end change
-  
-  wo_copy_is.setup_names();
-  ro_copy_is.setup_names();
-  
-  // build merged iteration space for calculating temporary array size
-  bool already_use_recthull = false;
-  Relation untampered_copy_is = ConvexRepresentation(Union(copy(wo_copy_is), copy(ro_copy_is)));
-  Relation copy_is = untampered_copy_is;
-  if (copy_is.number_of_conjuncts() > 1) {
-  try {
-  copy_is = ConvexHull(copy(untampered_copy_is));
-  }
-  catch (const std::overflow_error &e) {
-  copy_is = RectHull(copy(untampered_copy_is));
-  already_use_recthull = true;
-  }
-  }
-  
-  
-  Retry_copy_is:
-  // extract temporary array information
-  CG_outputBuilder *ocg = ir->builder();
-  std::vector<CG_outputRepr *> index_lb(n_dim); // initialized to NULL
-  std::vector<coef_t> index_stride(n_dim, 1);
-  std::vector<bool> is_index_eq(n_dim, false);
-  std::vector<std::pair<int, CG_outputRepr *> > index_sz(0);  
-  Relation reduced_copy_is = copy(copy_is);
-  
-  for (int i = 0; i < n_dim; i++) {
-  if (i != 0)
-  reduced_copy_is = Project(reduced_copy_is, level-1+privatized_levels.size()+i, Set_Var);
-  Relation bound = get_loop_bound(reduced_copy_is, level-1+privatized_levels.size()+i);
-  
-  // extract stride
-  EQ_Handle stride_eq;
-  {
-  bool simple_stride = true;
-  int strides = countStrides(bound.query_DNF()->single_conjunct(), bound.set_var(level-1+privatized_levels.size()+i+1), stride_eq, simple_stride);
-  if (strides > 1) {
-  throw loop_error("too many strides");
-  }
-  else if (strides == 1) {
-  int sign = stride_eq.get_coef(bound.set_var(level-1+privatized_levels.size()+i+1));
-  Constr_Vars_Iter it(stride_eq, true);
-  index_stride[i] = abs((*it).coef/sign);
-  }
-  }
-  
-  // check if this arary index requires loop
-  Conjunct *c = bound.query_DNF()->single_conjunct();
-  for (EQ_Iterator ei(c->EQs()); ei; ei++) {
-  if ((*ei).has_wildcards())
-  continue;
-  
-  int coef = (*ei).get_coef(bound.set_var(level-1+privatized_levels.size()+i+1));
-  if (coef != 0) {
-  int sign = 1;
-  if (coef < 0) {
-  coef = -coef;
-  sign = -1;
-  }
-  
-  CG_outputRepr *op = NULL;
-  for (Constr_Vars_Iter ci(*ei); ci; ci++) {
-  switch ((*ci).var->kind()) {
-  case Input_Var:
-  {
-  if ((*ci).var != bound.set_var(level-1+privatized_levels.size()+i+1))
-  if ((*ci).coef*sign == 1)
-  op = ocg->CreateMinus(op, ocg->CreateIdent((*ci).var->name()));
-  else if ((*ci).coef*sign == -1)
-  op = ocg->CreatePlus(op, ocg->CreateIdent((*ci).var->name()));
-  else if ((*ci).coef*sign > 1)
-  op = ocg->CreateMinus(op, ocg->CreateTimes(ocg->CreateInt(abs((*ci).coef)), ocg->CreateIdent((*ci).var->name())));
-  else // (*ci).coef*sign < -1
-  op = ocg->CreatePlus(op, ocg->CreateTimes(ocg->CreateInt(abs((*ci).coef)), ocg->CreateIdent((*ci).var->name())));
-  break;
-  }
-  case Global_Var:
-  {
-  Global_Var_ID g = (*ci).var->get_global_var();
-  if ((*ci).coef*sign == 1)
-  op = ocg->CreateMinus(op, ocg->CreateIdent(g->base_name()));
-  else if ((*ci).coef*sign == -1)
-  op = ocg->CreatePlus(op, ocg->CreateIdent(g->base_name()));
-  else if ((*ci).coef*sign > 1)
-  op = ocg->CreateMinus(op, ocg->CreateTimes(ocg->CreateInt(abs((*ci).coef)), ocg->CreateIdent(g->base_name())));
-  else // (*ci).coef*sign < -1
-  op = ocg->CreatePlus(op, ocg->CreateTimes(ocg->CreateInt(abs((*ci).coef)), ocg->CreateIdent(g->base_name())));
-  break;
-  }
-  default:
-  throw loop_error("unsupported array index expression");
-  }
-  }
-  if ((*ei).get_const() != 0)
-  op = ocg->CreatePlus(op, ocg->CreateInt(-sign*((*ei).get_const())));
-  if (coef != 1)
-  op = ocg->CreateIntegerDivide(op, ocg->CreateInt(coef));
-  
-  index_lb[i] = op;
-  is_index_eq[i] = true;
-  break;
-  }
-  }
-  if (is_index_eq[i])
-  continue;
-  
-  // seperate lower and upper bounds
-  std::vector<GEQ_Handle> lb_list, ub_list;
-  for (GEQ_Iterator gi(c->GEQs()); gi; gi++) {
-  int coef = (*gi).get_coef(bound.set_var(level-1+privatized_levels.size()+i+1));
-  if (coef != 0 && (*gi).has_wildcards()) {
-  bool clean_bound = true;
-  GEQ_Handle h;
-  for (Constr_Vars_Iter cvi(*gi, true); gi; gi++)
-  if (!findFloorInequality(bound, (*cvi).var, h, bound.set_var(level-1+privatized_levels.size()+i+1))) {
-  clean_bound = false;
-  break;
-  }
-  if (!clean_bound)
-  continue;
-  }
-  
-  if (coef > 0)
-  lb_list.push_back(*gi);
-  else if (coef < 0)
-  ub_list.push_back(*gi);
-  }
-  if (lb_list.size() == 0 || ub_list.size() == 0)
-  if (already_use_recthull)
-  throw loop_error("failed to calcuate array footprint size");
-  else {
-  copy_is = RectHull(copy(untampered_copy_is));
-  already_use_recthull = true;
-  goto Retry_copy_is;
-  }
-  
-  // build lower bound representation
-  Tuple<CG_outputRepr *> lb_repr_list;
-  for (int j = 0; j < lb_list.size(); j++)
-  lb_repr_list.append(outputLBasRepr(ocg, lb_list[j], bound,
-  bound.set_var(level-1+privatized_levels.size()+i+1), 
-  index_stride[i], stride_eq, Relation::True(bound.n_set()),
-  std::vector<CG_outputRepr *>(bound.n_set())));
-  
-  if (lb_repr_list.size() > 1)
-  index_lb[i] = ocg->CreateInvoke("max", lb_repr_list);
-  else if (lb_repr_list.size() == 1)
-  index_lb[i] = lb_repr_list[1];
-  
-  // build temporary array size representation
-  {
-  Relation cal(copy_is.n_set(), 1);
-  F_And *f_root = cal.add_and();
-  for (int j = 0; j < ub_list.size(); j++)
-  for (int k = 0; k < lb_list.size(); k++) {
-  GEQ_Handle h = f_root->add_GEQ();
-  
-  for (Constr_Vars_Iter ci(ub_list[j]); ci; ci++) {
-  switch ((*ci).var->kind()) {
-  case Input_Var:
-  {
-  int pos = (*ci).var->get_position();
-  h.update_coef(cal.input_var(pos), (*ci).coef);
-  break;
-  }
-  case Global_Var:
-  {
-  Global_Var_ID g = (*ci).var->get_global_var();
-  Variable_ID v;
-  if (g->arity() == 0)
-  v = cal.get_local(g);
-  else
-  v = cal.get_local(g, (*ci).var->function_of());
-  h.update_coef(v, (*ci).coef);
-  break;
-  }
-  default:
-  throw loop_error("cannot calculate temporay array size statically");
-  }
-  }
-  h.update_const(ub_list[j].get_const());
-  
-  for (Constr_Vars_Iter ci(lb_list[k]); ci; ci++) {
-  switch ((*ci).var->kind()) {
-  case Input_Var:
-  {
-  int pos = (*ci).var->get_position();
-  h.update_coef(cal.input_var(pos), (*ci).coef);
-  break;
-  }
-  case Global_Var:
-  {
-  Global_Var_ID g = (*ci).var->get_global_var();
-  Variable_ID v;
-  if (g->arity() == 0)
-  v = cal.get_local(g);
-  else
-  v = cal.get_local(g, (*ci).var->function_of());
-  h.update_coef(v, (*ci).coef);
-  break;
-  }
-  default:
-  throw loop_error("cannot calculate temporay array size statically");
-  }
-  }
-  h.update_const(lb_list[k].get_const());
-  
-  h.update_const(1);
-  h.update_coef(cal.output_var(1), -1);
-  }
-  
-  cal = Restrict_Domain(cal, copy(copy_is));
-  for (int j = 1; j <= cal.n_inp(); j++)
-  cal = Project(cal, j, Input_Var);
-  cal.simplify();
-  
-  // pad temporary array size
-  // TODO: for variable array size, create padding formula
-  Conjunct *c = cal.query_DNF()->single_conjunct();
-  bool is_index_bound_const = false;
-  for (GEQ_Iterator gi(c->GEQs()); gi && !is_index_bound_const; gi++)
-  if ((*gi).is_const(cal.output_var(1))) {
-  coef_t size = (*gi).get_const() / (-(*gi).get_coef(cal.output_var(1)));
-  if (padding_stride != 0) {
-  size = (size + index_stride[i] - 1) / index_stride[i];
-  if (i == fastest_changing_dimension)
-  size = size * padding_stride;
-  }
-  if (i == fastest_changing_dimension) {
-  if (padding_alignment > 1) { // align to boundary for data packing
-  int residue = size % padding_alignment;
-  if (residue)
-  size = size+padding_alignment-residue;
-  }
-  else if (padding_alignment < -1) {  // un-alignment for memory bank conflicts
-  while (gcd(size, static_cast<coef_t>(-padding_alignment)) != 1)
-  size++;
-  }
-  }
-  index_sz.push_back(std::make_pair(i, ocg->CreateInt(size)));
-  is_index_bound_const = true;
-  }
-  
-  if (!is_index_bound_const) {
-  for (GEQ_Iterator gi(c->GEQs()); gi && !is_index_bound_const; gi++) {
-  int coef = (*gi).get_coef(cal.output_var(1));
-  if (coef < 0) {
-  CG_outputRepr *op = NULL;
-  for (Constr_Vars_Iter ci(*gi); ci; ci++) {
-  if ((*ci).var != cal.output_var(1)) {
-  switch((*ci).var->kind()) {
-  case Global_Var:
-  {
-  Global_Var_ID g = (*ci).var->get_global_var();
-  if ((*ci).coef == 1)
-  op = ocg->CreatePlus(op, ocg->CreateIdent(g->base_name()));
-  else if ((*ci).coef == -1)
-  op = ocg->CreateMinus(op, ocg->CreateIdent(g->base_name()));
-  else if ((*ci).coef > 1)
-  op = ocg->CreatePlus(op, ocg->CreateTimes(ocg->CreateInt((*ci).coef), ocg->CreateIdent(g->base_name())));
-  else // (*ci).coef < -1
-  op = ocg->CreateMinus(op, ocg->CreateTimes(ocg->CreateInt(-(*ci).coef), ocg->CreateIdent(g->base_name())));
-  break;
-  }
-  default:
-  throw loop_error("failed to generate array index bound code");
-  }
-  }
-  }
-  int c = (*gi).get_const();
-  if (c > 0)
-  op = ocg->CreatePlus(op, ocg->CreateInt(c));
-  else if (c < 0)
-  op = ocg->CreateMinus(op, ocg->CreateInt(-c));
-  if (padding_stride != 0) {
-  if (i == fastest_changing_dimension) {
-  coef_t g = gcd(index_stride[i], static_cast<coef_t>(padding_stride));
-  coef_t t1 = index_stride[i] / g;
-  if (t1 != 1)
-  op = ocg->CreateIntegerDivide(ocg->CreatePlus(op, ocg->CreateInt(t1-1)), ocg->CreateInt(t1));
-  coef_t t2 = padding_stride / g;
-  if (t2 != 1)
-  op = ocg->CreateTimes(op, ocg->CreateInt(t2));
-  }
-  else if (index_stride[i] != 1) {
-  op = ocg->CreateIntegerDivide(ocg->CreatePlus(op, ocg->CreateInt(index_stride[i]-1)), ocg->CreateInt(index_stride[i]));
-  }
-  }
-  
-  index_sz.push_back(std::make_pair(i, op));
-  break;
-  }
-  }
-  }
-  }
-  }
-  
-  // change the temporary array index order
-  for (int i = 0; i < index_sz.size(); i++)
-  if (index_sz[i].first == fastest_changing_dimension)
-  switch (sym->layout_type()) {
-  case IR_ARRAY_LAYOUT_ROW_MAJOR:
-  std::swap(index_sz[index_sz.size()-1], index_sz[i]);
-  break;
-  case IR_ARRAY_LAYOUT_COLUMN_MAJOR:
-  std::swap(index_sz[0], index_sz[i]);
-  break;
-  default:
-  throw loop_error("unsupported array layout");
-  }
-  
-  // declare temporary array or scalar
-  IR_Symbol *tmp_sym;
-  if (index_sz.size() == 0) {
-  tmp_sym = ir->CreateScalarSymbol(sym, memory_type);
-  }
-  else {
-  std::vector<CG_outputRepr *> tmp_array_size(index_sz.size());
-  for (int i = 0; i < index_sz.size(); i++)
-  tmp_array_size[i] = index_sz[i].second->clone();
-  tmp_sym = ir->CreateArraySymbol(sym, tmp_array_size, memory_type);
-  }
-  
-  // create temporary array read initialization code
-  CG_outputRepr *copy_code_read;
-  if (has_read_refs)
-  if (index_sz.size() == 0) {
-  IR_ScalarRef *tmp_scalar_ref = ir->CreateScalarRef(static_cast<IR_ScalarSymbol *>(tmp_sym));
-  
-  std::vector<CG_outputRepr *> rhs_index(n_dim);
-  for (int i = 0; i < index_lb.size(); i++)
-  if (is_index_eq[i])
-  rhs_index[i] = index_lb[i]->clone();
-  else
-  rhs_index[i] = ir->builder()->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+i+1)->name());
-  IR_ArrayRef *copied_array_ref = ir->CreateArrayRef(sym, rhs_index);
-  
-  copy_code_read = ir->builder()->CreateAssignment(0, tmp_scalar_ref->convert(), copied_array_ref->convert());
-  }
-  else {
-  std::vector<CG_outputRepr *> lhs_index(index_sz.size());
-  for (int i = 0; i < index_sz.size(); i++) {
-  int cur_index_num = index_sz[i].first;
-  CG_outputRepr *cur_index_repr = ocg->CreateMinus(ocg->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+cur_index_num+1)->name()), index_lb[cur_index_num]->clone());
-  if (padding_stride != 0) {
-  if (i == n_dim-1) {
-  coef_t g = gcd(index_stride[cur_index_num], static_cast<coef_t>(padding_stride));
-  coef_t t1 = index_stride[cur_index_num] / g;
-  if (t1 != 1)
-  cur_index_repr = ocg->CreateIntegerDivide(cur_index_repr, ocg->CreateInt(t1));
-  coef_t t2 = padding_stride / g;
-  if (t2 != 1)
-  cur_index_repr = ocg->CreateTimes(cur_index_repr, ocg->CreateInt(t2));
-  }
-  else if (index_stride[cur_index_num] != 1) {
-  cur_index_repr = ocg->CreateIntegerDivide(cur_index_repr, ocg->CreateInt(index_stride[cur_index_num]));
-  }
-  }
-  
-  if (ir->ArrayIndexStartAt() != 0)
-  cur_index_repr = ocg->CreatePlus(cur_index_repr, ocg->CreateInt(ir->ArrayIndexStartAt()));
-  lhs_index[i] = cur_index_repr;
-  }
-  
-  IR_ArrayRef *tmp_array_ref = ir->CreateArrayRef(static_cast<IR_ArraySymbol *>(tmp_sym), lhs_index);
-  
-  std::vector<CG_outputRepr *> rhs_index(n_dim);
-  for (int i = 0; i < index_lb.size(); i++)
-  if (is_index_eq[i])
-  rhs_index[i] = index_lb[i]->clone();
-  else
-  rhs_index[i] = ir->builder()->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+i+1)->name());
-  IR_ArrayRef *copied_array_ref = ir->CreateArrayRef(sym, rhs_index);
-  
-  copy_code_read = ir->builder()->CreateAssignment(0, tmp_array_ref->convert(), copied_array_ref->convert());
-  }
-  
-  // create temporary array write back code
-  CG_outputRepr *copy_code_write;
-  if (has_write_refs)
-  if (index_sz.size() == 0) {
-  IR_ScalarRef *tmp_scalar_ref = ir->CreateScalarRef(static_cast<IR_ScalarSymbol *>(tmp_sym));
-  
-  std::vector<CG_outputRepr *> rhs_index(n_dim);
-  for (int i = 0; i < index_lb.size(); i++)
-  if (is_index_eq[i])
-  rhs_index[i] = index_lb[i]->clone();
-  else
-  rhs_index[i] = ir->builder()->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+i+1)->name());
-  IR_ArrayRef *copied_array_ref = ir->CreateArrayRef(sym, rhs_index);
-  
-  copy_code_write = ir->builder()->CreateAssignment(0, copied_array_ref->convert(), tmp_scalar_ref->convert());
-  }
-  else {
-  std::vector<CG_outputRepr *> lhs_index(n_dim);
-  for (int i = 0; i < index_lb.size(); i++)
-  if (is_index_eq[i])
-  lhs_index[i] = index_lb[i]->clone();
-  else
-  lhs_index[i] = ir->builder()->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+i+1)->name());
-  IR_ArrayRef *copied_array_ref = ir->CreateArrayRef(sym, lhs_index);
-  
-  std::vector<CG_outputRepr *> rhs_index(index_sz.size());
-  for (int i = 0; i < index_sz.size(); i++) {
-  int cur_index_num = index_sz[i].first;
-  CG_outputRepr *cur_index_repr = ocg->CreateMinus(ocg->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+cur_index_num+1)->name()), index_lb[cur_index_num]->clone());
-  if (padding_stride != 0) {
-  if (i == n_dim-1) {
-  coef_t g = gcd(index_stride[cur_index_num], static_cast<coef_t>(padding_stride));
-  coef_t t1 = index_stride[cur_index_num] / g;
-  if (t1 != 1)
-  cur_index_repr = ocg->CreateIntegerDivide(cur_index_repr, ocg->CreateInt(t1));
-  coef_t t2 = padding_stride / g;
-  if (t2 != 1)
-  cur_index_repr = ocg->CreateTimes(cur_index_repr, ocg->CreateInt(t2));
-  }
-  else if (index_stride[cur_index_num] != 1) {
-  cur_index_repr = ocg->CreateIntegerDivide(cur_index_repr, ocg->CreateInt(index_stride[cur_index_num]));
-  }
-  }
-  
-  if (ir->ArrayIndexStartAt() != 0)
-  cur_index_repr = ocg->CreatePlus(cur_index_repr, ocg->CreateInt(ir->ArrayIndexStartAt()));
-  rhs_index[i] = cur_index_repr;
-  }
-  IR_ArrayRef *tmp_array_ref = ir->CreateArrayRef(static_cast<IR_ArraySymbol *>(tmp_sym), rhs_index);
-  
-  copy_code_write = ir->builder()->CreateAssignment(0, copied_array_ref->convert(), tmp_array_ref->convert());
-  }
-  
-  // now we can remove those loops for array indexes that are
-  // dependent on others
-  if (!(index_sz.size() == n_dim && (sym->layout_type() == IR_ARRAY_LAYOUT_ROW_MAJOR || n_dim <= 1))) {
-  Relation mapping(level-1+privatized_levels.size()+n_dim, level-1+privatized_levels.size()+index_sz.size());
-  F_And *f_root = mapping.add_and();
-  for (int i = 1; i <= level-1+privatized_levels.size(); i++) {
-  EQ_Handle h = f_root->add_EQ();
-  h.update_coef(mapping.input_var(i), 1);
-  h.update_coef(mapping.output_var(i), -1);
-  }
-  
-  int cur_index = 0;
-  std::vector<int> mapped_index(index_sz.size());
-  for (int i = 0; i < n_dim; i++)
-  if (!is_index_eq[i]) {
-  EQ_Handle h = f_root->add_EQ();
-  h.update_coef(mapping.input_var(level-1+privatized_levels.size()+i+1), 1);
-  switch (sym->layout_type()) {
-  case IR_ARRAY_LAYOUT_COLUMN_MAJOR: {
-  h.update_coef(mapping.output_var(level-1+privatized_levels.size()+index_sz.size()-cur_index), -1);
-  mapped_index[index_sz.size()-cur_index-1] = i;
-  break;
-  }
-  case IR_ARRAY_LAYOUT_ROW_MAJOR: {
-  h.update_coef(mapping.output_var(level-1+privatized_levels.size()+cur_index+1), -1);
-  mapped_index[cur_index] = i;
-  break;
-  }
-  default:
-  throw loop_error("unsupported array layout");
-  }
-  cur_index++;
-  }
-  
-  wo_copy_is = Range(Restrict_Domain(copy(mapping), wo_copy_is));
-  ro_copy_is = Range(Restrict_Domain(copy(mapping), ro_copy_is));
-  
-  // protonu--replacing Chun's old code 
-  for (int i = 1; i <= level-1+privatized_levels.size(); i++) {
-  wo_copy_is.name_set_var(i, copy_is.set_var(i)->name());
-  ro_copy_is.name_set_var(i, copy_is.set_var(i)->name());
-  }
-  
-  
-  
-  for (int i = 0; i < index_sz.size(); i++) {
-  wo_copy_is.name_set_var(level-1+privatized_levels.size()+i+1, copy_is.set_var(level-1+privatized_levels.size()+mapped_index[i]+1)->name());
-  ro_copy_is.name_set_var(level-1+privatized_levels.size()+i+1, copy_is.set_var(level-1+privatized_levels.size()+mapped_index[i]+1)->name());
-  }      
-  wo_copy_is.setup_names();
-  ro_copy_is.setup_names();
-  }
-  
-  // insert read copy statement
-  int old_num_stmt = stmt.size();
-  int ro_copy_stmt_num = -1;
-  if (has_read_refs) {
-  Relation copy_xform(ro_copy_is.n_set(), 2*ro_copy_is.n_set()+1);
-  {
-  F_And *f_root = copy_xform.add_and();
-  for (int i = 1; i <= ro_copy_is.n_set(); i++) {
-  EQ_Handle h = f_root->add_EQ();
-  h.update_coef(copy_xform.input_var(i), 1);
-  h.update_coef(copy_xform.output_var(2*i), -1);
-  }
-  for (int i = 1; i <= dim; i+=2) {
-  EQ_Handle h = f_root->add_EQ();
-  h.update_coef(copy_xform.output_var(i), -1);
-  h.update_const(lex[i-1]);
-  }
-  for (int i = dim+2; i <= copy_xform.n_out(); i+=2) {
-  EQ_Handle h = f_root->add_EQ();
-  h.update_coef(copy_xform.output_var(i), 1);
-  }
-  }
-  
-  Statement copy_stmt_read;
-  copy_stmt_read.IS = ro_copy_is;
-  copy_stmt_read.xform = copy_xform;
-  copy_stmt_read.code = copy_code_read;
-  copy_stmt_read.loop_level = std::vector<LoopLevel>(ro_copy_is.n_set());
-  copy_stmt_read.ir_stmt_node = NULL;
-  for (int i = 0; i < level-1; i++) {
-  copy_stmt_read.loop_level[i].type = stmt[*(active.begin())].loop_level[i].type;
-  if (stmt[*(active.begin())].loop_level[i].type == LoopLevelTile &&
-  stmt[*(active.begin())].loop_level[i].payload >= level) {
-  int j;
-  for (j = 0; j < privatized_levels.size(); j++)
-  if (privatized_levels[j] == stmt[*(active.begin())].loop_level[i].payload)
-  break;
-  if (j == privatized_levels.size())
-  copy_stmt_read.loop_level[i].payload = -1;
-  else
-  copy_stmt_read.loop_level[i].payload = level + j;
-  }
-  else
-  copy_stmt_read.loop_level[i].payload = stmt[*(active.begin())].loop_level[i].payload;
-  copy_stmt_read.loop_level[i].parallel_level = stmt[*(active.begin())].loop_level[i].parallel_level;
-  }
-  for (int i = 0; i < privatized_levels.size(); i++) {
-  copy_stmt_read.loop_level[level-1+i].type = stmt[*(active.begin())].loop_level[privatized_levels[i]].type;
-  copy_stmt_read.loop_level[level-1+i].payload = stmt[*(active.begin())].loop_level[privatized_levels[i]].payload;
-  copy_stmt_read.loop_level[level-1+i].parallel_level = stmt[*(active.begin())].loop_level[privatized_levels[i]].parallel_level;
-  }
-  int left_num_dim = num_dep_dim - (get_last_dep_dim_before(*(active.begin()), level) + 1);
-  for (int i = 0; i < min(left_num_dim, static_cast<int>(index_sz.size())); i++) {
-  copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].type = LoopLevelOriginal;
-  copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].payload = num_dep_dim-left_num_dim+i;
-  copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].parallel_level = 0;
-  }
-  for (int i = min(left_num_dim, static_cast<int>(index_sz.size())); i < index_sz.size(); i++) {
-  copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].type = LoopLevelUnknown;
-  copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].payload = -1;
-  copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].parallel_level = 0;
-  }
-  
-  shiftLexicalOrder(lex, dim-1, 1);
-  stmt.push_back(copy_stmt_read);
-  ro_copy_stmt_num = stmt.size() - 1;
-  dep.insert();
-  }
-  
-  // insert write copy statement
-  int wo_copy_stmt_num = -1;
-  if (has_write_refs) {
-  Relation copy_xform(wo_copy_is.n_set(), 2*wo_copy_is.n_set()+1);
-  {
-  F_And *f_root = copy_xform.add_and();
-  for (int i = 1; i <= wo_copy_is.n_set(); i++) {
-  EQ_Handle h = f_root->add_EQ();
-  h.update_coef(copy_xform.input_var(i), 1);
-  h.update_coef(copy_xform.output_var(2*i), -1);
-  }
-  for (int i = 1; i <= dim; i+=2) {
-  EQ_Handle h = f_root->add_EQ();
-  h.update_coef(copy_xform.output_var(i), -1);
-  h.update_const(lex[i-1]);
-  }
-  for (int i = dim+2; i <= copy_xform.n_out(); i+=2) {
-  EQ_Handle h = f_root->add_EQ();
-  h.update_coef(copy_xform.output_var(i), 1);
-  }
-  }
-  
-  Statement copy_stmt_write;
-  copy_stmt_write.IS = wo_copy_is;
-  copy_stmt_write.xform = copy_xform;
-  copy_stmt_write.code = copy_code_write;
-  copy_stmt_write.loop_level = std::vector<LoopLevel>(wo_copy_is.n_set());
-  copy_stmt_write.ir_stmt_node = NULL;
-  
-  for (int i = 0; i < level-1; i++) {
-  copy_stmt_write.loop_level[i].type = stmt[*(active.begin())].loop_level[i].type;
-  if (stmt[*(active.begin())].loop_level[i].type == LoopLevelTile &&
-  stmt[*(active.begin())].loop_level[i].payload >= level) {
-  int j;
-  for (j = 0; j < privatized_levels.size(); j++)
-  if (privatized_levels[j] == stmt[*(active.begin())].loop_level[i].payload)
-  break;
-  if (j == privatized_levels.size())
-  copy_stmt_write.loop_level[i].payload = -1;
-  else
-  copy_stmt_write.loop_level[i].payload = level + j;
-  }
-  else
-  copy_stmt_write.loop_level[i].payload = stmt[*(active.begin())].loop_level[i].payload;
-  copy_stmt_write.loop_level[i].parallel_level = stmt[*(active.begin())].loop_level[i].parallel_level;
-  }
-  for (int i = 0; i < privatized_levels.size(); i++) {
-  copy_stmt_write.loop_level[level-1+i].type = stmt[*(active.begin())].loop_level[privatized_levels[i]].type;
-  copy_stmt_write.loop_level[level-1+i].payload = stmt[*(active.begin())].loop_level[privatized_levels[i]].payload;
-  copy_stmt_write.loop_level[level-1+i].parallel_level = stmt[*(active.begin())].loop_level[privatized_levels[i]].parallel_level;
-  }
-  int left_num_dim = num_dep_dim - (get_last_dep_dim_before(*(active.begin()), level) + 1);
-  for (int i = 0; i < min(left_num_dim, static_cast<int>(index_sz.size())); i++) {
-  copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].type = LoopLevelOriginal;
-  copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].payload = num_dep_dim-left_num_dim+i;
-  copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].parallel_level = 0;
-  }
-  for (int i = min(left_num_dim, static_cast<int>(index_sz.size())); i < index_sz.size(); i++) {
-  copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].type = LoopLevelUnknown;
-  copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].payload = -1;
-  copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].parallel_level = 0;
-  }
-  
-  lex[dim-1]++;
-  shiftLexicalOrder(lex, dim-1, -2);
-  stmt.push_back(copy_stmt_write);
-  wo_copy_stmt_num = stmt.size() - 1;
-  dep.insert();
-  } 
-  
-  // replace original array accesses with temporary array accesses
-  for (int i =0; i < stmt_refs.size(); i++)
-  for (int j = 0; j < stmt_refs[i].second.size(); j++) {
-  if (index_sz.size() == 0) {
-  IR_ScalarRef *tmp_scalar_ref = ir->CreateScalarRef(static_cast<IR_ScalarSymbol *>(tmp_sym));
-  ir->ReplaceExpression(stmt_refs[i].second[j], tmp_scalar_ref->convert());
-  }
-  else {
-  std::vector<CG_outputRepr *> index_repr(index_sz.size());
-  for (int k = 0; k < index_sz.size(); k++) {
-  int cur_index_num = index_sz[k].first;
-  
-  CG_outputRepr *cur_index_repr = ocg->CreateMinus(stmt_refs[i].second[j]->index(cur_index_num), index_lb[cur_index_num]->clone());
-  if (padding_stride != 0) {
-  if (k == n_dim-1) {
-  coef_t g = gcd(index_stride[cur_index_num], static_cast<coef_t>(padding_stride));
-  coef_t t1 = index_stride[cur_index_num] / g;
-  if (t1 != 1)
-  cur_index_repr = ocg->CreateIntegerDivide(cur_index_repr, ocg->CreateInt(t1));
-  coef_t t2 = padding_stride / g;
-  if (t2 != 1)
-  cur_index_repr = ocg->CreateTimes(cur_index_repr, ocg->CreateInt(t2));
-  }
-  else if (index_stride[cur_index_num] != 1) {
-  cur_index_repr = ocg->CreateIntegerDivide(cur_index_repr, ocg->CreateInt(index_stride[cur_index_num]));
-  }
-  }
-  
-  if (ir->ArrayIndexStartAt() != 0)
-  cur_index_repr = ocg->CreatePlus(cur_index_repr, ocg->CreateInt(ir->ArrayIndexStartAt()));
-  index_repr[k] = cur_index_repr;
-  }
-  
-  IR_ArrayRef *tmp_array_ref = ir->CreateArrayRef(static_cast<IR_ArraySymbol *>(tmp_sym), index_repr);
-  ir->ReplaceExpression(stmt_refs[i].second[j], tmp_array_ref->convert());
-  }
-  }
-  
-  // update dependence graph
-  int dep_dim = get_last_dep_dim_before(*(active.begin()), level) + 1;
-  if (ro_copy_stmt_num != -1) {
-  for (int i = 0; i < old_num_stmt; i++) {
-  std::vector<std::vector<DependenceVector> > D;
-  
-  for (DependenceGraph::EdgeList::iterator j = dep.vertex[i].second.begin(); j != dep.vertex[i].second.end();) {
-  if (active.find(i) != active.end() && active.find(j->first) == active.end()) {
-  std::vector<DependenceVector> dvs1, dvs2;
-  for (int k = 0; k < j->second.size(); k++) {
-  DependenceVector dv = j->second[k];
-  if (dv.sym != NULL && dv.sym->name() == sym->name() && (dv.type == DEP_R2R || dv.type == DEP_R2W))
-  dvs1.push_back(dv);
-  else
-  dvs2.push_back(dv);
-  }
-  j->second = dvs2;
-  if (dvs1.size() > 0)
-  dep.connect(ro_copy_stmt_num, j->first, dvs1);
-  }
-  else if (active.find(i) == active.end() && active.find(j->first) != active.end()) {
-  std::vector<DependenceVector> dvs1, dvs2;
-  for (int k = 0; k < j->second.size(); k++) {
-  DependenceVector dv = j->second[k];
-  if (dv.sym != NULL && dv.sym->name() == sym->name() && (dv.type == DEP_R2R || dv.type == DEP_W2R))
-  dvs1.push_back(dv);
-  else
-  dvs2.push_back(dv);
-  }
-  j->second = dvs2;
-  if (dvs1.size() > 0)
-  D.push_back(dvs1);
-  }
-  
-  if (j->second.size() == 0)
-  dep.vertex[i].second.erase(j++);
-  else
-  j++;
-  }
-  
-  for (int j = 0; j < D.size(); j++)
-  dep.connect(i, ro_copy_stmt_num, D[j]);
-  }
-  
-  // insert dependences from copy statement loop to copied statements
-  DependenceVector dv;
-  dv.type = DEP_W2R;
-  dv.sym = tmp_sym->clone();
-  dv.lbounds = std::vector<coef_t>(num_dep_dim, 0);
-  dv.ubounds = std::vector<coef_t>(num_dep_dim, 0);
-  for (int i = dep_dim; i < num_dep_dim; i++) {
-  dv.lbounds[i] = -posInfinity;
-  dv.ubounds[i] = posInfinity;
-  } 
-  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++)
-  dep.connect(ro_copy_stmt_num, *i, dv);
-  }
-  
-  if (wo_copy_stmt_num != -1) {
-  for (int i = 0; i < old_num_stmt; i++) {
-  std::vector<std::vector<DependenceVector> > D;
-  
-  for (DependenceGraph::EdgeList::iterator j = dep.vertex[i].second.begin(); j != dep.vertex[i].second.end();) {
-  if (active.find(i) != active.end() && active.find(j->first) == active.end()) {
-  std::vector<DependenceVector> dvs1, dvs2;
-  for (int k = 0; k < j->second.size(); k++) {
-  DependenceVector dv = j->second[k];
-  if (dv.sym != NULL && dv.sym->name() == sym->name() && (dv.type == DEP_W2R || dv.type == DEP_W2W))
-  dvs1.push_back(dv);
-  else
-  dvs2.push_back(dv);
-  }
-  j->second = dvs2;
-  if (dvs1.size() > 0)
-  dep.connect(wo_copy_stmt_num, j->first, dvs1);
-  }
-  else if (active.find(i) == active.end() && active.find(j->first) != active.end()) {
-  std::vector<DependenceVector> dvs1, dvs2;
-  for (int k = 0; k < j->second.size(); k++) {
-  DependenceVector dv = j->second[k];
-  if (dv.sym != NULL && dv.sym->name() == sym->name() && (dv.type == DEP_R2W || dv.type == DEP_W2W))
-  dvs1.push_back(dv);
-  else
-  dvs2.push_back(dv);
-  }
-  j->second = dvs2;
-  if (dvs1.size() > 0)
-  D.push_back(dvs1);
-  }
-  
-  if (j->second.size() == 0)
-  dep.vertex[i].second.erase(j++);
-  else
-  j++;
-  }
-  
-  for (int j = 0; j < D.size(); j++)
-  dep.connect(i, wo_copy_stmt_num, D[j]);
-  }
-  
-  // insert dependences from copied statements to write statements
-  DependenceVector dv;
-  dv.type = DEP_W2R;
-  dv.sym = tmp_sym->clone();
-  dv.lbounds = std::vector<coef_t>(num_dep_dim, 0);
-  dv.ubounds = std::vector<coef_t>(num_dep_dim, 0);
-  for (int i = dep_dim; i < num_dep_dim; i++) {
-  dv.lbounds[i] = -posInfinity;
-  dv.ubounds[i] = posInfinity;
-  } 
-  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++)
-  dep.connect(*i, wo_copy_stmt_num, dv);
-  
-  }
-  
-  // update variable name for dependences among copied statements
-  for (int i = 0; i < old_num_stmt; i++) {
-  if (active.find(i) != active.end())
-  for (DependenceGraph::EdgeList::iterator j = dep.vertex[i].second.begin(); j != dep.vertex[i].second.end(); j++)
-  if (active.find(j->first) != active.end())
-  for (int k = 0; k < j->second.size(); k++) {
-  IR_Symbol *s = tmp_sym->clone();
-  j->second[k].sym = s;
-  }
-  }
-  
-  // insert anti-dependence from write statement to read statement
-  if (ro_copy_stmt_num != -1 && wo_copy_stmt_num != -1)
-  if (dep_dim >= 0) {
-  DependenceVector dv;
-  dv.type = DEP_R2W;
-  dv.sym = tmp_sym->clone();
-  dv.lbounds = std::vector<coef_t>(num_dep_dim, 0);
-  dv.ubounds = std::vector<coef_t>(num_dep_dim, 0);
-  for (int k = dep_dim; k < num_dep_dim; k++) {
-  dv.lbounds[k] = -posInfinity;
-  dv.ubounds[k] = posInfinity;
-  }
-  for (int k = 0; k < dep_dim; k++) {
-  if (k != 0) {
-  dv.lbounds[k-1] = 0;
-  dv.ubounds[k-1] = 0;
-  }
-  dv.lbounds[k] = 1;
-  dv.ubounds[k] = posInfinity;
-  dep.connect(wo_copy_stmt_num, ro_copy_stmt_num, dv);
-  }
-  }
-  
-  
-  // cleanup
-  delete sym;
-  delete tmp_sym;
-  for (int i = 0; i < index_lb.size(); i++) {
-  index_lb[i]->clear();
-  delete index_lb[i];
-  }
-  for (int i = 0; i < index_sz.size(); i++) {
-  index_sz[i].second->clear();
-  delete index_sz[i].second;
-  }
-  
-  return true;
-  }
-*/
-bool Loop::datacopy_privatized(const std::vector<std::pair<int, std::vector<IR_ArrayRef *> > > &stmt_refs, int level,
-                               const std::vector<int> &privatized_levels,
-                               bool allow_extra_read, int fastest_changing_dimension,
-                               int padding_stride, int padding_alignment, int memory_type) {
-  if (stmt_refs.size() == 0)
-    return true;
-  
-  // check for sanity of parameters
-  IR_ArraySymbol *sym = NULL;
-  std::vector<int> lex;
-  std::set<int> active;
-  if (level <= 0)
-    throw std::invalid_argument("invalid loop level " + to_string(level));
-  for (int i = 0; i < privatized_levels.size(); i++) {
-    if (i == 0) {
-      if (privatized_levels[i] < level)
-        throw std::invalid_argument("privatized loop levels must be no less than level " + to_string(level));
-    }
-    else if (privatized_levels[i] <= privatized_levels[i-1])
-      throw std::invalid_argument("privatized loop levels must be in ascending order");
-  }
-  for (int i = 0; i < stmt_refs.size(); i++) {
-    int stmt_num = stmt_refs[i].first;
-    active.insert(stmt_num);
-    if (stmt_num < 0 || stmt_num >= stmt.size())
-      throw std::invalid_argument("invalid statement number " + to_string(stmt_num));
-    if (privatized_levels.size() != 0) {
-      if (privatized_levels[privatized_levels.size()-1] > stmt[stmt_num].loop_level.size())
-        throw std::invalid_argument("invalid loop level " + to_string(privatized_levels[privatized_levels.size()-1]) + " for statement " + to_string(stmt_num));
-    }
-    else {
-      if (level > stmt[stmt_num].loop_level.size())
-        throw std::invalid_argument("invalid loop level " + to_string(level) + " for statement " + to_string(stmt_num));
-    }
-    for (int j = 0; j < stmt_refs[i].second.size(); j++) {
-      if (sym == NULL) {
-        sym = stmt_refs[i].second[j]->symbol();
-        lex = getLexicalOrder(stmt_num);
-      }
-      else {
-        IR_ArraySymbol *t = stmt_refs[i].second[j]->symbol();
-        if (t->name() != sym->name()) {
-          delete t;
-          delete sym;
-          throw std::invalid_argument("try to copy data from different arrays");
-        }
-        delete t;
-      }
-    }
-  }
-  if (!(fastest_changing_dimension >= -1 && fastest_changing_dimension < sym->n_dim()))
-    throw std::invalid_argument("invalid fastest changing dimension for the array to be copied");
-  if (padding_stride < 0)
-    throw std::invalid_argument("invalid temporary array stride requirement");
-  if (padding_alignment == -1 || padding_alignment == 0)
-    throw std::invalid_argument("invalid temporary array alignment requirement");
-  
-  int dim = 2*level - 1;
-  int n_dim = sym->n_dim();
-  
-
-  if (fastest_changing_dimension == -1)
-    switch (sym->layout_type()) {
-    case IR_ARRAY_LAYOUT_ROW_MAJOR:
-      fastest_changing_dimension = n_dim - 1;
-      break;
-    case IR_ARRAY_LAYOUT_COLUMN_MAJOR:
-      fastest_changing_dimension = 0;
-      break;
-    default:
-      throw loop_error("unsupported array layout");
-    }
-
-  
-  // invalidate saved codegen computation
-  delete last_compute_cgr_;
-  last_compute_cgr_ = NULL;
-  delete last_compute_cg_;
-  last_compute_cg_ = NULL;
-  
-  // build iteration spaces for all reads and for all writes separately
-  apply_xform(active);
-  
-  bool has_write_refs = false;
-  bool has_read_refs = false;
-  Relation wo_copy_is = Relation::False(level-1+privatized_levels.size()+n_dim);
-  Relation ro_copy_is = Relation::False(level-1+privatized_levels.size()+n_dim);
-  for (int i = 0; i < stmt_refs.size(); i++) {
-    int stmt_num = stmt_refs[i].first;
-    
-    for (int j = 0; j < stmt_refs[i].second.size(); j++) {
-      Relation mapping(stmt[stmt_num].IS.n_set(), level-1+privatized_levels.size()+n_dim);
-      for (int k = 1; k <= mapping.n_inp(); k++)
-        mapping.name_input_var(k, stmt[stmt_num].IS.set_var(k)->name());
-      mapping.setup_names();
-      F_And *f_root = mapping.add_and();
-      for (int k = 1; k <= level-1; k++) {
-        EQ_Handle h = f_root->add_EQ();
-        h.update_coef(mapping.input_var(k), 1);
-        h.update_coef(mapping.output_var(k), -1);
-      }
-      for (int k = 0; k < privatized_levels.size(); k++) {
-        EQ_Handle h = f_root->add_EQ();
-        h.update_coef(mapping.input_var(privatized_levels[k]), 1);
-        h.update_coef(mapping.output_var(level+k), -1);
-      }
-      for (int k = 0; k < n_dim; k++) {
-        CG_outputRepr *repr = stmt_refs[i].second[j]->index(k);
-        exp2formula(ir, mapping, f_root, freevar, repr, mapping.output_var(level-1+privatized_levels.size()+k+1), 'w', IR_COND_EQ, false);
-        repr->clear();
-        delete repr;
-      }
-      Relation r = Range(Restrict_Domain(mapping, Intersection(copy(stmt[stmt_num].IS), Extend_Set(copy(this->known), stmt[stmt_num].IS.n_set() - this->known.n_set()))));
-      if (stmt_refs[i].second[j]->is_write()) {
-        has_write_refs = true;
-        wo_copy_is = Union(wo_copy_is, r);
-        wo_copy_is.simplify(2, 4);
-        
-        
-      }
-      else {
-        has_read_refs = true;
-        ro_copy_is = Union(ro_copy_is, r);
-        ro_copy_is.simplify(2, 4);
-        
-      }
-    }
-  }
-  
-  // simplify read and write footprint iteration space
-  {
-    if (allow_extra_read)
-      ro_copy_is = SimpleHull(ro_copy_is, true, true);
-    else
-      ro_copy_is = ConvexRepresentation(ro_copy_is);
-    
-    wo_copy_is = ConvexRepresentation(wo_copy_is);
-    if (wo_copy_is.number_of_conjuncts() > 1) {
-      Relation t = SimpleHull(wo_copy_is, true, true);
-      if (Must_Be_Subset(copy(t), copy(ro_copy_is)))
-        wo_copy_is = t;
-      else if (Must_Be_Subset(copy(wo_copy_is), copy(ro_copy_is)))
-        wo_copy_is = ro_copy_is;
-    }
-  }
-  
-  // make copy statement variable names match the ones in the original statements which
-  // already have the same names due to apply_xform
-  {
-    int ref_stmt = *active.begin();
-    for (std::set<int>::iterator i = active.begin(); i != active.end(); i++)
-      if (stmt[*i].IS.n_set() > stmt[ref_stmt].IS.n_set())
-        ref_stmt = *i;
-    for (int i = 1; i < level; i++) {
-      std::string s = stmt[ref_stmt].IS.input_var(i)->name();
-      wo_copy_is.name_set_var(i, s);
-      ro_copy_is.name_set_var(i, s);
-    }
-    for (int i = 0; i < privatized_levels.size(); i++) {
-      std::string s = stmt[ref_stmt].IS.input_var(privatized_levels[i])->name();
-      wo_copy_is.name_set_var(level+i, s);
-      ro_copy_is.name_set_var(level+i, s);
-    }
-    for (int i = level+privatized_levels.size(); i < level+privatized_levels.size()+n_dim; i++) {
-      std::string s = tmp_loop_var_name_prefix + to_string(tmp_loop_var_name_counter+i-level-privatized_levels.size());
-      wo_copy_is.name_set_var(i, s);
-      ro_copy_is.name_set_var(i, s);
-    }
-    tmp_loop_var_name_counter += n_dim;
-    wo_copy_is.setup_names();
-    ro_copy_is.setup_names();
-  }
-  
-  // build merged footprint iteration space for calculating temporary array size
-  Relation copy_is = SimpleHull(Union(copy(ro_copy_is), copy(wo_copy_is)), true, true);
-  
-  // extract temporary array information
-  CG_outputBuilder *ocg = ir->builder();
-  std::vector<CG_outputRepr *> index_lb(n_dim); // initialized to NULL
-  std::vector<coef_t> index_stride(n_dim);
-  std::vector<bool> is_index_eq(n_dim, false);
-  std::vector<std::pair<int, CG_outputRepr *> > index_sz(0);
-  Relation reduced_copy_is = copy(copy_is);
-  
-  for (int i = 0; i < n_dim; i++) {
-    if (i != 0)
-      reduced_copy_is = Project(reduced_copy_is, level-1+privatized_levels.size()+i, Set_Var);
-    Relation bound = get_loop_bound(reduced_copy_is, level-1+privatized_levels.size()+i);
-    
-    // extract stride
-    std::pair<EQ_Handle, Variable_ID> result = find_simplest_stride(bound, bound.set_var(level-1+privatized_levels.size()+i+1));
-    if (result.second != NULL)
-      index_stride[i] = abs(result.first.get_coef(result.second))/gcd(abs(result.first.get_coef(result.second)), abs(result.first.get_coef(bound.set_var(level-1+privatized_levels.size()+i+1))));
-    else
-      index_stride[i] = 1;
-    
-    // check if this arary index requires loop
-    Conjunct *c = bound.query_DNF()->single_conjunct();
-    for (EQ_Iterator ei(c->EQs()); ei; ei++) {
-      if ((*ei).has_wildcards())
-        continue;
-      
-      int coef = (*ei).get_coef(bound.set_var(level-1+privatized_levels.size()+i+1));
-      if (coef != 0) {
-        int sign = 1;
-        if (coef < 0) {
-          coef = -coef;
-          sign = -1;
-        }
-        
-        CG_outputRepr *op = NULL;
-        for (Constr_Vars_Iter ci(*ei); ci; ci++) {
-          switch ((*ci).var->kind()) {
-          case Input_Var:
-          {
-            if ((*ci).var != bound.set_var(level-1+privatized_levels.size()+i+1))
-              if ((*ci).coef*sign == 1)
-                op = ocg->CreateMinus(op, ocg->CreateIdent((*ci).var->name()));
-              else if ((*ci).coef*sign == -1)
-                op = ocg->CreatePlus(op, ocg->CreateIdent((*ci).var->name()));
-              else if ((*ci).coef*sign > 1)
-                op = ocg->CreateMinus(op, ocg->CreateTimes(ocg->CreateInt(abs((*ci).coef)), ocg->CreateIdent((*ci).var->name())));
-              else // (*ci).coef*sign < -1
-                op = ocg->CreatePlus(op, ocg->CreateTimes(ocg->CreateInt(abs((*ci).coef)), ocg->CreateIdent((*ci).var->name())));
-            break;
-          }
-          case Global_Var:
-          {
-            Global_Var_ID g = (*ci).var->get_global_var();
-            if ((*ci).coef*sign == 1)
-              op = ocg->CreateMinus(op, ocg->CreateIdent(g->base_name()));
-            else if ((*ci).coef*sign == -1)
-              op = ocg->CreatePlus(op, ocg->CreateIdent(g->base_name()));
-            else if ((*ci).coef*sign > 1)
-              op = ocg->CreateMinus(op, ocg->CreateTimes(ocg->CreateInt(abs((*ci).coef)), ocg->CreateIdent(g->base_name())));
-            else // (*ci).coef*sign < -1
-              op = ocg->CreatePlus(op, ocg->CreateTimes(ocg->CreateInt(abs((*ci).coef)), ocg->CreateIdent(g->base_name())));
-            break;
-          }
-          default:
-            throw loop_error("unsupported array index expression");
-          }
-        }
-        if ((*ei).get_const() != 0)
-          op = ocg->CreatePlus(op, ocg->CreateInt(-sign*((*ei).get_const())));
-        if (coef != 1)
-          op = ocg->CreateIntegerFloor(op, ocg->CreateInt(coef));
-        
-        index_lb[i] = op;
-        is_index_eq[i] = true;
-        break;
-      }
-    }
-    if (is_index_eq[i])
-      continue;
-    
-    // seperate lower and upper bounds
-    std::vector<GEQ_Handle> lb_list, ub_list;
-    std::set<Variable_ID> excluded_floor_vars;
-    excluded_floor_vars.insert(bound.set_var(level-1+privatized_levels.size()+i+1));
-    for (GEQ_Iterator gi(c->GEQs()); gi; gi++) {
-      int coef = (*gi).get_coef(bound.set_var(level-1+privatized_levels.size()+i+1));
-      if (coef != 0 && (*gi).has_wildcards()) {
-        bool clean_bound = true;
-        GEQ_Handle h;
-        for (Constr_Vars_Iter cvi(*gi, true); gi; gi++)
-          if (!find_floor_definition(bound, (*cvi).var, excluded_floor_vars).first) {
-            clean_bound = false;
-            break;
-          }
-        if (!clean_bound)
-          continue;
-      }
-      
-      if (coef > 0)
-        lb_list.push_back(*gi);
-      else if (coef < 0)
-        ub_list.push_back(*gi);
-    }
-    if (lb_list.size() == 0 || ub_list.size() == 0)
-      throw loop_error("failed to calcuate array footprint size");
-    
-    // build lower bound representation
-    std::vector<CG_outputRepr *> lb_repr_list;
-    for (int j = 0; j < lb_list.size(); j++){
-      if(this->known.n_set() == 0)
-        lb_repr_list.push_back(output_lower_bound_repr(ocg, lb_list[j], bound.set_var(level-1+privatized_levels.size()+i+1), result.first, result.second, bound, Relation::True(bound.n_set()), std::vector<std::pair<CG_outputRepr *, int> >(bound.n_set(), std::make_pair(static_cast<CG_outputRepr *>(NULL), 0))));
-      else
-        lb_repr_list.push_back(output_lower_bound_repr(ocg, lb_list[j], bound.set_var(level-1+privatized_levels.size()+i+1), result.first, result.second, bound, this->known, std::vector<std::pair<CG_outputRepr *, int> >(bound.n_set(), std::make_pair(static_cast<CG_outputRepr *>(NULL), 0))));
-    }
-    if (lb_repr_list.size() > 1)
-      index_lb[i] = ocg->CreateInvoke("max", lb_repr_list);
-    else if (lb_repr_list.size() == 1)
-      index_lb[i] = lb_repr_list[0];
-    
-    // build temporary array size representation
-    {
-      Relation cal(copy_is.n_set(), 1);
-      F_And *f_root = cal.add_and();
-      for (int j = 0; j < ub_list.size(); j++)
-        for (int k = 0; k < lb_list.size(); k++) {
-          GEQ_Handle h = f_root->add_GEQ();
-          
-          for (Constr_Vars_Iter ci(ub_list[j]); ci; ci++) {
-            switch ((*ci).var->kind()) {
-            case Input_Var:
-            {
-              int pos = (*ci).var->get_position();
-              h.update_coef(cal.input_var(pos), (*ci).coef);
-              break;
-            }
-            case Global_Var:
-            {
-              Global_Var_ID g = (*ci).var->get_global_var();
-              Variable_ID v;
-              if (g->arity() == 0)
-                v = cal.get_local(g);
-              else
-                v = cal.get_local(g, (*ci).var->function_of());
-              h.update_coef(v, (*ci).coef);
-              break;
-            }
-            default:
-              throw loop_error("cannot calculate temporay array size statically");
-            }
-          }
-          h.update_const(ub_list[j].get_const());
-          
-          for (Constr_Vars_Iter ci(lb_list[k]); ci; ci++) {
-            switch ((*ci).var->kind()) {
-            case Input_Var:
-            {
-              int pos = (*ci).var->get_position();
-              h.update_coef(cal.input_var(pos), (*ci).coef);
-              break;
-            }
-            case Global_Var:
-            {
-              Global_Var_ID g = (*ci).var->get_global_var();
-              Variable_ID v;
-              if (g->arity() == 0)
-                v = cal.get_local(g);
-              else
-                v = cal.get_local(g, (*ci).var->function_of());
-              h.update_coef(v, (*ci).coef);
-              break;
-            }
-            default:
-              throw loop_error("cannot calculate temporay array size statically");
-            }
-          }
-          h.update_const(lb_list[k].get_const());
-          
-          h.update_const(1);
-          h.update_coef(cal.output_var(1), -1);
-        }
-      
-      cal = Restrict_Domain(cal, copy(copy_is));
-      for (int j = 1; j <= cal.n_inp(); j++)
-        cal = Project(cal, j, Input_Var);
-      cal.simplify();
-      
-      // pad temporary array size
-      // TODO: for variable array size, create padding formula
-      Conjunct *c = cal.query_DNF()->single_conjunct();
-      bool is_index_bound_const = false;
-      for (GEQ_Iterator gi(c->GEQs()); gi && !is_index_bound_const; gi++)
-        if ((*gi).is_const(cal.output_var(1))) {
-          coef_t size = (*gi).get_const() / (-(*gi).get_coef(cal.output_var(1)));
-          if (padding_stride != 0) {
-            size = (size + index_stride[i] - 1) / index_stride[i];
-            if (i == fastest_changing_dimension)
-              size = size * padding_stride;
-          }
-          if (i == fastest_changing_dimension) {
-            if (padding_alignment > 1) { // align to boundary for data packing
-              int residue = size % padding_alignment;
-              if (residue)
-                size = size+padding_alignment-residue;
-            }
-            else if (padding_alignment < -1) {  // un-alignment for memory bank conflicts
-              while (gcd(size, static_cast<coef_t>(-padding_alignment)) != 1)
-                size++;
-            }
-          }
-          index_sz.push_back(std::make_pair(i, ocg->CreateInt(size)));
-          is_index_bound_const = true;
-        }
-      
-      if (!is_index_bound_const) {
-        for (GEQ_Iterator gi(c->GEQs()); gi && !is_index_bound_const; gi++) {
-          int coef = (*gi).get_coef(cal.output_var(1));
-          if (coef < 0) {
-            CG_outputRepr *op = NULL;
-            for (Constr_Vars_Iter ci(*gi); ci; ci++) {
-              if ((*ci).var != cal.output_var(1)) {
-                switch((*ci).var->kind()) {
-                case Global_Var:
-                {
-                  Global_Var_ID g = (*ci).var->get_global_var();
-                  if ((*ci).coef == 1)
-                    op = ocg->CreatePlus(op, ocg->CreateIdent(g->base_name()));
-                  else if ((*ci).coef == -1)
-                    op = ocg->CreateMinus(op, ocg->CreateIdent(g->base_name()));
-                  else if ((*ci).coef > 1)
-                    op = ocg->CreatePlus(op, ocg->CreateTimes(ocg->CreateInt((*ci).coef), ocg->CreateIdent(g->base_name())));
-                  else // (*ci).coef < -1
-                    op = ocg->CreateMinus(op, ocg->CreateTimes(ocg->CreateInt(-(*ci).coef), ocg->CreateIdent(g->base_name())));
-                  break;
-                }
-                default:
-                  throw loop_error("failed to generate array index bound code");
-                }
-              }
-            }
-            int c = (*gi).get_const();
-            if (c > 0)
-              op = ocg->CreatePlus(op, ocg->CreateInt(c));
-            else if (c < 0)
-              op = ocg->CreateMinus(op, ocg->CreateInt(-c));
-            if (padding_stride != 0) {
-              if (i == fastest_changing_dimension) {
-                coef_t g = gcd(index_stride[i], static_cast<coef_t>(padding_stride));
-                coef_t t1 = index_stride[i] / g;
-                if (t1 != 1)
-                  op = ocg->CreateIntegerFloor(ocg->CreatePlus(op, ocg->CreateInt(t1-1)), ocg->CreateInt(t1));
-                coef_t t2 = padding_stride / g;
-                if (t2 != 1)
-                  op = ocg->CreateTimes(op, ocg->CreateInt(t2));
-              }
-              else if (index_stride[i] != 1) {
-                op = ocg->CreateIntegerFloor(ocg->CreatePlus(op, ocg->CreateInt(index_stride[i]-1)), ocg->CreateInt(index_stride[i]));
-              }
-            }
-            
-            index_sz.push_back(std::make_pair(i, op));
-            break;
-          }
-        }
-      }
-    }
-  }
-  
-  // change the temporary array index order
-  for (int i = 0; i < index_sz.size(); i++)
-    if (index_sz[i].first == fastest_changing_dimension)
-      switch (sym->layout_type()) {
-      case IR_ARRAY_LAYOUT_ROW_MAJOR:
-        std::swap(index_sz[index_sz.size()-1], index_sz[i]);
-        break;
-      case IR_ARRAY_LAYOUT_COLUMN_MAJOR:
-        std::swap(index_sz[0], index_sz[i]);
-        break;
-      default:
-        throw loop_error("unsupported array layout");
-      }
-  
-  // declare temporary array or scalar
-  IR_Symbol *tmp_sym;
-  if (index_sz.size() == 0) {
-    tmp_sym = ir->CreateScalarSymbol(sym, memory_type);
-  }
-  else {
-    std::vector<CG_outputRepr *> tmp_array_size(index_sz.size());
-    for (int i = 0; i < index_sz.size(); i++)
-      tmp_array_size[i] = index_sz[i].second->clone();
-    tmp_sym = ir->CreateArraySymbol(sym, tmp_array_size, memory_type);
-  }
-  
-  // create temporary array read initialization code
-  CG_outputRepr *copy_code_read;
-  if (has_read_refs)
-    if (index_sz.size() == 0) {
-      IR_ScalarRef *tmp_scalar_ref = ir->CreateScalarRef(static_cast<IR_ScalarSymbol *>(tmp_sym));
-      
-      std::vector<CG_outputRepr *> rhs_index(n_dim);
-      for (int i = 0; i < index_lb.size(); i++)
-        if (is_index_eq[i])
-          rhs_index[i] = index_lb[i]->clone();
-        else
-          rhs_index[i] = ir->builder()->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+i+1)->name());
-      IR_ArrayRef *copied_array_ref = ir->CreateArrayRef(sym, rhs_index);
-      
-      copy_code_read = ir->builder()->CreateAssignment(0, tmp_scalar_ref->convert(), copied_array_ref->convert());
-    }
-    else {
-      std::vector<CG_outputRepr *> lhs_index(index_sz.size());
-      for (int i = 0; i < index_sz.size(); i++) {
-        int cur_index_num = index_sz[i].first;
-        CG_outputRepr *cur_index_repr = ocg->CreateMinus(ocg->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+cur_index_num+1)->name()), index_lb[cur_index_num]->clone());
-        if (padding_stride != 0) {
-          if (i == n_dim-1) {
-            coef_t g = gcd(index_stride[cur_index_num], static_cast<coef_t>(padding_stride));
-            coef_t t1 = index_stride[cur_index_num] / g;
-            if (t1 != 1)
-              cur_index_repr = ocg->CreateIntegerFloor(cur_index_repr, ocg->CreateInt(t1));
-            coef_t t2 = padding_stride / g;
-            if (t2 != 1)
-              cur_index_repr = ocg->CreateTimes(cur_index_repr, ocg->CreateInt(t2));
-          }
-          else if (index_stride[cur_index_num] != 1) {
-            cur_index_repr = ocg->CreateIntegerFloor(cur_index_repr, ocg->CreateInt(index_stride[cur_index_num]));
-          }
-        }
-        
-        if (ir->ArrayIndexStartAt() != 0)
-          cur_index_repr = ocg->CreatePlus(cur_index_repr, ocg->CreateInt(ir->ArrayIndexStartAt()));
-        lhs_index[i] = cur_index_repr;
-      }
-      
-      IR_ArrayRef *tmp_array_ref = ir->CreateArrayRef(static_cast<IR_ArraySymbol *>(tmp_sym), lhs_index);
-      
-      std::vector<CG_outputRepr *> rhs_index(n_dim);
-      for (int i = 0; i < index_lb.size(); i++)
-        if (is_index_eq[i])
-          rhs_index[i] = index_lb[i]->clone();
-        else
-          rhs_index[i] = ir->builder()->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+i+1)->name());
-      IR_ArrayRef *copied_array_ref = ir->CreateArrayRef(sym, rhs_index);
-      
-      copy_code_read = ir->builder()->CreateAssignment(0, tmp_array_ref->convert(), copied_array_ref->convert());
-    }
-  
-  // create temporary array write back code
-  CG_outputRepr *copy_code_write;
-  if (has_write_refs)
-    if (index_sz.size() == 0) {
-      IR_ScalarRef *tmp_scalar_ref = ir->CreateScalarRef(static_cast<IR_ScalarSymbol *>(tmp_sym));
-      
-      std::vector<CG_outputRepr *> rhs_index(n_dim);
-      for (int i = 0; i < index_lb.size(); i++)
-        if (is_index_eq[i])
-          rhs_index[i] = index_lb[i]->clone();
-        else
-          rhs_index[i] = ir->builder()->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+i+1)->name());
-      IR_ArrayRef *copied_array_ref = ir->CreateArrayRef(sym, rhs_index);
-      
-      copy_code_write = ir->builder()->CreateAssignment(0, copied_array_ref->convert(), tmp_scalar_ref->convert());
-    }
-    else {
-      std::vector<CG_outputRepr *> lhs_index(n_dim);
-      for (int i = 0; i < index_lb.size(); i++)
-        if (is_index_eq[i])
-          lhs_index[i] = index_lb[i]->clone();
-        else
-          lhs_index[i] = ir->builder()->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+i+1)->name());
-      IR_ArrayRef *copied_array_ref = ir->CreateArrayRef(sym, lhs_index);
-      
-      std::vector<CG_outputRepr *> rhs_index(index_sz.size());
-      for (int i = 0; i < index_sz.size(); i++) {
-        int cur_index_num = index_sz[i].first;
-        CG_outputRepr *cur_index_repr = ocg->CreateMinus(ocg->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+cur_index_num+1)->name()), index_lb[cur_index_num]->clone());
-        if (padding_stride != 0) {
-          if (i == n_dim-1) {
-            coef_t g = gcd(index_stride[cur_index_num], static_cast<coef_t>(padding_stride));
-            coef_t t1 = index_stride[cur_index_num] / g;
-            if (t1 != 1)
-              cur_index_repr = ocg->CreateIntegerFloor(cur_index_repr, ocg->CreateInt(t1));
-            coef_t t2 = padding_stride / g;
-            if (t2 != 1)
-              cur_index_repr = ocg->CreateTimes(cur_index_repr, ocg->CreateInt(t2));
-          }
-          else if (index_stride[cur_index_num] != 1) {
-            cur_index_repr = ocg->CreateIntegerFloor(cur_index_repr, ocg->CreateInt(index_stride[cur_index_num]));
-          }
-        }
-        
-        if (ir->ArrayIndexStartAt() != 0)
-          cur_index_repr = ocg->CreatePlus(cur_index_repr, ocg->CreateInt(ir->ArrayIndexStartAt()));
-        rhs_index[i] = cur_index_repr;
-      }
-      IR_ArrayRef *tmp_array_ref = ir->CreateArrayRef(static_cast<IR_ArraySymbol *>(tmp_sym), rhs_index);
-      
-      copy_code_write = ir->builder()->CreateAssignment(0, copied_array_ref->convert(), tmp_array_ref->convert());
-    }
-  
-  // now we can remove those loops for array indexes that are
-  // dependent on others
-  if (!(index_sz.size() == n_dim && (sym->layout_type() == IR_ARRAY_LAYOUT_ROW_MAJOR || n_dim <= 1))) {
-    Relation mapping(level-1+privatized_levels.size()+n_dim, level-1+privatized_levels.size()+index_sz.size());
-    F_And *f_root = mapping.add_and();
-    for (int i = 1; i <= level-1+privatized_levels.size(); i++) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(mapping.input_var(i), 1);
-      h.update_coef(mapping.output_var(i), -1);
-    }
-    
-    int cur_index = 0;
-    std::vector<int> mapped_index(index_sz.size());
-    for (int i = 0; i < n_dim; i++)
-      if (!is_index_eq[i]) {
-        EQ_Handle h = f_root->add_EQ();
-        h.update_coef(mapping.input_var(level-1+privatized_levels.size()+i+1), 1);
-        switch (sym->layout_type()) {
-        case IR_ARRAY_LAYOUT_COLUMN_MAJOR: {
-          h.update_coef(mapping.output_var(level-1+privatized_levels.size()+index_sz.size()-cur_index), -1);
-          mapped_index[index_sz.size()-cur_index-1] = i;
-          break;
-        }
-        case IR_ARRAY_LAYOUT_ROW_MAJOR: {
-          h.update_coef(mapping.output_var(level-1+privatized_levels.size()+cur_index+1), -1);
-          mapped_index[cur_index] = i;
-          break;
-        }
-        default:
-          throw loop_error("unsupported array layout");
-        }
-        cur_index++;
-      }
-    
-    wo_copy_is = Range(Restrict_Domain(copy(mapping), wo_copy_is));
-    ro_copy_is = Range(Restrict_Domain(copy(mapping), ro_copy_is));
-    for (int i = 1; i <= level-1+privatized_levels.size(); i++) {
-      wo_copy_is.name_set_var(i, copy_is.set_var(i)->name());
-      ro_copy_is.name_set_var(i, copy_is.set_var(i)->name());
-    }
-    for (int i = 0; i < index_sz.size(); i++) {
-      wo_copy_is.name_set_var(level-1+privatized_levels.size()+i+1, copy_is.set_var(level-1+privatized_levels.size()+mapped_index[i]+1)->name());
-      ro_copy_is.name_set_var(level-1+privatized_levels.size()+i+1, copy_is.set_var(level-1+privatized_levels.size()+mapped_index[i]+1)->name());
-    }
-    wo_copy_is.setup_names();
-    ro_copy_is.setup_names();
-  }
-  
-  // insert read copy statement
-  int old_num_stmt = stmt.size();
-  int ro_copy_stmt_num = -1;
-  if (has_read_refs) {
-    Relation copy_xform(ro_copy_is.n_set(), 2*ro_copy_is.n_set()+1);
-    {
-      F_And *f_root = copy_xform.add_and();
-      for (int i = 1; i <= ro_copy_is.n_set(); i++) {
-        EQ_Handle h = f_root->add_EQ();
-        h.update_coef(copy_xform.input_var(i), 1);
-        h.update_coef(copy_xform.output_var(2*i), -1);
-      }
-      for (int i = 1; i <= dim; i+=2) {
-        EQ_Handle h = f_root->add_EQ();
-        h.update_coef(copy_xform.output_var(i), -1);
-        h.update_const(lex[i-1]);
-      }
-      for (int i = dim+2; i <= copy_xform.n_out(); i+=2) {
-        EQ_Handle h = f_root->add_EQ();
-        h.update_coef(copy_xform.output_var(i), 1);
-      }
-    }
-    
-    Statement copy_stmt_read;
-    copy_stmt_read.IS = ro_copy_is;
-    copy_stmt_read.xform = copy_xform;
-    copy_stmt_read.code = copy_code_read;
-    copy_stmt_read.loop_level = std::vector<LoopLevel>(ro_copy_is.n_set());
-    copy_stmt_read.ir_stmt_node = NULL;
-    for (int i = 0; i < level-1; i++) {
-      copy_stmt_read.loop_level[i].type = stmt[*(active.begin())].loop_level[i].type;
-      if (stmt[*(active.begin())].loop_level[i].type == LoopLevelTile &&
-          stmt[*(active.begin())].loop_level[i].payload >= level) {
-        int j;
-        for (j = 0; j < privatized_levels.size(); j++)
-          if (privatized_levels[j] == stmt[*(active.begin())].loop_level[i].payload)
-            break;
-        if (j == privatized_levels.size())
-          copy_stmt_read.loop_level[i].payload = -1;
-        else
-          copy_stmt_read.loop_level[i].payload = level + j;
-      }
-      else
-        copy_stmt_read.loop_level[i].payload = stmt[*(active.begin())].loop_level[i].payload;
-      copy_stmt_read.loop_level[i].parallel_level = stmt[*(active.begin())].loop_level[i].parallel_level;
-    }
-    for (int i = 0; i < privatized_levels.size(); i++) {
-      copy_stmt_read.loop_level[level-1+i].type = stmt[*(active.begin())].loop_level[privatized_levels[i]].type;
-      copy_stmt_read.loop_level[level-1+i].payload = stmt[*(active.begin())].loop_level[privatized_levels[i]].payload;
-      copy_stmt_read.loop_level[level-1+i].parallel_level = stmt[*(active.begin())].loop_level[privatized_levels[i]].parallel_level;
-    }
-    int left_num_dim = num_dep_dim - (get_last_dep_dim_before(*(active.begin()), level) + 1);
-    for (int i = 0; i < min(left_num_dim, static_cast<int>(index_sz.size())); i++) {
-      copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].type = LoopLevelOriginal;
-      copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].payload = num_dep_dim-left_num_dim+i;
-      copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].parallel_level = 0;
-    }
-    for (int i = min(left_num_dim, static_cast<int>(index_sz.size())); i < index_sz.size(); i++) {
-      copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].type = LoopLevelUnknown;
-      copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].payload = -1;
-      copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].parallel_level = 0;
-    }
-    
-    
-    shiftLexicalOrder(lex, dim-1, 1);
-    stmt.push_back(copy_stmt_read);
-    ro_copy_stmt_num = stmt.size() - 1;
-    dep.insert();
-  }
-  
-  // insert write copy statement
-  int wo_copy_stmt_num = -1;
-  if (has_write_refs) {
-    Relation copy_xform(wo_copy_is.n_set(), 2*wo_copy_is.n_set()+1);
-    {
-      F_And *f_root = copy_xform.add_and();
-      for (int i = 1; i <= wo_copy_is.n_set(); i++) {
-        EQ_Handle h = f_root->add_EQ();
-        h.update_coef(copy_xform.input_var(i), 1);
-        h.update_coef(copy_xform.output_var(2*i), -1);
-      }
-      for (int i = 1; i <= dim; i+=2) {
-        EQ_Handle h = f_root->add_EQ();
-        h.update_coef(copy_xform.output_var(i), -1);
-        h.update_const(lex[i-1]);
-      }
-      for (int i = dim+2; i <= copy_xform.n_out(); i+=2) {
-        EQ_Handle h = f_root->add_EQ();
-        h.update_coef(copy_xform.output_var(i), 1);
-      }
-    }
-    
-    Statement copy_stmt_write;
-    copy_stmt_write.IS = wo_copy_is;
-    copy_stmt_write.xform = copy_xform;
-    copy_stmt_write.code = copy_code_write;
-    copy_stmt_write.loop_level = std::vector<LoopLevel>(wo_copy_is.n_set());
-    copy_stmt_write.ir_stmt_node = NULL;
-    
-    for (int i = 0; i < level-1; i++) {
-      copy_stmt_write.loop_level[i].type = stmt[*(active.begin())].loop_level[i].type;
-      if (stmt[*(active.begin())].loop_level[i].type == LoopLevelTile &&
-          stmt[*(active.begin())].loop_level[i].payload >= level) {
-        int j;
-        for (j = 0; j < privatized_levels.size(); j++)
-          if (privatized_levels[j] == stmt[*(active.begin())].loop_level[i].payload)
-            break;
-        if (j == privatized_levels.size())
-          copy_stmt_write.loop_level[i].payload = -1;
-        else
-          copy_stmt_write.loop_level[i].payload = level + j;
-      }
-      else
-        copy_stmt_write.loop_level[i].payload = stmt[*(active.begin())].loop_level[i].payload;
-      copy_stmt_write.loop_level[i].parallel_level = stmt[*(active.begin())].loop_level[i].parallel_level;
-    }
-    for (int i = 0; i < privatized_levels.size(); i++) {
-      copy_stmt_write.loop_level[level-1+i].type = stmt[*(active.begin())].loop_level[privatized_levels[i]].type;
-      copy_stmt_write.loop_level[level-1+i].payload = stmt[*(active.begin())].loop_level[privatized_levels[i]].payload;
-      copy_stmt_write.loop_level[level-1+i].parallel_level = stmt[*(active.begin())].loop_level[privatized_levels[i]].parallel_level;
-    }
-    int left_num_dim = num_dep_dim - (get_last_dep_dim_before(*(active.begin()), level) + 1);
-    for (int i = 0; i < min(left_num_dim, static_cast<int>(index_sz.size())); i++) {
-      copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].type = LoopLevelOriginal;
-      copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].payload = num_dep_dim-left_num_dim+i;
-      copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].parallel_level = 0;
-    }
-    for (int i = min(left_num_dim, static_cast<int>(index_sz.size())); i < index_sz.size(); i++) {
-      copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].type = LoopLevelUnknown;
-      copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].payload = -1;
-      copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].parallel_level = 0;
-    }
-    lex[dim-1]++;
-    shiftLexicalOrder(lex, dim-1, -2);
-    stmt.push_back(copy_stmt_write);
-    wo_copy_stmt_num = stmt.size() - 1;
-    dep.insert();
-  }
-  
-  // replace original array accesses with temporary array accesses
-  for (int i =0; i < stmt_refs.size(); i++)
-    for (int j = 0; j < stmt_refs[i].second.size(); j++) {
-      if (index_sz.size() == 0) {
-        IR_ScalarRef *tmp_scalar_ref = ir->CreateScalarRef(static_cast<IR_ScalarSymbol *>(tmp_sym));
-        ir->ReplaceExpression(stmt_refs[i].second[j], tmp_scalar_ref->convert());
-      }
-      else {
-        std::vector<CG_outputRepr *> index_repr(index_sz.size());
-        for (int k = 0; k < index_sz.size(); k++) {
-          int cur_index_num = index_sz[k].first;
-          
-          CG_outputRepr *cur_index_repr = ocg->CreateMinus(stmt_refs[i].second[j]->index(cur_index_num), index_lb[cur_index_num]->clone());
-          if (padding_stride != 0) {
-            if (k == n_dim-1) {
-              coef_t g = gcd(index_stride[cur_index_num], static_cast<coef_t>(padding_stride));
-              coef_t t1 = index_stride[cur_index_num] / g;
-              if (t1 != 1)
-                cur_index_repr = ocg->CreateIntegerFloor(cur_index_repr, ocg->CreateInt(t1));
-              coef_t t2 = padding_stride / g;
-              if (t2 != 1)
-                cur_index_repr = ocg->CreateTimes(cur_index_repr, ocg->CreateInt(t2));
-            }
-            else if (index_stride[cur_index_num] != 1) {
-              cur_index_repr = ocg->CreateIntegerFloor(cur_index_repr, ocg->CreateInt(index_stride[cur_index_num]));
-            }
-          }
-          
-          if (ir->ArrayIndexStartAt() != 0)
-            cur_index_repr = ocg->CreatePlus(cur_index_repr, ocg->CreateInt(ir->ArrayIndexStartAt()));
-          index_repr[k] = cur_index_repr;
-        }
-        
-        IR_ArrayRef *tmp_array_ref = ir->CreateArrayRef(static_cast<IR_ArraySymbol *>(tmp_sym), index_repr);
-        ir->ReplaceExpression(stmt_refs[i].second[j], tmp_array_ref->convert());
-      }
-    }
-  
-  // update dependence graph
-  int dep_dim = get_last_dep_dim_before(*(active.begin()), level) + 1;
-  if (ro_copy_stmt_num != -1) {
-    for (int i = 0; i < old_num_stmt; i++) {
-      std::vector<std::vector<DependenceVector> > D;
-      
-      for (DependenceGraph::EdgeList::iterator j = dep.vertex[i].second.begin(); j != dep.vertex[i].second.end();) {
-        if (active.find(i) != active.end() && active.find(j->first) == active.end()) {
-          std::vector<DependenceVector> dvs1, dvs2;
-          for (int k = 0; k < j->second.size(); k++) {
-            DependenceVector dv = j->second[k];
-            if (dv.sym != NULL && dv.sym->name() == sym->name() && (dv.type == DEP_R2R || dv.type == DEP_R2W))
-              dvs1.push_back(dv);
-            else
-              dvs2.push_back(dv);
-          }
-          j->second = dvs2;
-          if (dvs1.size() > 0)
-            dep.connect(ro_copy_stmt_num, j->first, dvs1);
-        }
-        else if (active.find(i) == active.end() && active.find(j->first) != active.end()) {
-          std::vector<DependenceVector> dvs1, dvs2;
-          for (int k = 0; k < j->second.size(); k++) {
-            DependenceVector dv = j->second[k];
-            if (dv.sym != NULL && dv.sym->name() == sym->name() && (dv.type == DEP_R2R || dv.type == DEP_W2R))
-              dvs1.push_back(dv);
-            else
-              dvs2.push_back(dv);
-          }
-          j->second = dvs2;
-          if (dvs1.size() > 0)
-            D.push_back(dvs1);
-        }
-        
-        if (j->second.size() == 0)
-          dep.vertex[i].second.erase(j++);
-        else
-          j++;
-      }
-      
-      for (int j = 0; j < D.size(); j++)
-        dep.connect(i, ro_copy_stmt_num, D[j]);
-    }
-    
-    // insert dependences from copy statement loop to copied statements
-    DependenceVector dv;
-    dv.type = DEP_W2R;
-    dv.sym = tmp_sym->clone();
-    dv.lbounds = std::vector<coef_t>(dep.num_dim(), 0);
-    dv.ubounds = std::vector<coef_t>(dep.num_dim(), 0);
-    for (int i = dep_dim; i < dep.num_dim(); i++) {
-      dv.lbounds[i] = -posInfinity;
-      dv.ubounds[i] = posInfinity;
-    }
-    for (std::set<int>::iterator i = active.begin(); i != active.end(); i++)
-      dep.connect(ro_copy_stmt_num, *i, dv);
-  }
-  
-  if (wo_copy_stmt_num != -1) {
-    for (int i = 0; i < old_num_stmt; i++) {
-      std::vector<std::vector<DependenceVector> > D;
-      
-      for (DependenceGraph::EdgeList::iterator j = dep.vertex[i].second.begin(); j != dep.vertex[i].second.end();) {
-        if (active.find(i) != active.end() && active.find(j->first) == active.end()) {
-          std::vector<DependenceVector> dvs1, dvs2;
-          for (int k = 0; k < j->second.size(); k++) {
-            DependenceVector dv = j->second[k];
-            if (dv.sym != NULL && dv.sym->name() == sym->name() && (dv.type == DEP_W2R || dv.type == DEP_W2W))
-              dvs1.push_back(dv);
-            else
-              dvs2.push_back(dv);
-          }
-          j->second = dvs2;
-          if (dvs1.size() > 0)
-            dep.connect(wo_copy_stmt_num, j->first, dvs1);
-        }
-        else if (active.find(i) == active.end() && active.find(j->first) != active.end()) {
-          std::vector<DependenceVector> dvs1, dvs2;
-          for (int k = 0; k < j->second.size(); k++) {
-            DependenceVector dv = j->second[k];
-            if (dv.sym != NULL && dv.sym->name() == sym->name() && (dv.type == DEP_R2W || dv.type == DEP_W2W))
-              dvs1.push_back(dv);
-            else
-              dvs2.push_back(dv);
-          }
-          j->second = dvs2;
-          if (dvs1.size() > 0)
-            D.push_back(dvs1);
-        }
-        
-        if (j->second.size() == 0)
-          dep.vertex[i].second.erase(j++);
-        else
-          j++;
-      }
-      
-      for (int j = 0; j < D.size(); j++)
-        dep.connect(i, wo_copy_stmt_num, D[j]);
-    }
-    
-    // insert dependences from copied statements to write statements
-    DependenceVector dv;
-    dv.type = DEP_W2R;
-    dv.sym = tmp_sym->clone();
-    dv.lbounds = std::vector<coef_t>(dep.num_dim(), 0);
-    dv.ubounds = std::vector<coef_t>(dep.num_dim(), 0);
-    for (int i = dep_dim; i < dep.num_dim(); i++) {
-      dv.lbounds[i] = -posInfinity;
-      dv.ubounds[i] = posInfinity;
-    }
-    for (std::set<int>::iterator i = active.begin(); i != active.end(); i++)
-      dep.connect(*i, wo_copy_stmt_num, dv);
-    
-  }
-  
-  // update variable name for dependences among copied statements
-  for (int i = 0; i < old_num_stmt; i++) {
-    if (active.find(i) != active.end())
-      for (DependenceGraph::EdgeList::iterator j = dep.vertex[i].second.begin(); j != dep.vertex[i].second.end(); j++)
-        if (active.find(j->first) != active.end())
-          for (int k = 0; k < j->second.size(); k++) {
-            IR_Symbol *s = tmp_sym->clone();
-            j->second[k].sym = s;
-          }
-  }
-  
-  // insert anti-dependence from write statement to read statement
-  if (ro_copy_stmt_num != -1 && wo_copy_stmt_num != -1)
-    if (dep_dim >= 0) {
-      DependenceVector dv;
-      dv.type = DEP_R2W;
-      dv.sym = tmp_sym->clone();
-      dv.lbounds = std::vector<coef_t>(dep.num_dim(), 0);
-      dv.ubounds = std::vector<coef_t>(dep.num_dim(), 0);
-      for (int k = dep_dim; k < dep.num_dim(); k++) {
-        dv.lbounds[k] = -posInfinity;
-        dv.ubounds[k] = posInfinity;
-      }
-      for (int k = 0; k < dep_dim; k++) {
-        if (k != 0) {
-          dv.lbounds[k-1] = 0;
-          dv.ubounds[k-1] = 0;
-        }
-        dv.lbounds[k] = 1;
-        dv.ubounds[k] = posInfinity;
-        dep.connect(wo_copy_stmt_num, ro_copy_stmt_num, dv);
-      }
-    }
-  
-  // cleanup
-  delete sym;
-  delete tmp_sym;
-  for (int i = 0; i < index_lb.size(); i++) {
-    index_lb[i]->clear();
-    delete index_lb[i];
-  }
-  for (int i = 0; i < index_sz.size(); i++) {
-    index_sz[i].second->clear();
-    delete index_sz[i].second;
-  }
-  
-  return true;
-}
diff --git a/chill/src/loop_extra.cc b/chill/src/loop_extra.cc
deleted file mode 100644
index dac05bf..0000000
--- a/chill/src/loop_extra.cc
+++ /dev/null
@@ -1,224 +0,0 @@
-/*****************************************************************************
- Copyright (C) 2010 University of Utah
- All Rights Reserved.
-
- Purpose:
-   Additional loop transformations.
-
- Notes:
-
- History:
-   07/31/10 Created by Chun Chen
-*****************************************************************************/
-
-#include <code_gen/codegen.h>
-#include <code_gen/CG_utils.h>
-#include "loop.hh"
-#include "omegatools.hh"
-#include "ir_code.hh"
-#include "chill_error.hh"
-
-using namespace omega;
-
-
-void Loop::shift_to(int stmt_num, int level, int absolute_position) {
-  // combo
-  tile(stmt_num, level, 1, level, CountedTile);
-  std::vector<int> lex = getLexicalOrder(stmt_num);
-  std::set<int> active = getStatements(lex, 2*level-2);
-  shift(active, level, absolute_position);
-  
-  // remove unnecessary tiled loop since tile size is one
-  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++) {
-    int n = stmt[*i].xform.n_out();
-    Relation mapping(n, n-2);
-    F_And *f_root = mapping.add_and();
-    for (int j = 1; j <= 2*level; j++) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(mapping.output_var(j), 1);
-      h.update_coef(mapping.input_var(j), -1);
-    }
-    for (int j = 2*level+3; j <= n; j++) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(mapping.output_var(j-2), 1);
-      h.update_coef(mapping.input_var(j), -1);
-    }
-    stmt[*i].xform = Composition(mapping, stmt[*i].xform);
-    stmt[*i].xform.simplify();
-    
-    for (int j = 0; j < stmt[*i].loop_level.size(); j++)
-      if (j != level-1 &&
-          stmt[*i].loop_level[j].type == LoopLevelTile &&
-          stmt[*i].loop_level[j].payload >= level)
-        stmt[*i].loop_level[j].payload--;
-    
-    stmt[*i].loop_level.erase(stmt[*i].loop_level.begin()+level-1);
-  }
-}
-
-
-std::set<int> Loop::unroll_extra(int stmt_num, int level, int unroll_amount, int cleanup_split_level) {
-  std::set<int> cleanup_stmts = unroll(stmt_num, level, unroll_amount,std::vector< std::vector<std::string> >(), cleanup_split_level);
-  for (std::set<int>::iterator i = cleanup_stmts.begin(); i != cleanup_stmts.end(); i++)
-    unroll(*i, level, 0);
-  
-  return cleanup_stmts;
-}
-
-void Loop::peel(int stmt_num, int level, int peel_amount) {
-  // check for sanity of parameters
-  if (stmt_num < 0 || stmt_num >= stmt.size())
-    throw std::invalid_argument("invalid statement number " + to_string(stmt_num));
-  if (level <= 0 || level > stmt[stmt_num].loop_level.size())
-    throw std::invalid_argument("invalid loop level " + to_string(level));
-  
-  if (peel_amount == 0)
-    return;
-  
-  std::set<int> subloop = getSubLoopNest(stmt_num, level);
-  std::vector<Relation> Rs;
-  for (std::set<int>::iterator i = subloop.begin(); i != subloop.end(); i++) {
-    Relation r = getNewIS(*i);
-    Relation f(r.n_set(), level);
-    F_And *f_root = f.add_and();
-    for (int j = 1; j <= level; j++) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(f.input_var(2*j), 1);
-      h.update_coef(f.output_var(j), -1);
-    }
-    r = Composition(f, r);
-    r.simplify();
-    Rs.push_back(r);
-  }
-  Relation hull = SimpleHull(Rs);
-  
-  if (peel_amount > 0) {
-    GEQ_Handle bound_eq;
-    bool found_bound = false;
-    for (GEQ_Iterator e(hull.single_conjunct()->GEQs()); e; e++)
-      if (!(*e).has_wildcards() && (*e).get_coef(hull.set_var(level)) > 0) {
-        bound_eq = *e;
-        found_bound = true;
-        break;
-      }
-    if (!found_bound)
-      for (GEQ_Iterator e(hull.single_conjunct()->GEQs()); e; e++)
-        if ((*e).has_wildcards() && (*e).get_coef(hull.set_var(level)) > 0) {
-          bool is_bound = true;
-          for (Constr_Vars_Iter cvi(*e, true); cvi; cvi++) {
-            std::pair<bool, GEQ_Handle> result = find_floor_definition(hull, cvi.curr_var());
-            if (!result.first) {
-              is_bound = false;
-              break;
-            }
-          }
-          if (is_bound) {
-            bound_eq = *e;
-            found_bound = true;
-            break;
-          }
-        }
-    if (!found_bound)
-      throw loop_error("can't find lower bound for peeling at loop level " + to_string(level));
-    
-    for (int i = 1; i <= peel_amount; i++) {
-      Relation r(level);
-      F_Exists *f_exists = r.add_and()->add_exists();
-      F_And *f_root = f_exists->add_and();
-      GEQ_Handle h = f_root->add_GEQ();
-      std::map<Variable_ID, Variable_ID> exists_mapping;
-      for (Constr_Vars_Iter cvi(bound_eq); cvi; cvi++)
-        switch (cvi.curr_var()->kind()) {
-        case Input_Var:
-          h.update_coef(r.set_var(cvi.curr_var()->get_position()), cvi.curr_coef());
-          break;
-        case Wildcard_Var: {
-          Variable_ID v = replicate_floor_definition(hull, cvi.curr_var(), r, f_exists, f_root, exists_mapping);
-          h.update_coef(v, 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(bound_eq.get_const() - i);
-      r.simplify();
-      
-      split(stmt_num, level, r);
-    }
-  }
-  else { // peel_amount < 0
-    GEQ_Handle bound_eq;
-    bool found_bound = false;
-    for (GEQ_Iterator e(hull.single_conjunct()->GEQs()); e; e++)
-      if (!(*e).has_wildcards() && (*e).get_coef(hull.set_var(level)) < 0) {
-        bound_eq = *e;
-        found_bound = true;
-        break;
-      }
-    if (!found_bound)
-      for (GEQ_Iterator e(hull.single_conjunct()->GEQs()); e; e++)
-        if ((*e).has_wildcards() && (*e).get_coef(hull.set_var(level)) < 0) {
-          bool is_bound = true;
-          for (Constr_Vars_Iter cvi(*e, true); cvi; cvi++) {
-            std::pair<bool, GEQ_Handle> result = find_floor_definition(hull, cvi.curr_var());
-            if (!result.first) {
-              is_bound = false;
-              break;
-            }
-          }
-          if (is_bound) {
-            bound_eq = *e;
-            found_bound = true;
-            break;
-          }
-        }
-    if (!found_bound)
-      throw loop_error("can't find upper bound for peeling at loop level " + to_string(level));
-    
-    for (int i = 1; i <= -peel_amount; i++) {
-      Relation r(level);
-      F_Exists *f_exists = r.add_and()->add_exists();
-      F_And *f_root = f_exists->add_and();
-      GEQ_Handle h = f_root->add_GEQ();
-      std::map<Variable_ID, Variable_ID> exists_mapping;
-      for (Constr_Vars_Iter cvi(bound_eq); cvi; cvi++)
-        switch (cvi.curr_var()->kind()) {
-        case Input_Var:
-          h.update_coef(r.set_var(cvi.curr_var()->get_position()), cvi.curr_coef());
-          break;
-        case Wildcard_Var: {
-          Variable_ID v = replicate_floor_definition(hull, cvi.curr_var(), r, f_exists, f_root, exists_mapping);
-          h.update_coef(v, 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(bound_eq.get_const() - i);
-      r.simplify();
-      
-      split(stmt_num, level, r);
-    }
-  }
-}
-
diff --git a/chill/src/loop_tile.cc b/chill/src/loop_tile.cc
deleted file mode 100644
index aae8dd8..0000000
--- a/chill/src/loop_tile.cc
+++ /dev/null
@@ -1,630 +0,0 @@
-/*
- * loop_tile.cc
- *
- *  Created on: Nov 12, 2012
- *      Author: anand
- */
-
-#include <code_gen/codegen.h>
-#include "loop.hh"
-#include "omegatools.hh"
-#include "ir_code.hh"
-#include "chill_error.hh"
-
-using namespace omega;
-
-
-
-
-void Loop::tile(int stmt_num, int level, int tile_size, int outer_level,
-                TilingMethodType method, int alignment_offset, int alignment_multiple) {
-  // check for sanity of parameters
-  if (tile_size < 0)
-    throw std::invalid_argument("invalid tile size");
-  if (alignment_multiple < 1 || alignment_offset < 0)
-    throw std::invalid_argument("invalid alignment for tile");
-  if (stmt_num < 0 || stmt_num >= stmt.size())
-    throw std::invalid_argument("invalid statement " + to_string(stmt_num));
-  if (level <= 0)
-    throw std::invalid_argument("invalid loop level " + to_string(level));
-  if (level > stmt[stmt_num].loop_level.size())
-    throw std::invalid_argument(
-      "there is no loop level " + to_string(level) + " for statement "
-      + to_string(stmt_num));
-  if (outer_level <= 0 || outer_level > level)
-    throw std::invalid_argument(
-      "invalid tile controlling loop level "
-      + to_string(outer_level));
-  
-  // invalidate saved codegen computation
-  delete last_compute_cgr_;
-  last_compute_cgr_ = NULL;
-  delete last_compute_cg_;
-  last_compute_cg_ = NULL;
-  
-  int dim = 2 * level - 1;
-  int outer_dim = 2 * outer_level - 1;
-  std::vector<int> lex = getLexicalOrder(stmt_num);
-  std::set<int> same_tiled_loop = getStatements(lex, dim - 1);
-  std::set<int> same_tile_controlling_loop = getStatements(lex,
-                                                           outer_dim - 1);
-  
-  for (std::set<int>::iterator i = same_tiled_loop.begin();
-       i != same_tiled_loop.end(); i++) {
-    for (DependenceGraph::EdgeList::iterator j =
-           dep.vertex[*i].second.begin(); j != dep.vertex[*i].second.end();
-         j++) {
-      if (same_tiled_loop.find(j->first) != same_tiled_loop.end())
-        for (int k = 0; k < j->second.size(); k++) {
-          DependenceVector dv = j->second[k];
-          int dim2 = level - 1;
-          if ((dv.type != DEP_CONTROL) && (dv.type != DEP_UNKNOWN)) {
-            while (stmt[*i].loop_level[dim2].type == LoopLevelTile) {
-              dim2 = stmt[*i].loop_level[dim2].payload - 1;
-            }
-            dim2 = stmt[*i].loop_level[dim2].payload;
-            
-            if (dv.hasNegative(dim2) && (!dv.quasi)) {
-              for (int l = outer_level; l < level; l++)
-                if (stmt[*i].loop_level[l - 1].type
-                    != LoopLevelTile) {
-                  if (dv.isCarried(
-                        stmt[*i].loop_level[l - 1].payload)
-                      && dv.hasPositive(
-                        stmt[*i].loop_level[l - 1].payload))
-                    throw loop_error(
-                      "loop error: Tiling is illegal, dependence violation!");
-                } else {
-                  
-                  int dim3 = l - 1;
-                  while (stmt[*i].loop_level[l - 1].type
-                         != LoopLevelTile) {
-                    dim3 =
-                      stmt[*i].loop_level[l - 1].payload
-                      - 1;
-                    
-                  }
-                  
-                  dim3 = stmt[*i].loop_level[l - 1].payload;
-                  if (dim3 < level - 1)
-                    if (dv.isCarried(dim3)
-                        && dv.hasPositive(dim3))
-                      throw loop_error(
-                        "loop error: Tiling is illegal, dependence violation!");
-                }
-            }
-          }
-        }
-    }
-  }
-  // special case for no tiling
-  if (tile_size == 0) {
-    for (std::set<int>::iterator i = same_tile_controlling_loop.begin();
-         i != same_tile_controlling_loop.end(); i++) {
-      Relation r(stmt[*i].xform.n_out(), stmt[*i].xform.n_out() + 2);
-      F_And *f_root = r.add_and();
-      for (int j = 1; j <= 2 * outer_level - 1; j++) {
-        EQ_Handle h = f_root->add_EQ();
-        h.update_coef(r.input_var(j), 1);
-        h.update_coef(r.output_var(j), -1);
-      }
-      EQ_Handle h1 = f_root->add_EQ();
-      h1.update_coef(r.output_var(2 * outer_level), 1);
-      EQ_Handle h2 = f_root->add_EQ();
-      h2.update_coef(r.output_var(2 * outer_level + 1), 1);
-      for (int j = 2 * outer_level; j <= stmt[*i].xform.n_out(); j++) {
-        EQ_Handle h = f_root->add_EQ();
-        h.update_coef(r.input_var(j), 1);
-        h.update_coef(r.output_var(j + 2), -1);
-      }
-      
-      stmt[*i].xform = Composition(copy(r), stmt[*i].xform);
-    }
-  }
-  // normal tiling
-  else {
-    std::set<int> private_stmt;
-    for (std::set<int>::iterator i = same_tile_controlling_loop.begin();
-         i != same_tile_controlling_loop.end(); i++) {
-//     if (same_tiled_loop.find(*i) == same_tiled_loop.end() && !is_single_iteration(getNewIS(*i), dim))
-//       same_tiled_loop.insert(*i);
-      
-      // should test dim's value directly but it is ok for now
-//    if (same_tiled_loop.find(*i) == same_tiled_loop.end() && get_const(stmt[*i].xform, dim+1, Output_Var) == posInfinity)
-      if (same_tiled_loop.find(*i) == same_tiled_loop.end()
-          && overflow.find(*i) != overflow.end())
-        private_stmt.insert(*i);
-    }
-    
-    // extract the union of the iteration space to be considered
-    Relation hull;
-    /*{
-      Tuple < Relation > r_list;
-      Tuple<int> r_mask;
-      
-      for (std::set<int>::iterator i = same_tile_controlling_loop.begin();
-      i != same_tile_controlling_loop.end(); i++)
-      if (private_stmt.find(*i) == private_stmt.end()) {
-      Relation r = project_onto_levels(getNewIS(*i), dim + 1,
-      true);
-      for (int j = outer_dim; j < dim; j++)
-      r = Project(r, j + 1, Set_Var);
-      for (int j = 0; j < outer_dim; j += 2)
-      r = Project(r, j + 1, Set_Var);
-      r_list.append(r);
-      r_mask.append(1);
-      }
-      
-      hull = Hull(r_list, r_mask, 1, true);
-      }*/
-    
-    {
-      std::vector<Relation> r_list;
-      
-      for (std::set<int>::iterator i = same_tile_controlling_loop.begin();
-           i != same_tile_controlling_loop.end(); i++)
-        if (private_stmt.find(*i) == private_stmt.end()) {
-          Relation r = getNewIS(*i);
-          for (int j = dim + 2; j <= r.n_set(); j++)
-            r = Project(r, r.set_var(j));
-          for (int j = outer_dim; j < dim; j++)
-            r = Project(r, j + 1, Set_Var);
-          for (int j = 0; j < outer_dim; j += 2)
-            r = Project(r, j + 1, Set_Var);
-          r.simplify(2, 4);
-          r_list.push_back(r);
-        }
-      
-      hull = SimpleHull(r_list);
-      // hull = Hull(r_list, std::vector<bool>(r_list.size(), true), 1, true);
-    }
-    
-    // extract the bound of the dimension to be tiled
-    Relation bound = get_loop_bound(hull, dim);
-    if (!bound.has_single_conjunct()) {
-      // further simplify the bound
-      hull = Approximate(hull);
-      bound = get_loop_bound(hull, dim);
-      
-      int i = outer_dim - 2;
-      while (!bound.has_single_conjunct() && i >= 0) {
-        hull = Project(hull, i + 1, Set_Var);
-        bound = get_loop_bound(hull, dim);
-        i -= 2;
-      }
-      
-      if (!bound.has_single_conjunct())
-        throw loop_error("cannot handle tile bounds");
-    }
-    
-    // separate lower and upper bounds
-    std::vector<GEQ_Handle> lb_list, ub_list;
-    {
-      Conjunct *c = bound.query_DNF()->single_conjunct();
-      for (GEQ_Iterator gi(c->GEQs()); gi; gi++) {
-        int coef = (*gi).get_coef(bound.set_var(dim + 1));
-        if (coef < 0)
-          ub_list.push_back(*gi);
-        else if (coef > 0)
-          lb_list.push_back(*gi);
-      }
-    }
-    if (lb_list.size() == 0)
-      throw loop_error(
-        "unable to calculate tile controlling loop lower bound");
-    if (ub_list.size() == 0)
-      throw loop_error(
-        "unable to calculate tile controlling loop upper bound");
-    
-    // find the simplest lower bound for StridedTile or simplest iteration count for CountedTile
-    int simplest_lb = 0, simplest_ub = 0;
-    if (method == StridedTile) {
-      int best_cost = INT_MAX;
-      for (int i = 0; i < lb_list.size(); i++) {
-        int cost = 0;
-        for (Constr_Vars_Iter ci(lb_list[i]); ci; ci++) {
-          switch ((*ci).var->kind()) {
-          case Input_Var: {
-            cost += 5;
-            break;
-          }
-          case Global_Var: {
-            cost += 2;
-            break;
-          }
-          default:
-            cost += 15;
-            break;
-          }
-        }
-        
-        if (cost < best_cost) {
-          best_cost = cost;
-          simplest_lb = i;
-        }
-      }
-    } else if (method == CountedTile) {
-      std::map<Variable_ID, coef_t> s1, s2, s3;
-      int best_cost = INT_MAX;
-      for (int i = 0; i < lb_list.size(); i++)
-        for (int j = 0; j < ub_list.size(); j++) {
-          int cost = 0;
-          
-          for (Constr_Vars_Iter ci(lb_list[i]); ci; ci++) {
-            switch ((*ci).var->kind()) {
-            case Input_Var: {
-              s1[(*ci).var] += (*ci).coef;
-              break;
-            }
-            case Global_Var: {
-              s2[(*ci).var] += (*ci).coef;
-              break;
-            }
-            case Exists_Var:
-            case Wildcard_Var: {
-              s3[(*ci).var] += (*ci).coef;
-              break;
-            }
-            default:
-              cost = INT_MAX - 2;
-              break;
-            }
-          }
-          
-          for (Constr_Vars_Iter ci(ub_list[j]); ci; ci++) {
-            switch ((*ci).var->kind()) {
-            case Input_Var: {
-              s1[(*ci).var] += (*ci).coef;
-              break;
-            }
-            case Global_Var: {
-              s2[(*ci).var] += (*ci).coef;
-              break;
-            }
-            case Exists_Var:
-            case Wildcard_Var: {
-              s3[(*ci).var] += (*ci).coef;
-              break;
-            }
-            default:
-              if (cost == INT_MAX - 2)
-                cost = INT_MAX - 1;
-              else
-                cost = INT_MAX - 3;
-              break;
-            }
-          }
-          
-          if (cost == 0) {
-            for (std::map<Variable_ID, coef_t>::iterator k =
-                   s1.begin(); k != s1.end(); k++)
-              if ((*k).second != 0)
-                cost += 5;
-            for (std::map<Variable_ID, coef_t>::iterator k =
-                   s2.begin(); k != s2.end(); k++)
-              if ((*k).second != 0)
-                cost += 2;
-            for (std::map<Variable_ID, coef_t>::iterator k =
-                   s3.begin(); k != s3.end(); k++)
-              if ((*k).second != 0)
-                cost += 15;
-          }
-          
-          if (cost < best_cost) {
-            best_cost = cost;
-            simplest_lb = i;
-            simplest_ub = j;
-          }
-        }
-    }
-    
-    // prepare the new transformation relations
-    for (std::set<int>::iterator i = same_tile_controlling_loop.begin();
-         i != same_tile_controlling_loop.end(); i++) {
-      Relation r(stmt[*i].xform.n_out(), stmt[*i].xform.n_out() + 2);
-      F_And *f_root = r.add_and();
-      for (int j = 0; j < outer_dim - 1; j++) {
-        EQ_Handle h = f_root->add_EQ();
-        h.update_coef(r.output_var(j + 1), 1);
-        h.update_coef(r.input_var(j + 1), -1);
-      }
-      
-      for (int j = outer_dim - 1; j < stmt[*i].xform.n_out(); j++) {
-        EQ_Handle h = f_root->add_EQ();
-        h.update_coef(r.output_var(j + 3), 1);
-        h.update_coef(r.input_var(j + 1), -1);
-      }
-      
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(r.output_var(outer_dim), 1);
-      h.update_const(-lex[outer_dim - 1]);
-      
-      stmt[*i].xform = Composition(r, stmt[*i].xform);
-    }
-    
-    // add tiling constraints.
-    for (std::set<int>::iterator i = same_tile_controlling_loop.begin();
-         i != same_tile_controlling_loop.end(); i++) {
-      F_And *f_super_root = stmt[*i].xform.and_with_and();
-      F_Exists *f_exists = f_super_root->add_exists();
-      F_And *f_root = f_exists->add_and();
-      
-      // create a lower bound variable for easy formula creation later
-      Variable_ID aligned_lb;
-      {
-        Variable_ID lb = f_exists->declare();
-        coef_t coef = lb_list[simplest_lb].get_coef(
-          bound.set_var(dim + 1));
-        if (coef == 1) { // e.g. if i >= m+5, then LB = m+5
-          EQ_Handle h = f_root->add_EQ();
-          h.update_coef(lb, 1);
-          for (Constr_Vars_Iter ci(lb_list[simplest_lb]); ci; ci++) {
-            switch ((*ci).var->kind()) {
-            case Input_Var: {
-              int pos = (*ci).var->get_position();
-              if (pos != dim + 1)
-                h.update_coef(stmt[*i].xform.output_var(pos),
-                              (*ci).coef);
-              break;
-            }
-            case Global_Var: {
-              Global_Var_ID g = (*ci).var->get_global_var();
-              Variable_ID v;
-              if (g->arity() == 0)
-                v = stmt[*i].xform.get_local(g);
-              else
-                v = stmt[*i].xform.get_local(g,
-                                             (*ci).var->function_of());
-              h.update_coef(v, (*ci).coef);
-              break;
-            }
-            default:
-              throw loop_error("cannot handle tile bounds");
-            }
-          }
-          h.update_const(lb_list[simplest_lb].get_const());
-        } else { // e.g. if 2i >= m+5, then m+5 <= 2*LB < m+5+2
-          GEQ_Handle h1 = f_root->add_GEQ();
-          GEQ_Handle h2 = f_root->add_GEQ();
-          for (Constr_Vars_Iter ci(lb_list[simplest_lb]); ci; ci++) {
-            switch ((*ci).var->kind()) {
-            case Input_Var: {
-              int pos = (*ci).var->get_position();
-              if (pos == dim + 1) {
-                h1.update_coef(lb, (*ci).coef);
-                h2.update_coef(lb, -(*ci).coef);
-              } else {
-                h1.update_coef(stmt[*i].xform.output_var(pos),
-                               (*ci).coef);
-                h2.update_coef(stmt[*i].xform.output_var(pos),
-                               -(*ci).coef);
-              }
-              break;
-            }
-            case Global_Var: {
-              Global_Var_ID g = (*ci).var->get_global_var();
-              Variable_ID v;
-              if (g->arity() == 0)
-                v = stmt[*i].xform.get_local(g);
-              else
-                v = stmt[*i].xform.get_local(g,
-                                             (*ci).var->function_of());
-              h1.update_coef(v, (*ci).coef);
-              h2.update_coef(v, -(*ci).coef);
-              break;
-            }
-            default:
-              throw loop_error("cannot handle tile bounds");
-            }
-          }
-          h1.update_const(lb_list[simplest_lb].get_const());
-          h2.update_const(-lb_list[simplest_lb].get_const());
-          h2.update_const(coef - 1);
-        }
-        
-        Variable_ID offset_lb;
-        if (alignment_offset == 0)
-          offset_lb = lb;
-        else {
-          EQ_Handle h = f_root->add_EQ();
-          offset_lb = f_exists->declare();
-          h.update_coef(offset_lb, 1);
-          h.update_coef(lb, -1);
-          h.update_const(alignment_offset);
-        }
-        
-        if (alignment_multiple == 1) { // trivial
-          aligned_lb = offset_lb;
-        } else { // e.g. to align at 4, aligned_lb = 4*alpha && LB-4 < 4*alpha <= LB
-          aligned_lb = f_exists->declare();
-          Variable_ID e = f_exists->declare();
-          
-          EQ_Handle h = f_root->add_EQ();
-          h.update_coef(aligned_lb, 1);
-          h.update_coef(e, -alignment_multiple);
-          
-          GEQ_Handle h1 = f_root->add_GEQ();
-          GEQ_Handle h2 = f_root->add_GEQ();
-          h1.update_coef(e, alignment_multiple);
-          h2.update_coef(e, -alignment_multiple);
-          h1.update_coef(offset_lb, -1);
-          h2.update_coef(offset_lb, 1);
-          h1.update_const(alignment_multiple - 1);
-        }
-      }
-      
-      // create an upper bound variable for easy formula creation later
-      Variable_ID ub = f_exists->declare();
-      {
-        coef_t coef = -ub_list[simplest_ub].get_coef(
-          bound.set_var(dim + 1));
-        if (coef == 1) { // e.g. if i <= m+5, then UB = m+5
-          EQ_Handle h = f_root->add_EQ();
-          h.update_coef(ub, -1);
-          for (Constr_Vars_Iter ci(ub_list[simplest_ub]); ci; ci++) {
-            switch ((*ci).var->kind()) {
-            case Input_Var: {
-              int pos = (*ci).var->get_position();
-              if (pos != dim + 1)
-                h.update_coef(stmt[*i].xform.output_var(pos),
-                              (*ci).coef);
-              break;
-            }
-            case Global_Var: {
-              Global_Var_ID g = (*ci).var->get_global_var();
-              Variable_ID v;
-              if (g->arity() == 0)
-                v = stmt[*i].xform.get_local(g);
-              else
-                v = stmt[*i].xform.get_local(g,
-                                             (*ci).var->function_of());
-              h.update_coef(v, (*ci).coef);
-              break;
-            }
-            default:
-              throw loop_error("cannot handle tile bounds");
-            }
-          }
-          h.update_const(ub_list[simplest_ub].get_const());
-        } else { // e.g. if 2i <= m+5, then m+5-2 < 2*UB <= m+5
-          GEQ_Handle h1 = f_root->add_GEQ();
-          GEQ_Handle h2 = f_root->add_GEQ();
-          for (Constr_Vars_Iter ci(ub_list[simplest_ub]); ci; ci++) {
-            switch ((*ci).var->kind()) {
-            case Input_Var: {
-              int pos = (*ci).var->get_position();
-              if (pos == dim + 1) {
-                h1.update_coef(ub, -(*ci).coef);
-                h2.update_coef(ub, (*ci).coef);
-              } else {
-                h1.update_coef(stmt[*i].xform.output_var(pos),
-                               -(*ci).coef);
-                h2.update_coef(stmt[*i].xform.output_var(pos),
-                               (*ci).coef);
-              }
-              break;
-            }
-            case Global_Var: {
-              Global_Var_ID g = (*ci).var->get_global_var();
-              Variable_ID v;
-              if (g->arity() == 0)
-                v = stmt[*i].xform.get_local(g);
-              else
-                v = stmt[*i].xform.get_local(g,
-                                             (*ci).var->function_of());
-              h1.update_coef(v, -(*ci).coef);
-              h2.update_coef(v, (*ci).coef);
-              break;
-            }
-            default:
-              throw loop_error("cannot handle tile bounds");
-            }
-          }
-          h1.update_const(-ub_list[simplest_ub].get_const());
-          h2.update_const(ub_list[simplest_ub].get_const());
-          h1.update_const(coef - 1);
-        }
-      }
-      
-      // insert tile controlling loop constraints
-      if (method == StridedTile) { // e.g. ii = LB + 32 * alpha && alpha >= 0
-        Variable_ID e = f_exists->declare();
-        GEQ_Handle h1 = f_root->add_GEQ();
-        h1.update_coef(e, 1);
-        
-        EQ_Handle h2 = f_root->add_EQ();
-        h2.update_coef(stmt[*i].xform.output_var(outer_dim + 1), 1);
-        h2.update_coef(e, -tile_size);
-        h2.update_coef(aligned_lb, -1);
-      } else if (method == CountedTile) { // e.g. 0 <= ii < ceiling((UB-LB+1)/32)
-        GEQ_Handle h1 = f_root->add_GEQ();
-        h1.update_coef(stmt[*i].xform.output_var(outer_dim + 1), 1);
-        
-        GEQ_Handle h2 = f_root->add_GEQ();
-        h2.update_coef(stmt[*i].xform.output_var(outer_dim + 1),
-                       -tile_size);
-        h2.update_coef(aligned_lb, -1);
-        h2.update_coef(ub, 1);
-      }
-      
-      // special care for private statements like overflow assignment
-      if (private_stmt.find(*i) != private_stmt.end()) { // e.g. ii <= UB
-        GEQ_Handle h = f_root->add_GEQ();
-        h.update_coef(stmt[*i].xform.output_var(outer_dim + 1), -1);
-        h.update_coef(ub, 1);
-      }
-      // if (private_stmt.find(*i) != private_stmt.end()) {
-      //   if (stmt[*i].xform.n_out() > dim+3) { // e.g. ii <= UB && i = ii
-      //     GEQ_Handle h = f_root->add_GEQ();
-      //     h.update_coef(stmt[*i].xform.output_var(outer_dim+1), -1);
-      //     h.update_coef(ub, 1);
-      
-      //     stmt[*i].xform = Project(stmt[*i].xform, dim+3, Output_Var);
-      //     f_root = stmt[*i].xform.and_with_and();
-      //     EQ_Handle h1 = f_root->add_EQ();
-      //     h1.update_coef(stmt[*i].xform.output_var(dim+3), 1);
-      //     h1.update_coef(stmt[*i].xform.output_var(outer_dim+1), -1);
-      //   }
-      //   else if (method == StridedTile) { // e.g. ii <= UB since i does not exist
-      //     GEQ_Handle h = f_root->add_GEQ();
-      //     h.update_coef(stmt[*i].xform.output_var(outer_dim+1), -1);
-      //     h.update_coef(ub, 1);
-      //   }
-      // }
-      
-      // restrict original loop index inside the tile
-      else {
-        if (method == StridedTile) { // e.g. ii <= i < ii + tile_size
-          GEQ_Handle h1 = f_root->add_GEQ();
-          h1.update_coef(stmt[*i].xform.output_var(dim + 3), 1);
-          h1.update_coef(stmt[*i].xform.output_var(outer_dim + 1),
-                         -1);
-          
-          GEQ_Handle h2 = f_root->add_GEQ();
-          h2.update_coef(stmt[*i].xform.output_var(dim + 3), -1);
-          h2.update_coef(stmt[*i].xform.output_var(outer_dim + 1), 1);
-          h2.update_const(tile_size - 1);
-        } else if (method == CountedTile) { // e.g. LB+32*ii <= i < LB+32*ii+tile_size
-          GEQ_Handle h1 = f_root->add_GEQ();
-          h1.update_coef(stmt[*i].xform.output_var(outer_dim + 1),
-                         -tile_size);
-          h1.update_coef(stmt[*i].xform.output_var(dim + 3), 1);
-          h1.update_coef(aligned_lb, -1);
-          
-          GEQ_Handle h2 = f_root->add_GEQ();
-          h2.update_coef(stmt[*i].xform.output_var(outer_dim + 1),
-                         tile_size);
-          h2.update_coef(stmt[*i].xform.output_var(dim + 3), -1);
-          h2.update_const(tile_size - 1);
-          h2.update_coef(aligned_lb, 1);
-        }
-      }
-    }
-  }
-  
-  // update loop level information
-  for (std::set<int>::iterator i = same_tile_controlling_loop.begin();
-       i != same_tile_controlling_loop.end(); i++) {
-    for (int j = 1; j <= stmt[*i].loop_level.size(); j++)
-      switch (stmt[*i].loop_level[j - 1].type) {
-      case LoopLevelOriginal:
-        break;
-      case LoopLevelTile:
-        if (stmt[*i].loop_level[j - 1].payload >= outer_level)
-          stmt[*i].loop_level[j - 1].payload++;
-        break;
-      default:
-        throw loop_error(
-          "unknown loop level type for statement "
-          + to_string(*i));
-      }
-    
-    LoopLevel ll;
-    ll.type = LoopLevelTile;
-    ll.payload = level + 1;
-    ll.parallel_level = 0;
-    stmt[*i].loop_level.insert(
-      stmt[*i].loop_level.begin() + (outer_level - 1), ll);
-  }
-}
-
diff --git a/chill/src/loop_unroll.cc b/chill/src/loop_unroll.cc
deleted file mode 100644
index 9bc6acf..0000000
--- a/chill/src/loop_unroll.cc
+++ /dev/null
@@ -1,1166 +0,0 @@
-/*
- * loop_unroll.cc
- *
- *  Created on: Nov 12, 2012
- *      Author: anand
- */
-
-#include <code_gen/codegen.h>
-#include <code_gen/CG_utils.h>
-#include "loop.hh"
-#include "omegatools.hh"
-#include "ir_code.hh"
-#include "chill_error.hh"
-#include <math.h>
-
-using namespace omega;
-
-
-std::set<int> Loop::unroll(int stmt_num, int level, int unroll_amount,
-                           std::vector<std::vector<std::string> > idxNames,
-                           int cleanup_split_level) {
-  // check for sanity of parameters
-  // check for sanity of parameters
-  if (unroll_amount < 0)
-    throw std::invalid_argument(
-      "invalid unroll amount " + to_string(unroll_amount));
-  if (stmt_num < 0 || stmt_num >= stmt.size())
-    throw std::invalid_argument("invalid statement " + to_string(stmt_num));
-  if (level <= 0 || level > stmt[stmt_num].loop_level.size())
-    throw std::invalid_argument("invalid loop level " + to_string(level));
-  
-  if (cleanup_split_level == 0)
-    cleanup_split_level = level;
-  if (cleanup_split_level > level)
-    throw std::invalid_argument(
-      "cleanup code must be split at or outside the unrolled loop level "
-      + to_string(level));
-  if (cleanup_split_level <= 0)
-    throw std::invalid_argument(
-      "invalid split loop level " + to_string(cleanup_split_level));
-  
-  // invalidate saved codegen computation
-  delete last_compute_cgr_;
-  last_compute_cgr_ = NULL;
-  delete last_compute_cg_;
-  last_compute_cg_ = NULL;
-  
-  int dim = 2 * level - 1;
-  std::vector<int> lex = getLexicalOrder(stmt_num);
-  std::set<int> same_loop = getStatements(lex, dim - 1);
-  
-  // nothing to do
-  if (unroll_amount == 1)
-    return std::set<int>();
-  
-  for (std::set<int>::iterator i = same_loop.begin(); i != same_loop.end();
-       i++) {
-    std::vector<std::pair<int, DependenceVector> > D;
-    int n = stmt[*i].xform.n_out();
-    for (DependenceGraph::EdgeList::iterator j =
-           dep.vertex[*i].second.begin(); j != dep.vertex[*i].second.end();
-         j++) {
-      if (same_loop.find(j->first) != same_loop.end())
-        for (int k = 0; k < j->second.size(); k++) {
-          DependenceVector dv = j->second[k];
-          int dim2 = level - 1;
-          if (dv.type != DEP_CONTROL) {
-            
-            while (stmt[*i].loop_level[dim2].type == LoopLevelTile) {
-              dim2 = stmt[*i].loop_level[dim2].payload - 1;
-            }
-            dim2 = stmt[*i].loop_level[dim2].payload;
-            
-            /*if (dv.isCarried(dim2)
-              && (dv.hasNegative(dim2) && !dv.quasi))
-              throw loop_error(
-              "loop error: Unrolling is illegal, dependence violation!");
-              
-              if (dv.isCarried(dim2)
-              && (dv.hasPositive(dim2) && dv.quasi))
-              throw loop_error(
-              "loop error: Unrolling is illegal, dependence violation!");
-            */
-            bool safe = false;
-            
-            if (dv.isCarried(dim2) && dv.hasPositive(dim2)) {
-              if (dv.quasi)
-                throw loop_error(
-                  "loop error: a quasi dependence with a positive carried distance");
-              if (!dv.quasi) {
-                if (dv.lbounds[dim2] != posInfinity) {
-                  //if (dv.lbounds[dim2] != negInfinity)
-                  if (dv.lbounds[dim2] > unroll_amount)
-                    safe = true;
-                } else
-                  safe = true;
-              }/* else {
-                  if (dv.ubounds[dim2] != negInfinity) {
-                  if (dv.ubounds[dim2] != posInfinity)
-                  if ((-(dv.ubounds[dim2])) > unroll_amount)
-                  safe = true;
-                  } else
-                  safe = true;
-                  }*/
-              
-              if (!safe) {
-                for (int l = level + 1; l <= (n - 1) / 2; l++) {
-                  int dim3 = l - 1;
-                  
-                  if (stmt[*i].loop_level[dim3].type
-                      != LoopLevelTile)
-                    dim3 =
-                      stmt[*i].loop_level[dim3].payload;
-                  else {
-                    while (stmt[*i].loop_level[dim3].type
-                           == LoopLevelTile) {
-                      dim3 =
-                        stmt[*i].loop_level[dim3].payload
-                        - 1;
-                    }
-                    dim3 =
-                      stmt[*i].loop_level[dim3].payload;
-                  }
-                  
-                  if (dim3 > dim2) {
-                    
-                    if (dv.hasPositive(dim3))
-                      break;
-                    else if (dv.hasNegative(dim3))
-                      throw loop_error(
-                        "loop error: Unrolling is illegal, dependence violation!");
-                  }
-                }
-              }
-            }
-          }
-        }
-    }
-  }
-  // extract the intersection of the iteration space to be considered
-  Relation hull = Relation::True(level);
-  apply_xform(same_loop);
-  for (std::set<int>::iterator i = same_loop.begin(); i != same_loop.end();
-       i++) {
-    if (stmt[*i].IS.is_upper_bound_satisfiable()) {
-      Relation mapping(stmt[*i].IS.n_set(), level);
-      F_And *f_root = mapping.add_and();
-      for (int j = 1; j <= level; j++) {
-        EQ_Handle h = f_root->add_EQ();
-        h.update_coef(mapping.input_var(j), 1);
-        h.update_coef(mapping.output_var(j), -1);
-      }
-      hull = Intersection(hull,
-                          Range(Restrict_Domain(mapping, copy(stmt[*i].IS))));
-      hull.simplify(2, 4);
-      
-    }
-  }
-  for (int i = 1; i <= level; i++) {
-    std::string name = tmp_loop_var_name_prefix + to_string(i);
-    hull.name_set_var(i, name);
-  }
-  hull.setup_names();
-  
-  // extract the exact loop bound of the dimension to be unrolled
-  if (is_single_loop_iteration(hull, level, this->known))
-    return std::set<int>();
-  Relation bound = get_loop_bound(hull, level, this->known);
-  if (!bound.has_single_conjunct() || !bound.is_satisfiable()
-      || bound.is_tautology())
-    throw loop_error("unable to extract loop bound for unrolling");
-  
-  // extract the loop stride
-  coef_t stride;
-  std::pair<EQ_Handle, Variable_ID> result = find_simplest_stride(bound,
-                                                                  bound.set_var(level));
-  if (result.second == NULL)
-    stride = 1;
-  else
-    stride = abs(result.first.get_coef(result.second))
-      / gcd(abs(result.first.get_coef(result.second)),
-            abs(result.first.get_coef(bound.set_var(level))));
-  
-  // separate lower and upper bounds
-  std::vector<GEQ_Handle> lb_list, ub_list;
-  {
-    Conjunct *c = bound.query_DNF()->single_conjunct();
-    for (GEQ_Iterator gi(c->GEQs()); gi; gi++) {
-      int coef = (*gi).get_coef(bound.set_var(level));
-      if (coef < 0)
-        ub_list.push_back(*gi);
-      else if (coef > 0)
-        lb_list.push_back(*gi);
-    }
-  }
-  
-  // simplify overflow expression for each pair of upper and lower bounds
-  std::vector<std::vector<std::map<Variable_ID, int> > > overflow_table(
-    lb_list.size(),
-    std::vector<std::map<Variable_ID, int> >(ub_list.size(),
-                                             std::map<Variable_ID, int>()));
-  bool is_overflow_simplifiable = true;
-  for (int i = 0; i < lb_list.size(); i++) {
-    if (!is_overflow_simplifiable)
-      break;
-    
-    for (int j = 0; j < ub_list.size(); j++) {
-      // lower bound or upper bound has non-unit coefficient, can't simplify
-      if (ub_list[j].get_coef(bound.set_var(level)) != -1
-          || lb_list[i].get_coef(bound.set_var(level)) != 1) {
-        is_overflow_simplifiable = false;
-        break;
-      }
-      
-      for (Constr_Vars_Iter ci(ub_list[j]); ci; ci++) {
-        switch ((*ci).var->kind()) {
-        case Input_Var: {
-          if ((*ci).var != bound.set_var(level))
-            overflow_table[i][j][(*ci).var] += (*ci).coef;
-          
-          break;
-        }
-        case Global_Var: {
-          Global_Var_ID g = (*ci).var->get_global_var();
-          Variable_ID v;
-          if (g->arity() == 0)
-            v = bound.get_local(g);
-          else
-            v = bound.get_local(g, (*ci).var->function_of());
-          overflow_table[i][j][(*ci).var] += (*ci).coef;
-          break;
-        }
-        default:
-          throw loop_error("failed to calculate overflow amount");
-        }
-      }
-      overflow_table[i][j][NULL] += ub_list[j].get_const();
-      
-      for (Constr_Vars_Iter ci(lb_list[i]); ci; ci++) {
-        switch ((*ci).var->kind()) {
-        case Input_Var: {
-          if ((*ci).var != bound.set_var(level)) {
-            overflow_table[i][j][(*ci).var] += (*ci).coef;
-            if (overflow_table[i][j][(*ci).var] == 0)
-              overflow_table[i][j].erase(
-                overflow_table[i][j].find((*ci).var));
-          }
-          break;
-        }
-        case Global_Var: {
-          Global_Var_ID g = (*ci).var->get_global_var();
-          Variable_ID v;
-          if (g->arity() == 0)
-            v = bound.get_local(g);
-          else
-            v = bound.get_local(g, (*ci).var->function_of());
-          overflow_table[i][j][(*ci).var] += (*ci).coef;
-          if (overflow_table[i][j][(*ci).var] == 0)
-            overflow_table[i][j].erase(
-              overflow_table[i][j].find((*ci).var));
-          break;
-        }
-        default:
-          throw loop_error("failed to calculate overflow amount");
-        }
-      }
-      overflow_table[i][j][NULL] += lb_list[i].get_const();
-      
-      overflow_table[i][j][NULL] += stride;
-      if (unroll_amount == 0
-          || (overflow_table[i][j].size() == 1
-              && overflow_table[i][j][NULL] / stride
-              < unroll_amount))
-        unroll_amount = overflow_table[i][j][NULL] / stride;
-    }
-  }
-  
-  // loop iteration count can't be determined, bail out gracefully
-  if (unroll_amount == 0)
-    return std::set<int>();
-  
-  // further simply overflow calculation using coefficients' modular
-  if (is_overflow_simplifiable) {
-    for (int i = 0; i < lb_list.size(); i++)
-      for (int j = 0; j < ub_list.size(); j++)
-        if (stride == 1) {
-          for (std::map<Variable_ID, int>::iterator k =
-                 overflow_table[i][j].begin();
-               k != overflow_table[i][j].end();)
-            if ((*k).first != NULL) {
-              int t = int_mod_hat((*k).second, unroll_amount);
-              if (t == 0) {
-                overflow_table[i][j].erase(k++);
-              } else {
-                int t2 = hull.query_variable_mod((*k).first,
-                                                 unroll_amount);
-                if (t2 != INT_MAX) {
-                  overflow_table[i][j][NULL] += t * t2;
-                  overflow_table[i][j].erase(k++);
-                } else {
-                  (*k).second = t;
-                  k++;
-                }
-              }
-            } else
-              k++;
-          
-          overflow_table[i][j][NULL] = int_mod_hat(
-            overflow_table[i][j][NULL], unroll_amount);
-          
-          // Since we don't have MODULO instruction in SUIF yet (only MOD), make all coef positive in the final formula
-          for (std::map<Variable_ID, int>::iterator k =
-                 overflow_table[i][j].begin();
-               k != overflow_table[i][j].end(); k++)
-            if ((*k).second < 0)
-              (*k).second += unroll_amount;
-        }
-  }
-  
-  // build overflow statement
-  CG_outputBuilder *ocg = ir->builder();
-  CG_outputRepr *overflow_code = NULL;
-  Relation cond_upper(level), cond_lower(level);
-  Relation overflow_constraint(0);
-  F_And *overflow_constraint_root = overflow_constraint.add_and();
-  std::vector<Free_Var_Decl *> over_var_list;
-  if (is_overflow_simplifiable && lb_list.size() == 1) {
-    for (int i = 0; i < ub_list.size(); i++) {
-      if (overflow_table[0][i].size() == 1) {
-        // upper splitting condition
-        GEQ_Handle h = cond_upper.and_with_GEQ(ub_list[i]);
-        h.update_const(
-          ((overflow_table[0][i][NULL] / stride) % unroll_amount)
-          * -stride);
-      } else {
-        // upper splitting condition
-        std::string over_name = overflow_var_name_prefix
-          + to_string(overflow_var_name_counter++);
-        Free_Var_Decl *over_free_var = new Free_Var_Decl(over_name);
-        over_var_list.push_back(over_free_var);
-        GEQ_Handle h = cond_upper.and_with_GEQ(ub_list[i]);
-        h.update_coef(cond_upper.get_local(over_free_var), -stride);
-        
-        // insert constraint 0 <= overflow < unroll_amount
-        Variable_ID v = overflow_constraint.get_local(over_free_var);
-        GEQ_Handle h1 = overflow_constraint_root->add_GEQ();
-        h1.update_coef(v, 1);
-        GEQ_Handle h2 = overflow_constraint_root->add_GEQ();
-        h2.update_coef(v, -1);
-        h2.update_const(unroll_amount - 1);
-        
-        // create overflow assignment
-        bound.setup_names(); // hack to fix omega relation variable names issue
-        CG_outputRepr *rhs = NULL;
-        bool is_split_illegal = false;
-        for (std::map<Variable_ID, int>::iterator j =
-               overflow_table[0][i].begin();
-             j != overflow_table[0][i].end(); j++)
-          if ((*j).first != NULL) {
-            if ((*j).first->kind() == Input_Var
-                && (*j).first->get_position()
-                >= cleanup_split_level)
-              is_split_illegal = true;
-            
-            CG_outputRepr *t = ocg->CreateIdent((*j).first->name());
-            if ((*j).second != 1)
-              t = ocg->CreateTimes(ocg->CreateInt((*j).second),
-                                   t);
-            rhs = ocg->CreatePlus(rhs, t);
-          } else if ((*j).second != 0)
-            rhs = ocg->CreatePlus(rhs, ocg->CreateInt((*j).second));
-        
-        if (is_split_illegal) {
-          rhs->clear();
-          delete rhs;
-          throw loop_error(
-            "cannot split cleanup code at loop level "
-            + to_string(cleanup_split_level)
-            + " due to overflow variable data dependence");
-        }
-        
-        if (stride != 1)
-          rhs = ocg->CreateIntegerCeil(rhs, ocg->CreateInt(stride));
-        rhs = ocg->CreateIntegerMod(rhs, ocg->CreateInt(unroll_amount));
-        
-        CG_outputRepr *lhs = ocg->CreateIdent(over_name);
-        init_code = ocg->StmtListAppend(init_code,
-                                        ocg->CreateAssignment(0, lhs, ocg->CreateInt(0)));
-        lhs = ocg->CreateIdent(over_name);
-        overflow_code = ocg->StmtListAppend(overflow_code,
-                                            ocg->CreateAssignment(0, lhs, rhs));
-      }
-    }
-    
-    // lower splitting condition
-    GEQ_Handle h = cond_lower.and_with_GEQ(lb_list[0]);
-  } else if (is_overflow_simplifiable && ub_list.size() == 1) {
-    for (int i = 0; i < lb_list.size(); i++) {
-      
-      if (overflow_table[i][0].size() == 1) {
-        // lower splitting condition
-        GEQ_Handle h = cond_lower.and_with_GEQ(lb_list[i]);
-        h.update_const(overflow_table[i][0][NULL] * -stride);
-      } else {
-        // lower splitting condition
-        std::string over_name = overflow_var_name_prefix
-          + to_string(overflow_var_name_counter++);
-        Free_Var_Decl *over_free_var = new Free_Var_Decl(over_name);
-        over_var_list.push_back(over_free_var);
-        GEQ_Handle h = cond_lower.and_with_GEQ(lb_list[i]);
-        h.update_coef(cond_lower.get_local(over_free_var), -stride);
-        
-        // insert constraint 0 <= overflow < unroll_amount
-        Variable_ID v = overflow_constraint.get_local(over_free_var);
-        GEQ_Handle h1 = overflow_constraint_root->add_GEQ();
-        h1.update_coef(v, 1);
-        GEQ_Handle h2 = overflow_constraint_root->add_GEQ();
-        h2.update_coef(v, -1);
-        h2.update_const(unroll_amount - 1);
-        
-        // create overflow assignment
-        bound.setup_names(); // hack to fix omega relation variable names issue
-        CG_outputRepr *rhs = NULL;
-        for (std::map<Variable_ID, int>::iterator j =
-               overflow_table[0][i].begin();
-             j != overflow_table[0][i].end(); j++)
-          if ((*j).first != NULL) {
-            CG_outputRepr *t = ocg->CreateIdent((*j).first->name());
-            if ((*j).second != 1)
-              t = ocg->CreateTimes(ocg->CreateInt((*j).second),
-                                   t);
-            rhs = ocg->CreatePlus(rhs, t);
-          } else if ((*j).second != 0)
-            rhs = ocg->CreatePlus(rhs, ocg->CreateInt((*j).second));
-        
-        if (stride != 1)
-          rhs = ocg->CreateIntegerCeil(rhs, ocg->CreateInt(stride));
-        rhs = ocg->CreateIntegerMod(rhs, ocg->CreateInt(unroll_amount));
-        
-        CG_outputRepr *lhs = ocg->CreateIdent(over_name);
-        init_code = ocg->StmtListAppend(init_code,
-                                        ocg->CreateAssignment(0, lhs, ocg->CreateInt(0)));
-        lhs = ocg->CreateIdent(over_name);
-        overflow_code = ocg->StmtListAppend(overflow_code,
-                                            ocg->CreateAssignment(0, lhs, rhs));
-      }
-    }
-    
-    // upper splitting condition
-    GEQ_Handle h = cond_upper.and_with_GEQ(ub_list[0]);
-  } else {
-    std::string over_name = overflow_var_name_prefix
-      + to_string(overflow_var_name_counter++);
-    Free_Var_Decl *over_free_var = new Free_Var_Decl(over_name);
-    over_var_list.push_back(over_free_var);
-    
-    std::vector<CG_outputRepr *> lb_repr_list, ub_repr_list;
-    for (int i = 0; i < lb_list.size(); i++) {
-      lb_repr_list.push_back(
-        output_lower_bound_repr(ocg, lb_list[i],
-                                bound.set_var(dim + 1), result.first, result.second,
-                                bound, Relation::True(bound.n_set()),
-                                std::vector<std::pair<CG_outputRepr *, int> >(
-                                  bound.n_set(),
-                                  std::make_pair(
-                                    static_cast<CG_outputRepr *>(NULL),
-                                    0))));
-      GEQ_Handle h = cond_lower.and_with_GEQ(lb_list[i]);
-    }
-    for (int i = 0; i < ub_list.size(); i++) {
-      ub_repr_list.push_back(
-        output_upper_bound_repr(ocg, ub_list[i],
-                                bound.set_var(dim + 1), bound,
-                                std::vector<std::pair<CG_outputRepr *, int> >(
-                                  bound.n_set(),
-                                  std::make_pair(
-                                    static_cast<CG_outputRepr *>(NULL),
-                                    0))));
-      GEQ_Handle h = cond_upper.and_with_GEQ(ub_list[i]);
-      h.update_coef(cond_upper.get_local(over_free_var), -stride);
-    }
-    
-    CG_outputRepr *lbRepr, *ubRepr;
-    if (lb_repr_list.size() > 1)
-      lbRepr = ocg->CreateInvoke("max", lb_repr_list);
-    else if (lb_repr_list.size() == 1)
-      lbRepr = lb_repr_list[0];
-    
-    if (ub_repr_list.size() > 1)
-      ubRepr = ocg->CreateInvoke("min", ub_repr_list);
-    else if (ub_repr_list.size() == 1)
-      ubRepr = ub_repr_list[0];
-    
-    // create overflow assignment
-    CG_outputRepr *rhs = ocg->CreatePlus(ocg->CreateMinus(ubRepr, lbRepr),
-                                         ocg->CreateInt(1));
-    if (stride != 1)
-      rhs = ocg->CreateIntegerFloor(rhs, ocg->CreateInt(stride));
-    rhs = ocg->CreateIntegerMod(rhs, ocg->CreateInt(unroll_amount));
-    CG_outputRepr *lhs = ocg->CreateIdent(over_name);
-    init_code = ocg->StmtListAppend(init_code,
-                                    ocg->CreateAssignment(0, lhs, ocg->CreateInt(0)));
-    lhs = ocg->CreateIdent(over_name);
-    overflow_code = ocg->CreateAssignment(0, lhs, rhs);
-    
-    // insert constraint 0 <= overflow < unroll_amount
-    Variable_ID v = overflow_constraint.get_local(over_free_var);
-    GEQ_Handle h1 = overflow_constraint_root->add_GEQ();
-    h1.update_coef(v, 1);
-    GEQ_Handle h2 = overflow_constraint_root->add_GEQ();
-    h2.update_coef(v, -1);
-    h2.update_const(unroll_amount - 1);
-  }
-  
-  // insert overflow statement
-  int overflow_stmt_num = -1;
-  if (overflow_code != NULL) {
-    // build iteration space for overflow statement
-    Relation mapping(level, cleanup_split_level - 1);
-    F_And *f_root = mapping.add_and();
-    for (int i = 1; i < cleanup_split_level; i++) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(mapping.output_var(i), 1);
-      h.update_coef(mapping.input_var(i), -1);
-    }
-    Relation overflow_IS = Range(Restrict_Domain(mapping, copy(hull)));
-    for (int i = 1; i < cleanup_split_level; i++)
-      overflow_IS.name_set_var(i, hull.set_var(i)->name());
-    overflow_IS.setup_names();
-    
-    // build dumb transformation relation for overflow statement
-    Relation overflow_xform(cleanup_split_level - 1,
-                            2 * (cleanup_split_level - 1) + 1);
-    f_root = overflow_xform.add_and();
-    for (int i = 1; i <= cleanup_split_level - 1; i++) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(overflow_xform.output_var(2 * i), 1);
-      h.update_coef(overflow_xform.input_var(i), -1);
-      
-      h = f_root->add_EQ();
-      h.update_coef(overflow_xform.output_var(2 * i - 1), 1);
-      h.update_const(-lex[2 * i - 2]);
-    }
-    EQ_Handle h = f_root->add_EQ();
-    h.update_coef(
-      overflow_xform.output_var(2 * (cleanup_split_level - 1) + 1),
-      1);
-    h.update_const(-lex[2 * (cleanup_split_level - 1)]);
-    
-    shiftLexicalOrder(lex, 2 * cleanup_split_level - 2, 1);
-    Statement overflow_stmt;
-    
-    overflow_stmt.code = overflow_code;
-    overflow_stmt.IS = overflow_IS;
-    overflow_stmt.xform = overflow_xform;
-    overflow_stmt.loop_level = std::vector<LoopLevel>(level - 1);
-    overflow_stmt.ir_stmt_node = NULL;
-    for (int i = 0; i < level - 1; i++) {
-      overflow_stmt.loop_level[i].type =
-        stmt[stmt_num].loop_level[i].type;
-      if (stmt[stmt_num].loop_level[i].type == LoopLevelTile
-          && stmt[stmt_num].loop_level[i].payload >= level)
-        overflow_stmt.loop_level[i].payload = -1;
-      else
-        overflow_stmt.loop_level[i].payload =
-          stmt[stmt_num].loop_level[i].payload;
-      overflow_stmt.loop_level[i].parallel_level =
-        stmt[stmt_num].loop_level[i].parallel_level;
-    }
-    
-    stmt.push_back(overflow_stmt);
-    dep.insert();
-    overflow_stmt_num = stmt.size() - 1;
-    overflow[overflow_stmt_num] = over_var_list;
-    
-    // update the global known information on overflow variable
-    this->known = Intersection(this->known,
-                               Extend_Set(copy(overflow_constraint),
-                                          this->known.n_set() - overflow_constraint.n_set()));
-    
-    // update dependence graph
-    DependenceVector dv;
-    dv.type = DEP_CONTROL;
-    for (std::set<int>::iterator i = same_loop.begin();
-         i != same_loop.end(); i++)
-      dep.connect(overflow_stmt_num, *i, dv);
-    dv.type = DEP_W2W;
-    {
-      IR_ScalarSymbol *overflow_sym = NULL;
-      std::vector<IR_ScalarRef *> scalars = ir->FindScalarRef(
-        overflow_code);
-      for (int i = scalars.size() - 1; i >= 0; i--)
-        if (scalars[i]->is_write()) {
-          overflow_sym = scalars[i]->symbol();
-          break;
-        }
-      for (int i = scalars.size() - 1; i >= 0; i--)
-        delete scalars[i];
-      dv.sym = overflow_sym;
-    }
-    dv.lbounds = std::vector<coef_t>(dep.num_dim(), 0);
-    dv.ubounds = std::vector<coef_t>(dep.num_dim(), 0);
-    int dep_dim = get_last_dep_dim_before(stmt_num, level);
-    for (int i = dep_dim + 1; i < dep.num_dim(); i++) {
-      dv.lbounds[i] = -posInfinity;
-      dv.ubounds[i] = posInfinity;
-    }
-    for (int i = 0; i <= dep_dim; i++) {
-      if (i != 0) {
-        dv.lbounds[i - 1] = 0;
-        dv.ubounds[i - 1] = 0;
-      }
-      dv.lbounds[i] = 1;
-      dv.ubounds[i] = posInfinity;
-      dep.connect(overflow_stmt_num, overflow_stmt_num, dv);
-    }
-  }
-  
-  // split the loop so it can be fully unrolled
-  std::set<int> new_stmts = split(stmt_num, cleanup_split_level, cond_upper);
-  std::set<int> new_stmts2 = split(stmt_num, cleanup_split_level, cond_lower);
-  new_stmts.insert(new_stmts2.begin(), new_stmts2.end());
-  
-  // check if unrolled statements can be trivially lumped together as one statement
-  bool can_be_lumped = true;
-  if (can_be_lumped) {
-    for (std::set<int>::iterator i = same_loop.begin();
-         i != same_loop.end(); i++)
-      if (*i != stmt_num) {
-        if (stmt[*i].loop_level.size()
-            != stmt[stmt_num].loop_level.size()) {
-          can_be_lumped = false;
-          break;
-        }
-        for (int j = 0; j < stmt[stmt_num].loop_level.size(); j++)
-          if (!(stmt[*i].loop_level[j].type
-                == stmt[stmt_num].loop_level[j].type
-                && stmt[*i].loop_level[j].payload
-                == stmt[stmt_num].loop_level[j].payload)) {
-            can_be_lumped = false;
-            break;
-          }
-        if (!can_be_lumped)
-          break;
-        std::vector<int> lex2 = getLexicalOrder(*i);
-        for (int j = 2 * level; j < lex.size() - 1; j += 2)
-          if (lex[j] != lex2[j]) {
-            can_be_lumped = false;
-            break;
-          }
-        if (!can_be_lumped)
-          break;
-      }
-  }
-  if (can_be_lumped) {
-    for (std::set<int>::iterator i = same_loop.begin();
-         i != same_loop.end(); i++)
-      if (is_inner_loop_depend_on_level(stmt[*i].IS, level,
-                                        this->known)) {
-        can_be_lumped = false;
-        break;
-      }
-  }
-  if (can_be_lumped) {
-    for (std::set<int>::iterator i = same_loop.begin();
-         i != same_loop.end(); i++)
-      if (*i != stmt_num) {
-        if (!(Must_Be_Subset(copy(stmt[*i].IS), copy(stmt[stmt_num].IS))
-              && Must_Be_Subset(copy(stmt[stmt_num].IS),
-                                copy(stmt[*i].IS)))) {
-          can_be_lumped = false;
-          break;
-        }
-      }
-  }
-  if (can_be_lumped) {
-    for (std::set<int>::iterator i = same_loop.begin();
-         i != same_loop.end(); i++) {
-      for (DependenceGraph::EdgeList::iterator j =
-             dep.vertex[*i].second.begin();
-           j != dep.vertex[*i].second.end(); j++)
-        if (same_loop.find(j->first) != same_loop.end()) {
-          for (int k = 0; k < j->second.size(); k++)
-            if (j->second[k].type == DEP_CONTROL
-                || j->second[k].type == DEP_UNKNOWN) {
-              can_be_lumped = false;
-              break;
-            }
-          if (!can_be_lumped)
-            break;
-        }
-      if (!can_be_lumped)
-        break;
-    }
-  }
-  
-  // insert unrolled statements
-  int old_num_stmt = stmt.size();
-  if (!can_be_lumped) {
-    std::map<int, std::vector<int> > what_stmt_num;
-    
-    for (int j = 1; j < unroll_amount; j++) {
-      for (std::set<int>::iterator i = same_loop.begin();
-           i != same_loop.end(); i++) {
-        Statement new_stmt;
-        
-        std::vector<std::string> loop_vars;
-        std::vector<CG_outputRepr *> subs;
-        loop_vars.push_back(stmt[*i].IS.set_var(level)->name());
-        subs.push_back(
-          ocg->CreatePlus(
-            ocg->CreateIdent(
-              stmt[*i].IS.set_var(level)->name()),
-            ocg->CreateInt(j * stride)));
-        new_stmt.code = ocg->CreateSubstitutedStmt(0,
-                                                   stmt[*i].code->clone(), loop_vars, subs);
-        
-        new_stmt.IS = adjust_loop_bound(stmt[*i].IS, level, j * stride);
-        add_loop_stride(new_stmt.IS, bound, level - 1,
-                        unroll_amount * stride);
-        
-        new_stmt.xform = copy(stmt[*i].xform);
-        
-        new_stmt.loop_level = stmt[*i].loop_level;
-        new_stmt.ir_stmt_node = NULL;
-        stmt.push_back(new_stmt);
-        dep.insert();
-        what_stmt_num[*i].push_back(stmt.size() - 1);
-      }
-    }
-    for (std::set<int>::iterator i = same_loop.begin();
-         i != same_loop.end(); i++)
-      add_loop_stride(stmt[*i].IS, bound, level - 1,
-                      unroll_amount * stride);
-    
-    // update dependence graph
-    if (stmt[stmt_num].loop_level[level - 1].type == LoopLevelOriginal) {
-      int dep_dim = stmt[stmt_num].loop_level[level - 1].payload;
-      int new_stride = unroll_amount * stride;
-      for (int i = 0; i < old_num_stmt; i++) {
-        std::vector<std::pair<int, DependenceVector> > D;
-        
-        for (DependenceGraph::EdgeList::iterator j =
-               dep.vertex[i].second.begin();
-             j != dep.vertex[i].second.end();) {
-          if (same_loop.find(i) != same_loop.end()) {
-            if (same_loop.find(j->first) != same_loop.end()) {
-              for (int k = 0; k < j->second.size(); k++) {
-                DependenceVector dv = j->second[k];
-                if (dv.type == DEP_CONTROL
-                    || dv.type == DEP_UNKNOWN) {
-                  D.push_back(std::make_pair(j->first, dv));
-                  for (int kk = 0; kk < unroll_amount - 1;
-                       kk++)
-                    if (what_stmt_num[i][kk] != -1
-                        && what_stmt_num[j->first][kk]
-                        != -1)
-                      dep.connect(what_stmt_num[i][kk],
-                                  what_stmt_num[j->first][kk],
-                                  dv);
-                } else {
-                  coef_t lb = dv.lbounds[dep_dim];
-                  coef_t ub = dv.ubounds[dep_dim];
-                  if (ub == lb
-                      && int_mod(lb,
-                                 static_cast<coef_t>(new_stride))
-                      == 0) {
-                    D.push_back(
-                      std::make_pair(j->first, dv));
-                    for (int kk = 0; kk < unroll_amount - 1;
-                         kk++)
-                      if (what_stmt_num[i][kk] != -1
-                          && what_stmt_num[j->first][kk]
-                          != -1)
-                        dep.connect(
-                          what_stmt_num[i][kk],
-                          what_stmt_num[j->first][kk],
-                          dv);
-                  } else if (lb == -posInfinity
-                             && ub == posInfinity) {
-                    D.push_back(
-                      std::make_pair(j->first, dv));
-                    for (int kk = 0; kk < unroll_amount;
-                         kk++)
-                      if (kk == 0)
-                        D.push_back(
-                          std::make_pair(j->first,
-                                         dv));
-                      else if (what_stmt_num[j->first][kk
-                                                       - 1] != -1)
-                        D.push_back(
-                          std::make_pair(
-                            what_stmt_num[j->first][kk
-                                                    - 1],
-                            dv));
-                    for (int t = 0; t < unroll_amount - 1;
-                         t++)
-                      if (what_stmt_num[i][t] != -1)
-                        for (int kk = 0;
-                             kk < unroll_amount;
-                             kk++)
-                          if (kk == 0)
-                            dep.connect(
-                              what_stmt_num[i][t],
-                              j->first, dv);
-                          else if (what_stmt_num[j->first][kk
-                                                           - 1] != -1)
-                            dep.connect(
-                              what_stmt_num[i][t],
-                              what_stmt_num[j->first][kk
-                                                      - 1],
-                              dv);
-                  } else {
-                    for (int kk = 0; kk < unroll_amount;
-                         kk++) {
-                      if (lb != -posInfinity) {
-                        if (kk * stride
-                            < int_mod(lb,
-                                      static_cast<coef_t>(new_stride)))
-                          dv.lbounds[dep_dim] =
-                            floor(
-                              static_cast<double>(lb)
-                              / new_stride)
-                            * new_stride
-                            + new_stride;
-                        else
-                          dv.lbounds[dep_dim] =
-                            floor(
-                              static_cast<double>(lb)
-                              / new_stride)
-                            * new_stride;
-                      }
-                      if (ub != posInfinity) {
-                        if (kk * stride
-                            > int_mod(ub,
-                                      static_cast<coef_t>(new_stride)))
-                          dv.ubounds[dep_dim] =
-                            floor(
-                              static_cast<double>(ub)
-                              / new_stride)
-                            * new_stride
-                            - new_stride;
-                        else
-                          dv.ubounds[dep_dim] =
-                            floor(
-                              static_cast<double>(ub)
-                              / new_stride)
-                            * new_stride;
-                      }
-                      if (dv.ubounds[dep_dim]
-                          >= dv.lbounds[dep_dim]) {
-                        if (kk == 0)
-                          D.push_back(
-                            std::make_pair(
-                              j->first,
-                              dv));
-                        else if (what_stmt_num[j->first][kk
-                                                         - 1] != -1)
-                          D.push_back(
-                            std::make_pair(
-                              what_stmt_num[j->first][kk
-                                                      - 1],
-                              dv));
-                      }
-                    }
-                    for (int t = 0; t < unroll_amount - 1;
-                         t++)
-                      if (what_stmt_num[i][t] != -1)
-                        for (int kk = 0;
-                             kk < unroll_amount;
-                             kk++) {
-                          if (lb != -posInfinity) {
-                            if (kk * stride
-                                < int_mod(
-                                  lb + t
-                                  + 1,
-                                  static_cast<coef_t>(new_stride)))
-                              dv.lbounds[dep_dim] =
-                                floor(
-                                  static_cast<double>(lb
-                                                      + (t
-                                                         + 1)
-                                                      * stride)
-                                  / new_stride)
-                                * new_stride
-                                + new_stride;
-                            else
-                              dv.lbounds[dep_dim] =
-                                floor(
-                                  static_cast<double>(lb
-                                                      + (t
-                                                         + 1)
-                                                      * stride)
-                                  / new_stride)
-                                * new_stride;
-                          }
-                          if (ub != posInfinity) {
-                            if (kk * stride
-                                > int_mod(
-                                  ub + t
-                                  + 1,
-                                  static_cast<coef_t>(new_stride)))
-                              dv.ubounds[dep_dim] =
-                                floor(
-                                  static_cast<double>(ub
-                                                      + (t
-                                                         + 1)
-                                                      * stride)
-                                  / new_stride)
-                                * new_stride
-                                - new_stride;
-                            else
-                              dv.ubounds[dep_dim] =
-                                floor(
-                                  static_cast<double>(ub
-                                                      + (t
-                                                         + 1)
-                                                      * stride)
-                                  / new_stride)
-                                * new_stride;
-                          }
-                          if (dv.ubounds[dep_dim]
-                              >= dv.lbounds[dep_dim]) {
-                            if (kk == 0)
-                              dep.connect(
-                                what_stmt_num[i][t],
-                                j->first,
-                                dv);
-                            else if (what_stmt_num[j->first][kk
-                                                             - 1] != -1)
-                              dep.connect(
-                                what_stmt_num[i][t],
-                                what_stmt_num[j->first][kk
-                                                        - 1],
-                                dv);
-                          }
-                        }
-                  }
-                }
-              }
-              
-              dep.vertex[i].second.erase(j++);
-            } else {
-              for (int kk = 0; kk < unroll_amount - 1; kk++)
-                if (what_stmt_num[i][kk] != -1)
-                  dep.connect(what_stmt_num[i][kk], j->first,
-                              j->second);
-              
-              j++;
-            }
-          } else {
-            if (same_loop.find(j->first) != same_loop.end())
-              for (int k = 0; k < j->second.size(); k++)
-                for (int kk = 0; kk < unroll_amount - 1; kk++)
-                  if (what_stmt_num[j->first][kk] != -1)
-                    D.push_back(
-                      std::make_pair(
-                        what_stmt_num[j->first][kk],
-                        j->second[k]));
-            j++;
-          }
-        }
-        
-        for (int j = 0; j < D.size(); j++)
-          dep.connect(i, D[j].first, D[j].second);
-      }
-    }
-    
-    // reset lexical order for the unrolled loop body
-    std::set<int> new_same_loop;
-    
-    int count = 0;
-    
-    for (std::map<int, std::vector<int> >::iterator i =
-           what_stmt_num.begin(); i != what_stmt_num.end(); i++) {
-      
-      new_same_loop.insert(i->first);
-      for (int k = dim + 1; k < stmt[i->first].xform.n_out(); k += 2)
-        assign_const(stmt[i->first].xform, k,
-                     get_const(stmt[(what_stmt_num.begin())->first].xform, k,
-                               Output_Var) + count);
-      count++;
-      for (int j = 0; j < i->second.size(); j++) {
-        new_same_loop.insert(i->second[j]);
-        for (int k = dim + 1; k < stmt[i->second[j]].xform.n_out(); k +=
-               2)
-          assign_const(stmt[i->second[j]].xform, k,
-                       get_const(
-                         stmt[(what_stmt_num.begin())->first].xform,
-                         k, Output_Var) + count);
-        count++;
-      }
-    }
-    setLexicalOrder(dim + 1, new_same_loop, 0, idxNames);
-  } else {
-    for (std::set<int>::iterator i = same_loop.begin();
-         i != same_loop.end(); i++)
-      add_loop_stride(stmt[*i].IS, bound, level - 1,
-                      unroll_amount * stride);
-    
-    int max_level = stmt[stmt_num].loop_level.size();
-    std::vector<std::pair<int, int> > stmt_order;
-    for (std::set<int>::iterator i = same_loop.begin();
-         i != same_loop.end(); i++)
-      stmt_order.push_back(
-        std::make_pair(
-          get_const(stmt[*i].xform, 2 * max_level,
-                    Output_Var), *i));
-    sort(stmt_order.begin(), stmt_order.end());
-    
-    Statement new_stmt;
-    new_stmt.code = NULL;
-    for (int j = 1; j < unroll_amount; j++)
-      for (int i = 0; i < stmt_order.size(); i++) {
-        std::vector<std::string> loop_vars;
-        std::vector<CG_outputRepr *> subs;
-        loop_vars.push_back(
-          stmt[stmt_order[i].second].IS.set_var(level)->name());
-        subs.push_back(
-          ocg->CreatePlus(
-            ocg->CreateIdent(
-              stmt[stmt_order[i].second].IS.set_var(
-                level)->name()),
-            ocg->CreateInt(j * stride)));
-        CG_outputRepr *code = ocg->CreateSubstitutedStmt(0,
-                                                         stmt[stmt_order[i].second].code->clone(), loop_vars,
-                                                         subs);
-        new_stmt.code = ocg->StmtListAppend(new_stmt.code, code);
-      }
-    
-    new_stmt.IS = copy(stmt[stmt_num].IS);
-    new_stmt.xform = copy(stmt[stmt_num].xform);
-    assign_const(new_stmt.xform, 2 * max_level,
-                 stmt_order[stmt_order.size() - 1].first + 1);
-    new_stmt.loop_level = stmt[stmt_num].loop_level;
-    new_stmt.ir_stmt_node = NULL;
-    stmt.push_back(new_stmt);
-    dep.insert();
-    
-    // update dependence graph
-    if (stmt[stmt_num].loop_level[level - 1].type == LoopLevelOriginal) {
-      int dep_dim = stmt[stmt_num].loop_level[level - 1].payload;
-      int new_stride = unroll_amount * stride;
-      for (int i = 0; i < old_num_stmt; i++) {
-        std::vector<std::pair<int, std::vector<DependenceVector> > > D;
-        
-        for (DependenceGraph::EdgeList::iterator j =
-               dep.vertex[i].second.begin();
-             j != dep.vertex[i].second.end();) {
-          if (same_loop.find(i) != same_loop.end()) {
-            if (same_loop.find(j->first) != same_loop.end()) {
-              std::vector<DependenceVector> dvs11, dvs12, dvs22,
-                dvs21;
-              for (int k = 0; k < j->second.size(); k++) {
-                DependenceVector dv = j->second[k];
-                if (dv.type == DEP_CONTROL
-                    || dv.type == DEP_UNKNOWN) {
-                  if (i == j->first) {
-                    dvs11.push_back(dv);
-                    dvs22.push_back(dv);
-                  } else
-                    throw loop_error(
-                      "unrolled statements lumped together illegally");
-                } else {
-                  coef_t lb = dv.lbounds[dep_dim];
-                  coef_t ub = dv.ubounds[dep_dim];
-                  if (ub == lb
-                      && int_mod(lb,
-                                 static_cast<coef_t>(new_stride))
-                      == 0) {
-                    dvs11.push_back(dv);
-                    dvs22.push_back(dv);
-                  } else {
-                    if (lb != -posInfinity)
-                      dv.lbounds[dep_dim] = ceil(
-                        static_cast<double>(lb)
-                        / new_stride)
-                        * new_stride;
-                    if (ub != posInfinity)
-                      dv.ubounds[dep_dim] = floor(
-                        static_cast<double>(ub)
-                        / new_stride)
-                        * new_stride;
-                    if (dv.ubounds[dep_dim]
-                        >= dv.lbounds[dep_dim])
-                      dvs11.push_back(dv);
-                    
-                    if (lb != -posInfinity)
-                      dv.lbounds[dep_dim] = ceil(
-                        static_cast<double>(lb)
-                        / new_stride)
-                        * new_stride;
-                    if (ub != posInfinity)
-                      dv.ubounds[dep_dim] = ceil(
-                        static_cast<double>(ub)
-                        / new_stride)
-                        * new_stride;
-                    if (dv.ubounds[dep_dim]
-                        >= dv.lbounds[dep_dim])
-                      dvs21.push_back(dv);
-                    
-                    if (lb != -posInfinity)
-                      dv.lbounds[dep_dim] = floor(
-                        static_cast<double>(lb)
-                        / new_stride)
-                        * new_stride;
-                    if (ub != posInfinity)
-                      dv.ubounds[dep_dim] = floor(
-                        static_cast<double>(ub
-                                            - stride)
-                        / new_stride)
-                        * new_stride;
-                    if (dv.ubounds[dep_dim]
-                        >= dv.lbounds[dep_dim])
-                      dvs12.push_back(dv);
-                    
-                    if (lb != -posInfinity)
-                      dv.lbounds[dep_dim] = floor(
-                        static_cast<double>(lb)
-                        / new_stride)
-                        * new_stride;
-                    if (ub != posInfinity)
-                      dv.ubounds[dep_dim] = ceil(
-                        static_cast<double>(ub
-                                            - stride)
-                        / new_stride)
-                        * new_stride;
-                    if (dv.ubounds[dep_dim]
-                        >= dv.lbounds[dep_dim])
-                      dvs22.push_back(dv);
-                  }
-                }
-              }
-              if (dvs11.size() > 0)
-                D.push_back(std::make_pair(i, dvs11));
-              if (dvs22.size() > 0)
-                dep.connect(old_num_stmt, old_num_stmt, dvs22);
-              if (dvs12.size() > 0)
-                D.push_back(
-                  std::make_pair(old_num_stmt, dvs12));
-              if (dvs21.size() > 0)
-                dep.connect(old_num_stmt, i, dvs21);
-              
-              dep.vertex[i].second.erase(j++);
-            } else {
-              dep.connect(old_num_stmt, j->first, j->second);
-              j++;
-            }
-          } else {
-            if (same_loop.find(j->first) != same_loop.end())
-              D.push_back(
-                std::make_pair(old_num_stmt, j->second));
-            j++;
-          }
-        }
-        
-        for (int j = 0; j < D.size(); j++)
-          dep.connect(i, D[j].first, D[j].second);
-      }
-    }
-  }
-  
-  return new_stmts;
-}
-
-
diff --git a/chill/src/omegatools.cc b/chill/src/omegatools.cc
deleted file mode 100644
index 3aac404..0000000
--- a/chill/src/omegatools.cc
+++ /dev/null
@@ -1,1185 +0,0 @@
-/*****************************************************************************
- Copyright (C) 2008 University of Southern California
- Copyright (C) 2009-2010 University of Utah
- All Rights Reserved.
-
- Purpose:
-   Useful tools involving Omega manipulation.
-
- Notes:
-
- History:
-   01/2006 Created by Chun Chen.
-   03/2009 Upgrade Omega's interaction with compiler to IR_Code, by Chun Chen.
-*****************************************************************************/
-
-#include <code_gen/codegen.h>
-#include "omegatools.hh"
-#include "ir_code.hh"
-#include "chill_error.hh"
-
-using namespace omega;
-
-namespace {
-  struct DependenceLevel {
-    Relation r;
-    int level;
-    int dir; // direction upto current level:
-    // -1:negative, 0: undetermined, 1: postive
-    std::vector<coef_t> lbounds;
-    std::vector<coef_t> ubounds;
-    DependenceLevel(const Relation &_r, int _dims):
-      r(_r), level(0), dir(0), lbounds(_dims), ubounds(_dims) {}
-  };
-}
-
-
-
-
-std::string tmp_e() {
-  static int counter = 1;
-  return std::string("e")+to_string(counter++);
-}
-
-void exp2formula(IR_Code *ir, Relation &r, F_And *f_root, std::vector<Free_Var_Decl*> &freevars,
-                 CG_outputRepr *repr, Variable_ID lhs, char side, IR_CONDITION_TYPE rel, bool destroy) {
-  
-  switch (ir->QueryExpOperation(repr)) {
-  case IR_OP_CONSTANT:
-  {
-    std::vector<CG_outputRepr *> v = ir->QueryExpOperand(repr);
-    IR_ConstantRef *ref = static_cast<IR_ConstantRef *>(ir->Repr2Ref(v[0]));
-    if (!ref->is_integer())
-      throw ir_exp_error("non-integer constant coefficient");
-    
-    coef_t c = ref->integer();
-    if (rel == IR_COND_GE || rel == IR_COND_GT) {
-      GEQ_Handle h = f_root->add_GEQ();
-      h.update_coef(lhs, 1);
-      if (rel == IR_COND_GE)
-        h.update_const(-c);
-      else
-        h.update_const(-c-1);
-    }
-    else if (rel == IR_COND_LE || rel == IR_COND_LT) {
-      GEQ_Handle h = f_root->add_GEQ();
-      h.update_coef(lhs, -1);
-      if (rel == IR_COND_LE)
-        h.update_const(c);
-      else
-        h.update_const(c-1);
-    }
-    else if (rel == IR_COND_EQ) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(lhs, 1);
-      h.update_const(-c);
-    }
-    else
-      throw std::invalid_argument("unsupported condition type");
-    
-    delete v[0];
-    delete ref;
-    if (destroy)
-      delete repr;
-    break;
-  }
-  case IR_OP_VARIABLE:
-  {
-    std::vector<CG_outputRepr *> v = ir->QueryExpOperand(repr);
-    IR_ScalarRef *ref = static_cast<IR_ScalarRef *>(ir->Repr2Ref(v[0]));
-    
-    std::string s = ref->name();
-    Variable_ID e = find_index(r, s, side);
-    
-    if (e == NULL) { // must be free variable
-      Free_Var_Decl *t = NULL;
-      for (unsigned i = 0; i < freevars.size(); i++) {
-        std::string ss = freevars[i]->base_name();
-        if (s == ss) {
-          t = freevars[i];
-          break;
-        }
-      }
-      
-      if (t == NULL) {
-        t = new Free_Var_Decl(s);
-        freevars.insert(freevars.end(), t);
-      }
-      
-      e = r.get_local(t);
-    }
-    
-    if (rel == IR_COND_GE || rel == IR_COND_GT) {
-      GEQ_Handle h = f_root->add_GEQ();
-      h.update_coef(lhs, 1);
-      h.update_coef(e, -1);
-      if (rel == IR_COND_GT)
-        h.update_const(-1);
-    }
-    else if (rel == IR_COND_LE || rel == IR_COND_LT) {
-      GEQ_Handle h = f_root->add_GEQ();
-      h.update_coef(lhs, -1);
-      h.update_coef(e, 1);
-      if (rel == IR_COND_LT)
-        h.update_const(-1);
-    }
-    else if (rel == IR_COND_EQ) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(lhs, 1);
-      h.update_coef(e, -1);
-    }
-    else
-      throw std::invalid_argument("unsupported condition type");
-    
-    //  delete v[0];
-    delete ref;
-    if (destroy)
-      delete repr;
-    break;
-  }
-  case IR_OP_ASSIGNMENT:
-  {
-    std::vector<CG_outputRepr *> v = ir->QueryExpOperand(repr);
-    exp2formula(ir, r, f_root, freevars, v[0], lhs, side, rel, true);
-    if (destroy)
-      delete repr;
-    break;
-  }
-  case IR_OP_PLUS:
-  {
-    F_Exists *f_exists = f_root->add_exists();
-    Variable_ID e1 = f_exists->declare(tmp_e());
-    Variable_ID e2 = f_exists->declare(tmp_e());
-    F_And *f_and = f_exists->add_and();
-    
-    if (rel == IR_COND_GE || rel == IR_COND_GT) {
-      GEQ_Handle h = f_and->add_GEQ();
-      h.update_coef(lhs, 1);
-      h.update_coef(e1, -1);
-      h.update_coef(e2, -1);
-      if (rel == IR_COND_GT)
-        h.update_const(-1);
-    }
-    else if (rel == IR_COND_LE || rel == IR_COND_LT) {
-      GEQ_Handle h = f_and->add_GEQ();
-      h.update_coef(lhs, -1);
-      h.update_coef(e1, 1);
-      h.update_coef(e2, 1);
-      if (rel == IR_COND_LT)
-        h.update_const(-1);
-    }
-    else if (rel == IR_COND_EQ) {
-      EQ_Handle h = f_and->add_EQ();
-      h.update_coef(lhs, 1);
-      h.update_coef(e1, -1);
-      h.update_coef(e2, -1);
-    }
-    else
-      throw std::invalid_argument("unsupported condition type");
-    
-    std::vector<CG_outputRepr *> v = ir->QueryExpOperand(repr);
-    exp2formula(ir, r, f_and, freevars, v[0], e1, side, IR_COND_EQ, true);
-    exp2formula(ir, r, f_and, freevars, v[1], e2, side, IR_COND_EQ, true);
-    if (destroy)
-      delete repr;
-    break;
-  }
-  case IR_OP_MINUS:
-  {
-    F_Exists *f_exists = f_root->add_exists();
-    Variable_ID e1 = f_exists->declare(tmp_e());
-    Variable_ID e2 = f_exists->declare(tmp_e());
-    F_And *f_and = f_exists->add_and();
-    
-    if (rel == IR_COND_GE || rel == IR_COND_GT) {
-      GEQ_Handle h = f_and->add_GEQ();
-      h.update_coef(lhs, 1);
-      h.update_coef(e1, -1);
-      h.update_coef(e2, 1);
-      if (rel == IR_COND_GT)
-        h.update_const(-1);
-    }
-    else if (rel == IR_COND_LE || rel == IR_COND_LT) {
-      GEQ_Handle h = f_and->add_GEQ();
-      h.update_coef(lhs, -1);
-      h.update_coef(e1, 1);
-      h.update_coef(e2, -1);
-      if (rel == IR_COND_LT)
-        h.update_const(-1);
-    }
-    else if (rel == IR_COND_EQ) {
-      EQ_Handle h = f_and->add_EQ();
-      h.update_coef(lhs, 1);
-      h.update_coef(e1, -1);
-      h.update_coef(e2, 1);
-    }
-    else
-      throw std::invalid_argument("unsupported condition type");
-    
-    std::vector<CG_outputRepr *> v = ir->QueryExpOperand(repr);
-    exp2formula(ir, r, f_and, freevars, v[0], e1, side, IR_COND_EQ, true);
-    exp2formula(ir, r, f_and, freevars, v[1], e2, side, IR_COND_EQ, true);
-    if (destroy)
-      delete repr;
-    break;
-  }
-  case IR_OP_MULTIPLY:
-  {
-    std::vector<CG_outputRepr *> v = ir->QueryExpOperand(repr);
-    
-    coef_t coef;
-    CG_outputRepr *term;
-    if (ir->QueryExpOperation(v[0]) == IR_OP_CONSTANT) {
-      IR_ConstantRef *ref = static_cast<IR_ConstantRef *>(ir->Repr2Ref(v[0]));
-      coef = ref->integer();
-      delete v[0];
-      delete ref;
-      term = v[1];
-    }
-    else if (ir->QueryExpOperation(v[1]) == IR_OP_CONSTANT) {
-      IR_ConstantRef *ref = static_cast<IR_ConstantRef *>(ir->Repr2Ref(v[1]));
-      coef = ref->integer();
-      delete v[1];
-      delete ref;
-      term = v[0];
-    }
-    else
-      throw ir_exp_error("not presburger expression");
-    
-    F_Exists *f_exists = f_root->add_exists();
-    Variable_ID e = f_exists->declare(tmp_e());
-    F_And *f_and = f_exists->add_and();
-    
-    if (rel == IR_COND_GE || rel == IR_COND_GT) {
-      GEQ_Handle h = f_and->add_GEQ();
-      h.update_coef(lhs, 1);
-      h.update_coef(e, -coef);
-      if (rel == IR_COND_GT)
-        h.update_const(-1);
-    }
-    else if (rel == IR_COND_LE || rel == IR_COND_LT) {
-      GEQ_Handle h = f_and->add_GEQ();
-      h.update_coef(lhs, -1);
-      h.update_coef(e, coef);
-      if (rel == IR_COND_LT)
-        h.update_const(-1);
-    }
-    else if (rel == IR_COND_EQ) {
-      EQ_Handle h = f_and->add_EQ();
-      h.update_coef(lhs, 1);
-      h.update_coef(e, -coef);
-    }
-    else
-      throw std::invalid_argument("unsupported condition type");
-    
-    exp2formula(ir, r, f_and, freevars, term, e, side, IR_COND_EQ, true);
-    if (destroy)
-      delete repr;
-    break;
-  }
-  case IR_OP_DIVIDE:
-  {
-    std::vector<CG_outputRepr *> v = ir->QueryExpOperand(repr);
-    
-    assert(ir->QueryExpOperation(v[1]) == IR_OP_CONSTANT);
-    IR_ConstantRef *ref = static_cast<IR_ConstantRef *>(ir->Repr2Ref(v[1]));
-    coef_t coef = ref->integer();
-    delete v[1];
-    delete ref;
-    
-    F_Exists *f_exists = f_root->add_exists();
-    Variable_ID e = f_exists->declare(tmp_e());
-    F_And *f_and = f_exists->add_and();
-    
-    if (rel == IR_COND_GE || rel == IR_COND_GT) {
-      GEQ_Handle h = f_and->add_GEQ();
-      h.update_coef(lhs, coef);
-      h.update_coef(e, -1);
-      if (rel == IR_COND_GT)
-        h.update_const(-1);
-    }
-    else if (rel == IR_COND_LE || rel == IR_COND_LT) {
-      GEQ_Handle h = f_and->add_GEQ();
-      h.update_coef(lhs, -coef);
-      h.update_coef(e, 1);
-      if (rel == IR_COND_LT)
-        h.update_const(-1);
-    }
-    else if (rel == IR_COND_EQ) {
-      EQ_Handle h = f_and->add_EQ();
-      h.update_coef(lhs, coef);
-      h.update_coef(e, -1);
-    }
-    else
-      throw std::invalid_argument("unsupported condition type");
-    
-    exp2formula(ir, r, f_and, freevars, v[0], e, side, IR_COND_EQ, true);
-    if (destroy)
-      delete repr;
-    break;
-  }
-  case IR_OP_POSITIVE:
-  {
-    std::vector<CG_outputRepr *> v = ir->QueryExpOperand(repr);
-    
-    exp2formula(ir, r, f_root, freevars, v[0], lhs, side, rel, true);
-    if (destroy)
-      delete repr;
-    break;
-  }
-  case IR_OP_NEGATIVE:
-  {
-    std::vector<CG_outputRepr *> v = ir->QueryExpOperand(repr);
-    
-    F_Exists *f_exists = f_root->add_exists();
-    Variable_ID e = f_exists->declare(tmp_e());
-    F_And *f_and = f_exists->add_and();
-    
-    if (rel == IR_COND_GE || rel == IR_COND_GT) {
-      GEQ_Handle h = f_and->add_GEQ();
-      h.update_coef(lhs, 1);
-      h.update_coef(e, 1);
-      if (rel == IR_COND_GT)
-        h.update_const(-1);
-    }
-    else if (rel == IR_COND_LE || rel == IR_COND_LT) {
-      GEQ_Handle h = f_and->add_GEQ();
-      h.update_coef(lhs, -1);
-      h.update_coef(e, -1);
-      if (rel == IR_COND_LT)
-        h.update_const(-1);
-    }
-    else if (rel == IR_COND_EQ) {
-      EQ_Handle h = f_and->add_EQ();
-      h.update_coef(lhs, 1);
-      h.update_coef(e, 1);
-    }
-    else
-      throw std::invalid_argument("unsupported condition type");
-    
-    exp2formula(ir, r, f_and, freevars, v[0], e, side, IR_COND_EQ, true);
-    if (destroy)
-      delete repr;
-    break;
-  }
-  case IR_OP_MIN:
-  {
-    std::vector<CG_outputRepr *> v = ir->QueryExpOperand(repr);
-    
-    F_Exists *f_exists = f_root->add_exists();
-    
-    if (rel == IR_COND_GE || rel == IR_COND_GT) {
-      F_Or *f_or = f_exists->add_and()->add_or();
-      for (int i = 0; i < v.size(); i++) {
-        Variable_ID e = f_exists->declare(tmp_e());
-        F_And *f_and = f_or->add_and();
-        GEQ_Handle h = f_and->add_GEQ();
-        h.update_coef(lhs, 1);
-        h.update_coef(e, -1);
-        if (rel == IR_COND_GT)
-          h.update_const(-1);
-        
-        exp2formula(ir, r, f_and, freevars, v[i], e, side, IR_COND_EQ, true);
-      }
-    }
-    else if (rel == IR_COND_LE || rel == IR_COND_LT) {
-      F_And *f_and = f_exists->add_and();
-      for (int i = 0; i < v.size(); i++) {
-        Variable_ID e = f_exists->declare(tmp_e());        
-        GEQ_Handle h = f_and->add_GEQ();
-        h.update_coef(lhs, -1);
-        h.update_coef(e, 1);
-        if (rel == IR_COND_LT)
-          h.update_const(-1);
-        
-        exp2formula(ir, r, f_and, freevars, v[i], e, side, IR_COND_EQ, true);
-      }
-    }
-    else if (rel == IR_COND_EQ) {
-      F_Or *f_or = f_exists->add_and()->add_or();
-      for (int i = 0; i < v.size(); i++) {
-        Variable_ID e = f_exists->declare(tmp_e());
-        F_And *f_and = f_or->add_and();
-        
-        EQ_Handle h = f_and->add_EQ();
-        h.update_coef(lhs, 1);
-        h.update_coef(e, -1);
-        
-        exp2formula(ir, r, f_and, freevars, v[i], e, side, IR_COND_EQ, false);
-        
-        for (int j = 0; j < v.size(); j++)
-          if (j != i) {
-            Variable_ID e2 = f_exists->declare(tmp_e());
-            GEQ_Handle h2 = f_and->add_GEQ();
-            h2.update_coef(e, -1);
-            h2.update_coef(e2, 1);
-            
-            exp2formula(ir, r, f_and, freevars, v[j], e2, side, IR_COND_EQ, false);
-          }
-      }
-      
-      for (int i = 0; i < v.size(); i++)
-        delete v[i];
-    }
-    else
-      throw std::invalid_argument("unsupported condition type");
-    
-    if (destroy)
-      delete repr;
-  }
-  case IR_OP_MAX:
-  {
-    std::vector<CG_outputRepr *> v = ir->QueryExpOperand(repr);
-    
-    F_Exists *f_exists = f_root->add_exists();
-    
-    if (rel == IR_COND_LE || rel == IR_COND_LT) {
-      F_Or *f_or = f_exists->add_and()->add_or();
-      for (int i = 0; i < v.size(); i++) {
-        Variable_ID e = f_exists->declare(tmp_e());
-        F_And *f_and = f_or->add_and();
-        GEQ_Handle h = f_and->add_GEQ();
-        h.update_coef(lhs, -1);
-        h.update_coef(e, 1);
-        if (rel == IR_COND_LT)
-          h.update_const(-1);
-        
-        exp2formula(ir, r, f_and, freevars, v[i], e, side, IR_COND_EQ, true);
-      }
-    }
-    else if (rel == IR_COND_GE || rel == IR_COND_GT) {
-      F_And *f_and = f_exists->add_and();
-      for (int i = 0; i < v.size(); i++) {
-        Variable_ID e = f_exists->declare(tmp_e());        
-        GEQ_Handle h = f_and->add_GEQ();
-        h.update_coef(lhs, 1);
-        h.update_coef(e, -1);
-        if (rel == IR_COND_GT)
-          h.update_const(-1);
-        
-        exp2formula(ir, r, f_and, freevars, v[i], e, side, IR_COND_EQ, true);
-      }
-    }
-    else if (rel == IR_COND_EQ) {
-      F_Or *f_or = f_exists->add_and()->add_or();
-      for (int i = 0; i < v.size(); i++) {
-        Variable_ID e = f_exists->declare(tmp_e());
-        F_And *f_and = f_or->add_and();
-        
-        EQ_Handle h = f_and->add_EQ();
-        h.update_coef(lhs, 1);
-        h.update_coef(e, -1);
-        
-        exp2formula(ir, r, f_and, freevars, v[i], e, side, IR_COND_EQ, false);
-        
-        for (int j = 0; j < v.size(); j++)
-          if (j != i) {
-            Variable_ID e2 = f_exists->declare(tmp_e());
-            GEQ_Handle h2 = f_and->add_GEQ();
-            h2.update_coef(e, 1);
-            h2.update_coef(e2, -1);
-            
-            exp2formula(ir, r, f_and, freevars, v[j], e2, side, IR_COND_EQ, false);
-          }
-      }
-      
-      for (int i = 0; i < v.size(); i++)
-        delete v[i];
-    }
-    else
-      throw std::invalid_argument("unsupported condition type");
-    
-    if (destroy)
-      delete repr;
-  }
-  case IR_OP_NULL:
-    break;
-  default:
-    throw ir_exp_error("unsupported operand type");
-  }
-}
-
-Relation arrays2relation(IR_Code *ir, std::vector<Free_Var_Decl*> &freevars,
-                         const IR_ArrayRef *ref_src, const Relation &IS_w,
-                         const IR_ArrayRef *ref_dst, const Relation &IS_r) {
-  Relation &IS1 = const_cast<Relation &>(IS_w);
-  Relation &IS2 = const_cast<Relation &>(IS_r);
-  
-  Relation r(IS1.n_set(), IS2.n_set());
-  
-  for (int i = 1; i <= IS1.n_set(); i++)
-    r.name_input_var(i, IS1.set_var(i)->name());
-  
-  for (int i = 1; i <= IS2.n_set(); i++)
-    r.name_output_var(i, IS2.set_var(i)->name()+"'");
-  
-  IR_Symbol *sym_src = ref_src->symbol();
-  IR_Symbol *sym_dst = ref_dst->symbol();
-  if (*sym_src != *sym_dst) {
-    r.add_or(); // False Relation
-    delete sym_src;
-    delete sym_dst;
-    return r;
-  }
-  else {
-    delete sym_src;
-    delete sym_dst;
-  }
-  
-  F_And *f_root = r.add_and();
-  
-  for (int i = 0; i < ref_src->n_dim(); i++) {
-    F_Exists *f_exists = f_root->add_exists();
-    Variable_ID e1 = f_exists->declare(tmp_e());
-    Variable_ID e2 = f_exists->declare(tmp_e());
-    F_And *f_and = f_exists->add_and();
-    
-    CG_outputRepr *repr_src = ref_src->index(i);
-    CG_outputRepr *repr_dst = ref_dst->index(i);
-    
-    bool has_complex_formula = false;
-    try {
-      exp2formula(ir, r, f_and, freevars, repr_src, e1, 'w', IR_COND_EQ, false);
-      exp2formula(ir, r, f_and, freevars, repr_dst, e2, 'r', IR_COND_EQ, false);
-    }
-    catch (const ir_exp_error &e) {
-      has_complex_formula = true;
-    }
-    
-    if (!has_complex_formula) {
-      EQ_Handle h = f_and->add_EQ();
-      h.update_coef(e1, 1);
-      h.update_coef(e2, -1);
-    }
-    
-    repr_src->clear();
-    repr_dst->clear();
-    delete repr_src;
-    delete repr_dst;
-  }
-  
-  // add iteration space restriction
-  r = Restrict_Domain(r, copy(IS1));
-  r = Restrict_Range(r, copy(IS2));
-  
-  // reset the output variable names lost in restriction
-  for (int i = 1; i <= IS2.n_set(); i++)
-    r.name_output_var(i, IS2.set_var(i)->name()+"'");
-  
-  return r;
-}
-
-std::pair<std::vector<DependenceVector>, std::vector<DependenceVector> > relation2dependences (const IR_ArrayRef *ref_src, const IR_ArrayRef *ref_dst, const Relation &r) {
-  assert(r.n_inp() == r.n_out());
-  
-  std::vector<DependenceVector> dependences1, dependences2;  
-  std::stack<DependenceLevel> working;
-  working.push(DependenceLevel(r, r.n_inp()));
-  
-  while (!working.empty()) {
-    DependenceLevel dep = working.top();
-    working.pop();
-    
-    // No dependence exists, move on.
-    if (!dep.r.is_satisfiable())
-      continue;
-    
-    if (dep.level == r.n_inp()) {
-      DependenceVector dv;
-      
-      // for loop independent dependence, use lexical order to
-      // determine the correct source and destination
-      if (dep.dir == 0) {
-        if (*ref_src == *ref_dst)
-          continue; // trivial self zero-dependence
-        
-        if (ref_src->is_write()) {
-          if (ref_dst->is_write())
-            dv.type = DEP_W2W;
-          else
-            dv.type = DEP_W2R;
-        }
-        else {
-          if (ref_dst->is_write())
-            dv.type = DEP_R2W;
-          else
-            dv.type = DEP_R2R;
-        }
-        
-      }
-      else if (dep.dir == 1) {
-        if (ref_src->is_write()) {
-          if (ref_dst->is_write())
-            dv.type = DEP_W2W;
-          else
-            dv.type = DEP_W2R;
-        }
-        else {
-          if (ref_dst->is_write())
-            dv.type = DEP_R2W;
-          else
-            dv.type = DEP_R2R;
-        }
-      }
-      else { // dep.dir == -1
-        if (ref_dst->is_write()) {
-          if (ref_src->is_write())
-            dv.type = DEP_W2W;
-          else
-            dv.type = DEP_W2R;
-        }
-        else {
-          if (ref_src->is_write())
-            dv.type = DEP_R2W;
-          else
-            dv.type = DEP_R2R;
-        }
-      }
-      
-      dv.lbounds = dep.lbounds;
-      dv.ubounds = dep.ubounds;
-      dv.sym = ref_src->symbol();
-      
-      if (dep.dir == 0 || dep.dir == 1)
-        dependences1.push_back(dv);
-      else
-        dependences2.push_back(dv);
-    }
-    else {
-      // now work on the next dimension level
-      int level = ++dep.level;
-      
-      coef_t lbound, ubound;
-      Relation delta = Deltas(copy(dep.r));
-      delta.query_variable_bounds(delta.set_var(level), lbound, ubound);
-      
-      if (dep.dir == 0) {
-        if (lbound > 0) {
-          dep.dir = 1;
-          dep.lbounds[level-1] = lbound;
-          dep.ubounds[level-1] = ubound;
-          
-          working.push(dep);
-        }
-        else if (ubound < 0) {
-          dep.dir = -1;
-          dep.lbounds[level-1] = -ubound;
-          dep.ubounds[level-1] = -lbound;
-          
-          working.push(dep);
-        }
-        else {
-          // split the dependence vector into flow- and anti-dependence
-          // for the first non-zero distance, also separate zero distance
-          // at this level.
-          {
-            DependenceLevel dep2 = dep;
-            
-            dep2.lbounds[level-1] =  0;
-            dep2.ubounds[level-1] =  0;
-            
-            F_And *f_root = dep2.r.and_with_and();
-            EQ_Handle h = f_root->add_EQ();
-            h.update_coef(dep2.r.input_var(level), 1);
-            h.update_coef(dep2.r.output_var(level), -1);
-            
-            working.push(dep2);
-          }
-          
-          if (lbound < 0 && *ref_src != *ref_dst) {
-            DependenceLevel dep2 = dep;
-            
-            F_And *f_root = dep2.r.and_with_and();
-            GEQ_Handle h = f_root->add_GEQ();
-            h.update_coef(dep2.r.input_var(level), 1);
-            h.update_coef(dep2.r.output_var(level), -1);
-            h.update_const(-1);
-            
-            // get tighter bounds under new constraints
-            coef_t lbound, ubound;
-            delta = Deltas(copy(dep2.r));
-            delta.query_variable_bounds(delta.set_var(level),
-                                        lbound, ubound);
-            
-            dep2.dir = -1;            
-            dep2.lbounds[level-1] = max(-ubound,static_cast<coef_t>(1)); // use max() to avoid Omega retardness
-            dep2.ubounds[level-1] = -lbound;
-            
-            working.push(dep2);
-          }
-          
-          if (ubound > 0) {
-            DependenceLevel dep2 = dep;
-            
-            F_And *f_root = dep2.r.and_with_and();
-            GEQ_Handle h = f_root->add_GEQ();
-            h.update_coef(dep2.r.input_var(level), -1);
-            h.update_coef(dep2.r.output_var(level), 1);
-            h.update_const(-1);
-            
-            // get tighter bonds under new constraints
-            coef_t lbound, ubound;
-            delta = Deltas(copy(dep2.r));
-            delta.query_variable_bounds(delta.set_var(level),
-                                        lbound, ubound);
-            dep2.dir = 1;
-            dep2.lbounds[level-1] = max(lbound,static_cast<coef_t>(1)); // use max() to avoid Omega retardness
-            dep2.ubounds[level-1] = ubound;
-            
-            working.push(dep2);
-          }
-        }
-      }
-      // now deal with dependence vector with known direction
-      // determined at previous levels
-      else {
-        // For messy bounds, further test to see if the dependence distance
-        // can be reduced to positive/negative.  This is an omega hack.
-        if (lbound == negInfinity && ubound == posInfinity) {
-          {
-            Relation t = dep.r;
-            F_And *f_root = t.and_with_and();
-            GEQ_Handle h = f_root->add_GEQ();
-            h.update_coef(t.input_var(level), 1);
-            h.update_coef(t.output_var(level), -1);
-            h.update_const(-1);
-            
-            if (!t.is_satisfiable()) {
-              lbound = 0;
-            }
-          }
-          {
-            Relation t = dep.r;
-            F_And *f_root = t.and_with_and();
-            GEQ_Handle h = f_root->add_GEQ();
-            h.update_coef(t.input_var(level), -1);
-            h.update_coef(t.output_var(level), 1);
-            h.update_const(-1);
-            
-            if (!t.is_satisfiable()) {
-              ubound = 0;
-            }
-          }
-        }
-        
-        // Same thing as above, test to see if zero dependence
-        // distance possible.
-        if (lbound == 0 || ubound == 0) {
-          Relation t = dep.r;
-          F_And *f_root = t.and_with_and();
-          EQ_Handle h = f_root->add_EQ();
-          h.update_coef(t.input_var(level), 1);
-          h.update_coef(t.output_var(level), -1);
-          
-          if (!t.is_satisfiable()) {
-            if (lbound == 0)
-              lbound = 1;
-            if (ubound == 0)
-              ubound = -1;
-          }
-        }
-        
-        if (dep.dir == -1) {
-          dep.lbounds[level-1] = -ubound;
-          dep.ubounds[level-1] = -lbound;
-        }
-        else { // dep.dir == 1
-          dep.lbounds[level-1] = lbound;
-          dep.ubounds[level-1] = ubound;
-        }
-        
-        working.push(dep);
-      }
-    }
-  }
-  
-  return std::make_pair(dependences1, dependences2);
-}
-
-void exp2constraint(IR_Code *ir, Relation &r, F_And *f_root,
-                    std::vector<Free_Var_Decl *> &freevars,
-                    CG_outputRepr *repr, bool destroy) {
-  IR_CONDITION_TYPE cond = ir->QueryBooleanExpOperation(repr);
-  switch (cond) {
-  case IR_COND_LT:
-  case IR_COND_LE:
-  case IR_COND_EQ:
-  case IR_COND_GT:
-  case IR_COND_GE: {
-    F_Exists *f_exist = f_root->add_exists();
-    Variable_ID e = f_exist->declare();
-    F_And *f_and = f_exist->add_and();
-    std::vector<omega::CG_outputRepr *> op = ir->QueryExpOperand(repr);
-    exp2formula(ir, r, f_and, freevars, op[0], e, 's', IR_COND_EQ, true);
-    exp2formula(ir, r, f_and, freevars, op[1], e, 's', cond, true);
-    if (destroy)
-      delete repr;
-    break;
-  }
-  case IR_COND_NE: {
-    F_Exists *f_exist = f_root->add_exists();
-    Variable_ID e = f_exist->declare();
-    F_Or *f_or = f_exist->add_or();
-    F_And *f_and = f_or->add_and();
-    std::vector<omega::CG_outputRepr *> op = ir->QueryExpOperand(repr);
-    exp2formula(ir, r, f_and, freevars, op[0], e, 's', IR_COND_EQ, false);
-    exp2formula(ir, r, f_and, freevars, op[1], e, 's', IR_COND_GT, false);
-    
-    f_and = f_or->add_and();
-    exp2formula(ir, r, f_and, freevars, op[0], e, 's', IR_COND_EQ, true);
-    exp2formula(ir, r, f_and, freevars, op[1], e, 's', IR_COND_LT, true);
-    
-    if (destroy)
-      delete repr;
-    break;
-  }    
-  default:
-    throw ir_exp_error("unrecognized conditional expression");
-  }
-}
-
-bool is_single_loop_iteration(const Relation &r, int level, const Relation &known) {
-  int n = r.n_set();
-  Relation r1 = Intersection(copy(r), Extend_Set(copy(known), n-known.n_set()));
-  
-  Relation mapping(n, n);
-  F_And *f_root = mapping.add_and();
-  for (int i = 1; i <= level; i++) {
-    EQ_Handle h = f_root->add_EQ();
-    h.update_coef(mapping.input_var(i), 1);
-    h.update_coef(mapping.output_var(i), -1);
-  }
-  r1 = Range(Restrict_Domain(mapping, r1));
-  r1.simplify();
-  
-  Variable_ID v = r1.set_var(level);
-  for (DNF_Iterator di(r1.query_DNF()); di; di++) {
-    bool is_single = false;
-    for (EQ_Iterator ei((*di)->EQs()); ei; ei++)
-      if ((*ei).get_coef(v) != 0 && !(*ei).has_wildcards()) {
-        is_single = true;
-        break;
-      }
-    
-    if (!is_single)
-      return false;
-  }
-  
-  return true;
-}
-
-
-bool is_single_iteration(const Relation &r, int dim) {
-  assert(r.is_set());
-  const int n = r.n_set();
-  
-  if (dim >= n)
-    return true;
-  
-  Relation bound = get_loop_bound(r, dim);
-  
-  for (DNF_Iterator di(bound.query_DNF()); di; di++) {
-    bool is_single = false;
-    for (EQ_Iterator ei((*di)->EQs()); ei; ei++)
-      if (!(*ei).has_wildcards()) {
-        is_single = true;
-        break;
-      }
-    
-    if (!is_single)
-      return false;
-  }
-  
-  return true;
-}
-
-void assign_const(Relation &r, int dim, int val) {
-  const int n = r.n_out();
-  
-  Relation mapping(n, n);
-  F_And *f_root = mapping.add_and();
-  
-  for (int i = 1; i <= n; i++) {
-    if (i != dim+1) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(mapping.output_var(i), 1);
-      h.update_coef(mapping.input_var(i), -1);
-    }
-    else {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(mapping.output_var(i), 1);
-      h.update_const(-val);
-    }
-  }
-  
-  r = Composition(mapping, r);
-}
-
-
-int get_const(const Relation &r, int dim, Var_Kind type) {
-  Relation &rr = const_cast<Relation &>(r);
-  
-  Variable_ID v;
-  switch (type) {
-  case Input_Var:
-    v = rr.input_var(dim+1);
-    break;
-  case Output_Var:
-    v = rr.output_var(dim+1);
-    break;
-  default:
-    throw std::invalid_argument("unsupported variable type");
-  }
-  
-  for (DNF_Iterator di(rr.query_DNF()); di; di++)
-    for (EQ_Iterator ei = (*di)->EQs(); ei; ei++)
-      if ((*ei).is_const(v))
-        return (*ei).get_const();
-  
-  throw std::runtime_error("cannot get variable's constant value");
-}
-
-Relation get_loop_bound(const Relation &r, int dim) {
-  assert(r.is_set());
-  const int n = r.n_set();
-  
-  Relation mapping(n,n);
-  F_And *f_root = mapping.add_and();
-  for (int i = 1; i <= dim+1; i++) {
-    EQ_Handle h = f_root->add_EQ();
-    h.update_coef(mapping.input_var(i), 1);
-    h.update_coef(mapping.output_var(i), -1);
-  }
-  Relation r1 = Range(Restrict_Domain(mapping, copy(r)));
-  for (int i = 1; i <= n; i++)
-    r1.name_set_var(i, const_cast<Relation &>(r).set_var(i)->name());
-  r1.setup_names();
-  Relation r2 = Project(copy(r1), dim+1, Set_Var);
-  
-  return Gist(r1, r2, 1);
-}
-
-Relation get_loop_bound(const Relation &r, int level, const Relation &known) {
-  int n = r.n_set();
-  Relation r1 = Intersection(copy(r), Extend_Set(copy(known), n-known.n_set()));
-  
-  Relation mapping(n, n);
-  F_And *f_root = mapping.add_and();
-  for (int i = 1; i <= level; i++) {
-    EQ_Handle h = f_root->add_EQ();
-    h.update_coef(mapping.input_var(i), 1);
-    h.update_coef(mapping.output_var(i), -1);
-  }
-  r1 = Range(Restrict_Domain(mapping, r1));
-  Relation r2 = Project(copy(r1), level, Set_Var);
-  r1 = Gist(r1, r2, 1);
-  
-  for (int i = 1; i <= n; i++)
-    r1.name_set_var(i, const_cast<Relation &>(r).set_var(i)->name());
-  r1.setup_names();
-  
-  return r1;
-}
-
-
-
-Relation get_max_loop_bound(const std::vector<Relation> &r, int dim) {
-  if (r.size() == 0)
-    return Relation::Null();
-  
-  const int n = r[0].n_set();
-  Relation res(Relation::False(n));
-  for (int i = 0; i < r.size(); i++) {
-    Relation &t = const_cast<Relation &>(r[i]);
-    if (t.is_satisfiable())
-      res = Union(get_loop_bound(t, dim), res);
-  }
-  
-  res.simplify();
-  
-  return res;
-}
-
-Relation get_min_loop_bound(const std::vector<Relation> &r, int dim) {
-  if (r.size() == 0)
-    return Relation::Null();
-  
-  const int n = r[0].n_set();
-  Relation res(Relation::True(n));
-  for (int i = 0; i < r.size(); i++) {
-    Relation &t = const_cast<Relation &>(r[i]);
-    if (t.is_satisfiable())
-      res = Intersection(get_loop_bound(t, dim), res);
-  }
-  
-  res.simplify();
-  
-  return res;
-}
-
-void add_loop_stride(Relation &r, const Relation &bound_, int dim, int stride) {
-  F_And *f_root = r.and_with_and();
-  Relation &bound = const_cast<Relation &>(bound_);
-  for (DNF_Iterator di(bound.query_DNF()); di; di++) {
-    F_Exists *f_exists = f_root->add_exists();
-    Variable_ID e1 = f_exists->declare(tmp_e());
-    Variable_ID e2 = f_exists->declare(tmp_e());
-    F_And *f_and = f_exists->add_and();
-    EQ_Handle stride_eq = f_and->add_EQ();
-    stride_eq.update_coef(e1, 1);
-    stride_eq.update_coef(e2, stride);
-    if (!r.is_set())
-      stride_eq.update_coef(r.output_var(dim+1), -1);
-    else
-      stride_eq.update_coef(r.set_var(dim+1), -1);
-    F_Or *f_or = f_and->add_or();
-    
-    for (GEQ_Iterator gi = (*di)->GEQs(); gi; gi++) {
-      if ((*gi).get_coef(bound.set_var(dim+1)) > 0) {
-        // copy the lower bound constraint
-        EQ_Handle h1 = f_or->add_and()->add_EQ();
-        GEQ_Handle h2 = f_and->add_GEQ();
-        for (Constr_Vars_Iter ci(*gi); ci; ci++) {
-          switch ((*ci).var->kind()) {
-            // case Set_Var:
-          case Input_Var: {
-            int pos = (*ci).var->get_position();
-            if (pos == dim + 1) {
-              h1.update_coef(e1, (*ci).coef);
-              h2.update_coef(e1, (*ci).coef);
-            }
-            else {
-              if (!r.is_set()) {
-                h1.update_coef(r.output_var(pos), (*ci).coef);
-                h2.update_coef(r.output_var(pos), (*ci).coef);
-              }
-              else {
-                h1.update_coef(r.set_var(pos), (*ci).coef);
-                h2.update_coef(r.set_var(pos), (*ci).coef);
-              }                
-            }
-            break;
-          }
-          case Global_Var: {
-            Global_Var_ID g = (*ci).var->get_global_var();
-            h1.update_coef(r.get_local(g, (*ci).var->function_of()), (*ci).coef);
-            h2.update_coef(r.get_local(g, (*ci).var->function_of()), (*ci).coef);
-            break;
-          }
-          default:
-            break;
-          }
-        }
-        h1.update_const((*gi).get_const());
-        h2.update_const((*gi).get_const());
-      }
-    }
-  }
-}
-
-
-bool is_inner_loop_depend_on_level(const Relation &r, int level, const Relation &known) {
-  Relation r1 = Intersection(copy(r), Extend_Set(copy(known), r.n_set()-known.n_set()));
-  Relation r2 = copy(r1);
-  for (int i = level+1; i <= r2.n_set(); i++)
-    r2 = Project(r2, r2.set_var(i));
-  r2.simplify(2, 4);
-  Relation r3 = Gist(r1, r2);
-  
-  Variable_ID v = r3.set_var(level);
-  for (DNF_Iterator di(r3.query_DNF()); di; di++) {
-    for (EQ_Iterator ei = (*di)->EQs(); ei; ei++)
-      if ((*ei).get_coef(v) != 0)
-        return true;
-    
-    for (GEQ_Iterator gi = (*di)->GEQs(); gi; gi++)
-      if ((*gi).get_coef(v) != 0)
-        return true;
-  }
-  
-  return false;
-}
-
-Relation adjust_loop_bound(const Relation &r, int level, int adjustment) {
-  if (adjustment == 0)
-    return copy(r);
-  
-  const int n = r.n_set();
-  Relation r1 = copy(r);
-  for (int i = level+1; i <= r1.n_set(); i++)
-    r1 = Project(r1, r1.set_var(i));
-  r1.simplify(2, 4);
-  Relation r2 = Gist(copy(r), copy(r1));
-  
-  Relation mapping(n, n);
-  F_And *f_root = mapping.add_and();
-  for (int i = 1; i <= n; i++)
-    if (i == level) {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(mapping.input_var(level), -1);
-      h.update_coef(mapping.output_var(level), 1);
-      h.update_const(static_cast<coef_t>(adjustment));
-    }
-    else {
-      EQ_Handle h = f_root->add_EQ();
-      h.update_coef(mapping.input_var(i), -1);
-      h.update_coef(mapping.output_var(i), 1);
-    }
-  
-  r2 = Range(Restrict_Domain(mapping, r2));
-  r1 = Intersection(r1, r2);
-  r1.simplify();
-  
-  for (int i = 1; i <= n; i++)
-    r1.name_set_var(i, const_cast<Relation &>(r).set_var(i)->name());
-  r1.setup_names();
-  return r1;
-}
-
-Relation permute_relation(const std::vector<int> &pi) {
-  const int n = pi.size();
-  
-  Relation r(n, n);
-  F_And *f_root = r.add_and();
-  
-  for (int i = 0; i < n; i++) {    
-    EQ_Handle h = f_root->add_EQ();
-    h.update_coef(r.output_var(i+1), 1);
-    h.update_coef(r.input_var(pi[i]+1), -1);
-  }
-  
-  return r;
-}
-
-Variable_ID find_index(Relation &r, const std::string &s, char side) {
-  // Omega quirks: assure the names are propagated inside the relation
-  r.setup_names();
-  
-  if (r.is_set()) { // side == 's'
-    for (int i = 1; i <= r.n_set(); i++) {
-      std::string ss = r.set_var(i)->name();
-      if (s == ss) {
-        return r.set_var(i);
-      }
-    }
-  }
-  else if (side == 'w') {
-    for (int i = 1; i <= r.n_inp(); i++) {
-      std::string ss = r.input_var(i)->name();
-      if (s == ss) {
-        return r.input_var(i);
-      }
-    }
-  }
-  else { // side == 'r'
-    for (int i = 1; i <= r.n_out(); i++) {
-      std::string ss = r.output_var(i)->name();
-      if (s+"'" == ss) {
-        return r.output_var(i);
-      }
-    }
-  }
-  
-  return NULL;
-}
-
diff --git a/chill/src/parse_expr.ll b/chill/src/parse_expr.ll
deleted file mode 100644
index a9b389f..0000000
--- a/chill/src/parse_expr.ll
+++ /dev/null
@@ -1,24 +0,0 @@
-%{
-// some C++ code
-#include "chill_run_util.hh"
-#include "parse_expr.tab.hh"
-%}
-
-%option noyywrap
-
-%%
-[ \t]+                  /*ignore*/
-\n                      /*ignore*/
-L[0-9]+                 { yylval.val = atoi(&yytext[1]); return LEVEL; }
-[0-9]+                  { yylval.val = atoi(yytext); return NUMBER; }
-\<\=                    return LE;
-\>\=                    return GE;
-\=(\=)?                 return EQ;
-[a-zA-Z_][a-zA-Z_0-9]*  {
-                           yylval.str_val = new char[yyleng+1];
-                           strcpy(yylval.str_val, yytext);
-                           return VARIABLE;
-                         }
-.                        return (int)yytext[0];
-%%
-
diff --git a/chill/src/parse_expr.yy b/chill/src/parse_expr.yy
deleted file mode 100644
index c2943c2..0000000
--- a/chill/src/parse_expr.yy
+++ /dev/null
@@ -1,85 +0,0 @@
-%{
-#include "chill_run_util.hh"
-#include "parse_expr.ll.hh"
-
-extern int yydebug;
-
-void yyerror(const char*);
-int yyparse(simap_vec_t** rel);
-
-static simap_vec_t* return_rel; // used as the return value for yyparse
-
-%}
-
-%union {
-  int val;
-  char* str_val;
-  simap_t* cond_item;
-  simap_vec_t* cond;
-}
-
-%token <val> NUMBER
-%token <val> LEVEL
-%token <str_val> VARIABLE
-
-%left LE GE EQ '<' '>'
-%left '-' '+' '*' '/'
-
-/*the final output from this language should be an Omega Relation object*/
-%type <cond> cond prog
-%type <cond_item> expr add_expr mul_expr neg_expr
-
-%%
-prog : cond                      { return_rel = make_prog($1); }
-;
-
-cond : expr '>' expr             { $$ = make_cond_gt($1, $3); }
-     | expr '<' expr             { $$ = make_cond_lt($1, $3); }
-     | expr GE expr              { $$ = make_cond_ge($1, $3); }
-     | expr LE expr              { $$ = make_cond_le($1, $3); }
-     | expr EQ expr              { $$ = make_cond_eq($1, $3); }
-;
-
-expr : add_expr                  { $$ = $1; }
-;
-
-add_expr : add_expr '+' mul_expr { $$ = make_cond_item_add($1,$3); }
-         | add_expr '-' mul_expr { $$ = make_cond_item_sub($1,$3); }
-         | mul_expr              { $$ = $1; }
-;
-
-mul_expr : mul_expr '*' neg_expr { $$ = make_cond_item_mul($1,$3); }
-         | neg_expr              { $$ = $1; }
-;
-
-neg_expr : '-' neg_expr          { $$ = make_cond_item_neg($2); }
-         | '(' expr ')'          { $$ = $2; }
-         | NUMBER                { $$ = make_cond_item_number($1); }
-         | LEVEL                 { $$ = make_cond_item_level($1); }
-         | VARIABLE              { $$ = make_cond_item_variable($1); }
-;
-%%
-
-void yyerror(const char* msg) {
-  fprintf(stderr, "Parse error: %s", msg);
-}
-
-simap_vec_t* parse_relation_vector(const char* expr) {
-  yydebug=0;
-  YY_BUFFER_STATE state;
-  
-  //if(yylex_init()) {
-  //   TODO: error out or something
-  //}
-  
-  state = yy_scan_string(expr);
-  
-  if(yyparse()) {
-    // TODO: error out or something
-  }
-  
-  yy_delete_buffer(state);
-  yylex_destroy();
-  return return_rel;
-}
-
diff --git a/include/chill_error.hh b/include/chill_error.hh
new file mode 100644
index 0000000..88e49fc
--- /dev/null
+++ b/include/chill_error.hh
@@ -0,0 +1,24 @@
+#ifndef CHILL_ERROR_HH
+#define CHILL_ERROR_HH
+
+/*!
+ * \file
+ * \brief CHiLL runtime exceptions
+ */
+
+//! for loop transformation problem
+struct loop_error: public std::runtime_error {
+  loop_error(const std::string &msg): std::runtime_error(msg){}
+};
+
+//! for generic compiler intermediate code handling problem
+struct ir_error: public std::runtime_error {
+  ir_error(const std::string &msg): std::runtime_error(msg){}
+};
+
+//! for specific for expression to preburger math translation problem
+struct ir_exp_error: public ir_error {
+  ir_exp_error(const std::string &msg): ir_error(msg){}
+};
+
+#endif
diff --git a/include/chill_run_util.hh b/include/chill_run_util.hh
new file mode 100644
index 0000000..8df5871
--- /dev/null
+++ b/include/chill_run_util.hh
@@ -0,0 +1,29 @@
+#ifndef CHILL_RUN_UTIL_HH
+#define CHILL_RUN_UTIL_HH
+
+#include <vector>
+#include <map>
+#include <string>
+
+typedef std::map<std::string, int>               simap_t;
+typedef std::vector<std::map<std::string, int> > simap_vec_t;
+
+// in chill_run_util.cc
+simap_vec_t* make_prog(simap_vec_t* cond);
+simap_vec_t* make_cond_gt(simap_t* lhs, simap_t* rhs);
+simap_vec_t* make_cond_lt(simap_t* lhs, simap_t* rhs);
+simap_vec_t* make_cond_ge(simap_t* lhs, simap_t* rhs);
+simap_vec_t* make_cond_le(simap_t* lhs, simap_t* rhs);
+simap_vec_t* make_cond_eq(simap_t* lhs, simap_t* rhs);
+simap_t* make_cond_item_add(simap_t* lhs, simap_t* rhs);
+simap_t* make_cond_item_sub(simap_t* lhs, simap_t* rhs);
+simap_t* make_cond_item_mul(simap_t* lhs, simap_t* rhs);
+simap_t* make_cond_item_neg(simap_t* expr);
+simap_t* make_cond_item_number(int n);
+simap_t* make_cond_item_variable(const char* var);
+simap_t* make_cond_item_level(int n);
+
+// in parse_expr.yy
+simap_vec_t* parse_relation_vector(const char* expr);
+
+#endif
diff --git a/include/chilldebug.h b/include/chilldebug.h
new file mode 100644
index 0000000..865f1f6
--- /dev/null
+++ b/include/chilldebug.h
@@ -0,0 +1,15 @@
+
+// a central place to turn on debugging messages
+
+// enable the next line to get lots of output 
+//#define DEBUGCHILL
+#ifndef DEBUGCHILL_H
+#define DEBUGCHILL_H
+
+#ifdef DEBUGCHILL 
+#define DEBUG_PRINT(args...) fprintf(stderr, args )
+#else
+#define DEBUG_PRINT(args...) do {} while(0) /* Don't do anything  */
+#endif
+
+#endif
diff --git a/include/chillmodule.hh b/include/chillmodule.hh
new file mode 100644
index 0000000..e83119f
--- /dev/null
+++ b/include/chillmodule.hh
@@ -0,0 +1,17 @@
+#ifndef CHILLMODULE_HH
+#define CHILLMODULE_HH
+
+/*!
+ * \file
+ * \brief chill interface to python
+ */
+
+#include <Python.h>
+
+void finalize_loop(int loop_num_start, int loop_num_end);
+int get_loop_num_start();
+int get_loop_num_end();
+//! pass C methods to python
+PyMODINIT_FUNC initchill();
+
+#endif
diff --git a/include/dep.hh b/include/dep.hh
new file mode 100644
index 0000000..6c535ce
--- /dev/null
+++ b/include/dep.hh
@@ -0,0 +1,94 @@
+#ifndef DEP_HH
+#define DEP_HH
+
+/*!
+ * \file 
+ * \brief Data dependence vector and graph.
+ *
+ * All dependence vectors are normalized, i.e., the first non-zero distance
+ * must be positve. Thus the correct dependence meaning can be given based on
+ * source/destination pair's read/write type. Suppose for a dependence vector
+ * 1, 0~5, -3), we want to permute the first and the second dimension,
+ * the result would be two dependence vectors (0, 1, -3) and (1~5, 1, -3).
+ * All operations on dependence vectors are non-destructive, i.e., new
+ * dependence vectors are returned.
+ */
+
+#include <omega.h>
+#include "graph.hh"
+#include "ir_code.hh"
+#include "chill_error.hh"
+
+enum DependenceType { DEP_W2R, DEP_R2W, DEP_W2W, DEP_R2R, DEP_CONTROL, DEP_UNKNOWN };
+
+class DependenceVector;
+typedef std::vector<DependenceVector> DependenceList;
+
+struct DependenceVector {
+  DependenceType type;
+  IR_Symbol *sym;
+ 
+  bool is_reduction; //!< used to identify a class of flow dependence
+                     //!< that can be broken
+  std::vector<omega::coef_t> lbounds;
+  std::vector<omega::coef_t> ubounds;
+  
+  bool quasi;
+  bool is_scalar_dependence;
+  DependenceVector() {
+    type = DEP_UNKNOWN;
+    sym = NULL;
+    is_reduction = false;
+    quasi = false;
+    is_scalar_dependence = false;
+  }
+  DependenceVector(const DependenceVector &that);
+  ~DependenceVector() {delete sym;}
+  DependenceVector &operator=(const DependenceVector &that);
+  
+  bool is_data_dependence() const;
+  bool is_control_dependence() const;
+  bool has_negative_been_carried_at(int dim) const;
+  bool has_been_carried_at(int dim) const;
+  bool has_been_carried_before(int dim) const;
+  
+  // TODO the following functions will be cleaned up or removed later
+  bool isZero() const;
+  bool isPositive() const;
+  bool isNegative() const;
+  bool isAllPositive() const;
+  bool isAllNegative() const;
+  bool isZero(int dim) const;
+  bool hasPositive(int dim) const;
+  bool hasNegative(int dim) const;
+  bool isCarried(int dim, omega::coef_t distance = posInfinity) const;
+  bool canPermute(const std::vector<int> &pi) const;
+  
+  std::vector<DependenceVector> normalize() const;
+  std::vector<DependenceVector> permute(const std::vector<int> &pi) const;
+  DependenceVector reverse() const;
+  DependenceType getType() const;
+  friend std::ostream& operator<<(std::ostream &os, const DependenceVector &d);
+};
+
+
+
+class DependenceGraph: public Graph<Empty, DependenceVector> {
+  
+protected:
+  int num_dim_;
+  
+public:
+  DependenceGraph(int n) { num_dim_ = n; }
+  DependenceGraph() { num_dim_ = 0; }
+  ~DependenceGraph() {}
+  int num_dim() const { return num_dim_; }
+  DependenceGraph permute(const std::vector<int> &pi,
+                          const std::set<int> &active = std::set<int>()) const;
+  DependenceGraph subspace(int dim) const;
+  bool isPositive() const;
+  bool hasPositive(int dim) const;
+  bool hasNegative(int dim) const;
+};
+
+#endif
diff --git a/include/graph.hh b/include/graph.hh
new file mode 100644
index 0000000..211444a
--- /dev/null
+++ b/include/graph.hh
@@ -0,0 +1,328 @@
+/*****************************************************************************
+ Copyright (C) 2008 University of Southern California
+ Copyright (C) 2010 University of Utah
+ All Rights Reserved.
+
+ Purpose:
+   Graph<VertexType, EdgeType> template class supports topological sort
+ with return result observing strongly connected component.
+
+ Notes:
+   The result of topologically sorting a graph V={1,2,3,4} and E={1->2, 1->3,
+ 2->3, 3->2, 3->4} is ({1}, {2,3}, {4}).
+ 
+ History:
+   01/2006 Created by Chun Chen.
+   07/2010 add a new topological order, -chun
+*****************************************************************************/
+
+#ifndef GRAPH_HH
+#define GRAPH_HH
+
+/*!
+ * \file
+ * \brief  Graph<VertexType, EdgeType> template class supports topological sort
+ *
+ * The result of topologically sorting a graph V={1,2,3,4} and E={1->2, 1->3,
+ * 2->3, 3->2, 3->4} is ({1}, {2,3}, {4}).
+ */
+
+#include <set>
+#include <vector>
+#include <map>
+#include <iostream>
+#include <stack>
+#include <algorithm>
+#include <assert.h>
+
+struct Empty {
+  Empty() {};
+  bool operator<(const Empty &) const { return true; };
+  bool operator==(const Empty &) const { return false; };
+  friend std::ostream& operator<<(std::ostream &os, const Empty &) { return os; };
+};
+
+namespace {
+  enum GraphColorType {WHITE, GREY, BLACK};
+}
+
+template<typename VertexType, typename EdgeType> struct Graph;
+template<typename VertexType, typename EdgeType> std::ostream& operator<<(std::ostream &os, const Graph<VertexType, EdgeType> &g);
+
+template<typename VertexType = Empty, typename EdgeType = Empty>
+struct Graph {
+  typedef std::map<int, std::vector<EdgeType> > EdgeList;
+  typedef std::vector<std::pair<VertexType, EdgeList> > VertexList;
+
+  VertexList vertex;
+  bool directed;
+
+  Graph(bool directed = true);
+  
+  int vertexCount() const;
+  int edgeCount() const;
+  bool isEmpty() const;
+  bool isDirected() const;
+  int insert(const VertexType &v = VertexType());
+  void connect(int v1, int v2, const EdgeType &e = EdgeType());
+  void connect(int v1, int v2, const std::vector<EdgeType> &e);
+  void disconnect(int v1, int v2);
+  bool hasEdge(int v1, int v2) const;
+  std::vector<EdgeType> getEdge(int v1, int v2) const;
+  
+  //! Topological sort
+  /*! This topological sort does handle SCC in graph. */
+  std::vector<std::set<int> > topoSort() const;
+  //! Topological sort
+  /*! This topological sort does not handle SCC in graph. */
+  std::vector<std::set<int> > packed_topoSort() const;
+
+  void dump() {
+    std::cout << *this;
+  }
+  
+  friend std::ostream& operator<< <>(std::ostream &os, const Graph<VertexType, EdgeType> &g);
+};
+
+template<typename VertexType, typename EdgeType>
+std::ostream& operator<<(std::ostream &os, const Graph<VertexType, EdgeType> &g) {
+  for (int i = 0; i < g.vertex.size(); i++)
+    for (typename Graph<VertexType,EdgeType>::EdgeList::const_iterator j = g.vertex[i].second.begin(); j != g.vertex[i].second.end(); j++) {
+	os << "s" << i << "->" << "s" << j->first << ":";
+      for (typename std::vector<EdgeType>::const_iterator k = j->second.begin(); k != j->second.end(); k++)
+        os << " " << *k;
+      os << std::endl;
+    }
+
+  return os;
+}
+
+
+template<typename VertexType, typename EdgeType>
+Graph<VertexType, EdgeType>::Graph(bool directed_):
+  directed(directed_) {
+}
+
+template<typename VertexType, typename EdgeType>
+int Graph<VertexType, EdgeType>::vertexCount() const {
+  return vertex.size();
+}
+
+template<typename VertexType, typename EdgeType>
+int Graph<VertexType, EdgeType>::edgeCount() const {
+  int result = 0;
+
+  for (int i = 0; i < vertex.size(); i++)
+    for (typename EdgeList::const_iterator j = vertex[i].second.begin(); j != vertex[i].second.end(); j++)
+      result += j->second.size();
+
+  if (!directed)
+    result = result/2;
+  
+  return result;
+}
+
+template<typename VertexType, typename EdgeType>
+bool Graph<VertexType, EdgeType>::isEmpty() const {
+  return vertex.size() == 0;
+}
+
+template<typename VertexType, typename EdgeType>
+bool Graph<VertexType, EdgeType>::isDirected() const {
+  return directed;
+}
+
+template<typename VertexType, typename EdgeType>
+int Graph<VertexType, EdgeType>::insert(const VertexType & v) {
+  for (int i = 0; i < vertex.size(); i++)
+    if (vertex[i].first == v)
+      return i;
+
+  vertex.push_back(std::make_pair(v, EdgeList()));
+  return vertex.size() - 1;
+}
+  
+  
+template<typename VertexType, typename EdgeType>
+void Graph<VertexType, EdgeType>::connect(int v1, int v2, const EdgeType &e)  {
+  assert(v1 < vertex.size() && v2 < vertex.size());
+
+  vertex[v1].second[v2].push_back(e);;
+  if (!directed)
+    vertex[v2].second[v1].push_back(e);
+}
+
+template<typename VertexType, typename EdgeType>
+void Graph<VertexType, EdgeType>::connect(int v1, int v2, const std::vector<EdgeType> &e)  {
+  assert(v1 < vertex.size() && v2 < vertex.size());
+
+  if (e.size() == 0)
+    return;
+  
+  copy(e.begin(), e.end(), back_inserter(vertex[v1].second[v2]));
+  if (!directed)
+    copy(e.begin(), e.end(), back_inserter(vertex[v2].second[v1]));
+}
+
+template<typename VertexType, typename EdgeType>
+void Graph<VertexType, EdgeType>::disconnect(int v1, int v2)  {
+  assert(v1 < vertex.size() && v2 < vertex.size());
+
+  vertex[v1].second.erase(v2);
+  if (!directed)
+    vertex[v2].second.erase(v1);
+}
+
+template<typename VertexType, typename EdgeType>
+bool Graph<VertexType,EdgeType>::hasEdge(int v1, int v2) const {
+  return vertex[v1].second.find(v2) != vertex[v1].second.end();
+}
+
+template<typename VertexType, typename EdgeType>
+std::vector<EdgeType> Graph<VertexType,EdgeType>::getEdge(int v1, int v2) const {
+  if (!hasEdge(v1, v2))
+    return std::vector<EdgeType>();
+
+  return vertex[v1].second.find(v2)->second;
+}
+
+template<typename VertexType, typename EdgeType>
+std::vector<std::set<int> > Graph<VertexType, EdgeType>::topoSort() const {
+  const int n = vertex.size();
+  std::vector<GraphColorType> color(n, WHITE);
+  std::stack<int> S;
+
+  std::vector<int> order(n);
+  int c = n;
+  
+  // first DFS
+  for (int i = n-1; i >= 0; i--)
+    if (color[i] == WHITE) {
+      S.push(i);
+      while (!S.empty()) {
+        int v = S.top();
+
+        if (color[v] == WHITE) {
+          for (typename EdgeList::const_iterator j = vertex[v].second.begin(); j != vertex[v].second.end(); j++)
+            if (color[j->first] == WHITE)
+              S.push(j->first);
+
+          color[v] = GREY;
+        }
+        else if (color[v] == GREY) {
+          color[v] = BLACK;
+          S.pop();
+          order[--c] = v;
+        }
+        else {
+          S.pop();
+        }
+      }
+    }
+
+  // transpose edge
+  std::vector<std::set<int> > edgeT(n);
+  for (int i = 0; i < n; i++)
+    for (typename EdgeList::const_iterator j = vertex[i].second.begin(); j != vertex[i].second.end(); j++)
+      edgeT[j->first].insert(i);
+  
+  // second DFS in transposed graph starting from last finished vertex
+  fill(color.begin(), color.end(), WHITE);
+  std::vector<std::set<int> > result;
+  for (int i = 0; i < n; i++)
+    if (color[order[i]] == WHITE) {
+      std::set<int> s;
+      
+      S.push(order[i]);
+      while (!S.empty()) {
+        int v = S.top();
+      
+        if(color[v] == WHITE) {
+          for (std::set<int>::const_iterator j = edgeT[v].begin(); j != edgeT[v].end(); j++)
+            if (color[*j] == WHITE)
+              S.push(*j);
+
+          color[v] = GREY;
+        }
+        else if (color[v] == GREY) {
+          color[v] = BLACK;
+          S.pop();
+          s.insert(v);
+        }
+        else {
+          S.pop();
+        }
+      }
+
+      result.push_back(s);
+    }
+
+  return result;
+}
+
+template<typename VertexType, typename EdgeType>
+std::vector<std::set<int> > Graph<VertexType, EdgeType>::packed_topoSort() const {
+  const int n = vertex.size();
+  std::vector<GraphColorType> color(n, WHITE);
+  std::stack<int> S;
+
+  std::vector<bool> is_root(n, false);
+  std::vector<std::set<int> > edges(n);
+  
+  // first DFS
+  for (int i = n-1; i >= 0; i--)
+    if (color[i] == WHITE) {
+      S.push(i);
+      is_root[i] = true;
+      while (!S.empty()) {
+        int v = S.top();
+
+        if (color[v] == WHITE) {
+          for (typename EdgeList::const_iterator j = vertex[v].second.begin(); j != vertex[v].second.end(); j++)
+            if (color[j->first] == WHITE) {
+              S.push(j->first);
+              edges[v].insert(j->first);
+            }
+            else if (color[j->first] == BLACK) {
+              if (is_root[j->first]) {
+                is_root[j->first] = false;
+                edges[v].insert(j->first);
+              }
+            }
+
+          color[v] = GREY;
+        }
+        else if (color[v] == GREY) {
+          color[v] = BLACK;
+          S.pop();
+        }
+        else {
+          S.pop();
+        }
+      }
+    }
+
+
+  // second BFS in DFS tree starting from roots
+  std::vector<std::set<int> > result;
+  std::set<int> s;
+  for (int i = 0; i < n; i++)
+    if (is_root[i])
+      s.insert(i);
+  if (s.size() != 0) {
+    result.push_back(s);
+    while (true) {
+      std::set<int> s;
+      for (std::set<int>::iterator i = result[result.size()-1].begin(); i != result[result.size()-1].end(); i++)
+        s.insert(edges[*i].begin(), edges[*i].end());
+      if (s.size() != 0)
+        result.push_back(s);
+      else
+        break;
+    }
+  }
+
+  return result;
+}
+
+#endif
diff --git a/include/ir_code.hh b/include/ir_code.hh
new file mode 100644
index 0000000..d695474
--- /dev/null
+++ b/include/ir_code.hh
@@ -0,0 +1,289 @@
+/*****************************************************************************
+ Copyright (C) 2009-2010 University of Utah
+ All Rights Reserved.
+
+ Purpose:
+   CHiLL's compiler intermediate representation interface that extends
+ Omega's builder interface to accomodate compiler analyses and
+ extra code generation.
+.
+ Notes:
+   Unlike CG_outputRepr, IR_Symbol,IR_Ref and IR_Control are place holders
+ to the underlying code, thus deleting or duplicating them does not affect
+ the actual code.  Similar to Omega builder's memory allocation strategy,
+ all non-const pointer parameters of CG_outputRepr/IR_Symbol/IR_Ref/IR_Control
+ are destroyed after the call.
+
+ History:
+   02/2009 Created by Chun Chen.
+   06/2010 Add IR_Control interface, by chun.  
+*****************************************************************************/
+
+#ifndef IR_CODE_HH
+#define IR_CODE_HH
+
+/*!
+ * \file
+ * \brief CHiLL's compiler intermediate representation interface that extends Omega's builder interface to accomodate compiler analyses and extra code generation.
+ * 
+ * Unlike CG_outputRepr, IR_Symbol,IR_Ref and IR_Control are place holders 
+ * to the underlying code, thus deleting or duplicating them does not affect
+ * the actual code.  Similar to Omega builder's memory allocation strategy,
+ * all non-const pointer parameters of CG_outputRepr/IR_Symbol/IR_Ref/IR_Control
+ * are destroyed after the call.
+ */
+
+
+#include <code_gen/CG_outputRepr.h>
+#include <code_gen/CG_outputBuilder.h>
+#include <vector>
+
+enum IR_OPERATION_TYPE    {IR_OP_CONSTANT, IR_OP_VARIABLE,
+                           IR_OP_PLUS, IR_OP_MINUS, IR_OP_MULTIPLY, IR_OP_DIVIDE,
+                           IR_OP_POSITIVE, IR_OP_NEGATIVE,
+                           IR_OP_MIN, IR_OP_MAX,
+                           IR_OP_ASSIGNMENT,
+                           IR_OP_NULL, IR_OP_UNKNOWN};
+enum IR_CONTROL_TYPE      {IR_CONTROL_LOOP, IR_CONTROL_IF, IR_CONTROL_WHILE, IR_CONTROL_BLOCK};
+enum IR_CONSTANT_TYPE     {IR_CONSTANT_INT, IR_CONSTANT_FLOAT,
+                           IR_CONSTANT_UNKNOWN};
+enum IR_CONDITION_TYPE    {IR_COND_LT, IR_COND_LE,
+                           IR_COND_GT, IR_COND_GE,
+                           IR_COND_EQ, IR_COND_NE,
+                           IR_COND_UNKNOWN};
+enum IR_ARRAY_LAYOUT_TYPE {IR_ARRAY_LAYOUT_ROW_MAJOR,
+                           IR_ARRAY_LAYOUT_COLUMN_MAJOR,
+                           IR_ARRAY_LAYOUT_SPACE_FILLING};
+
+class IR_Code;
+
+
+//! Base abstract class for scalar and array symbols.
+/*! This is a place holder for related declaration in IR code.*/
+struct IR_Symbol {
+  const IR_Code *ir_;
+  
+  virtual ~IR_Symbol() {/* ir_ is not the responsibility of this object */}
+  virtual int n_dim() const = 0;
+  virtual std::string name() const = 0;
+  virtual bool operator==(const IR_Symbol &that) const = 0;
+  virtual bool operator!=(const IR_Symbol &that) const {return !(*this == that);}
+  virtual IR_Symbol *clone() const = 0;  /* shallow copy */
+};
+
+
+struct IR_ScalarSymbol: public IR_Symbol {
+  virtual ~IR_ScalarSymbol() {}
+  int n_dim() const {return 0;}
+  virtual int size() const = 0;
+};
+
+
+struct IR_ArraySymbol: public IR_Symbol {
+  virtual ~IR_ArraySymbol() {}
+  virtual int elem_size() const = 0;
+  virtual omega::CG_outputRepr *size(int dim) const = 0;
+  virtual IR_ARRAY_LAYOUT_TYPE layout_type() const = 0;
+};
+
+
+//! Base abstract class for scalar and array references.  
+/*! This is a place holder for related code in IR code. */
+struct IR_Ref {
+  const IR_Code *ir_;
+  
+  virtual ~IR_Ref() {/* ir_ is not the responsibility of this object */}
+  virtual int n_dim() const = 0;
+  virtual bool is_write() const = 0;
+  virtual std::string name() const = 0;
+  virtual bool operator==(const IR_Ref &that) const = 0;
+  virtual bool operator!=(const IR_Ref &that) const {return !(*this == that);}
+  virtual omega::CG_outputRepr *convert() = 0;
+  //! shallow copy
+  virtual IR_Ref *clone() const = 0;
+};
+
+
+struct IR_ConstantRef: public IR_Ref {
+  IR_CONSTANT_TYPE type_;
+
+  virtual ~IR_ConstantRef() {}
+  int n_dim() const {return 0;}
+  bool is_write() const {return false;}
+  std::string name() const {return std::string();}
+  virtual bool is_integer() const {return type_ == IR_CONSTANT_INT;}
+  virtual omega::coef_t integer() const = 0;
+};
+  
+
+struct IR_ScalarRef: public IR_Ref {
+  virtual ~IR_ScalarRef() {}
+  int n_dim() const {return 0;}
+  virtual IR_ScalarSymbol *symbol() const = 0;
+  std::string name() const {
+    IR_ScalarSymbol *sym = symbol();
+    std::string s = sym->name();
+    delete sym;
+    return s;
+  }
+  virtual int size() const {
+    IR_ScalarSymbol *sym = symbol();
+    int s = sym->size();
+    delete sym;
+    return s;
+  }
+};
+
+
+struct IR_ArrayRef: public IR_Ref {
+  virtual ~IR_ArrayRef() {}
+  int n_dim() const {
+    IR_ArraySymbol *sym = symbol();
+    int n = sym->n_dim();
+    delete sym;
+    return n;
+  }
+  virtual omega::CG_outputRepr *index(int dim) const = 0;
+  virtual IR_ArraySymbol *symbol() const = 0;
+  std::string name() const {
+    IR_ArraySymbol *sym = symbol();
+    std::string s = sym->name();
+    delete sym;
+    return s;
+  }
+  virtual int elem_size() const {
+    IR_ArraySymbol *sym = symbol();
+    int s = sym->elem_size();
+    delete sym;
+    return s;
+  }
+  virtual IR_ARRAY_LAYOUT_TYPE layout_type() const {
+    IR_ArraySymbol *sym = symbol();
+    IR_ARRAY_LAYOUT_TYPE t = sym->layout_type();
+    delete sym;
+    return t;
+  }
+};
+
+
+struct IR_Block;
+
+//! Base abstract class for code structures.  
+/*!  
+ * This is a place holder for the actual structure in the IR code.  
+ * However, in cases that original source code may be transformed during 
+ * loop initialization such as converting a while loop to a for loop or 
+ * reconstructing the loop from low level IR code, the helper loop class (NOT
+ * IMPLEMENTED) must contain the transformed code that needs to be 
+ * freed when out of service. 
+ */
+struct IR_Control {
+  const IR_Code *ir_;
+
+  virtual ~IR_Control() {/* ir_ is not the responsibility of this object */}
+  virtual IR_CONTROL_TYPE type() const = 0;
+  virtual IR_Block *convert() = 0;
+  //! shallow copy
+  virtual IR_Control *clone() const = 0;
+};
+
+
+struct IR_Loop: public IR_Control {  
+  virtual ~IR_Loop() {}
+  virtual IR_ScalarSymbol *index() const = 0;
+  virtual omega::CG_outputRepr *lower_bound() const = 0;
+  virtual omega::CG_outputRepr *upper_bound() const = 0;
+  virtual IR_CONDITION_TYPE stop_cond() const = 0;
+  virtual IR_Block *body() const = 0;
+  virtual int step_size() const = 0;
+  IR_CONTROL_TYPE type() const { return IR_CONTROL_LOOP; }
+};
+
+
+struct IR_Block: public IR_Control {
+  virtual ~IR_Block() {}
+  virtual omega::CG_outputRepr *extract() const = 0;
+  IR_Block *convert() {return this;}
+  IR_CONTROL_TYPE type() const { return IR_CONTROL_BLOCK; }
+  virtual omega::CG_outputRepr *original() const = 0;
+};
+
+
+struct IR_If: public IR_Control {
+  virtual ~IR_If() {}
+  virtual omega::CG_outputRepr *condition() const = 0;
+  virtual IR_Block *then_body() const = 0;
+  virtual IR_Block *else_body() const = 0;
+  IR_CONTROL_TYPE type() const { return IR_CONTROL_IF; }
+};
+
+
+  
+struct IR_While: public IR_Control {
+  // NOT IMPLEMENTED
+};
+
+
+//! Abstract class for compiler IR.
+class IR_Code {
+protected:
+  omega::CG_outputBuilder *ocg_;
+  omega::CG_outputRepr *init_code_;
+  omega::CG_outputRepr *cleanup_code_;
+
+public:
+  IR_Code() {ocg_ = NULL; init_code_ = cleanup_code_ = NULL;}
+  virtual ~IR_Code() { delete ocg_; delete init_code_; delete cleanup_code_; } 
+  /* the content of init and cleanup code have already been released in derived classes */
+  
+  /*! 
+   * \param memory_type is for differentiating the location of 
+   *    where the new memory is allocated. this is useful for 
+   *    processors with heterogeneous memory hierarchy.
+   */
+  virtual IR_ScalarSymbol *CreateScalarSymbol(const IR_Symbol *sym, int memory_type) = 0;
+  virtual IR_ArraySymbol *CreateArraySymbol(const IR_Symbol *sym, std::vector<omega::CG_outputRepr *> &size, int memory_type) = 0;
+  
+  virtual IR_ScalarRef *CreateScalarRef(const IR_ScalarSymbol *sym) = 0;
+  virtual IR_ArrayRef *CreateArrayRef(const IR_ArraySymbol *sym, std::vector<omega::CG_outputRepr *> &index) = 0;
+  virtual int ArrayIndexStartAt() {return 0;}
+
+  /*! 
+   * Array references should be returned in their accessing order.
+   *
+   * ~~~
+   * e.g. s1: A[i] = A[i-1]
+   *      s2: B[C[i]] = D[i] + E[i]
+   * return A[i-1], A[i], D[i], E[i], C[i], B[C[i]] in this order.
+   * ~~~
+   */
+  virtual std::vector<IR_ArrayRef *> FindArrayRef(const omega::CG_outputRepr *repr) const = 0;
+  virtual std::vector<IR_ScalarRef *> FindScalarRef(const omega::CG_outputRepr *repr) const = 0;
+
+  /*!
+   * If there is no sub structure interesting inside the block, return empty,
+   * so we know when to stop looking inside.
+   */
+  virtual std::vector<IR_Control *> FindOneLevelControlStructure(const IR_Block *block) const = 0;
+
+  /*! 
+   * All controls must be in the same block, at the same level and in
+   * contiguous lexical order as appeared in parameter vector.
+   */
+  virtual IR_Block *MergeNeighboringControlStructures(const std::vector<IR_Control *> &controls) const = 0;
+  
+  virtual IR_Block *GetCode() const = 0;
+  virtual void ReplaceCode(IR_Control *old, omega::CG_outputRepr *repr) = 0;
+  virtual void ReplaceExpression(IR_Ref *old, omega::CG_outputRepr *repr) = 0;
+  
+  virtual IR_OPERATION_TYPE QueryExpOperation(const omega::CG_outputRepr *repr) const = 0;
+  virtual IR_CONDITION_TYPE QueryBooleanExpOperation(const omega::CG_outputRepr *repr) const = 0;
+  virtual std::vector<omega::CG_outputRepr *> QueryExpOperand(const omega::CG_outputRepr *repr) const = 0;
+  virtual IR_Ref *Repr2Ref(const omega::CG_outputRepr *repr) const = 0;
+  
+  //! Codegen Omega code builder interface
+  omega::CG_outputBuilder *builder() const {return ocg_;}
+
+};
+
+#endif  
diff --git a/include/ir_rose.hh b/include/ir_rose.hh
new file mode 100644
index 0000000..03ea50d
--- /dev/null
+++ b/include/ir_rose.hh
@@ -0,0 +1,267 @@
+#ifndef IR_ROSE_HH
+#define IR_ROSE_HH
+
+/*!
+ * \file
+ * \brief CHiLL's rose interface.
+ */
+
+#include <omega.h>
+#include "ir_code.hh"
+#include "ir_rose_utils.hh"
+#include <AstInterface_ROSE.h>
+#include "chill_error.hh"
+#include "staticSingleAssignment.h"
+#include "VariableRenaming.h"
+#include "ssaUnfilteredCfg.h"
+#include "virtualCFG.h"
+#include <omega.h>
+
+struct IR_roseScalarSymbol: public IR_ScalarSymbol {
+  SgVariableSymbol* vs_;
+  
+  IR_roseScalarSymbol(const IR_Code *ir, SgVariableSymbol *vs) {
+    ir_ = ir;
+    vs_ = vs;
+  }
+  
+  std::string name() const;
+  int size() const;
+  bool operator==(const IR_Symbol &that) const;
+  IR_Symbol *clone() const;
+};
+
+struct IR_roseArraySymbol: public IR_ArraySymbol {
+  
+  SgVariableSymbol* vs_;
+  
+  IR_roseArraySymbol(const IR_Code *ir, SgVariableSymbol* vs) {
+    ir_ = ir;
+    vs_ = vs;
+  }
+  std::string name() const;
+  int elem_size() const;
+  int n_dim() const;
+  omega::CG_outputRepr *size(int dim) const;
+  bool operator==(const IR_Symbol &that) const;
+  IR_ARRAY_LAYOUT_TYPE layout_type() const;
+  IR_Symbol *clone() const;
+  
+};
+
+struct IR_roseConstantRef: public IR_ConstantRef {
+  union {
+    omega::coef_t i_;
+    double f_;
+  };
+  
+  IR_roseConstantRef(const IR_Code *ir, omega::coef_t i) {
+    ir_ = ir;
+    type_ = IR_CONSTANT_INT;
+    i_ = i;
+  }
+  IR_roseConstantRef(const IR_Code *ir, double f) {
+    ir_ = ir;
+    type_ = IR_CONSTANT_FLOAT;
+    f_ = f;
+  }
+  omega::coef_t integer() const {
+    assert(is_integer());
+    return i_;
+  }
+  bool operator==(const IR_Ref &that) const;
+  omega::CG_outputRepr *convert();
+  IR_Ref *clone() const;
+  
+};
+
+struct IR_roseScalarRef: public IR_ScalarRef {
+  SgAssignOp *ins_pos_;
+  int op_pos_; // -1 means destination operand, otherwise source operand
+  SgVarRefExp *vs_;
+  int is_write_;
+  IR_roseScalarRef(const IR_Code *ir, SgVarRefExp *sym) {
+    ir_ = ir;
+    ins_pos_ = isSgAssignOp(sym->get_parent());
+    op_pos_ = 0;
+    if (ins_pos_ != NULL)
+      if (sym == isSgVarRefExp(ins_pos_->get_lhs_operand()))
+        op_pos_ = -1;
+    
+    vs_ = sym;
+  }
+  IR_roseScalarRef(const IR_Code *ir, SgVarRefExp *ins, int pos) {
+    ir_ = ir;
+    /*  ins_pos_ = ins;
+        op_pos_ = pos;
+        SgExpression* op;
+        if (pos == -1)
+        op = ins->get_lhs_operand();
+        else
+        op = ins->get_rhs_operand();
+        
+    */
+    
+    is_write_ = pos;
+    
+    /*  if (vs_ == NULL || pos > 0)
+        throw ir_error(
+        "Src operand not a variable or more than one src operand!!");
+    */
+    
+    vs_ = ins;
+    
+  }
+  bool is_write() const;
+  IR_ScalarSymbol *symbol() const;
+  bool operator==(const IR_Ref &that) const;
+  omega::CG_outputRepr *convert();
+  IR_Ref *clone() const;
+};
+
+struct IR_roseArrayRef: public IR_ArrayRef {
+  
+  SgPntrArrRefExp *ia_;
+  
+  int is_write_;
+  IR_roseArrayRef(const IR_Code *ir, SgPntrArrRefExp *ia, int write) {
+    ir_ = ir;
+    ia_ = ia;
+    is_write_ = write;
+  }
+  bool is_write() const;
+  omega::CG_outputRepr *index(int dim) const;
+  IR_ArraySymbol *symbol() const;
+  bool operator==(const IR_Ref &that) const;
+  omega::CG_outputRepr *convert();
+  IR_Ref *clone() const;
+};
+
+struct IR_roseLoop: public IR_Loop {
+  SgNode *tf_;
+  
+  IR_roseLoop(const IR_Code *ir, SgNode *tf) {
+    ir_ = ir;
+    tf_ = tf;
+  }
+  
+  IR_ScalarSymbol *index() const;
+  omega::CG_outputRepr *lower_bound() const;
+  omega::CG_outputRepr *upper_bound() const;
+  IR_CONDITION_TYPE stop_cond() const;
+  IR_Block *body() const;
+  IR_Block *convert();
+  int step_size() const;
+  IR_Control *clone() const;
+};
+
+struct IR_roseBlock: public IR_Block {
+  SgNode* tnl_;
+  SgNode *start_, *end_;
+  
+  IR_roseBlock(const IR_Code *ir, SgNode *tnl, SgNode *start, SgNode *end) {
+    ir_ = ir;
+    tnl_ = tnl;
+    start_ = start;
+    end_ = end;
+  }
+  
+  IR_roseBlock(const IR_Code *ir, SgNode *tnl) {
+    ir_ = ir;
+    tnl_ = tnl;
+    start_ = tnl_->get_traversalSuccessorByIndex(0);
+    end_ = tnl_->get_traversalSuccessorByIndex(
+      (tnl_->get_numberOfTraversalSuccessors()) - 1);
+  }
+  omega::CG_outputRepr *extract() const;
+  omega::CG_outputRepr *original() const;
+  IR_Control *clone() const;
+};
+
+struct IR_roseIf: public IR_If {
+  SgNode *ti_;
+  
+  IR_roseIf(const IR_Code *ir, SgNode *ti) {
+    ir_ = ir;
+    ti_ = ti;
+  }
+  ~IR_roseIf() {
+  }
+  omega::CG_outputRepr *condition() const;
+  IR_Block *then_body() const;
+  IR_Block *else_body() const;
+  IR_Block *convert();
+  IR_Control *clone() const;
+};
+
+class IR_roseCode_Global_Init {
+private:
+  static IR_roseCode_Global_Init *pinstance;
+public:
+  SgProject* project;
+  static IR_roseCode_Global_Init *Instance(char** argv);
+};
+
+class IR_roseCode: public IR_Code {
+protected:
+  SgSourceFile* file;
+  SgGlobal *root;
+  SgGlobal *firstScope;
+  SgSymbolTable* symtab_;
+  SgSymbolTable* symtab2_;
+  SgSymbolTable* symtab3_;
+  SgDeclarationStatementPtrList::iterator p;
+  SgFunctionDeclaration *func;
+  bool is_fortran_;
+  int i_;
+  StaticSingleAssignment *ssa_for_scalar;
+  ssa_unfiltered_cfg::SSA_UnfilteredCfg *main_ssa;
+  VariableRenaming *varRenaming_for_scalar;
+public:
+  IR_roseCode(const char *filename, const char* proc_name);
+  ~IR_roseCode();
+  
+  IR_ScalarSymbol *CreateScalarSymbol(const IR_Symbol *sym, int memory_type =
+                                      0);
+  IR_ArraySymbol *CreateArraySymbol(const IR_Symbol *sym,
+                                    std::vector<omega::CG_outputRepr *> &size, int memory_type = 0);
+  IR_ScalarRef *CreateScalarRef(const IR_ScalarSymbol *sym);
+  IR_ArrayRef *CreateArrayRef(const IR_ArraySymbol *sym,
+                              std::vector<omega::CG_outputRepr *> &index);
+  int ArrayIndexStartAt() {
+    if (is_fortran_)
+      return 1;
+    else
+      return 0;
+  }
+  
+  void populateLists(SgNode* tnl_1, SgStatementPtrList* list_1,
+                     SgStatementPtrList& output_list_1);
+  void populateScalars(const omega::CG_outputRepr *repr1,
+                       std::map<SgVarRefExp*, IR_ScalarRef*> &read_scalars_1,
+                       std::map<SgVarRefExp*, IR_ScalarRef*> &write_scalars_1,
+                       std::set<std::string> &indices, std::vector<std::string> &index);
+  std::vector<IR_ArrayRef *> FindArrayRef(
+    const omega::CG_outputRepr *repr) const;
+  std::vector<IR_ScalarRef *> FindScalarRef(
+    const omega::CG_outputRepr *repr) const;
+  std::vector<IR_Control *> FindOneLevelControlStructure(
+    const IR_Block *block) const;
+  IR_Block *MergeNeighboringControlStructures(
+    const std::vector<IR_Control *> &controls) const;
+  IR_Block *GetCode() const;
+  void ReplaceCode(IR_Control *old, omega::CG_outputRepr *repr);
+  void ReplaceExpression(IR_Ref *old, omega::CG_outputRepr *repr);
+  
+  IR_OPERATION_TYPE QueryExpOperation(const omega::CG_outputRepr *repr) const;
+  IR_CONDITION_TYPE QueryBooleanExpOperation(
+    const omega::CG_outputRepr *repr) const;
+  std::vector<omega::CG_outputRepr *> QueryExpOperand(
+    const omega::CG_outputRepr *repr) const;
+  IR_Ref *Repr2Ref(const omega::CG_outputRepr *) const;
+  void finalizeRose();
+  friend class IR_roseArraySymbol;
+  friend class IR_roseArrayRef;
+};
+
+#endif
diff --git a/include/ir_rose_utils.hh b/include/ir_rose_utils.hh
new file mode 100644
index 0000000..350aa24
--- /dev/null
+++ b/include/ir_rose_utils.hh
@@ -0,0 +1,19 @@
+#ifndef IR_ROSE_UTILS_HH
+#define IR_ROSE_UTILS_HH
+
+/*!
+ * \file
+ * \brief ROSE interface utilities
+ */
+#include <vector>
+#include <rose.h>
+#include <sageBuilder.h>
+
+std::vector<SgForStatement *> find_deepest_loops(SgNode *tnl);
+std::vector<SgForStatement *> find_loops(SgNode *tnl);
+
+SgNode* loop_body_at_level(SgNode* tnl, int level);
+SgNode* loop_body_at_level(SgForStatement* loop, int level);
+void swap_node_for_node_list(SgNode* tn, SgNode* new_tnl);
+
+#endif
diff --git a/include/irtools.hh b/include/irtools.hh
new file mode 100644
index 0000000..a3b552a
--- /dev/null
+++ b/include/irtools.hh
@@ -0,0 +1,48 @@
+#ifndef IRTOOLS_HH
+#define IRTOOLS_HH
+
+/*!
+ * \file
+ * \brief Useful tools to analyze code in compiler IR format.
+ */
+
+#include <vector>
+#include <omega.h>
+#include <code_gen/CG_outputRepr.h>
+#include "ir_code.hh"
+#include "dep.hh"
+
+//! It is used to initialize a loop.
+struct ir_tree_node {
+  IR_Control *content;
+  ir_tree_node *parent;
+  std::vector<ir_tree_node *> children;
+/*! 
+ * * For a loop node, payload is its mapped iteration space dimension. 
+ * * For a simple block node, payload is its mapped statement number. 
+ * * Normal if-else is splitted into two nodes
+ *   * the one with odd payload represents then-part and
+ *   * the one with even payload represents else-part.
+ */
+  int payload;
+  
+  ~ir_tree_node() {
+    for (int i = 0; i < children.size(); i++)
+      delete children[i];
+    delete content;
+  }
+};
+
+std::vector<ir_tree_node *> build_ir_tree(IR_Control *control,
+                                          ir_tree_node *parent = NULL);
+std::vector<ir_tree_node *> extract_ir_stmts(
+  const std::vector<ir_tree_node *> &ir_tree);
+bool is_dependence_valid(ir_tree_node *src_node, ir_tree_node *dst_node,
+                         const DependenceVector &dv, bool before);
+std::pair<std::vector<DependenceVector>, std::vector<DependenceVector> > test_data_dependences(
+  IR_Code *ir, const omega::CG_outputRepr *repr1,
+  const omega::Relation &IS1, const omega::CG_outputRepr *repr2,
+  const omega::Relation &IS2, std::vector<omega::Free_Var_Decl*> &freevar,
+  std::vector<std::string> index, int i, int j);
+
+#endif
diff --git a/include/loop.hh b/include/loop.hh
new file mode 100644
index 0000000..9620489
--- /dev/null
+++ b/include/loop.hh
@@ -0,0 +1,200 @@
+#ifndef LOOP_HH
+#define LOOP_HH
+
+/*!
+ * \file 
+ * \brief Core loop transformation functionality.
+ *
+ * "level" (starting from 1) means loop level and it corresponds to "dim"
+ * (starting from 0) in transformed iteration space [c_1,l_1,c_2,l_2,....,
+ * c_n,l_n,c_(n+1)], e.g., l_2 is loop level 2 in generated code, dim 3
+ * in transformed iteration space, and variable 4 in Omega relation.
+ * All c's are constant numbers only and they will not show up as actual loops.
+ * 
+ * Formula:
+ *
+ * ~~~
+ *   dim = 2*level - 1
+ *   var = dim + 1
+ * ~~~
+ */
+ 
+
+#include <omega.h>
+#include <code_gen/codegen.h>
+#include <code_gen/CG.h>
+#include <vector>
+#include <map>
+#include <set>
+#include "dep.hh"
+#include "ir_code.hh"
+#include "irtools.hh"
+
+class IR_Code;
+
+enum TilingMethodType { StridedTile, CountedTile };
+enum LoopLevelType { LoopLevelOriginal, LoopLevelTile, LoopLevelUnknown };
+
+
+//! Describes properties of each loop level of a statement. 
+struct LoopLevel {
+  LoopLevelType type;
+/*! 
+ * For LoopLevelOriginal means iteration space dimension 
+ * For LoopLevelTile means tiled loop level. Special value -1 for
+ * LoopLevelTile means purely derived loop. For dependence dimension
+ * payloads, the values must be in an increasing order.
+ */
+  int payload;  
+/*!
+ * Used by code generation to support
+ * multi-level parallelization (default 0 means sequential loop under
+ * the current parallelization level).
+ */
+  int parallel_level;
+};
+
+struct Statement {
+  omega::CG_outputRepr *code;
+  omega::Relation IS;
+  omega::Relation xform;
+  std::vector<LoopLevel> loop_level;
+  ir_tree_node *ir_stmt_node;
+  //protonu--temporarily putting this back here
+  //omega::Tuple<int> nonSplitLevels;
+  //end--protonu.
+};
+
+
+class Loop {
+protected:
+  int tmp_loop_var_name_counter;
+  static const std::string tmp_loop_var_name_prefix;
+  int overflow_var_name_counter;
+  static const std::string overflow_var_name_prefix;
+  std::vector<int> stmt_nesting_level_;
+  std::vector<std::string> index;
+  std::map<int, omega::CG_outputRepr *> replace;
+  
+public:
+  IR_Code *ir;
+  std::vector<omega::Free_Var_Decl*> freevar;
+  std::vector<Statement> stmt;
+  std::vector<ir_tree_node *> ir_stmt;
+  std::vector<ir_tree_node *> ir_tree;
+  DependenceGraph dep;
+  int num_dep_dim;
+  omega::Relation known;
+  omega::CG_outputRepr *init_code;
+  omega::CG_outputRepr *cleanup_code;
+  std::map<int, std::vector<omega::Free_Var_Decl *> > overflow;
+  
+  
+protected:
+  mutable omega::CodeGen *last_compute_cg_;
+  mutable omega::CG_result *last_compute_cgr_;
+  mutable int last_compute_effort_;
+  
+protected:
+  bool init_loop(std::vector<ir_tree_node *> &ir_tree, std::vector<ir_tree_node *> &ir_stmt);
+  int get_dep_dim_of(int stmt, int level) const;
+  int get_last_dep_dim_before(int stmt, int level) const;
+  std::vector<omega::Relation> getNewIS() const;
+  omega::Relation getNewIS(int stmt_num) const;
+  std::vector<int> getLexicalOrder(int stmt_num) const;
+  int getLexicalOrder(int stmt_num, int level) const;
+  std::set<int> getStatements(const std::vector<int> &lex, int dim) const;
+  void shiftLexicalOrder(const std::vector<int> &lex, int dim, int amount);
+  void setLexicalOrder(int dim, const std::set<int> &active, int starting_order = 0, std::vector< std::vector<std::string> >idxNames= std::vector< std::vector<std::string> >());
+  void apply_xform(int stmt_num);
+  void apply_xform(std::set<int> &active);
+  void apply_xform();
+  std::set<int> getSubLoopNest(int stmt_num, int level) const;
+  
+  
+public:
+  Loop() { ir = NULL; tmp_loop_var_name_counter = 1; init_code = NULL; }
+  Loop(const IR_Control *control);
+  ~Loop();
+  
+  omega::CG_outputRepr *getCode(int effort = 1) const;
+  void printCode(int effort = 1) const;
+  void addKnown(const omega::Relation &cond);
+  void print_internal_loop_structure() const;
+  bool isInitialized() const;
+  int num_statement() const { return stmt.size(); }
+  void printIterationSpace() const;
+  void printDependenceGraph() const;
+  void removeDependence(int stmt_num_from, int stmt_num_to);
+  void dump() const;
+  
+  std::vector<std::set <int > > sort_by_same_loops(std::set<int > active, int level);
+  //
+  //! legacy unimodular transformations for perfectly nested loops
+  /*!
+   * e.g. \f$M*(i,j)^T = (i',j')^T or M*(i,j,1)^T = (i',j')^T\f$
+   */
+  bool nonsingular(const std::vector<std::vector<int> > &M);
+  
+  /*!
+   * \defgroup hltrans High-level loop transformations
+   * @{
+   */
+  void permute(const std::set<int> &active, const std::vector<int> &pi);
+  void permute(int stmt_num, int level, const std::vector<int> &pi);
+  void permute(const std::vector<int> &pi);
+  void original();
+  
+  void tile(int stmt_num, int level, int tile_size, int outer_level = 1, TilingMethodType method = StridedTile, int alignment_offset = 0, int alignment_multiple = 1);
+  std::set<int> split(int stmt_num, int level, const omega::Relation &cond);
+  std::set<int> unroll(int stmt_num, int level, int unroll_amount, std::vector< std::vector<std::string> >idxNames= std::vector< std::vector<std::string> >(), int cleanup_split_level = 0);
+  
+  bool datacopy(const std::vector<std::pair<int, std::vector<int> > > &array_ref_nums, int level, bool allow_extra_read = false, int fastest_changing_dimension = -1, int padding_stride = 1, int padding_alignment = 4, int memory_type = 0);
+  bool datacopy(int stmt_num, int level, const std::string &array_name, bool allow_extra_read = false, int fastest_changing_dimension = -1, int padding_stride = 1, int padding_alignment = 4, int memory_type = 0);
+  bool datacopy_privatized(int stmt_num, int level, const std::string &array_name, const std::vector<int> &privatized_levels, bool allow_extra_read = false, int fastest_changing_dimension = -1, int padding_stride = 1, int padding_alignment = 1, int memory_type = 0);
+  bool datacopy_privatized(const std::vector<std::pair<int, std::vector<int> > > &array_ref_nums, int level, const std::vector<int> &privatized_levels, bool allow_extra_read = false, int fastest_changing_dimension = -1, int padding_stride = 1, int padding_alignment = 1, int memory_type = 0);
+  bool datacopy_privatized(const std::vector<std::pair<int, std::vector<IR_ArrayRef *> > > &stmt_refs, int level, const std::vector<int> &privatized_levels, bool allow_extra_read, int fastest_changing_dimension, int padding_stride, int padding_alignment, int memory_type = 0);
+  
+  
+  Graph<std::set<int>, bool> construct_induced_graph_at_level(std::vector<std::set<int> > s, DependenceGraph dep, int dep_dim);
+  std::vector<std::set<int> > typed_fusion(Graph<std::set<int>, bool> g);
+  void fuse(const std::set<int> &stmt_nums, int level);
+  void distribute(const std::set<int> &stmt_nums, int level);
+  void skew(const std::set<int> &stmt_nums, int level, const std::vector<int> &skew_amount);
+  void shift(const std::set<int> &stmt_nums, int level, int shift_amount);
+  void scale(const std::set<int> &stmt_nums, int level, int scale_amount);
+  void reverse(const std::set<int> &stmt_nums, int level);
+  void peel(int stmt_num, int level, int peel_amount = 1);
+  /*!
+   * \defgroup hlfancy fancy loop transformations
+   * @{
+   */
+  void modular_shift(int stmt_num, int level, int shift_amount) {}
+  void diagonal_map(int stmt_num, const std::pair<int, int> &levels, int offset) {}
+  void modular_partition(int stmt_num, int level, int stride) {}
+  /*! @} */
+  
+  /*! 
+   * \defgroup hlderived derived loop transformations
+   * @{
+   */
+
+  void shift_to(int stmt_num, int level, int absolute_position);
+  std::set<int> unroll_extra(int stmt_num, int level, int unroll_amount, int cleanup_split_level = 0);
+  bool is_dependence_valid_based_on_lex_order(int i, int j,
+			const DependenceVector &dv, bool before);
+  /*! @} */
+
+  /*! 
+   * \defgroup hlother other public operations
+   * @{
+   */
+  void pragma(int stmt_num, int level, const std::string &pragmaText);
+  void prefetch(int stmt_num, int level, const std::string &arrName, int hint);
+  /*! @} */
+
+  /*! @} */
+};
+
+
+#endif
diff --git a/include/omegatools.hh b/include/omegatools.hh
new file mode 100644
index 0000000..b51b2bd
--- /dev/null
+++ b/include/omegatools.hh
@@ -0,0 +1,93 @@
+#ifndef OMEGATOOLS_HH
+#define OMEGATOOLS_HH
+
+/*!
+ * \file
+ * \brief Useful tools involving Omega manipulation.
+ */
+
+#include <string>
+#include <omega.h>
+#include "dep.hh"
+#include "ir_code.hh"
+
+std::string tmp_e();
+
+//! Convert expression tree to omega relation.
+/*!
+ * \param destroy shallow deallocation of "repr", not freeing the actual code inside.
+ */
+void exp2formula(IR_Code *ir, omega::Relation &r, omega::F_And *f_root,
+                 std::vector<omega::Free_Var_Decl *> &freevars,
+                 omega::CG_outputRepr *repr, omega::Variable_ID lhs, char side,
+                 IR_CONDITION_TYPE rel, bool destroy);
+
+//! Build dependence relation for two array references.
+omega::Relation arrays2relation(IR_Code *ir, std::vector<omega::Free_Var_Decl*> &freevars,
+                                const IR_ArrayRef *ref_src, const omega::Relation &IS_w,
+                                const IR_ArrayRef *ref_dst, const omega::Relation &IS_r);
+//! Convert array dependence relation into set of dependence vectors
+/*!
+ * assuming ref_w is lexicographically before ref_r in the source code.
+ */
+std::pair<std::vector<DependenceVector>, std::vector<DependenceVector> > relation2dependences(
+  const IR_ArrayRef *ref_src, const IR_ArrayRef *ref_dst, const omega::Relation &r);
+
+//! Convert a boolean expression to omega relation.  
+/*!
+ * \param destroy shallow deallocation of "repr", not freeing the actual code inside.
+ */
+void exp2constraint(IR_Code *ir, omega::Relation &r, omega::F_And *f_root,
+                    std::vector<omega::Free_Var_Decl *> &freevars,
+                    omega::CG_outputRepr *repr, bool destroy);
+
+bool is_single_iteration(const omega::Relation &r, int dim);
+//!  Set/get the value of a variable which is know to be constant.
+void assign_const(omega::Relation &r, int dim, int val);
+
+int get_const(const omega::Relation &r, int dim, omega::Var_Kind type);
+
+//! Find the position index variable in a Relation by name.
+omega::Variable_ID find_index(omega::Relation &r, const std::string &s, char side);
+
+//! Generate mapping relation for permuation.
+omega::Relation permute_relation(const std::vector<int> &pi);
+
+omega::Relation get_loop_bound(const omega::Relation &r, int dim);
+
+//!  Determine whether the loop (starting from 0) in the iteration space has only one iteration.
+bool is_single_loop_iteration(const omega::Relation &r, int level, const omega::Relation &known);
+//! Get the bound for a specific loop.
+omega::Relation get_loop_bound(const omega::Relation &r, int level, const omega::Relation &known);
+omega::Relation get_max_loop_bound(const std::vector<omega::Relation> &r, int dim);
+omega::Relation get_min_loop_bound(const std::vector<omega::Relation> &r, int dim);
+
+//! Add strident to a loop.
+/*!
+ * Issues:
+ *
+ * * Don't work with relations with multiple disjuncts.
+ * * Omega's dealing with max lower bound is awkward.
+ */
+void add_loop_stride(omega::Relation &r, const omega::Relation &bound, int dim, int stride);
+bool is_inner_loop_depend_on_level(const omega::Relation &r, int level, const omega::Relation &known);
+/*!
+ * Suppose loop dim is i. Replace i with i+adjustment in loop bounds.
+ *
+ * ~~~
+ * do i = 1, n
+ *   do j = i, n
+ * ~~~
+ *  
+ *  after call with dim = 0 and adjustment = 1:
+ *
+ * ~~~
+ * do i = 1, n
+ *   do j = i+1, n
+ * ~~~
+ */
+omega::Relation adjust_loop_bound(const omega::Relation &r, int level, int adjustment);
+
+enum LexicalOrderType {LEX_MATCH, LEX_BEFORE, LEX_AFTER, LEX_UNKNOWN};
+
+#endif
diff --git a/lib/codegen/CMakeLists.txt b/lib/codegen/CMakeLists.txt
new file mode 100644
index 0000000..13bf0fe
--- /dev/null
+++ b/lib/codegen/CMakeLists.txt
@@ -0,0 +1,24 @@
+set(CG_SRC
+    src/codegen.cc
+    src/CG.cc
+    src/CG_stringBuilder.cc
+    src/CG_utils.cc
+    )
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-write-strings")
+
+include_directories(
+    include
+    ${OMEGAROOT}/include
+    )
+
+add_library(codegen
+    ${CG_SRC}
+    )
+
+add_dependencies(codegen omega)
+
+install(TARGETS codegen
+    ARCHIVE DESTINATION lib)
+install(DIRECTORY include
+    DESTINATION .)
diff --git a/lib/codegen/include/code_gen/CG.h b/lib/codegen/include/code_gen/CG.h
new file mode 100644
index 0000000..ce56768
--- /dev/null
+++ b/lib/codegen/include/code_gen/CG.h
@@ -0,0 +1,118 @@
+#ifndef _CG_H
+#define _CG_H
+
+#include <omega/Relation.h>
+#include <basic/BoolSet.h>
+#include <code_gen/CG_outputBuilder.h>
+#include <vector>
+
+namespace omega {
+
+class CodeGen;
+
+struct CG_result {
+  CodeGen *codegen_;
+  BoolSet<> active_;
+
+  CG_result() { codegen_ = NULL; }
+  virtual ~CG_result() { /* not responsible for codegen_ */ }
+  
+  virtual CG_result *recompute(const BoolSet<> &parent_active, const Relation &known, const Relation &restriction) = 0;
+  virtual int populateDepth() = 0;
+  virtual std::pair<CG_result *, Relation> liftOverhead(int depth, bool propagate_up) = 0;
+  virtual Relation hoistGuard() = 0;
+  virtual void removeGuard(const Relation &guard) = 0;
+  virtual CG_outputRepr *printRepr(int indent, CG_outputBuilder *ocg, const std::vector<CG_outputRepr *> &stmts, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) const = 0;
+  CG_outputRepr *printRepr(CG_outputBuilder *ocg, const std::vector<CG_outputRepr *> &stmts) const;
+  std::string printString() const;
+  int num_level() const;
+  virtual CG_result *clone() const = 0;
+  virtual void dump(int indent) const {}
+  void dump() { dump(0); }
+};
+
+
+struct CG_split: public CG_result {
+  std::vector<Relation> restrictions_;
+  std::vector<CG_result *> clauses_;
+
+  CG_split(CodeGen *codegen, const BoolSet<> &active, const std::vector<Relation> &restrictions, const std::vector<CG_result *> &clauses) {
+    codegen_ = codegen;
+    active_ = active;
+    restrictions_ = restrictions;
+    clauses_ = clauses;
+  } 
+  ~CG_split() {
+    for (int i = 0; i < clauses_.size(); i++)
+      delete clauses_[i];
+  } 
+  
+  CG_result *recompute(const BoolSet<> &parent_active, const Relation &known, const Relation &restriction);
+  int populateDepth();
+  std::pair<CG_result *, Relation> liftOverhead(int depth, bool propagate_up);
+  Relation hoistGuard();
+  void removeGuard(const Relation &guard);
+  CG_outputRepr *printRepr(int indent, CG_outputBuilder *ocg, const std::vector<CG_outputRepr *> &stmts, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) const;
+  CG_result *clone() const;
+  void dump(int indent) const;
+
+private:
+  std::vector<CG_result *> findNextLevel() const;
+};
+
+
+struct CG_loop: public CG_result {
+  int level_;
+  CG_result *body_;
+
+  Relation known_;
+  Relation restriction_;
+  Relation bounds_;
+  Relation guard_;
+  bool needLoop_;
+  int depth_;
+
+  CG_loop(CodeGen *codegen, const BoolSet<> &active, int level, CG_result *body) {
+    codegen_ = codegen;
+    active_ = active;
+    level_ = level;
+    body_ = body;
+  }
+  ~CG_loop() { delete body_; }
+  
+  CG_result *recompute(const BoolSet<> &parent_active, const Relation &known, const Relation &restriction);
+  int populateDepth();
+  std::pair<CG_result *, Relation> liftOverhead(int depth, bool propagate_up);
+  Relation hoistGuard();
+  void removeGuard(const Relation &guard);
+  CG_outputRepr *printRepr(int indent, CG_outputBuilder *ocg, const std::vector<CG_outputRepr *> &stmts, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) const;
+  CG_outputRepr *printRepr(bool do_print_guard, int indent, CG_outputBuilder *ocg, const std::vector<CG_outputRepr *> &stmts, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) const;
+  CG_result *clone() const;
+  void dump(int indent) const;
+};
+
+
+
+struct CG_leaf: public CG_result {
+  Relation known_;
+  std::map<int, Relation> guards_;
+  
+  CG_leaf(CodeGen *codegen, const BoolSet<> &active) {
+    codegen_ = codegen;
+    active_ = active;
+  }
+  ~CG_leaf() {}
+  
+  CG_result *recompute(const BoolSet<> &parent_active, const Relation &known, const Relation &restriction);
+  int populateDepth() { return 0; }
+  std::pair<CG_result *, Relation> liftOverhead(int depth, bool propagate_up);
+  Relation hoistGuard();
+  void removeGuard(const Relation &guard);
+  CG_outputRepr *printRepr(int indent, CG_outputBuilder *ocg, const std::vector<CG_outputRepr *> &stmts, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) const;
+  CG_result *clone() const;
+  void dump(int indent) const;
+};
+
+}
+
+#endif
diff --git a/lib/codegen/include/code_gen/CG_outputBuilder.h b/lib/codegen/include/code_gen/CG_outputBuilder.h
new file mode 100644
index 0000000..19dc440
--- /dev/null
+++ b/lib/codegen/include/code_gen/CG_outputBuilder.h
@@ -0,0 +1,161 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 the Omega Project Team
+ Copyright (C) 2005-2011 Chun Chen
+ All Rights Reserved.
+
+ Purpose:
+   abstract base class of comiler IR code builder
+
+ Notes:
+   All "CG_outputRepr *" parameters are consumed inside the the function
+ unless explicitly stated otherwise, i.e., not valid after the call.
+   Parameter "indent" normally not used except it is used in unstructured
+ string output for correct indentation.
+ 
+ History:
+   04/17/96 created - Lei Zhou
+   05/02/08 clarify integer floor/mod/ceil definitions, -chen
+   05/31/08 use virtual clone to implement CreateCopy, -chun
+   08/05/10 clarify NULL parameter allowance, -chun
+*****************************************************************************/
+
+#ifndef _CG_OUTPUTBUILDER_H
+#define _CG_OUTPUTBUILDER_H
+
+#include <code_gen/CG_outputRepr.h>
+
+#include <string>
+#include <vector>
+
+namespace omega {
+
+//! abstract base class of comiler IR code builder
+class CG_outputBuilder {
+public:
+  CG_outputBuilder() {}
+  virtual ~CG_outputBuilder() {}
+
+  //! substitute variables in stmt
+  virtual CG_outputRepr *CreateSubstitutedStmt(int indent, CG_outputRepr *stmt,
+                                               const std::vector<std::string> &vars,
+                                               std::vector<CG_outputRepr *> &subs) const = 0;
+
+  //! assignment stmt generation
+  virtual CG_outputRepr *CreateAssignment(int indent, CG_outputRepr *lhs,
+                                          CG_outputRepr *rhs) const = 0;
+
+  //! function invocation generation
+  virtual CG_outputRepr *CreateInvoke(const std::string &funcName,
+                                      std::vector<CG_outputRepr *> &argList) const = 0;
+
+  //! comment generation
+  virtual CG_outputRepr *CreateComment(int indent,
+                                       const std::string &commentText) const = 0;
+
+  //! Attribute generation
+  virtual CG_outputRepr* CreateAttribute(CG_outputRepr  *control,
+                                           const std::string &commentText) const = 0;
+  //! Pragma Attribute
+  virtual CG_outputRepr* CreatePragmaAttribute(CG_outputRepr *scopeStmt, int looplevel, const std::string &pragmaText) const = 0;
+  
+  //! Prefetch Attribute
+  virtual CG_outputRepr* CreatePrefetchAttribute(CG_outputRepr *scopeStmt, int looplevel, const std::string &arrName, int hint) const = 0;
+
+  //! generate if stmt, true/false stmt can be NULL but not the condition
+  virtual CG_outputRepr *CreateIf(int indent, CG_outputRepr *guardCondition,
+                                  CG_outputRepr *true_stmtList,
+                                  CG_outputRepr *false_stmtList) const = 0;
+
+  //! generate loop inductive variable (loop control structure)
+  virtual CG_outputRepr *CreateInductive(CG_outputRepr *index,
+                                         CG_outputRepr *lower,
+                                         CG_outputRepr *upper,
+                                         CG_outputRepr *step) const = 0;
+
+  //! generate loop stmt from loop control and loop body, NULL parameter allowed
+  virtual CG_outputRepr *CreateLoop(int indent, CG_outputRepr *control,
+                                    CG_outputRepr *stmtList) const = 0;
+
+  //! copy operation, NULL parameter allowed.
+  /*!
+   * this function makes pointer handling uniform regardless NULL status
+   */
+  virtual CG_outputRepr *CreateCopy(CG_outputRepr *original) const {
+    if (original == NULL)
+      return NULL;
+    else
+      return original->clone();
+  }
+
+  //! basic integer number creation
+  virtual CG_outputRepr *CreateInt(int num) const = 0;
+  virtual bool isInteger(CG_outputRepr *op) const = 0;
+
+
+  //! basic identity/variable creation
+  virtual CG_outputRepr *CreateIdent(const std::string &varName) const = 0;
+
+  //! Addition operations, NULL parameter means 0,
+  virtual CG_outputRepr *CreatePlus(CG_outputRepr *lop, CG_outputRepr *rop) const = 0;
+  //! Subtraction operations, NULL parameter means 0,
+  virtual CG_outputRepr *CreateMinus(CG_outputRepr *lop, CG_outputRepr *rop) const = 0;
+  //! Multiplication operations, NULL parameter means 0,
+  virtual CG_outputRepr *CreateTimes(CG_outputRepr *lop, CG_outputRepr *rop) const = 0;
+  //! Division operations, NULL parameter means 0,
+  /*!
+   * integer division truncation method undefined, only use when lop is known
+   * to be multiple of rop, otherwise use integer floor instead
+   */
+  virtual CG_outputRepr *CreateDivide(CG_outputRepr *lop, CG_outputRepr *rop) const {
+    return CreateIntegerFloor(lop, rop);
+  }
+  
+  //! integer floor functions, NULL parameter means 0
+  /*! 
+   * second parameter must be postive (i.e. b > 0 below), otherwise function undefined
+   * 
+   * floor(a, b)
+   * * = a/b if a >= 0
+   * * = (a-b+1)/b if a < 0
+   */
+  virtual CG_outputRepr *CreateIntegerFloor(CG_outputRepr *lop, CG_outputRepr *rop) const = 0;
+  //! integer mod functions, NULL parameter means 0
+  /*! 
+   * second parameter must be postive (i.e. b > 0 below), otherwise function undefined
+   *
+   * mod(a, b) = a-b*floor(a, b) where result must lie in range [0,b)
+   */
+  virtual CG_outputRepr *CreateIntegerMod(CG_outputRepr *lop, CG_outputRepr *rop) const {
+    CG_outputRepr *lop2 = CreateCopy(lop);
+    CG_outputRepr *rop2 = CreateCopy(rop);
+    return CreateMinus(lop2, CreateTimes(rop2, CreateIntegerFloor(lop, rop)));
+  }
+  //! integer ceil functions, NULL parameter means 0
+  /*! 
+   * second parameter must be postive (i.e. b > 0 below), otherwise function undefined
+   *
+   * ceil(a, b) = -floor(-a, b) or floor(a+b-1, b) or floor(a-1, b)+1
+   */
+  virtual CG_outputRepr *CreateIntegerCeil(CG_outputRepr *lop, CG_outputRepr *rop) const {
+    return CreateMinus(NULL, CreateIntegerFloor(CreateMinus(NULL, lop), rop));
+  }
+
+  //! binary logical operation, NULL parameter means TRUE
+  virtual CG_outputRepr *CreateAnd(CG_outputRepr *lop, CG_outputRepr *rop) const = 0;
+
+  //! binary conditional Greater than or equal to
+  virtual CG_outputRepr *CreateGE(CG_outputRepr *lop, CG_outputRepr *rop) const {
+    return CreateLE(rop, lop);
+  } 
+  //! binary conditional Less than or equal to
+  virtual CG_outputRepr *CreateLE(CG_outputRepr *lop, CG_outputRepr *rop) const = 0;
+  //! binary conditional equal to
+  virtual CG_outputRepr *CreateEQ(CG_outputRepr *lop, CG_outputRepr *rop) const = 0;
+ 
+  //! join stmts together, NULL parameter allowed
+  virtual CG_outputRepr *StmtListAppend(CG_outputRepr *list1, CG_outputRepr *list2) const = 0;
+};
+
+}
+
+#endif
diff --git a/lib/codegen/include/code_gen/CG_outputRepr.h b/lib/codegen/include/code_gen/CG_outputRepr.h
new file mode 100644
index 0000000..0897007
--- /dev/null
+++ b/lib/codegen/include/code_gen/CG_outputRepr.h
@@ -0,0 +1,33 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 the Omega Project Team
+ Copyright (C) 2005-2011 Chun Chen
+ All Rights Reserved.
+
+ Purpose:
+   abstract base class of compiler IR code wrapper
+
+ Notes:
+
+ History:
+   04/17/96 - Lei Zhou - created
+*****************************************************************************/
+
+#ifndef _CG_OUTPUTREPR_H
+#define _CG_OUTPUTREPR_H
+
+namespace omega {
+
+class CG_outputRepr {
+public:
+  CG_outputRepr() {}
+  //! shallow delete
+  virtual ~CG_outputRepr() { }
+  virtual CG_outputRepr *clone() const = 0;
+  //! delete actual IR code wrapped inside
+  virtual void clear() { }
+  virtual void dump() const {}
+};
+
+}
+
+#endif
diff --git a/lib/codegen/include/code_gen/CG_stringBuilder.h b/lib/codegen/include/code_gen/CG_stringBuilder.h
new file mode 100644
index 0000000..09d3503
--- /dev/null
+++ b/lib/codegen/include/code_gen/CG_stringBuilder.h
@@ -0,0 +1,44 @@
+#ifndef _CG_STRINGBUILDER_H
+#define _CG_STRINGBUILDER_H
+
+#include <code_gen/CG_outputBuilder.h>
+#include <code_gen/CG_stringRepr.h>
+
+namespace omega {
+
+class CG_stringBuilder: public CG_outputBuilder { 
+public:
+  CG_stringBuilder() {}
+  ~CG_stringBuilder() {}
+  bool isInteger(CG_outputRepr *op) const;
+  CG_stringRepr *CreateSubstitutedStmt(int indent, CG_outputRepr *stmt, const std::vector<std::string> &vars, std::vector<CG_outputRepr *> &subs) const;
+  CG_stringRepr *CreateAssignment(int indent, CG_outputRepr *lhs, CG_outputRepr *rhs) const;
+  CG_stringRepr *CreateInvoke(const std::string &funcName, std::vector<CG_outputRepr *> &argList) const;
+  CG_stringRepr *CreateComment(int indent, const std::string &commentText) const;
+  CG_stringRepr* CreateAttribute(CG_outputRepr *control,
+                                          const std::string &commentText) const;
+  CG_outputRepr *CreatePragmaAttribute(CG_outputRepr *scopeStmt, int looplevel, const std::string &pragmaText) const;
+  CG_outputRepr *CreatePrefetchAttribute(CG_outputRepr *scopeStmt, int looplevel, const std::string &arrName, int hint) const;
+  CG_stringRepr *CreateIf(int indent, CG_outputRepr *guardCondition, CG_outputRepr *true_stmtList, CG_outputRepr *false_stmtList) const;
+  CG_stringRepr *CreateInductive(CG_outputRepr *index, CG_outputRepr *lower, CG_outputRepr *upper, CG_outputRepr *step) const;
+  CG_stringRepr *CreateLoop(int indent, CG_outputRepr *control, CG_outputRepr *stmtList) const;
+  CG_stringRepr *CreateInt(int num) const;
+  CG_stringRepr *CreateIdent(const std::string &varName) const;
+  CG_stringRepr *CreatePlus(CG_outputRepr *lop, CG_outputRepr *rop) const;
+  CG_stringRepr *CreateMinus(CG_outputRepr *lop, CG_outputRepr *rop) const;
+  CG_stringRepr *CreateTimes(CG_outputRepr *lop, CG_outputRepr *rop) const;
+  CG_stringRepr *CreateDivide(CG_outputRepr *lop, CG_outputRepr *rop) const;
+  CG_stringRepr *CreateIntegerFloor(CG_outputRepr *lop, CG_outputRepr *rop) const;
+  CG_stringRepr *CreateIntegerMod(CG_outputRepr *lop, CG_outputRepr *rop) const;
+  CG_stringRepr *CreateIntegerCeil(CG_outputRepr *lop, CG_outputRepr *rop) const;
+  CG_stringRepr *CreateAnd(CG_outputRepr *lop, CG_outputRepr *rop) const;
+  CG_stringRepr *CreateGE(CG_outputRepr *lop, CG_outputRepr *rop) const;
+  CG_stringRepr *CreateLE(CG_outputRepr *lop, CG_outputRepr *rop) const;
+  CG_stringRepr *CreateEQ(CG_outputRepr *lop, CG_outputRepr *rop) const;
+  CG_stringRepr *StmtListAppend(CG_outputRepr *list1, CG_outputRepr *list2) const;
+};
+
+
+}
+
+#endif
diff --git a/lib/codegen/include/code_gen/CG_stringRepr.h b/lib/codegen/include/code_gen/CG_stringRepr.h
new file mode 100644
index 0000000..a6df85d
--- /dev/null
+++ b/lib/codegen/include/code_gen/CG_stringRepr.h
@@ -0,0 +1,43 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 the Omega Project Team
+ Copyright (C) 2005-2011 Chun Chen
+ All Rights Reserved.
+
+ Purpose:
+   pseudo string code wrapper
+
+ Notes:
+
+ History:
+   04/17/96 - Lei Zhou - created
+*****************************************************************************/
+
+#ifndef _CG_STRINGREPR_H
+#define _CG_STRINGREPR_H
+
+#include <code_gen/CG_outputRepr.h>
+#include <string>
+#include <iostream>
+
+namespace omega {
+
+class CG_stringRepr: public CG_outputRepr {
+private:
+  std::string s_;
+
+public:
+  CG_stringRepr() {}
+  CG_stringRepr(const std::string &s) { s_ = s; }
+  ~CG_stringRepr() {}
+  CG_outputRepr *clone() const { return new CG_stringRepr(s_); }
+  void dump() const { std::cout << s_ << std::endl; }
+
+  //---------------------------------------------------------------------------
+  // basic operation
+  //---------------------------------------------------------------------------
+  std::string GetString() const { return s_; }
+};
+
+}
+
+#endif
diff --git a/lib/codegen/include/code_gen/CG_utils.h b/lib/codegen/include/code_gen/CG_utils.h
new file mode 100755
index 0000000..a6128bc
--- /dev/null
+++ b/lib/codegen/include/code_gen/CG_utils.h
@@ -0,0 +1,45 @@
+#ifndef _CG_UTILS_H
+#define _CG_UTILS_H
+
+#include <omega.h>
+#include <code_gen/CG_outputBuilder.h>
+#include <basic/BoolSet.h>
+#include <vector>
+#include <set>
+#include <map>
+
+namespace omega {
+
+class CG_loop;
+
+CG_outputRepr *output_inequality_repr(CG_outputBuilder *ocg, const GEQ_Handle &inequality, Variable_ID v, const Relation &R, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly, std::set<Variable_ID> excluded_floor_vars = std::set<Variable_ID>());
+CG_outputRepr *output_substitution_repr(CG_outputBuilder *ocg, const EQ_Handle &equality, Variable_ID v, bool apply_v_coef, const Relation &R, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly);
+CG_outputRepr *output_upper_bound_repr(CG_outputBuilder *ocg, const GEQ_Handle &inequality, Variable_ID v, const Relation &R, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly);
+CG_outputRepr *output_lower_bound_repr(CG_outputBuilder *ocg, const GEQ_Handle &inequality, Variable_ID v, const EQ_Handle &stride_eq, Variable_ID wc, const Relation &R, const Relation &known, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly);
+
+CG_outputRepr *output_ident(CG_outputBuilder *ocg, const Relation &R, Variable_ID v, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly);
+std::pair<CG_outputRepr *, std::pair<CG_outputRepr *, int> > output_assignment(CG_outputBuilder *ocg, const Relation &R, int level, const Relation &known, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly);
+CG_outputRepr *output_loop(CG_outputBuilder *ocg, const Relation &R, int level, const Relation &known, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly);
+CG_outputRepr *output_guard(CG_outputBuilder *ocg, const Relation &R, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly);
+std::vector<CG_outputRepr *> output_substitutions(CG_outputBuilder *ocg, const Relation &R, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly);
+
+bool bound_must_hit_stride(const GEQ_Handle &inequality, Variable_ID v, const EQ_Handle &stride_eq, Variable_ID wc, const Relation &bounds, const Relation &known);
+std::pair<EQ_Handle, int> find_simplest_assignment(const Relation &R, Variable_ID v, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly = std::vector<std::pair<CG_outputRepr *, int> >());
+std::pair<bool, GEQ_Handle> find_floor_definition(const Relation &R, Variable_ID v, std::set<Variable_ID> excluded_floor_vars = std::set<Variable_ID>());
+std::pair<EQ_Handle, Variable_ID> find_simplest_stride(const Relation &R, Variable_ID v);
+Variable_ID replicate_floor_definition(const Relation &R, const Variable_ID floor_var, Relation &r, F_Exists *f_exists, F_And *f_root, std::map<Variable_ID, Variable_ID> &exists_mapping);
+
+Relation pick_one_guard(const Relation &R, int level = 0);
+CG_outputRepr *leaf_print_repr(BoolSet<> active, const std::map<int, Relation> &guards,
+                               CG_outputRepr *guard_repr, const Relation &known,
+                               int indent, CG_outputBuilder *ocg, const std::vector<int> &remap,
+                               const std::vector<Relation> &xforms, const std::vector<CG_outputRepr *> &stmts,
+                               const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly);
+CG_outputRepr *loop_print_repr(const std::vector<CG_loop *> &loops, int start, int end,
+                               const Relation &guard, CG_outputRepr *guard_repr,
+                               int indent, CG_outputBuilder *ocg, const std::vector<CG_outputRepr *> &stmts,
+                               const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly);
+
+}
+
+#endif
diff --git a/lib/codegen/include/code_gen/code_gen.h b/lib/codegen/include/code_gen/code_gen.h
new file mode 100644
index 0000000..abfab7c
--- /dev/null
+++ b/lib/codegen/include/code_gen/code_gen.h
@@ -0,0 +1,47 @@
+#if !defined(Already_Included_code_gen)
+#define Already_Included_code_gen
+
+#include <basic/Tuple.h>
+#include <omega/Relation.h>
+#include <code_gen/CG.h>
+#include <code_gen/CG_outputRepr.h>
+#include <code_gen/CG_outputBuilder.h>
+
+namespace omega {
+
+typedef Tuple<int> IntTuple;
+typedef Tuple<Relation> SetTuple;
+typedef Tuple<SetTuple> SetTupleTuple;
+typedef Tuple<Relation> RelTuple;
+typedef Tuple<RelTuple> RelTupleTuple;
+
+CG_outputRepr *MMGenerateCode(CG_outputBuilder* ocg,
+                              Tuple<Relation> &T, Tuple<Relation> &old_IS,
+                              const Tuple<CG_outputRepr *> &stmt_content,
+                              Relation &known, int effort=1);
+std::string MMGenerateCode(Tuple<Relation> &T, Tuple<Relation> &old_IS, Relation &known,
+                           int effort=1);
+
+//protonu-adding a new variant to keep Gabe's code happy
+CG_outputRepr* MMGenerateCode(CG_outputBuilder* ocg, RelTuple &T, SetTuple &old_IS, 
+		const Tuple<CG_outputRepr *> &stmt_content, Relation &known,
+		Tuple< IntTuple >& smtNonSplitLevels_,
+	       	std::vector< std::pair<int, std::string> > syncs_,
+	       	const Tuple< Tuple<std::string> >& loopIdxNames_, 
+	       	int effort=1);
+//end-protonu
+
+struct Polyhedra {
+  int last_level;
+  Tuple<Relation> transformations;
+  Relation known;
+
+  Tuple<int> remap;  // after initial iteration space's disjoint set splitting, the new statement number maps to old statement number
+  Tuple<Tuple<Relation> > projected_nIS;
+ 
+  Polyhedra(const Tuple<Relation> &T, const Tuple<Relation> &old_IS, const Relation &known = Relation::Null());
+  ~Polyhedra() {}
+};
+
+}
+#endif
diff --git a/lib/codegen/include/code_gen/codegen.h b/lib/codegen/include/code_gen/codegen.h
new file mode 100755
index 0000000..cb63bfd
--- /dev/null
+++ b/lib/codegen/include/code_gen/codegen.h
@@ -0,0 +1,48 @@
+#ifndef _CODEGEN_H
+#define _CODEGEN_H
+
+#include <omega/Relation.h>
+#include <code_gen/CG.h>
+#include <code_gen/CG_outputBuilder.h>
+#include <vector>
+#include <string>
+
+namespace omega {
+
+class CodeGen {
+public:
+  static const std::string loop_var_name_prefix;
+  static const int var_substitution_threshold;
+  
+protected:
+  //! projected_IS_[level-1][new stmt#]
+  std::vector<std::vector<Relation> > projected_IS_;
+  //! transformations[original stmt#]
+  std::vector<Relation> xforms_;
+  //! no need to generate code for constraints satisfied in known
+  Relation known_;
+  //! map new stmt# to original stmt#
+  std::vector<int> remap_;
+
+public:
+  CodeGen(const std::vector<Relation> &xforms, const std::vector<Relation> &IS, const Relation &known = Relation::Null(),
+		                 std::vector< std::vector<int > > smtNonSplitLevels_ =   std::vector< std::vector<int > >(),
+		                 std::vector< std::vector<std::string> > loopIdxNames_ =  std::vector< std::vector<std::string> >(),
+		                 std::vector< std::pair<int, std::string> >  syncs_ =    std::vector< std::pair<int, std::string> >()
+		         );
+  ~CodeGen() {}
+  
+  CG_result *buildAST(int effort = 1);
+  int num_level() const { return projected_IS_.size(); }
+  
+private:
+  CG_result *buildAST(int level, const BoolSet<> &active, bool split_on_const, const Relation &restriction);
+
+  friend class CG_result;
+  friend class CG_split;
+  friend class CG_loop;
+  friend class CG_leaf;
+};
+
+}
+#endif
diff --git a/lib/codegen/include/code_gen/codegen_error.h b/lib/codegen/include/code_gen/codegen_error.h
new file mode 100755
index 0000000..06ecc2b
--- /dev/null
+++ b/lib/codegen/include/code_gen/codegen_error.h
@@ -0,0 +1,15 @@
+#ifndef _CODEGEN_ERROR_H
+#define _CODEGEN_ERROR_H
+
+#include <stdexcept>
+
+namespace omega {
+
+struct codegen_error: public std::runtime_error {
+  codegen_error(const std::string &msg): std::runtime_error("codegen error: " + msg) {}
+};
+
+
+}
+#endif
+
diff --git a/lib/codegen/include/code_gen/output_repr.h b/lib/codegen/include/code_gen/output_repr.h
new file mode 100644
index 0000000..254e71b
--- /dev/null
+++ b/lib/codegen/include/code_gen/output_repr.h
@@ -0,0 +1,46 @@
+#ifndef OUTPUT_REPR_H
+#define OUTPUT_REPR_H
+
+#include <omega.h>
+#include <code_gen/CG_outputBuilder.h>
+#include <code_gen/CG_outputRepr.h>
+#include <vector>
+#include <set>
+
+namespace omega {
+extern int last_level;
+
+CG_outputRepr* outputIdent(CG_outputBuilder* ocg, const Relation &R, Variable_ID v, const std::vector<CG_outputRepr *> &assigned_on_the_fly);
+std::pair<CG_outputRepr *, bool> outputAssignment(CG_outputBuilder *ocg, const Relation &R_, Variable_ID v, Relation &enforced, CG_outputRepr *&if_repr, const std::vector<CG_outputRepr *> &assigned_on_the_fly);
+std::pair<CG_outputRepr *, bool> outputBounds(CG_outputBuilder* ocg, const Relation &bounds, Variable_ID v, int indent, Relation &enforced, const std::vector<CG_outputRepr *> &assigned_on_the_fly);
+Tuple<CG_outputRepr*> outputSubstitution(CG_outputBuilder* ocg, const Relation &R, const std::vector<CG_outputRepr *> &assigned_on_the_fly);
+CG_outputRepr* outputStatement(CG_outputBuilder* ocg, CG_outputRepr *stmt, int indent,  const Relation &mapping, const Relation &known, const std::vector<CG_outputRepr *> &assigned_on_the_fly);
+CG_outputRepr* outputGuard(CG_outputBuilder* ocg, const Relation &guards_in, const std::vector<CG_outputRepr *> &assigned_on_the_fly);
+CG_outputRepr* output_as_guard(CG_outputBuilder* ocg, const Relation &guards_in, Constraint_Handle e, bool is_equality, const std::vector<CG_outputRepr *> &assigned_on_the_fly);
+CG_outputRepr* output_EQ_strides(CG_outputBuilder* ocg, const Relation &guards_in, const std::vector<CG_outputRepr *> &assigned_on_the_fly);
+CG_outputRepr* output_GEQ_strides(CG_outputBuilder* ocg, const Relation &guards_in, const std::vector<CG_outputRepr *> &assigned_on_the_fly);
+CG_outputRepr *outputLBasRepr(CG_outputBuilder* ocg, const GEQ_Handle &g, Relation &bounds, Variable_ID v, coef_t stride, const EQ_Handle &strideEQ, Relation known, const std::vector<CG_outputRepr *> &assigned_on_the_fly);
+CG_outputRepr *outputUBasRepr(CG_outputBuilder* ocg, const GEQ_Handle &g,  Relation & bounds, Variable_ID v,
+                              coef_t /*stride*/, // currently unused
+                              const EQ_Handle &/*strideEQ*/,
+                              const std::vector<CG_outputRepr *> &assigned_on_the_fly = std::vector<CG_outputRepr *>(last_level, static_cast<CG_outputRepr *>(NULL)));
+CG_outputRepr* outputEasyBoundAsRepr(CG_outputBuilder* ocg, Relation &bounds, const Constraint_Handle &g, Variable_ID v, bool ignoreWC, int ceiling, const std::vector<CG_outputRepr *> &assigned_on_the_fly);
+
+
+bool boundHitsStride(const GEQ_Handle &g, Variable_ID v, const EQ_Handle &strideEQ, coef_t /*stride, currently unused*/, Relation known);
+Relation greatest_common_step(const Tuple<Relation> &I, const Tuple<int> &active, int level, const Relation &known = Relation::Null());
+bool findFloorInequality(Relation &r, Variable_ID v, GEQ_Handle &h, Variable_ID excluded);
+Relation project_onto_levels(Relation R, int last_level, bool wildcards);
+bool isSimpleStride(const EQ_Handle &g, Variable_ID v);
+int countStrides(Conjunct *c, Variable_ID v, EQ_Handle &strideEQ, bool &simple);
+bool hasBound(Relation r, int level, int UB);
+bool find_any_constraint(int s, int level, Relation &kr, int direction, Relation &S, bool approx);
+bool has_nonstride_EQ(Relation r, int level);
+Relation pickOverhead(Relation r, int liftTo);
+Relation minMaxOverhead(Relation r, int level);
+int max_fs_arity(const Constraint_Handle &c);
+
+
+}
+
+#endif
diff --git a/lib/codegen/src/CG.cc b/lib/codegen/src/CG.cc
new file mode 100644
index 0000000..42bd172
--- /dev/null
+++ b/lib/codegen/src/CG.cc
@@ -0,0 +1,1163 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 the Omega Project Team
+ Copyright (C) 2005-2011 Chun Chen
+ All Rights Reserved.
+
+ Purpose:
+ CG node classes, used to build AST tree from polyhedra scanning.
+
+ Notes:
+ Parameter "restriction" is always tighter than "known" since CG_split
+ node does not correspond to any code for enforcement. This property is
+ destroyed after hoistGuard since "restriction" is not used anymore.
+ CG node's children are guaranteed not to be NULL, either NULL child is
+ removed from the children or the parent node itself becomes NULL.
+
+ History:
+ 04/20/96 printRepr added by D people. Lei Zhou
+ 10/24/06 hoistGuard added by chun
+ 08/03/10 collect CG classes into one place, by Chun Chen
+ 08/04/10 track dynamically substituted variables in printRepr, by chun
+ 04/02/11 rewrite the CG node classes, by chun
+ *****************************************************************************/
+
+#include <typeinfo>
+#include <assert.h>
+#include <omega.h>
+#include <code_gen/codegen.h>
+#include <code_gen/CG.h>
+#include <code_gen/CG_outputBuilder.h>
+#include <code_gen/CG_stringBuilder.h>
+#include <code_gen/CG_utils.h>
+#include <code_gen/codegen_error.h>
+#include <stack>
+#include <string.h>
+
+namespace omega {
+
+extern std::vector<std::vector<int> > smtNonSplitLevels;
+extern std::vector<std::vector<std::string> > loopIdxNames; //per stmt
+extern std::vector<std::pair<int, std::string> > syncs;
+
+extern int checkLoopLevel;
+extern int stmtForLoopCheck;
+extern int upperBoundForLevel;
+extern int lowerBoundForLevel;
+extern bool fillInBounds;
+
+//-----------------------------------------------------------------------------
+// Class: CG_result
+//-----------------------------------------------------------------------------
+
+CG_outputRepr *CG_result::printRepr(CG_outputBuilder *ocg,
+		const std::vector<CG_outputRepr *> &stmts) const {
+	return printRepr(1, ocg, stmts,
+			std::vector<std::pair<CG_outputRepr *, int> >(num_level(),
+					std::make_pair(static_cast<CG_outputRepr *>(NULL), 0)));
+}
+
+std::string CG_result::printString() const {
+	CG_stringBuilder ocg;
+	std::vector<CG_outputRepr *> stmts(codegen_->xforms_.size());
+	for (int i = 0; i < stmts.size(); i++)
+		stmts[i] = new CG_stringRepr("s" + to_string(i));
+	CG_stringRepr *repr = static_cast<CG_stringRepr *>(printRepr(&ocg, stmts));
+	for (int i = 0; i < stmts.size(); i++)
+		delete stmts[i];
+
+	if (repr != NULL) {
+		std::string s = repr->GetString();
+		delete repr;
+		return s;
+	} else
+		return std::string();
+}
+
+int CG_result::num_level() const {
+	return codegen_->num_level();
+}
+
+//-----------------------------------------------------------------------------
+// Class: CG_split
+//-----------------------------------------------------------------------------
+
+CG_result *CG_split::recompute(const BoolSet<> &parent_active,
+		const Relation &known, const Relation &restriction) {
+	active_ &= parent_active;
+	if (active_.empty()) {
+		delete this;
+		return NULL;
+	}
+
+
+	int i = 0;
+	while (i < restrictions_.size()) {
+		Relation new_restriction = Intersection(copy(restrictions_[i]),
+				copy(restriction));
+
+		new_restriction.simplify(2, 4);
+		//new_restriction.simplify();
+		clauses_[i] = clauses_[i]->recompute(active_, copy(known),
+				new_restriction);
+		if (clauses_[i] == NULL) {
+			restrictions_.erase(restrictions_.begin() + i);
+			clauses_.erase(clauses_.begin() + i);
+		} else
+			i++;
+	}
+
+
+	if (restrictions_.size() == 0) {
+		delete this;
+		return NULL;
+	} else
+		return this;
+}
+
+int CG_split::populateDepth() {
+	int max_depth = 0;
+	for (int i = 0; i < clauses_.size(); i++) {
+		int t = clauses_[i]->populateDepth();
+		if (t > max_depth)
+			max_depth = t;
+	}
+	return max_depth;
+}
+
+std::pair<CG_result *, Relation> CG_split::liftOverhead(int depth,
+		bool propagate_up) {
+	for (int i = 0; i < clauses_.size();) {
+		std::pair<CG_result *, Relation> result = clauses_[i]->liftOverhead(
+				depth, propagate_up);
+		if (result.first == NULL)
+			clauses_.erase(clauses_.begin() + i);
+		else {
+			clauses_[i] = result.first;
+			if (!result.second.is_obvious_tautology())
+				return std::make_pair(this, result.second);
+			i++;
+		}
+
+	}
+
+	if (clauses_.size() == 0) {
+		delete this;
+		return std::make_pair(static_cast<CG_result *>(NULL),
+				Relation::True(num_level()));
+	} else
+		return std::make_pair(this, Relation::True(num_level()));
+}
+
+Relation CG_split::hoistGuard() {
+	std::vector<Relation> guards;
+	for (int i = 0; i < clauses_.size(); i++)
+		guards.push_back(clauses_[i]->hoistGuard());
+
+	return SimpleHull(guards, true, true);
+}
+
+void CG_split::removeGuard(const Relation &guard) {
+	for (int i = 0; i < clauses_.size(); i++)
+		clauses_[i]->removeGuard(guard);
+}
+
+std::vector<CG_result *> CG_split::findNextLevel() const {
+	std::vector<CG_result *> result;
+	for (int i = 0; i < clauses_.size(); i++) {
+		CG_split *splt = dynamic_cast<CG_split *>(clauses_[i]);
+		if (splt != NULL) {
+			std::vector<CG_result *> t = splt->findNextLevel();
+			result.insert(result.end(), t.begin(), t.end());
+		} else
+			result.push_back(clauses_[i]);
+	}
+
+	return result;
+}
+
+CG_outputRepr *CG_split::printRepr(int indent, CG_outputBuilder *ocg,
+		const std::vector<CG_outputRepr *> &stmts,
+		const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) const {
+	CG_outputRepr *stmtList = NULL;
+	std::vector<CG_result *> next_level = findNextLevel();
+
+	std::vector<CG_loop *> cur_loops;
+	for (int i = 0; i < next_level.size(); i++) {
+		CG_loop *lp = dynamic_cast<CG_loop *>(next_level[i]);
+		if (lp != NULL) {
+			cur_loops.push_back(lp);
+		} else {
+			stmtList = ocg->StmtListAppend(stmtList,
+					loop_print_repr(cur_loops, 0, cur_loops.size(),
+							Relation::True(num_level()), NULL, indent, ocg,
+							stmts, assigned_on_the_fly));
+			stmtList = ocg->StmtListAppend(stmtList,
+					next_level[i]->printRepr(indent, ocg, stmts,
+							assigned_on_the_fly));
+			cur_loops.clear();
+		}
+	}
+
+	stmtList = ocg->StmtListAppend(stmtList,
+			loop_print_repr(cur_loops, 0, cur_loops.size(),
+					Relation::True(num_level()), NULL, indent, ocg, stmts,
+					assigned_on_the_fly));
+	return stmtList;
+}
+
+CG_result *CG_split::clone() const {
+	std::vector<CG_result *> clauses(clauses_.size());
+	for (int i = 0; i < clauses_.size(); i++)
+		clauses[i] = clauses_[i]->clone();
+	return new CG_split(codegen_, active_, restrictions_, clauses);
+}
+
+void CG_split::dump(int indent) const {
+	std::string prefix;
+	for (int i = 0; i < indent; i++)
+		prefix += "  ";
+	std::cout << prefix << "SPLIT: " << active_ << std::endl;
+	for (int i = 0; i < restrictions_.size(); i++) {
+		std::cout << prefix << "restriction: ";
+		const_cast<CG_split *>(this)->restrictions_[i].print();
+		clauses_[i]->dump(indent + 1);
+	}
+
+}
+
+//-----------------------------------------------------------------------------
+// Class: CG_loop
+//-----------------------------------------------------------------------------
+
+CG_result *CG_loop::recompute(const BoolSet<> &parent_active,
+		const Relation &known, const Relation &restriction) {
+	known_ = copy(known);
+	restriction_ = copy(restriction);
+	active_ &= parent_active;
+
+	std::vector<Relation> Rs;
+	for (BoolSet<>::iterator i = active_.begin(); i != active_.end(); i++) {
+		Relation r = Intersection(copy(restriction),
+				copy(codegen_->projected_IS_[level_ - 1][*i]));
+
+		//r.simplify(2, 4);
+		r.simplify();
+		if (!r.is_upper_bound_satisfiable()) {
+			active_.unset(*i);
+			continue;
+		}
+		Rs.push_back(copy(r));
+	}
+
+	if (active_.empty()) {
+		delete this;
+		return NULL;
+	}
+
+	Relation hull = SimpleHull(Rs, true, true);
+
+	//hull.simplify(2,4);
+
+	// check if actual loop is needed
+	std::pair<EQ_Handle, int> result = find_simplest_assignment(hull,
+			hull.set_var(level_));
+	if (result.second < INT_MAX) {
+		needLoop_ = false;
+
+		bounds_ = Relation(hull.n_set());
+		F_Exists *f_exists = bounds_.add_and()->add_exists();
+		F_And *f_root = f_exists->add_and();
+		std::map<Variable_ID, Variable_ID> exists_mapping;
+		EQ_Handle h = f_root->add_EQ();
+		for (Constr_Vars_Iter cvi(result.first); cvi; cvi++) {
+			Variable_ID v = cvi.curr_var();
+			switch (v->kind()) {
+			case Input_Var:
+				h.update_coef(bounds_.input_var(v->get_position()),
+						cvi.curr_coef());
+				break;
+			case Wildcard_Var: {
+				Variable_ID v2 = replicate_floor_definition(hull, v, bounds_,
+						f_exists, f_root, exists_mapping);
+				h.update_coef(v2, cvi.curr_coef());
+				break;
+			}
+			case Global_Var: {
+				Global_Var_ID g = v->get_global_var();
+				Variable_ID v2;
+				if (g->arity() == 0)
+					v2 = bounds_.get_local(g);
+				else
+					v2 = bounds_.get_local(g, v->function_of());
+				h.update_coef(v2, cvi.curr_coef());
+				break;
+			}
+			default:
+				assert(false);
+			}
+		}
+		h.update_const(result.first.get_const());
+		bounds_.simplify();
+	}
+	// loop iterates more than once, extract bounds now
+	else {
+		needLoop_ = true;
+
+		bounds_ = Relation(hull.n_set());
+		F_Exists *f_exists = bounds_.add_and()->add_exists();
+		F_And *f_root = f_exists->add_and();
+		std::map<Variable_ID, Variable_ID> exists_mapping;
+
+		Relation b = Gist(copy(hull), copy(known), 1);
+		bool has_unresolved_bound = false;
+
+		std::set<Variable_ID> excluded_floor_vars;
+		excluded_floor_vars.insert(b.set_var(level_));
+		for (GEQ_Iterator e(b.single_conjunct()->GEQs()); e; e++)
+			if ((*e).get_coef(b.set_var(level_)) != 0) {
+				bool is_bound = true;
+				for (Constr_Vars_Iter cvi(*e, true); cvi; cvi++) {
+					std::pair<bool, GEQ_Handle> result = find_floor_definition(
+							b, cvi.curr_var(), excluded_floor_vars);
+					if (!result.first) {
+						is_bound = false;
+						has_unresolved_bound = true;
+						break;
+					}
+				}
+
+				if (!is_bound)
+					continue;
+
+				GEQ_Handle h = f_root->add_GEQ();
+				for (Constr_Vars_Iter cvi(*e); cvi; cvi++) {
+					Variable_ID v = cvi.curr_var();
+					switch (v->kind()) {
+					case Input_Var:
+						h.update_coef(bounds_.input_var(v->get_position()),
+								cvi.curr_coef());
+						break;
+					case Wildcard_Var: {
+						Variable_ID v2 = replicate_floor_definition(b, v,
+								bounds_, f_exists, f_root, exists_mapping);
+						h.update_coef(v2, cvi.curr_coef());
+						break;
+					}
+					case Global_Var: {
+						Global_Var_ID g = v->get_global_var();
+						Variable_ID v2;
+						if (g->arity() == 0)
+							v2 = bounds_.get_local(g);
+						else
+							v2 = bounds_.get_local(g, v->function_of());
+						h.update_coef(v2, cvi.curr_coef());
+						break;
+					}
+					default:
+						assert(false);
+					}
+				}
+				h.update_const((*e).get_const());
+			}
+
+		if (has_unresolved_bound) {
+			b = Approximate(b);
+			b.simplify(2, 4);
+			//Simplification of Hull
+			hull = Approximate(hull);
+			hull.simplify(2, 4);
+			//end : Anand
+			for (GEQ_Iterator e(b.single_conjunct()->GEQs()); e; e++)
+				if ((*e).get_coef(b.set_var(level_)) != 0)
+					f_root->add_GEQ(*e);
+		}
+		bounds_.simplify();
+                hull.simplify(2,4);
+		// Since current SimpleHull does not support max() upper bound or min() lower bound,
+		// we have to forcefully split the loop when hull approximation does not return any bound.
+		bool has_lb = false;
+		bool has_ub = false;
+		for (GEQ_Iterator e = bounds_.single_conjunct()->GEQs(); e; e++) {
+			if ((*e).get_coef(bounds_.set_var(level_)) > 0)
+				has_lb = true;
+			else if ((*e).get_coef(bounds_.set_var(level_)) < 0)
+				has_ub = true;
+			if (has_lb && has_ub)
+				break;
+		}
+
+		if (!has_lb) {
+			for (int i = 0; i < Rs.size(); i++) {
+				Relation r = Approximate(copy(Rs[i]));
+				r.simplify(2, 4);
+				for (GEQ_Iterator e = r.single_conjunct()->GEQs(); e; e++)
+					if ((*e).get_coef(r.input_var(level_)) > 0) {
+						Relation r2 = Relation::True(num_level());
+						r2.and_with_GEQ(*e);
+						r2.simplify();
+						std::vector<Relation> restrictions(2);
+						restrictions[0] = Complement(copy(r2));
+						restrictions[0].simplify();
+						restrictions[1] = r2;
+						std::vector<CG_result *> clauses(2);
+						clauses[0] = this;
+						clauses[1] = this->clone();
+						CG_result *cgr = new CG_split(codegen_, active_,
+								restrictions, clauses);
+						cgr = cgr->recompute(active_, copy(known),
+								copy(restriction));
+						return cgr;
+					}
+			}
+			for (int i = 0; i < Rs.size(); i++) {
+				Relation r = Approximate(copy(Rs[i]));
+				r.simplify(2, 4);
+				for (EQ_Iterator e = r.single_conjunct()->EQs(); e; e++)
+					if ((*e).get_coef(r.input_var(level_)) != 0) {
+						Relation r2 = Relation::True(num_level());
+						r2.and_with_GEQ(*e);
+						r2.simplify();
+						std::vector<Relation> restrictions(2);
+						if ((*e).get_coef(r.input_var(level_)) > 0) {
+							restrictions[0] = Complement(copy(r2));
+							restrictions[0].simplify();
+							restrictions[1] = r2;
+						} else {
+							restrictions[0] = r2;
+							restrictions[1] = Complement(copy(r2));
+							restrictions[1].simplify();
+						}
+						std::vector<CG_result *> clauses(2);
+						clauses[0] = this;
+						clauses[1] = this->clone();
+						CG_result *cgr = new CG_split(codegen_, active_,
+								restrictions, clauses);
+						cgr = cgr->recompute(active_, copy(known),
+								copy(restriction));
+						return cgr;
+					}
+			}
+		} else if (!has_ub) {
+			for (int i = 0; i < Rs.size(); i++) {
+				Relation r = Approximate(copy(Rs[i]));
+				r.simplify(2, 4);
+				for (GEQ_Iterator e = r.single_conjunct()->GEQs(); e; e++)
+					if ((*e).get_coef(r.input_var(level_)) < 0) {
+						Relation r2 = Relation::True(num_level());
+						r2.and_with_GEQ(*e);
+						r2.simplify();
+						std::vector<Relation> restrictions(2);
+						restrictions[1] = Complement(copy(r2));
+						restrictions[1].simplify();
+						restrictions[0] = r2;
+						std::vector<CG_result *> clauses(2);
+						clauses[0] = this;
+						clauses[1] = this->clone();
+						CG_result *cgr = new CG_split(codegen_, active_,
+								restrictions, clauses);
+						cgr = cgr->recompute(active_, copy(known),
+								copy(restriction));
+						return cgr;
+					}
+			}
+			for (int i = 0; i < Rs.size(); i++) {
+				Relation r = Approximate(copy(Rs[i]));
+				r.simplify(2, 4);
+				for (EQ_Iterator e = r.single_conjunct()->EQs(); e; e++)
+					if ((*e).get_coef(r.input_var(level_)) != 0) {
+						Relation r2 = Relation::True(num_level());
+						r2.and_with_GEQ(*e);
+						r2.simplify();
+						std::vector<Relation> restrictions(2);
+						if ((*e).get_coef(r.input_var(level_)) > 0) {
+							restrictions[0] = Complement(copy(r2));
+							restrictions[0].simplify();
+							restrictions[1] = r2;
+						} else {
+							restrictions[0] = r2;
+							restrictions[1] = Complement(copy(r2));
+							restrictions[1].simplify();
+						}
+						std::vector<CG_result *> clauses(2);
+						clauses[0] = this;
+						clauses[1] = this->clone();
+						CG_result *cgr = new CG_split(codegen_, active_,
+								restrictions, clauses);
+						cgr = cgr->recompute(active_, copy(known),
+								copy(restriction));
+						return cgr;
+					}
+			}
+		}
+
+		if (!has_lb && !has_ub)
+			throw codegen_error(
+					"can't find any bound at loop level " + to_string(level_));
+		else if (!has_lb)
+			throw codegen_error(
+					"can't find lower bound at loop level "
+							+ to_string(level_));
+		else if (!has_ub)
+			throw codegen_error(
+					"can't find upper bound at loop level "
+							+ to_string(level_));
+	}
+	bounds_.copy_names(hull);
+	bounds_.setup_names();
+
+	// additional guard/stride condition extraction
+	if (needLoop_) {
+		Relation cur_known = Intersection(copy(bounds_), copy(known_));
+		cur_known.simplify();
+		hull = Gist(hull, copy(cur_known), 1);
+
+		std::pair<EQ_Handle, Variable_ID> result = find_simplest_stride(hull,
+				hull.set_var(level_));
+		if (result.second != NULL)
+			if (abs(result.first.get_coef(hull.set_var(level_))) == 1) {
+				F_Exists *f_exists = bounds_.and_with_and()->add_exists();
+				F_And *f_root = f_exists->add_and();
+				std::map<Variable_ID, Variable_ID> exists_mapping;
+				EQ_Handle h = f_root->add_EQ();
+				for (Constr_Vars_Iter cvi(result.first); cvi; cvi++) {
+					Variable_ID v = cvi.curr_var();
+					switch (v->kind()) {
+					case Input_Var:
+						h.update_coef(bounds_.input_var(v->get_position()),
+								cvi.curr_coef());
+						break;
+					case Wildcard_Var: {
+						Variable_ID v2;
+						if (v == result.second)
+							v2 = f_exists->declare();
+						else
+							v2 = replicate_floor_definition(hull, v, bounds_,
+									f_exists, f_root, exists_mapping);
+						h.update_coef(v2, cvi.curr_coef());
+						break;
+					}
+					case Global_Var: {
+						Global_Var_ID g = v->get_global_var();
+						Variable_ID v2;
+						if (g->arity() == 0)
+							v2 = bounds_.get_local(g);
+						else
+							v2 = bounds_.get_local(g, v->function_of());
+						h.update_coef(v2, cvi.curr_coef());
+						break;
+					}
+					default:
+						assert(false);
+					}
+				}
+				h.update_const(result.first.get_const());
+			} else {
+				// since gist is not powerful enough on modular constraints for now,
+				// make an educated guess
+				coef_t stride = abs(result.first.get_coef(result.second))
+						/ gcd(abs(result.first.get_coef(result.second)),
+								abs(
+										result.first.get_coef(
+												hull.set_var(level_))));
+
+				Relation r1(hull.n_inp());
+				F_Exists *f_exists = r1.add_and()->add_exists();
+				F_And *f_root = f_exists->add_and();
+				std::map<Variable_ID, Variable_ID> exists_mapping;
+				EQ_Handle h = f_root->add_EQ();
+				for (Constr_Vars_Iter cvi(result.first); cvi; cvi++) {
+					Variable_ID v = cvi.curr_var();
+					switch (v->kind()) {
+					case Input_Var:
+						h.update_coef(r1.input_var(v->get_position()),
+								cvi.curr_coef());
+						break;
+					case Wildcard_Var: {
+						Variable_ID v2;
+						if (v == result.second)
+							v2 = f_exists->declare();
+						else
+							v2 = replicate_floor_definition(hull, v, r1,
+									f_exists, f_root, exists_mapping);
+						h.update_coef(v2, cvi.curr_coef());
+						break;
+					}
+					case Global_Var: {
+						Global_Var_ID g = v->get_global_var();
+						Variable_ID v2;
+						if (g->arity() == 0)
+							v2 = r1.get_local(g);
+						else
+							v2 = r1.get_local(g, v->function_of());
+						h.update_coef(v2, cvi.curr_coef());
+						break;
+					}
+					default:
+						assert(false);
+					}
+				}
+				h.update_const(result.first.get_const());
+				r1.simplify();
+
+				bool guess_success = false;
+				for (GEQ_Iterator e(bounds_.single_conjunct()->GEQs()); e; e++)
+					if ((*e).get_coef(bounds_.set_var(level_)) == 1) {
+						Relation r2(hull.n_inp());
+						F_Exists *f_exists = r2.add_and()->add_exists();
+						F_And *f_root = f_exists->add_and();
+						std::map<Variable_ID, Variable_ID> exists_mapping;
+						EQ_Handle h = f_root->add_EQ();
+						h.update_coef(f_exists->declare(), stride);
+						for (Constr_Vars_Iter cvi(*e); cvi; cvi++) {
+							Variable_ID v = cvi.curr_var();
+							switch (v->kind()) {
+							case Input_Var:
+								h.update_coef(r2.input_var(v->get_position()),
+										cvi.curr_coef());
+								break;
+							case Wildcard_Var: {
+								Variable_ID v2 = replicate_floor_definition(
+										hull, v, r2, f_exists, f_root,
+										exists_mapping);
+								h.update_coef(v2, 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(false);
+							}
+						}
+						h.update_const((*e).get_const());
+						r2.simplify();
+
+						if (Gist(copy(r1),
+								Intersection(copy(cur_known), copy(r2)), 1).is_obvious_tautology()
+								&& Gist(copy(r2),
+										Intersection(copy(cur_known), copy(r1)),
+										1).is_obvious_tautology()) {
+							bounds_ = Intersection(bounds_, r2);
+							bounds_.simplify();
+							guess_success = true;
+							break;
+						}
+					}
+
+				// this is really a stride with non-unit coefficient for this loop variable
+				if (!guess_success) {
+					// TODO: for stride ax = b mod n it might be beneficial to
+					//       generate modular linear equation solver code for
+					//       runtime to get the starting position in printRepr,
+					//       and stride would be n/gcd(|a|,n), thus this stride
+					//       can be put into bounds_ too.
+				}
+
+			}
+
+		hull = Project(hull, hull.set_var(level_));
+		hull.simplify(2, 4);
+		guard_ = Gist(hull, Intersection(copy(bounds_), copy(known_)), 1);
+	}
+	// don't generate guard for non-actual loop, postpone it. otherwise
+	// redundant if-conditions might be generated since for-loop semantics
+	// includes implicit comparison checking.  -- by chun 09/14/10
+	else
+		guard_ = Relation::True(num_level());
+	guard_.copy_names(bounds_);
+	guard_.setup_names();
+
+        //guard_.simplify();  
+	// recursively down the AST
+	Relation new_known = Intersection(copy(known),
+			Intersection(copy(bounds_), copy(guard_)));
+	new_known.simplify(2, 4);
+	Relation new_restriction = Intersection(copy(restriction),
+			Intersection(copy(bounds_), copy(guard_)));
+	new_restriction.simplify(2, 4);
+	body_ = body_->recompute(active_, new_known, new_restriction);
+	if (body_ == NULL) {
+		delete this;
+		return NULL;
+	} else
+		return this;
+}
+
+int CG_loop::populateDepth() {
+	int depth = body_->populateDepth();
+	if (needLoop_)
+		depth_ = depth + 1;
+	else
+		depth_ = depth;
+	return depth_;
+}
+
+std::pair<CG_result *, Relation> CG_loop::liftOverhead(int depth,
+		bool propagate_up) {
+	if (depth_ > depth) {
+		assert(propagate_up == false);
+		std::pair<CG_result *, Relation> result = body_->liftOverhead(depth,
+				false);
+		body_ = result.first;
+		return std::make_pair(this, Relation::True(num_level()));
+	} else { // (depth_ <= depth)
+		if (propagate_up) {
+			Relation r = pick_one_guard(guard_, level_);
+			if (!r.is_obvious_tautology())
+				return std::make_pair(this, r);
+		}
+
+		std::pair<CG_result *, Relation> result;
+		if (propagate_up || needLoop_)
+			result = body_->liftOverhead(depth, true);
+		else
+			result = body_->liftOverhead(depth, false);
+		body_ = result.first;
+		if (result.second.is_obvious_tautology())
+			return std::make_pair(this, result.second);
+
+		// loop is an assignment, replace this loop variable in overhead condition
+		if (!needLoop_) {
+			result.second = Intersection(result.second, copy(bounds_));
+			result.second = Project(result.second,
+					result.second.set_var(level_));
+			result.second.simplify(2, 4);
+		}
+
+
+		int max_level = 0;
+		bool has_wildcard = false;
+		bool direction = true;
+		for (EQ_Iterator e(result.second.single_conjunct()->EQs()); e; e++)
+			if ((*e).has_wildcards()) {
+				if (has_wildcard)
+					assert(false);
+				else
+					has_wildcard = true;
+				for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
+					if (cvi.curr_var()->kind() == Input_Var
+							&& cvi.curr_var()->get_position() > max_level)
+						max_level = cvi.curr_var()->get_position();
+			} else
+				assert(false);
+
+		if (!has_wildcard) {
+			int num_simple_geq = 0;
+			for (GEQ_Iterator e(result.second.single_conjunct()->GEQs()); e;
+					e++)
+				if (!(*e).has_wildcards()) {
+					num_simple_geq++;
+					for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
+						if (cvi.curr_var()->kind() == Input_Var
+								&& cvi.curr_var()->get_position() > max_level) {
+							max_level = cvi.curr_var()->get_position();
+							direction = (cvi.curr_coef() < 0) ? true : false;
+						}
+				} else {
+					has_wildcard = true;
+					for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
+						if (cvi.curr_var()->kind() == Input_Var
+								&& cvi.curr_var()->get_position() > max_level) {
+							max_level = cvi.curr_var()->get_position();
+						}
+				}
+			assert(
+					(has_wildcard && num_simple_geq == 0) || (!has_wildcard && num_simple_geq == 1));
+		}
+
+		// check if this is the top loop level for splitting for this overhead
+		if (!propagate_up || (has_wildcard && max_level == level_ - 1)
+				|| (!has_wildcard && max_level == level_)) {
+			std::vector<Relation> restrictions(2);
+			std::vector<CG_result *> clauses(2);
+			int saved_num_level = num_level();
+			if (has_wildcard || direction) {
+				restrictions[1] = Complement(copy(result.second));
+				restrictions[1].simplify();
+				clauses[1] = this->clone();
+				restrictions[0] = result.second;
+				clauses[0] = this;
+			} else {
+				restrictions[0] = Complement(copy(result.second));
+				restrictions[0].simplify();
+				clauses[0] = this->clone();
+				restrictions[1] = result.second;
+				clauses[1] = this;
+			}
+			CG_result *cgr = new CG_split(codegen_, active_, restrictions,
+					clauses);
+			CG_result *new_cgr = cgr->recompute(active_, copy(known_),
+					copy(restriction_));
+			new_cgr->populateDepth();
+			assert(new_cgr==cgr);
+			if (static_cast<CG_split *>(new_cgr)->clauses_.size() == 1)
+				// infinite recursion detected, bail out
+				return std::make_pair(new_cgr, Relation::True(saved_num_level));
+			else
+				return cgr->liftOverhead(depth, propagate_up);
+		} else
+			return std::make_pair(this, result.second);
+	}
+}
+
+Relation CG_loop::hoistGuard() {
+
+	Relation r = body_->hoistGuard();
+
+	// TODO: should bookkeep catched contraints in loop output as enforced and check if anything missing
+	// if (!Gist(copy(b), copy(enforced)).is_obvious_tautology()) {
+	//   fprintf(stderr, "need to generate extra guard inside the loop\n");
+	// }
+
+	  if (!needLoop_)
+	    r = Intersection(r, copy(bounds_));
+	  r = Project(r, r.set_var(level_));
+	  r = Gist(r, copy(known_), 1);
+
+	  Relation eliminate_existentials_r;
+	  Relation eliminate_existentials_known;
+
+	  eliminate_existentials_r = copy(r);
+	  if (!r.is_obvious_tautology()) {
+		  eliminate_existentials_r = Approximate(copy(r));
+		  eliminate_existentials_r.simplify(2,4);
+		  eliminate_existentials_known = Approximate(copy(known_));
+		  eliminate_existentials_known.simplify(2,4);
+
+		  eliminate_existentials_r = Gist( eliminate_existentials_r, eliminate_existentials_known, 1);
+	  }
+          
+
+	  if (!eliminate_existentials_r.is_obvious_tautology()) {
+	 // if (!r.is_obvious_tautology()) {
+	    body_->removeGuard(r);
+	    guard_ = Intersection(guard_, copy(r));
+	    guard_.simplify();
+	  }
+
+	  return guard_;
+
+	//   return ifList;
+	// }
+
+
+}
+
+void CG_loop::removeGuard(const Relation &guard) {
+	known_ = Intersection(known_, copy(guard));
+	known_.simplify();
+
+	guard_ = Gist(guard_, copy(known_), 1);
+	guard_.copy_names(known_);
+	guard_.setup_names();
+}
+
+CG_outputRepr *CG_loop::printRepr(int indent, CG_outputBuilder *ocg,
+		const std::vector<CG_outputRepr *> &stmts,
+		const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) const {
+	return printRepr(true, indent, ocg, stmts, assigned_on_the_fly);
+}
+
+CG_outputRepr *CG_loop::printRepr(bool do_print_guard, int indent,
+		CG_outputBuilder *ocg, const std::vector<CG_outputRepr *> &stmts,
+		const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) const {
+	CG_outputRepr *guardRepr;
+	if (do_print_guard)
+		guardRepr = output_guard(ocg, guard_, assigned_on_the_fly);
+	else
+		guardRepr = NULL;
+
+	Relation cur_known = Intersection(copy(known_), copy(guard_));
+	cur_known.simplify();
+	if (needLoop_) {
+
+		if (checkLoopLevel)
+			if (level_ == checkLoopLevel)
+				if (active_.get(stmtForLoopCheck))
+					fillInBounds = true;
+
+		CG_outputRepr *ctrlRepr = output_loop(ocg, bounds_, level_, cur_known,
+				assigned_on_the_fly);
+
+		fillInBounds = false;
+
+		CG_outputRepr *bodyRepr = body_->printRepr(
+				(guardRepr == NULL) ? indent + 1 : indent + 2, ocg, stmts,
+				assigned_on_the_fly);
+		CG_outputRepr * loopRepr;
+
+		if (guardRepr == NULL)
+			loopRepr = ocg->CreateLoop(indent, ctrlRepr, bodyRepr);
+		else
+			loopRepr = ocg->CreateLoop(indent + 1, ctrlRepr, bodyRepr);
+
+		if (!smtNonSplitLevels.empty()) {
+			bool blockLoop = false;
+			bool threadLoop = false;
+			bool sync = false;
+			int firstActiveStmt = -1;
+			for (int s = 0; s < active_.size(); s++) {
+				if (active_.get(s)) {
+					if (firstActiveStmt < 0)
+						firstActiveStmt = s;
+					//We assume smtNonSplitLevels is only used to mark the first of
+					//the block or thread loops to be reduced in CUDA-CHiLL. Here we
+					//place some comments to help with final code generation.
+					//int idx = smtNonSplitLevels[s].index(level_);
+
+					if (s < smtNonSplitLevels.size()) {
+						if (smtNonSplitLevels[s].size() > 0)
+							if (smtNonSplitLevels[s][0] == level_) {
+								blockLoop = true;
+							}
+						//Assume every stmt marked with a thread loop index also has a block loop idx
+						if (smtNonSplitLevels[s].size() > 1)
+							if (smtNonSplitLevels[s][1] == level_) {
+								threadLoop = true;
+							}
+					}
+				}
+			}
+			if (blockLoop && threadLoop) {
+				fprintf(stderr,
+						"Warning, have %d level more than once in smtNonSplitLevels\n",
+						level_);
+				threadLoop = false;
+			}
+			std::string preferredIdx;
+			if (loopIdxNames.size()
+					&& (level_ / 2) - 1 < loopIdxNames[firstActiveStmt].size())
+				preferredIdx = loopIdxNames[firstActiveStmt][(level_ / 2) - 1];
+			for (int s = 0; s < active_.size(); s++) {
+				if (active_.get(s)) {
+					for (int i = 0; i < syncs.size(); i++) {
+						if (syncs[i].first == s
+								&& strcmp(syncs[i].second.c_str(),
+										preferredIdx.c_str()) == 0) {
+							sync = true;
+							//printf("FOUND SYNC\n");
+						}
+
+					}
+				}
+		
+			}
+			if (threadLoop || blockLoop || preferredIdx.length() != 0) {
+				char buf[1024];
+				std::string loop;
+				if (blockLoop)
+					loop = "blockLoop ";
+				if (threadLoop)
+					loop = "threadLoop ";
+				if (preferredIdx.length() != 0 && sync) {
+					sprintf(buf, "~cuda~ %spreferredIdx: %s sync", loop.c_str(),
+							preferredIdx.c_str());
+				} else if (preferredIdx.length() != 0) {
+					sprintf(buf, "~cuda~ %spreferredIdx: %s", loop.c_str(),
+							preferredIdx.c_str());
+				} else {
+					sprintf(buf, "~cuda~ %s", loop.c_str());
+				}
+
+
+				loopRepr = ocg->CreateAttribute(loopRepr, buf);
+			}
+
+		}
+		if (guardRepr == NULL)
+			return loopRepr;
+		else
+			return ocg->CreateIf(indent, guardRepr, loopRepr, NULL);
+	} else {
+		std::pair<CG_outputRepr *, std::pair<CG_outputRepr *, int> > result =
+				output_assignment(ocg, bounds_, level_, cur_known,
+						assigned_on_the_fly);
+		guardRepr = ocg->CreateAnd(guardRepr, result.first);
+
+		if (result.second.second < CodeGen::var_substitution_threshold) {
+			std::vector<std::pair<CG_outputRepr *, int> > atof =
+					assigned_on_the_fly;
+			atof[level_ - 1] = result.second;
+			CG_outputRepr *bodyRepr = body_->printRepr(
+					(guardRepr == NULL) ? indent : indent + 1, ocg, stmts,
+					atof);
+			delete atof[level_ - 1].first;
+			if (guardRepr == NULL)
+				return bodyRepr;
+			else
+				return ocg->CreateIf(indent, guardRepr, bodyRepr, NULL);
+		} else {
+			CG_outputRepr *assignRepr = ocg->CreateAssignment(
+					(guardRepr == NULL) ? indent : indent + 1,
+					output_ident(ocg, bounds_,
+							const_cast<CG_loop *>(this)->bounds_.set_var(
+									level_), assigned_on_the_fly),
+					result.second.first);
+			CG_outputRepr *bodyRepr = body_->printRepr(
+					(guardRepr == NULL) ? indent : indent + 1, ocg, stmts,
+					assigned_on_the_fly);
+			if (guardRepr == NULL)
+				return ocg->StmtListAppend(assignRepr, bodyRepr);
+			else
+				return ocg->CreateIf(indent, guardRepr,
+						ocg->StmtListAppend(assignRepr, bodyRepr), NULL);
+		}
+
+	}
+}
+
+CG_result *CG_loop::clone() const {
+	return new CG_loop(codegen_, active_, level_, body_->clone());
+}
+
+void CG_loop::dump(int indent) const {
+	std::string prefix;
+	for (int i = 0; i < indent; i++)
+		prefix += "  ";
+	std::cout << prefix << "LOOP (level " << level_ << "): " << active_
+			<< std::endl;
+	std::cout << prefix << "known: ";
+	const_cast<CG_loop *>(this)->known_.print();
+	std::cout << prefix << "restriction: ";
+	const_cast<CG_loop *>(this)->restriction_.print();
+	std::cout << prefix << "bounds: ";
+	const_cast<CG_loop *>(this)->bounds_.print();
+	std::cout << prefix << "guard: ";
+	const_cast<CG_loop *>(this)->guard_.print();
+	body_->dump(indent + 1);
+}
+
+//-----------------------------------------------------------------------------
+// Class: CG_leaf
+//-----------------------------------------------------------------------------
+
+CG_result* CG_leaf::recompute(const BoolSet<> &parent_active,
+		const Relation &known, const Relation &restriction) {
+	active_ &= parent_active;
+	known_ = copy(known);
+
+	guards_.clear();
+	for (BoolSet<>::iterator i = active_.begin(); i != active_.end(); i++) {
+		Relation r = Intersection(
+				copy(codegen_->projected_IS_[num_level() - 1][*i]),
+				copy(restriction));
+		r.simplify(2, 4);
+		if (!r.is_upper_bound_satisfiable())
+			active_.unset(*i);
+		else {
+			r = Gist(r, copy(known), 1);
+			if (!r.is_obvious_tautology()) {
+				guards_[*i] = r;
+				guards_[*i].copy_names(known);
+				guards_[*i].setup_names();
+			}
+		}
+	}
+
+
+	if (active_.empty()) {
+		delete this;
+		return NULL;
+	} else
+		return this;
+}
+
+std::pair<CG_result *, Relation> CG_leaf::liftOverhead(int depth, bool) {
+	if (depth == 0)
+		return std::make_pair(this, Relation::True(num_level()));
+
+	for (std::map<int, Relation>::iterator i = guards_.begin();
+			i != guards_.end(); i++) {
+		Relation r = pick_one_guard(i->second);
+		if (!r.is_obvious_tautology()) {
+			bool has_wildcard = false;
+			int max_level = 0;
+			for (EQ_Iterator e(r.single_conjunct()->EQs()); e; e++) {
+				if ((*e).has_wildcards())
+					has_wildcard = true;
+				for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
+					if (cvi.curr_var()->kind() == Input_Var
+							&& cvi.curr_var()->get_position() > max_level)
+						max_level = cvi.curr_var()->get_position();
+			}
+			for (GEQ_Iterator e(r.single_conjunct()->GEQs()); e; e++) {
+				if ((*e).has_wildcards())
+					has_wildcard = true;
+				for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
+					if (cvi.curr_var()->kind() == Input_Var
+							&& cvi.curr_var()->get_position() > max_level)
+						max_level = cvi.curr_var()->get_position();
+			}
+
+			if (!(has_wildcard && max_level == codegen_->num_level()))
+				return std::make_pair(this, r);
+		}
+	}
+
+	return std::make_pair(this, Relation::True(num_level()));
+}
+
+Relation CG_leaf::hoistGuard() {
+	std::vector<Relation> guards;
+	for (BoolSet<>::iterator i = active_.begin(); i != active_.end(); i++) {
+		std::map<int, Relation>::iterator j = guards_.find(*i);
+		if (j == guards_.end()) {
+			Relation r = Relation::True(num_level());
+			r.copy_names(known_);
+			r.setup_names();
+			return r;
+		} else {
+			guards.push_back(j->second);
+		}
+	}
+
+	return SimpleHull(guards, true, true);
+}
+
+void CG_leaf::removeGuard(const Relation &guard) {
+	known_ = Intersection(known_, copy(guard));
+	known_.simplify();
+
+	std::map<int, Relation>::iterator i = guards_.begin();
+	while (i != guards_.end()) {
+		i->second = Gist(i->second, copy(known_), 1);
+		if (i->second.is_obvious_tautology())
+			guards_.erase(i++);
+		else
+			++i;
+	}
+}
+
+CG_outputRepr *CG_leaf::printRepr(int indent, CG_outputBuilder *ocg,
+		const std::vector<CG_outputRepr *> &stmts,
+		const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) const {
+	return leaf_print_repr(active_, guards_, NULL, known_, indent, ocg,
+			codegen_->remap_, codegen_->xforms_, stmts, assigned_on_the_fly);
+}
+
+CG_result *CG_leaf::clone() const {
+	return new CG_leaf(codegen_, active_);
+}
+
+void CG_leaf::dump(int indent) const {
+	std::string prefix;
+	for (int i = 0; i < indent; i++)
+		prefix += "  ";
+	std::cout << prefix << "LEAF: " << active_ << std::endl;
+	std::cout << prefix << "known: ";
+	const_cast<CG_leaf *>(this)->known_.print();
+	for (std::map<int, Relation>::const_iterator i = guards_.begin();
+			i != guards_.end(); i++) {
+		std::cout << prefix << "guard #" << i->first << ":";
+		const_cast<Relation &>(i->second).print();
+	}
+}
+
+}
diff --git a/lib/codegen/src/CG_stringBuilder.cc b/lib/codegen/src/CG_stringBuilder.cc
new file mode 100644
index 0000000..2f9286f
--- /dev/null
+++ b/lib/codegen/src/CG_stringBuilder.cc
@@ -0,0 +1,487 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 the Omega Project Team
+ Copyright (C) 2005-2011 Chun Chen
+ All Rights Reserved.
+
+ Purpose:
+   generate pseudo string code
+
+ Notes:
+   There is no need to check illegal NULL parameter and throw invalid_argument
+ in other IR interface implementation. They are for debugging purpose.
+   intMod implements modular function that returns positve remainder no matter
+ lop is postive or nagative and rop is guranteed to be positive here.
+     
+ History:
+   04/17/96 - Lei Zhou - created
+   08/31/09 add parenthesis to string operands, Chun Chen
+*****************************************************************************/
+
+#include <code_gen/CG_stringBuilder.h>
+#include <code_gen/codegen_error.h>
+#include <basic/util.h>
+#include <string>
+#include <stdexcept>
+#include <ctype.h>
+#include <string.h>
+
+namespace {
+
+std::string SafeguardString(const std::string &s, char op) {
+  int len = s.length();
+  int paren_level = 0;
+  int num_plusminus = 0;
+  int num_mul = 0;
+  int num_div = 0;
+  for (int i = 0; i < len; i++)
+    switch (s[i]) {
+    case '(':
+      paren_level++;
+      break;
+    case ')':
+      paren_level--;
+      break;
+    case '+':
+    case '-':
+      if (paren_level == 0)
+        num_plusminus++;
+      break;
+    case '*':
+      if (paren_level == 0)
+        num_mul++;
+      break;
+    case '/':
+      if (paren_level == 0)
+        num_div++;
+      break;
+    default:
+      break;
+    }
+
+  bool need_paren = false;
+  switch (op) {
+  case '-':
+    if (num_plusminus > 0)
+      need_paren = true;
+    break;
+  case '*':
+    if (num_plusminus > 0 || num_div > 0)
+      need_paren = true;
+    break;
+  case '/':
+    if (num_plusminus > 0 || num_div > 0 || num_mul > 0)
+      need_paren = true;
+    break;
+  default:
+    break;
+  }
+
+  if (need_paren)
+    return "(" + s + ")";
+  else
+    return s;
+}
+
+
+std::string GetIndentSpaces(int indent) {
+  std::string indentStr;
+  for (int i = 1; i < indent; i++) {
+    indentStr += "  ";
+  }
+  return indentStr;
+}
+
+
+// A shortcut to extract the string enclosed in the CG_outputRepr and delete
+// the original holder.
+std::string GetString(omega::CG_outputRepr *repr) {
+  std::string result = static_cast<omega::CG_stringRepr *>(repr)->GetString();
+  delete repr;
+  return result;
+}
+
+}
+
+
+namespace omega {
+
+
+
+//-----------------------------------------------------------------------------
+// Class: CG_stringBuilder
+//-----------------------------------------------------------------------------
+
+CG_stringRepr *CG_stringBuilder::CreateSubstitutedStmt(int indent, CG_outputRepr *stmt,
+                                                       const std::vector<std::string> &vars,
+                                                       std::vector<CG_outputRepr *> &subs) const {
+  std::string listStr = "";
+
+  for (int i = 0; i < subs.size(); i++) {
+    if (subs[i] == NULL)
+      listStr += "N/A";
+    else 
+      listStr += GetString(subs[i]);
+    if (i < subs.size() - 1)
+      listStr += ",";
+  } 
+
+  std::string stmtName = GetString(stmt);
+  std::string indentStr = GetIndentSpaces(indent);
+
+  return new CG_stringRepr(indentStr + stmtName + "(" + listStr + ");\n");
+}
+
+CG_stringRepr *CG_stringBuilder::CreateAssignment(int indent, 
+                                                  CG_outputRepr *lhs,
+                                                  CG_outputRepr *rhs) const {
+  if (lhs == NULL || rhs == NULL)
+    throw std::invalid_argument("missing lhs or rhs in assignment");
+
+  std::string lhsStr = GetString(lhs);
+  std::string rhsStr = GetString(rhs);
+
+  std::string indentStr = GetIndentSpaces(indent);
+
+  return new CG_stringRepr(indentStr + lhsStr + "=" + rhsStr + ";\n");
+}
+
+
+CG_stringRepr *CG_stringBuilder::CreateInvoke(const std::string &funcName,
+                                              std::vector<CG_outputRepr *> &list) const {
+  std::string listStr = "";
+
+  for (int i = 0; i < list.size(); i++) {
+    listStr += GetString(list[i]);
+    if ( i < list.size()-1)
+      listStr += ",";
+  }
+
+  return new CG_stringRepr(funcName + "(" + listStr + ")");
+}
+    
+
+CG_stringRepr *CG_stringBuilder::CreateComment(int indent, const std::string &commentText) const {
+  if (commentText == std::string("")) {
+    return NULL;
+  }
+
+  std::string indentStr = GetIndentSpaces(indent);
+
+  return new CG_stringRepr(indentStr + "// " + commentText + "\n");
+}
+
+CG_stringRepr* CG_stringBuilder::CreateAttribute(CG_outputRepr *control,
+		const std::string &commentText) const {
+	if (commentText == std::string("")) {
+		return static_cast<CG_stringRepr *> (control);
+	}
+
+	std::string controlString = GetString(control);
+
+	return new CG_stringRepr("// " + commentText + "\n" + controlString);
+
+}
+
+CG_outputRepr* CG_stringBuilder::CreatePragmaAttribute(CG_outputRepr *scopeStmt, int looplevel, const std::string &pragmaText) const {
+	// -- Not Implemented
+	return scopeStmt;
+}
+
+CG_outputRepr* CG_stringBuilder::CreatePrefetchAttribute(CG_outputRepr* scopeStmt, int looplevel, const std::string& arrName, int hint) const {
+	// -- Not Implemented
+	return scopeStmt;
+}
+
+CG_stringRepr *CG_stringBuilder::CreateIf(int indent, CG_outputRepr *guardList,
+                                          CG_outputRepr *true_stmtList, CG_outputRepr *false_stmtList) const {
+  if (guardList == NULL)
+    throw std::invalid_argument("missing if condition");
+  
+  if (true_stmtList == NULL && false_stmtList == NULL) {
+    delete guardList;
+    return NULL;
+  }
+
+  std::string guardListStr = GetString(guardList);
+  std::string indentStr = GetIndentSpaces(indent);
+  std::string s;
+  if (true_stmtList != NULL && false_stmtList == NULL) {
+    s = indentStr + "if (" + guardListStr + ") {\n"
+      + GetString(true_stmtList)
+      + indentStr + "}\n";
+  }
+  else if (true_stmtList == NULL && false_stmtList != NULL) {
+    s = indentStr + "if !(" + guardListStr + ") {\n"
+      + GetString(false_stmtList)
+      + indentStr + "}\n";
+  }
+  else {
+    s = indentStr + "if (" + guardListStr + ") {\n" 
+      + GetString(true_stmtList)
+      + indentStr + "}\n"
+      + indentStr + "else {\n"
+      + GetString(false_stmtList)
+      + indentStr + "}\n";
+  }
+  
+  return new CG_stringRepr(s);
+}
+
+
+
+CG_stringRepr *CG_stringBuilder::CreateInductive(CG_outputRepr *index,
+                                                 CG_outputRepr *lower, CG_outputRepr *upper,
+                                                 CG_outputRepr *step) const {
+  if (index == NULL)
+    throw std::invalid_argument("missing loop index");
+  if (lower == NULL)
+    throw std::invalid_argument("missing loop lower bound");
+  if (upper == NULL)
+    throw std::invalid_argument("missing loop upper bound");
+  if (step == NULL)
+    throw std::invalid_argument("missing loop step size");
+  
+  std::string indexStr = GetString(index);
+  std::string lowerStr = GetString(lower);
+  std::string upperStr = GetString(upper);
+
+  std::string doStr = "for(" + indexStr + " = " + lowerStr + "; "
+    + indexStr + " <= " + upperStr + "; " 
+    + indexStr;
+  
+  std::string stepStr = GetString(step);
+  if (stepStr == to_string(1))
+    doStr += "++";
+  else
+    doStr += " += " + stepStr;
+        
+  doStr += ")";
+      
+  return new CG_stringRepr(doStr);
+}
+
+
+CG_stringRepr *CG_stringBuilder::CreateLoop(int indent, CG_outputRepr *control,
+                                            CG_outputRepr *stmtList) const {
+  if (stmtList == NULL) {
+    delete control;
+    return NULL;
+  }
+  else if (control == NULL)
+    return static_cast<CG_stringRepr *>(stmtList);
+
+  std::string ctrlStr = GetString(control);
+  std::string stmtStr = GetString(stmtList);
+
+  std::string indentStr = GetIndentSpaces(indent);
+
+  std::string s = indentStr + ctrlStr + " {\n"
+    + stmtStr 
+    + indentStr + "}\n";
+
+  return new CG_stringRepr(s);
+}
+
+
+
+CG_stringRepr *CG_stringBuilder::CreateInt(int num) const {
+  std::string s = to_string(num);
+  return new CG_stringRepr(s);
+}
+
+
+
+bool CG_stringBuilder::isInteger(CG_outputRepr *op) const {
+
+	 char * cstr;
+     std::string s = GetString(op);
+     cstr = new char [s.size()+1];
+     strcpy (cstr, s.c_str());
+     int count = 0;
+     while(cstr[count] != '\n' && cstr[count] != '\0' )
+        if( !isdigit(cstr[count]))
+    	   return false;
+
+
+     return true;
+}
+
+
+
+CG_stringRepr *CG_stringBuilder::CreateIdent(const std::string &varName) const {
+  if (varName == std::string("")) {
+    return NULL;
+  }
+
+  return new CG_stringRepr(varName);
+}
+
+
+CG_stringRepr *CG_stringBuilder::CreatePlus(CG_outputRepr *lop, CG_outputRepr *rop) const {
+  if (rop == NULL) {
+    return static_cast<CG_stringRepr *>(lop);
+  }
+  else if (lop == NULL) {
+    return static_cast<CG_stringRepr *>(rop);
+  }
+
+  std::string lopStr = GetString(lop);
+  std::string ropStr = GetString(rop);
+
+  return new CG_stringRepr(lopStr + "+" + ropStr);
+}
+
+
+CG_stringRepr *CG_stringBuilder::CreateMinus(CG_outputRepr *lop, CG_outputRepr *rop) const {
+  if (rop == NULL) {
+    return static_cast<CG_stringRepr *>(lop);
+  }
+  else if (lop == NULL) {
+    std::string ropStr = GetString(rop);
+    return new CG_stringRepr("-" + SafeguardString(ropStr, '-'));
+  }
+
+  std::string lopStr = GetString(lop);
+  std::string ropStr = GetString(rop);
+
+  return new CG_stringRepr(lopStr + "-" + SafeguardString(ropStr, '-'));
+}
+
+
+CG_stringRepr *CG_stringBuilder::CreateTimes(CG_outputRepr *lop, CG_outputRepr *rop) const {
+  if (rop == NULL || lop == NULL) {
+    delete rop;
+    delete lop;
+    return NULL;
+  }
+
+  std::string lopStr = GetString(lop);
+  std::string ropStr = GetString(rop);
+
+  return new CG_stringRepr(SafeguardString(lopStr, '*') + "*" + SafeguardString(ropStr, '*'));
+}
+
+
+CG_stringRepr *CG_stringBuilder::CreateDivide(CG_outputRepr *lop, CG_outputRepr *rop) const {
+  if (rop == NULL)
+    throw codegen_error("integer division by zero");
+  else if (lop == NULL) {
+    delete rop;
+    return NULL;
+  }
+
+  std::string lopStr = GetString(lop);
+  std::string ropStr = GetString(rop);
+
+  return new CG_stringRepr(SafeguardString(lopStr, '/') + "/" + SafeguardString(ropStr, '/'));
+}
+
+
+CG_stringRepr *CG_stringBuilder::CreateIntegerFloor(CG_outputRepr *lop, CG_outputRepr *rop) const {
+  if (rop == NULL)
+    throw codegen_error("integer division by zero");
+  else if (lop == NULL) {
+    delete rop;
+    return NULL;
+  }
+
+  std::string lopStr = GetString(lop);
+  std::string ropStr = GetString(rop);
+
+  return new CG_stringRepr("intFloor(" + lopStr + "," + ropStr + ")");
+}
+
+
+CG_stringRepr *CG_stringBuilder::CreateIntegerMod(CG_outputRepr *lop, CG_outputRepr *rop) const {
+  if (rop == NULL)
+    throw codegen_error("integer modulo by zero");
+  else if (lop == NULL) {
+    delete rop;
+    return NULL;
+  }
+
+  std::string lopStr = GetString(lop);
+  std::string ropStr = GetString(rop);
+
+  return new CG_stringRepr("intMod(" + lopStr + "," + ropStr + ")");
+}
+
+CG_stringRepr *CG_stringBuilder::CreateIntegerCeil(CG_outputRepr *lop, CG_outputRepr *rop) const {
+  if (rop == 0)
+    throw codegen_error("integer ceiling by zero");
+  else if (lop == NULL) {
+    delete rop;
+    return NULL;
+  }
+
+  std::string lopStr = GetString(lop);
+  std::string ropStr = GetString(rop);
+
+  return new CG_stringRepr("intCeil(" + lopStr + "," + ropStr + ")");
+}
+
+
+CG_stringRepr *CG_stringBuilder::CreateAnd(CG_outputRepr *lop, CG_outputRepr *rop) const {
+  if (rop == NULL)
+    return static_cast<CG_stringRepr *>(lop);
+  else if (lop == NULL)
+    return static_cast<CG_stringRepr *>(rop);
+
+  std::string lopStr = GetString(lop);
+  std::string ropStr = GetString(rop);
+
+  return new CG_stringRepr(lopStr + " && " + ropStr);
+}
+
+
+CG_stringRepr *CG_stringBuilder::CreateGE(CG_outputRepr *lop, CG_outputRepr *rop) const {
+  if (rop == NULL || lop == NULL)
+    throw std::invalid_argument("missing operand in greater than equal comparison condition");
+
+  std::string lopStr = GetString(lop);
+  std::string ropStr = GetString(rop);
+
+  return new CG_stringRepr(lopStr + " >= " + ropStr);
+}
+
+
+
+CG_stringRepr *CG_stringBuilder::CreateLE(CG_outputRepr *lop, CG_outputRepr *rop) const {
+  if (rop == NULL || lop == NULL)
+    throw std::invalid_argument("missing operand in less than equal comparison condition");
+
+  std::string lopStr = GetString(lop);
+  std::string ropStr = GetString(rop);
+
+  return new CG_stringRepr(lopStr + " <= " + ropStr);
+}
+
+
+
+CG_stringRepr *CG_stringBuilder::CreateEQ(CG_outputRepr *lop, CG_outputRepr *rop) const {
+  if (rop == NULL || lop == NULL)
+    throw std::invalid_argument("missing operand in equal comparison condition");
+
+  std::string lopStr = GetString(lop);
+  std::string ropStr = GetString(rop);
+
+  return new CG_stringRepr(lopStr + " == " + ropStr);
+}
+
+
+
+CG_stringRepr *CG_stringBuilder::StmtListAppend(CG_outputRepr *list1, CG_outputRepr *list2) const {
+  if (list2 == NULL) {
+    return static_cast<CG_stringRepr *>(list1);
+  }
+  else if (list1 == NULL) {
+    return static_cast<CG_stringRepr *>(list2);
+  }
+
+  std::string list1Str = GetString(list1);
+  std::string list2Str = GetString(list2);
+
+  return new CG_stringRepr(list1Str + list2Str);
+}
+
+}
diff --git a/lib/codegen/src/CG_utils.cc b/lib/codegen/src/CG_utils.cc
new file mode 100755
index 0000000..d3a5f71
--- /dev/null
+++ b/lib/codegen/src/CG_utils.cc
@@ -0,0 +1,1735 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 the Omega Project Team
+ Copyright (C) 2005-2011 Chun Chen
+ All Rights Reserved.
+
+ Purpose:
+   Utility functions for processing CG tree.
+
+ Notes:
+     
+ History:
+   07/19/07 when generating output variable substitutions for a mapping
+            relation, map it to each output to get correct equality, -chun
+   07/29/10 when translating equality to assignment, generate appropriate
+            if-condition when necesssary, -chun
+*****************************************************************************/
+
+#include <typeinfo>
+#include <omega.h>
+#include <code_gen/CG.h>
+#include <code_gen/CG_utils.h>
+#include <code_gen/codegen_error.h>
+#include <math.h>
+#include <stack>
+
+namespace omega {
+
+int checkLoopLevel;
+int stmtForLoopCheck;
+int upperBoundForLevel;
+int lowerBoundForLevel;
+bool fillInBounds;
+
+//trick to static init checkLoopLevel to 0
+class JunkStaticInit{ public: JunkStaticInit(){ checkLoopLevel=0; fillInBounds=false;} };
+static JunkStaticInit junkInitInstance__;
+
+
+
+
+namespace {
+
+Relation find_best_guard(const Relation &R, const BoolSet<> &active, const std::map<int, Relation> &guards) {
+  std::pair<int, int> best_cost = std::make_pair(0, 0);
+  Relation best_cond = Relation::True(R.n_set());
+  
+  Relation r = copy(R);
+  int max_iter_count = 2*(r.single_conjunct()->n_EQs()) + r.single_conjunct()->n_GEQs();
+  int iter_count = 0;
+  while (!r.is_obvious_tautology()) {
+    std::pair<int, int> cost = std::make_pair(0, 0);        
+    Relation cond = pick_one_guard(r);
+    Relation complement_cond = Complement(copy(cond));
+    complement_cond.simplify();    
+    for (BoolSet<>::const_iterator i = active.begin(); i != active.end(); i++) {
+      std::map<int, Relation>::const_iterator j = guards.find(*i);
+      if (j == guards.end())
+        continue;
+      if (Must_Be_Subset(copy(j->second), copy(cond)))
+        cost.first++;
+      else if (Must_Be_Subset(copy(j->second), copy(complement_cond)))
+        cost.second++;
+    }
+    if (cost > best_cost) {
+      best_cost = cost;
+      best_cond = copy(cond);
+    }
+    r = Gist(r, cond, 1);
+
+    if (iter_count > max_iter_count)
+      throw codegen_error("guard condition too complex to handle");
+
+    iter_count++;
+  }
+
+  return best_cond;
+}
+
+
+Relation find_best_guard(const Relation &R, const std::vector<CG_loop *> &loops, int start, int end) {
+  std::pair<int, int> best_cost = std::make_pair(0, 0);
+  Relation best_cond = Relation::True(R.n_set());
+  
+  Relation r = copy(R);
+  int max_iter_count = 2*(r.single_conjunct()->n_EQs()) + r.single_conjunct()->n_GEQs();
+  int iter_count = 0;
+  while (!r.is_obvious_tautology()) {
+    std::pair<int, int> cost = std::make_pair(0, 0);
+    Relation cond = pick_one_guard(r);
+    int i = start;
+    for ( ; i < end; i++) {
+      if (Must_Be_Subset(copy(loops[i]->guard_), copy(cond)))
+        cost.first++;
+      else
+        break;
+    }
+    Relation complement_cond = Complement(copy(cond));
+    complement_cond.simplify();
+    for (int j = i; j < end; j++)
+      if (Must_Be_Subset(copy(loops[j]->guard_), copy(complement_cond)))
+        cost.second++;
+      else
+        break;
+    
+    if (cost > best_cost) {
+      best_cost = cost;
+      best_cond = copy(cond);
+    }
+    r = Gist(r, cond, 1);
+
+    if (iter_count > max_iter_count)
+      throw codegen_error("guard condition too complex to handle");
+
+    iter_count++;
+  }
+
+  return best_cond;
+}
+
+}
+
+bool bound_must_hit_stride(const GEQ_Handle &inequality, Variable_ID v, const EQ_Handle &stride_eq, Variable_ID wc, const Relation &bounds, const Relation &known) {
+  assert(inequality.get_coef(v) != 0 && abs(stride_eq.get_coef(v)) == 1 && wc->kind() == Wildcard_Var && abs(stride_eq.get_coef(wc)) > 1);
+
+  // if bound expression uses floor operation, bail out for now
+  // TODO: in the future, handle this
+  if (abs(inequality.get_coef(v)) != 1)
+    return false;
+  
+  coef_t stride = abs(stride_eq.get_coef(wc));
+  
+  Relation r1(known.n_set());
+  F_Exists *f_exists1 = r1.add_and()->add_exists();
+  F_And *f_root1 = f_exists1->add_and();
+  std::map<Variable_ID, Variable_ID> exists_mapping1;
+  EQ_Handle h1 = f_root1->add_EQ();
+  Relation r2(known.n_set());
+  F_Exists *f_exists2 = r2.add_and()->add_exists();
+  F_And *f_root2 = f_exists2->add_and();
+  std::map<Variable_ID, Variable_ID> exists_mapping2;
+  EQ_Handle h2 = f_root2->add_EQ();
+  for (Constr_Vars_Iter cvi(inequality); cvi; cvi++) {
+    Variable_ID v = cvi.curr_var();
+    switch (v->kind()) {
+    case Input_Var: 
+      h1.update_coef(r1.input_var(v->get_position()), cvi.curr_coef());
+      h2.update_coef(r2.input_var(v->get_position()), cvi.curr_coef());
+      break;
+    case Global_Var: {      
+      Global_Var_ID g = v->get_global_var();
+      Variable_ID v1, v2;
+      if (g->arity() == 0) {
+        v1 = r1.get_local(g);
+        v2 = r2.get_local(g);
+      }
+      else {
+        v1 = r1.get_local(g, v->function_of());
+        v2 = r2.get_local(g, v->function_of());
+      }
+      h1.update_coef(v1, cvi.curr_coef());
+      h2.update_coef(v2, cvi.curr_coef());
+      break;
+    }
+    case Wildcard_Var: {
+      Variable_ID v1 = replicate_floor_definition(bounds, v, r1, f_exists1, f_root1, exists_mapping1);
+      Variable_ID v2 = replicate_floor_definition(bounds, v, r2, f_exists2, f_root2, exists_mapping2);
+      h1.update_coef(v1, cvi.curr_coef());
+      h2.update_coef(v2, cvi.curr_coef());
+      break;
+    }
+    default:
+      assert(false);
+    }
+  }
+  h1.update_const(inequality.get_const());
+  h1.update_coef(f_exists1->declare(), stride);
+  h2.update_const(inequality.get_const());
+  r1.simplify();
+  r2.simplify();
+
+  Relation all_known = Intersection(copy(bounds), copy(known));
+  all_known.simplify();
+
+  if (Gist(r1, copy(all_known), 1).is_obvious_tautology()) {
+    Relation r3(known.n_set());
+    F_Exists *f_exists3 = r3.add_and()->add_exists();
+    F_And *f_root3 = f_exists3->add_and();
+    std::map<Variable_ID, Variable_ID> exists_mapping3;
+    EQ_Handle h3 = f_root3->add_EQ();
+    for (Constr_Vars_Iter cvi(stride_eq); cvi; cvi++) {
+      Variable_ID v= cvi.curr_var();
+      switch (v->kind()) {
+      case Input_Var:
+        h3.update_coef(r3.input_var(v->get_position()), cvi.curr_coef());
+        break;
+      case Global_Var: {
+        Global_Var_ID g = v->get_global_var();
+        Variable_ID v3;
+        if (g->arity() == 0)
+          v3 = r3.get_local(g);
+        else
+          v3 = r3.get_local(g, v->function_of());
+        h3.update_coef(v3, cvi.curr_coef());
+        break;
+      }
+      case Wildcard_Var:
+        if (v == wc)
+          h3.update_coef(f_exists3->declare(), cvi.curr_coef());
+        else {
+          Variable_ID v3 = replicate_floor_definition(bounds, v, r3, f_exists3, f_root3, exists_mapping3);
+          h3.update_coef(v3, cvi.curr_coef());
+        }
+        break;
+      default:
+        assert(false);
+      }
+    }
+    h3.update_const(stride_eq.get_const());
+    r3.simplify();
+    
+    if (Gist(r3, Intersection(r2, all_known), 1).is_obvious_tautology())
+      return true;
+    else
+      return false;
+  }
+  else    
+    return false;
+}
+
+
+//
+// output variable by its name, however if this variable need to be substituted,
+// return the substitution.
+//
+CG_outputRepr *output_ident(CG_outputBuilder *ocg, const Relation &R, Variable_ID v, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) {
+  const_cast<Relation &>(R).setup_names(); // hack
+  
+  if (v->kind() == Input_Var) {
+    int pos = v->get_position();
+    if (assigned_on_the_fly[pos-1].first != NULL)
+      return assigned_on_the_fly[pos-1].first->clone();
+    else
+      return ocg->CreateIdent(v->name());
+  }
+  else if (v->kind() == Global_Var) {
+    if (v->get_global_var()->arity() == 0)
+      return ocg->CreateIdent(v->name());
+    else {
+      /* This should be improved to take into account the possible elimination
+         of the set variables. */
+      int arity = v->get_global_var()->arity();
+      std::vector<CG_outputRepr *> argList;
+      for(int i = 1; i <= arity; i++)
+        argList.push_back(ocg->CreateIdent(const_cast<Relation &>(R).input_var(i)->name()));
+      CG_outputRepr *call = ocg->CreateInvoke(v->get_global_var()->base_name(), argList);
+      return call;
+    }
+  }
+  else
+    assert(false);
+}
+
+
+//
+// return pair<if condition, <assignment rhs, assignment cost> >
+//
+std::pair<CG_outputRepr *, std::pair<CG_outputRepr *, int> > output_assignment(CG_outputBuilder *ocg, const Relation &R, int level, const Relation &known, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) {
+  Variable_ID v = const_cast<Relation &>(R).set_var(level);
+  Conjunct *c = const_cast<Relation &>(R).single_conjunct();
+
+  std::pair<EQ_Handle, int> result = find_simplest_assignment(R, v, assigned_on_the_fly);
+
+  if (result.second == INT_MAX)
+    return std::make_pair(static_cast<CG_outputRepr *>(NULL), std::make_pair(static_cast<CG_outputRepr *>(NULL), INT_MAX));
+  
+  CG_outputRepr *if_repr = NULL;
+  CG_outputRepr *assign_repr = NULL;
+  // check whether to generate if-conditions from equality constraints
+  if (abs(result.first.get_coef(v)) != 1) {
+    Relation r(R.n_set());
+    F_Exists *f_exists = r.add_and()->add_exists();
+    F_And *f_root = f_exists->add_and();
+    std::map<Variable_ID, Variable_ID> exists_mapping;
+    exists_mapping[v] = f_exists->declare();
+
+    EQ_Handle h = f_root->add_EQ();
+    for (Constr_Vars_Iter cvi(result.first); cvi; cvi++)
+      switch (cvi.curr_var()->kind()) {
+      case Input_Var: {
+        if (cvi.curr_var() == v)
+          h.update_coef(exists_mapping[v], cvi.curr_coef());
+        else
+          h.update_coef(r.set_var(cvi.curr_var()->get_position()), cvi.curr_coef());
+        break;
+      }
+      case Global_Var: {            
+        Global_Var_ID g = cvi.curr_var()->get_global_var();
+        Variable_ID v2;
+        if (g->arity() == 0)
+          v2 = r.get_local(g);
+        else
+          v2 = r.get_local(g, cvi.curr_var()->function_of());
+        h.update_coef(v2, cvi.curr_coef());
+        break;
+      }
+      case Wildcard_Var: {
+        std::map<Variable_ID, Variable_ID>::iterator p = exists_mapping.find(cvi.curr_var());
+        Variable_ID v2;
+        if (p == exists_mapping.end()) {
+          v2 = f_exists->declare();
+          exists_mapping[cvi.curr_var()] = v2;
+        }
+        else
+          v2 = p->second;
+        h.update_coef(v2, cvi.curr_coef());
+        break;
+      }
+      default:
+        assert(0);
+      }
+    h.update_const(result.first.get_const());
+      
+    for (EQ_Iterator e(c->EQs()); e; e++)
+      if (!((*e) == result.first)) {
+        EQ_Handle h = f_root->add_EQ();
+        for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
+          switch (cvi.curr_var()->kind()) {
+          case Input_Var: {
+            assert(cvi.curr_var() != v);
+            h.update_coef(r.set_var(cvi.curr_var()->get_position()), cvi.curr_coef());
+            break;
+          }
+          case Global_Var: {            
+            Global_Var_ID g = cvi.curr_var()->get_global_var();
+            Variable_ID v2;
+            if (g->arity() == 0)
+              v2 = r.get_local(g);
+            else
+              v2 = r.get_local(g, cvi.curr_var()->function_of());
+            h.update_coef(v2, cvi.curr_coef());
+            break;
+          }
+          case Wildcard_Var: {
+            std::map<Variable_ID, Variable_ID>::iterator p = exists_mapping.find(cvi.curr_var());
+            Variable_ID v2;
+            if (p == exists_mapping.end()) {
+              v2 = f_exists->declare();
+              exists_mapping[cvi.curr_var()] = v2;
+            }
+            else
+              v2 = p->second;
+            h.update_coef(v2, cvi.curr_coef());
+            break;
+          }
+          default:
+            assert(0);
+          }
+        h.update_const((*e).get_const());
+      }
+        
+    for (GEQ_Iterator e(c->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()), cvi.curr_coef());
+          break;
+        }
+        case Global_Var: {            
+          Global_Var_ID g = cvi.curr_var()->get_global_var();
+          Variable_ID v2;
+          if (g->arity() == 0)
+            v2 = r.get_local(g);
+          else
+            v2 = r.get_local(g, cvi.curr_var()->function_of());
+          h.update_coef(v2, cvi.curr_coef());
+          break;
+        }
+        case Wildcard_Var: {
+          std::map<Variable_ID, Variable_ID>::iterator p = exists_mapping.find(cvi.curr_var());
+          Variable_ID v2;
+          if (p == exists_mapping.end()) {
+            v2 = f_exists->declare();
+            exists_mapping[cvi.curr_var()] = v2;
+          }
+          else
+            v2 = p->second;
+          h.update_coef(v2, cvi.curr_coef());
+          break;
+        }
+        default:
+          assert(0);
+        }
+      h.update_const((*e).get_const());
+    }
+      
+    r.simplify();
+    if (!Gist(r, copy(known), 1).is_obvious_tautology()) {
+      CG_outputRepr *lhs = output_substitution_repr(ocg, result.first, v, false, R, assigned_on_the_fly);  
+      if_repr = ocg->CreateEQ(ocg->CreateIntegerMod(lhs->clone(), ocg->CreateInt(abs(result.first.get_coef(v)))), ocg->CreateInt(0));
+      assign_repr = ocg->CreateDivide(lhs, ocg->CreateInt(abs(result.first.get_coef(v))));
+    }
+    else
+      assign_repr = output_substitution_repr(ocg, result.first, v, true, R, assigned_on_the_fly);
+  }
+  else
+    assign_repr = output_substitution_repr(ocg, result.first, v, true, R, assigned_on_the_fly);
+
+  if (assign_repr == NULL)
+    assign_repr = ocg->CreateInt(0);
+  
+  return std::make_pair(if_repr, std::make_pair(assign_repr, result.second));
+}
+
+
+//
+// return NULL if 0
+//
+CG_outputRepr *output_substitution_repr(CG_outputBuilder *ocg, const EQ_Handle &equality, Variable_ID v, bool apply_v_coef, const Relation &R, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) {
+  const_cast<Relation &>(R).setup_names(); // hack
+  
+  coef_t a = equality.get_coef(v);
+  assert(a != 0);
+  
+  CG_outputRepr *repr = NULL;
+  for (Constr_Vars_Iter cvi(equality); cvi; cvi++)
+    if (cvi.curr_var() != v) {
+      CG_outputRepr *t;
+      if (cvi.curr_var()->kind() == Wildcard_Var) {
+        std::pair<bool, GEQ_Handle> result = find_floor_definition(R, cvi.curr_var());
+        if (!result.first) {
+          delete repr;
+          throw codegen_error("can't output non floor defined wildcard");
+        }
+        t = output_inequality_repr(ocg, result.second, cvi.curr_var(), R, assigned_on_the_fly);
+      }
+      else
+        t = output_ident(ocg, R, cvi.curr_var(), assigned_on_the_fly);
+      coef_t coef = cvi.curr_coef();
+
+      if (a > 0) {
+        if (coef > 0) {
+          if (coef == 1)
+            repr = ocg->CreateMinus(repr, t);
+          else
+            repr = ocg->CreateMinus(repr, ocg->CreateTimes(ocg->CreateInt(coef), t));
+        }
+        else { // coef < 0
+          if (coef == -1)
+            repr = ocg->CreatePlus(repr, t);
+          else
+            repr = ocg->CreatePlus(repr, ocg->CreateTimes(ocg->CreateInt(-coef), t));
+        }          
+      }
+      else {
+        if (coef > 0) {
+          if (coef == 1)
+            repr = ocg->CreatePlus(repr, t);
+          else
+            repr = ocg->CreatePlus(repr, ocg->CreateTimes(ocg->CreateInt(coef), t));
+        }
+        else { // coef < 0
+          if (coef == -1)
+            repr = ocg->CreateMinus(repr, t);
+          else
+            repr = ocg->CreateMinus(repr, ocg->CreateTimes(ocg->CreateInt(-coef), t));
+        }        
+      }
+    }
+  
+  int c = equality.get_const();
+  if (a > 0) {
+    if (c > 0)
+      repr = ocg->CreateMinus(repr, ocg->CreateInt(c));
+    else if (c < 0)
+      repr = ocg->CreatePlus(repr, ocg->CreateInt(-c));
+  }
+  else {
+    if (c > 0)
+      repr = ocg->CreatePlus(repr, ocg->CreateInt(c));
+    else if (c < 0)
+      repr = ocg->CreateMinus(repr, ocg->CreateInt(-c));
+  }
+    
+  if (apply_v_coef && abs(a) != 1)
+    repr = ocg->CreateDivide(repr, ocg->CreateInt(abs(a)));
+
+  return repr;
+}
+
+
+//
+// original Substitutions class from omega can't handle integer
+// division, this is new way.
+//
+std::vector<CG_outputRepr*> output_substitutions(CG_outputBuilder *ocg, const Relation &R, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) {
+  std::vector<CG_outputRepr *> subs;
+    
+  for (int i = 1; i <= R.n_out(); i++) {
+    Relation mapping(R.n_out(), 1);
+    F_And *f_root = mapping.add_and();
+    EQ_Handle h = f_root->add_EQ();
+    h.update_coef(mapping.output_var(1), 1);
+    h.update_coef(mapping.input_var(i), -1);
+    Relation r = Composition(mapping, copy(R));
+    r.simplify();
+
+    Variable_ID v = r.output_var(1);
+    CG_outputRepr *repr = NULL;
+    std::pair<EQ_Handle, int> result = find_simplest_assignment(r, v, assigned_on_the_fly);
+    if (result.second < INT_MAX)
+      repr = output_substitution_repr(ocg, result.first, v, true, r, assigned_on_the_fly);
+    else {
+      std::pair<bool, GEQ_Handle> result = find_floor_definition(R, v);
+      if (result.first)
+        try {
+          repr = output_inequality_repr(ocg, result.second, v, R, assigned_on_the_fly);
+        }
+        catch (const codegen_error &) {
+        }
+    }
+
+    subs.push_back(repr);
+  }
+
+  return subs;
+}
+    
+
+//
+// handle floor definition wildcards in equality, the second in returned pair
+// is the cost.
+//
+std::pair<EQ_Handle, int> find_simplest_assignment(const Relation &R, Variable_ID v, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) {
+  Conjunct *c = const_cast<Relation &>(R).single_conjunct();
+
+  int min_cost = INT_MAX;
+  EQ_Handle eq;
+  for (EQ_Iterator e(c->EQs()); e; e++)
+    if (!(*e).has_wildcards() && (*e).get_coef(v) != 0) {
+      int cost = 0;
+
+      if (abs((*e).get_coef(v)) != 1)
+        cost += 4;  // divide cost
+
+      int num_var = 0;
+      for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
+        if (cvi.curr_var() != v) {
+          num_var++;
+          if (abs(cvi.curr_coef()) != 1)
+            cost += 2;  // multiply cost
+          if (cvi.curr_var()->kind() == Global_Var && cvi.curr_var()->get_global_var()->arity() > 0)
+            cost += 10;  // function cost
+          else if (cvi.curr_var()->kind() == Input_Var &&
+                   assigned_on_the_fly.size() >= cvi.curr_var()->get_position() &&
+                   assigned_on_the_fly[cvi.curr_var()->get_position()-1].first != NULL)
+            cost += assigned_on_the_fly[cvi.curr_var()->get_position()-1].second;  // substitution cost on record
+        }
+      if ((*e).get_const() != 0)
+        num_var++;
+      if (num_var > 1)
+        cost += num_var - 1; // addition cost
+
+      if (cost < min_cost) {
+        min_cost = cost;
+        eq = *e;
+      }
+    }
+    
+  if (min_cost < INT_MAX)
+    return std::make_pair(eq, min_cost);
+
+  for (EQ_Iterator e(c->EQs()); e; e++)
+    if ((*e).has_wildcards() && (*e).get_coef(v) != 0) {
+      bool is_assignment = true;
+      for (Constr_Vars_Iter cvi(*e, true); cvi; cvi++) {
+        std::pair<bool, GEQ_Handle> result = find_floor_definition(R, v);
+        if (!result.first) {
+          is_assignment = false;
+          break;
+        }
+      }
+      if (!is_assignment)
+        continue;
+
+      int cost = 0;
+      
+      if (abs((*e).get_coef(v)) != 1)
+        cost += 4;  // divide cost
+
+      int num_var = 0;
+      for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
+        if (cvi.curr_var() != v) {
+          num_var++;
+          if (abs(cvi.curr_coef()) != 1)
+            cost += 2;  // multiply cost
+          if (cvi.curr_var()->kind() == Wildcard_Var)
+            cost += 10; // floor operation cost
+          else if (cvi.curr_var()->kind() == Global_Var && cvi.curr_var()->get_global_var()->arity() > 0)
+            cost += 20;  // function cost
+          else if (cvi.curr_var()->kind() == Input_Var &&
+                   assigned_on_the_fly.size() >= cvi.curr_var()->get_position() &&
+                   assigned_on_the_fly[cvi.curr_var()->get_position()-1].first != NULL)
+            cost += assigned_on_the_fly[cvi.curr_var()->get_position()-1].second;  // substitution cost on record
+        }
+      if ((*e).get_const() != 0)
+        num_var++;
+      if (num_var > 1)
+        cost += num_var - 1; // addition cost
+
+      if (cost < min_cost) {
+        min_cost = cost;
+        eq = *e;
+      }
+    }
+
+  return std::make_pair(eq, min_cost);
+}
+
+
+//
+// find floor definition for variable v, e.g. m-c <= 4v <= m, (c is
+// constant and 0 <= c < 4). this translates to v = floor(m, 4) and
+// return 4v<=m in this case. All wildcards in such inequality are
+// also floor defined.
+//
+std::pair<bool, GEQ_Handle> find_floor_definition(const Relation &R, Variable_ID v, std::set<Variable_ID> excluded_floor_vars) {
+  Conjunct *c = const_cast<Relation &>(R).single_conjunct();
+
+  excluded_floor_vars.insert(v);
+  for (GEQ_Iterator e = c->GEQs(); e; e++) {
+    coef_t a = (*e).get_coef(v);
+    if (a >= -1)
+      continue;
+    a = -a;
+    
+    bool interested = true;
+    for (std::set<Variable_ID>::const_iterator i = excluded_floor_vars.begin(); i != excluded_floor_vars.end(); i++)
+      if ((*i) != v && (*e).get_coef(*i) != 0) {
+        interested = false;
+        break;
+      }
+    if (!interested)
+      continue;
+
+    // check if any wildcard is floor defined
+    bool has_undefined_wc = false;
+    for (Constr_Vars_Iter cvi(*e, true); cvi; cvi++) 
+      if (excluded_floor_vars.find(cvi.curr_var()) == excluded_floor_vars.end()) {
+        std::pair<bool, GEQ_Handle> result = find_floor_definition(R, cvi.curr_var(), excluded_floor_vars);
+        if (!result.first) {
+          has_undefined_wc = true;
+          break;
+        }
+      }
+    if (has_undefined_wc)
+      continue;
+
+    // find the matching upper bound for floor definition
+    for (GEQ_Iterator e2 = c->GEQs(); e2; e2++)
+      if ((*e2).get_coef(v) == a && (*e).get_const() + (*e2).get_const() < a) {
+        bool match = true;
+        for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
+          if ((*e2).get_coef(cvi.curr_var()) != -cvi.curr_coef()) {
+            match = false;
+            break;
+          }
+        if (!match)
+          continue;
+        for (Constr_Vars_Iter cvi(*e2); cvi; cvi++)
+          if ((*e).get_coef(cvi.curr_var()) != -cvi.curr_coef()) {
+            match = false;
+            break;
+          }
+        if (match)
+          return std::make_pair(true, *e);
+      }
+  }
+
+  return std::make_pair(false, GEQ_Handle());
+}
+
+//
+// find the stride involving the specified variable, the stride
+// equality can have other wildcards as long as they are defined as
+// floor variables.
+//
+std::pair<EQ_Handle, Variable_ID> find_simplest_stride(const Relation &R, Variable_ID v) {
+  int best_num_var = INT_MAX;
+  coef_t best_coef;
+  EQ_Handle best_eq;
+  Variable_ID best_stride_wc;
+  for (EQ_Iterator e(const_cast<Relation &>(R).single_conjunct()->EQs()); e; e++)
+    if ((*e).has_wildcards() && (*e).get_coef(v) != 0) {
+      bool is_stride = true;
+      bool found_free = false;
+      int num_var = 0;
+      int num_floor = 0;
+      Variable_ID stride_wc;
+      for (Constr_Vars_Iter cvi(*e); cvi; cvi++) {
+        switch (cvi.curr_var()->kind()) {
+        case Wildcard_Var: {
+          bool is_free = true;
+          for (GEQ_Iterator e2(const_cast<Relation &>(R).single_conjunct()->GEQs()); e2; e2++)
+            if ((*e2).get_coef(cvi.curr_var()) != 0) {
+              is_free = false;
+              break;
+            }
+          if (is_free) {
+            if (found_free)
+              is_stride = false;
+            else {
+              found_free = true;
+              stride_wc = cvi.curr_var();
+            }
+          }
+          else {
+            std::pair<bool, GEQ_Handle> result = find_floor_definition(R, cvi.curr_var());
+            if (result.first)
+              num_floor++;
+            else 
+              is_stride = false;
+          }
+          break;
+        }
+        case Input_Var:
+          num_var++;
+          break;
+        default:
+          ;
+        }
+        
+        if (!is_stride)
+          break;
+      }
+
+      if (is_stride) {
+        coef_t coef = abs((*e).get_coef(v));
+        if (best_num_var == INT_MAX || coef < best_coef ||
+            (coef == best_coef && num_var < best_num_var)) {
+          best_coef = coef;
+          best_num_var = num_var;
+          best_eq = *e;
+          best_stride_wc = stride_wc;
+        }
+      }
+    }
+
+  if (best_num_var != INT_MAX)
+    return std::make_pair(best_eq, best_stride_wc);
+  else
+    return std::make_pair(EQ_Handle(), static_cast<Variable_ID>(NULL));
+}
+            
+//
+// convert relation to if-condition
+//
+CG_outputRepr *output_guard(CG_outputBuilder *ocg, const Relation &R, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) {
+  assert(R.n_out()==0);
+
+  CG_outputRepr *result = NULL;
+  Conjunct *c = const_cast<Relation &>(R).single_conjunct();
+
+  // e.g. 4i=5*j
+  for (EQ_Iterator e = c->EQs(); e; e++)
+    if (!(*e).has_wildcards()) {
+      CG_outputRepr *lhs = NULL;
+      CG_outputRepr *rhs = NULL;
+      for (Constr_Vars_Iter cvi(*e); cvi; cvi++) {
+        CG_outputRepr *v = output_ident(ocg, R, cvi.curr_var(), assigned_on_the_fly);
+        coef_t coef = cvi.curr_coef();
+        if (coef > 0) {
+          if (coef == 1)
+            lhs = ocg->CreatePlus(lhs, v);
+          else
+            lhs = ocg->CreatePlus(lhs, ocg->CreateTimes(ocg->CreateInt(coef), v));
+        }
+        else { // coef < 0
+          if (coef == -1)
+            rhs = ocg->CreatePlus(rhs, v);
+          else
+            rhs = ocg->CreatePlus(rhs, ocg->CreateTimes(ocg->CreateInt(-coef), v));
+        }
+      }
+      coef_t c = (*e).get_const();
+      
+      CG_outputRepr *term;
+      if (lhs == NULL) 
+        term = ocg->CreateEQ(rhs, ocg->CreateInt(c));
+      else {
+        if (c > 0)
+          rhs = ocg->CreateMinus(rhs, ocg->CreateInt(c));
+        else if (c < 0)
+          rhs = ocg->CreatePlus(rhs, ocg->CreateInt(-c));
+        else if (rhs == NULL)
+          rhs = ocg->CreateInt(0);
+        term = ocg->CreateEQ(lhs, rhs);
+      }
+      result = ocg->CreateAnd(result, term);
+    }
+
+  // e.g. i>5j
+  for (GEQ_Iterator e = c->GEQs(); e; e++)
+    if (!(*e).has_wildcards()) {
+      CG_outputRepr *lhs = NULL;
+      CG_outputRepr *rhs = NULL;
+      for (Constr_Vars_Iter cvi(*e); cvi; cvi++) {
+        CG_outputRepr *v = output_ident(ocg, R, cvi.curr_var(), assigned_on_the_fly);
+        coef_t coef = cvi.curr_coef();
+        if (coef > 0) {
+          if (coef == 1)
+            lhs = ocg->CreatePlus(lhs, v);
+          else
+            lhs = ocg->CreatePlus(lhs, ocg->CreateTimes(ocg->CreateInt(coef), v));
+        }
+        else { // coef < 0
+          if (coef == -1)
+            rhs = ocg->CreatePlus(rhs, v);
+          else
+            rhs = ocg->CreatePlus(rhs, ocg->CreateTimes(ocg->CreateInt(-coef), v));
+        }
+      }
+      coef_t c = (*e).get_const();
+
+      CG_outputRepr *term;
+      if (lhs == NULL)
+        term = ocg->CreateLE(rhs, ocg->CreateInt(c));
+      else {
+        if (c > 0)
+          rhs = ocg->CreateMinus(rhs, ocg->CreateInt(c));
+        else if (c < 0)
+          rhs = ocg->CreatePlus(rhs, ocg->CreateInt(-c));
+        else if (rhs == NULL)
+          rhs = ocg->CreateInt(0);
+        term = ocg->CreateGE(lhs, rhs);
+      }
+      result = ocg->CreateAnd(result, term);
+    }
+
+  // e.g. 4i=5j+4alpha
+  for (EQ_Iterator e = c->EQs(); e; e++)
+    if ((*e).has_wildcards()) {
+      Variable_ID wc;
+      int num_wildcard = 0;
+      int num_positive = 0;
+      int num_negative = 0;
+      for (Constr_Vars_Iter cvi(*e); cvi; cvi++) {
+        if (cvi.curr_var()->kind() == Wildcard_Var) {
+          num_wildcard++;
+          wc = cvi.curr_var();
+        }
+        else {
+          if (cvi.curr_coef() > 0)
+            num_positive++;
+          else
+            num_negative++;
+        }
+      }
+
+      if (num_wildcard > 1) {
+        delete result;
+        throw codegen_error("Can't generate equality condition with multiple wildcards");
+      }
+      int sign = (num_positive>=num_negative)?1:-1;
+      
+      CG_outputRepr *lhs = NULL;
+      for (Constr_Vars_Iter cvi(*e); cvi; cvi++) {
+        if (cvi.curr_var() != wc) {
+          CG_outputRepr *v = output_ident(ocg, R, cvi.curr_var(), assigned_on_the_fly);
+          coef_t coef = cvi.curr_coef();
+          if (sign == 1) {
+            if (coef > 0) {
+              if (coef == 1)
+                lhs = ocg->CreatePlus(lhs, v);
+              else
+                lhs = ocg->CreatePlus(lhs, ocg->CreateTimes(ocg->CreateInt(coef), v));
+            }
+            else { // coef < 0
+              if (coef == -1)
+                lhs = ocg->CreateMinus(lhs, v);
+              else
+                lhs = ocg->CreateMinus(lhs, ocg->CreateTimes(ocg->CreateInt(-coef), v));
+            }
+          }
+          else {
+            if (coef > 0) {
+              if (coef == 1)
+                lhs = ocg->CreateMinus(lhs, v);
+              else
+                lhs = ocg->CreateMinus(lhs, ocg->CreateTimes(ocg->CreateInt(coef), v));
+            }
+            else { // coef < 0
+              if (coef == -1)
+                lhs = ocg->CreatePlus(lhs, v);
+              else
+                lhs = ocg->CreatePlus(lhs, ocg->CreateTimes(ocg->CreateInt(-coef), v));
+            }
+          }            
+        }
+      }
+      coef_t c = (*e).get_const();
+      if (sign == 1) {
+        if (c > 0)
+          lhs = ocg->CreatePlus(lhs, ocg->CreateInt(c));
+        else if (c < 0)
+          lhs = ocg->CreateMinus(lhs, ocg->CreateInt(-c));
+      }
+      else {
+        if (c > 0)
+          lhs = ocg->CreateMinus(lhs, ocg->CreateInt(c));
+        else if (c < 0)
+          lhs = ocg->CreatePlus(lhs, ocg->CreateInt(-c));
+      }
+
+      lhs = ocg->CreateIntegerMod(lhs, ocg->CreateInt(abs((*e).get_coef(wc))));
+      CG_outputRepr *term = ocg->CreateEQ(lhs, ocg->CreateInt(0));
+      result = ocg->CreateAnd(result, term);
+    }
+
+  // e.g. 4alpha<=i<=5alpha
+  for (GEQ_Iterator e = c->GEQs(); e; e++)
+    if ((*e).has_wildcards()) {
+      Variable_ID wc;
+      int num_wildcard = 0;
+      for (Constr_Vars_Iter cvi(*e, true); cvi; cvi++)
+        if (num_wildcard == 0) {
+          wc = cvi.curr_var();
+          num_wildcard = 1;
+        }
+        else
+          num_wildcard++;
+
+      if (num_wildcard > 1) {
+        delete result;
+        // e.g.  c*alpha - x >= 0              (*)
+        //       -d*alpha + y >= 0             (*)
+        //       e1*alpha + f1*beta + g1 >= 0  (**)
+        //       e2*alpha + f2*beta + g2 >= 0  (**)
+        //       ...
+        // TODO: should generate a testing loop for alpha using its lower and
+        // upper bounds from (*) constraints and do the same if-condition test
+        // for beta from each pair of opposite (**) constraints as above,
+        // and exit the loop when if-condition satisfied.
+        throw codegen_error("Can't generate multiple wildcard GEQ guards right now");
+      }
+
+      coef_t c = (*e).get_coef(wc);
+      int sign = (c>0)?1:-1;
+      
+      GEQ_Iterator e2 = e;
+      e2++;
+      for ( ; e2; e2++) {
+        coef_t c2 = (*e2).get_coef(wc);
+        if (c2 == 0)
+          continue;
+        int sign2 = (c2>0)?1:-1;
+        if (sign != -sign2)
+          continue;
+        int num_wildcard2 = 0;
+        for (Constr_Vars_Iter cvi(*e2, true); cvi; cvi++)
+          num_wildcard2++;
+        if (num_wildcard2 > 1)
+          continue;
+
+        GEQ_Handle lb, ub;
+        if (sign == 1) {
+          lb = (*e);
+          ub = (*e2);
+        }
+        else {
+          lb = (*e2);
+          ub = (*e);
+        }
+
+        CG_outputRepr *lhs = NULL;
+        for (Constr_Vars_Iter cvi(lb); cvi; cvi++)
+          if (cvi.curr_var() != wc) {
+            CG_outputRepr *v = output_ident(ocg, R, cvi.curr_var(), assigned_on_the_fly);
+            coef_t coef = cvi.curr_coef();
+            if (coef > 0) {
+              if (coef == 1)
+                lhs = ocg->CreateMinus(lhs, v);
+              else
+                lhs = ocg->CreateMinus(lhs, ocg->CreateTimes(ocg->CreateInt(coef), v));
+            }
+            else { // coef < 0
+              if (coef == -1)
+                lhs = ocg->CreatePlus(lhs, v);
+              else
+                lhs = ocg->CreatePlus(lhs, ocg->CreateTimes(ocg->CreateInt(-coef), v));
+            }
+          }
+        coef_t c = lb.get_const();
+        if (c > 0)
+          lhs = ocg->CreateMinus(lhs, ocg->CreateInt(c));
+        else if (c < 0)
+          lhs = ocg->CreatePlus(lhs, ocg->CreateInt(-c));
+
+        CG_outputRepr *rhs = NULL;
+        for (Constr_Vars_Iter cvi(ub); cvi; cvi++)
+          if (cvi.curr_var() != wc) {
+            CG_outputRepr *v = output_ident(ocg, R, cvi.curr_var(), assigned_on_the_fly);
+            coef_t coef = cvi.curr_coef();
+            if (coef > 0) {
+              if (coef == 1)
+                rhs = ocg->CreatePlus(rhs, v);
+              else
+                rhs = ocg->CreatePlus(rhs, ocg->CreateTimes(ocg->CreateInt(coef), v));
+            }
+            else { // coef < 0
+              if (coef == -1)
+                rhs = ocg->CreateMinus(rhs, v);
+              else
+                rhs = ocg->CreateMinus(rhs, ocg->CreateTimes(ocg->CreateInt(-coef), v));
+            }
+          }
+        c = ub.get_const();
+        if (c > 0)
+          rhs = ocg->CreatePlus(rhs, ocg->CreateInt(c));
+        else if (c < 0)
+          rhs = ocg->CreateMinus(rhs, ocg->CreateInt(-c));
+
+        rhs = ocg->CreateIntegerFloor(rhs, ocg->CreateInt(-ub.get_coef(wc)));
+        rhs = ocg->CreateTimes(ocg->CreateInt(lb.get_coef(wc)), rhs);
+        CG_outputRepr *term = ocg->CreateLE(lhs, rhs);
+        result = ocg->CreateAnd(result, term);
+      }
+    }
+  
+  return result;
+}
+
+
+//
+// return NULL if 0
+//
+CG_outputRepr *output_inequality_repr(CG_outputBuilder *ocg, const GEQ_Handle &inequality, Variable_ID v, const Relation &R, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly, std::set<Variable_ID> excluded_floor_vars) {
+  const_cast<Relation &>(R).setup_names(); // hack
+  
+  coef_t a = inequality.get_coef(v);
+  assert(a != 0);
+  excluded_floor_vars.insert(v);
+  
+  CG_outputRepr *repr = NULL;
+  for (Constr_Vars_Iter cvi(inequality); cvi; cvi++)
+    if (cvi.curr_var() != v) {
+      CG_outputRepr *t;
+      if (cvi.curr_var()->kind() == Wildcard_Var) {
+        std::pair<bool, GEQ_Handle> result = find_floor_definition(R, cvi.curr_var(), excluded_floor_vars);
+        if (!result.first) {
+          delete repr;
+          throw codegen_error("Can't generate bound expression with wildcard not involved in floor definition");
+        }
+        try {
+          t = output_inequality_repr(ocg, result.second, cvi.curr_var(), R, assigned_on_the_fly, excluded_floor_vars);
+        }
+        catch (const std::exception &e) {
+          delete repr;
+          throw e;
+        }
+      }
+      else
+        t = output_ident(ocg, R, cvi.curr_var(), assigned_on_the_fly);
+
+      coef_t coef = cvi.curr_coef();
+      if (a > 0) {
+        if (coef > 0) {
+          if (coef == 1)
+            repr = ocg->CreateMinus(repr, t);
+          else
+            repr = ocg->CreateMinus(repr, ocg->CreateTimes(ocg->CreateInt(coef), t));
+        }
+        else {
+          if (coef == -1)
+            repr = ocg->CreatePlus(repr, t);
+          else
+            repr = ocg->CreatePlus(repr, ocg->CreateTimes(ocg->CreateInt(-coef), t));
+        }
+      }
+      else {
+        if (coef > 0) {
+          if (coef == 1)
+            repr = ocg->CreatePlus(repr, t);
+          else
+            repr = ocg->CreatePlus(repr, ocg->CreateTimes(ocg->CreateInt(coef), t));
+        }
+        else {
+          if (coef == -1)
+            repr = ocg->CreateMinus(repr, t);
+          else
+            repr = ocg->CreateMinus(repr, ocg->CreateTimes(ocg->CreateInt(-coef), t));
+        }
+      }
+    }
+  coef_t c = inequality.get_const();
+  if (c > 0) {
+    if (a > 0)
+      repr = ocg->CreateMinus(repr, ocg->CreateInt(c));
+    else 
+      repr = ocg->CreatePlus(repr, ocg->CreateInt(c));
+  }
+  else if (c < 0) {
+    if (a > 0)
+      repr = ocg->CreatePlus(repr, ocg->CreateInt(-c));
+    else
+      repr = ocg->CreateMinus(repr, ocg->CreateInt(-c));
+  }    
+
+  if (abs(a) == 1)
+    return repr;
+  else if (a > 0)
+    return ocg->CreateIntegerCeil(repr, ocg->CreateInt(a));
+  else // a < 0
+    return ocg->CreateIntegerFloor(repr, ocg->CreateInt(-a));  
+}
+
+
+//
+// nothing special, just an alias
+//
+CG_outputRepr *output_upper_bound_repr(CG_outputBuilder *ocg, const GEQ_Handle &inequality, Variable_ID v, const Relation &R, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) {
+  assert(inequality.get_coef(v) < 0);
+  CG_outputRepr* zero_;
+
+  zero_ =  output_inequality_repr(ocg, inequality, v, R, assigned_on_the_fly);
+
+  if(!zero_)
+         zero_ = ocg->CreateInt(0);
+
+  return zero_;
+
+}
+
+
+//
+// output lower bound with respect to lattice
+//
+CG_outputRepr *output_lower_bound_repr(CG_outputBuilder *ocg, const GEQ_Handle &inequality, Variable_ID v, const EQ_Handle &stride_eq, Variable_ID wc, const Relation &R, const Relation &known, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) {
+  assert(inequality.get_coef(v) > 0);
+  CG_outputRepr* zero_;
+  if (wc == NULL || bound_must_hit_stride(inequality, v, stride_eq, wc, R, known)){
+    zero_ =  output_inequality_repr(ocg, inequality, v, R, assigned_on_the_fly);
+    if(!zero_)
+       zero_ = ocg->CreateInt(0);
+
+    return zero_;
+  }
+  CG_outputRepr *strideBoundRepr = NULL;
+  int sign = (stride_eq.get_coef(v)>0)?1:-1;
+  for (Constr_Vars_Iter cvi(stride_eq); cvi; cvi++) {
+    Variable_ID v2 = cvi.curr_var();
+    if (v2 == v || v2 == wc)
+      continue;
+
+    CG_outputRepr *v_repr;
+    if (v2->kind() == Input_Var || v2->kind() == Global_Var)
+      v_repr = output_ident(ocg, R, v2, assigned_on_the_fly);
+    else if (v2->kind() == Wildcard_Var) {
+      std::pair<bool, GEQ_Handle> result = find_floor_definition(R, v2);
+      assert(result.first);
+      v_repr = output_inequality_repr(ocg, result.second, v2, R, assigned_on_the_fly);
+    }
+
+    coef_t coef = cvi.curr_coef();
+    if (sign < 0) {
+      if (coef > 0) {
+        if (coef == 1)
+          strideBoundRepr = ocg->CreatePlus(strideBoundRepr, v_repr);
+        else
+          strideBoundRepr = ocg->CreatePlus(strideBoundRepr, ocg->CreateTimes(ocg->CreateInt(coef), v_repr));
+      }
+      else { // coef < 0
+        if (coef == -1)
+          strideBoundRepr = ocg->CreateMinus(strideBoundRepr, v_repr);
+        else
+          strideBoundRepr = ocg->CreateMinus(strideBoundRepr, ocg->CreateTimes(ocg->CreateInt(-coef), v_repr));
+      }
+    }
+    else {
+      if (coef > 0) {
+        if (coef == 1)
+          strideBoundRepr = ocg->CreateMinus(strideBoundRepr, v_repr);
+        else
+          strideBoundRepr = ocg->CreateMinus(strideBoundRepr, ocg->CreateTimes(ocg->CreateInt(coef), v_repr));
+      }
+      else { // coef < 0
+        if (coef == -1)
+          strideBoundRepr = ocg->CreatePlus(strideBoundRepr, v_repr);
+        else
+          strideBoundRepr = ocg->CreatePlus(strideBoundRepr, ocg->CreateTimes(ocg->CreateInt(-coef), v_repr));
+      }
+    }
+  }  
+  coef_t c = stride_eq.get_const();
+  if (c > 0) {
+    if (sign < 0)
+      strideBoundRepr = ocg->CreatePlus(strideBoundRepr, ocg->CreateInt(c));
+    else
+      strideBoundRepr = ocg->CreateMinus(strideBoundRepr, ocg->CreateInt(c));
+  }
+  else if (c < 0) {
+    if (sign < 0)
+      strideBoundRepr = ocg->CreateMinus(strideBoundRepr, ocg->CreateInt(-c));
+    else
+      strideBoundRepr = ocg->CreatePlus(strideBoundRepr, ocg->CreateInt(-c));
+  }
+
+  CG_outputRepr *repr = output_inequality_repr(ocg, inequality, v, R, assigned_on_the_fly);
+  CG_outputRepr *repr2 = ocg->CreateCopy(repr);
+  repr = ocg->CreatePlus(repr2, ocg->CreateIntegerMod(ocg->CreateMinus(strideBoundRepr, repr), ocg->CreateInt(abs(stride_eq.get_coef(wc)))));
+
+  return repr;
+}
+  
+
+//
+// return loop control structure only
+//
+CG_outputRepr *output_loop(CG_outputBuilder *ocg, const Relation &R, int level, const Relation &known, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) {
+  std::pair<EQ_Handle, Variable_ID> result = find_simplest_stride(R, const_cast<Relation &>(R).set_var(level));
+  if (result.second != NULL)
+    assert(abs(result.first.get_coef(const_cast<Relation &>(R).set_var(level))) == 1);
+
+  std::vector<CG_outputRepr *> lbList, ubList;  
+  try {
+
+	coef_t const_lb = negInfinity, const_ub = posInfinity;
+
+    for (GEQ_Iterator e(const_cast<Relation &>(R).single_conjunct()->GEQs()); e; e++) {
+      coef_t coef = (*e).get_coef(const_cast<Relation &>(R).set_var(level));
+
+      if (coef > 0) {
+        CG_outputRepr *repr = output_lower_bound_repr(ocg, *e, const_cast<Relation &>(R).set_var(level), result.first, result.second, R, known, assigned_on_the_fly);
+          if (repr == NULL)
+           repr = ocg->CreateInt(0);
+        lbList.push_back(repr);
+
+        if ((*e).is_const(const_cast<Relation &>(R).set_var(level))){
+        	if(!result.second) {
+
+                //no variables but v in constr
+                coef_t L,m;
+                L = -((*e).get_const());
+
+                m = (*e).get_coef(const_cast<Relation &>(R).set_var(level));
+                coef_t sb  =  (int) (ceil(((float) L) /m));
+                set_max(const_lb, sb);
+            }
+        	else{
+
+        		coef_t L,m,s,c;
+        		        L = -((*e).get_const());
+        		        m = (*e).get_coef(const_cast<Relation &>(R).set_var(level));
+        		        s = abs(result.first.get_coef(result.second));
+        		        c = result.first.get_const();
+        		        coef_t sb  =  (s * (int) (ceil( (float) (L - (c * m)) /(s*m))))+ c;
+        		        set_max(const_lb, sb);
+
+        	}
+        }
+
+      }
+      else if (coef < 0) {
+        CG_outputRepr *repr = output_upper_bound_repr(ocg, *e, const_cast<Relation &>(R).set_var(level), R, assigned_on_the_fly);
+        if (repr == NULL)
+          repr = ocg->CreateInt(0);
+        ubList.push_back(repr);
+
+        if ((*e).is_const(const_cast<Relation &>(R).set_var(level))) {
+                // no variables but v in constraint
+                set_min(const_ub,-(*e).get_const()/(*e).get_coef(const_cast<Relation &>(R).set_var(level)));
+        }
+
+      }
+    }
+    
+    if(fillInBounds && lbList.size() == 1 && const_lb != negInfinity)
+       lowerBoundForLevel = const_lb;
+
+    if(fillInBounds && const_ub != posInfinity)
+       upperBoundForLevel = const_ub;
+    if (lbList.size() == 0)
+      throw codegen_error("missing lower bound at loop level " + to_string(level));
+    if (ubList.size() == 0)
+      throw codegen_error("missing upper bound at loop level " + to_string(level));
+  }
+  catch (const std::exception &e) {
+    for (int i = 0; i < lbList.size(); i++)
+      delete lbList[i];
+    for (int i = 0; i < ubList.size(); i++)
+      delete ubList[i];
+    throw e;
+  }
+
+  CG_outputRepr *lbRepr = NULL;
+  if (lbList.size() > 1)
+    lbRepr = ocg->CreateInvoke("max", lbList);
+  else // (lbList.size() == 1)
+    lbRepr = lbList[0];
+
+  CG_outputRepr *ubRepr = NULL;
+  if (ubList.size() > 1)
+    ubRepr = ocg->CreateInvoke("min", ubList);
+  else // (ubList.size() == 1)
+    ubRepr = ubList[0];
+
+  CG_outputRepr *stRepr;
+  if (result.second == NULL)
+    stRepr = ocg->CreateInt(1);
+  else
+    stRepr = ocg->CreateInt(abs(result.first.get_coef(result.second)));
+  CG_outputRepr *indexRepr = output_ident(ocg, R, const_cast<Relation &>(R).set_var(level), assigned_on_the_fly);
+  return ocg->CreateInductive(indexRepr, lbRepr, ubRepr, stRepr);
+}
+
+
+//
+// parameter f_root is inside f_exists, not the other way around.
+// return replicated variable in new relation, with all cascaded floor definitions
+// using wildcards defined in the same way as in the original relation.
+//
+Variable_ID replicate_floor_definition(const Relation &R, const Variable_ID floor_var,
+                                       Relation &r, F_Exists *f_exists, F_And *f_root,
+                                       std::map<Variable_ID, Variable_ID> &exists_mapping) {
+  assert(R.n_out() == 0 && r.n_out() == 0 && R.n_inp() == r.n_inp());
+
+  std::set<Variable_ID> excluded_floor_vars;
+  std::stack<Variable_ID> to_fill;
+  to_fill.push(floor_var);
+
+  while (!to_fill.empty()) {
+    Variable_ID v = to_fill.top();
+    to_fill.pop();
+    if (excluded_floor_vars.find(v) != excluded_floor_vars.end())
+      continue;
+    
+    std::pair<bool, GEQ_Handle> result = find_floor_definition(R, v, excluded_floor_vars);
+    assert(result.first);
+    excluded_floor_vars.insert(v);
+      
+    GEQ_Handle h1 = f_root->add_GEQ();
+    GEQ_Handle h2 = f_root->add_GEQ();
+    for (Constr_Vars_Iter cvi(result.second); cvi; cvi++) {
+      Variable_ID v2 = cvi.curr_var();
+      switch  (v2->kind()) {
+      case Input_Var: {
+        int pos = v2->get_position();
+        h1.update_coef(r.input_var(pos), cvi.curr_coef());
+        h2.update_coef(r.input_var(pos), -cvi.curr_coef());
+        break;
+      }
+      case Wildcard_Var: {
+        std::map<Variable_ID, Variable_ID>::iterator p = exists_mapping.find(v2);
+        Variable_ID v3;
+        if (p == exists_mapping.end()) {
+          v3 = f_exists->declare();
+          exists_mapping[v2] = v3;
+        }
+        else
+          v3 = p->second;
+        h1.update_coef(v3, cvi.curr_coef());
+        h2.update_coef(v3, -cvi.curr_coef());
+        if (v2 != v)
+          to_fill.push(v2);
+        break;
+      }
+      case Global_Var: {
+        Global_Var_ID g = v2->get_global_var();
+        Variable_ID v3;
+        if (g->arity() == 0)
+          v3 = r.get_local(g);
+        else
+          v3 = r.get_local(g, v2->function_of());
+        h1.update_coef(v3, cvi.curr_coef());
+        h2.update_coef(v3, -cvi.curr_coef());
+        break;
+      }
+      default:
+        assert(false);
+      }
+    }
+    h1.update_const(result.second.get_const());
+    h2.update_const(-result.second.get_const()-result.second.get_coef(v)-1);
+  }
+
+  if (floor_var->kind() == Input_Var)
+    return r.input_var(floor_var->get_position());
+  else if (floor_var->kind() == Wildcard_Var)
+    return exists_mapping[floor_var];
+  else
+    assert(false);
+}
+
+
+//
+// pick one guard condition from relation. it can involve multiple
+// constraints when involving wildcards, as long as its complement
+// is a single conjunct.
+//
+Relation pick_one_guard(const Relation &R, int level) {
+  assert(R.n_out()==0);
+  
+  Relation r = Relation::True(R.n_set());
+  
+  for (GEQ_Iterator e(const_cast<Relation &>(R).single_conjunct()->GEQs()); e; e++)
+    if (!(*e).has_wildcards()) {
+      r.and_with_GEQ(*e);
+      r.simplify();
+      r.copy_names(R);
+      r.setup_names();
+      return r;
+    }
+  
+  for (EQ_Iterator e(const_cast<Relation &>(R).single_conjunct()->EQs()); e; e++)
+    if (!(*e).has_wildcards()) {
+      r.and_with_GEQ(*e);
+      r.simplify();
+      r.copy_names(R);
+      r.setup_names();
+      return r;
+    }
+  
+  for (EQ_Iterator e(const_cast<Relation &>(R).single_conjunct()->EQs()); e; e++)
+    if ((*e).has_wildcards()) {
+      int num_wildcard = 0;
+      int max_level = 0;
+      for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
+        switch (cvi.curr_var()->kind()) {
+        case Wildcard_Var:
+          num_wildcard++;
+          break;
+        case Input_Var:
+          if (cvi.curr_var()->get_position() > max_level)
+            max_level = cvi.curr_var()->get_position();
+          break;
+        default:
+          ;
+        }
+          
+      if (num_wildcard == 1 && max_level != level-1) {
+        r.and_with_EQ(*e);
+        r.simplify();
+        r.copy_names(R);
+        r.setup_names();
+        return r;
+      }
+    }
+
+  for (GEQ_Iterator e(const_cast<Relation &>(R).single_conjunct()->GEQs()); e; e++)
+    if ((*e).has_wildcards()) {
+      int num_wildcard = 0;
+      int max_level = 0;
+      bool direction;
+      Variable_ID wc;
+      for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
+        switch (cvi.curr_var()->kind()) {
+        case Wildcard_Var:
+          num_wildcard++;
+          wc = cvi.curr_var();
+          direction = cvi.curr_coef()>0?true:false;
+          break;
+        case Input_Var:
+          if (cvi.curr_var()->get_position() > max_level)
+            max_level = cvi.curr_var()->get_position();
+          break;
+        default:
+          ;
+        }
+          
+      if (num_wildcard == 1 && max_level != level-1) {
+        // find the pairing inequality
+        GEQ_Iterator e2 = e;
+        e2++;
+        for ( ; e2; e2++) {
+          int num_wildcard2 = 0;
+          int max_level2 = 0;
+          bool direction2;
+          Variable_ID wc2;
+          for (Constr_Vars_Iter cvi(*e2); cvi; cvi++)
+            switch (cvi.curr_var()->kind()) {
+            case Wildcard_Var:
+              num_wildcard2++;
+              wc2 = cvi.curr_var();
+              direction2 = cvi.curr_coef()>0?true:false;
+              break;
+            case Input_Var:
+              if (cvi.curr_var()->get_position() > max_level2)
+                max_level2 = cvi.curr_var()->get_position();
+              break;
+            default:
+              ;
+            }
+
+          if (num_wildcard2 == 1 && max_level2 != level-1 && wc2 == wc && direction2 == not direction) {
+            F_Exists *f_exists = r.and_with_and()->add_exists();
+            Variable_ID wc3 = f_exists->declare();
+            F_And *f_root = f_exists->add_and();
+            GEQ_Handle h = f_root->add_GEQ();
+            for (Constr_Vars_Iter cvi(*e); cvi; cvi++) {
+              switch (cvi.curr_var()->kind()) {
+              case Wildcard_Var:
+                h.update_coef(wc3, cvi.curr_coef());
+                break;
+              case Input_Var:
+                h.update_coef(r.input_var(cvi.curr_var()->get_position()), 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());
+            
+            h = f_root->add_GEQ();
+            for (Constr_Vars_Iter cvi(*e2); cvi; cvi++) {
+              switch (cvi.curr_var()->kind()) {
+              case Wildcard_Var:
+                h.update_coef(wc3, cvi.curr_coef());
+                break;
+              case Input_Var:
+                h.update_coef(r.input_var(cvi.curr_var()->get_position()), 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((*e2).get_const());
+
+            r.simplify();
+            r.copy_names(R);
+            r.setup_names();
+            return r;
+          }
+        }
+      }
+    }
+}
+
+
+//
+// heavy lifting for code output for one leaf node
+//
+CG_outputRepr *leaf_print_repr(BoolSet<> active, const std::map<int, Relation> &guards, 
+                               CG_outputRepr *guard_repr, const Relation &known,
+                               int indent, CG_outputBuilder *ocg, const std::vector<int> &remap,
+                               const std::vector<Relation> &xforms, const std::vector<CG_outputRepr *> &stmts,
+                               const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) {
+  if (active.num_elem() == 0)
+    return NULL;
+  
+  CG_outputRepr *stmt_list = NULL;
+  for (BoolSet<>::iterator i = active.begin(); i != active.end(); i++) {
+    std::map<int, Relation>::const_iterator j = guards.find(*i);
+    if (j == guards.end() || Must_Be_Subset(copy(known), copy(j->second))) {
+      Relation mapping = Inverse(copy((xforms[remap[*i]])));
+      mapping.simplify();
+      mapping.setup_names();
+      std::vector<std::string> loop_vars;
+      for (int k = 1; k <= mapping.n_out(); k++) {
+        loop_vars.push_back(mapping.output_var(k)->name());
+//        std::cout << "CG_Utils:: " << k << ", " << mapping.output_var(k)->name().c_str() << "\n";
+      }
+      std::vector<CG_outputRepr *> sList = output_substitutions(ocg, mapping, assigned_on_the_fly);
+      stmt_list = ocg->StmtListAppend(stmt_list, ocg->CreateSubstitutedStmt((guard_repr==NULL)?indent:indent+1, stmts[remap[*i]]->clone(), loop_vars, sList));
+      active.unset(*i);
+    }
+  }
+
+  if (stmt_list != NULL) {
+    if (active.num_elem() != 0)
+      stmt_list = ocg->StmtListAppend(stmt_list, leaf_print_repr(active, guards, NULL, known, (guard_repr==NULL)?indent:indent+1, ocg, remap, xforms, stmts, assigned_on_the_fly));
+    if (guard_repr == NULL)
+      return stmt_list;
+    else
+      return ocg->CreateIf(indent, guard_repr, stmt_list, NULL);
+  }
+  else {
+    Relation then_cond = find_best_guard(const_cast<std::map<int, Relation> &>(guards)[*(active.begin())], active, guards);
+    assert(!then_cond.is_obvious_tautology());
+    Relation new_then_known = Intersection(copy(known), copy(then_cond));
+    new_then_known.simplify();
+    Relation else_cond = Complement(copy(then_cond));
+    else_cond.simplify();
+    Relation new_else_known = Intersection(copy(known), copy(else_cond));
+    new_else_known.simplify();
+    
+    BoolSet<> then_active(active.size()), else_active(active.size()), indep_active(active.size());
+    std::map<int, Relation> then_guards, else_guards;
+    for (BoolSet<>::iterator i = active.begin(); i != active.end(); i++) {
+      Relation &r = const_cast<std::map<int, Relation> &>(guards)[*i];
+      if (Must_Be_Subset(copy(r), copy(then_cond))) {
+        Relation r2 = Gist(copy(r), copy(then_cond), 1);
+        if (!r2.is_obvious_tautology())
+          then_guards[*i] = r2;
+        then_active.set(*i);
+      }
+      else if (Must_Be_Subset(copy(r), copy(else_cond))) {
+        Relation r2 = Gist(copy(r), copy(else_cond), 1);
+        if (!r2.is_obvious_tautology())
+          else_guards[*i] = r2;
+        else_active.set(*i);
+      }
+      else
+        indep_active.set(*i);
+    }
+    assert(!then_active.empty());
+    
+    CG_outputRepr *new_guard_repr = output_guard(ocg, then_cond, assigned_on_the_fly);
+    if (else_active.empty() && indep_active.empty()) {      
+      guard_repr = ocg->CreateAnd(guard_repr, new_guard_repr);
+      return leaf_print_repr(then_active, then_guards, guard_repr, new_then_known, indent, ocg, remap, xforms, stmts, assigned_on_the_fly);
+    }
+    else if (else_active.empty() && !indep_active.empty()) {
+      int new_indent = (guard_repr==NULL)?indent:indent+1;
+      stmt_list = leaf_print_repr(then_active, then_guards, new_guard_repr, new_then_known, new_indent, ocg, remap, xforms, stmts, assigned_on_the_fly);
+      stmt_list = ocg->StmtListAppend(stmt_list, leaf_print_repr(indep_active, guards, NULL, known, new_indent, ocg, remap, xforms, stmts, assigned_on_the_fly));
+      if (guard_repr == NULL)
+        return stmt_list;
+      else
+        return ocg->CreateIf(indent, guard_repr, stmt_list, NULL);
+    }
+    else { // (!else_active.empty())
+      int new_indent = (guard_repr==NULL)?indent:indent+1;
+      CG_outputRepr *then_stmt_list = leaf_print_repr(then_active, then_guards, NULL, new_then_known, new_indent+1, ocg, remap, xforms, stmts, assigned_on_the_fly);
+      CG_outputRepr *else_stmt_list = leaf_print_repr(else_active, else_guards, NULL, new_else_known, new_indent+1, ocg, remap, xforms, stmts, assigned_on_the_fly);
+      stmt_list = ocg->CreateIf(new_indent, new_guard_repr, then_stmt_list, else_stmt_list);
+      if (!indep_active.empty())
+        stmt_list = ocg->StmtListAppend(stmt_list, leaf_print_repr(indep_active, guards, NULL, known, new_indent, ocg, remap, xforms, stmts, assigned_on_the_fly));
+      if (guard_repr == NULL)
+        return stmt_list;
+      else
+        return ocg->CreateIf(indent, guard_repr, stmt_list, NULL);
+    }
+  }
+}
+
+
+//
+// heavy lifting for code output for one level of loop nodes
+//
+CG_outputRepr *loop_print_repr(const std::vector<CG_loop *> &loops, int start, int end,
+                               const Relation &guard, CG_outputRepr *guard_repr,
+                               int indent, CG_outputBuilder *ocg, const std::vector<CG_outputRepr *> &stmts,
+                               const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) {
+  if (start >= end)
+    return NULL;
+
+  Relation R = Gist(copy(loops[start]->guard_), copy(guard), 1);
+  if (Must_Be_Subset(Intersection(copy(loops[start]->known_), copy(guard)), copy(R))) {
+    int new_indent = (guard_repr==NULL)?indent:indent+1;
+    int i = start+1;
+    for ( ; i < end; i++)
+      if (!Gist(copy(loops[i]->guard_), copy(guard), 1).is_obvious_tautology())
+        break;
+    CG_outputRepr *stmt_list = NULL;
+    for (int j = start; j < i; j++)
+      stmt_list = ocg->StmtListAppend(stmt_list, loops[j]->printRepr(false, new_indent, ocg, stmts, assigned_on_the_fly));
+    stmt_list = ocg->StmtListAppend(stmt_list, loop_print_repr(loops, i, end, guard, NULL, new_indent, ocg, stmts, assigned_on_the_fly));
+    if (guard_repr == NULL)
+      return stmt_list;
+    else
+      return ocg->CreateIf(indent, guard_repr, stmt_list, NULL);
+  }
+
+  Relation then_cond = find_best_guard(R, loops, start, end);
+  assert(!then_cond.is_obvious_tautology());
+  Relation else_cond = Complement(copy(then_cond));
+  else_cond.simplify();
+  
+  std::vector<CG_loop *> then_loops, else_loops, indep_loops;
+  int i = start;
+  for ( ; i < end; i++)
+    if (!Must_Be_Subset(copy(loops[i]->guard_), copy(then_cond)))
+      break;
+  int j = i;
+  for ( ; j < end; j++)
+    if (!Must_Be_Subset(copy(loops[j]->guard_), copy(else_cond)))
+      break;
+  assert(i>start);
+
+  CG_outputRepr *new_guard_repr = output_guard(ocg, then_cond, assigned_on_the_fly);
+  if (j == i && end == j) {
+    guard_repr = ocg->CreateAnd(guard_repr, new_guard_repr);
+    Relation new_guard = Intersection(copy(guard), copy(then_cond));
+    new_guard.simplify();
+    return loop_print_repr(loops, start, end, new_guard, guard_repr, indent, ocg, stmts, assigned_on_the_fly);
+  }
+  else if (j == i && end > j) {
+    int new_indent = (guard_repr==NULL)?indent:indent+1;
+    Relation new_guard = Intersection(copy(guard), copy(then_cond));
+    new_guard.simplify();
+    CG_outputRepr *stmt_list = loop_print_repr(loops, start, i, new_guard, new_guard_repr, new_indent, ocg, stmts, assigned_on_the_fly);
+    stmt_list = ocg->StmtListAppend(stmt_list, loop_print_repr(loops, j, end, guard, NULL, new_indent, ocg, stmts, assigned_on_the_fly));
+    if (guard_repr == NULL)
+      return stmt_list;
+    else
+      return ocg->CreateIf(indent, guard_repr, stmt_list, NULL);
+  }
+  else { // (j > i)
+    int new_indent = (guard_repr==NULL)?indent:indent+1;
+    Relation then_new_guard = Intersection(copy(guard), copy(then_cond));
+    then_new_guard.simplify();
+    CG_outputRepr *then_stmt_list = loop_print_repr(loops, start, i, then_new_guard, NULL, new_indent+1, ocg, stmts, assigned_on_the_fly);
+    Relation else_new_guard = Intersection(copy(guard), copy(else_cond));
+    else_new_guard.simplify();
+    CG_outputRepr *else_stmt_list = loop_print_repr(loops, i, j, else_new_guard, NULL, new_indent+1, ocg, stmts, assigned_on_the_fly);
+    CG_outputRepr *stmt_list = ocg->CreateIf(new_indent, new_guard_repr, then_stmt_list, else_stmt_list);
+    stmt_list = ocg->StmtListAppend(stmt_list, loop_print_repr(loops, j, end, guard, NULL, new_indent, ocg, stmts, assigned_on_the_fly));
+    if (guard_repr == NULL)
+      return stmt_list;
+    else
+      return ocg->CreateIf(indent, guard_repr, stmt_list, NULL);
+  }
+}
+
+}
diff --git a/lib/codegen/src/codegen.cc b/lib/codegen/src/codegen.cc
new file mode 100755
index 0000000..92ca702
--- /dev/null
+++ b/lib/codegen/src/codegen.cc
@@ -0,0 +1,378 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 the Omega Project Team
+ Copyright (C) 2005-2011 Chun Chen
+ All Rights Reserved.
+
+ Purpose:
+   CodeGen class as entry point for code generation.
+
+ Notes:
+   Loop variable name prefix should not cause any possible name conflicts
+ with original loop variables wrapped in statement holder. This guarantees
+ that variable substitution done correctly in the generated code.
+
+ History:
+   04/24/96 MMGenerateCode, added by Fortran D people. Lei Zhou
+   09/17/08 loop overhead removal based on actual nesting depth -- by chun
+   03/05/11 fold MMGenerateCode into CodeGen class, Chun Chen
+*****************************************************************************/
+
+#include <typeinfo>
+#include <omega.h>
+#include <basic/util.h>
+#include <math.h>
+#include <vector>
+#include <algorithm>
+
+#include <code_gen/CG.h>
+#include <code_gen/codegen.h>
+#include <code_gen/CG_outputBuilder.h>
+#include <code_gen/codegen_error.h>
+
+namespace omega {
+
+const std::string CodeGen::loop_var_name_prefix = "t";
+const int CodeGen::var_substitution_threshold = 10;
+
+//Anand--adding stuff to make Chun's code work with Gabe's
+std::vector< std::vector<int> > smtNonSplitLevels;
+std::vector< std::vector<std::string> > loopIdxNames;//per stmt
+std::vector< std::pair<int, std::string> > syncs;
+
+
+
+CodeGen::CodeGen(const std::vector<Relation> &xforms, const std::vector<Relation> &IS, const Relation &known, std::vector< std::vector<int> > smtNonSplitLevels_ , std::vector< std::vector<std::string> > loopIdxNames_,  std::vector< std::pair<int, std::string> > syncs_) {
+  // check for sanity of parameters
+  int num_stmt = IS.size();
+  if (xforms.size() != num_stmt)
+    throw std::invalid_argument("number of iteration spaces does not match number of transformations");
+  known_ = copy(known);
+  if (known_.n_out() != 0)
+    throw std::invalid_argument("known condition must be a set relation");
+  if (known_.is_null())
+    known_ = Relation::True(0);
+  else
+    known_.simplify(2, 4);
+  if (!known_.is_upper_bound_satisfiable())
+    return;
+  if (known_.number_of_conjuncts() > 1)
+    throw std::invalid_argument("only one conjunct allowed in known condition");
+  xforms_ = xforms;
+  for (int i = 0; i < num_stmt; i++) {
+    xforms_[i].simplify();
+    if (!xforms_[i].has_single_conjunct())
+      throw std::invalid_argument("mapping relation must have only one conjunct");
+    if (xforms_[i].n_inp() != IS[i].n_inp() || IS[i].n_out() != 0)
+      throw std::invalid_argument("illegal iteration space or transformation arity");
+  }
+
+
+  //protonu--
+  //easier to handle this as a global
+  smtNonSplitLevels = smtNonSplitLevels_;
+  syncs = syncs_;
+  loopIdxNames = loopIdxNames_;
+  //end-protonu
+
+
+
+  // find the maximum iteration space dimension we are going to operate on
+  int num_level = known_.n_inp();
+  for (int i = 0; i < num_stmt; i++)
+    if (xforms_[i].n_out() > num_level)
+      num_level = xforms_[i].n_out();
+  known_ = Extend_Set(known_, num_level-known_.n_inp());
+  for (int i = 1; i <= num_level; i++)
+    known_.name_set_var(i, loop_var_name_prefix + to_string(i));
+  known_.setup_names();
+
+  // split disjoint conjunctions in original iteration spaces
+  std::vector<Relation> new_IS;
+  for (int i = 0; i < num_stmt; i++) {
+    for (int j = 1; j <= IS[i].n_inp(); j++)
+      xforms_[i].name_input_var(j, const_cast<std::vector<Relation> &>(IS)[i].input_var(j)->name());
+    for (int j = 1; j <= xforms_[i].n_out(); j++)
+      xforms_[i].name_output_var(j, loop_var_name_prefix + to_string(j));
+    xforms_[i].setup_names();
+
+    Relation R = Range(Restrict_Domain(copy(xforms_[i]), copy(IS[i])));
+    R = Intersection(Extend_Set(R, num_level-R.n_inp()), copy(known_));
+    R.simplify(2, 4);
+    if (R.is_inexact())
+      throw codegen_error("cannot generate code for inexact iteration spaces");
+
+    while(R.is_upper_bound_satisfiable()) {
+      DNF *dnf = R.query_DNF();
+      DNF_Iterator c(dnf);
+      Relation R2 = Relation(R, *c);
+      R2.simplify();
+      new_IS.push_back(copy(R2));
+      remap_.push_back(i);
+      c.next();
+      if (!c.live()) 
+        break;
+      Relation remainder(R, *c);
+      c.next();
+      while (c.live()) {
+        remainder = Union(remainder, Relation(R, *c));
+        c.next();
+      }
+      R = Difference(remainder, R2);
+      R.simplify(2, 4);
+    }
+  }
+
+  // number of new statements after splitting
+  num_stmt = new_IS.size();
+  if(!smtNonSplitLevels.empty())
+      smtNonSplitLevels.resize(num_stmt);
+  // assign a dummy value to loops created for the purpose of expanding to maximum dimension
+  for (int i = 0; i < num_stmt; i++) {
+    if (xforms[remap_[i]].n_out() < num_level) {
+      F_And *f_root = new_IS[i].and_with_and();
+      for (int j = xforms[remap_[i]].n_out()+1; j <= num_level; j++) {
+        EQ_Handle h = f_root->add_EQ();
+        h.update_coef(new_IS[i].set_var(j), 1);
+        h.update_const(posInfinity);
+      }
+      new_IS[i].simplify();
+    }   
+  }
+
+  // calculate projected subspaces for each loop level once and save for CG tree manipulation later
+  projected_IS_ = std::vector<std::vector<Relation> >(num_level);
+  for (int i = 0; i < num_level; i++)
+    projected_IS_[i] = std::vector<Relation>(num_stmt);
+  for (int i = 0; i < num_stmt; i++) {
+    if (num_level > 0)
+      projected_IS_[num_level-1][i] = new_IS[i];
+    for (int j = num_level-1; j >= 1; j--) {
+      projected_IS_[j-1][i] = Project(copy(projected_IS_[j][i]), j+1, Set_Var);
+      projected_IS_[j-1][i].simplify(2, 4);
+    }
+  }
+}
+
+
+CG_result *CodeGen::buildAST(int level, const BoolSet<> &active, bool split_on_const, const Relation &restriction) {
+  if (level > num_level())
+    return new CG_leaf(this, active);
+
+  int num_active_stmt = active.num_elem();
+  if (num_active_stmt == 0)
+    return NULL;
+  else if (num_active_stmt == 1)
+    return new CG_loop(this, active, level, buildAST(level+1, active, true, restriction));
+
+  // use estimated constant bounds for fast non-overlap iteration space splitting
+  if (split_on_const) {
+    std::vector<std::pair<std::pair<coef_t, coef_t>, int> > bounds;
+
+    for (BoolSet<>::const_iterator i = active.begin(); i != active.end(); i++) {
+      Relation r = Intersection(copy(projected_IS_[level-1][*i]), copy(restriction));
+      r.simplify(2, 4);
+      if (!r.is_upper_bound_satisfiable())
+        continue;
+      coef_t lb, ub;
+      r.single_conjunct()->query_variable_bounds(r.set_var(level),lb,ub);
+      bounds.push_back(std::make_pair(std::make_pair(lb, ub), *i));
+    }
+    sort(bounds.begin(), bounds.end());
+
+    std::vector<Relation> split_cond;
+    std::vector<CG_result *> split_child;
+
+    coef_t prev_val = -posInfinity;
+    coef_t next_val = bounds[0].first.second;
+    BoolSet<> next_active(active.size());
+    int i = 0;
+    while (i < bounds.size()) {
+      if (bounds[i].first.first <= next_val) {
+        next_active.set(bounds[i].second);
+        next_val = max(next_val, bounds[i].first.second);
+        i++;
+      }
+      else {
+        Relation r(num_level());
+        F_And *f_root = r.add_and();
+        if (prev_val != -posInfinity) {
+          GEQ_Handle h = f_root->add_GEQ();
+          h.update_coef(r.set_var(level), 1);
+          h.update_const(-prev_val-1);
+        }
+        if (next_val != posInfinity) {
+          GEQ_Handle h = f_root->add_GEQ();
+          h.update_coef(r.set_var(level), -1);
+          h.update_const(next_val);
+        }
+        r.simplify();
+
+        Relation new_restriction = Intersection(copy(r), copy(restriction));
+        new_restriction.simplify(2, 4);
+        CG_result *child = buildAST(level, next_active, false, new_restriction);
+        if (child != NULL) {
+          split_cond.push_back(copy(r));
+          split_child.push_back(child);
+        }
+        next_active.unset_all();
+        prev_val = next_val;
+        next_val = bounds[i].first.second;
+      }
+    }
+    if (!next_active.empty()) {
+      Relation r = Relation::True(num_level());
+      if (prev_val != -posInfinity) {
+        F_And *f_root = r.and_with_and();
+        GEQ_Handle h = f_root->add_GEQ();
+        h.update_coef(r.set_var(level), 1);
+        h.update_const(-prev_val-1);
+        r.simplify();
+      }
+      Relation new_restriction = Intersection(copy(r), copy(restriction));
+      new_restriction.simplify(2, 4);
+      CG_result *child = buildAST(level, next_active, false, new_restriction);
+      if (child != NULL) {
+        split_cond.push_back(copy(r));
+        split_child.push_back(child);
+      }
+    }
+
+    if (split_child.size() == 0)
+      return NULL;
+    else if (split_child.size() == 1)
+      return split_child[0];
+    else
+      return new CG_split(this, active, split_cond, split_child);
+  }
+  // check bound conditions exhaustively for non-overlap iteration space splitting
+  else {
+    std::vector<Relation> Rs(active.size());
+    for (BoolSet<>::const_iterator i = active.begin(); i != active.end(); i++) {
+      Rs[*i] = Intersection(Approximate(copy(projected_IS_[level-1][*i])), copy(restriction));
+      Rs[*i].simplify(2, 4);
+    }
+    Relation hull = SimpleHull(Rs);
+
+    //protonu-warn Chun about this change
+  //This does some fancy splitting of statements into loops with the
+  //fewest dimentions, but that's not necessarily what we want when
+  //code-gening for CUDA. smtNonSplitLevels keeps track per-statment of
+  //the levels that should not be split on.
+  bool checkForSplits = true;
+ for (BoolSet<>::const_iterator i = active.begin(); i != active.end(); i++) {
+      if(*i  < smtNonSplitLevels.size())
+         for(int k = 0; k <smtNonSplitLevels[*i].size();  k++)
+           if(smtNonSplitLevels[*i][k] == (level-2)){
+               checkForSplits = false;
+              break;
+      }
+    }
+  
+
+
+
+    for (BoolSet<>::const_iterator i = active.begin(); i != active.end() && checkForSplits; i++) {
+      Relation r = Gist(copy(Rs[*i]), copy(hull), 1);
+      if (r.is_obvious_tautology())
+        continue;
+      r = EQs_to_GEQs(r);
+
+      for (GEQ_Iterator e = r.single_conjunct()->GEQs(); e; e++) {
+        if ((*e).has_wildcards())
+          continue;
+            
+        Relation cond = Relation::True(num_level());
+        BoolSet<> first_chunk(active.size());
+        BoolSet<> second_chunk(active.size());
+
+        if ((*e).get_coef(hull.set_var(level)) > 0) {
+          cond.and_with_GEQ(*e);
+          cond = Complement(cond);;
+          cond.simplify();
+          second_chunk.set(*i);
+        }
+        else if ((*e).get_coef(hull.set_var(level)) < 0) {
+          cond.and_with_GEQ(*e);
+          cond.simplify();
+          first_chunk.set(*i);
+        }
+        else
+          continue;
+
+        bool is_proper_split_cond = true;
+        for (BoolSet<>::const_iterator j = active.begin(); j != active.end(); j++)
+          if ( *j != *i) {
+          bool in_first = Intersection(copy(Rs[*j]), copy(cond)).is_upper_bound_satisfiable();
+          bool in_second = Difference(copy(Rs[*j]), copy(cond)).is_upper_bound_satisfiable();
+
+          if (in_first && in_second) {
+            is_proper_split_cond = false;
+            break;
+          }
+
+          if (in_first)
+            first_chunk.set(*j);
+          else if (in_second)
+            second_chunk.set(*j);
+          }
+
+        if (is_proper_split_cond && first_chunk.num_elem() != 0 && second_chunk.num_elem() != 0) {
+          CG_result *first_cg = buildAST(level, first_chunk, false, copy(cond));
+          CG_result *second_cg = buildAST(level, second_chunk, false, Complement(copy(cond)));
+          if (first_cg == NULL)
+            return second_cg;
+          else if (second_cg == NULL)
+            return first_cg;
+          else {
+            std::vector<Relation> split_cond;
+            std::vector<CG_result *> split_child;
+            split_cond.push_back(copy(cond));
+            split_child.push_back(first_cg);
+            split_cond.push_back(Complement(copy(cond)));
+            split_child.push_back(second_cg);
+
+            return new CG_split(this, active, split_cond, split_child);
+          }
+        }
+      }
+    }
+    return new CG_loop(this, active, level, buildAST(level+1, active, true, restriction));
+  }
+}
+
+
+CG_result *CodeGen::buildAST(int effort) {
+  if (remap_.size() == 0)
+    return NULL;
+
+  CG_result *cgr = buildAST(1, ~BoolSet<>(remap_.size()), true, Relation::True(num_level()));
+  if (cgr == NULL)
+    return NULL;
+
+
+  // break down the complete iteration space condition to levels of bound/guard condtions
+  cgr = cgr->recompute(cgr->active_, copy(known_), copy(known_));
+
+
+
+  if (cgr == NULL)
+    return NULL;
+
+  // calculate each loop's nesting depth
+  int depth = cgr->populateDepth();
+
+
+  // redistribute guard condition locations by additional splittings
+  std::pair<CG_result *, Relation> result = cgr->liftOverhead(min(effort,depth), false);
+
+  // since guard conditions are postponed for non-loop levels, hoist them now.
+  // this enables proper if-condition simplication when outputting actual code.
+  result.first->hoistGuard();
+
+
+
+
+  return result.first;
+}
+
+}
diff --git a/lib/omega/CMakeLists.txt b/lib/omega/CMakeLists.txt
new file mode 100644
index 0000000..a7b99c7
--- /dev/null
+++ b/lib/omega/CMakeLists.txt
@@ -0,0 +1,71 @@
+set(OMEGAROOT ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE)
+
+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/lib/omega/doc/interface.pdf b/lib/omega/doc/interface.pdf
new file mode 100644
index 0000000..7f918ae
Binary files /dev/null and b/lib/omega/doc/interface.pdf differ
diff --git a/lib/omega/include/basic/Bag.h b/lib/omega/include/basic/Bag.h
new file mode 100644
index 0000000..a3d07a0
--- /dev/null
+++ b/lib/omega/include/basic/Bag.h
@@ -0,0 +1,405 @@
+#if ! defined _Bag_h
+#define _Bag_h 1
+
+#include <stdio.h>
+#include <basic/Iterator.h>
+#include <basic/Collection.h>
+#include <basic/Link.h>
+#include <assert.h>
+
+namespace omega {
+
+template<class T> class Bag : public Collection<T> { 
+public:
+virtual ~Bag();
+	Bag();
+	Bag(const Bag<T>&);
+	Bag & operator=(const Bag<T>&);
+    //! add elements in b
+    virtual	void operator |= (const Bag<T> & 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();
+	Ordered_Bag(const Ordered_Bag<T>& B) : Bag<T>(B) {}
+	void insert(T);
+    //! add elements in b
+    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();
+	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
+    
+    //! add elements in b
+    virtual	void operator |= (const Set<T> & b);
+    //! add elements in b
+	void operator |= (const Ordered_Bag<T> & b);
+    //! add elements in b
+	void operator |= (const Bag<T> & b);
+
+    //! delete items also in b
+    void operator -= (const Set<T> & b);
+    //! delete items not in b
+    void operator &= (const Set<T> & b);
+    //! check for elements in common
+    bool operator & (const Set<T> &) const;
+};
+
+} // namespace
+
+#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)
+
+
+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
+
+#endif
diff --git a/lib/omega/include/basic/BoolSet.h b/lib/omega/include/basic/BoolSet.h
new file mode 100755
index 0000000..a78af2e
--- /dev/null
+++ b/lib/omega/include/basic/BoolSet.h
@@ -0,0 +1,641 @@
+/*****************************************************************************
+ 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 {
+
+    //!  BoolSet class, used as a set of integers from 0 to n-1 where n is a very small integer.
+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> &); 
+
+  //! 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> &, const BoolSet<TT> &);
+  //! complement
+  template<typename TT> friend BoolSet<TT> operator~(const BoolSet<TT> &);                 
+  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> &);
+
+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/lib/omega/include/basic/Collection.h b/lib/omega/include/basic/Collection.h
new file mode 100644
index 0000000..80ddf48
--- /dev/null
+++ b/lib/omega/include/basic/Collection.h
@@ -0,0 +1,43 @@
+#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;
+
+    /*! Y in X --> X[X.index(Y)] == Y */
+    virtual int index(const T &) const = 0;  };
+
+} // 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/lib/omega/include/basic/Collections.h b/lib/omega/include/basic/Collections.h
new file mode 100644
index 0000000..1e68031
--- /dev/null
+++ b/lib/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/lib/omega/include/basic/ConstString.h b/lib/omega/include/basic/ConstString.h
new file mode 100644
index 0000000..f149c9d
--- /dev/null
+++ b/lib/omega/include/basic/ConstString.h
@@ -0,0 +1,57 @@
+#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/lib/omega/include/basic/DynamicArray.h b/lib/omega/include/basic/DynamicArray.h
new file mode 100644
index 0000000..08f8b91
--- /dev/null
+++ b/lib/omega/include/basic/DynamicArray.h
@@ -0,0 +1,318 @@
+#ifndef Already_Included_DynamicArray
+#define Already_Included_DynamicArray
+
+#include <assert.h>
+
+namespace omega {
+
+template <class T> class DynamicArray2;
+template <class T> class DynamicArray3;
+template <class T> class DynamicArray4;
+
+template <class T, int d> class DynamicArray
+    {
+    public:
+	DynamicArray(DynamicArray<T,d> &D);
+        ~DynamicArray();
+
+    protected:
+	DynamicArray();
+	bool partial;
+	int *bounds;
+	T *elements;
+
+	void do_constr();
+	void do_destruct();
+    };
+
+
+template <class T> class DynamicArray1 : public DynamicArray<T,1>
+    {
+    public:
+	DynamicArray1(const char *s0 = 0);
+	DynamicArray1(int d0);
+	void resize(int d0);
+        T& operator[](int d);
+
+	friend class DynamicArray2<T>;
+
+    private:
+	void do_construct(int d0);
+    };
+
+
+template <class T> class DynamicArray2 : public DynamicArray<T,2>
+    {
+    public:
+	DynamicArray2(const char *s0 = 0, const char *s1 = 0);
+	DynamicArray2(int d0, int d1);
+	void resize(int d0, int d1);
+  	DynamicArray1<T> operator[](int d);
+
+	friend class DynamicArray3<T>;
+
+    private:
+	void do_construct(int d0, int d1);
+    };
+
+
+template <class T> class DynamicArray3 : public DynamicArray<T,3>
+    {
+    public:
+	DynamicArray3(const char *s0 = 0, const char *s1 = 0, const char *s2 = 0);
+	DynamicArray3(int d0, int d1, int d2);
+	void resize(int d0, int d1, int d2);
+  	DynamicArray2<T> operator[](int d);
+
+	friend class DynamicArray4<T>;
+
+    private:
+	void do_construct(int d0, int d1, int d2);
+    };
+
+template <class T> class DynamicArray4 : public DynamicArray<T,4>
+    {
+    public:
+	DynamicArray4(const char *s0 = 0, const char *s1 = 0, const char *s2 = 0, const char *s3 = 0);
+	DynamicArray4(int d0, int d1, int d2, int d3);
+	void resize(int d0, int d1, int d2, int d3);
+  	DynamicArray3<T> operator[](int d);
+
+    private:
+	void do_construct(int d0, int d1, int d2, int d3);
+    };
+
+} // namespace
+
+#define instantiate_DynamicArray1(T)	template class DynamicArray1<T>; \
+					template class DynamicArray<T,1>;
+
+#define instantiate_DynamicArray2(T)	template class DynamicArray2<T>;  \
+					template class DynamicArray<T,2>; \
+					instantiate_DynamicArray1(T);
+
+#define instantiate_DynamicArray3(T)	template class DynamicArray3<T>;  \
+					template class DynamicArray<T,3>; \
+					instantiate_DynamicArray2(T);
+
+#define instantiate_DynamicArray4(T)	template class DynamicArray4<T>;  \
+					template class DynamicArray<T,4>; \
+					instantiate_DynamicArray3(T);
+
+namespace omega {
+  
+template<class T, int d> void DynamicArray<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 DynamicArray1<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 DynamicArray2<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 DynamicArray3<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 DynamicArray4<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> DynamicArray<T,d>::DynamicArray()
+    {
+    do_constr();
+    }
+
+template<class T> DynamicArray1<T>::DynamicArray1(const char *)
+    {
+    this->do_constr();
+    }
+
+template<class T> DynamicArray2<T>::DynamicArray2(const char *,const char *)
+    {
+    this->do_constr();
+    }
+
+template<class T> DynamicArray3<T>::DynamicArray3(const char *,const char *,const char *)
+    {
+    this->do_constr();
+    }
+
+template<class T> DynamicArray4<T>::DynamicArray4(const char *,const char *,const char *,const char *)
+    {
+    this->do_constr();
+    }
+
+template<class T> DynamicArray1<T>::DynamicArray1(int d0)
+    {
+    do_construct(d0);
+    } 
+
+template<class T> DynamicArray2<T>::DynamicArray2(int d0, int d1)
+    {
+    do_construct(d0, d1);
+    }
+
+template<class T> DynamicArray3<T>::DynamicArray3(int d0,int d1,int d2)
+    {
+    do_construct(d0, d1, d2);
+    }
+
+template<class T> DynamicArray4<T>::DynamicArray4(int d0,int d1,int d2,int d3)
+    {
+    do_construct(d0, d1, d2, d3);
+    }
+
+
+template<class T, int d> void DynamicArray<T,d>::do_destruct()
+    {
+    if (! partial)
+	{
+        delete [] bounds;
+        delete [] elements;
+	}
+    }
+
+
+template<class T, int d> DynamicArray<T,d>::~DynamicArray()
+    {
+    do_destruct();
+    }
+
+
+template<class T> void DynamicArray1<T>::resize(int d0)
+    {
+    assert(!this->partial);
+    this->do_destruct();
+    if (d0 == 0)
+        this->do_constr();
+    else
+        do_construct(d0);
+    } 
+
+template<class T> void DynamicArray2<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 DynamicArray3<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 DynamicArray4<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& DynamicArray1<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>  DynamicArray1<T> DynamicArray2<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
+
+    DynamicArray1<T> result;
+    result.bounds = this->bounds+1;
+    result.elements = this->elements + this->bounds[1] * d0;
+    result.partial = true;
+    return result;
+    }
+
+template<class T>  DynamicArray2<T> DynamicArray3<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
+    DynamicArray2<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>  DynamicArray3<T> DynamicArray4<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
+
+    DynamicArray3<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> 
+    DynamicArray<T,d>::DynamicArray(DynamicArray<T,d> &D)
+    {
+    assert(D.elements != 0 && "Trying to copy an undefined array");
+    partial = true;
+    bounds = D.bounds;
+    elements = D.elements;
+    }
+
+} // namespace
+#endif
diff --git a/lib/omega/include/basic/Iterator.h b/lib/omega/include/basic/Iterator.h
new file mode 100644
index 0000000..f62874c
--- /dev/null
+++ b/lib/omega/include/basic/Iterator.h
@@ -0,0 +1,129 @@
+/*
+ * 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)
+
+/*!
+ * \brief 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
+/*! Values 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:
+    //! take over *p, *p MUST BE ON THE HEAP
+    Any_Iterator(Iterator<T> *p) { me = p; }
+    friend class Collection<T>;
+/* 
+ *   // Couldn't make this work with g++258
+ *   friend Any_Iterator<T> Collection<T>::any_iterator();
+ */
+    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/lib/omega/include/basic/Link.h b/lib/omega/include/basic/Link.h
new file mode 100644
index 0000000..bdf169c
--- /dev/null
+++ b/lib/omega/include/basic/Link.h
@@ -0,0 +1,97 @@
+#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
+
+#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
+/*! 
+ * \brief 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.
+ */
+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/lib/omega/include/basic/List.h b/lib/omega/include/basic/List.h
new file mode 100644
index 0000000..28ab1d5
--- /dev/null
+++ b/lib/omega/include/basic/List.h
@@ -0,0 +1,233 @@
+#if ! defined _List_h
+#define _List_h 1
+
+/*
+ *  Linked lists with an interface like a bit of libg++'s SLList class
+ */
+#include <stdio.h>  // for NULL
+#include <basic/Iterator.h>
+#include <basic/Collection.h>
+#include <basic/Link.h>
+#include <assert.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
+
+#define instantiate_List(T)	template class List<T>; \
+				template class List_Iterator<T>; \
+				instantiate_Only_List_Element(T) \
+				instantiate_Sequence(T)
+
+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
+#endif
diff --git a/lib/omega/include/basic/Map.h b/lib/omega/include/basic/Map.h
new file mode 100644
index 0000000..25a116d
--- /dev/null
+++ b/lib/omega/include/basic/Map.h
@@ -0,0 +1,127 @@
+#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
+
+#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)
+
+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
+#endif
diff --git a/lib/omega/include/basic/Section.h b/lib/omega/include/basic/Section.h
new file mode 100644
index 0000000..7a4d241
--- /dev/null
+++ b/lib/omega/include/basic/Section.h
@@ -0,0 +1,138 @@
+#if ! defined _Section_h
+#define _Section_h 1
+/*
+  Section of an existing collection viewed as a collection
+  */
+
+#include <basic/Collection.h>
+#include <assert.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
+
+#define instantiate_Section(T)	template class Section<T>; \
+				template class Section_Iterator<T>; \
+				instantiate_Sequence(T)
+#define instantiate_Section_Iterator(T)	  instantiate_Section(T)
+
+
+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
+#endif
diff --git a/lib/omega/include/basic/SimpleList.h b/lib/omega/include/basic/SimpleList.h
new file mode 100644
index 0000000..104390d
--- /dev/null
+++ b/lib/omega/include/basic/SimpleList.h
@@ -0,0 +1,194 @@
+#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
+
+#define instantiate_Simple_List(T)	template class Simple_List<T>;  \
+  template class Simple_List_Iterator<T>;                           \
+  instantiate_Only_List_Element(T)                                  \
+  instantiate_Sequence(T)
+
+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
+#endif
diff --git a/lib/omega/include/basic/Tuple.h b/lib/omega/include/basic/Tuple.h
new file mode 100644
index 0000000..e9aae84
--- /dev/null
+++ b/lib/omega/include/basic/Tuple.h
@@ -0,0 +1,336 @@
+#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
+
+#define instantiate_Tuple(T)	template class Tuple<T>; \
+				template class Tuple_Iterator<T>; \
+				instantiate_Sequence(T)
+
+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
+#endif
diff --git a/lib/omega/include/basic/omega_error.h b/lib/omega/include/basic/omega_error.h
new file mode 100644
index 0000000..e342efb
--- /dev/null
+++ b/lib/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/lib/omega/include/basic/util.h b/lib/omega/include/basic/util.h
new file mode 100644
index 0000000..4e807cd
--- /dev/null
+++ b/lib/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/lib/omega/include/omega.h b/lib/omega/include/omega.h
new file mode 100644
index 0000000..8aa2c08
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/RelBody.h b/lib/omega/include/omega/RelBody.h
new file mode 100644
index 0000000..3c11702
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/Rel_map.h b/lib/omega/include/omega/Rel_map.h
new file mode 100644
index 0000000..5641cb3
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/Relation.h b/lib/omega/include/omega/Relation.h
new file mode 100644
index 0000000..b41bef5
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/Relations.h b/lib/omega/include/omega/Relations.h
new file mode 100644
index 0000000..4fd81e6
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/closure.h b/lib/omega/include/omega/closure.h
new file mode 100644
index 0000000..67088dd
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/evac.h b/lib/omega/include/omega/evac.h
new file mode 100644
index 0000000..a561f8c
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/farkas.h b/lib/omega/include/omega/farkas.h
new file mode 100644
index 0000000..e77ed66
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/hull.h b/lib/omega/include/omega/hull.h
new file mode 100644
index 0000000..928d0c6
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/omega_core/debugging.h b/lib/omega/include/omega/omega_core/debugging.h
new file mode 100644
index 0000000..e217ae9
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/omega_core/oc.h b/lib/omega/include/omega/omega_core/oc.h
new file mode 100644
index 0000000..e4f5444
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/omega_core/oc_i.h b/lib/omega/include/omega/omega_core/oc_i.h
new file mode 100644
index 0000000..9533a40
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/omega_i.h b/lib/omega/include/omega/omega_i.h
new file mode 100644
index 0000000..e5d9230
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/pres_cmpr.h b/lib/omega/include/omega/pres_cmpr.h
new file mode 100644
index 0000000..fb3e6f0
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/pres_cnstr.h b/lib/omega/include/omega/pres_cnstr.h
new file mode 100644
index 0000000..7b2d98d
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/pres_conj.h b/lib/omega/include/omega/pres_conj.h
new file mode 100644
index 0000000..ea10a2c
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/pres_decl.h b/lib/omega/include/omega/pres_decl.h
new file mode 100644
index 0000000..7fec0bc
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/pres_dnf.h b/lib/omega/include/omega/pres_dnf.h
new file mode 100644
index 0000000..93d5942
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/pres_form.h b/lib/omega/include/omega/pres_form.h
new file mode 100644
index 0000000..ed3258e
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/pres_gen.h b/lib/omega/include/omega/pres_gen.h
new file mode 100644
index 0000000..ba6a793
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/pres_logic.h b/lib/omega/include/omega/pres_logic.h
new file mode 100644
index 0000000..27c4553
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/pres_quant.h b/lib/omega/include/omega/pres_quant.h
new file mode 100644
index 0000000..98c30df
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/pres_subs.h b/lib/omega/include/omega/pres_subs.h
new file mode 100644
index 0000000..8a9ee92
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/pres_tree.h b/lib/omega/include/omega/pres_tree.h
new file mode 100644
index 0000000..ad78ad0
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/pres_var.h b/lib/omega/include/omega/pres_var.h
new file mode 100644
index 0000000..bf60dcb
--- /dev/null
+++ b/lib/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/lib/omega/include/omega/reach.h b/lib/omega/include/omega/reach.h
new file mode 100644
index 0000000..76d7dee
--- /dev/null
+++ b/lib/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;
+	DynamicArray1<Relation> start_nodes;
+	DynamicArray2<Relation> transitions;
+};
+
+
+DynamicArray1<Relation> *
+Reachable_Nodes(reachable_information * reachable_info);
+
+DynamicArray1<Relation> *
+I_Reachable_Nodes(reachable_information * reachable_info);
+
+} // namespace
+
+#endif
diff --git a/lib/omega/src/RelBody.cc b/lib/omega/src/RelBody.cc
new file mode 100644
index 0000000..825b153
--- /dev/null
+++ b/lib/omega/src/RelBody.cc
@@ -0,0 +1,906 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 the Omega Project Team
+ Copyright (C) 2005-2011 Chun Chen
+ All Rights Reserved.
+
+ Purpose:
+   class Rel_Body, internal Relation representation
+
+ Notes:
+
+ History:
+   11/26/09  Remove unecessary mandatary checking for set or relation,
+             treat them uniformly for easy coding, by Chun Chen
+*****************************************************************************/
+
+#include <basic/util.h>
+#include <omega/RelBody.h>
+#include <omega/Relation.h>
+#include <omega/pres_tree.h>
+#include <omega/pres_conj.h>
+#include <omega/omega_i.h>
+#include <assert.h>
+
+namespace omega {
+
+Rel_Body null_rel;
+bool Rel_Body::is_null() const {
+  return(this == &null_rel);
+}
+
+
+int Rel_Body::max_ufs_arity() {
+  int ma = 0, a;
+  for (Variable_ID_Iterator v(*global_decls()); v; v++) {
+    a = (*v)->get_global_var()->arity();
+    if (a > ma)
+      ma = a;
+  }
+  return ma;
+}
+
+int Rel_Body::max_ufs_arity_of_set() {
+  int ma = 0, a;
+  for (Variable_ID_Iterator v(*global_decls()); v; v++)
+    if ((*v)->function_of() == Set_Tuple) {
+      a = (*v)->get_global_var()->arity();
+      if (a > ma)
+        ma = a;
+    }
+  return ma;
+}
+
+int Rel_Body::max_ufs_arity_of_in() {
+  int ma = 0, a;
+  for (Variable_ID_Iterator v(*global_decls()); v; v++)
+    if ((*v)->function_of() == Input_Tuple) {
+      a = (*v)->get_global_var()->arity();
+      if (a > ma)
+        ma = a;
+    }
+  return ma;
+}
+
+int Rel_Body::max_ufs_arity_of_out() {
+  int ma = 0, a;
+  for (Variable_ID_Iterator v(*global_decls()); v; v++)
+    if ((*v)->function_of() == Output_Tuple) {
+      a = (*v)->get_global_var()->arity();
+      if (a > ma)
+        ma = a;
+    }
+  return ma;
+}
+
+int Rel_Body::max_shared_ufs_arity() {
+  int ma = 0, a;
+  for (Variable_ID_Iterator v(*global_decls()); v; v++)
+    for (Variable_ID_Iterator v2(*global_decls()); v2; v2++)
+      if (*v != *v2 
+          && (*v)->get_global_var() == (*v2)->get_global_var()
+          && (*v)->function_of() != (*v2)->function_of()) {
+        a = (*v)->get_global_var()->arity();
+        if (a > ma)
+          ma = a;
+      }
+  return ma;
+}
+
+//
+// Input and output variables.
+//
+void Rel_Body::name_input_var(int nth, Const_String S) {
+  // assert(1 <= nth && nth <= number_input && (!is_set() || skip_set_checks > 0));
+  if (is_null())
+    throw std::invalid_argument("empty relation");
+  if (nth < 1 || nth > number_input)
+    throw std::invalid_argument("invalid input var number");
+  In_Names[nth] = S;
+}
+
+void Rel_Body::name_output_var(int nth, Const_String S) {
+  // assert(1<= nth && nth <= number_output && (!is_set() || skip_set_checks > 0));
+  if (is_null())
+    throw std::invalid_argument("empty relation");
+  if (nth < 1 || nth > number_output)
+    throw std::invalid_argument("invalid output var number");
+  Out_Names[nth] = S;
+}
+
+void Rel_Body::name_set_var(int nth, Const_String S) {
+  if (number_output != 0)
+    throw std::runtime_error("relation is not a set");
+  name_input_var(nth, S);
+}
+
+int Rel_Body::n_inp() const {
+  // assert(!is_null() && (!is_set()||skip_set_checks>0));
+  if (is_null())
+    return 0;
+  else
+    return number_input;
+}
+
+int Rel_Body::n_out() const {
+  // assert(!is_null() && (!is_set()||skip_set_checks>0));
+  if (is_null())
+    return 0;
+  else
+    return number_output;
+}
+
+int Rel_Body::n_set() const {
+  if (number_output != 0)
+    throw std::runtime_error("relation is not a set");
+  return n_inp();
+}
+
+Variable_ID Rel_Body::input_var(int nth) {
+  // assert(!is_null());
+  // assert(!is_set() || skip_set_checks>0);
+  // assert(1 <= nth && nth <= number_input);
+  if (is_null())
+    throw std::invalid_argument("empty relation");
+  if (nth < 1 || nth > number_input)
+    throw std::invalid_argument("invalid input var number");
+  input_vars[nth]->base_name = In_Names[nth];
+  return input_vars[nth];
+}
+
+Variable_ID Rel_Body::output_var(int nth) {
+  // assert(!is_null());
+  // assert(!is_set() || skip_set_checks>0);
+  // assert(1<= nth && nth <= number_output);
+  if (is_null())
+    throw std::invalid_argument("empty relation");
+  if (nth < 1 || nth > number_output)
+    throw std::invalid_argument("invalid output var number");
+  output_vars[nth]->base_name = Out_Names[nth];
+  return output_vars[nth];
+}
+
+Variable_ID Rel_Body::set_var(int nth) {
+  if (number_output != 0)
+    throw std::runtime_error("relation is not a set");
+  return input_var(nth);
+}
+
+//
+// Add the AND node to the relation.
+// Useful for adding restraints.
+//
+F_And *Rel_Body::and_with_and() {
+  assert(!is_null());
+  if (is_simplified())
+    DNF_to_formula();
+  relation()->finalized = false;
+  Formula *f = rm_formula();
+  F_And *a = add_and();
+  a->add_child(f);
+  return a;
+}
+
+//
+// Add constraint to relation at the upper level.
+//
+EQ_Handle Rel_Body::and_with_EQ() {
+  assert(!is_null());
+  if (is_simplified())
+    DNF_to_formula();
+  assert(! is_shared());  // The relation has been split.
+  relation()->finalized = false;
+  return find_available_conjunct()->add_EQ();
+}
+
+EQ_Handle Rel_Body::and_with_EQ(const Constraint_Handle &initial) {
+  assert(!is_null());
+  assert(initial.relation()->is_simplified());
+  EQ_Handle H = and_with_EQ();
+  copy_constraint(H, initial);
+  return H;
+}
+
+GEQ_Handle Rel_Body::and_with_GEQ() {
+  assert(!is_null());
+  if (is_simplified())
+    DNF_to_formula();
+  assert(! is_shared());  // The relation has been split.
+  relation()->finalized = false;  // We are giving out a handle.
+  // We should evantually implement finalization
+  // of subtrees, so the existing formula cannot
+  // be modified.
+  return find_available_conjunct()->add_GEQ();
+}
+
+GEQ_Handle Rel_Body::and_with_GEQ(const Constraint_Handle &initial) {
+  assert(!is_null());
+  assert(initial.relation()->is_simplified());
+  GEQ_Handle H = and_with_GEQ();
+  copy_constraint(H, initial);
+  return H;
+}
+
+
+
+Conjunct *Rel_Body::find_available_conjunct() {
+  Conjunct *c;
+  assert(!is_null());
+
+  if (children().empty()) {
+    c = add_conjunct();
+  }
+  else {
+    assert(children().length() == 1);
+    Formula *kid = children().front();  // RelBodies have only one child
+    c = kid->find_available_conjunct();
+    if (c==NULL) {
+      remove_child(kid);
+      F_And *a = add_and();
+      a->add_child(kid);
+      c = a->add_conjunct();
+    }
+  } 
+  return c;
+}
+
+void Rel_Body::finalize() {
+  assert(!is_null());
+  if (!is_finalized())
+    assert(! is_shared());  // no other pointers into here
+  finalized = true;
+  if (! children().empty())
+    children().front()->finalize();  // Can have at most one child
+}
+
+// Null Rel_Body
+// This is the only rel_body constructor that has ref_count initialized to 1;
+// That's because it's used to construct the global Rel_Body "null_rel". 
+// Unfortunately because we don't know in what order global constructors will
+// be called, we could create a global relation with the default relation
+// constructor (which would set the null_rel ref count to 1), and *then* 
+// call Rel_Body::Rel_Body(), which would set it back to 0, leaving a relation
+// that points to a rel_body with it's ref_count set to 0!  So this is done as
+// a special case, in which the ref_count is always 1.
+Rel_Body::Rel_Body():
+  Formula(0, this), 
+  ref_count(1),
+  status(under_construction),
+  number_input(0), number_output(0),
+  In_Names(0), Out_Names(0),
+  simplified_DNF(NULL),
+  r_conjs(0), 
+  finalized(true),
+  _is_set(false) {
+}
+
+
+Rel_Body::Rel_Body(int n_input, int n_output):
+  Formula(0, this),
+  ref_count(0),
+  status(under_construction),
+  number_input(n_input), number_output(n_output), 
+  In_Names(n_input), Out_Names(n_output),
+  simplified_DNF(NULL),
+  r_conjs(0), 
+  finalized(false) {
+  if (n_output == 0)
+    _is_set = true;
+  else
+    _is_set = false;
+  if(pres_debug) {
+    fprintf(DebugFile, "+++ Create Rel_Body::Rel_Body(%d, %d) = 0x%p +++\n",
+            n_input, n_output, this);
+  }
+  int i; 
+  for(i=1; i<=number_input; i++) {
+    In_Names[i] = Const_String();
+  }
+  for(i=1; i<=number_output; i++) {
+    Out_Names[i] = Const_String();
+  }
+}
+
+// Rel_Body::Rel_Body(Rel_Body *r):
+//   Formula(0, this),
+//   ref_count(0),
+//   status(r->status),
+//   number_input(r->number_input), number_output(r->number_output),
+//   In_Names(r->number_input), Out_Names(r->number_output),
+//   simplified_DNF(NULL),
+//   r_conjs(r->r_conjs), 
+//   finalized(r->finalized),
+//   _is_set(r->_is_set) {
+//   if(pres_debug) {
+//     fprintf(DebugFile, "+++ Copy Rel_Body::Rel_Body(Rel_Body * 0x%p) = 0x%p +++\n", r, this);
+//     prefix_print(DebugFile);
+//   }
+
+//   int i;
+//   for(i=1;i<=r->number_input;i++) In_Names[i] = r->In_Names[i];
+//   for(i=1;i<=r->number_output;i++) Out_Names[i] = r->Out_Names[i];
+//   copy_var_decls(Symbolic,r->Symbolic);
+
+//   if(!r->children().empty() && r->simplified_DNF==NULL) {
+//     Formula *f = r->formula()->copy(this,this);
+//     f->remap();
+//     children().append(f);
+//   }
+//   else if(r->children().empty() && r->simplified_DNF!=NULL) {
+//     simplified_DNF = r->simplified_DNF->copy(this);
+//     simplified_DNF->remap();
+//   }
+//   else {   // copy NULL relation
+//   }
+
+//   reset_remap_field(r->Symbolic);
+// }
+
+Rel_Body *Rel_Body::clone() {
+  Rel_Body *b = new Rel_Body();
+
+  b->ref_count = 0;
+  b->status = status;
+  b->number_input = number_input;
+  b->number_output = number_output;
+  b->r_conjs = r_conjs;
+  b->finalized = finalized;
+  b->_is_set = _is_set;
+  
+  b->In_Names = Tuple<Const_String>(number_input);
+  b->Out_Names = Tuple<Const_String>(number_output);
+  for(int i = 1; i <= number_input; i++)
+    b->In_Names[i] = In_Names[i];
+  for(int i = 1; i <= number_output; i++)
+    b->Out_Names[i] = Out_Names[i];
+  
+  copy_var_decls(b->Symbolic, Symbolic);
+
+  if(!children().empty() && simplified_DNF==NULL) {
+    Formula *f = formula()->copy(b, b);
+    f->remap();
+    b->children().append(f);
+  }
+  else if(children().empty() && simplified_DNF!=NULL) {
+    b->simplified_DNF = simplified_DNF->copy(b);
+    b->simplified_DNF->remap();
+  }
+  else {   // copy NULL relation
+  }
+
+  reset_remap_field(Symbolic);
+  return b;
+}
+
+
+Rel_Body::Rel_Body(Rel_Body *r, Conjunct *c):
+  Formula(0, this),
+  ref_count(0),
+  status(uncompressed),
+  number_input(r->number_input), number_output(r->number_output),
+  In_Names(r->number_input), Out_Names(r->number_output),
+  r_conjs(0), 
+  finalized(r->finalized),
+  _is_set(r->_is_set) {
+  if(pres_debug) {
+    fprintf(DebugFile, "+++ Copy Rel_Body::Rel_Body(Rel_Body * 0x%p, Conjunct * 0x%p) = 0x%p +++\n",r,c,this);
+  }
+
+  int i;
+  for(i=1;i<=r->number_input;i++) In_Names[i] = r->In_Names[i];
+  for(i=1;i<=r->number_output;i++) Out_Names[i] = r->Out_Names[i];
+  copy_var_decls(Symbolic,r->Symbolic);
+
+  // assert that r has as many variables as c requires, or that c is from r
+  assert(r == c->relation());
+  assert(r->simplified_DNF != NULL);
+  simplified_DNF = new DNF;
+  simplified_DNF->add_conjunct(c->copy_conj_diff_relation(this,this));
+  single_conjunct()->remap();
+
+  reset_remap_field(r->Symbolic);
+}
+
+Rel_Body::~Rel_Body() {
+  if(pres_debug) {
+    fprintf(DebugFile, "+++ Destroy Rel_Body::~Rel_Body() 0x%p +++\n", this);
+  }
+  free_var_decls(Symbolic);
+  if(simplified_DNF != NULL) {
+    delete simplified_DNF;
+  }
+}
+
+//
+// Take a relation that has been simplified and convert it 
+// back to formula form.  
+//
+void Rel_Body::DNF_to_formula() {
+  assert(!is_null());
+  if (simplified_DNF != NULL) {
+    simplified_DNF->DNF_to_formula(this);
+    simplified_DNF = NULL;
+    status = under_construction;
+  }
+}
+
+bool Rel_Body::can_add_child() {
+  assert(this != &null_rel);
+  return n_children() < 1;
+}
+
+
+
+// ********************
+//  Simplify functions
+// ********************
+
+
+extern int s_rdt_constrs;
+
+
+//
+// Simplify a given relation.
+// Store the resulting DNF in the relation, clean out the formula.
+//
+void Rel_Body::simplify(int rdt_conjs, int rdt_constrs) {
+  if(simplified_DNF == NULL) {
+    finalized = true;
+    if(children().empty()) {
+      simplified_DNF = new DNF;
+    }
+    else {
+      if(pres_debug) {
+        if(DebugFile==NULL) {
+          DebugFile = fopen("test.out", "w");
+          if(DebugFile==NULL)
+            fprintf(stderr, "Can not open file test.out\n");
+        }
+      }
+
+      assert(children().length()==1);
+      if(pres_debug) {
+        fprintf(DebugFile, "=== %p Rel_Body::simplify(%d, %d) Input tree (%d) ===\n", this,rdt_conjs,rdt_constrs,r_conjs);
+        prefix_print(DebugFile);
+      }
+      verify_tree();
+
+      beautify();
+      verify_tree();
+
+      rearrange();
+      verify_tree();
+
+      beautify();
+      verify_tree();
+
+      s_rdt_constrs = rdt_constrs;
+      if(pres_debug) {
+        fprintf(DebugFile, "\n=== In simplify, before DNFize ===\n");
+        prefix_print(DebugFile);
+      }
+      DNFize();
+      if(pres_debug) {
+        fprintf(DebugFile, "\n=== In simplify, after DNFize ===\n");
+        prefix_print(DebugFile);
+      }
+      verify_tree();
+
+
+      simplified_DNF->rm_redundant_inexact_conjs();
+      verify_tree();
+
+      if (rdt_conjs > 0 && !simplified_DNF->is_definitely_false() && simplified_DNF->length() > 1) {
+        simplified_DNF->rm_redundant_conjs(rdt_conjs-1);
+        verify_tree();
+      }
+      
+      if(pres_debug) {
+        fprintf(DebugFile, "\n=== Resulting Relation ===\n");
+        prefix_print(DebugFile);
+      }
+    }
+  }
+  else {
+    /* Reprocess DNF to get rid of redundant stuff */
+
+    if (rdt_constrs < 0) return;
+    simplified_DNF->rm_redundant_inexact_conjs();
+
+    if (rdt_conjs > r_conjs) {
+      if(pres_debug) 
+        fprintf(DebugFile,"=== Rel_Body::simplify() redundant CONJUNCTS ===\n");
+      simplified_DNF->rm_redundant_conjs(rdt_conjs-1);
+    }
+    if (rdt_constrs > 0 ) {
+      if(pres_debug) 
+        fprintf(DebugFile,"=== Rel_Body::simplify() redundant CONSTR-S ===\n");
+      s_rdt_constrs = rdt_constrs;
+      simplified_DNF->simplify();
+    }
+  }
+
+  r_conjs = rdt_conjs;
+
+  for(DNF_Iterator D(simplified_DNF); D.live(); D.next()) {
+    D.curr()->set_relation(this);
+    D.curr()->set_parent(this);
+  }
+}
+
+
+// ******************
+//  Query functions
+// ******************
+
+
+//
+// Check if relation has a single conjunct formula and return this conjunct.
+//
+Conjunct *Rel_Body::single_conjunct() {
+  simplify();
+  return simplified_DNF->single_conjunct();
+}
+
+bool Rel_Body::has_single_conjunct() {
+  simplify();
+  return simplified_DNF->has_single_conjunct();
+}
+
+//
+// Remove and return first conjunct
+//
+Conjunct *Rel_Body::rm_first_conjunct() {
+  simplify();
+  return simplified_DNF->rm_first_conjunct();
+}
+
+
+void Rel_Body::query_difference(Variable_ID v1, Variable_ID v2, coef_t &lowerBound, coef_t &upperBound, bool &guaranteed) {
+  simplify();
+
+  coef_t _lb, _ub;
+  int first = 1;
+  bool _g;
+  lowerBound = negInfinity;  // default values if no DNF's
+  upperBound = posInfinity;
+  guaranteed = 0;
+
+  for (DNF_Iterator D(simplified_DNF); D.live(); D.next()) {
+    (*D)->query_difference(v1, v2, _lb, _ub, _g);
+    if (first) {
+      lowerBound = _lb;
+      upperBound = _ub;
+      guaranteed = _g;
+      first = 0;
+    }
+    else {
+      guaranteed = guaranteed && _g;
+      lowerBound = min(lowerBound, _lb);
+      upperBound = max(upperBound, _ub);
+    }
+  }
+}
+
+
+void Rel_Body::query_variable_bounds(Variable_ID v, coef_t &lowerBound, coef_t &upperBound) {
+  simplify();
+
+  coef_t _lb, _ub;
+  int first = 1;
+  lowerBound = negInfinity;  // default values if no DNF's
+  upperBound = posInfinity;
+
+  for (DNF_Iterator D(simplified_DNF); D.live(); D.next()) {
+    (*D)->query_variable_bounds(v, _lb, _ub);
+    if (first) {
+      lowerBound = _lb;
+      upperBound = _ub;
+      first = 0;
+    }
+    else {
+      lowerBound = min(lowerBound, _lb);
+      upperBound = max(upperBound, _ub);
+    }
+  }
+}
+
+coef_t Rel_Body::query_variable_mod(Variable_ID v, coef_t factor) {
+  simplify();
+
+  bool first = true;
+  coef_t result;
+
+  for (DNF_Iterator D(simplified_DNF); D.live(); D.next()) {
+    coef_t t = (*D)->query_variable_mod(v, factor);
+    if (t == posInfinity)
+      return posInfinity;
+
+    if (first) {
+      result = t;
+      first = false;
+    }
+    else {
+      if (result != t)
+        return posInfinity;
+    }
+  }
+
+  return result;
+}
+
+
+
+//
+// Simplify formula if needed and return the resulting DNF.
+//
+DNF* Rel_Body::query_DNF() {
+  return(query_DNF(false,false));
+}
+
+DNF* Rel_Body::query_DNF(int rdt_conjs, int rdt_constrs) {
+  simplify(rdt_conjs, rdt_constrs);
+  return(simplified_DNF);
+}
+
+//
+// Other formula queries.
+//
+
+// Interpret UNKNOWN as true, then check satisfiability
+// i.e., check if the formula simplifies to FALSE, since the library
+// will never say that if the *known* constraints are unsatisfiable by 
+// themselves.
+bool Rel_Body::is_upper_bound_satisfiable() {
+  int tmp = s_rdt_constrs;
+  s_rdt_constrs = -1;
+  simplify();
+  s_rdt_constrs = tmp;
+  return(!simplified_DNF->is_definitely_false());
+}
+
+// Interpret UNKNOWN as false, then check satisfiability
+// i.e., check if there exist any exact conjuncts in the solution
+bool Rel_Body::is_lower_bound_satisfiable() {
+  int tmp = s_rdt_constrs;
+  s_rdt_constrs = -1;
+  simplify();
+  s_rdt_constrs = tmp;
+  for(DNF_Iterator d(simplified_DNF); d; d++)
+    if((*d)->is_exact()) return true;
+  return false;
+}
+
+bool Rel_Body::is_satisfiable() {
+  assert(is_lower_bound_satisfiable() == is_upper_bound_satisfiable());
+  return is_upper_bound_satisfiable();
+}
+
+// Check if we can easily determine if the formula evaluates to true.
+bool Rel_Body::is_obvious_tautology() {
+  int tmp = s_rdt_constrs;
+  s_rdt_constrs = 0;
+  simplify();
+  s_rdt_constrs = tmp;
+  return(simplified_DNF->is_definitely_true());
+}
+
+// Expensive check to determine if the formula evaluates to true.
+bool Rel_Body::is_definite_tautology() {
+  if(is_obvious_tautology()) return true;
+  Relation l =  Lower_Bound(Relation(*this,1));
+  return !(Complement(l).is_upper_bound_satisfiable());
+}
+
+bool Rel_Body::is_unknown() {
+  simplify();
+  return(has_single_conjunct() && single_conjunct()->is_unknown());
+}
+
+//
+// Get accuracy status of the relation
+//
+
+Rel_Unknown_Uses Rel_Body::unknown_uses() {
+  if (!is_simplified())
+    simplify();
+    
+  Rel_Unknown_Uses local_status=0; 
+  int n_conj=0;
+
+  for (DNF_Iterator c(simplified_DNF); c; c++) {
+    n_conj++;
+    if ((*c)->is_exact())
+      local_status |= no_u;
+    else if ((*c)->is_unknown())
+      local_status |= or_u;
+    else
+      local_status |= and_u;
+  }
+
+  if (n_conj == 0) {
+    assert(local_status == 0);
+    local_status = no_u;
+  }
+  assert(local_status);
+#if ! defined NDEBUG
+  Rel_Unknown_Uses impossible = (and_u | or_u);
+  assert( (local_status & impossible) != impossible);
+#endif
+
+  return local_status;
+}
+
+void Rel_Body::interpret_unknown_as_false() {
+  simplify();
+  simplified_DNF->remove_inexact_conj();  
+}
+       
+void Rel_Body::interpret_unknown_as_true() {
+  simplify();
+  for(DNF_Iterator d(simplified_DNF); d; d++)
+    (*d)->interpret_unknown_as_true();
+}
+       
+
+void Rel_Body::reverse_leading_dir_info() {
+  if (is_simplified()) {
+    for (DNF_Iterator c(simplified_DNF); c; c++)
+      (*c)->reverse_leading_dir_info();
+  }
+  else {
+    assert(!simplified_DNF);
+    assert(children().size() == 1);
+    children().front()->reverse_leading_dir_info();
+  }
+}
+
+//
+// Rel_Body::DNFize just DNF-izes its child node and calls verify
+//
+
+DNF* Rel_Body::DNFize() {
+#if defined(INCLUDE_COMPRESSION)
+  assert(!this->is_compressed());
+#endif
+  if (! simplified_DNF) {
+    simplified_DNF = children().remove_front()->DNFize();
+
+    int mua = max_shared_ufs_arity();
+    if (mua > 0) {
+      if (pres_debug) {
+        fprintf(DebugFile, "\n=== In DNFize, before LCDNF ===\n");
+        prefix_print(DebugFile);
+      }
+
+      simplified_DNF->make_level_carried_to(mua);
+    }
+
+    if(pres_debug) {
+      fprintf(DebugFile, "\n=== In DNFize, before verify ===\n");
+      prefix_print(DebugFile);
+    }
+
+    simplified_DNF->simplify();
+  }
+
+  assert(children().length() == 0);
+
+  return simplified_DNF;
+}
+
+void Rel_Body::make_level_carried_to(int level) {
+  if (!simplified_DNF) {
+    DNFize();
+  }
+
+  assert(simplified_DNF && children().empty());
+
+  simplified_DNF->make_level_carried_to(level);
+}
+
+//
+// if direction==0, move all conjuncts with >= level leading 0's to return
+//            else  move all conjuncts with level-1 0's followed by
+//      the appropriate signed difference to returned Relation
+//
+
+Relation Rel_Body::extract_dnf_by_carried_level(int level, int direction) {
+  if (!simplified_DNF) {
+    DNFize();
+  }
+
+  assert(simplified_DNF && children().empty());
+
+  simplified_DNF->make_level_carried_to(level);
+
+  Relation extracted(n_inp(), n_out());
+  extracted.copy_names(*this);
+  assert(extracted.rel_body->children().empty());
+  assert(extracted.rel_body->simplified_DNF == NULL);
+  extracted.rel_body->simplified_DNF = new DNF;
+  extracted.rel_body->Symbolic = Symbolic;
+
+  DNF *remaining = new DNF;
+  Conjunct *curr;
+
+  for (curr = simplified_DNF->rm_first_conjunct();
+       curr;
+       curr = simplified_DNF->rm_first_conjunct()) {
+    assert(curr->guaranteed_leading_0s >= level || curr->guaranteed_leading_0s == curr->possible_leading_0s);
+    assert(curr->possible_leading_0s >= 0);
+
+    curr->assert_leading_info();
+
+    if ((direction == 0 && curr->guaranteed_leading_0s >= level) ||
+        (curr->guaranteed_leading_0s == level-1 &&
+         curr->leading_dir_valid_and_known() &&
+         curr->leading_dir * direction > 0)) {
+      extracted.rel_body->simplified_DNF->add_conjunct(curr);
+    }
+    else {
+      remaining->add_conjunct(curr);
+    }
+  }
+  delete simplified_DNF;
+  simplified_DNF = remaining;
+
+#if ! defined NDEBUG
+  for (DNF_Iterator rc(simplified_DNF); rc; rc++)
+    (*rc)->assert_leading_info();
+
+  for (DNF_Iterator ec(extracted.rel_body->simplified_DNF); ec; ec++)
+    (*ec)->assert_leading_info();
+#endif
+
+  finalize();
+  extracted.finalize();
+  return extracted;
+}
+
+//Compress/uncompress functions
+
+bool Rel_Body::is_compressed() {
+#if defined(INCLUDE_COMPRESSION)
+  if(is_simplified()) {
+    for(DNF_Iterator p(simplified_DNF); p.live(); p.next()) {
+      if(p.curr()->is_compressed())
+        return true;
+    }
+  }
+  return false;
+#else
+  return true; // This allows is_compressed assertions to work
+#endif
+}
+
+void Rel_Body::compress() {
+#if !defined(INCLUDE_COMPRESSION)
+  return;
+#else
+  if (status == compressed)
+    return;
+  if (pres_debug)
+    fprintf(DebugFile,">>> Compressing relation %p\n",this);
+  simplify();
+  for(DNF_Iterator p(simplified_DNF); p.live(); p.next()) {
+    p.curr()->compress();
+    status = compressed;
+  }
+#endif
+}
+
+void Rel_Body::uncompress() {
+#if !defined(INCLUDE_COMPRESSION)
+  return;
+#else
+  if (pres_debug)
+    fprintf(DebugFile,"<<< Uncompressing relation %p\n",this);
+  assert(is_simplified());
+  for(DNF_Iterator p(simplified_DNF); p.live(); p.next()) {
+    p.curr()->uncompress();
+    status = uncompressed;
+  }
+#endif
+}
+
+}
diff --git a/lib/omega/src/RelVar.cc b/lib/omega/src/RelVar.cc
new file mode 100644
index 0000000..d9b977c
--- /dev/null
+++ b/lib/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/lib/omega/src/Relation.cc b/lib/omega/src/Relation.cc
new file mode 100644
index 0000000..1cca43a
--- /dev/null
+++ b/lib/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/lib/omega/src/Relations.cc b/lib/omega/src/Relations.cc
new file mode 100644
index 0000000..d7dbe86
--- /dev/null
+++ b/lib/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/lib/omega/src/basic/ConstString.cc b/lib/omega/src/basic/ConstString.cc
new file mode 100644
index 0000000..7d2ec1e
--- /dev/null
+++ b/lib/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/lib/omega/src/basic/Link.cc b/lib/omega/src/basic/Link.cc
new file mode 100644
index 0000000..50b9441
--- /dev/null
+++ b/lib/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/lib/omega/src/closure.cc b/lib/omega/src/closure.cc
new file mode 100644
index 0000000..416a3e7
--- /dev/null
+++ b/lib/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/lib/omega/src/evac.cc b/lib/omega/src/evac.cc
new file mode 100644
index 0000000..ff872c9
--- /dev/null
+++ b/lib/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/lib/omega/src/farkas.cc b/lib/omega/src/farkas.cc
new file mode 100644
index 0000000..1b3ef87
--- /dev/null
+++ b/lib/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/lib/omega/src/hull_legacy.cc b/lib/omega/src/hull_legacy.cc
new file mode 100755
index 0000000..a59d34f
--- /dev/null
+++ b/lib/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/lib/omega/src/hull_simple.cc b/lib/omega/src/hull_simple.cc
new file mode 100755
index 0000000..62dcb26
--- /dev/null
+++ b/lib/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/lib/omega/src/omega_core/oc.cc b/lib/omega/src/omega_core/oc.cc
new file mode 100644
index 0000000..0dc9b49
--- /dev/null
+++ b/lib/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/lib/omega/src/omega_core/oc_eq.cc b/lib/omega/src/omega_core/oc_eq.cc
new file mode 100644
index 0000000..dc595ea
--- /dev/null
+++ b/lib/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/lib/omega/src/omega_core/oc_exp_kill.cc b/lib/omega/src/omega_core/oc_exp_kill.cc
new file mode 100644
index 0000000..fdb2718
--- /dev/null
+++ b/lib/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/lib/omega/src/omega_core/oc_global.cc b/lib/omega/src/omega_core/oc_global.cc
new file mode 100644
index 0000000..17d8a0c
--- /dev/null
+++ b/lib/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/lib/omega/src/omega_core/oc_print.cc b/lib/omega/src/omega_core/oc_print.cc
new file mode 100644
index 0000000..7934713
--- /dev/null
+++ b/lib/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/lib/omega/src/omega_core/oc_problems.cc b/lib/omega/src/omega_core/oc_problems.cc
new file mode 100644
index 0000000..8b6e04c
--- /dev/null
+++ b/lib/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/lib/omega/src/omega_core/oc_query.cc b/lib/omega/src/omega_core/oc_query.cc
new file mode 100644
index 0000000..528b297
--- /dev/null
+++ b/lib/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/lib/omega/src/omega_core/oc_quick_kill.cc b/lib/omega/src/omega_core/oc_quick_kill.cc
new file mode 100644
index 0000000..1b988d4
--- /dev/null
+++ b/lib/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/lib/omega/src/omega_core/oc_simple.cc b/lib/omega/src/omega_core/oc_simple.cc
new file mode 100644
index 0000000..0e492db
--- /dev/null
+++ b/lib/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/lib/omega/src/omega_core/oc_solve.cc b/lib/omega/src/omega_core/oc_solve.cc
new file mode 100644
index 0000000..c25b6d0
--- /dev/null
+++ b/lib/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/lib/omega/src/omega_core/oc_util.cc b/lib/omega/src/omega_core/oc_util.cc
new file mode 100644
index 0000000..a7d21be
--- /dev/null
+++ b/lib/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/lib/omega/src/pres_beaut.cc b/lib/omega/src/pres_beaut.cc
new file mode 100644
index 0000000..c23962a
--- /dev/null
+++ b/lib/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/lib/omega/src/pres_cnstr.cc b/lib/omega/src/pres_cnstr.cc
new file mode 100644
index 0000000..a8ebd15
--- /dev/null
+++ b/lib/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/lib/omega/src/pres_col.cc b/lib/omega/src/pres_col.cc
new file mode 100644
index 0000000..1569116
--- /dev/null
+++ b/lib/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/lib/omega/src/pres_conj.cc b/lib/omega/src/pres_conj.cc
new file mode 100644
index 0000000..f3f458d
--- /dev/null
+++ b/lib/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/lib/omega/src/pres_decl.cc b/lib/omega/src/pres_decl.cc
new file mode 100644
index 0000000..f5ac312
--- /dev/null
+++ b/lib/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/lib/omega/src/pres_dnf.cc b/lib/omega/src/pres_dnf.cc
new file mode 100644
index 0000000..c9fd7e6
--- /dev/null
+++ b/lib/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/lib/omega/src/pres_form.cc b/lib/omega/src/pres_form.cc
new file mode 100644
index 0000000..82b710b
--- /dev/null
+++ b/lib/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/lib/omega/src/pres_gen.cc b/lib/omega/src/pres_gen.cc
new file mode 100644
index 0000000..0f05d40
--- /dev/null
+++ b/lib/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/lib/omega/src/pres_logic.cc b/lib/omega/src/pres_logic.cc
new file mode 100644
index 0000000..8ee90f1
--- /dev/null
+++ b/lib/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/lib/omega/src/pres_print.cc b/lib/omega/src/pres_print.cc
new file mode 100644
index 0000000..4f2cd0d
--- /dev/null
+++ b/lib/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/lib/omega/src/pres_quant.cc b/lib/omega/src/pres_quant.cc
new file mode 100644
index 0000000..5483bad
--- /dev/null
+++ b/lib/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/lib/omega/src/pres_rear.cc b/lib/omega/src/pres_rear.cc
new file mode 100644
index 0000000..508959d
--- /dev/null
+++ b/lib/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/lib/omega/src/pres_subs.cc b/lib/omega/src/pres_subs.cc
new file mode 100644
index 0000000..9854b09
--- /dev/null
+++ b/lib/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/lib/omega/src/pres_var.cc b/lib/omega/src/pres_var.cc
new file mode 100644
index 0000000..0ec406f
--- /dev/null
+++ b/lib/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/lib/omega/src/reach.cc b/lib/omega/src/reach.cc
new file mode 100644
index 0000000..6569edb
--- /dev/null
+++ b/lib/omega/src/reach.cc
@@ -0,0 +1,211 @@
+#include <omega.h>
+#include <omega/Relations.h>
+#include <basic/DynamicArray.h>
+#include <omega/reach.h>
+
+namespace omega {
+
+typedef DynamicArray1<Relation> Rel_Array1;
+typedef DynamicArray2<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
diff --git a/lib/rosecg/CMakeLists.txt b/lib/rosecg/CMakeLists.txt
new file mode 100644
index 0000000..610bc50
--- /dev/null
+++ b/lib/rosecg/CMakeLists.txt
@@ -0,0 +1,18 @@
+set(CODEGEN_ROSE_SRC
+    src/CG_roseBuilder.cc
+    src/CG_roseRepr.cc
+    src/rose_attributes.cc
+    )
+
+include_directories(
+    include
+    ${OMEGA_INC}
+    ${ROSEHOME}/include
+    ${ROSEHOME}/include/rose
+    ${BOOSTHOME}/include
+    )
+
+add_library(rosecg ${CODEGEN_ROSE_SRC})
+
+install(TARGETS rosecg
+        DESTINATION lib)
diff --git a/lib/rosecg/include/CG_roseBuilder.h b/lib/rosecg/include/CG_roseBuilder.h
new file mode 100644
index 0000000..bb622c7
--- /dev/null
+++ b/lib/rosecg/include/CG_roseBuilder.h
@@ -0,0 +1,108 @@
+#ifndef CG_roseBuilder_h
+#define CG_roseBuilder_h
+
+#include <basic/Tuple.h>
+#include "rose_attributes.h"
+#include <code_gen/CG_outputBuilder.h>
+#include "CG_roseRepr.h"
+#include <string>
+
+namespace omega {
+
+class CG_roseBuilder : public CG_outputBuilder { 
+public:
+  CG_roseBuilder(int isFortran, SgGlobal* global, SgGlobal* global_scope, SgSymbolTable* symtab1, SgSymbolTable* symtab2,  SgNode* root);
+  ~CG_roseBuilder();
+   
+  //! substitute variables in stmt
+   CG_outputRepr *CreateSubstitutedStmt(int indent, CG_outputRepr *stmt,
+                                               const std::vector<std::string> &vars,
+                                               std::vector<CG_outputRepr *> &subs) const;
+
+
+  
+  //! assignment generation
+   CG_outputRepr* CreateAssignment(int indent, CG_outputRepr* lhs,
+                                          CG_outputRepr* rhs) const;
+
+  //! function invocation generation
+    CG_outputRepr* CreateInvoke(const std::string &funcName,
+    		std::vector<CG_outputRepr *> &argList) const;
+  
+  //! comment generation
+   CG_outputRepr* CreateComment(int indent, const std::string &commentText) const;
+  //! Attribute generation
+    CG_outputRepr* CreateAttribute(CG_outputRepr  *control,
+                                          const std::string &commentText) const;
+  //! Pragma Attribute
+  CG_outputRepr* CreatePragmaAttribute(CG_outputRepr *scopeStmt, int looplevel,
+                                          const std::string &pragmaText) const;
+  
+  //! Prefetch Attribute
+  CG_outputRepr* CreatePrefetchAttribute(CG_outputRepr *scopeStmt, int looplevel,
+                                          const std::string &arrName, int hint) const;
+
+  //! if stmt gen operations
+   CG_outputRepr* CreateIf(int indent, CG_outputRepr* guardCondition,
+                                  CG_outputRepr* true_stmtList, CG_outputRepr* false_stmtList) const;
+   
+  //! inductive variable generation, to be used in CreateLoop as control
+   CG_outputRepr* CreateInductive(CG_outputRepr* index,
+                                         CG_outputRepr* lower,
+                                         CG_outputRepr* upper,
+                                         CG_outputRepr* step) const;
+
+  //! loop stmt generation
+   CG_outputRepr* CreateLoop(int indent, CG_outputRepr* control,
+                                    CG_outputRepr* stmtList) const;
+
+   CG_outputRepr* CreateInt(int num ) const;
+   bool isInteger(CG_outputRepr *op) const;
+   CG_outputRepr* CreateIdent(const std::string &varName) const;
+
+   //! binary arithmetic operations
+   CG_outputRepr* CreatePlus(CG_outputRepr* lop, CG_outputRepr* rop) const;
+   CG_outputRepr* CreateMinus(CG_outputRepr* lop, CG_outputRepr* rop) const;
+   CG_outputRepr* CreateTimes(CG_outputRepr* lop, CG_outputRepr* rop) const;
+   CG_outputRepr* CreateIntegerFloor(CG_outputRepr* lop, CG_outputRepr* rop) const;
+   CG_outputRepr* CreateIntegerMod(CG_outputRepr* lop, CG_outputRepr* rop) const;
+
+  //! binary logical operations
+   CG_outputRepr* CreateAnd(CG_outputRepr* lop, CG_outputRepr* rop) const;
+
+  //---------------------------------------------------------------------------
+  // binary relational operations
+  //---------------------------------------------------------------------------
+  // CG_outputRepr* CreateGE(CG_outputRepr*, CG_outputRepr*) const;
+   CG_outputRepr* CreateLE(CG_outputRepr* lop, CG_outputRepr* rop) const;
+   CG_outputRepr* CreateEQ(CG_outputRepr* lop, CG_outputRepr* rop) const;
+     
+  //---------------------------------------------------------------------------
+  // stmt list gen operations
+  //---------------------------------------------------------------------------
+   CG_outputRepr*
+    StmtListAppend(CG_outputRepr* list1, CG_outputRepr* list2) const;
+
+   CG_outputRepr* CreateDim3(const char* varName, CG_outputRepr* arg1, CG_outputRepr*  arg2, CG_outputRepr* arg3 = NULL) const;
+
+   // Manu:: added for fortran support
+   bool isInputFortran() const;
+
+private:
+  SgSymbolTable *symtab_;
+  SgSymbolTable *symtab2_;
+  SgNode* root_;
+  SgGlobal* global_;
+  SgGlobal* global_scope;
+  int isFortran; // Manu:: added for fortran support
+};
+
+extern char *k_ocg_comment;
+std::vector<SgVarRefExp *>substitute(SgNode *tnl, const SgVariableSymbol *sym, SgExpression *expr,SgNode* root) ;
+
+
+
+
+} // namespace
+
+#endif
diff --git a/lib/rosecg/include/CG_roseRepr.h b/lib/rosecg/include/CG_roseRepr.h
new file mode 100644
index 0000000..28553e7
--- /dev/null
+++ b/lib/rosecg/include/CG_roseRepr.h
@@ -0,0 +1,46 @@
+#ifndef CG_roseRepr_h
+#define CG_roseRepr_h
+
+#include <code_gen/CG_outputRepr.h>
+#include "rose.h"
+
+namespace omega {
+
+class CG_roseRepr : public CG_outputRepr {
+  friend class CG_roseBuilder;
+public:
+  CG_roseRepr();
+  CG_roseRepr(SgNode *tnl);
+  CG_roseRepr(SgExpression *exp);
+  CG_roseRepr(SgStatementPtrList* stmtlist);
+
+  ~CG_roseRepr();
+  CG_outputRepr *clone() const;
+  void clear();
+
+  SgNode* GetCode() const;
+  SgStatementPtrList* GetList() const;
+  SgExpression *GetExpression() const;
+
+
+
+
+  //---------------------------------------------------------------------------
+  // Dump operations
+  //---------------------------------------------------------------------------
+  void Dump() const;
+private:
+  // only one of _tnl and _op would be active at any time, depending on
+  // whether it is building a statement list or an expression tree
+  SgNode  *tnl_;
+  SgExpression  *op_;
+  SgStatementPtrList *list_;
+  void DumpFileHelper(SgNode* node, FILE* fp) const; 
+  //operand op_;
+};
+
+
+
+} // namespace
+
+#endif
diff --git a/lib/rosecg/include/rose_attributes.h b/lib/rosecg/include/rose_attributes.h
new file mode 100644
index 0000000..9766f52
--- /dev/null
+++ b/lib/rosecg/include/rose_attributes.h
@@ -0,0 +1,91 @@
+#ifndef ROSE_ATTRIBUTES_HH
+#define ROSE_ATTRIBUTES_HH
+
+#include "rose.h"
+#include <algorithm>
+#include <string>
+#include <vector>
+
+namespace omega {
+
+class CodeInsertion;
+
+typedef std::vector<CodeInsertion*> CodeInsertionPtrList;
+typedef std::vector<CodeInsertion*>::iterator CodeInsertionPtrListItr;
+
+class CodeInsertion {
+public:
+	int loop_level;
+	bool marked;
+	CodeInsertion(int looplevel) { this->loop_level = looplevel; marked = false; }
+	~CodeInsertion() {}
+	virtual SgStatement* getStatement(SgScopeStatement* scopeStmt = NULL) = 0;
+};
+
+class PragmaInsertion : public CodeInsertion {
+private:
+	std::string name;
+public:
+	PragmaInsertion(int loop_level, const std::string &pragma) : CodeInsertion(loop_level) { this->name = std::string(pragma); }
+	~PragmaInsertion() { }
+	virtual SgStatement* getStatement(SgScopeStatement* scopeStmt = NULL);
+};
+
+class MMPrefetchInsertion : public CodeInsertion {
+private:
+	std::string arrName;
+	std::vector<std::string*> indecies;
+	std::vector<int> offsets;
+	int indexCount;
+	int cacheHint;
+	void initialize(const std::string& arrName, int hint);
+	void addDim(int offset);
+	void addDim(int offset, const std::string& indexer);
+	SgExpression* buildArrArg(SgScopeStatement* scopeStmt);
+	SgExpression* makeIndexExp(int dim, SgScopeStatement* scopeStmt);
+public:
+	MMPrefetchInsertion(int loop_level, const std::string &arr, int hint) : CodeInsertion(loop_level)
+		{ this->initialize(arr, hint); }
+	~MMPrefetchInsertion() { }
+	virtual SgStatement* getStatement(SgScopeStatement* scopeStmt = NULL);
+};
+
+class CodeInsertionAttribute : public AstAttribute {
+private:
+	std::vector<CodeInsertion*> code_insertions;
+public:
+	CodeInsertionAttribute() { code_insertions = std::vector<CodeInsertion*>(); }
+	~CodeInsertionAttribute() {}
+	
+	void add(CodeInsertion* ci) { code_insertions.push_back(ci); }
+	CodeInsertionPtrListItr begin() { return code_insertions.begin(); }
+	CodeInsertionPtrListItr end() { return code_insertions.end(); }
+	void remove(CodeInsertion* ci) { std::remove(code_insertions.begin(), code_insertions.end(), ci); }
+	int countCodeInsertions() { return code_insertions.size(); }
+};
+
+struct CodeInsertionMark {
+public:
+	SgStatement* stmt;
+	CodeInsertion* ci;
+};
+
+class CodeInsertionVisitor : public AstPrePostProcessing {
+private:
+	int loop_level;
+	std::vector<CodeInsertionMark*> ci_marks;
+	void markStmt(SgStatement* stmt, CodeInsertion* ci);
+public:
+	void initialize();
+	virtual void preOrderVisit(SgNode* n);
+	virtual void postOrderVisit(SgNode* n);
+	void insertCode();
+};
+
+void postProcessRoseCodeInsertion(SgProject* proj);
+void copyAttributes(SgNode* s, SgNode* d);
+CodeInsertionAttribute* getOrCreateCodeInsertionAttribute(SgNode* node);
+
+}
+
+#endif
diff --git a/lib/rosecg/src/CG_roseBuilder.cc b/lib/rosecg/src/CG_roseBuilder.cc
new file mode 100644
index 0000000..09370a4
--- /dev/null
+++ b/lib/rosecg/src/CG_roseBuilder.cc
@@ -0,0 +1,1093 @@
+/*****************************************************************************
+ Copyright (C) 2008 University of Southern California
+ Copyright (C) 2009-2010 University of Utah
+ All Rights Reserved.
+
+ Purpose:
+ generate suif code for omega
+
+ Notes:
+
+ History:
+ 02/01/06 created by Chun Chen
+ *****************************************************************************/
+
+#include <stack>
+#include "CG_roseBuilder.h"
+#include <string>
+
+struct ir_error: public std::runtime_error {
+	ir_error(const std::string &msg) :
+			std::runtime_error(msg) {
+	}
+};
+
+using namespace SageBuilder;
+using namespace SageInterface;
+using namespace OmpSupport;
+
+namespace omega {
+
+//-----------------------------------------------------------------------------
+// make suif initilization happy
+//-----------------------------------------------------------------------------
+char *k_ocg_comment;
+
+CG_roseBuilder::CG_roseBuilder(int is_fortran, SgGlobal* global, SgGlobal* firstScope,
+		SgSymbolTable* symtab, SgSymbolTable* symtab2, SgNode* root) :
+		isFortran(is_fortran), global_(global), global_scope(firstScope), symtab_(symtab), symtab2_(
+				symtab2), root_(root) {
+}
+
+
+CG_roseBuilder::~CG_roseBuilder() {
+}
+
+// Manu:: returns true if input is in fortran, else returns false
+bool CG_roseBuilder::isInputFortran() const{
+	if (isFortran)
+		return true;
+	else
+		return false;
+}
+
+//-----------------------------------------------------------------------------
+// place holder generation
+//-----------------------------------------------------------------------------
+CG_outputRepr* CG_roseBuilder::CreateSubstitutedStmt(int, CG_outputRepr *stmt,
+		const std::vector<std::string> &vars, std::vector<CG_outputRepr*> &subs) const {
+
+	SgStatementPtrList* list = static_cast<CG_roseRepr *>(stmt)->list_;
+	SgNode *tnl;
+	SgStatement* statement;
+	if (list != NULL) {
+		delete stmt;
+		for (int i = 0; i < subs.size(); i++) {
+                  if (subs[i] == NULL)
+                        continue;
+
+			CG_roseRepr *repr = static_cast<CG_roseRepr*>(subs[i]);
+			SgExpression* op = repr->op_;
+
+			for (SgStatementPtrList::iterator it = (*list).begin();
+					it != (*list).end(); it++) {
+				statement = (*it);
+				tnl = isSgNode(statement);
+
+				int j;
+				int not_in_symtab_;
+
+				not_in_symtab_ = 0;
+
+				SgVariableSymbol *vs = symtab_->find_variable(
+						SgName(vars[i].c_str()));
+
+				if (vs == NULL) {
+
+					not_in_symtab_ = 1;
+
+					vs = symtab2_->find_variable(SgName(vars[i].c_str()));
+				}
+				if (vs != NULL) {
+
+					std::vector<SgVarRefExp *> array = substitute(tnl,
+							(const SgVariableSymbol*) vs, op, root_);
+					for (std::vector<SgVarRefExp *>::iterator it =
+							array.begin(); it != array.end(); it++) {
+
+						if (isSgVarRefExp(op)) {
+							if (strcmp(
+									isSgVarRefExp(op)->get_symbol()->get_name().getString().c_str(),
+									vs->get_name().getString().c_str())) {
+
+								(*it)->set_symbol(
+										isSgVarRefExp(op)->get_symbol());
+
+							}
+						} else if (isSgExpression(op)) {
+
+							if (isSgBinaryOp((*it)->get_parent()))
+								isSgBinaryOp((*it)->get_parent())->replace_expression(
+										*it, op);
+							else if (isSgUnaryOp((*it)->get_parent()))
+								isSgUnaryOp((*it)->get_parent())->replace_expression(
+										*it, op);
+							else if (isSgExprListExp((*it)->get_parent()))
+								isSgExprListExp((*it)->get_parent())->replace_expression(
+										*it, op);
+							else
+								throw ir_error("unrecognized expression type");
+						}
+
+					}
+				}
+
+			}
+
+			delete repr;
+			subs[i] = NULL;
+
+			if (subs[i] != NULL)
+				throw ir_error("not freed properly");
+
+		}
+
+		return new CG_roseRepr(list);
+
+	} else {
+		tnl = static_cast<CG_roseRepr *>(stmt)->tnl_;
+
+		if (tnl == NULL)
+			throw ir_error("both list and tnl are null!!");
+
+		delete stmt;
+		int j;
+		int not_in_symtab_;
+	 for (int i = 0; i < subs.size(); i++) {
+                if (subs[i] == NULL)
+                       continue;
+			not_in_symtab_ = 0;
+
+			
+			CG_roseRepr *repr = static_cast<CG_roseRepr*>(subs[i]);
+			SgExpression* op = repr->op_;
+			delete repr;
+			subs[i] = NULL;
+
+			SgVariableSymbol *vs = symtab_->find_variable(
+					SgName(vars[i].c_str()));
+
+			if (vs == NULL) {
+
+				not_in_symtab_ = 1;
+
+				vs = symtab2_->find_variable(SgName(vars[i].c_str()));
+			}
+			if (vs != NULL) {
+				std::vector<SgVarRefExp *> array = substitute(tnl, vs, op,
+						root_);
+
+				if (not_in_symtab_ && isSgVarRefExp(op)) {
+					if (strcmp(
+							isSgVarRefExp(op)->get_symbol()->get_name().getString().c_str(),
+							vs->get_name().getString().c_str())) {
+					}
+				}
+				
+				for (std::vector<SgVarRefExp *>::iterator j = array.begin();
+						j != array.end(); j++) {
+
+					if (isSgVarRefExp(op)) {
+						if (strcmp(
+								isSgVarRefExp(op)->get_symbol()->get_name().getString().c_str(),
+								vs->get_name().getString().c_str())) {
+							(*j)->set_symbol(isSgVarRefExp(op)->get_symbol());
+
+						}
+					} else if (isSgExpression(op)) {
+
+						if (isSgBinaryOp((*j)->get_parent()))
+							isSgBinaryOp((*j)->get_parent())->replace_expression(
+									*j, op);
+						else if (isSgUnaryOp((*j)->get_parent()))
+							isSgUnaryOp((*j)->get_parent())->replace_expression(
+									*j, op);
+						else if (isSgExprListExp((*j)->get_parent())) { // Manu:: fortran indices are stored this way
+							isSgExprListExp((*j)->get_parent())->replace_expression(*j, op);
+						}
+						else
+							throw ir_error("unrecognized expression type");
+
+					}
+
+				}
+			}
+		}
+		return new CG_roseRepr(tnl);
+	}
+
+}
+
+//-----------------------------------------------------------------------------
+// assignment generation
+//-----------------------------------------------------------------------------
+CG_outputRepr* CG_roseBuilder::CreateAssignment(int, CG_outputRepr *lhs,
+		CG_outputRepr *rhs) const {
+	if (lhs == NULL || rhs == NULL) {
+		fprintf(stderr, "Code generation: Missing lhs or rhs\n");
+		return NULL;
+	}
+
+	SgExpression* src = static_cast<CG_roseRepr*>(rhs)->op_;
+	SgExpression* dst = static_cast<CG_roseRepr*>(lhs)->op_;
+
+	SgExprStatement* ins = buildAssignStatement(dst, src);
+	src->set_parent(ins);
+	dst->set_parent(ins);
+
+	SgStatementPtrList* new_list = new SgStatementPtrList;
+
+	(*new_list).push_back(isSgStatement(ins));
+
+	delete lhs;
+	delete rhs;
+
+	return new CG_roseRepr(new_list);
+
+}
+
+//-----------------------------------------------------------------------------
+// function invocation generation
+//-----------------------------------------------------------------------------
+CG_outputRepr* CG_roseBuilder::CreateInvoke(const std::string &fname,
+		std::vector<CG_outputRepr *> &list) const {
+
+	if (fname == std::string("max") || fname == std::string("min")) {
+		if (list.size() == 0) {
+			return NULL;
+		} else if (list.size() == 1) {
+			 return list[0];
+		} else {
+			 int last = list.size() - 1;
+			SgExpression* op2 = static_cast<CG_roseRepr*>(list[last])->op_;
+			delete list[last];
+		    list.erase(list.end()-1);
+			CG_roseRepr *repr = static_cast<CG_roseRepr*>(CreateInvoke(fname,
+					list));
+			SgExpression* op1 = repr->op_;
+
+
+			SgExpression *ins;
+			SgExprListExp* arg_list = buildExprListExp();
+			appendExpression(arg_list, op1);
+			appendExpression(arg_list, op2);
+			SgVarRefExp* opaque_var;
+
+
+			if (fname == std::string("max")) {
+				opaque_var = buildOpaqueVarRefExp("__rose_gt", global_);
+				ins = isSgExpression(buildFunctionCallExp(opaque_var, arg_list));
+
+				// Manu:: fortran support
+				if (isInputFortran()) {
+					SgName fName("merge");
+					SgTypeInt *retType = buildIntType();
+
+					SgExpression *cond = static_cast<CG_roseRepr *>(CreateLE(new CG_roseRepr(op2), new CG_roseRepr(op1)))->op_;
+		            appendExpression(arg_list, cond);
+					ins = isSgExpression(buildFunctionCallExp(fName, retType, arg_list, global_));
+				}
+
+			} else {
+				opaque_var = buildOpaqueVarRefExp("__rose_lt", global_);
+				ins = isSgExpression(buildFunctionCallExp(opaque_var, arg_list));
+
+				// Manu:: fortran support
+				if (isInputFortran()) {
+					SgName fName("merge");
+					SgTypeInt *retType = buildIntType();
+
+					SgExpression *cond = static_cast<CG_roseRepr *>(CreateLE(new CG_roseRepr(op1), new CG_roseRepr(op2)))->op_;
+		            appendExpression(arg_list, cond);
+					ins = isSgExpression(buildFunctionCallExp(fName, retType, arg_list, global_));
+				}
+
+			}
+
+			repr->op_ = ins;
+			return repr;
+		}
+	} else {
+		fprintf(stderr,
+				"Code generation: invoke function io_call not implemented\n");
+		return NULL;
+	}
+
+}
+
+//-----------------------------------------------------------------------------
+// comment generation
+//-----------------------------------------------------------------------------
+CG_outputRepr* CG_roseBuilder::CreateComment(int,
+		const std::string &commentText) const {
+	if (commentText == std::string("")) {
+		return NULL;
+	}
+
+	SgLocatedNode *tnl = new SgLocatedNode();
+	buildComment(tnl, "//omega_comment: " + commentText);
+
+	return new CG_roseRepr(isSgNode(tnl));
+
+}
+
+//-----------------------------------------------------------------------------
+// if stmt gen operations
+//-----------------------------------------------------------------------------
+CG_outputRepr* CG_roseBuilder::CreateIf(int, CG_outputRepr *guardList,
+		CG_outputRepr *true_stmtList, CG_outputRepr *false_stmtList) const {
+
+	if (true_stmtList == NULL && false_stmtList == NULL) {
+		delete guardList;
+		return NULL;
+	} else if (guardList == NULL) {
+		return StmtListAppend(true_stmtList, false_stmtList);
+	}
+
+	SgExpression* header = static_cast<CG_roseRepr*>(guardList)->op_;
+
+	SgStatementPtrList *then_part1, *else_part1;
+	SgStatement* then_part;
+	SgStatement* else_part;
+	SgBasicBlock* then_part2;
+	SgBasicBlock* else_part2;
+	if (true_stmtList != NULL) {
+		then_part1 = static_cast<CG_roseRepr*>(true_stmtList)->list_;
+		if (then_part1 != NULL) {
+			then_part = *((*then_part1).begin());
+
+			if ((*then_part1).size() > 1) {
+				then_part2 = buildBasicBlock();
+				for (SgStatementPtrList::iterator it = (*then_part1).begin();
+						it != (*then_part1).end(); it++) {
+					then_part2->append_statement(*it);
+
+				}
+				then_part = isSgStatement(then_part2);
+
+			}
+		} else {
+			// Manu:: fortran support (if part)
+			if (isInputFortran()) {
+				then_part2 = buildBasicBlock();
+				then_part2->append_statement(isSgStatement(static_cast<CG_roseRepr*>(true_stmtList)->tnl_));
+				then_part = isSgStatement(then_part2);
+			} else
+				then_part = isSgStatement(static_cast<CG_roseRepr*>(true_stmtList)->tnl_);
+		}
+	} else {
+		then_part = NULL;
+	}
+	if (false_stmtList != NULL) {
+		else_part1 = static_cast<CG_roseRepr*>(false_stmtList)->list_;
+		if (else_part1 != NULL) {
+			else_part = *((*else_part1).begin());
+			if ((*else_part1).size() > 1) {
+				else_part2 = buildBasicBlock();
+				for (SgStatementPtrList::iterator it2 = (*else_part1).begin();
+						it2 != (*else_part1).end(); it2++) {
+					else_part2->append_statement(*it2);
+
+				}
+				else_part = isSgStatement(else_part2);
+
+			}
+		} else {
+			// Manu:: fortran support (if part)
+			if (isInputFortran()) {
+				else_part2 = buildBasicBlock();
+				else_part2->append_statement(isSgStatement(static_cast<CG_roseRepr*>(false_stmtList)->tnl_));
+				else_part = isSgStatement(else_part2);
+			} else
+				else_part = isSgStatement(static_cast<CG_roseRepr*>(false_stmtList)->tnl_);
+		}
+	} else {
+		else_part = NULL;
+	}
+
+	SgIfStmt* ti = buildIfStmt(header, isSgStatement(then_part),
+			isSgStatement(else_part));
+
+	delete guardList;
+	delete true_stmtList;
+	delete false_stmtList;
+
+	return new CG_roseRepr(isSgNode(ti));
+
+}
+
+//-----------------------------------------------------------------------------
+// inductive variable generation, to be used in CreateLoop as control
+//-----------------------------------------------------------------------------
+CG_outputRepr* CG_roseBuilder::CreateInductive(CG_outputRepr *index,
+		CG_outputRepr *lower, CG_outputRepr *upper, CG_outputRepr *step) const {
+
+	if (index == NULL || lower == NULL || upper == NULL) {
+		fprintf(stderr,
+				"Code generation: something wrong in CreateInductive\n");
+		return NULL;
+	}
+
+	if (step == NULL)
+		step = new CG_roseRepr(isSgExpression(buildIntVal(1)));
+
+	SgVarRefExp *index_sym = isSgVarRefExp(
+			static_cast<CG_roseRepr*>(index)->op_);
+	SgExpression* lower_bound = static_cast<CG_roseRepr*>(lower)->op_;
+	SgExpression* upper_bound = static_cast<CG_roseRepr*>(upper)->op_;
+	SgExpression* step_size = static_cast<CG_roseRepr*>(step)->op_;
+
+	SgStatement* for_init_stmt = buildAssignStatement(index_sym, lower_bound);
+	SgLessOrEqualOp* cond = buildLessOrEqualOp(index_sym, upper_bound);
+	SgExprStatement* test = buildExprStatement(cond);
+	SgPlusAssignOp* increment = buildPlusAssignOp(index_sym, step_size);
+	SgForStatement *for_stmt = buildForStatement(for_init_stmt,
+			isSgStatement(test), increment, NULL);
+
+	delete index;
+	delete lower;
+	delete upper;
+	delete step;
+
+
+	// Manu
+	if (isInputFortran()) {
+        SgFortranDo * forStmt=new SgFortranDo(Sg_File_Info::generateDefaultFileInfoForTransformationNode());
+        forStmt->set_has_end_statement(true);
+        forStmt->set_bound(upper_bound);
+        forStmt->set_increment(step_size);
+        forStmt->set_initialization(isSgExprStatement(for_init_stmt)->get_expression());
+        return new CG_roseRepr(isSgNode(forStmt));
+	} else {
+
+		return new CG_roseRepr(isSgNode(for_stmt));
+
+	}
+
+}
+
+//-----------------------------------------------------------------------------
+// Attribute Creation
+//-----------------------------------------------------------------------------
+CG_outputRepr* CG_roseBuilder::CreateAttribute(CG_outputRepr *control,
+		const std::string &commentText) const {
+
+	SgNode *tnl = static_cast<CG_roseRepr*>(control)->tnl_;
+
+	tnl->setAttribute("omega_comment", new AstTextAttribute(commentText));
+
+	return static_cast<CG_roseRepr*>(control);
+
+}
+
+//-----------------------------------------------------------------------------
+// Pragma Attribute
+//-----------------------------------------------------------------------------
+CG_outputRepr* CG_roseBuilder::CreatePragmaAttribute(CG_outputRepr *stmt, int looplevel, const std::string &pragmaText) const {
+	SgNode *tnl = static_cast<CG_roseRepr*>(stmt)->tnl_;
+	CodeInsertionAttribute* attr = NULL;
+	if (!tnl->attributeExists("code_insertion")) {
+		attr = new CodeInsertionAttribute();
+		tnl->setAttribute("code_insertion", attr);
+	}
+	else {
+		attr = static_cast<CodeInsertionAttribute*>(tnl->getAttribute("code_insertion"));
+	}
+	attr->add(new PragmaInsertion(looplevel, pragmaText));
+	return stmt;
+}
+
+//-----------------------------------------------------------------------------
+// Prefetch Attribute
+//-----------------------------------------------------------------------------
+CG_outputRepr* CG_roseBuilder::CreatePrefetchAttribute(CG_outputRepr* stmt, int looplevel, const std::string &arrName, int hint) const {
+	SgNode *tnl = static_cast<CG_roseRepr*>(stmt)->tnl_;
+	CodeInsertionAttribute *attr = getOrCreateCodeInsertionAttribute(tnl);
+	attr->add(new MMPrefetchInsertion(looplevel, arrName, hint));
+}
+
+//-----------------------------------------------------------------------------
+// loop stmt generation
+//-----------------------------------------------------------------------------
+CG_outputRepr* CG_roseBuilder::CreateLoop(int, CG_outputRepr *control,
+		CG_outputRepr *stmtList) const {
+	if (stmtList == NULL) {
+		delete control;
+		return NULL;
+	} else if (control == NULL) {
+		fprintf(stderr, "Code generation: no inductive for this loop\n");
+		return stmtList;
+	}
+
+	SgNode *tnl = static_cast<CG_roseRepr*>(control)->tnl_;
+	SgForStatement *tf = isSgForStatement(tnl);
+
+	// Manu :: fortran support
+	SgFortranDo *tfd = NULL;
+	if (isInputFortran()) {
+		tfd = isSgFortranDo(tnl);
+	}
+	SgStatementPtrList * body = static_cast<CG_roseRepr*>(stmtList)->list_;
+
+	if (body != NULL) {
+		if (!((*body).empty())) {
+			if ((*body).size() == 1) {
+				if (!isInputFortran()) {  // Manu:: added if-else for fortran support
+				  tf->set_loop_body(*((*body).begin()));
+				  (*((*body).begin()))->set_parent(tf);
+				} else {
+					SgBasicBlock* bb1 = buildBasicBlock();
+					bb1->set_parent(tfd);
+					bb1->append_statement(*((*body).begin()));
+					tfd->set_body(bb1);
+				}
+			} else {
+				// Manu:: support for fortran label (do - continue)
+				SgName *sname = NULL;
+
+				SgBasicBlock* bb = buildBasicBlock();
+				if (!isInputFortran())
+				    bb->set_parent(tf);
+				else
+					bb->set_parent(tfd);
+				for (SgStatementPtrList::iterator it = (*body).begin();
+						it != (*body).end(); it++) {
+					bb->append_statement(*it);
+					(*it)->set_parent(bb);
+				}
+				if (!isInputFortran())
+				   tf->set_loop_body(bb);
+				else {
+					tfd->set_body(bb);
+				}
+			}
+		}
+	} else {
+		SgNode* tnl2 = static_cast<CG_roseRepr*>(stmtList)->tnl_;
+
+		if (tnl2 != NULL) {
+			if (!isInputFortran()) {
+			   tf->set_loop_body(isSgStatement(tnl2));
+			   tnl2->set_parent(tf);
+			} else {
+				SgBasicBlock* bb1 = buildBasicBlock();
+				bb1->set_parent(tfd);
+				bb1->append_statement(isSgStatement(tnl2));
+				tfd->set_body(bb1);
+  			    tnl2->set_parent(bb1);
+			}
+		}
+	}
+
+	delete stmtList;
+
+	return control;
+}
+
+//-----------------------------------------------------------------------------
+// basic int, identifier gen operations
+//-----------------------------------------------------------------------------
+CG_outputRepr* CG_roseBuilder::CreateInt(int _i) const {
+	return new CG_roseRepr(isSgExpression(buildIntVal(_i)));
+}
+bool CG_roseBuilder::isInteger(CG_outputRepr *op) const{
+
+	 SgExpression *op1 = static_cast<CG_roseRepr *>(op)->op_;
+
+	 if(op1)
+       if(isSgIntVal(op1))
+	       return true;
+
+     return false;
+}
+CG_outputRepr* CG_roseBuilder::CreateIdent(const std::string &_s) const {
+
+	SgVariableSymbol *vs = symtab_->find_variable(SgName(_s.c_str()));
+	SgVariableSymbol *vs2 = symtab2_->find_variable(SgName(_s.c_str()));
+
+	if (vs == NULL && vs2 == NULL) {
+
+		SgVariableDeclaration* defn = buildVariableDeclaration(
+				SgName(_s.c_str()), buildIntType());
+		SgInitializedNamePtrList& variables = defn->get_variables();
+		SgInitializedNamePtrList::const_iterator i = variables.begin();
+		SgInitializedName* initializedName = *i;
+		vs = new SgVariableSymbol(initializedName);
+		prependStatement(defn, isSgScopeStatement(root_));
+
+		vs->set_parent(symtab2_);
+		symtab2_->insert(SgName(_s.c_str()), vs);
+		return new CG_roseRepr(isSgExpression(buildVarRefExp(vs)));
+
+	}
+
+	/* May have problem */
+
+	if (!isSgExpression(buildVarRefExp(SgName(_s.c_str()))))
+		throw ir_error("error in Create ident!!");
+	if (vs2 != NULL)
+		return new CG_roseRepr(isSgExpression(buildVarRefExp(vs2)));
+
+	return new CG_roseRepr(isSgExpression(buildVarRefExp(vs)));
+
+}
+
+//-----------------------------------------------------------------------------
+// binary arithmetic operations
+//-----------------------------------------------------------------------------
+CG_outputRepr* CG_roseBuilder::CreatePlus(CG_outputRepr *lop,
+		CG_outputRepr *rop) const {
+	if (rop == NULL) {
+		return lop;
+	} else if (lop == NULL) {
+		return rop;
+	}
+
+	SgExpression* op1 = static_cast<CG_roseRepr*>(lop)->op_;
+	SgExpression* op2 = static_cast<CG_roseRepr*>(rop)->op_;
+
+	SgAddOp *ins = buildAddOp(op1, op2);
+	op1->set_parent(ins);
+	op2->set_parent(ins);
+	delete lop;
+	delete rop;
+
+	return new CG_roseRepr(isSgExpression(ins));
+
+}
+
+CG_outputRepr* CG_roseBuilder::CreateMinus(CG_outputRepr *lop,
+		CG_outputRepr *rop) const {
+	if (rop == NULL) {
+		return lop; /* May Cause Problem */
+	} else if (lop == NULL) {
+		SgExpression *op = static_cast<CG_roseRepr*>(rop)->op_;
+		SgMinusOp *ins = buildMinusOp(op);
+
+		delete rop;
+
+		return new CG_roseRepr(isSgExpression(ins));
+	} else {
+		SgExpression* op1 = static_cast<CG_roseRepr*>(lop)->op_;
+		SgExpression* op2 = static_cast<CG_roseRepr*>(rop)->op_;
+
+		SgSubtractOp *ins = buildSubtractOp(op1, op2);
+		op1->set_parent(ins);
+		op2->set_parent(ins);
+		delete lop;
+		delete rop;
+		return new CG_roseRepr(isSgExpression(ins));
+	}
+
+}
+
+CG_outputRepr* CG_roseBuilder::CreateTimes(CG_outputRepr *lop,
+		CG_outputRepr *rop) const {
+	if (rop == NULL || lop == NULL) {
+		if (rop != NULL) {
+			rop->clear();
+			delete rop;
+		}
+		if (lop != NULL) {
+			lop->clear();
+			delete lop;
+		}
+		return NULL;
+	}
+
+	SgExpression* op1 = static_cast<CG_roseRepr*>(lop)->op_;
+	SgExpression* op2 = static_cast<CG_roseRepr*>(rop)->op_;
+
+	SgMultiplyOp *ins = buildMultiplyOp(op1, op2);
+	op1->set_parent(ins);
+	op2->set_parent(ins);
+	delete lop;
+	delete rop;
+
+	return new CG_roseRepr(isSgExpression(ins));
+
+}
+
+CG_outputRepr* CG_roseBuilder::CreateIntegerFloor(CG_outputRepr *lop,
+		CG_outputRepr *rop) const {
+	if (rop == NULL) {
+		fprintf(stderr, "Code generation: divide by NULL\n");
+		return NULL;
+	} else if (lop == NULL) {
+		delete rop;
+		return NULL;
+	}
+
+	//  (6+5)*10 / 4
+	SgExpression* op1 = static_cast<CG_roseRepr*>(lop)->op_;
+	SgExpression* op2 = static_cast<CG_roseRepr*>(rop)->op_;
+
+	// bugs in SUIF prevent use of correct io_divfloor
+	SgDivideOp *ins = buildDivideOp(op1, op2);
+
+	delete lop;
+	delete rop;
+
+	return new CG_roseRepr(isSgExpression(ins));
+
+}
+
+CG_outputRepr* CG_roseBuilder::CreateIntegerMod(CG_outputRepr *lop,
+		CG_outputRepr *rop) const {
+	if (rop == NULL || lop == NULL) {
+		return NULL;
+	}
+
+	SgExpression* op1 = static_cast<CG_roseRepr*>(lop)->op_;
+	SgExpression* op2 = static_cast<CG_roseRepr*>(rop)->op_;
+
+	// bugs in SUIF prevent use of correct io_mod
+	SgModOp *ins;
+	if (!isInputFortran()) {
+		ins = buildModOp(op1, op2);
+		delete lop;
+		delete rop;
+
+		return new CG_roseRepr(isSgExpression(ins));
+	} else { // Manu:: fortran mod is a function call and not an operator (f77 and f90)
+		SgExpression *fins;
+		SgName fName("MOD");
+		SgExprListExp* arg_list = buildExprListExp();
+		appendExpression(arg_list, op1);
+		appendExpression(arg_list, op2);
+		SgTypeInt *retType = buildIntType();
+		fins = isSgExpression(buildFunctionCallExp(fName, retType, arg_list, global_));
+		return new CG_roseRepr(isSgExpression(fins));
+	}
+
+}
+
+//-----------------------------------------------------------------------------
+// binary logical operations
+//-----------------------------------------------------------------------------
+CG_outputRepr* CG_roseBuilder::CreateAnd(CG_outputRepr *lop,
+		CG_outputRepr *rop) const {
+
+	if (rop == NULL)
+		return lop;
+	else if (lop == NULL)
+		return rop;
+
+	SgExpression* op1 = static_cast<CG_roseRepr*>(lop)->op_;
+	SgExpression* op2 = static_cast<CG_roseRepr*>(rop)->op_;
+
+	SgAndOp *ins = buildAndOp(op1, op2);
+
+	delete lop;
+	delete rop;
+
+	return new CG_roseRepr(isSgExpression(ins));
+
+}
+
+//-----------------------------------------------------------------------------
+// binary relational operations
+//-----------------------------------------------------------------------------
+CG_outputRepr* CG_roseBuilder::CreateLE(CG_outputRepr *lop,
+		CG_outputRepr *rop) const {
+	if (rop == NULL || lop == NULL) {
+		return NULL;
+	}
+
+	SgExpression* op1 = static_cast<CG_roseRepr*>(lop)->op_;
+	SgExpression* op2 = static_cast<CG_roseRepr*>(rop)->op_;
+
+	SgLessOrEqualOp *ins = buildLessOrEqualOp(op1, op2);
+
+	delete lop;
+	delete rop;
+
+	return new CG_roseRepr(isSgExpression(ins));
+
+}
+
+CG_outputRepr* CG_roseBuilder::CreateEQ(CG_outputRepr *lop,
+		CG_outputRepr *rop) const {
+	if (rop == NULL || lop == NULL) {
+		return NULL;
+	}
+
+	SgExpression* op1 = static_cast<CG_roseRepr*>(lop)->op_;
+	SgExpression* op2 = static_cast<CG_roseRepr*>(rop)->op_;
+
+	SgEqualityOp *ins = buildEqualityOp(op1, op2);
+
+	delete lop;
+	delete rop;
+
+	return new CG_roseRepr(isSgExpression(ins));
+
+}
+
+//-----------------------------------------------------------------------------
+// stmt list gen operations
+//-----------------------------------------------------------------------------
+CG_outputRepr* CG_roseBuilder::StmtListAppend(CG_outputRepr *list1,
+		CG_outputRepr *list2) const {
+
+	if (list2 == NULL) {
+		return list1;
+	} else if (list1 == NULL) {
+		return list2;
+	}
+
+	SgStatementPtrList* new_list;
+
+	SgStatementPtrList* tnl1 = static_cast<CG_roseRepr *>(list1)->list_;
+	SgStatementPtrList* tnl2 = static_cast<CG_roseRepr *>(list2)->list_;
+	SgNode* one = static_cast<CG_roseRepr *>(list1)->tnl_;
+	SgNode* two = static_cast<CG_roseRepr *>(list2)->tnl_;
+
+	SgExpression* exp1 = static_cast<CG_roseRepr *>(list1)->op_;
+	SgExpression* exp2 = static_cast<CG_roseRepr *>(list2)->op_;
+
+	if (exp1 || exp2)
+		throw ir_error("error in stmtlistappend!!");
+
+	if (tnl1 && one)
+		throw ir_error("error in stmtlistappend!!");
+
+	if (tnl2 && two)
+		throw ir_error("error in stmtlistappend!!");
+	if ((tnl1 == NULL) && (tnl2 == NULL)) {
+
+		if ((one != NULL) && (two != NULL)) {
+
+			new_list = new SgStatementPtrList;
+
+			(*new_list).push_back(isSgStatement(one));
+			(*new_list).push_back(isSgStatement(two));
+
+			CG_roseRepr* new_rep = new CG_roseRepr(new_list);
+
+			return static_cast<CG_outputRepr *>(new_rep);
+
+		} else if ((one != NULL) && (two == NULL)) {
+
+			return static_cast<CG_outputRepr *>(new CG_roseRepr(one));
+
+		} else if ((two != NULL) && (one == NULL)) {
+			return static_cast<CG_outputRepr *>(new CG_roseRepr(two));
+
+		}
+
+	} else {
+		if ((tnl2 != NULL) && (tnl1 == NULL)) {
+			if (one == NULL)
+				return list2;
+			else {
+				new_list = new SgStatementPtrList;
+				(*new_list).push_back(isSgStatement(one));
+
+				for (SgStatementPtrList::iterator it = (*tnl2).begin();
+						it != (*tnl2).end(); it++) {
+					(*new_list).push_back(*it);
+
+				}
+				return static_cast<CG_outputRepr *>(new CG_roseRepr(new_list));
+			}
+		} else if ((tnl1 != NULL) && (tnl2 == NULL)) {
+			if (two == NULL)
+				return list1;
+			else {
+
+				(*tnl1).push_back(isSgStatement(two));
+				return static_cast<CG_outputRepr *>(new CG_roseRepr(tnl1));
+
+			}
+
+		} else if ((tnl1 != NULL) && (tnl2 != NULL)) {
+
+			for (SgStatementPtrList::iterator it = (*tnl2).begin();
+					it != (*tnl2).end(); it++) {
+				(*tnl1).push_back(*it);
+
+			}
+
+			return static_cast<CG_outputRepr *>(new CG_roseRepr(tnl1));
+		}
+
+	}
+
+}
+
+
+CG_outputRepr* CG_roseBuilder::CreateDim3(const char* varName, CG_outputRepr* arg1,
+		CG_outputRepr* arg2, CG_outputRepr* arg3) const {
+
+    SgFunctionSymbol * ctor_symbol = global_scope->lookup_function_symbol(
+			SgName("dim3"));
+
+	SgExprListExp * ctor_args;
+	if(arg3 != NULL)
+	ctor_args = buildExprListExp(static_cast<CG_roseRepr*>(arg1)->op_,
+			static_cast<CG_roseRepr*>(arg2)->op_, static_cast<CG_roseRepr*>(arg3)->op_);
+	else
+    ctor_args = buildExprListExp(static_cast<CG_roseRepr*>(arg1)->op_,
+    		static_cast<CG_roseRepr*>(arg2)->op_);
+	SgFunctionCallExp * dim3_func_call = buildFunctionCallExp(
+			buildFunctionRefExp(ctor_symbol->get_declaration()), ctor_args);
+
+	char joined_str[20];
+
+	strcpy(joined_str, "dim3 ");
+	strcat(joined_str, varName);
+
+	SgExprStatement* decl = buildAssignStatement(
+			buildOpaqueVarRefExp(joined_str, isSgScopeStatement(root_)),
+			dim3_func_call);
+
+	SgStatementPtrList *tnl2 = new SgStatementPtrList;
+
+	(*tnl2).push_back(decl);
+	return new CG_roseRepr(tnl2);
+
+}
+
+std::vector<SgVarRefExp *> substitute(SgNode *in, const SgVariableSymbol *sym,
+		SgExpression* expr, SgNode* root) {
+
+	SgStatement* stmt;
+	SgExpression* op;
+	std::vector<SgVarRefExp *> arrays;
+
+	if (in != NULL) {
+		if (stmt = isSgStatement(in)) {
+			if (isSgBasicBlock(stmt)) {
+				SgStatementPtrList& stmts =
+						isSgBasicBlock(stmt)->get_statements();
+				for (int i = 0; i < stmts.size(); i++) {
+					stmts[i]->set_parent(stmt);
+					std::vector<SgVarRefExp *> a = substitute(
+							isSgNode(stmts[i]), sym, expr, root);
+					std::copy(a.begin(), a.end(), back_inserter(arrays));
+				}
+			} else if (isSgForStatement(stmt)) {
+				SgForStatement *tnf = isSgForStatement(stmt);
+				tnf->get_for_init_stmt()->set_parent(tnf);
+				tnf->get_test()->set_parent(tnf);
+				tnf->get_increment()->set_parent(tnf);
+				tnf->get_loop_body()->set_parent(tnf);
+				std::vector<SgVarRefExp *> a = substitute(
+						isSgNode(tnf->get_for_init_stmt()), sym, expr, root);
+				std::copy(a.begin(), a.end(), back_inserter(arrays));
+				std::vector<SgVarRefExp *> a1 = substitute(
+						isSgNode(tnf->get_test()), sym, expr, root);
+				std::copy(a1.begin(), a1.end(), back_inserter(arrays));
+				std::vector<SgVarRefExp *> a2 = substitute(
+						isSgNode(tnf->get_increment()), sym, expr, root);
+				std::copy(a2.begin(), a2.end(), back_inserter(arrays));
+				std::vector<SgVarRefExp *> a3 = substitute(
+						isSgNode(tnf->get_loop_body()), sym, expr, root);
+				std::copy(a3.begin(), a3.end(), back_inserter(arrays));
+			} else if (isSgFortranDo(stmt)) { // Manu:: fortran support
+				SgFortranDo *tnf = isSgFortranDo(stmt);
+				tnf->get_initialization()->set_parent(tnf);
+				tnf->get_bound()->set_parent(tnf);
+				tnf->get_increment()->set_parent(tnf);
+				tnf->get_body()->set_parent(tnf);
+				std::vector<SgVarRefExp *> a = substitute(
+						isSgNode(tnf->get_initialization()), sym, expr, root);
+				std::copy(a.begin(), a.end(), back_inserter(arrays));
+				std::vector<SgVarRefExp *> a1 = substitute(
+						isSgNode(tnf->get_bound()), sym, expr, root);
+				std::copy(a1.begin(), a1.end(), back_inserter(arrays));
+				std::vector<SgVarRefExp *> a2 = substitute(
+						isSgNode(tnf->get_increment()), sym, expr, root);
+				std::copy(a2.begin(), a2.end(), back_inserter(arrays));
+				std::vector<SgVarRefExp *> a3 = substitute(
+						isSgNode(tnf->get_body()), sym, expr, root);
+				std::copy(a3.begin(), a3.end(), back_inserter(arrays));
+			} else if (isSgForInitStatement(stmt)) {
+
+				SgStatementPtrList& stmts =
+						isSgForInitStatement(stmt)->get_init_stmt();
+
+				for (SgStatementPtrList::iterator it = stmts.begin();
+						it != stmts.end(); it++) {
+					std::vector<SgVarRefExp *> a = substitute(isSgNode(*it),
+							sym, expr, root);
+
+					std::copy(a.begin(), a.end(), back_inserter(arrays));
+				}
+			}
+			else if (isSgVariableDeclaration(stmt)) {
+				if (SgExpression *init =
+						isSgVariableDeclaration(stmt)->get_variables().front()->get_initializer()) {
+					if (isSgAssignInitializer(init)) {
+						std::vector<SgVarRefExp *> a = substitute(
+								isSgAssignInitializer(init)->get_operand(), sym,
+								expr, root);
+						std::copy(a.begin(), a.end(), back_inserter(arrays));
+					}
+				}
+			} else if (isSgIfStmt(stmt)) {
+				SgIfStmt* tni = isSgIfStmt(stmt);
+				std::vector<SgVarRefExp *> a = substitute(
+						isSgNode(tni->get_conditional()), sym, expr, root);
+				std::copy(a.begin(), a.end(), back_inserter(arrays));
+				std::vector<SgVarRefExp *> a1 = substitute(
+						isSgNode(tni->get_true_body()), sym, expr, root);
+				std::copy(a1.begin(), a1.end(), back_inserter(arrays));
+				std::vector<SgVarRefExp *> a2 = substitute(
+						isSgNode(tni->get_false_body()), sym, expr, root);
+				std::copy(a2.begin(), a2.end(), back_inserter(arrays));
+			} else if (isSgExprStatement(stmt)) {
+				(isSgExprStatement(stmt)->get_expression())->set_parent(
+						isSgExprStatement(stmt));
+				std::vector<SgVarRefExp *> a = substitute(
+						isSgNode(isSgExprStatement(stmt)->get_expression()),
+						sym, expr, root);
+				std::copy(a.begin(), a.end(), back_inserter(arrays));
+			}  
+		} 
+		else {
+			op = isSgExpression(in);
+			std::string y = sym->get_name().getString();
+
+			if (isSgBinaryOp(op)) {
+
+				isSgBinaryOp(op)->get_lhs_operand()->set_parent(op);
+				isSgBinaryOp(op)->get_rhs_operand()->set_parent(op);
+
+				std::vector<SgVarRefExp *> a = substitute(
+						isSgBinaryOp(op)->get_lhs_operand(), sym, expr, root);
+				std::copy(a.begin(), a.end(), back_inserter(arrays));
+				std::vector<SgVarRefExp *> a1 = substitute(
+						isSgBinaryOp(op)->get_rhs_operand(), sym, expr, root);
+				std::copy(a1.begin(), a1.end(), back_inserter(arrays));
+			} else if (isSgUnaryOp(op)) {
+				std::vector<SgVarRefExp *> a = substitute(
+						isSgUnaryOp(op)->get_operand(), sym, expr, root);
+				std::copy(a.begin(), a.end(), back_inserter(arrays));
+			} else if (isSgVarRefExp(op)) {
+				std::string z =
+						isSgVarRefExp(op)->get_symbol()->get_name().getString();
+				if (!strcmp(z.c_str(), y.c_str())) {
+					arrays.push_back(isSgVarRefExp(op));
+				}   
+			}    
+			else if (isSgCallExpression(op)) {
+				SgExprListExp* exprs = isSgCallExpression(op)->get_args();
+				SgExpressionPtrList &expr_list = exprs->get_expressions();
+
+				for (SgExpressionPtrList::iterator it = expr_list.begin();
+						it != expr_list.end(); it++) {
+					std::vector<SgVarRefExp *> a = substitute(isSgNode(*it),
+							sym, expr, root);
+					std::copy(a.begin(), a.end(), back_inserter(arrays));
+				}
+			} else if (isSgExprListExp(op)) { // Manu:: fortran indices are stored this way
+				SgExpressionPtrList &expr_list = isSgExprListExp(op)->get_expressions();
+
+				for (SgExpressionPtrList::iterator it = expr_list.begin();
+						it != expr_list.end(); it++) {
+					std::vector<SgVarRefExp *> a = substitute(isSgNode(*it),
+							sym, expr, root);
+					std::copy(a.begin(), a.end(), back_inserter(arrays));
+				}
+
+			}
+
+		}  
+	}       
+
+	return arrays;
+}
+
+} // namespace
diff --git a/lib/rosecg/src/CG_roseRepr.cc b/lib/rosecg/src/CG_roseRepr.cc
new file mode 100644
index 0000000..0b0c073
--- /dev/null
+++ b/lib/rosecg/src/CG_roseRepr.cc
@@ -0,0 +1,125 @@
+/*****************************************************************************
+ Copyright (C) 2008 University of Southern California. 
+ All Rights Reserved.
+
+ Purpose:
+   omega holder for suif implementaion
+
+ Notes:
+
+ History:
+   02/01/06 - Chun Chen - created
+*****************************************************************************/
+
+#include "CG_roseRepr.h"
+#include "rose_attributes.h"
+#include <stdio.h>
+#include <string.h>
+#include <cstring>
+namespace omega {
+
+
+
+
+CG_roseRepr::CG_roseRepr(): tnl_(NULL), op_(NULL), list_(NULL){
+
+}
+
+CG_roseRepr::CG_roseRepr(SgNode *tnl): tnl_(tnl), op_(NULL),list_(NULL) {
+}
+
+CG_roseRepr::CG_roseRepr(SgExpression* op): tnl_(NULL), op_(op),list_(NULL){
+}
+CG_roseRepr::CG_roseRepr(SgStatementPtrList* stmtlist):tnl_(NULL), op_(NULL), list_(stmtlist){
+}
+  
+CG_roseRepr::~CG_roseRepr() {
+  // delete nothing here. operand or tree_node_list should already be
+  // grafted to other expression tree or statement list
+}
+
+CG_outputRepr* CG_roseRepr::clone()  const {
+
+  if( tnl_ != NULL) {
+    SgTreeCopy  tc;      
+    SgNode *tnl = tnl_->copy(tc);
+    copyAttributes(tnl_, tnl);
+    
+    tnl->set_parent(tnl_->get_parent());
+    return new CG_roseRepr(tnl);
+  }
+  else if(op_ != NULL)
+  {
+     SgTreeCopy tc1;
+     SgNode* op =  isSgNode(op_)->copy(tc1);
+     copyAttributes(op_, op);
+  
+     op->set_parent(isSgNode(op_)->get_parent());   
+     return new CG_roseRepr(isSgExpression(op));
+  }
+  else if(list_ != NULL) 
+  {
+     SgStatementPtrList* list2 = new SgStatementPtrList;
+     
+     for(SgStatementPtrList::iterator it = (*list_).begin(); it != (*list_).end(); it++){
+        SgTreeCopy  tc3;      
+        SgNode *tnl2  =  isSgNode(*it)->copy(tc3);
+        copyAttributes(*it, tnl2);
+        
+        tnl2->set_parent(isSgNode(*it)->get_parent());
+       
+        (*list2).push_back(isSgStatement(tnl2));       
+    }   
+    return new CG_roseRepr(list2);
+  }
+  
+  return NULL;
+}
+
+void CG_roseRepr::clear() {
+  if(tnl_ != NULL) {
+    delete tnl_;
+    tnl_ = NULL;
+  }
+}
+
+SgNode* CG_roseRepr::GetCode() const {
+  return tnl_;
+}
+
+SgStatementPtrList* CG_roseRepr::GetList() const {
+  return list_;
+}
+
+SgExpression* CG_roseRepr::GetExpression() const {
+   return op_;
+} 
+void CG_roseRepr::Dump() const {
+SgNode* tnl = tnl_;
+SgExpression* op = op_ ;
+ if(tnl != NULL)
+  DumpFileHelper(tnl, stdout);
+ else if(op != NULL)
+   DumpFileHelper(isSgNode(op), stdout);             
+
+}
+
+void  CG_roseRepr::DumpFileHelper(SgNode* node, FILE *fp) const{
+  std::string x;
+  size_t numberOfSuccessors = node->get_numberOfTraversalSuccessors();
+ if(numberOfSuccessors == 0){
+    x = node->unparseToString ();   
+    fprintf(fp, "%s", x.c_str());
+ }
+ else{     
+   for (size_t idx = 0; idx < numberOfSuccessors; idx++)
+   {
+       SgNode *child = NULL;
+       child = node->get_traversalSuccessorByIndex(idx);
+       DumpFileHelper(child, fp);                 
+   }
+ 
+}
+}
+
+} // namespace
diff --git a/lib/rosecg/src/rose_attributes.cc b/lib/rosecg/src/rose_attributes.cc
new file mode 100644
index 0000000..3debb2d
--- /dev/null
+++ b/lib/rosecg/src/rose_attributes.cc
@@ -0,0 +1,183 @@
+#include "rose_attributes.h"
+
+namespace omega {
+
+CodeInsertionAttribute* getOrCreateCodeInsertionAttribute(SgNode* node) {
+	CodeInsertionAttribute* attr;
+	if(node->attributeExists("code_insertion"))
+		return static_cast<CodeInsertionAttribute*>(node->getAttribute("code_insertion"));
+	attr = new CodeInsertionAttribute();
+	node->setAttribute("code_insertion", attr);
+	return attr;
+}
+
+void postProcessRoseCodeInsertion(SgProject* proj) {
+	//generatePDF(*proj);
+	CodeInsertionVisitor visitor = CodeInsertionVisitor();
+	visitor.initialize();
+	visitor.traverseInputFiles(proj);
+	visitor.insertCode();
+}
+
+// Swap a code insertion from one node (sn) to another (dn)
+// -- note that this function does not currently remove the insertion from the sn node
+void moveCodeInsertion(SgNode* sn, CodeInsertion* ci, SgNode* dn) {
+	CodeInsertionAttribute* new_attr;
+	// TODO in the near future: replace the above statement with 'new_attr = getOrCreateCodeInsertionAttribute(...)'
+	CodeInsertionAttribute* old_attr = static_cast<CodeInsertionAttribute*>(sn->getAttribute("code_insertion"));
+	if(dn->attributeExists("code_insertion")) {
+		new_attr = static_cast<CodeInsertionAttribute*>(dn->getAttribute("code_insertion"));
+	}
+	else {
+		new_attr = new CodeInsertionAttribute();
+		dn->setAttribute("code_insertion", new_attr);
+	}
+	new_attr->add(ci);
+}
+
+// A function that copies a specific attribute from one node to another
+// this function exists to get around a ROSE limitation that does not
+// copy attributes
+void copyAttribute(std::string attr_name, SgNode* s, SgNode* d) {
+	if(s->attributeExists(attr_name)) {
+		d->setAttribute(attr_name,s->getAttribute(attr_name));
+	}
+}
+
+// TODO: find all existng attributes and iterate over them instead of doing them
+//       individually
+void copyAttributes(SgNode* s, SgNode* d) {
+	copyAttribute("code_insertion", s, d);
+	//...any other attributes...
+}
+
+void CodeInsertionVisitor::initialize() {
+	this->loop_level = 0;
+	this->ci_marks = std::vector<CodeInsertionMark*>();
+}
+
+void CodeInsertionVisitor::markStmt(SgStatement* stmt, CodeInsertion* ci) {
+	// this check prevents multiple copies of stmts
+	// -- may be changed in the future
+	if(!ci->marked) {
+		CodeInsertionMark* pos = new CodeInsertionMark();
+		pos->stmt = stmt;
+		pos->ci = ci;
+		this->ci_marks.push_back(pos);
+		ci->marked = true;
+	}
+}
+
+// increase loop_level as the visitor descends
+void CodeInsertionVisitor::preOrderVisit(SgNode* n) {
+	if (isSgForStatement(n)) {
+		this->loop_level++;
+	}
+}
+
+void CodeInsertionVisitor::postOrderVisit(SgNode* n) {
+	if(isSgForStatement(n)) {
+		this->loop_level--;
+	}
+	if(isSgStatement(n)) {
+		if(n->attributeExists("code_insertion")) {
+			CodeInsertionAttribute *attr = static_cast<CodeInsertionAttribute*>(n->getAttribute("code_insertion"));
+			for(CodeInsertionPtrListItr itr = attr->begin(); itr != attr->end(); ++itr) {
+				CodeInsertion *insertion = *itr;
+				// check loop level -- if it is equivelent, mark statement for insertion
+				//                  -- else, move attribute up to parent
+				if(insertion->loop_level != this->loop_level) {
+					moveCodeInsertion(n, insertion, n->get_parent());
+				}
+				else {
+					this->markStmt(isSgStatement(n), insertion);
+				}
+			}
+		}
+	}
+}
+
+// final stage of algorithm that inserts marked statements
+void CodeInsertionVisitor::insertCode() {
+	for(std::vector<CodeInsertionMark*>::iterator itr = this->ci_marks.begin(); itr != this->ci_marks.end(); ++itr) {
+		CodeInsertionMark* mark = *itr;
+		SgScopeStatement* scope = static_cast<SgScopeStatement*>(mark->stmt->get_parent());
+		SageInterface::insertStatementBefore(mark->stmt, mark->ci->getStatement(scope));
+	}
+}
+
+SgStatement* PragmaInsertion::getStatement(SgScopeStatement* scopeStmt) {
+	SgStatement* stmt = SageBuilder::buildPragmaDeclaration(this->name);
+	return stmt;
+}
+
+//SgStatement* MMPrefetchInsertion::getStatement(SgScopeStatement* scopeStmt) {
+//	const SgName& name = SgName("_mm_prefetch");
+//	SgType* rtype = SageBuilder::buildVoidType();
+//	SgExpression* arr_arg = SageBuilder::buildVarRefExp(this->arrName);
+//	SgExpression* hint_arg = SageBuilder::buildShortVal(this->cacheHint);
+//	SgExprListExp* args = SageBuilder::buildExprListExp(arr_arg,hint_arg);
+//	SgStatement* stmt = SageBuilder::buildFunctionCallStmt(name, rtype, args, scopeStmt);
+//	return stmt;
+//}
+
+SgStatement* MMPrefetchInsertion::getStatement(SgScopeStatement* scopeStmt) {
+	const SgName fname = SgName("_mm_prefetch");
+	SgType* rtype = SageBuilder::buildVoidType();
+	SgExpression* arr_arg = this->buildArrArg(scopeStmt);
+	SgExpression* hint_arg = SageBuilder::buildShortVal(this->cacheHint);
+	SgExprListExp* args = SageBuilder::buildExprListExp(arr_arg, hint_arg);
+	return SageBuilder::buildFunctionCallStmt(fname, rtype, args, scopeStmt);
+}
+
+SgExpression* MMPrefetchInsertion::buildArrArg(SgScopeStatement* scopeStmt) {
+	// if there are no index arguments given, just return a variable reference
+	if(this->indexCount == 0) {
+		const SgName aname = SgName(this->arrName);
+		return SageBuilder::buildVarRefExp(aname, scopeStmt);
+	}
+	std::vector<SgExpression*> argList = std::vector<SgExpression*>();
+	// foreach dimension
+	for(int i = 0; i < this->indexCount; i++) {
+		argList.push_back(this->makeIndexExp(i, scopeStmt));
+	}
+	return SageBuilder::buildExprListExp(argList);
+}
+
+SgExpression* MMPrefetchInsertion::makeIndexExp(int dim, SgScopeStatement* scopeStmt) {
+	//(i + offset) or (offset) or (i)
+	std::string* indexer = this->indecies.at(dim);
+	int offset = this->offsets.at(dim);
+	if(indexer == NULL) {
+		return SageBuilder::buildIntVal(offset);
+	}
+	else {
+		const SgName name = SgName(*indexer);
+		SgVarRefExp* iref = SageBuilder::buildVarRefExp(name, scopeStmt);
+		if(offset == 0) {
+			return iref;
+		}
+		else {
+			return SageBuilder::buildAddOp(iref, SageBuilder::buildIntVal(offset));
+		}
+	}
+}
+
+void MMPrefetchInsertion::initialize(const std::string& arrName, int hint) {
+	this->arrName = std::string(arrName);
+	this->cacheHint = hint;
+	this->indecies = std::vector<std::string*>();
+	this->offsets = std::vector<int>();
+	this->indexCount = 0;
+}
+void MMPrefetchInsertion::addDim(int offset) {
+	this->offsets.push_back(offset);
+	this->indecies.push_back(NULL);
+	this->indexCount++;
+}
+void MMPrefetchInsertion::addDim(int offset, const std::string& indexer) {
+	this->offsets.push_back(offset);
+	this->indecies.push_back(new std::string(indexer));
+	this->indexCount++;
+}
+}
diff --git a/omegalib/CMakeLists.txt b/omegalib/CMakeLists.txt
deleted file mode 100644
index 501d67a..0000000
--- a/omegalib/CMakeLists.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-cmake_minimum_required(VERSION 2.8)
-project(omegalib)
-
-if(NOT DEFINED ROSEHOME)
-    message( FATAL_ERROR "ROSEHOME is not set, try use -DROSEHOME" )
-endif()
-if (NOT DEFINED BOOSTHOME)
-    message( FATAL_ERROR "BOOSTHOME is not set, try use -DBOOSTHOME" )
-endif()
-
-set(OMEGAROOT ${PROJECT_SOURCE_DIR})
-
-add_subdirectory(omega)
-add_subdirectory(codegen)
diff --git a/omegalib/LICENSE b/omegalib/LICENSE
deleted file mode 100644
index f0fbe69..0000000
--- a/omegalib/LICENSE
+++ /dev/null
@@ -1,705 +0,0 @@
-Omega+ and CodeGen+
-Copyright (C) 2005-2011 Chun Chen
-All rights reserved.
-
-                    GNU GENERAL PUBLIC LICENSE
-                       Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-                            Preamble
-
-  The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
-  The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works.  By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users.  We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors.  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
-  To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights.  Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received.  You must make sure that they, too, receive
-or can get the source code.  And you must show them these terms so they
-know their rights.
-
-  Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
-  For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software.  For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
-  Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so.  This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software.  The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable.  Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products.  If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
-  Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary.  To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-                       TERMS AND CONDITIONS
-
-  0. Definitions.
-
-  "This License" refers to version 3 of the GNU General Public License.
-
-  "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
-  "The Program" refers to any copyrightable work licensed under this
-License.  Each licensee is addressed as "you".  "Licensees" and
-"recipients" may be individuals or organizations.
-
-  To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy.  The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
-  A "covered work" means either the unmodified Program or a work based
-on the Program.
-
-  To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy.  Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
-  To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies.  Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
-  An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License.  If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
-  1. Source Code.
-
-  The "source code" for a work means the preferred form of the work
-for making modifications to it.  "Object code" means any non-source
-form of a work.
-
-  A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
-  The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form.  A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
-  The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities.  However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work.  For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
-  The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
-  The Corresponding Source for a work in source code form is that
-same work.
-
-  2. Basic Permissions.
-
-  All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met.  This License explicitly affirms your unlimited
-permission to run the unmodified Program.  The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work.  This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
-  You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force.  You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright.  Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
-  Conveying under any other circumstances is permitted solely under
-the conditions stated below.  Sublicensing is not allowed; section 10
-makes it unnecessary.
-
-  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
-  No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
-  When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
-  4. Conveying Verbatim Copies.
-
-  You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
-  You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
-  5. Conveying Modified Source Versions.
-
-  You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
-    a) The work must carry prominent notices stating that you modified
-    it, and giving a relevant date.
-
-    b) The work must carry prominent notices stating that it is
-    released under this License and any conditions added under section
-    7.  This requirement modifies the requirement in section 4 to
-    "keep intact all notices".
-
-    c) You must license the entire work, as a whole, under this
-    License to anyone who comes into possession of a copy.  This
-    License will therefore apply, along with any applicable section 7
-    additional terms, to the whole of the work, and all its parts,
-    regardless of how they are packaged.  This License gives no
-    permission to license the work in any other way, but it does not
-    invalidate such permission if you have separately received it.
-
-    d) If the work has interactive user interfaces, each must display
-    Appropriate Legal Notices; however, if the Program has interactive
-    interfaces that do not display Appropriate Legal Notices, your
-    work need not make them do so.
-
-  A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit.  Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
-  6. Conveying Non-Source Forms.
-
-  You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
-    a) Convey the object code in, or embodied in, a physical product
-    (including a physical distribution medium), accompanied by the
-    Corresponding Source fixed on a durable physical medium
-    customarily used for software interchange.
-
-    b) Convey the object code in, or embodied in, a physical product
-    (including a physical distribution medium), accompanied by a
-    written offer, valid for at least three years and valid for as
-    long as you offer spare parts or customer support for that product
-    model, to give anyone who possesses the object code either (1) a
-    copy of the Corresponding Source for all the software in the
-    product that is covered by this License, on a durable physical
-    medium customarily used for software interchange, for a price no
-    more than your reasonable cost of physically performing this
-    conveying of source, or (2) access to copy the
-    Corresponding Source from a network server at no charge.
-
-    c) Convey individual copies of the object code with a copy of the
-    written offer to provide the Corresponding Source.  This
-    alternative is allowed only occasionally and noncommercially, and
-    only if you received the object code with such an offer, in accord
-    with subsection 6b.
-
-    d) Convey the object code by offering access from a designated
-    place (gratis or for a charge), and offer equivalent access to the
-    Corresponding Source in the same way through the same place at no
-    further charge.  You need not require recipients to copy the
-    Corresponding Source along with the object code.  If the place to
-    copy the object code is a network server, the Corresponding Source
-    may be on a different server (operated by you or a third party)
-    that supports equivalent copying facilities, provided you maintain
-    clear directions next to the object code saying where to find the
-    Corresponding Source.  Regardless of what server hosts the
-    Corresponding Source, you remain obligated to ensure that it is
-    available for as long as needed to satisfy these requirements.
-
-    e) Convey the object code using peer-to-peer transmission, provided
-    you inform other peers where the object code and Corresponding
-    Source of the work are being offered to the general public at no
-    charge under subsection 6d.
-
-  A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
-  A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling.  In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage.  For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product.  A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
-  "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source.  The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
-  If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information.  But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
-  The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed.  Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
-  Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
-  7. Additional Terms.
-
-  "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law.  If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
-  When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it.  (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.)  You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
-  Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
-    a) Disclaiming warranty or limiting liability differently from the
-    terms of sections 15 and 16 of this License; or
-
-    b) Requiring preservation of specified reasonable legal notices or
-    author attributions in that material or in the Appropriate Legal
-    Notices displayed by works containing it; or
-
-    c) Prohibiting misrepresentation of the origin of that material, or
-    requiring that modified versions of such material be marked in
-    reasonable ways as different from the original version; or
-
-    d) Limiting the use for publicity purposes of names of licensors or
-    authors of the material; or
-
-    e) Declining to grant rights under trademark law for use of some
-    trade names, trademarks, or service marks; or
-
-    f) Requiring indemnification of licensors and authors of that
-    material by anyone who conveys the material (or modified versions of
-    it) with contractual assumptions of liability to the recipient, for
-    any liability that these contractual assumptions directly impose on
-    those licensors and authors.
-
-  All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10.  If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term.  If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
-  If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
-  Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
-  8. Termination.
-
-  You may not propagate or modify a covered work except as expressly
-provided under this License.  Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
-  However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
-  Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
-  Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License.  If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
-  9. Acceptance Not Required for Having Copies.
-
-  You are not required to accept this License in order to receive or
-run a copy of the Program.  Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance.  However,
-nothing other than this License grants you permission to propagate or
-modify any covered work.  These actions infringe copyright if you do
-not accept this License.  Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
-  10. Automatic Licensing of Downstream Recipients.
-
-  Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License.  You are not responsible
-for enforcing compliance by third parties with this License.
-
-  An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations.  If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
-  You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License.  For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
-  11. Patents.
-
-  A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based.  The
-work thus licensed is called the contributor's "contributor version".
-
-  A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version.  For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
-  Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
-  In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement).  To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
-  If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients.  "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
-  If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
-  A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License.  You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
-  Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
-  12. No Surrender of Others' Freedom.
-
-  If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all.  For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
-  13. Use with the GNU Affero General Public License.
-
-  Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work.  The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
-  14. Revised Versions of this License.
-
-  The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-  Each version is given a distinguishing version number.  If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation.  If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
-  If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
-  Later license versions may give you additional or different
-permissions.  However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
-  15. Disclaimer of Warranty.
-
-  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-  16. Limitation of Liability.
-
-  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
-  17. Interpretation of Sections 15 and 16.
-
-  If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
-                     END OF TERMS AND CONDITIONS
-
-            How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    This program is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-Also add information on how to contact you by electronic and paper mail.
-
-  If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
-    <program>  Copyright (C) <year>  <name of author>
-    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
-  You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-<http://www.gnu.org/licenses/>.
-
-  The GNU General Public License does not permit incorporating your program
-into proprietary programs.  If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library.  If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.  But first, please read
-<http://www.gnu.org/philosophy/why-not-lgpl.html>.
-
-==============================================================================
-
-The Omega Project
-Copyright (C) 1994-2000 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
diff --git a/omegalib/codegen/CMakeLists.txt b/omegalib/codegen/CMakeLists.txt
deleted file mode 100644
index 79bdcb4..0000000
--- a/omegalib/codegen/CMakeLists.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-set(CG_SRC
-    src/codegen.cc
-    src/CG.cc
-    src/CG_stringBuilder.cc
-    src/CG_utils.cc
-
-    src/rose_attributes.cc
-    src/CG_roseBuilder.cc
-    src/CG_roseRepr.cc
-    )
-
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-write-strings")
-
-include_directories(
-    include
-    ${OMEGAROOT}/omega/include
-    ${ROSEHOME}/include/rose
-    ${BOOSTHOME}/include
-    )
-
-add_library(codegen
-    ${CG_SRC}
-    )
-
-add_dependencies(codegen omega)
-
-install(TARGETS codegen
-    ARCHIVE DESTINATION lib)
-install(DIRECTORY include
-    DESTINATION .)
diff --git a/omegalib/codegen/include/code_gen/CG.h b/omegalib/codegen/include/code_gen/CG.h
deleted file mode 100644
index ce56768..0000000
--- a/omegalib/codegen/include/code_gen/CG.h
+++ /dev/null
@@ -1,118 +0,0 @@
-#ifndef _CG_H
-#define _CG_H
-
-#include <omega/Relation.h>
-#include <basic/BoolSet.h>
-#include <code_gen/CG_outputBuilder.h>
-#include <vector>
-
-namespace omega {
-
-class CodeGen;
-
-struct CG_result {
-  CodeGen *codegen_;
-  BoolSet<> active_;
-
-  CG_result() { codegen_ = NULL; }
-  virtual ~CG_result() { /* not responsible for codegen_ */ }
-  
-  virtual CG_result *recompute(const BoolSet<> &parent_active, const Relation &known, const Relation &restriction) = 0;
-  virtual int populateDepth() = 0;
-  virtual std::pair<CG_result *, Relation> liftOverhead(int depth, bool propagate_up) = 0;
-  virtual Relation hoistGuard() = 0;
-  virtual void removeGuard(const Relation &guard) = 0;
-  virtual CG_outputRepr *printRepr(int indent, CG_outputBuilder *ocg, const std::vector<CG_outputRepr *> &stmts, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) const = 0;
-  CG_outputRepr *printRepr(CG_outputBuilder *ocg, const std::vector<CG_outputRepr *> &stmts) const;
-  std::string printString() const;
-  int num_level() const;
-  virtual CG_result *clone() const = 0;
-  virtual void dump(int indent) const {}
-  void dump() { dump(0); }
-};
-
-
-struct CG_split: public CG_result {
-  std::vector<Relation> restrictions_;
-  std::vector<CG_result *> clauses_;
-
-  CG_split(CodeGen *codegen, const BoolSet<> &active, const std::vector<Relation> &restrictions, const std::vector<CG_result *> &clauses) {
-    codegen_ = codegen;
-    active_ = active;
-    restrictions_ = restrictions;
-    clauses_ = clauses;
-  } 
-  ~CG_split() {
-    for (int i = 0; i < clauses_.size(); i++)
-      delete clauses_[i];
-  } 
-  
-  CG_result *recompute(const BoolSet<> &parent_active, const Relation &known, const Relation &restriction);
-  int populateDepth();
-  std::pair<CG_result *, Relation> liftOverhead(int depth, bool propagate_up);
-  Relation hoistGuard();
-  void removeGuard(const Relation &guard);
-  CG_outputRepr *printRepr(int indent, CG_outputBuilder *ocg, const std::vector<CG_outputRepr *> &stmts, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) const;
-  CG_result *clone() const;
-  void dump(int indent) const;
-
-private:
-  std::vector<CG_result *> findNextLevel() const;
-};
-
-
-struct CG_loop: public CG_result {
-  int level_;
-  CG_result *body_;
-
-  Relation known_;
-  Relation restriction_;
-  Relation bounds_;
-  Relation guard_;
-  bool needLoop_;
-  int depth_;
-
-  CG_loop(CodeGen *codegen, const BoolSet<> &active, int level, CG_result *body) {
-    codegen_ = codegen;
-    active_ = active;
-    level_ = level;
-    body_ = body;
-  }
-  ~CG_loop() { delete body_; }
-  
-  CG_result *recompute(const BoolSet<> &parent_active, const Relation &known, const Relation &restriction);
-  int populateDepth();
-  std::pair<CG_result *, Relation> liftOverhead(int depth, bool propagate_up);
-  Relation hoistGuard();
-  void removeGuard(const Relation &guard);
-  CG_outputRepr *printRepr(int indent, CG_outputBuilder *ocg, const std::vector<CG_outputRepr *> &stmts, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) const;
-  CG_outputRepr *printRepr(bool do_print_guard, int indent, CG_outputBuilder *ocg, const std::vector<CG_outputRepr *> &stmts, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) const;
-  CG_result *clone() const;
-  void dump(int indent) const;
-};
-
-
-
-struct CG_leaf: public CG_result {
-  Relation known_;
-  std::map<int, Relation> guards_;
-  
-  CG_leaf(CodeGen *codegen, const BoolSet<> &active) {
-    codegen_ = codegen;
-    active_ = active;
-  }
-  ~CG_leaf() {}
-  
-  CG_result *recompute(const BoolSet<> &parent_active, const Relation &known, const Relation &restriction);
-  int populateDepth() { return 0; }
-  std::pair<CG_result *, Relation> liftOverhead(int depth, bool propagate_up);
-  Relation hoistGuard();
-  void removeGuard(const Relation &guard);
-  CG_outputRepr *printRepr(int indent, CG_outputBuilder *ocg, const std::vector<CG_outputRepr *> &stmts, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) const;
-  CG_result *clone() const;
-  void dump(int indent) const;
-};
-
-}
-
-#endif
diff --git a/omegalib/codegen/include/code_gen/CG_outputBuilder.h b/omegalib/codegen/include/code_gen/CG_outputBuilder.h
deleted file mode 100644
index 19dc440..0000000
--- a/omegalib/codegen/include/code_gen/CG_outputBuilder.h
+++ /dev/null
@@ -1,161 +0,0 @@
-/*****************************************************************************
- Copyright (C) 1994-2000 the Omega Project Team
- Copyright (C) 2005-2011 Chun Chen
- All Rights Reserved.
-
- Purpose:
-   abstract base class of comiler IR code builder
-
- Notes:
-   All "CG_outputRepr *" parameters are consumed inside the the function
- unless explicitly stated otherwise, i.e., not valid after the call.
-   Parameter "indent" normally not used except it is used in unstructured
- string output for correct indentation.
- 
- History:
-   04/17/96 created - Lei Zhou
-   05/02/08 clarify integer floor/mod/ceil definitions, -chen
-   05/31/08 use virtual clone to implement CreateCopy, -chun
-   08/05/10 clarify NULL parameter allowance, -chun
-*****************************************************************************/
-
-#ifndef _CG_OUTPUTBUILDER_H
-#define _CG_OUTPUTBUILDER_H
-
-#include <code_gen/CG_outputRepr.h>
-
-#include <string>
-#include <vector>
-
-namespace omega {
-
-//! abstract base class of comiler IR code builder
-class CG_outputBuilder {
-public:
-  CG_outputBuilder() {}
-  virtual ~CG_outputBuilder() {}
-
-  //! substitute variables in stmt
-  virtual CG_outputRepr *CreateSubstitutedStmt(int indent, CG_outputRepr *stmt,
-                                               const std::vector<std::string> &vars,
-                                               std::vector<CG_outputRepr *> &subs) const = 0;
-
-  //! assignment stmt generation
-  virtual CG_outputRepr *CreateAssignment(int indent, CG_outputRepr *lhs,
-                                          CG_outputRepr *rhs) const = 0;
-
-  //! function invocation generation
-  virtual CG_outputRepr *CreateInvoke(const std::string &funcName,
-                                      std::vector<CG_outputRepr *> &argList) const = 0;
-
-  //! comment generation
-  virtual CG_outputRepr *CreateComment(int indent,
-                                       const std::string &commentText) const = 0;
-
-  //! Attribute generation
-  virtual CG_outputRepr* CreateAttribute(CG_outputRepr  *control,
-                                           const std::string &commentText) const = 0;
-  //! Pragma Attribute
-  virtual CG_outputRepr* CreatePragmaAttribute(CG_outputRepr *scopeStmt, int looplevel, const std::string &pragmaText) const = 0;
-  
-  //! Prefetch Attribute
-  virtual CG_outputRepr* CreatePrefetchAttribute(CG_outputRepr *scopeStmt, int looplevel, const std::string &arrName, int hint) const = 0;
-
-  //! generate if stmt, true/false stmt can be NULL but not the condition
-  virtual CG_outputRepr *CreateIf(int indent, CG_outputRepr *guardCondition,
-                                  CG_outputRepr *true_stmtList,
-                                  CG_outputRepr *false_stmtList) const = 0;
-
-  //! generate loop inductive variable (loop control structure)
-  virtual CG_outputRepr *CreateInductive(CG_outputRepr *index,
-                                         CG_outputRepr *lower,
-                                         CG_outputRepr *upper,
-                                         CG_outputRepr *step) const = 0;
-
-  //! generate loop stmt from loop control and loop body, NULL parameter allowed
-  virtual CG_outputRepr *CreateLoop(int indent, CG_outputRepr *control,
-                                    CG_outputRepr *stmtList) const = 0;
-
-  //! copy operation, NULL parameter allowed.
-  /*!
-   * this function makes pointer handling uniform regardless NULL status
-   */
-  virtual CG_outputRepr *CreateCopy(CG_outputRepr *original) const {
-    if (original == NULL)
-      return NULL;
-    else
-      return original->clone();
-  }
-
-  //! basic integer number creation
-  virtual CG_outputRepr *CreateInt(int num) const = 0;
-  virtual bool isInteger(CG_outputRepr *op) const = 0;
-
-
-  //! basic identity/variable creation
-  virtual CG_outputRepr *CreateIdent(const std::string &varName) const = 0;
-
-  //! Addition operations, NULL parameter means 0,
-  virtual CG_outputRepr *CreatePlus(CG_outputRepr *lop, CG_outputRepr *rop) const = 0;
-  //! Subtraction operations, NULL parameter means 0,
-  virtual CG_outputRepr *CreateMinus(CG_outputRepr *lop, CG_outputRepr *rop) const = 0;
-  //! Multiplication operations, NULL parameter means 0,
-  virtual CG_outputRepr *CreateTimes(CG_outputRepr *lop, CG_outputRepr *rop) const = 0;
-  //! Division operations, NULL parameter means 0,
-  /*!
-   * integer division truncation method undefined, only use when lop is known
-   * to be multiple of rop, otherwise use integer floor instead
-   */
-  virtual CG_outputRepr *CreateDivide(CG_outputRepr *lop, CG_outputRepr *rop) const {
-    return CreateIntegerFloor(lop, rop);
-  }
-  
-  //! integer floor functions, NULL parameter means 0
-  /*! 
-   * second parameter must be postive (i.e. b > 0 below), otherwise function undefined
-   * 
-   * floor(a, b)
-   * * = a/b if a >= 0
-   * * = (a-b+1)/b if a < 0
-   */
-  virtual CG_outputRepr *CreateIntegerFloor(CG_outputRepr *lop, CG_outputRepr *rop) const = 0;
-  //! integer mod functions, NULL parameter means 0
-  /*! 
-   * second parameter must be postive (i.e. b > 0 below), otherwise function undefined
-   *
-   * mod(a, b) = a-b*floor(a, b) where result must lie in range [0,b)
-   */
-  virtual CG_outputRepr *CreateIntegerMod(CG_outputRepr *lop, CG_outputRepr *rop) const {
-    CG_outputRepr *lop2 = CreateCopy(lop);
-    CG_outputRepr *rop2 = CreateCopy(rop);
-    return CreateMinus(lop2, CreateTimes(rop2, CreateIntegerFloor(lop, rop)));
-  }
-  //! integer ceil functions, NULL parameter means 0
-  /*! 
-   * second parameter must be postive (i.e. b > 0 below), otherwise function undefined
-   *
-   * ceil(a, b) = -floor(-a, b) or floor(a+b-1, b) or floor(a-1, b)+1
-   */
-  virtual CG_outputRepr *CreateIntegerCeil(CG_outputRepr *lop, CG_outputRepr *rop) const {
-    return CreateMinus(NULL, CreateIntegerFloor(CreateMinus(NULL, lop), rop));
-  }
-
-  //! binary logical operation, NULL parameter means TRUE
-  virtual CG_outputRepr *CreateAnd(CG_outputRepr *lop, CG_outputRepr *rop) const = 0;
-
-  //! binary conditional Greater than or equal to
-  virtual CG_outputRepr *CreateGE(CG_outputRepr *lop, CG_outputRepr *rop) const {
-    return CreateLE(rop, lop);
-  } 
-  //! binary conditional Less than or equal to
-  virtual CG_outputRepr *CreateLE(CG_outputRepr *lop, CG_outputRepr *rop) const = 0;
-  //! binary conditional equal to
-  virtual CG_outputRepr *CreateEQ(CG_outputRepr *lop, CG_outputRepr *rop) const = 0;
- 
-  //! join stmts together, NULL parameter allowed
-  virtual CG_outputRepr *StmtListAppend(CG_outputRepr *list1, CG_outputRepr *list2) const = 0;
-};
-
-}
-
-#endif
diff --git a/omegalib/codegen/include/code_gen/CG_outputRepr.h b/omegalib/codegen/include/code_gen/CG_outputRepr.h
deleted file mode 100644
index 0897007..0000000
--- a/omegalib/codegen/include/code_gen/CG_outputRepr.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*****************************************************************************
- Copyright (C) 1994-2000 the Omega Project Team
- Copyright (C) 2005-2011 Chun Chen
- All Rights Reserved.
-
- Purpose:
-   abstract base class of compiler IR code wrapper
-
- Notes:
-
- History:
-   04/17/96 - Lei Zhou - created
-*****************************************************************************/
-
-#ifndef _CG_OUTPUTREPR_H
-#define _CG_OUTPUTREPR_H
-
-namespace omega {
-
-class CG_outputRepr {
-public:
-  CG_outputRepr() {}
-  //! shallow delete
-  virtual ~CG_outputRepr() { }
-  virtual CG_outputRepr *clone() const = 0;
-  //! delete actual IR code wrapped inside
-  virtual void clear() { }
-  virtual void dump() const {}
-};
-
-}
-
-#endif
diff --git a/omegalib/codegen/include/code_gen/CG_roseBuilder.h b/omegalib/codegen/include/code_gen/CG_roseBuilder.h
deleted file mode 100644
index 5dad663..0000000
--- a/omegalib/codegen/include/code_gen/CG_roseBuilder.h
+++ /dev/null
@@ -1,108 +0,0 @@
-#ifndef CG_roseBuilder_h
-#define CG_roseBuilder_h
-
-#include <basic/Tuple.h>
-#include <code_gen/rose_attributes.h>
-#include <code_gen/CG_outputBuilder.h>
-#include <code_gen/CG_roseRepr.h>
-#include <string>
-
-namespace omega {
-
-class CG_roseBuilder : public CG_outputBuilder { 
-public:
-  CG_roseBuilder(int isFortran, SgGlobal* global, SgGlobal* global_scope, SgSymbolTable* symtab1, SgSymbolTable* symtab2,  SgNode* root);
-  ~CG_roseBuilder();
-   
-  //! substitute variables in stmt
-   CG_outputRepr *CreateSubstitutedStmt(int indent, CG_outputRepr *stmt,
-                                               const std::vector<std::string> &vars,
-                                               std::vector<CG_outputRepr *> &subs) const;
-
-
-  
-  //! assignment generation
-   CG_outputRepr* CreateAssignment(int indent, CG_outputRepr* lhs,
-                                          CG_outputRepr* rhs) const;
-
-  //! function invocation generation
-    CG_outputRepr* CreateInvoke(const std::string &funcName,
-    		std::vector<CG_outputRepr *> &argList) const;
-  
-  //! comment generation
-   CG_outputRepr* CreateComment(int indent, const std::string &commentText) const;
-  //! Attribute generation
-    CG_outputRepr* CreateAttribute(CG_outputRepr  *control,
-                                          const std::string &commentText) const;
-  //! Pragma Attribute
-  CG_outputRepr* CreatePragmaAttribute(CG_outputRepr *scopeStmt, int looplevel,
-                                          const std::string &pragmaText) const;
-  
-  //! Prefetch Attribute
-  CG_outputRepr* CreatePrefetchAttribute(CG_outputRepr *scopeStmt, int looplevel,
-                                          const std::string &arrName, int hint) const;
-
-  //! if stmt gen operations
-   CG_outputRepr* CreateIf(int indent, CG_outputRepr* guardCondition,
-                                  CG_outputRepr* true_stmtList, CG_outputRepr* false_stmtList) const;
-   
-  //! inductive variable generation, to be used in CreateLoop as control
-   CG_outputRepr* CreateInductive(CG_outputRepr* index,
-                                         CG_outputRepr* lower,
-                                         CG_outputRepr* upper,
-                                         CG_outputRepr* step) const;
-
-  //! loop stmt generation
-   CG_outputRepr* CreateLoop(int indent, CG_outputRepr* control,
-                                    CG_outputRepr* stmtList) const;
-
-   CG_outputRepr* CreateInt(int num ) const;
-   bool isInteger(CG_outputRepr *op) const;
-   CG_outputRepr* CreateIdent(const std::string &varName) const;
-
-   //! binary arithmetic operations
-   CG_outputRepr* CreatePlus(CG_outputRepr* lop, CG_outputRepr* rop) const;
-   CG_outputRepr* CreateMinus(CG_outputRepr* lop, CG_outputRepr* rop) const;
-   CG_outputRepr* CreateTimes(CG_outputRepr* lop, CG_outputRepr* rop) const;
-   CG_outputRepr* CreateIntegerFloor(CG_outputRepr* lop, CG_outputRepr* rop) const;
-   CG_outputRepr* CreateIntegerMod(CG_outputRepr* lop, CG_outputRepr* rop) const;
-
-  //! binary logical operations
-   CG_outputRepr* CreateAnd(CG_outputRepr* lop, CG_outputRepr* rop) const;
-
-  //---------------------------------------------------------------------------
-  // binary relational operations
-  //---------------------------------------------------------------------------
-  // CG_outputRepr* CreateGE(CG_outputRepr*, CG_outputRepr*) const;
-   CG_outputRepr* CreateLE(CG_outputRepr* lop, CG_outputRepr* rop) const;
-   CG_outputRepr* CreateEQ(CG_outputRepr* lop, CG_outputRepr* rop) const;
-     
-  //---------------------------------------------------------------------------
-  // stmt list gen operations
-  //---------------------------------------------------------------------------
-   CG_outputRepr*
-    StmtListAppend(CG_outputRepr* list1, CG_outputRepr* list2) const;
-
-   CG_outputRepr* CreateDim3(const char* varName, CG_outputRepr* arg1, CG_outputRepr*  arg2, CG_outputRepr* arg3 = NULL) const;
-
-   // Manu:: added for fortran support
-   bool isInputFortran() const;
-
-private:
-  SgSymbolTable *symtab_;
-  SgSymbolTable *symtab2_;
-  SgNode* root_;
-  SgGlobal* global_;
-  SgGlobal* global_scope;
-  int isFortran; // Manu:: added for fortran support
-};
-
-extern char *k_ocg_comment;
-std::vector<SgVarRefExp *>substitute(SgNode *tnl, const SgVariableSymbol *sym, SgExpression *expr,SgNode* root) ;
-
-
-
-
-} // namespace
-
-#endif
diff --git a/omegalib/codegen/include/code_gen/CG_roseRepr.h b/omegalib/codegen/include/code_gen/CG_roseRepr.h
deleted file mode 100644
index 28553e7..0000000
--- a/omegalib/codegen/include/code_gen/CG_roseRepr.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef CG_roseRepr_h
-#define CG_roseRepr_h
-
-#include <code_gen/CG_outputRepr.h>
-#include "rose.h"
-
-namespace omega {
-
-class CG_roseRepr : public CG_outputRepr {
-  friend class CG_roseBuilder;
-public:
-  CG_roseRepr();
-  CG_roseRepr(SgNode *tnl);
-  CG_roseRepr(SgExpression *exp);
-  CG_roseRepr(SgStatementPtrList* stmtlist);
-
-  ~CG_roseRepr();
-  CG_outputRepr *clone() const;
-  void clear();
-
-  SgNode* GetCode() const;
-  SgStatementPtrList* GetList() const;
-  SgExpression *GetExpression() const;
-
-
-
-
-  //---------------------------------------------------------------------------
-  // Dump operations
-  //---------------------------------------------------------------------------
-  void Dump() const;
-private:
-  // only one of _tnl and _op would be active at any time, depending on
-  // whether it is building a statement list or an expression tree
-  SgNode  *tnl_;
-  SgExpression  *op_;
-  SgStatementPtrList *list_;
-  void DumpFileHelper(SgNode* node, FILE* fp) const; 
-  //operand op_;
-};
-
-
-
-} // namespace
-
-#endif
diff --git a/omegalib/codegen/include/code_gen/CG_stringBuilder.h b/omegalib/codegen/include/code_gen/CG_stringBuilder.h
deleted file mode 100644
index 09d3503..0000000
--- a/omegalib/codegen/include/code_gen/CG_stringBuilder.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef _CG_STRINGBUILDER_H
-#define _CG_STRINGBUILDER_H
-
-#include <code_gen/CG_outputBuilder.h>
-#include <code_gen/CG_stringRepr.h>
-
-namespace omega {
-
-class CG_stringBuilder: public CG_outputBuilder { 
-public:
-  CG_stringBuilder() {}
-  ~CG_stringBuilder() {}
-  bool isInteger(CG_outputRepr *op) const;
-  CG_stringRepr *CreateSubstitutedStmt(int indent, CG_outputRepr *stmt, const std::vector<std::string> &vars, std::vector<CG_outputRepr *> &subs) const;
-  CG_stringRepr *CreateAssignment(int indent, CG_outputRepr *lhs, CG_outputRepr *rhs) const;
-  CG_stringRepr *CreateInvoke(const std::string &funcName, std::vector<CG_outputRepr *> &argList) const;
-  CG_stringRepr *CreateComment(int indent, const std::string &commentText) const;
-  CG_stringRepr* CreateAttribute(CG_outputRepr *control,
-                                          const std::string &commentText) const;
-  CG_outputRepr *CreatePragmaAttribute(CG_outputRepr *scopeStmt, int looplevel, const std::string &pragmaText) const;
-  CG_outputRepr *CreatePrefetchAttribute(CG_outputRepr *scopeStmt, int looplevel, const std::string &arrName, int hint) const;
-  CG_stringRepr *CreateIf(int indent, CG_outputRepr *guardCondition, CG_outputRepr *true_stmtList, CG_outputRepr *false_stmtList) const;
-  CG_stringRepr *CreateInductive(CG_outputRepr *index, CG_outputRepr *lower, CG_outputRepr *upper, CG_outputRepr *step) const;
-  CG_stringRepr *CreateLoop(int indent, CG_outputRepr *control, CG_outputRepr *stmtList) const;
-  CG_stringRepr *CreateInt(int num) const;
-  CG_stringRepr *CreateIdent(const std::string &varName) const;
-  CG_stringRepr *CreatePlus(CG_outputRepr *lop, CG_outputRepr *rop) const;
-  CG_stringRepr *CreateMinus(CG_outputRepr *lop, CG_outputRepr *rop) const;
-  CG_stringRepr *CreateTimes(CG_outputRepr *lop, CG_outputRepr *rop) const;
-  CG_stringRepr *CreateDivide(CG_outputRepr *lop, CG_outputRepr *rop) const;
-  CG_stringRepr *CreateIntegerFloor(CG_outputRepr *lop, CG_outputRepr *rop) const;
-  CG_stringRepr *CreateIntegerMod(CG_outputRepr *lop, CG_outputRepr *rop) const;
-  CG_stringRepr *CreateIntegerCeil(CG_outputRepr *lop, CG_outputRepr *rop) const;
-  CG_stringRepr *CreateAnd(CG_outputRepr *lop, CG_outputRepr *rop) const;
-  CG_stringRepr *CreateGE(CG_outputRepr *lop, CG_outputRepr *rop) const;
-  CG_stringRepr *CreateLE(CG_outputRepr *lop, CG_outputRepr *rop) const;
-  CG_stringRepr *CreateEQ(CG_outputRepr *lop, CG_outputRepr *rop) const;
-  CG_stringRepr *StmtListAppend(CG_outputRepr *list1, CG_outputRepr *list2) const;
-};
-
-
-}
-
-#endif
diff --git a/omegalib/codegen/include/code_gen/CG_stringRepr.h b/omegalib/codegen/include/code_gen/CG_stringRepr.h
deleted file mode 100644
index a6df85d..0000000
--- a/omegalib/codegen/include/code_gen/CG_stringRepr.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*****************************************************************************
- Copyright (C) 1994-2000 the Omega Project Team
- Copyright (C) 2005-2011 Chun Chen
- All Rights Reserved.
-
- Purpose:
-   pseudo string code wrapper
-
- Notes:
-
- History:
-   04/17/96 - Lei Zhou - created
-*****************************************************************************/
-
-#ifndef _CG_STRINGREPR_H
-#define _CG_STRINGREPR_H
-
-#include <code_gen/CG_outputRepr.h>
-#include <string>
-#include <iostream>
-
-namespace omega {
-
-class CG_stringRepr: public CG_outputRepr {
-private:
-  std::string s_;
-
-public:
-  CG_stringRepr() {}
-  CG_stringRepr(const std::string &s) { s_ = s; }
-  ~CG_stringRepr() {}
-  CG_outputRepr *clone() const { return new CG_stringRepr(s_); }
-  void dump() const { std::cout << s_ << std::endl; }
-
-  //---------------------------------------------------------------------------
-  // basic operation
-  //---------------------------------------------------------------------------
-  std::string GetString() const { return s_; }
-};
-
-}
-
-#endif
diff --git a/omegalib/codegen/include/code_gen/CG_utils.h b/omegalib/codegen/include/code_gen/CG_utils.h
deleted file mode 100755
index a6128bc..0000000
--- a/omegalib/codegen/include/code_gen/CG_utils.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef _CG_UTILS_H
-#define _CG_UTILS_H
-
-#include <omega.h>
-#include <code_gen/CG_outputBuilder.h>
-#include <basic/BoolSet.h>
-#include <vector>
-#include <set>
-#include <map>
-
-namespace omega {
-
-class CG_loop;
-
-CG_outputRepr *output_inequality_repr(CG_outputBuilder *ocg, const GEQ_Handle &inequality, Variable_ID v, const Relation &R, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly, std::set<Variable_ID> excluded_floor_vars = std::set<Variable_ID>());
-CG_outputRepr *output_substitution_repr(CG_outputBuilder *ocg, const EQ_Handle &equality, Variable_ID v, bool apply_v_coef, const Relation &R, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly);
-CG_outputRepr *output_upper_bound_repr(CG_outputBuilder *ocg, const GEQ_Handle &inequality, Variable_ID v, const Relation &R, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly);
-CG_outputRepr *output_lower_bound_repr(CG_outputBuilder *ocg, const GEQ_Handle &inequality, Variable_ID v, const EQ_Handle &stride_eq, Variable_ID wc, const Relation &R, const Relation &known, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly);
-
-CG_outputRepr *output_ident(CG_outputBuilder *ocg, const Relation &R, Variable_ID v, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly);
-std::pair<CG_outputRepr *, std::pair<CG_outputRepr *, int> > output_assignment(CG_outputBuilder *ocg, const Relation &R, int level, const Relation &known, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly);
-CG_outputRepr *output_loop(CG_outputBuilder *ocg, const Relation &R, int level, const Relation &known, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly);
-CG_outputRepr *output_guard(CG_outputBuilder *ocg, const Relation &R, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly);
-std::vector<CG_outputRepr *> output_substitutions(CG_outputBuilder *ocg, const Relation &R, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly);
-
-bool bound_must_hit_stride(const GEQ_Handle &inequality, Variable_ID v, const EQ_Handle &stride_eq, Variable_ID wc, const Relation &bounds, const Relation &known);
-std::pair<EQ_Handle, int> find_simplest_assignment(const Relation &R, Variable_ID v, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly = std::vector<std::pair<CG_outputRepr *, int> >());
-std::pair<bool, GEQ_Handle> find_floor_definition(const Relation &R, Variable_ID v, std::set<Variable_ID> excluded_floor_vars = std::set<Variable_ID>());
-std::pair<EQ_Handle, Variable_ID> find_simplest_stride(const Relation &R, Variable_ID v);
-Variable_ID replicate_floor_definition(const Relation &R, const Variable_ID floor_var, Relation &r, F_Exists *f_exists, F_And *f_root, std::map<Variable_ID, Variable_ID> &exists_mapping);
-
-Relation pick_one_guard(const Relation &R, int level = 0);
-CG_outputRepr *leaf_print_repr(BoolSet<> active, const std::map<int, Relation> &guards,
-                               CG_outputRepr *guard_repr, const Relation &known,
-                               int indent, CG_outputBuilder *ocg, const std::vector<int> &remap,
-                               const std::vector<Relation> &xforms, const std::vector<CG_outputRepr *> &stmts,
-                               const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly);
-CG_outputRepr *loop_print_repr(const std::vector<CG_loop *> &loops, int start, int end,
-                               const Relation &guard, CG_outputRepr *guard_repr,
-                               int indent, CG_outputBuilder *ocg, const std::vector<CG_outputRepr *> &stmts,
-                               const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly);
-
-}
-
-#endif
diff --git a/omegalib/codegen/include/code_gen/code_gen.h b/omegalib/codegen/include/code_gen/code_gen.h
deleted file mode 100644
index abfab7c..0000000
--- a/omegalib/codegen/include/code_gen/code_gen.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#if !defined(Already_Included_code_gen)
-#define Already_Included_code_gen
-
-#include <basic/Tuple.h>
-#include <omega/Relation.h>
-#include <code_gen/CG.h>
-#include <code_gen/CG_outputRepr.h>
-#include <code_gen/CG_outputBuilder.h>
-
-namespace omega {
-
-typedef Tuple<int> IntTuple;
-typedef Tuple<Relation> SetTuple;
-typedef Tuple<SetTuple> SetTupleTuple;
-typedef Tuple<Relation> RelTuple;
-typedef Tuple<RelTuple> RelTupleTuple;
-
-CG_outputRepr *MMGenerateCode(CG_outputBuilder* ocg,
-                              Tuple<Relation> &T, Tuple<Relation> &old_IS,
-                              const Tuple<CG_outputRepr *> &stmt_content,
-                              Relation &known, int effort=1);
-std::string MMGenerateCode(Tuple<Relation> &T, Tuple<Relation> &old_IS, Relation &known,
-                           int effort=1);
-
-//protonu-adding a new variant to keep Gabe's code happy
-CG_outputRepr* MMGenerateCode(CG_outputBuilder* ocg, RelTuple &T, SetTuple &old_IS, 
-		const Tuple<CG_outputRepr *> &stmt_content, Relation &known,
-		Tuple< IntTuple >& smtNonSplitLevels_,
-	       	std::vector< std::pair<int, std::string> > syncs_,
-	       	const Tuple< Tuple<std::string> >& loopIdxNames_, 
-	       	int effort=1);
-//end-protonu
-
-struct Polyhedra {
-  int last_level;
-  Tuple<Relation> transformations;
-  Relation known;
-
-  Tuple<int> remap;  // after initial iteration space's disjoint set splitting, the new statement number maps to old statement number
-  Tuple<Tuple<Relation> > projected_nIS;
- 
-  Polyhedra(const Tuple<Relation> &T, const Tuple<Relation> &old_IS, const Relation &known = Relation::Null());
-  ~Polyhedra() {}
-};
-
-}
-#endif
diff --git a/omegalib/codegen/include/code_gen/codegen.h b/omegalib/codegen/include/code_gen/codegen.h
deleted file mode 100755
index cb63bfd..0000000
--- a/omegalib/codegen/include/code_gen/codegen.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef _CODEGEN_H
-#define _CODEGEN_H
-
-#include <omega/Relation.h>
-#include <code_gen/CG.h>
-#include <code_gen/CG_outputBuilder.h>
-#include <vector>
-#include <string>
-
-namespace omega {
-
-class CodeGen {
-public:
-  static const std::string loop_var_name_prefix;
-  static const int var_substitution_threshold;
-  
-protected:
-  //! projected_IS_[level-1][new stmt#]
-  std::vector<std::vector<Relation> > projected_IS_;
-  //! transformations[original stmt#]
-  std::vector<Relation> xforms_;
-  //! no need to generate code for constraints satisfied in known
-  Relation known_;
-  //! map new stmt# to original stmt#
-  std::vector<int> remap_;
-
-public:
-  CodeGen(const std::vector<Relation> &xforms, const std::vector<Relation> &IS, const Relation &known = Relation::Null(),
-		                 std::vector< std::vector<int > > smtNonSplitLevels_ =   std::vector< std::vector<int > >(),
-		                 std::vector< std::vector<std::string> > loopIdxNames_ =  std::vector< std::vector<std::string> >(),
-		                 std::vector< std::pair<int, std::string> >  syncs_ =    std::vector< std::pair<int, std::string> >()
-		         );
-  ~CodeGen() {}
-  
-  CG_result *buildAST(int effort = 1);
-  int num_level() const { return projected_IS_.size(); }
-  
-private:
-  CG_result *buildAST(int level, const BoolSet<> &active, bool split_on_const, const Relation &restriction);
-
-  friend class CG_result;
-  friend class CG_split;
-  friend class CG_loop;
-  friend class CG_leaf;
-};
-
-}
-#endif
diff --git a/omegalib/codegen/include/code_gen/codegen_error.h b/omegalib/codegen/include/code_gen/codegen_error.h
deleted file mode 100755
index 06ecc2b..0000000
--- a/omegalib/codegen/include/code_gen/codegen_error.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef _CODEGEN_ERROR_H
-#define _CODEGEN_ERROR_H
-
-#include <stdexcept>
-
-namespace omega {
-
-struct codegen_error: public std::runtime_error {
-  codegen_error(const std::string &msg): std::runtime_error("codegen error: " + msg) {}
-};
-
-
-}
-#endif
-
diff --git a/omegalib/codegen/include/code_gen/output_repr.h b/omegalib/codegen/include/code_gen/output_repr.h
deleted file mode 100644
index 254e71b..0000000
--- a/omegalib/codegen/include/code_gen/output_repr.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef OUTPUT_REPR_H
-#define OUTPUT_REPR_H
-
-#include <omega.h>
-#include <code_gen/CG_outputBuilder.h>
-#include <code_gen/CG_outputRepr.h>
-#include <vector>
-#include <set>
-
-namespace omega {
-extern int last_level;
-
-CG_outputRepr* outputIdent(CG_outputBuilder* ocg, const Relation &R, Variable_ID v, const std::vector<CG_outputRepr *> &assigned_on_the_fly);
-std::pair<CG_outputRepr *, bool> outputAssignment(CG_outputBuilder *ocg, const Relation &R_, Variable_ID v, Relation &enforced, CG_outputRepr *&if_repr, const std::vector<CG_outputRepr *> &assigned_on_the_fly);
-std::pair<CG_outputRepr *, bool> outputBounds(CG_outputBuilder* ocg, const Relation &bounds, Variable_ID v, int indent, Relation &enforced, const std::vector<CG_outputRepr *> &assigned_on_the_fly);
-Tuple<CG_outputRepr*> outputSubstitution(CG_outputBuilder* ocg, const Relation &R, const std::vector<CG_outputRepr *> &assigned_on_the_fly);
-CG_outputRepr* outputStatement(CG_outputBuilder* ocg, CG_outputRepr *stmt, int indent,  const Relation &mapping, const Relation &known, const std::vector<CG_outputRepr *> &assigned_on_the_fly);
-CG_outputRepr* outputGuard(CG_outputBuilder* ocg, const Relation &guards_in, const std::vector<CG_outputRepr *> &assigned_on_the_fly);
-CG_outputRepr* output_as_guard(CG_outputBuilder* ocg, const Relation &guards_in, Constraint_Handle e, bool is_equality, const std::vector<CG_outputRepr *> &assigned_on_the_fly);
-CG_outputRepr* output_EQ_strides(CG_outputBuilder* ocg, const Relation &guards_in, const std::vector<CG_outputRepr *> &assigned_on_the_fly);
-CG_outputRepr* output_GEQ_strides(CG_outputBuilder* ocg, const Relation &guards_in, const std::vector<CG_outputRepr *> &assigned_on_the_fly);
-CG_outputRepr *outputLBasRepr(CG_outputBuilder* ocg, const GEQ_Handle &g, Relation &bounds, Variable_ID v, coef_t stride, const EQ_Handle &strideEQ, Relation known, const std::vector<CG_outputRepr *> &assigned_on_the_fly);
-CG_outputRepr *outputUBasRepr(CG_outputBuilder* ocg, const GEQ_Handle &g,  Relation & bounds, Variable_ID v,
-                              coef_t /*stride*/, // currently unused
-                              const EQ_Handle &/*strideEQ*/,
-                              const std::vector<CG_outputRepr *> &assigned_on_the_fly = std::vector<CG_outputRepr *>(last_level, static_cast<CG_outputRepr *>(NULL)));
-CG_outputRepr* outputEasyBoundAsRepr(CG_outputBuilder* ocg, Relation &bounds, const Constraint_Handle &g, Variable_ID v, bool ignoreWC, int ceiling, const std::vector<CG_outputRepr *> &assigned_on_the_fly);
-
-
-bool boundHitsStride(const GEQ_Handle &g, Variable_ID v, const EQ_Handle &strideEQ, coef_t /*stride, currently unused*/, Relation known);
-Relation greatest_common_step(const Tuple<Relation> &I, const Tuple<int> &active, int level, const Relation &known = Relation::Null());
-bool findFloorInequality(Relation &r, Variable_ID v, GEQ_Handle &h, Variable_ID excluded);
-Relation project_onto_levels(Relation R, int last_level, bool wildcards);
-bool isSimpleStride(const EQ_Handle &g, Variable_ID v);
-int countStrides(Conjunct *c, Variable_ID v, EQ_Handle &strideEQ, bool &simple);
-bool hasBound(Relation r, int level, int UB);
-bool find_any_constraint(int s, int level, Relation &kr, int direction, Relation &S, bool approx);
-bool has_nonstride_EQ(Relation r, int level);
-Relation pickOverhead(Relation r, int liftTo);
-Relation minMaxOverhead(Relation r, int level);
-int max_fs_arity(const Constraint_Handle &c);
-
-
-}
-
-#endif
diff --git a/omegalib/codegen/include/code_gen/rose_attributes.h b/omegalib/codegen/include/code_gen/rose_attributes.h
deleted file mode 100644
index 9766f52..0000000
--- a/omegalib/codegen/include/code_gen/rose_attributes.h
+++ /dev/null
@@ -1,91 +0,0 @@
-#ifndef ROSE_ATTRIBUTES_HH
-#define ROSE_ATTRIBUTES_HH
-
-#include "rose.h"
-#include <algorithm>
-#include <string>
-#include <vector>
-
-namespace omega {
-
-class CodeInsertion;
-
-typedef std::vector<CodeInsertion*> CodeInsertionPtrList;
-typedef std::vector<CodeInsertion*>::iterator CodeInsertionPtrListItr;
-
-class CodeInsertion {
-public:
-	int loop_level;
-	bool marked;
-	CodeInsertion(int looplevel) { this->loop_level = looplevel; marked = false; }
-	~CodeInsertion() {}
-	virtual SgStatement* getStatement(SgScopeStatement* scopeStmt = NULL) = 0;
-};
-
-class PragmaInsertion : public CodeInsertion {
-private:
-	std::string name;
-public:
-	PragmaInsertion(int loop_level, const std::string &pragma) : CodeInsertion(loop_level) { this->name = std::string(pragma); }
-	~PragmaInsertion() { }
-	virtual SgStatement* getStatement(SgScopeStatement* scopeStmt = NULL);
-};
-
-class MMPrefetchInsertion : public CodeInsertion {
-private:
-	std::string arrName;
-	std::vector<std::string*> indecies;
-	std::vector<int> offsets;
-	int indexCount;
-	int cacheHint;
-	void initialize(const std::string& arrName, int hint);
-	void addDim(int offset);
-	void addDim(int offset, const std::string& indexer);
-	SgExpression* buildArrArg(SgScopeStatement* scopeStmt);
-	SgExpression* makeIndexExp(int dim, SgScopeStatement* scopeStmt);
-public:
-	MMPrefetchInsertion(int loop_level, const std::string &arr, int hint) : CodeInsertion(loop_level)
-		{ this->initialize(arr, hint); }
-	~MMPrefetchInsertion() { }
-	virtual SgStatement* getStatement(SgScopeStatement* scopeStmt = NULL);
-};
-
-class CodeInsertionAttribute : public AstAttribute {
-private:
-	std::vector<CodeInsertion*> code_insertions;
-public:
-	CodeInsertionAttribute() { code_insertions = std::vector<CodeInsertion*>(); }
-	~CodeInsertionAttribute() {}
-	
-	void add(CodeInsertion* ci) { code_insertions.push_back(ci); }
-	CodeInsertionPtrListItr begin() { return code_insertions.begin(); }
-	CodeInsertionPtrListItr end() { return code_insertions.end(); }
-	void remove(CodeInsertion* ci) { std::remove(code_insertions.begin(), code_insertions.end(), ci); }
-	int countCodeInsertions() { return code_insertions.size(); }
-};
-
-struct CodeInsertionMark {
-public:
-	SgStatement* stmt;
-	CodeInsertion* ci;
-};
-
-class CodeInsertionVisitor : public AstPrePostProcessing {
-private:
-	int loop_level;
-	std::vector<CodeInsertionMark*> ci_marks;
-	void markStmt(SgStatement* stmt, CodeInsertion* ci);
-public:
-	void initialize();
-	virtual void preOrderVisit(SgNode* n);
-	virtual void postOrderVisit(SgNode* n);
-	void insertCode();
-};
-
-void postProcessRoseCodeInsertion(SgProject* proj);
-void copyAttributes(SgNode* s, SgNode* d);
-CodeInsertionAttribute* getOrCreateCodeInsertionAttribute(SgNode* node);
-
-}
-
-#endif
diff --git a/omegalib/codegen/src/CG.cc b/omegalib/codegen/src/CG.cc
deleted file mode 100644
index 42bd172..0000000
--- a/omegalib/codegen/src/CG.cc
+++ /dev/null
@@ -1,1163 +0,0 @@
-/*****************************************************************************
- Copyright (C) 1994-2000 the Omega Project Team
- Copyright (C) 2005-2011 Chun Chen
- All Rights Reserved.
-
- Purpose:
- CG node classes, used to build AST tree from polyhedra scanning.
-
- Notes:
- Parameter "restriction" is always tighter than "known" since CG_split
- node does not correspond to any code for enforcement. This property is
- destroyed after hoistGuard since "restriction" is not used anymore.
- CG node's children are guaranteed not to be NULL, either NULL child is
- removed from the children or the parent node itself becomes NULL.
-
- History:
- 04/20/96 printRepr added by D people. Lei Zhou
- 10/24/06 hoistGuard added by chun
- 08/03/10 collect CG classes into one place, by Chun Chen
- 08/04/10 track dynamically substituted variables in printRepr, by chun
- 04/02/11 rewrite the CG node classes, by chun
- *****************************************************************************/
-
-#include <typeinfo>
-#include <assert.h>
-#include <omega.h>
-#include <code_gen/codegen.h>
-#include <code_gen/CG.h>
-#include <code_gen/CG_outputBuilder.h>
-#include <code_gen/CG_stringBuilder.h>
-#include <code_gen/CG_utils.h>
-#include <code_gen/codegen_error.h>
-#include <stack>
-#include <string.h>
-
-namespace omega {
-
-extern std::vector<std::vector<int> > smtNonSplitLevels;
-extern std::vector<std::vector<std::string> > loopIdxNames; //per stmt
-extern std::vector<std::pair<int, std::string> > syncs;
-
-extern int checkLoopLevel;
-extern int stmtForLoopCheck;
-extern int upperBoundForLevel;
-extern int lowerBoundForLevel;
-extern bool fillInBounds;
-
-//-----------------------------------------------------------------------------
-// Class: CG_result
-//-----------------------------------------------------------------------------
-
-CG_outputRepr *CG_result::printRepr(CG_outputBuilder *ocg,
-		const std::vector<CG_outputRepr *> &stmts) const {
-	return printRepr(1, ocg, stmts,
-			std::vector<std::pair<CG_outputRepr *, int> >(num_level(),
-					std::make_pair(static_cast<CG_outputRepr *>(NULL), 0)));
-}
-
-std::string CG_result::printString() const {
-	CG_stringBuilder ocg;
-	std::vector<CG_outputRepr *> stmts(codegen_->xforms_.size());
-	for (int i = 0; i < stmts.size(); i++)
-		stmts[i] = new CG_stringRepr("s" + to_string(i));
-	CG_stringRepr *repr = static_cast<CG_stringRepr *>(printRepr(&ocg, stmts));
-	for (int i = 0; i < stmts.size(); i++)
-		delete stmts[i];
-
-	if (repr != NULL) {
-		std::string s = repr->GetString();
-		delete repr;
-		return s;
-	} else
-		return std::string();
-}
-
-int CG_result::num_level() const {
-	return codegen_->num_level();
-}
-
-//-----------------------------------------------------------------------------
-// Class: CG_split
-//-----------------------------------------------------------------------------
-
-CG_result *CG_split::recompute(const BoolSet<> &parent_active,
-		const Relation &known, const Relation &restriction) {
-	active_ &= parent_active;
-	if (active_.empty()) {
-		delete this;
-		return NULL;
-	}
-
-
-	int i = 0;
-	while (i < restrictions_.size()) {
-		Relation new_restriction = Intersection(copy(restrictions_[i]),
-				copy(restriction));
-
-		new_restriction.simplify(2, 4);
-		//new_restriction.simplify();
-		clauses_[i] = clauses_[i]->recompute(active_, copy(known),
-				new_restriction);
-		if (clauses_[i] == NULL) {
-			restrictions_.erase(restrictions_.begin() + i);
-			clauses_.erase(clauses_.begin() + i);
-		} else
-			i++;
-	}
-
-
-	if (restrictions_.size() == 0) {
-		delete this;
-		return NULL;
-	} else
-		return this;
-}
-
-int CG_split::populateDepth() {
-	int max_depth = 0;
-	for (int i = 0; i < clauses_.size(); i++) {
-		int t = clauses_[i]->populateDepth();
-		if (t > max_depth)
-			max_depth = t;
-	}
-	return max_depth;
-}
-
-std::pair<CG_result *, Relation> CG_split::liftOverhead(int depth,
-		bool propagate_up) {
-	for (int i = 0; i < clauses_.size();) {
-		std::pair<CG_result *, Relation> result = clauses_[i]->liftOverhead(
-				depth, propagate_up);
-		if (result.first == NULL)
-			clauses_.erase(clauses_.begin() + i);
-		else {
-			clauses_[i] = result.first;
-			if (!result.second.is_obvious_tautology())
-				return std::make_pair(this, result.second);
-			i++;
-		}
-
-	}
-
-	if (clauses_.size() == 0) {
-		delete this;
-		return std::make_pair(static_cast<CG_result *>(NULL),
-				Relation::True(num_level()));
-	} else
-		return std::make_pair(this, Relation::True(num_level()));
-}
-
-Relation CG_split::hoistGuard() {
-	std::vector<Relation> guards;
-	for (int i = 0; i < clauses_.size(); i++)
-		guards.push_back(clauses_[i]->hoistGuard());
-
-	return SimpleHull(guards, true, true);
-}
-
-void CG_split::removeGuard(const Relation &guard) {
-	for (int i = 0; i < clauses_.size(); i++)
-		clauses_[i]->removeGuard(guard);
-}
-
-std::vector<CG_result *> CG_split::findNextLevel() const {
-	std::vector<CG_result *> result;
-	for (int i = 0; i < clauses_.size(); i++) {
-		CG_split *splt = dynamic_cast<CG_split *>(clauses_[i]);
-		if (splt != NULL) {
-			std::vector<CG_result *> t = splt->findNextLevel();
-			result.insert(result.end(), t.begin(), t.end());
-		} else
-			result.push_back(clauses_[i]);
-	}
-
-	return result;
-}
-
-CG_outputRepr *CG_split::printRepr(int indent, CG_outputBuilder *ocg,
-		const std::vector<CG_outputRepr *> &stmts,
-		const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) const {
-	CG_outputRepr *stmtList = NULL;
-	std::vector<CG_result *> next_level = findNextLevel();
-
-	std::vector<CG_loop *> cur_loops;
-	for (int i = 0; i < next_level.size(); i++) {
-		CG_loop *lp = dynamic_cast<CG_loop *>(next_level[i]);
-		if (lp != NULL) {
-			cur_loops.push_back(lp);
-		} else {
-			stmtList = ocg->StmtListAppend(stmtList,
-					loop_print_repr(cur_loops, 0, cur_loops.size(),
-							Relation::True(num_level()), NULL, indent, ocg,
-							stmts, assigned_on_the_fly));
-			stmtList = ocg->StmtListAppend(stmtList,
-					next_level[i]->printRepr(indent, ocg, stmts,
-							assigned_on_the_fly));
-			cur_loops.clear();
-		}
-	}
-
-	stmtList = ocg->StmtListAppend(stmtList,
-			loop_print_repr(cur_loops, 0, cur_loops.size(),
-					Relation::True(num_level()), NULL, indent, ocg, stmts,
-					assigned_on_the_fly));
-	return stmtList;
-}
-
-CG_result *CG_split::clone() const {
-	std::vector<CG_result *> clauses(clauses_.size());
-	for (int i = 0; i < clauses_.size(); i++)
-		clauses[i] = clauses_[i]->clone();
-	return new CG_split(codegen_, active_, restrictions_, clauses);
-}
-
-void CG_split::dump(int indent) const {
-	std::string prefix;
-	for (int i = 0; i < indent; i++)
-		prefix += "  ";
-	std::cout << prefix << "SPLIT: " << active_ << std::endl;
-	for (int i = 0; i < restrictions_.size(); i++) {
-		std::cout << prefix << "restriction: ";
-		const_cast<CG_split *>(this)->restrictions_[i].print();
-		clauses_[i]->dump(indent + 1);
-	}
-
-}
-
-//-----------------------------------------------------------------------------
-// Class: CG_loop
-//-----------------------------------------------------------------------------
-
-CG_result *CG_loop::recompute(const BoolSet<> &parent_active,
-		const Relation &known, const Relation &restriction) {
-	known_ = copy(known);
-	restriction_ = copy(restriction);
-	active_ &= parent_active;
-
-	std::vector<Relation> Rs;
-	for (BoolSet<>::iterator i = active_.begin(); i != active_.end(); i++) {
-		Relation r = Intersection(copy(restriction),
-				copy(codegen_->projected_IS_[level_ - 1][*i]));
-
-		//r.simplify(2, 4);
-		r.simplify();
-		if (!r.is_upper_bound_satisfiable()) {
-			active_.unset(*i);
-			continue;
-		}
-		Rs.push_back(copy(r));
-	}
-
-	if (active_.empty()) {
-		delete this;
-		return NULL;
-	}
-
-	Relation hull = SimpleHull(Rs, true, true);
-
-	//hull.simplify(2,4);
-
-	// check if actual loop is needed
-	std::pair<EQ_Handle, int> result = find_simplest_assignment(hull,
-			hull.set_var(level_));
-	if (result.second < INT_MAX) {
-		needLoop_ = false;
-
-		bounds_ = Relation(hull.n_set());
-		F_Exists *f_exists = bounds_.add_and()->add_exists();
-		F_And *f_root = f_exists->add_and();
-		std::map<Variable_ID, Variable_ID> exists_mapping;
-		EQ_Handle h = f_root->add_EQ();
-		for (Constr_Vars_Iter cvi(result.first); cvi; cvi++) {
-			Variable_ID v = cvi.curr_var();
-			switch (v->kind()) {
-			case Input_Var:
-				h.update_coef(bounds_.input_var(v->get_position()),
-						cvi.curr_coef());
-				break;
-			case Wildcard_Var: {
-				Variable_ID v2 = replicate_floor_definition(hull, v, bounds_,
-						f_exists, f_root, exists_mapping);
-				h.update_coef(v2, cvi.curr_coef());
-				break;
-			}
-			case Global_Var: {
-				Global_Var_ID g = v->get_global_var();
-				Variable_ID v2;
-				if (g->arity() == 0)
-					v2 = bounds_.get_local(g);
-				else
-					v2 = bounds_.get_local(g, v->function_of());
-				h.update_coef(v2, cvi.curr_coef());
-				break;
-			}
-			default:
-				assert(false);
-			}
-		}
-		h.update_const(result.first.get_const());
-		bounds_.simplify();
-	}
-	// loop iterates more than once, extract bounds now
-	else {
-		needLoop_ = true;
-
-		bounds_ = Relation(hull.n_set());
-		F_Exists *f_exists = bounds_.add_and()->add_exists();
-		F_And *f_root = f_exists->add_and();
-		std::map<Variable_ID, Variable_ID> exists_mapping;
-
-		Relation b = Gist(copy(hull), copy(known), 1);
-		bool has_unresolved_bound = false;
-
-		std::set<Variable_ID> excluded_floor_vars;
-		excluded_floor_vars.insert(b.set_var(level_));
-		for (GEQ_Iterator e(b.single_conjunct()->GEQs()); e; e++)
-			if ((*e).get_coef(b.set_var(level_)) != 0) {
-				bool is_bound = true;
-				for (Constr_Vars_Iter cvi(*e, true); cvi; cvi++) {
-					std::pair<bool, GEQ_Handle> result = find_floor_definition(
-							b, cvi.curr_var(), excluded_floor_vars);
-					if (!result.first) {
-						is_bound = false;
-						has_unresolved_bound = true;
-						break;
-					}
-				}
-
-				if (!is_bound)
-					continue;
-
-				GEQ_Handle h = f_root->add_GEQ();
-				for (Constr_Vars_Iter cvi(*e); cvi; cvi++) {
-					Variable_ID v = cvi.curr_var();
-					switch (v->kind()) {
-					case Input_Var:
-						h.update_coef(bounds_.input_var(v->get_position()),
-								cvi.curr_coef());
-						break;
-					case Wildcard_Var: {
-						Variable_ID v2 = replicate_floor_definition(b, v,
-								bounds_, f_exists, f_root, exists_mapping);
-						h.update_coef(v2, cvi.curr_coef());
-						break;
-					}
-					case Global_Var: {
-						Global_Var_ID g = v->get_global_var();
-						Variable_ID v2;
-						if (g->arity() == 0)
-							v2 = bounds_.get_local(g);
-						else
-							v2 = bounds_.get_local(g, v->function_of());
-						h.update_coef(v2, cvi.curr_coef());
-						break;
-					}
-					default:
-						assert(false);
-					}
-				}
-				h.update_const((*e).get_const());
-			}
-
-		if (has_unresolved_bound) {
-			b = Approximate(b);
-			b.simplify(2, 4);
-			//Simplification of Hull
-			hull = Approximate(hull);
-			hull.simplify(2, 4);
-			//end : Anand
-			for (GEQ_Iterator e(b.single_conjunct()->GEQs()); e; e++)
-				if ((*e).get_coef(b.set_var(level_)) != 0)
-					f_root->add_GEQ(*e);
-		}
-		bounds_.simplify();
-                hull.simplify(2,4);
-		// Since current SimpleHull does not support max() upper bound or min() lower bound,
-		// we have to forcefully split the loop when hull approximation does not return any bound.
-		bool has_lb = false;
-		bool has_ub = false;
-		for (GEQ_Iterator e = bounds_.single_conjunct()->GEQs(); e; e++) {
-			if ((*e).get_coef(bounds_.set_var(level_)) > 0)
-				has_lb = true;
-			else if ((*e).get_coef(bounds_.set_var(level_)) < 0)
-				has_ub = true;
-			if (has_lb && has_ub)
-				break;
-		}
-
-		if (!has_lb) {
-			for (int i = 0; i < Rs.size(); i++) {
-				Relation r = Approximate(copy(Rs[i]));
-				r.simplify(2, 4);
-				for (GEQ_Iterator e = r.single_conjunct()->GEQs(); e; e++)
-					if ((*e).get_coef(r.input_var(level_)) > 0) {
-						Relation r2 = Relation::True(num_level());
-						r2.and_with_GEQ(*e);
-						r2.simplify();
-						std::vector<Relation> restrictions(2);
-						restrictions[0] = Complement(copy(r2));
-						restrictions[0].simplify();
-						restrictions[1] = r2;
-						std::vector<CG_result *> clauses(2);
-						clauses[0] = this;
-						clauses[1] = this->clone();
-						CG_result *cgr = new CG_split(codegen_, active_,
-								restrictions, clauses);
-						cgr = cgr->recompute(active_, copy(known),
-								copy(restriction));
-						return cgr;
-					}
-			}
-			for (int i = 0; i < Rs.size(); i++) {
-				Relation r = Approximate(copy(Rs[i]));
-				r.simplify(2, 4);
-				for (EQ_Iterator e = r.single_conjunct()->EQs(); e; e++)
-					if ((*e).get_coef(r.input_var(level_)) != 0) {
-						Relation r2 = Relation::True(num_level());
-						r2.and_with_GEQ(*e);
-						r2.simplify();
-						std::vector<Relation> restrictions(2);
-						if ((*e).get_coef(r.input_var(level_)) > 0) {
-							restrictions[0] = Complement(copy(r2));
-							restrictions[0].simplify();
-							restrictions[1] = r2;
-						} else {
-							restrictions[0] = r2;
-							restrictions[1] = Complement(copy(r2));
-							restrictions[1].simplify();
-						}
-						std::vector<CG_result *> clauses(2);
-						clauses[0] = this;
-						clauses[1] = this->clone();
-						CG_result *cgr = new CG_split(codegen_, active_,
-								restrictions, clauses);
-						cgr = cgr->recompute(active_, copy(known),
-								copy(restriction));
-						return cgr;
-					}
-			}
-		} else if (!has_ub) {
-			for (int i = 0; i < Rs.size(); i++) {
-				Relation r = Approximate(copy(Rs[i]));
-				r.simplify(2, 4);
-				for (GEQ_Iterator e = r.single_conjunct()->GEQs(); e; e++)
-					if ((*e).get_coef(r.input_var(level_)) < 0) {
-						Relation r2 = Relation::True(num_level());
-						r2.and_with_GEQ(*e);
-						r2.simplify();
-						std::vector<Relation> restrictions(2);
-						restrictions[1] = Complement(copy(r2));
-						restrictions[1].simplify();
-						restrictions[0] = r2;
-						std::vector<CG_result *> clauses(2);
-						clauses[0] = this;
-						clauses[1] = this->clone();
-						CG_result *cgr = new CG_split(codegen_, active_,
-								restrictions, clauses);
-						cgr = cgr->recompute(active_, copy(known),
-								copy(restriction));
-						return cgr;
-					}
-			}
-			for (int i = 0; i < Rs.size(); i++) {
-				Relation r = Approximate(copy(Rs[i]));
-				r.simplify(2, 4);
-				for (EQ_Iterator e = r.single_conjunct()->EQs(); e; e++)
-					if ((*e).get_coef(r.input_var(level_)) != 0) {
-						Relation r2 = Relation::True(num_level());
-						r2.and_with_GEQ(*e);
-						r2.simplify();
-						std::vector<Relation> restrictions(2);
-						if ((*e).get_coef(r.input_var(level_)) > 0) {
-							restrictions[0] = Complement(copy(r2));
-							restrictions[0].simplify();
-							restrictions[1] = r2;
-						} else {
-							restrictions[0] = r2;
-							restrictions[1] = Complement(copy(r2));
-							restrictions[1].simplify();
-						}
-						std::vector<CG_result *> clauses(2);
-						clauses[0] = this;
-						clauses[1] = this->clone();
-						CG_result *cgr = new CG_split(codegen_, active_,
-								restrictions, clauses);
-						cgr = cgr->recompute(active_, copy(known),
-								copy(restriction));
-						return cgr;
-					}
-			}
-		}
-
-		if (!has_lb && !has_ub)
-			throw codegen_error(
-					"can't find any bound at loop level " + to_string(level_));
-		else if (!has_lb)
-			throw codegen_error(
-					"can't find lower bound at loop level "
-							+ to_string(level_));
-		else if (!has_ub)
-			throw codegen_error(
-					"can't find upper bound at loop level "
-							+ to_string(level_));
-	}
-	bounds_.copy_names(hull);
-	bounds_.setup_names();
-
-	// additional guard/stride condition extraction
-	if (needLoop_) {
-		Relation cur_known = Intersection(copy(bounds_), copy(known_));
-		cur_known.simplify();
-		hull = Gist(hull, copy(cur_known), 1);
-
-		std::pair<EQ_Handle, Variable_ID> result = find_simplest_stride(hull,
-				hull.set_var(level_));
-		if (result.second != NULL)
-			if (abs(result.first.get_coef(hull.set_var(level_))) == 1) {
-				F_Exists *f_exists = bounds_.and_with_and()->add_exists();
-				F_And *f_root = f_exists->add_and();
-				std::map<Variable_ID, Variable_ID> exists_mapping;
-				EQ_Handle h = f_root->add_EQ();
-				for (Constr_Vars_Iter cvi(result.first); cvi; cvi++) {
-					Variable_ID v = cvi.curr_var();
-					switch (v->kind()) {
-					case Input_Var:
-						h.update_coef(bounds_.input_var(v->get_position()),
-								cvi.curr_coef());
-						break;
-					case Wildcard_Var: {
-						Variable_ID v2;
-						if (v == result.second)
-							v2 = f_exists->declare();
-						else
-							v2 = replicate_floor_definition(hull, v, bounds_,
-									f_exists, f_root, exists_mapping);
-						h.update_coef(v2, cvi.curr_coef());
-						break;
-					}
-					case Global_Var: {
-						Global_Var_ID g = v->get_global_var();
-						Variable_ID v2;
-						if (g->arity() == 0)
-							v2 = bounds_.get_local(g);
-						else
-							v2 = bounds_.get_local(g, v->function_of());
-						h.update_coef(v2, cvi.curr_coef());
-						break;
-					}
-					default:
-						assert(false);
-					}
-				}
-				h.update_const(result.first.get_const());
-			} else {
-				// since gist is not powerful enough on modular constraints for now,
-				// make an educated guess
-				coef_t stride = abs(result.first.get_coef(result.second))
-						/ gcd(abs(result.first.get_coef(result.second)),
-								abs(
-										result.first.get_coef(
-												hull.set_var(level_))));
-
-				Relation r1(hull.n_inp());
-				F_Exists *f_exists = r1.add_and()->add_exists();
-				F_And *f_root = f_exists->add_and();
-				std::map<Variable_ID, Variable_ID> exists_mapping;
-				EQ_Handle h = f_root->add_EQ();
-				for (Constr_Vars_Iter cvi(result.first); cvi; cvi++) {
-					Variable_ID v = cvi.curr_var();
-					switch (v->kind()) {
-					case Input_Var:
-						h.update_coef(r1.input_var(v->get_position()),
-								cvi.curr_coef());
-						break;
-					case Wildcard_Var: {
-						Variable_ID v2;
-						if (v == result.second)
-							v2 = f_exists->declare();
-						else
-							v2 = replicate_floor_definition(hull, v, r1,
-									f_exists, f_root, exists_mapping);
-						h.update_coef(v2, cvi.curr_coef());
-						break;
-					}
-					case Global_Var: {
-						Global_Var_ID g = v->get_global_var();
-						Variable_ID v2;
-						if (g->arity() == 0)
-							v2 = r1.get_local(g);
-						else
-							v2 = r1.get_local(g, v->function_of());
-						h.update_coef(v2, cvi.curr_coef());
-						break;
-					}
-					default:
-						assert(false);
-					}
-				}
-				h.update_const(result.first.get_const());
-				r1.simplify();
-
-				bool guess_success = false;
-				for (GEQ_Iterator e(bounds_.single_conjunct()->GEQs()); e; e++)
-					if ((*e).get_coef(bounds_.set_var(level_)) == 1) {
-						Relation r2(hull.n_inp());
-						F_Exists *f_exists = r2.add_and()->add_exists();
-						F_And *f_root = f_exists->add_and();
-						std::map<Variable_ID, Variable_ID> exists_mapping;
-						EQ_Handle h = f_root->add_EQ();
-						h.update_coef(f_exists->declare(), stride);
-						for (Constr_Vars_Iter cvi(*e); cvi; cvi++) {
-							Variable_ID v = cvi.curr_var();
-							switch (v->kind()) {
-							case Input_Var:
-								h.update_coef(r2.input_var(v->get_position()),
-										cvi.curr_coef());
-								break;
-							case Wildcard_Var: {
-								Variable_ID v2 = replicate_floor_definition(
-										hull, v, r2, f_exists, f_root,
-										exists_mapping);
-								h.update_coef(v2, 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(false);
-							}
-						}
-						h.update_const((*e).get_const());
-						r2.simplify();
-
-						if (Gist(copy(r1),
-								Intersection(copy(cur_known), copy(r2)), 1).is_obvious_tautology()
-								&& Gist(copy(r2),
-										Intersection(copy(cur_known), copy(r1)),
-										1).is_obvious_tautology()) {
-							bounds_ = Intersection(bounds_, r2);
-							bounds_.simplify();
-							guess_success = true;
-							break;
-						}
-					}
-
-				// this is really a stride with non-unit coefficient for this loop variable
-				if (!guess_success) {
-					// TODO: for stride ax = b mod n it might be beneficial to
-					//       generate modular linear equation solver code for
-					//       runtime to get the starting position in printRepr,
-					//       and stride would be n/gcd(|a|,n), thus this stride
-					//       can be put into bounds_ too.
-				}
-
-			}
-
-		hull = Project(hull, hull.set_var(level_));
-		hull.simplify(2, 4);
-		guard_ = Gist(hull, Intersection(copy(bounds_), copy(known_)), 1);
-	}
-	// don't generate guard for non-actual loop, postpone it. otherwise
-	// redundant if-conditions might be generated since for-loop semantics
-	// includes implicit comparison checking.  -- by chun 09/14/10
-	else
-		guard_ = Relation::True(num_level());
-	guard_.copy_names(bounds_);
-	guard_.setup_names();
-
-        //guard_.simplify();  
-	// recursively down the AST
-	Relation new_known = Intersection(copy(known),
-			Intersection(copy(bounds_), copy(guard_)));
-	new_known.simplify(2, 4);
-	Relation new_restriction = Intersection(copy(restriction),
-			Intersection(copy(bounds_), copy(guard_)));
-	new_restriction.simplify(2, 4);
-	body_ = body_->recompute(active_, new_known, new_restriction);
-	if (body_ == NULL) {
-		delete this;
-		return NULL;
-	} else
-		return this;
-}
-
-int CG_loop::populateDepth() {
-	int depth = body_->populateDepth();
-	if (needLoop_)
-		depth_ = depth + 1;
-	else
-		depth_ = depth;
-	return depth_;
-}
-
-std::pair<CG_result *, Relation> CG_loop::liftOverhead(int depth,
-		bool propagate_up) {
-	if (depth_ > depth) {
-		assert(propagate_up == false);
-		std::pair<CG_result *, Relation> result = body_->liftOverhead(depth,
-				false);
-		body_ = result.first;
-		return std::make_pair(this, Relation::True(num_level()));
-	} else { // (depth_ <= depth)
-		if (propagate_up) {
-			Relation r = pick_one_guard(guard_, level_);
-			if (!r.is_obvious_tautology())
-				return std::make_pair(this, r);
-		}
-
-		std::pair<CG_result *, Relation> result;
-		if (propagate_up || needLoop_)
-			result = body_->liftOverhead(depth, true);
-		else
-			result = body_->liftOverhead(depth, false);
-		body_ = result.first;
-		if (result.second.is_obvious_tautology())
-			return std::make_pair(this, result.second);
-
-		// loop is an assignment, replace this loop variable in overhead condition
-		if (!needLoop_) {
-			result.second = Intersection(result.second, copy(bounds_));
-			result.second = Project(result.second,
-					result.second.set_var(level_));
-			result.second.simplify(2, 4);
-		}
-
-
-		int max_level = 0;
-		bool has_wildcard = false;
-		bool direction = true;
-		for (EQ_Iterator e(result.second.single_conjunct()->EQs()); e; e++)
-			if ((*e).has_wildcards()) {
-				if (has_wildcard)
-					assert(false);
-				else
-					has_wildcard = true;
-				for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
-					if (cvi.curr_var()->kind() == Input_Var
-							&& cvi.curr_var()->get_position() > max_level)
-						max_level = cvi.curr_var()->get_position();
-			} else
-				assert(false);
-
-		if (!has_wildcard) {
-			int num_simple_geq = 0;
-			for (GEQ_Iterator e(result.second.single_conjunct()->GEQs()); e;
-					e++)
-				if (!(*e).has_wildcards()) {
-					num_simple_geq++;
-					for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
-						if (cvi.curr_var()->kind() == Input_Var
-								&& cvi.curr_var()->get_position() > max_level) {
-							max_level = cvi.curr_var()->get_position();
-							direction = (cvi.curr_coef() < 0) ? true : false;
-						}
-				} else {
-					has_wildcard = true;
-					for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
-						if (cvi.curr_var()->kind() == Input_Var
-								&& cvi.curr_var()->get_position() > max_level) {
-							max_level = cvi.curr_var()->get_position();
-						}
-				}
-			assert(
-					(has_wildcard && num_simple_geq == 0) || (!has_wildcard && num_simple_geq == 1));
-		}
-
-		// check if this is the top loop level for splitting for this overhead
-		if (!propagate_up || (has_wildcard && max_level == level_ - 1)
-				|| (!has_wildcard && max_level == level_)) {
-			std::vector<Relation> restrictions(2);
-			std::vector<CG_result *> clauses(2);
-			int saved_num_level = num_level();
-			if (has_wildcard || direction) {
-				restrictions[1] = Complement(copy(result.second));
-				restrictions[1].simplify();
-				clauses[1] = this->clone();
-				restrictions[0] = result.second;
-				clauses[0] = this;
-			} else {
-				restrictions[0] = Complement(copy(result.second));
-				restrictions[0].simplify();
-				clauses[0] = this->clone();
-				restrictions[1] = result.second;
-				clauses[1] = this;
-			}
-			CG_result *cgr = new CG_split(codegen_, active_, restrictions,
-					clauses);
-			CG_result *new_cgr = cgr->recompute(active_, copy(known_),
-					copy(restriction_));
-			new_cgr->populateDepth();
-			assert(new_cgr==cgr);
-			if (static_cast<CG_split *>(new_cgr)->clauses_.size() == 1)
-				// infinite recursion detected, bail out
-				return std::make_pair(new_cgr, Relation::True(saved_num_level));
-			else
-				return cgr->liftOverhead(depth, propagate_up);
-		} else
-			return std::make_pair(this, result.second);
-	}
-}
-
-Relation CG_loop::hoistGuard() {
-
-	Relation r = body_->hoistGuard();
-
-	// TODO: should bookkeep catched contraints in loop output as enforced and check if anything missing
-	// if (!Gist(copy(b), copy(enforced)).is_obvious_tautology()) {
-	//   fprintf(stderr, "need to generate extra guard inside the loop\n");
-	// }
-
-	  if (!needLoop_)
-	    r = Intersection(r, copy(bounds_));
-	  r = Project(r, r.set_var(level_));
-	  r = Gist(r, copy(known_), 1);
-
-	  Relation eliminate_existentials_r;
-	  Relation eliminate_existentials_known;
-
-	  eliminate_existentials_r = copy(r);
-	  if (!r.is_obvious_tautology()) {
-		  eliminate_existentials_r = Approximate(copy(r));
-		  eliminate_existentials_r.simplify(2,4);
-		  eliminate_existentials_known = Approximate(copy(known_));
-		  eliminate_existentials_known.simplify(2,4);
-
-		  eliminate_existentials_r = Gist( eliminate_existentials_r, eliminate_existentials_known, 1);
-	  }
-          
-
-	  if (!eliminate_existentials_r.is_obvious_tautology()) {
-	 // if (!r.is_obvious_tautology()) {
-	    body_->removeGuard(r);
-	    guard_ = Intersection(guard_, copy(r));
-	    guard_.simplify();
-	  }
-
-	  return guard_;
-
-	//   return ifList;
-	// }
-
-
-}
-
-void CG_loop::removeGuard(const Relation &guard) {
-	known_ = Intersection(known_, copy(guard));
-	known_.simplify();
-
-	guard_ = Gist(guard_, copy(known_), 1);
-	guard_.copy_names(known_);
-	guard_.setup_names();
-}
-
-CG_outputRepr *CG_loop::printRepr(int indent, CG_outputBuilder *ocg,
-		const std::vector<CG_outputRepr *> &stmts,
-		const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) const {
-	return printRepr(true, indent, ocg, stmts, assigned_on_the_fly);
-}
-
-CG_outputRepr *CG_loop::printRepr(bool do_print_guard, int indent,
-		CG_outputBuilder *ocg, const std::vector<CG_outputRepr *> &stmts,
-		const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) const {
-	CG_outputRepr *guardRepr;
-	if (do_print_guard)
-		guardRepr = output_guard(ocg, guard_, assigned_on_the_fly);
-	else
-		guardRepr = NULL;
-
-	Relation cur_known = Intersection(copy(known_), copy(guard_));
-	cur_known.simplify();
-	if (needLoop_) {
-
-		if (checkLoopLevel)
-			if (level_ == checkLoopLevel)
-				if (active_.get(stmtForLoopCheck))
-					fillInBounds = true;
-
-		CG_outputRepr *ctrlRepr = output_loop(ocg, bounds_, level_, cur_known,
-				assigned_on_the_fly);
-
-		fillInBounds = false;
-
-		CG_outputRepr *bodyRepr = body_->printRepr(
-				(guardRepr == NULL) ? indent + 1 : indent + 2, ocg, stmts,
-				assigned_on_the_fly);
-		CG_outputRepr * loopRepr;
-
-		if (guardRepr == NULL)
-			loopRepr = ocg->CreateLoop(indent, ctrlRepr, bodyRepr);
-		else
-			loopRepr = ocg->CreateLoop(indent + 1, ctrlRepr, bodyRepr);
-
-		if (!smtNonSplitLevels.empty()) {
-			bool blockLoop = false;
-			bool threadLoop = false;
-			bool sync = false;
-			int firstActiveStmt = -1;
-			for (int s = 0; s < active_.size(); s++) {
-				if (active_.get(s)) {
-					if (firstActiveStmt < 0)
-						firstActiveStmt = s;
-					//We assume smtNonSplitLevels is only used to mark the first of
-					//the block or thread loops to be reduced in CUDA-CHiLL. Here we
-					//place some comments to help with final code generation.
-					//int idx = smtNonSplitLevels[s].index(level_);
-
-					if (s < smtNonSplitLevels.size()) {
-						if (smtNonSplitLevels[s].size() > 0)
-							if (smtNonSplitLevels[s][0] == level_) {
-								blockLoop = true;
-							}
-						//Assume every stmt marked with a thread loop index also has a block loop idx
-						if (smtNonSplitLevels[s].size() > 1)
-							if (smtNonSplitLevels[s][1] == level_) {
-								threadLoop = true;
-							}
-					}
-				}
-			}
-			if (blockLoop && threadLoop) {
-				fprintf(stderr,
-						"Warning, have %d level more than once in smtNonSplitLevels\n",
-						level_);
-				threadLoop = false;
-			}
-			std::string preferredIdx;
-			if (loopIdxNames.size()
-					&& (level_ / 2) - 1 < loopIdxNames[firstActiveStmt].size())
-				preferredIdx = loopIdxNames[firstActiveStmt][(level_ / 2) - 1];
-			for (int s = 0; s < active_.size(); s++) {
-				if (active_.get(s)) {
-					for (int i = 0; i < syncs.size(); i++) {
-						if (syncs[i].first == s
-								&& strcmp(syncs[i].second.c_str(),
-										preferredIdx.c_str()) == 0) {
-							sync = true;
-							//printf("FOUND SYNC\n");
-						}
-
-					}
-				}
-		
-			}
-			if (threadLoop || blockLoop || preferredIdx.length() != 0) {
-				char buf[1024];
-				std::string loop;
-				if (blockLoop)
-					loop = "blockLoop ";
-				if (threadLoop)
-					loop = "threadLoop ";
-				if (preferredIdx.length() != 0 && sync) {
-					sprintf(buf, "~cuda~ %spreferredIdx: %s sync", loop.c_str(),
-							preferredIdx.c_str());
-				} else if (preferredIdx.length() != 0) {
-					sprintf(buf, "~cuda~ %spreferredIdx: %s", loop.c_str(),
-							preferredIdx.c_str());
-				} else {
-					sprintf(buf, "~cuda~ %s", loop.c_str());
-				}
-
-
-				loopRepr = ocg->CreateAttribute(loopRepr, buf);
-			}
-
-		}
-		if (guardRepr == NULL)
-			return loopRepr;
-		else
-			return ocg->CreateIf(indent, guardRepr, loopRepr, NULL);
-	} else {
-		std::pair<CG_outputRepr *, std::pair<CG_outputRepr *, int> > result =
-				output_assignment(ocg, bounds_, level_, cur_known,
-						assigned_on_the_fly);
-		guardRepr = ocg->CreateAnd(guardRepr, result.first);
-
-		if (result.second.second < CodeGen::var_substitution_threshold) {
-			std::vector<std::pair<CG_outputRepr *, int> > atof =
-					assigned_on_the_fly;
-			atof[level_ - 1] = result.second;
-			CG_outputRepr *bodyRepr = body_->printRepr(
-					(guardRepr == NULL) ? indent : indent + 1, ocg, stmts,
-					atof);
-			delete atof[level_ - 1].first;
-			if (guardRepr == NULL)
-				return bodyRepr;
-			else
-				return ocg->CreateIf(indent, guardRepr, bodyRepr, NULL);
-		} else {
-			CG_outputRepr *assignRepr = ocg->CreateAssignment(
-					(guardRepr == NULL) ? indent : indent + 1,
-					output_ident(ocg, bounds_,
-							const_cast<CG_loop *>(this)->bounds_.set_var(
-									level_), assigned_on_the_fly),
-					result.second.first);
-			CG_outputRepr *bodyRepr = body_->printRepr(
-					(guardRepr == NULL) ? indent : indent + 1, ocg, stmts,
-					assigned_on_the_fly);
-			if (guardRepr == NULL)
-				return ocg->StmtListAppend(assignRepr, bodyRepr);
-			else
-				return ocg->CreateIf(indent, guardRepr,
-						ocg->StmtListAppend(assignRepr, bodyRepr), NULL);
-		}
-
-	}
-}
-
-CG_result *CG_loop::clone() const {
-	return new CG_loop(codegen_, active_, level_, body_->clone());
-}
-
-void CG_loop::dump(int indent) const {
-	std::string prefix;
-	for (int i = 0; i < indent; i++)
-		prefix += "  ";
-	std::cout << prefix << "LOOP (level " << level_ << "): " << active_
-			<< std::endl;
-	std::cout << prefix << "known: ";
-	const_cast<CG_loop *>(this)->known_.print();
-	std::cout << prefix << "restriction: ";
-	const_cast<CG_loop *>(this)->restriction_.print();
-	std::cout << prefix << "bounds: ";
-	const_cast<CG_loop *>(this)->bounds_.print();
-	std::cout << prefix << "guard: ";
-	const_cast<CG_loop *>(this)->guard_.print();
-	body_->dump(indent + 1);
-}
-
-//-----------------------------------------------------------------------------
-// Class: CG_leaf
-//-----------------------------------------------------------------------------
-
-CG_result* CG_leaf::recompute(const BoolSet<> &parent_active,
-		const Relation &known, const Relation &restriction) {
-	active_ &= parent_active;
-	known_ = copy(known);
-
-	guards_.clear();
-	for (BoolSet<>::iterator i = active_.begin(); i != active_.end(); i++) {
-		Relation r = Intersection(
-				copy(codegen_->projected_IS_[num_level() - 1][*i]),
-				copy(restriction));
-		r.simplify(2, 4);
-		if (!r.is_upper_bound_satisfiable())
-			active_.unset(*i);
-		else {
-			r = Gist(r, copy(known), 1);
-			if (!r.is_obvious_tautology()) {
-				guards_[*i] = r;
-				guards_[*i].copy_names(known);
-				guards_[*i].setup_names();
-			}
-		}
-	}
-
-
-	if (active_.empty()) {
-		delete this;
-		return NULL;
-	} else
-		return this;
-}
-
-std::pair<CG_result *, Relation> CG_leaf::liftOverhead(int depth, bool) {
-	if (depth == 0)
-		return std::make_pair(this, Relation::True(num_level()));
-
-	for (std::map<int, Relation>::iterator i = guards_.begin();
-			i != guards_.end(); i++) {
-		Relation r = pick_one_guard(i->second);
-		if (!r.is_obvious_tautology()) {
-			bool has_wildcard = false;
-			int max_level = 0;
-			for (EQ_Iterator e(r.single_conjunct()->EQs()); e; e++) {
-				if ((*e).has_wildcards())
-					has_wildcard = true;
-				for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
-					if (cvi.curr_var()->kind() == Input_Var
-							&& cvi.curr_var()->get_position() > max_level)
-						max_level = cvi.curr_var()->get_position();
-			}
-			for (GEQ_Iterator e(r.single_conjunct()->GEQs()); e; e++) {
-				if ((*e).has_wildcards())
-					has_wildcard = true;
-				for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
-					if (cvi.curr_var()->kind() == Input_Var
-							&& cvi.curr_var()->get_position() > max_level)
-						max_level = cvi.curr_var()->get_position();
-			}
-
-			if (!(has_wildcard && max_level == codegen_->num_level()))
-				return std::make_pair(this, r);
-		}
-	}
-
-	return std::make_pair(this, Relation::True(num_level()));
-}
-
-Relation CG_leaf::hoistGuard() {
-	std::vector<Relation> guards;
-	for (BoolSet<>::iterator i = active_.begin(); i != active_.end(); i++) {
-		std::map<int, Relation>::iterator j = guards_.find(*i);
-		if (j == guards_.end()) {
-			Relation r = Relation::True(num_level());
-			r.copy_names(known_);
-			r.setup_names();
-			return r;
-		} else {
-			guards.push_back(j->second);
-		}
-	}
-
-	return SimpleHull(guards, true, true);
-}
-
-void CG_leaf::removeGuard(const Relation &guard) {
-	known_ = Intersection(known_, copy(guard));
-	known_.simplify();
-
-	std::map<int, Relation>::iterator i = guards_.begin();
-	while (i != guards_.end()) {
-		i->second = Gist(i->second, copy(known_), 1);
-		if (i->second.is_obvious_tautology())
-			guards_.erase(i++);
-		else
-			++i;
-	}
-}
-
-CG_outputRepr *CG_leaf::printRepr(int indent, CG_outputBuilder *ocg,
-		const std::vector<CG_outputRepr *> &stmts,
-		const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) const {
-	return leaf_print_repr(active_, guards_, NULL, known_, indent, ocg,
-			codegen_->remap_, codegen_->xforms_, stmts, assigned_on_the_fly);
-}
-
-CG_result *CG_leaf::clone() const {
-	return new CG_leaf(codegen_, active_);
-}
-
-void CG_leaf::dump(int indent) const {
-	std::string prefix;
-	for (int i = 0; i < indent; i++)
-		prefix += "  ";
-	std::cout << prefix << "LEAF: " << active_ << std::endl;
-	std::cout << prefix << "known: ";
-	const_cast<CG_leaf *>(this)->known_.print();
-	for (std::map<int, Relation>::const_iterator i = guards_.begin();
-			i != guards_.end(); i++) {
-		std::cout << prefix << "guard #" << i->first << ":";
-		const_cast<Relation &>(i->second).print();
-	}
-}
-
-}
diff --git a/omegalib/codegen/src/CG_roseBuilder.cc b/omegalib/codegen/src/CG_roseBuilder.cc
deleted file mode 100644
index 7e12634..0000000
--- a/omegalib/codegen/src/CG_roseBuilder.cc
+++ /dev/null
@@ -1,1093 +0,0 @@
-/*****************************************************************************
- Copyright (C) 2008 University of Southern California
- Copyright (C) 2009-2010 University of Utah
- All Rights Reserved.
-
- Purpose:
- generate suif code for omega
-
- Notes:
-
- History:
- 02/01/06 created by Chun Chen
- *****************************************************************************/
-
-#include <stack>
-#include <code_gen/CG_roseBuilder.h>
-#include <string>
-
-struct ir_error: public std::runtime_error {
-	ir_error(const std::string &msg) :
-			std::runtime_error(msg) {
-	}
-};
-
-using namespace SageBuilder;
-using namespace SageInterface;
-using namespace OmpSupport;
-
-namespace omega {
-
-//-----------------------------------------------------------------------------
-// make suif initilization happy
-//-----------------------------------------------------------------------------
-char *k_ocg_comment;
-
-CG_roseBuilder::CG_roseBuilder(int is_fortran, SgGlobal* global, SgGlobal* firstScope,
-		SgSymbolTable* symtab, SgSymbolTable* symtab2, SgNode* root) :
-		isFortran(is_fortran), global_(global), global_scope(firstScope), symtab_(symtab), symtab2_(
-				symtab2), root_(root) {
-}
-
-
-CG_roseBuilder::~CG_roseBuilder() {
-}
-
-// Manu:: returns true if input is in fortran, else returns false
-bool CG_roseBuilder::isInputFortran() const{
-	if (isFortran)
-		return true;
-	else
-		return false;
-}
-
-//-----------------------------------------------------------------------------
-// place holder generation
-//-----------------------------------------------------------------------------
-CG_outputRepr* CG_roseBuilder::CreateSubstitutedStmt(int, CG_outputRepr *stmt,
-		const std::vector<std::string> &vars, std::vector<CG_outputRepr*> &subs) const {
-
-	SgStatementPtrList* list = static_cast<CG_roseRepr *>(stmt)->list_;
-	SgNode *tnl;
-	SgStatement* statement;
-	if (list != NULL) {
-		delete stmt;
-		for (int i = 0; i < subs.size(); i++) {
-                  if (subs[i] == NULL)
-                        continue;
-
-			CG_roseRepr *repr = static_cast<CG_roseRepr*>(subs[i]);
-			SgExpression* op = repr->op_;
-
-			for (SgStatementPtrList::iterator it = (*list).begin();
-					it != (*list).end(); it++) {
-				statement = (*it);
-				tnl = isSgNode(statement);
-
-				int j;
-				int not_in_symtab_;
-
-				not_in_symtab_ = 0;
-
-				SgVariableSymbol *vs = symtab_->find_variable(
-						SgName(vars[i].c_str()));
-
-				if (vs == NULL) {
-
-					not_in_symtab_ = 1;
-
-					vs = symtab2_->find_variable(SgName(vars[i].c_str()));
-				}
-				if (vs != NULL) {
-
-					std::vector<SgVarRefExp *> array = substitute(tnl,
-							(const SgVariableSymbol*) vs, op, root_);
-					for (std::vector<SgVarRefExp *>::iterator it =
-							array.begin(); it != array.end(); it++) {
-
-						if (isSgVarRefExp(op)) {
-							if (strcmp(
-									isSgVarRefExp(op)->get_symbol()->get_name().getString().c_str(),
-									vs->get_name().getString().c_str())) {
-
-								(*it)->set_symbol(
-										isSgVarRefExp(op)->get_symbol());
-
-							}
-						} else if (isSgExpression(op)) {
-
-							if (isSgBinaryOp((*it)->get_parent()))
-								isSgBinaryOp((*it)->get_parent())->replace_expression(
-										*it, op);
-							else if (isSgUnaryOp((*it)->get_parent()))
-								isSgUnaryOp((*it)->get_parent())->replace_expression(
-										*it, op);
-							else if (isSgExprListExp((*it)->get_parent()))
-								isSgExprListExp((*it)->get_parent())->replace_expression(
-										*it, op);
-							else
-								throw ir_error("unrecognized expression type");
-						}
-
-					}
-				}
-
-			}
-
-			delete repr;
-			subs[i] = NULL;
-
-			if (subs[i] != NULL)
-				throw ir_error("not freed properly");
-
-		}
-
-		return new CG_roseRepr(list);
-
-	} else {
-		tnl = static_cast<CG_roseRepr *>(stmt)->tnl_;
-
-		if (tnl == NULL)
-			throw ir_error("both list and tnl are null!!");
-
-		delete stmt;
-		int j;
-		int not_in_symtab_;
-	 for (int i = 0; i < subs.size(); i++) {
-                if (subs[i] == NULL)
-                       continue;
-			not_in_symtab_ = 0;
-
-			
-			CG_roseRepr *repr = static_cast<CG_roseRepr*>(subs[i]);
-			SgExpression* op = repr->op_;
-			delete repr;
-			subs[i] = NULL;
-
-			SgVariableSymbol *vs = symtab_->find_variable(
-					SgName(vars[i].c_str()));
-
-			if (vs == NULL) {
-
-				not_in_symtab_ = 1;
-
-				vs = symtab2_->find_variable(SgName(vars[i].c_str()));
-			}
-			if (vs != NULL) {
-				std::vector<SgVarRefExp *> array = substitute(tnl, vs, op,
-						root_);
-
-				if (not_in_symtab_ && isSgVarRefExp(op)) {
-					if (strcmp(
-							isSgVarRefExp(op)->get_symbol()->get_name().getString().c_str(),
-							vs->get_name().getString().c_str())) {
-					}
-				}
-				
-				for (std::vector<SgVarRefExp *>::iterator j = array.begin();
-						j != array.end(); j++) {
-
-					if (isSgVarRefExp(op)) {
-						if (strcmp(
-								isSgVarRefExp(op)->get_symbol()->get_name().getString().c_str(),
-								vs->get_name().getString().c_str())) {
-							(*j)->set_symbol(isSgVarRefExp(op)->get_symbol());
-
-						}
-					} else if (isSgExpression(op)) {
-
-						if (isSgBinaryOp((*j)->get_parent()))
-							isSgBinaryOp((*j)->get_parent())->replace_expression(
-									*j, op);
-						else if (isSgUnaryOp((*j)->get_parent()))
-							isSgUnaryOp((*j)->get_parent())->replace_expression(
-									*j, op);
-						else if (isSgExprListExp((*j)->get_parent())) { // Manu:: fortran indices are stored this way
-							isSgExprListExp((*j)->get_parent())->replace_expression(*j, op);
-						}
-						else
-							throw ir_error("unrecognized expression type");
-
-					}
-
-				}
-			}
-		}
-		return new CG_roseRepr(tnl);
-	}
-
-}
-
-//-----------------------------------------------------------------------------
-// assignment generation
-//-----------------------------------------------------------------------------
-CG_outputRepr* CG_roseBuilder::CreateAssignment(int, CG_outputRepr *lhs,
-		CG_outputRepr *rhs) const {
-	if (lhs == NULL || rhs == NULL) {
-		fprintf(stderr, "Code generation: Missing lhs or rhs\n");
-		return NULL;
-	}
-
-	SgExpression* src = static_cast<CG_roseRepr*>(rhs)->op_;
-	SgExpression* dst = static_cast<CG_roseRepr*>(lhs)->op_;
-
-	SgExprStatement* ins = buildAssignStatement(dst, src);
-	src->set_parent(ins);
-	dst->set_parent(ins);
-
-	SgStatementPtrList* new_list = new SgStatementPtrList;
-
-	(*new_list).push_back(isSgStatement(ins));
-
-	delete lhs;
-	delete rhs;
-
-	return new CG_roseRepr(new_list);
-
-}
-
-//-----------------------------------------------------------------------------
-// function invocation generation
-//-----------------------------------------------------------------------------
-CG_outputRepr* CG_roseBuilder::CreateInvoke(const std::string &fname,
-		std::vector<CG_outputRepr *> &list) const {
-
-	if (fname == std::string("max") || fname == std::string("min")) {
-		if (list.size() == 0) {
-			return NULL;
-		} else if (list.size() == 1) {
-			 return list[0];
-		} else {
-			 int last = list.size() - 1;
-			SgExpression* op2 = static_cast<CG_roseRepr*>(list[last])->op_;
-			delete list[last];
-		    list.erase(list.end()-1);
-			CG_roseRepr *repr = static_cast<CG_roseRepr*>(CreateInvoke(fname,
-					list));
-			SgExpression* op1 = repr->op_;
-
-
-			SgExpression *ins;
-			SgExprListExp* arg_list = buildExprListExp();
-			appendExpression(arg_list, op1);
-			appendExpression(arg_list, op2);
-			SgVarRefExp* opaque_var;
-
-
-			if (fname == std::string("max")) {
-				opaque_var = buildOpaqueVarRefExp("__rose_gt", global_);
-				ins = isSgExpression(buildFunctionCallExp(opaque_var, arg_list));
-
-				// Manu:: fortran support
-				if (isInputFortran()) {
-					SgName fName("merge");
-					SgTypeInt *retType = buildIntType();
-
-					SgExpression *cond = static_cast<CG_roseRepr *>(CreateLE(new CG_roseRepr(op2), new CG_roseRepr(op1)))->op_;
-		            appendExpression(arg_list, cond);
-					ins = isSgExpression(buildFunctionCallExp(fName, retType, arg_list, global_));
-				}
-
-			} else {
-				opaque_var = buildOpaqueVarRefExp("__rose_lt", global_);
-				ins = isSgExpression(buildFunctionCallExp(opaque_var, arg_list));
-
-				// Manu:: fortran support
-				if (isInputFortran()) {
-					SgName fName("merge");
-					SgTypeInt *retType = buildIntType();
-
-					SgExpression *cond = static_cast<CG_roseRepr *>(CreateLE(new CG_roseRepr(op1), new CG_roseRepr(op2)))->op_;
-		            appendExpression(arg_list, cond);
-					ins = isSgExpression(buildFunctionCallExp(fName, retType, arg_list, global_));
-				}
-
-			}
-
-			repr->op_ = ins;
-			return repr;
-		}
-	} else {
-		fprintf(stderr,
-				"Code generation: invoke function io_call not implemented\n");
-		return NULL;
-	}
-
-}
-
-//-----------------------------------------------------------------------------
-// comment generation
-//-----------------------------------------------------------------------------
-CG_outputRepr* CG_roseBuilder::CreateComment(int,
-		const std::string &commentText) const {
-	if (commentText == std::string("")) {
-		return NULL;
-	}
-
-	SgLocatedNode *tnl = new SgLocatedNode();
-	buildComment(tnl, "//omega_comment: " + commentText);
-
-	return new CG_roseRepr(isSgNode(tnl));
-
-}
-
-//-----------------------------------------------------------------------------
-// if stmt gen operations
-//-----------------------------------------------------------------------------
-CG_outputRepr* CG_roseBuilder::CreateIf(int, CG_outputRepr *guardList,
-		CG_outputRepr *true_stmtList, CG_outputRepr *false_stmtList) const {
-
-	if (true_stmtList == NULL && false_stmtList == NULL) {
-		delete guardList;
-		return NULL;
-	} else if (guardList == NULL) {
-		return StmtListAppend(true_stmtList, false_stmtList);
-	}
-
-	SgExpression* header = static_cast<CG_roseRepr*>(guardList)->op_;
-
-	SgStatementPtrList *then_part1, *else_part1;
-	SgStatement* then_part;
-	SgStatement* else_part;
-	SgBasicBlock* then_part2;
-	SgBasicBlock* else_part2;
-	if (true_stmtList != NULL) {
-		then_part1 = static_cast<CG_roseRepr*>(true_stmtList)->list_;
-		if (then_part1 != NULL) {
-			then_part = *((*then_part1).begin());
-
-			if ((*then_part1).size() > 1) {
-				then_part2 = buildBasicBlock();
-				for (SgStatementPtrList::iterator it = (*then_part1).begin();
-						it != (*then_part1).end(); it++) {
-					then_part2->append_statement(*it);
-
-				}
-				then_part = isSgStatement(then_part2);
-
-			}
-		} else {
-			// Manu:: fortran support (if part)
-			if (isInputFortran()) {
-				then_part2 = buildBasicBlock();
-				then_part2->append_statement(isSgStatement(static_cast<CG_roseRepr*>(true_stmtList)->tnl_));
-				then_part = isSgStatement(then_part2);
-			} else
-				then_part = isSgStatement(static_cast<CG_roseRepr*>(true_stmtList)->tnl_);
-		}
-	} else {
-		then_part = NULL;
-	}
-	if (false_stmtList != NULL) {
-		else_part1 = static_cast<CG_roseRepr*>(false_stmtList)->list_;
-		if (else_part1 != NULL) {
-			else_part = *((*else_part1).begin());
-			if ((*else_part1).size() > 1) {
-				else_part2 = buildBasicBlock();
-				for (SgStatementPtrList::iterator it2 = (*else_part1).begin();
-						it2 != (*else_part1).end(); it2++) {
-					else_part2->append_statement(*it2);
-
-				}
-				else_part = isSgStatement(else_part2);
-
-			}
-		} else {
-			// Manu:: fortran support (if part)
-			if (isInputFortran()) {
-				else_part2 = buildBasicBlock();
-				else_part2->append_statement(isSgStatement(static_cast<CG_roseRepr*>(false_stmtList)->tnl_));
-				else_part = isSgStatement(else_part2);
-			} else
-				else_part = isSgStatement(static_cast<CG_roseRepr*>(false_stmtList)->tnl_);
-		}
-	} else {
-		else_part = NULL;
-	}
-
-	SgIfStmt* ti = buildIfStmt(header, isSgStatement(then_part),
-			isSgStatement(else_part));
-
-	delete guardList;
-	delete true_stmtList;
-	delete false_stmtList;
-
-	return new CG_roseRepr(isSgNode(ti));
-
-}
-
-//-----------------------------------------------------------------------------
-// inductive variable generation, to be used in CreateLoop as control
-//-----------------------------------------------------------------------------
-CG_outputRepr* CG_roseBuilder::CreateInductive(CG_outputRepr *index,
-		CG_outputRepr *lower, CG_outputRepr *upper, CG_outputRepr *step) const {
-
-	if (index == NULL || lower == NULL || upper == NULL) {
-		fprintf(stderr,
-				"Code generation: something wrong in CreateInductive\n");
-		return NULL;
-	}
-
-	if (step == NULL)
-		step = new CG_roseRepr(isSgExpression(buildIntVal(1)));
-
-	SgVarRefExp *index_sym = isSgVarRefExp(
-			static_cast<CG_roseRepr*>(index)->op_);
-	SgExpression* lower_bound = static_cast<CG_roseRepr*>(lower)->op_;
-	SgExpression* upper_bound = static_cast<CG_roseRepr*>(upper)->op_;
-	SgExpression* step_size = static_cast<CG_roseRepr*>(step)->op_;
-
-	SgStatement* for_init_stmt = buildAssignStatement(index_sym, lower_bound);
-	SgLessOrEqualOp* cond = buildLessOrEqualOp(index_sym, upper_bound);
-	SgExprStatement* test = buildExprStatement(cond);
-	SgPlusAssignOp* increment = buildPlusAssignOp(index_sym, step_size);
-	SgForStatement *for_stmt = buildForStatement(for_init_stmt,
-			isSgStatement(test), increment, NULL);
-
-	delete index;
-	delete lower;
-	delete upper;
-	delete step;
-
-
-	// Manu
-	if (isInputFortran()) {
-        SgFortranDo * forStmt=new SgFortranDo(Sg_File_Info::generateDefaultFileInfoForTransformationNode());
-        forStmt->set_has_end_statement(true);
-        forStmt->set_bound(upper_bound);
-        forStmt->set_increment(step_size);
-        forStmt->set_initialization(isSgExprStatement(for_init_stmt)->get_expression());
-        return new CG_roseRepr(isSgNode(forStmt));
-	} else {
-
-		return new CG_roseRepr(isSgNode(for_stmt));
-
-	}
-
-}
-
-//-----------------------------------------------------------------------------
-// Attribute Creation
-//-----------------------------------------------------------------------------
-CG_outputRepr* CG_roseBuilder::CreateAttribute(CG_outputRepr *control,
-		const std::string &commentText) const {
-
-	SgNode *tnl = static_cast<CG_roseRepr*>(control)->tnl_;
-
-	tnl->setAttribute("omega_comment", new AstTextAttribute(commentText));
-
-	return static_cast<CG_roseRepr*>(control);
-
-}
-
-//-----------------------------------------------------------------------------
-// Pragma Attribute
-//-----------------------------------------------------------------------------
-CG_outputRepr* CG_roseBuilder::CreatePragmaAttribute(CG_outputRepr *stmt, int looplevel, const std::string &pragmaText) const {
-	SgNode *tnl = static_cast<CG_roseRepr*>(stmt)->tnl_;
-	CodeInsertionAttribute* attr = NULL;
-	if (!tnl->attributeExists("code_insertion")) {
-		attr = new CodeInsertionAttribute();
-		tnl->setAttribute("code_insertion", attr);
-	}
-	else {
-		attr = static_cast<CodeInsertionAttribute*>(tnl->getAttribute("code_insertion"));
-	}
-	attr->add(new PragmaInsertion(looplevel, pragmaText));
-	return stmt;
-}
-
-//-----------------------------------------------------------------------------
-// Prefetch Attribute
-//-----------------------------------------------------------------------------
-CG_outputRepr* CG_roseBuilder::CreatePrefetchAttribute(CG_outputRepr* stmt, int looplevel, const std::string &arrName, int hint) const {
-	SgNode *tnl = static_cast<CG_roseRepr*>(stmt)->tnl_;
-	CodeInsertionAttribute *attr = getOrCreateCodeInsertionAttribute(tnl);
-	attr->add(new MMPrefetchInsertion(looplevel, arrName, hint));
-}
-
-//-----------------------------------------------------------------------------
-// loop stmt generation
-//-----------------------------------------------------------------------------
-CG_outputRepr* CG_roseBuilder::CreateLoop(int, CG_outputRepr *control,
-		CG_outputRepr *stmtList) const {
-	if (stmtList == NULL) {
-		delete control;
-		return NULL;
-	} else if (control == NULL) {
-		fprintf(stderr, "Code generation: no inductive for this loop\n");
-		return stmtList;
-	}
-
-	SgNode *tnl = static_cast<CG_roseRepr*>(control)->tnl_;
-	SgForStatement *tf = isSgForStatement(tnl);
-
-	// Manu :: fortran support
-	SgFortranDo *tfd = NULL;
-	if (isInputFortran()) {
-		tfd = isSgFortranDo(tnl);
-	}
-	SgStatementPtrList * body = static_cast<CG_roseRepr*>(stmtList)->list_;
-
-	if (body != NULL) {
-		if (!((*body).empty())) {
-			if ((*body).size() == 1) {
-				if (!isInputFortran()) {  // Manu:: added if-else for fortran support
-				  tf->set_loop_body(*((*body).begin()));
-				  (*((*body).begin()))->set_parent(tf);
-				} else {
-					SgBasicBlock* bb1 = buildBasicBlock();
-					bb1->set_parent(tfd);
-					bb1->append_statement(*((*body).begin()));
-					tfd->set_body(bb1);
-				}
-			} else {
-				// Manu:: support for fortran label (do - continue)
-				SgName *sname = NULL;
-
-				SgBasicBlock* bb = buildBasicBlock();
-				if (!isInputFortran())
-				    bb->set_parent(tf);
-				else
-					bb->set_parent(tfd);
-				for (SgStatementPtrList::iterator it = (*body).begin();
-						it != (*body).end(); it++) {
-					bb->append_statement(*it);
-					(*it)->set_parent(bb);
-				}
-				if (!isInputFortran())
-				   tf->set_loop_body(bb);
-				else {
-					tfd->set_body(bb);
-				}
-			}
-		}
-	} else {
-		SgNode* tnl2 = static_cast<CG_roseRepr*>(stmtList)->tnl_;
-
-		if (tnl2 != NULL) {
-			if (!isInputFortran()) {
-			   tf->set_loop_body(isSgStatement(tnl2));
-			   tnl2->set_parent(tf);
-			} else {
-				SgBasicBlock* bb1 = buildBasicBlock();
-				bb1->set_parent(tfd);
-				bb1->append_statement(isSgStatement(tnl2));
-				tfd->set_body(bb1);
-  			    tnl2->set_parent(bb1);
-			}
-		}
-	}
-
-	delete stmtList;
-
-	return control;
-}
-
-//-----------------------------------------------------------------------------
-// basic int, identifier gen operations
-//-----------------------------------------------------------------------------
-CG_outputRepr* CG_roseBuilder::CreateInt(int _i) const {
-	return new CG_roseRepr(isSgExpression(buildIntVal(_i)));
-}
-bool CG_roseBuilder::isInteger(CG_outputRepr *op) const{
-
-	 SgExpression *op1 = static_cast<CG_roseRepr *>(op)->op_;
-
-	 if(op1)
-       if(isSgIntVal(op1))
-	       return true;
-
-     return false;
-}
-CG_outputRepr* CG_roseBuilder::CreateIdent(const std::string &_s) const {
-
-	SgVariableSymbol *vs = symtab_->find_variable(SgName(_s.c_str()));
-	SgVariableSymbol *vs2 = symtab2_->find_variable(SgName(_s.c_str()));
-
-	if (vs == NULL && vs2 == NULL) {
-
-		SgVariableDeclaration* defn = buildVariableDeclaration(
-				SgName(_s.c_str()), buildIntType());
-		SgInitializedNamePtrList& variables = defn->get_variables();
-		SgInitializedNamePtrList::const_iterator i = variables.begin();
-		SgInitializedName* initializedName = *i;
-		vs = new SgVariableSymbol(initializedName);
-		prependStatement(defn, isSgScopeStatement(root_));
-
-		vs->set_parent(symtab2_);
-		symtab2_->insert(SgName(_s.c_str()), vs);
-		return new CG_roseRepr(isSgExpression(buildVarRefExp(vs)));
-
-	}
-
-	/* May have problem */
-
-	if (!isSgExpression(buildVarRefExp(SgName(_s.c_str()))))
-		throw ir_error("error in Create ident!!");
-	if (vs2 != NULL)
-		return new CG_roseRepr(isSgExpression(buildVarRefExp(vs2)));
-
-	return new CG_roseRepr(isSgExpression(buildVarRefExp(vs)));
-
-}
-
-//-----------------------------------------------------------------------------
-// binary arithmetic operations
-//-----------------------------------------------------------------------------
-CG_outputRepr* CG_roseBuilder::CreatePlus(CG_outputRepr *lop,
-		CG_outputRepr *rop) const {
-	if (rop == NULL) {
-		return lop;
-	} else if (lop == NULL) {
-		return rop;
-	}
-
-	SgExpression* op1 = static_cast<CG_roseRepr*>(lop)->op_;
-	SgExpression* op2 = static_cast<CG_roseRepr*>(rop)->op_;
-
-	SgAddOp *ins = buildAddOp(op1, op2);
-	op1->set_parent(ins);
-	op2->set_parent(ins);
-	delete lop;
-	delete rop;
-
-	return new CG_roseRepr(isSgExpression(ins));
-
-}
-
-CG_outputRepr* CG_roseBuilder::CreateMinus(CG_outputRepr *lop,
-		CG_outputRepr *rop) const {
-	if (rop == NULL) {
-		return lop; /* May Cause Problem */
-	} else if (lop == NULL) {
-		SgExpression *op = static_cast<CG_roseRepr*>(rop)->op_;
-		SgMinusOp *ins = buildMinusOp(op);
-
-		delete rop;
-
-		return new CG_roseRepr(isSgExpression(ins));
-	} else {
-		SgExpression* op1 = static_cast<CG_roseRepr*>(lop)->op_;
-		SgExpression* op2 = static_cast<CG_roseRepr*>(rop)->op_;
-
-		SgSubtractOp *ins = buildSubtractOp(op1, op2);
-		op1->set_parent(ins);
-		op2->set_parent(ins);
-		delete lop;
-		delete rop;
-		return new CG_roseRepr(isSgExpression(ins));
-	}
-
-}
-
-CG_outputRepr* CG_roseBuilder::CreateTimes(CG_outputRepr *lop,
-		CG_outputRepr *rop) const {
-	if (rop == NULL || lop == NULL) {
-		if (rop != NULL) {
-			rop->clear();
-			delete rop;
-		}
-		if (lop != NULL) {
-			lop->clear();
-			delete lop;
-		}
-		return NULL;
-	}
-
-	SgExpression* op1 = static_cast<CG_roseRepr*>(lop)->op_;
-	SgExpression* op2 = static_cast<CG_roseRepr*>(rop)->op_;
-
-	SgMultiplyOp *ins = buildMultiplyOp(op1, op2);
-	op1->set_parent(ins);
-	op2->set_parent(ins);
-	delete lop;
-	delete rop;
-
-	return new CG_roseRepr(isSgExpression(ins));
-
-}
-
-CG_outputRepr* CG_roseBuilder::CreateIntegerFloor(CG_outputRepr *lop,
-		CG_outputRepr *rop) const {
-	if (rop == NULL) {
-		fprintf(stderr, "Code generation: divide by NULL\n");
-		return NULL;
-	} else if (lop == NULL) {
-		delete rop;
-		return NULL;
-	}
-
-	//  (6+5)*10 / 4
-	SgExpression* op1 = static_cast<CG_roseRepr*>(lop)->op_;
-	SgExpression* op2 = static_cast<CG_roseRepr*>(rop)->op_;
-
-	// bugs in SUIF prevent use of correct io_divfloor
-	SgDivideOp *ins = buildDivideOp(op1, op2);
-
-	delete lop;
-	delete rop;
-
-	return new CG_roseRepr(isSgExpression(ins));
-
-}
-
-CG_outputRepr* CG_roseBuilder::CreateIntegerMod(CG_outputRepr *lop,
-		CG_outputRepr *rop) const {
-	if (rop == NULL || lop == NULL) {
-		return NULL;
-	}
-
-	SgExpression* op1 = static_cast<CG_roseRepr*>(lop)->op_;
-	SgExpression* op2 = static_cast<CG_roseRepr*>(rop)->op_;
-
-	// bugs in SUIF prevent use of correct io_mod
-	SgModOp *ins;
-	if (!isInputFortran()) {
-		ins = buildModOp(op1, op2);
-		delete lop;
-		delete rop;
-
-		return new CG_roseRepr(isSgExpression(ins));
-	} else { // Manu:: fortran mod is a function call and not an operator (f77 and f90)
-		SgExpression *fins;
-		SgName fName("MOD");
-		SgExprListExp* arg_list = buildExprListExp();
-		appendExpression(arg_list, op1);
-		appendExpression(arg_list, op2);
-		SgTypeInt *retType = buildIntType();
-		fins = isSgExpression(buildFunctionCallExp(fName, retType, arg_list, global_));
-		return new CG_roseRepr(isSgExpression(fins));
-	}
-
-}
-
-//-----------------------------------------------------------------------------
-// binary logical operations
-//-----------------------------------------------------------------------------
-CG_outputRepr* CG_roseBuilder::CreateAnd(CG_outputRepr *lop,
-		CG_outputRepr *rop) const {
-
-	if (rop == NULL)
-		return lop;
-	else if (lop == NULL)
-		return rop;
-
-	SgExpression* op1 = static_cast<CG_roseRepr*>(lop)->op_;
-	SgExpression* op2 = static_cast<CG_roseRepr*>(rop)->op_;
-
-	SgAndOp *ins = buildAndOp(op1, op2);
-
-	delete lop;
-	delete rop;
-
-	return new CG_roseRepr(isSgExpression(ins));
-
-}
-
-//-----------------------------------------------------------------------------
-// binary relational operations
-//-----------------------------------------------------------------------------
-CG_outputRepr* CG_roseBuilder::CreateLE(CG_outputRepr *lop,
-		CG_outputRepr *rop) const {
-	if (rop == NULL || lop == NULL) {
-		return NULL;
-	}
-
-	SgExpression* op1 = static_cast<CG_roseRepr*>(lop)->op_;
-	SgExpression* op2 = static_cast<CG_roseRepr*>(rop)->op_;
-
-	SgLessOrEqualOp *ins = buildLessOrEqualOp(op1, op2);
-
-	delete lop;
-	delete rop;
-
-	return new CG_roseRepr(isSgExpression(ins));
-
-}
-
-CG_outputRepr* CG_roseBuilder::CreateEQ(CG_outputRepr *lop,
-		CG_outputRepr *rop) const {
-	if (rop == NULL || lop == NULL) {
-		return NULL;
-	}
-
-	SgExpression* op1 = static_cast<CG_roseRepr*>(lop)->op_;
-	SgExpression* op2 = static_cast<CG_roseRepr*>(rop)->op_;
-
-	SgEqualityOp *ins = buildEqualityOp(op1, op2);
-
-	delete lop;
-	delete rop;
-
-	return new CG_roseRepr(isSgExpression(ins));
-
-}
-
-//-----------------------------------------------------------------------------
-// stmt list gen operations
-//-----------------------------------------------------------------------------
-CG_outputRepr* CG_roseBuilder::StmtListAppend(CG_outputRepr *list1,
-		CG_outputRepr *list2) const {
-
-	if (list2 == NULL) {
-		return list1;
-	} else if (list1 == NULL) {
-		return list2;
-	}
-
-	SgStatementPtrList* new_list;
-
-	SgStatementPtrList* tnl1 = static_cast<CG_roseRepr *>(list1)->list_;
-	SgStatementPtrList* tnl2 = static_cast<CG_roseRepr *>(list2)->list_;
-	SgNode* one = static_cast<CG_roseRepr *>(list1)->tnl_;
-	SgNode* two = static_cast<CG_roseRepr *>(list2)->tnl_;
-
-	SgExpression* exp1 = static_cast<CG_roseRepr *>(list1)->op_;
-	SgExpression* exp2 = static_cast<CG_roseRepr *>(list2)->op_;
-
-	if (exp1 || exp2)
-		throw ir_error("error in stmtlistappend!!");
-
-	if (tnl1 && one)
-		throw ir_error("error in stmtlistappend!!");
-
-	if (tnl2 && two)
-		throw ir_error("error in stmtlistappend!!");
-	if ((tnl1 == NULL) && (tnl2 == NULL)) {
-
-		if ((one != NULL) && (two != NULL)) {
-
-			new_list = new SgStatementPtrList;
-
-			(*new_list).push_back(isSgStatement(one));
-			(*new_list).push_back(isSgStatement(two));
-
-			CG_roseRepr* new_rep = new CG_roseRepr(new_list);
-
-			return static_cast<CG_outputRepr *>(new_rep);
-
-		} else if ((one != NULL) && (two == NULL)) {
-
-			return static_cast<CG_outputRepr *>(new CG_roseRepr(one));
-
-		} else if ((two != NULL) && (one == NULL)) {
-			return static_cast<CG_outputRepr *>(new CG_roseRepr(two));
-
-		}
-
-	} else {
-		if ((tnl2 != NULL) && (tnl1 == NULL)) {
-			if (one == NULL)
-				return list2;
-			else {
-				new_list = new SgStatementPtrList;
-				(*new_list).push_back(isSgStatement(one));
-
-				for (SgStatementPtrList::iterator it = (*tnl2).begin();
-						it != (*tnl2).end(); it++) {
-					(*new_list).push_back(*it);
-
-				}
-				return static_cast<CG_outputRepr *>(new CG_roseRepr(new_list));
-			}
-		} else if ((tnl1 != NULL) && (tnl2 == NULL)) {
-			if (two == NULL)
-				return list1;
-			else {
-
-				(*tnl1).push_back(isSgStatement(two));
-				return static_cast<CG_outputRepr *>(new CG_roseRepr(tnl1));
-
-			}
-
-		} else if ((tnl1 != NULL) && (tnl2 != NULL)) {
-
-			for (SgStatementPtrList::iterator it = (*tnl2).begin();
-					it != (*tnl2).end(); it++) {
-				(*tnl1).push_back(*it);
-
-			}
-
-			return static_cast<CG_outputRepr *>(new CG_roseRepr(tnl1));
-		}
-
-	}
-
-}
-
-
-CG_outputRepr* CG_roseBuilder::CreateDim3(const char* varName, CG_outputRepr* arg1,
-		CG_outputRepr* arg2, CG_outputRepr* arg3) const {
-
-    SgFunctionSymbol * ctor_symbol = global_scope->lookup_function_symbol(
-			SgName("dim3"));
-
-	SgExprListExp * ctor_args;
-	if(arg3 != NULL)
-	ctor_args = buildExprListExp(static_cast<CG_roseRepr*>(arg1)->op_,
-			static_cast<CG_roseRepr*>(arg2)->op_, static_cast<CG_roseRepr*>(arg3)->op_);
-	else
-    ctor_args = buildExprListExp(static_cast<CG_roseRepr*>(arg1)->op_,
-    		static_cast<CG_roseRepr*>(arg2)->op_);
-	SgFunctionCallExp * dim3_func_call = buildFunctionCallExp(
-			buildFunctionRefExp(ctor_symbol->get_declaration()), ctor_args);
-
-	char joined_str[20];
-
-	strcpy(joined_str, "dim3 ");
-	strcat(joined_str, varName);
-
-	SgExprStatement* decl = buildAssignStatement(
-			buildOpaqueVarRefExp(joined_str, isSgScopeStatement(root_)),
-			dim3_func_call);
-
-	SgStatementPtrList *tnl2 = new SgStatementPtrList;
-
-	(*tnl2).push_back(decl);
-	return new CG_roseRepr(tnl2);
-
-}
-
-std::vector<SgVarRefExp *> substitute(SgNode *in, const SgVariableSymbol *sym,
-		SgExpression* expr, SgNode* root) {
-
-	SgStatement* stmt;
-	SgExpression* op;
-	std::vector<SgVarRefExp *> arrays;
-
-	if (in != NULL) {
-		if (stmt = isSgStatement(in)) {
-			if (isSgBasicBlock(stmt)) {
-				SgStatementPtrList& stmts =
-						isSgBasicBlock(stmt)->get_statements();
-				for (int i = 0; i < stmts.size(); i++) {
-					stmts[i]->set_parent(stmt);
-					std::vector<SgVarRefExp *> a = substitute(
-							isSgNode(stmts[i]), sym, expr, root);
-					std::copy(a.begin(), a.end(), back_inserter(arrays));
-				}
-			} else if (isSgForStatement(stmt)) {
-				SgForStatement *tnf = isSgForStatement(stmt);
-				tnf->get_for_init_stmt()->set_parent(tnf);
-				tnf->get_test()->set_parent(tnf);
-				tnf->get_increment()->set_parent(tnf);
-				tnf->get_loop_body()->set_parent(tnf);
-				std::vector<SgVarRefExp *> a = substitute(
-						isSgNode(tnf->get_for_init_stmt()), sym, expr, root);
-				std::copy(a.begin(), a.end(), back_inserter(arrays));
-				std::vector<SgVarRefExp *> a1 = substitute(
-						isSgNode(tnf->get_test()), sym, expr, root);
-				std::copy(a1.begin(), a1.end(), back_inserter(arrays));
-				std::vector<SgVarRefExp *> a2 = substitute(
-						isSgNode(tnf->get_increment()), sym, expr, root);
-				std::copy(a2.begin(), a2.end(), back_inserter(arrays));
-				std::vector<SgVarRefExp *> a3 = substitute(
-						isSgNode(tnf->get_loop_body()), sym, expr, root);
-				std::copy(a3.begin(), a3.end(), back_inserter(arrays));
-			} else if (isSgFortranDo(stmt)) { // Manu:: fortran support
-				SgFortranDo *tnf = isSgFortranDo(stmt);
-				tnf->get_initialization()->set_parent(tnf);
-				tnf->get_bound()->set_parent(tnf);
-				tnf->get_increment()->set_parent(tnf);
-				tnf->get_body()->set_parent(tnf);
-				std::vector<SgVarRefExp *> a = substitute(
-						isSgNode(tnf->get_initialization()), sym, expr, root);
-				std::copy(a.begin(), a.end(), back_inserter(arrays));
-				std::vector<SgVarRefExp *> a1 = substitute(
-						isSgNode(tnf->get_bound()), sym, expr, root);
-				std::copy(a1.begin(), a1.end(), back_inserter(arrays));
-				std::vector<SgVarRefExp *> a2 = substitute(
-						isSgNode(tnf->get_increment()), sym, expr, root);
-				std::copy(a2.begin(), a2.end(), back_inserter(arrays));
-				std::vector<SgVarRefExp *> a3 = substitute(
-						isSgNode(tnf->get_body()), sym, expr, root);
-				std::copy(a3.begin(), a3.end(), back_inserter(arrays));
-			} else if (isSgForInitStatement(stmt)) {
-
-				SgStatementPtrList& stmts =
-						isSgForInitStatement(stmt)->get_init_stmt();
-
-				for (SgStatementPtrList::iterator it = stmts.begin();
-						it != stmts.end(); it++) {
-					std::vector<SgVarRefExp *> a = substitute(isSgNode(*it),
-							sym, expr, root);
-
-					std::copy(a.begin(), a.end(), back_inserter(arrays));
-				}
-			}
-			else if (isSgVariableDeclaration(stmt)) {
-				if (SgExpression *init =
-						isSgVariableDeclaration(stmt)->get_variables().front()->get_initializer()) {
-					if (isSgAssignInitializer(init)) {
-						std::vector<SgVarRefExp *> a = substitute(
-								isSgAssignInitializer(init)->get_operand(), sym,
-								expr, root);
-						std::copy(a.begin(), a.end(), back_inserter(arrays));
-					}
-				}
-			} else if (isSgIfStmt(stmt)) {
-				SgIfStmt* tni = isSgIfStmt(stmt);
-				std::vector<SgVarRefExp *> a = substitute(
-						isSgNode(tni->get_conditional()), sym, expr, root);
-				std::copy(a.begin(), a.end(), back_inserter(arrays));
-				std::vector<SgVarRefExp *> a1 = substitute(
-						isSgNode(tni->get_true_body()), sym, expr, root);
-				std::copy(a1.begin(), a1.end(), back_inserter(arrays));
-				std::vector<SgVarRefExp *> a2 = substitute(
-						isSgNode(tni->get_false_body()), sym, expr, root);
-				std::copy(a2.begin(), a2.end(), back_inserter(arrays));
-			} else if (isSgExprStatement(stmt)) {
-				(isSgExprStatement(stmt)->get_expression())->set_parent(
-						isSgExprStatement(stmt));
-				std::vector<SgVarRefExp *> a = substitute(
-						isSgNode(isSgExprStatement(stmt)->get_expression()),
-						sym, expr, root);
-				std::copy(a.begin(), a.end(), back_inserter(arrays));
-			}  
-		} 
-		else {
-			op = isSgExpression(in);
-			std::string y = sym->get_name().getString();
-
-			if (isSgBinaryOp(op)) {
-
-				isSgBinaryOp(op)->get_lhs_operand()->set_parent(op);
-				isSgBinaryOp(op)->get_rhs_operand()->set_parent(op);
-
-				std::vector<SgVarRefExp *> a = substitute(
-						isSgBinaryOp(op)->get_lhs_operand(), sym, expr, root);
-				std::copy(a.begin(), a.end(), back_inserter(arrays));
-				std::vector<SgVarRefExp *> a1 = substitute(
-						isSgBinaryOp(op)->get_rhs_operand(), sym, expr, root);
-				std::copy(a1.begin(), a1.end(), back_inserter(arrays));
-			} else if (isSgUnaryOp(op)) {
-				std::vector<SgVarRefExp *> a = substitute(
-						isSgUnaryOp(op)->get_operand(), sym, expr, root);
-				std::copy(a.begin(), a.end(), back_inserter(arrays));
-			} else if (isSgVarRefExp(op)) {
-				std::string z =
-						isSgVarRefExp(op)->get_symbol()->get_name().getString();
-				if (!strcmp(z.c_str(), y.c_str())) {
-					arrays.push_back(isSgVarRefExp(op));
-				}   
-			}    
-			else if (isSgCallExpression(op)) {
-				SgExprListExp* exprs = isSgCallExpression(op)->get_args();
-				SgExpressionPtrList &expr_list = exprs->get_expressions();
-
-				for (SgExpressionPtrList::iterator it = expr_list.begin();
-						it != expr_list.end(); it++) {
-					std::vector<SgVarRefExp *> a = substitute(isSgNode(*it),
-							sym, expr, root);
-					std::copy(a.begin(), a.end(), back_inserter(arrays));
-				}
-			} else if (isSgExprListExp(op)) { // Manu:: fortran indices are stored this way
-				SgExpressionPtrList &expr_list = isSgExprListExp(op)->get_expressions();
-
-				for (SgExpressionPtrList::iterator it = expr_list.begin();
-						it != expr_list.end(); it++) {
-					std::vector<SgVarRefExp *> a = substitute(isSgNode(*it),
-							sym, expr, root);
-					std::copy(a.begin(), a.end(), back_inserter(arrays));
-				}
-
-			}
-
-		}  
-	}       
-
-	return arrays;
-}
-
-} // namespace
diff --git a/omegalib/codegen/src/CG_roseRepr.cc b/omegalib/codegen/src/CG_roseRepr.cc
deleted file mode 100644
index 9265ab0..0000000
--- a/omegalib/codegen/src/CG_roseRepr.cc
+++ /dev/null
@@ -1,125 +0,0 @@
-/*****************************************************************************
- Copyright (C) 2008 University of Southern California. 
- All Rights Reserved.
-
- Purpose:
-   omega holder for suif implementaion
-
- Notes:
-
- History:
-   02/01/06 - Chun Chen - created
-*****************************************************************************/
-
-#include <code_gen/CG_roseRepr.h>
-#include <code_gen/rose_attributes.h>
-#include <stdio.h>
-#include <string.h>
-#include <cstring>
-namespace omega {
-
-
-
-
-CG_roseRepr::CG_roseRepr(): tnl_(NULL), op_(NULL), list_(NULL){
-
-}
-
-CG_roseRepr::CG_roseRepr(SgNode *tnl): tnl_(tnl), op_(NULL),list_(NULL) {
-}
-
-CG_roseRepr::CG_roseRepr(SgExpression* op): tnl_(NULL), op_(op),list_(NULL){
-}
-CG_roseRepr::CG_roseRepr(SgStatementPtrList* stmtlist):tnl_(NULL), op_(NULL), list_(stmtlist){
-}
-  
-CG_roseRepr::~CG_roseRepr() {
-  // delete nothing here. operand or tree_node_list should already be
-  // grafted to other expression tree or statement list
-}
-
-CG_outputRepr* CG_roseRepr::clone()  const {
-
-  if( tnl_ != NULL) {
-    SgTreeCopy  tc;      
-    SgNode *tnl = tnl_->copy(tc);
-    copyAttributes(tnl_, tnl);
-    
-    tnl->set_parent(tnl_->get_parent());
-    return new CG_roseRepr(tnl);
-  }
-  else if(op_ != NULL)
-  {
-     SgTreeCopy tc1;
-     SgNode* op =  isSgNode(op_)->copy(tc1);
-     copyAttributes(op_, op);
-  
-     op->set_parent(isSgNode(op_)->get_parent());   
-     return new CG_roseRepr(isSgExpression(op));
-  }
-  else if(list_ != NULL) 
-  {
-     SgStatementPtrList* list2 = new SgStatementPtrList;
-     
-     for(SgStatementPtrList::iterator it = (*list_).begin(); it != (*list_).end(); it++){
-        SgTreeCopy  tc3;      
-        SgNode *tnl2  =  isSgNode(*it)->copy(tc3);
-        copyAttributes(*it, tnl2);
-        
-        tnl2->set_parent(isSgNode(*it)->get_parent());
-       
-        (*list2).push_back(isSgStatement(tnl2));       
-    }   
-    return new CG_roseRepr(list2);
-  }
-  
-  return NULL;
-}
-
-void CG_roseRepr::clear() {
-  if(tnl_ != NULL) {
-    delete tnl_;
-    tnl_ = NULL;
-  }
-}
-
-SgNode* CG_roseRepr::GetCode() const {
-  return tnl_;
-}
-
-SgStatementPtrList* CG_roseRepr::GetList() const {
-  return list_;
-}
-
-SgExpression* CG_roseRepr::GetExpression() const {
-   return op_;
-} 
-void CG_roseRepr::Dump() const {
-SgNode* tnl = tnl_;
-SgExpression* op = op_ ;
- if(tnl != NULL)
-  DumpFileHelper(tnl, stdout);
- else if(op != NULL)
-   DumpFileHelper(isSgNode(op), stdout);             
-
-}
-
-void  CG_roseRepr::DumpFileHelper(SgNode* node, FILE *fp) const{
-  std::string x;
-  size_t numberOfSuccessors = node->get_numberOfTraversalSuccessors();
- if(numberOfSuccessors == 0){
-    x = node->unparseToString ();   
-    fprintf(fp, "%s", x.c_str());
- }
- else{     
-   for (size_t idx = 0; idx < numberOfSuccessors; idx++)
-   {
-       SgNode *child = NULL;
-       child = node->get_traversalSuccessorByIndex(idx);
-       DumpFileHelper(child, fp);                 
-   }
- 
-}
-}
-
-} // namespace
diff --git a/omegalib/codegen/src/CG_stringBuilder.cc b/omegalib/codegen/src/CG_stringBuilder.cc
deleted file mode 100644
index 2f9286f..0000000
--- a/omegalib/codegen/src/CG_stringBuilder.cc
+++ /dev/null
@@ -1,487 +0,0 @@
-/*****************************************************************************
- Copyright (C) 1994-2000 the Omega Project Team
- Copyright (C) 2005-2011 Chun Chen
- All Rights Reserved.
-
- Purpose:
-   generate pseudo string code
-
- Notes:
-   There is no need to check illegal NULL parameter and throw invalid_argument
- in other IR interface implementation. They are for debugging purpose.
-   intMod implements modular function that returns positve remainder no matter
- lop is postive or nagative and rop is guranteed to be positive here.
-     
- History:
-   04/17/96 - Lei Zhou - created
-   08/31/09 add parenthesis to string operands, Chun Chen
-*****************************************************************************/
-
-#include <code_gen/CG_stringBuilder.h>
-#include <code_gen/codegen_error.h>
-#include <basic/util.h>
-#include <string>
-#include <stdexcept>
-#include <ctype.h>
-#include <string.h>
-
-namespace {
-
-std::string SafeguardString(const std::string &s, char op) {
-  int len = s.length();
-  int paren_level = 0;
-  int num_plusminus = 0;
-  int num_mul = 0;
-  int num_div = 0;
-  for (int i = 0; i < len; i++)
-    switch (s[i]) {
-    case '(':
-      paren_level++;
-      break;
-    case ')':
-      paren_level--;
-      break;
-    case '+':
-    case '-':
-      if (paren_level == 0)
-        num_plusminus++;
-      break;
-    case '*':
-      if (paren_level == 0)
-        num_mul++;
-      break;
-    case '/':
-      if (paren_level == 0)
-        num_div++;
-      break;
-    default:
-      break;
-    }
-
-  bool need_paren = false;
-  switch (op) {
-  case '-':
-    if (num_plusminus > 0)
-      need_paren = true;
-    break;
-  case '*':
-    if (num_plusminus > 0 || num_div > 0)
-      need_paren = true;
-    break;
-  case '/':
-    if (num_plusminus > 0 || num_div > 0 || num_mul > 0)
-      need_paren = true;
-    break;
-  default:
-    break;
-  }
-
-  if (need_paren)
-    return "(" + s + ")";
-  else
-    return s;
-}
-
-
-std::string GetIndentSpaces(int indent) {
-  std::string indentStr;
-  for (int i = 1; i < indent; i++) {
-    indentStr += "  ";
-  }
-  return indentStr;
-}
-
-
-// A shortcut to extract the string enclosed in the CG_outputRepr and delete
-// the original holder.
-std::string GetString(omega::CG_outputRepr *repr) {
-  std::string result = static_cast<omega::CG_stringRepr *>(repr)->GetString();
-  delete repr;
-  return result;
-}
-
-}
-
-
-namespace omega {
-
-
-
-//-----------------------------------------------------------------------------
-// Class: CG_stringBuilder
-//-----------------------------------------------------------------------------
-
-CG_stringRepr *CG_stringBuilder::CreateSubstitutedStmt(int indent, CG_outputRepr *stmt,
-                                                       const std::vector<std::string> &vars,
-                                                       std::vector<CG_outputRepr *> &subs) const {
-  std::string listStr = "";
-
-  for (int i = 0; i < subs.size(); i++) {
-    if (subs[i] == NULL)
-      listStr += "N/A";
-    else 
-      listStr += GetString(subs[i]);
-    if (i < subs.size() - 1)
-      listStr += ",";
-  } 
-
-  std::string stmtName = GetString(stmt);
-  std::string indentStr = GetIndentSpaces(indent);
-
-  return new CG_stringRepr(indentStr + stmtName + "(" + listStr + ");\n");
-}
-
-CG_stringRepr *CG_stringBuilder::CreateAssignment(int indent, 
-                                                  CG_outputRepr *lhs,
-                                                  CG_outputRepr *rhs) const {
-  if (lhs == NULL || rhs == NULL)
-    throw std::invalid_argument("missing lhs or rhs in assignment");
-
-  std::string lhsStr = GetString(lhs);
-  std::string rhsStr = GetString(rhs);
-
-  std::string indentStr = GetIndentSpaces(indent);
-
-  return new CG_stringRepr(indentStr + lhsStr + "=" + rhsStr + ";\n");
-}
-
-
-CG_stringRepr *CG_stringBuilder::CreateInvoke(const std::string &funcName,
-                                              std::vector<CG_outputRepr *> &list) const {
-  std::string listStr = "";
-
-  for (int i = 0; i < list.size(); i++) {
-    listStr += GetString(list[i]);
-    if ( i < list.size()-1)
-      listStr += ",";
-  }
-
-  return new CG_stringRepr(funcName + "(" + listStr + ")");
-}
-    
-
-CG_stringRepr *CG_stringBuilder::CreateComment(int indent, const std::string &commentText) const {
-  if (commentText == std::string("")) {
-    return NULL;
-  }
-
-  std::string indentStr = GetIndentSpaces(indent);
-
-  return new CG_stringRepr(indentStr + "// " + commentText + "\n");
-}
-
-CG_stringRepr* CG_stringBuilder::CreateAttribute(CG_outputRepr *control,
-		const std::string &commentText) const {
-	if (commentText == std::string("")) {
-		return static_cast<CG_stringRepr *> (control);
-	}
-
-	std::string controlString = GetString(control);
-
-	return new CG_stringRepr("// " + commentText + "\n" + controlString);
-
-}
-
-CG_outputRepr* CG_stringBuilder::CreatePragmaAttribute(CG_outputRepr *scopeStmt, int looplevel, const std::string &pragmaText) const {
-	// -- Not Implemented
-	return scopeStmt;
-}
-
-CG_outputRepr* CG_stringBuilder::CreatePrefetchAttribute(CG_outputRepr* scopeStmt, int looplevel, const std::string& arrName, int hint) const {
-	// -- Not Implemented
-	return scopeStmt;
-}
-
-CG_stringRepr *CG_stringBuilder::CreateIf(int indent, CG_outputRepr *guardList,
-                                          CG_outputRepr *true_stmtList, CG_outputRepr *false_stmtList) const {
-  if (guardList == NULL)
-    throw std::invalid_argument("missing if condition");
-  
-  if (true_stmtList == NULL && false_stmtList == NULL) {
-    delete guardList;
-    return NULL;
-  }
-
-  std::string guardListStr = GetString(guardList);
-  std::string indentStr = GetIndentSpaces(indent);
-  std::string s;
-  if (true_stmtList != NULL && false_stmtList == NULL) {
-    s = indentStr + "if (" + guardListStr + ") {\n"
-      + GetString(true_stmtList)
-      + indentStr + "}\n";
-  }
-  else if (true_stmtList == NULL && false_stmtList != NULL) {
-    s = indentStr + "if !(" + guardListStr + ") {\n"
-      + GetString(false_stmtList)
-      + indentStr + "}\n";
-  }
-  else {
-    s = indentStr + "if (" + guardListStr + ") {\n" 
-      + GetString(true_stmtList)
-      + indentStr + "}\n"
-      + indentStr + "else {\n"
-      + GetString(false_stmtList)
-      + indentStr + "}\n";
-  }
-  
-  return new CG_stringRepr(s);
-}
-
-
-
-CG_stringRepr *CG_stringBuilder::CreateInductive(CG_outputRepr *index,
-                                                 CG_outputRepr *lower, CG_outputRepr *upper,
-                                                 CG_outputRepr *step) const {
-  if (index == NULL)
-    throw std::invalid_argument("missing loop index");
-  if (lower == NULL)
-    throw std::invalid_argument("missing loop lower bound");
-  if (upper == NULL)
-    throw std::invalid_argument("missing loop upper bound");
-  if (step == NULL)
-    throw std::invalid_argument("missing loop step size");
-  
-  std::string indexStr = GetString(index);
-  std::string lowerStr = GetString(lower);
-  std::string upperStr = GetString(upper);
-
-  std::string doStr = "for(" + indexStr + " = " + lowerStr + "; "
-    + indexStr + " <= " + upperStr + "; " 
-    + indexStr;
-  
-  std::string stepStr = GetString(step);
-  if (stepStr == to_string(1))
-    doStr += "++";
-  else
-    doStr += " += " + stepStr;
-        
-  doStr += ")";
-      
-  return new CG_stringRepr(doStr);
-}
-
-
-CG_stringRepr *CG_stringBuilder::CreateLoop(int indent, CG_outputRepr *control,
-                                            CG_outputRepr *stmtList) const {
-  if (stmtList == NULL) {
-    delete control;
-    return NULL;
-  }
-  else if (control == NULL)
-    return static_cast<CG_stringRepr *>(stmtList);
-
-  std::string ctrlStr = GetString(control);
-  std::string stmtStr = GetString(stmtList);
-
-  std::string indentStr = GetIndentSpaces(indent);
-
-  std::string s = indentStr + ctrlStr + " {\n"
-    + stmtStr 
-    + indentStr + "}\n";
-
-  return new CG_stringRepr(s);
-}
-
-
-
-CG_stringRepr *CG_stringBuilder::CreateInt(int num) const {
-  std::string s = to_string(num);
-  return new CG_stringRepr(s);
-}
-
-
-
-bool CG_stringBuilder::isInteger(CG_outputRepr *op) const {
-
-	 char * cstr;
-     std::string s = GetString(op);
-     cstr = new char [s.size()+1];
-     strcpy (cstr, s.c_str());
-     int count = 0;
-     while(cstr[count] != '\n' && cstr[count] != '\0' )
-        if( !isdigit(cstr[count]))
-    	   return false;
-
-
-     return true;
-}
-
-
-
-CG_stringRepr *CG_stringBuilder::CreateIdent(const std::string &varName) const {
-  if (varName == std::string("")) {
-    return NULL;
-  }
-
-  return new CG_stringRepr(varName);
-}
-
-
-CG_stringRepr *CG_stringBuilder::CreatePlus(CG_outputRepr *lop, CG_outputRepr *rop) const {
-  if (rop == NULL) {
-    return static_cast<CG_stringRepr *>(lop);
-  }
-  else if (lop == NULL) {
-    return static_cast<CG_stringRepr *>(rop);
-  }
-
-  std::string lopStr = GetString(lop);
-  std::string ropStr = GetString(rop);
-
-  return new CG_stringRepr(lopStr + "+" + ropStr);
-}
-
-
-CG_stringRepr *CG_stringBuilder::CreateMinus(CG_outputRepr *lop, CG_outputRepr *rop) const {
-  if (rop == NULL) {
-    return static_cast<CG_stringRepr *>(lop);
-  }
-  else if (lop == NULL) {
-    std::string ropStr = GetString(rop);
-    return new CG_stringRepr("-" + SafeguardString(ropStr, '-'));
-  }
-
-  std::string lopStr = GetString(lop);
-  std::string ropStr = GetString(rop);
-
-  return new CG_stringRepr(lopStr + "-" + SafeguardString(ropStr, '-'));
-}
-
-
-CG_stringRepr *CG_stringBuilder::CreateTimes(CG_outputRepr *lop, CG_outputRepr *rop) const {
-  if (rop == NULL || lop == NULL) {
-    delete rop;
-    delete lop;
-    return NULL;
-  }
-
-  std::string lopStr = GetString(lop);
-  std::string ropStr = GetString(rop);
-
-  return new CG_stringRepr(SafeguardString(lopStr, '*') + "*" + SafeguardString(ropStr, '*'));
-}
-
-
-CG_stringRepr *CG_stringBuilder::CreateDivide(CG_outputRepr *lop, CG_outputRepr *rop) const {
-  if (rop == NULL)
-    throw codegen_error("integer division by zero");
-  else if (lop == NULL) {
-    delete rop;
-    return NULL;
-  }
-
-  std::string lopStr = GetString(lop);
-  std::string ropStr = GetString(rop);
-
-  return new CG_stringRepr(SafeguardString(lopStr, '/') + "/" + SafeguardString(ropStr, '/'));
-}
-
-
-CG_stringRepr *CG_stringBuilder::CreateIntegerFloor(CG_outputRepr *lop, CG_outputRepr *rop) const {
-  if (rop == NULL)
-    throw codegen_error("integer division by zero");
-  else if (lop == NULL) {
-    delete rop;
-    return NULL;
-  }
-
-  std::string lopStr = GetString(lop);
-  std::string ropStr = GetString(rop);
-
-  return new CG_stringRepr("intFloor(" + lopStr + "," + ropStr + ")");
-}
-
-
-CG_stringRepr *CG_stringBuilder::CreateIntegerMod(CG_outputRepr *lop, CG_outputRepr *rop) const {
-  if (rop == NULL)
-    throw codegen_error("integer modulo by zero");
-  else if (lop == NULL) {
-    delete rop;
-    return NULL;
-  }
-
-  std::string lopStr = GetString(lop);
-  std::string ropStr = GetString(rop);
-
-  return new CG_stringRepr("intMod(" + lopStr + "," + ropStr + ")");
-}
-
-CG_stringRepr *CG_stringBuilder::CreateIntegerCeil(CG_outputRepr *lop, CG_outputRepr *rop) const {
-  if (rop == 0)
-    throw codegen_error("integer ceiling by zero");
-  else if (lop == NULL) {
-    delete rop;
-    return NULL;
-  }
-
-  std::string lopStr = GetString(lop);
-  std::string ropStr = GetString(rop);
-
-  return new CG_stringRepr("intCeil(" + lopStr + "," + ropStr + ")");
-}
-
-
-CG_stringRepr *CG_stringBuilder::CreateAnd(CG_outputRepr *lop, CG_outputRepr *rop) const {
-  if (rop == NULL)
-    return static_cast<CG_stringRepr *>(lop);
-  else if (lop == NULL)
-    return static_cast<CG_stringRepr *>(rop);
-
-  std::string lopStr = GetString(lop);
-  std::string ropStr = GetString(rop);
-
-  return new CG_stringRepr(lopStr + " && " + ropStr);
-}
-
-
-CG_stringRepr *CG_stringBuilder::CreateGE(CG_outputRepr *lop, CG_outputRepr *rop) const {
-  if (rop == NULL || lop == NULL)
-    throw std::invalid_argument("missing operand in greater than equal comparison condition");
-
-  std::string lopStr = GetString(lop);
-  std::string ropStr = GetString(rop);
-
-  return new CG_stringRepr(lopStr + " >= " + ropStr);
-}
-
-
-
-CG_stringRepr *CG_stringBuilder::CreateLE(CG_outputRepr *lop, CG_outputRepr *rop) const {
-  if (rop == NULL || lop == NULL)
-    throw std::invalid_argument("missing operand in less than equal comparison condition");
-
-  std::string lopStr = GetString(lop);
-  std::string ropStr = GetString(rop);
-
-  return new CG_stringRepr(lopStr + " <= " + ropStr);
-}
-
-
-
-CG_stringRepr *CG_stringBuilder::CreateEQ(CG_outputRepr *lop, CG_outputRepr *rop) const {
-  if (rop == NULL || lop == NULL)
-    throw std::invalid_argument("missing operand in equal comparison condition");
-
-  std::string lopStr = GetString(lop);
-  std::string ropStr = GetString(rop);
-
-  return new CG_stringRepr(lopStr + " == " + ropStr);
-}
-
-
-
-CG_stringRepr *CG_stringBuilder::StmtListAppend(CG_outputRepr *list1, CG_outputRepr *list2) const {
-  if (list2 == NULL) {
-    return static_cast<CG_stringRepr *>(list1);
-  }
-  else if (list1 == NULL) {
-    return static_cast<CG_stringRepr *>(list2);
-  }
-
-  std::string list1Str = GetString(list1);
-  std::string list2Str = GetString(list2);
-
-  return new CG_stringRepr(list1Str + list2Str);
-}
-
-}
diff --git a/omegalib/codegen/src/CG_utils.cc b/omegalib/codegen/src/CG_utils.cc
deleted file mode 100755
index d3a5f71..0000000
--- a/omegalib/codegen/src/CG_utils.cc
+++ /dev/null
@@ -1,1735 +0,0 @@
-/*****************************************************************************
- Copyright (C) 1994-2000 the Omega Project Team
- Copyright (C) 2005-2011 Chun Chen
- All Rights Reserved.
-
- Purpose:
-   Utility functions for processing CG tree.
-
- Notes:
-     
- History:
-   07/19/07 when generating output variable substitutions for a mapping
-            relation, map it to each output to get correct equality, -chun
-   07/29/10 when translating equality to assignment, generate appropriate
-            if-condition when necesssary, -chun
-*****************************************************************************/
-
-#include <typeinfo>
-#include <omega.h>
-#include <code_gen/CG.h>
-#include <code_gen/CG_utils.h>
-#include <code_gen/codegen_error.h>
-#include <math.h>
-#include <stack>
-
-namespace omega {
-
-int checkLoopLevel;
-int stmtForLoopCheck;
-int upperBoundForLevel;
-int lowerBoundForLevel;
-bool fillInBounds;
-
-//trick to static init checkLoopLevel to 0
-class JunkStaticInit{ public: JunkStaticInit(){ checkLoopLevel=0; fillInBounds=false;} };
-static JunkStaticInit junkInitInstance__;
-
-
-
-
-namespace {
-
-Relation find_best_guard(const Relation &R, const BoolSet<> &active, const std::map<int, Relation> &guards) {
-  std::pair<int, int> best_cost = std::make_pair(0, 0);
-  Relation best_cond = Relation::True(R.n_set());
-  
-  Relation r = copy(R);
-  int max_iter_count = 2*(r.single_conjunct()->n_EQs()) + r.single_conjunct()->n_GEQs();
-  int iter_count = 0;
-  while (!r.is_obvious_tautology()) {
-    std::pair<int, int> cost = std::make_pair(0, 0);        
-    Relation cond = pick_one_guard(r);
-    Relation complement_cond = Complement(copy(cond));
-    complement_cond.simplify();    
-    for (BoolSet<>::const_iterator i = active.begin(); i != active.end(); i++) {
-      std::map<int, Relation>::const_iterator j = guards.find(*i);
-      if (j == guards.end())
-        continue;
-      if (Must_Be_Subset(copy(j->second), copy(cond)))
-        cost.first++;
-      else if (Must_Be_Subset(copy(j->second), copy(complement_cond)))
-        cost.second++;
-    }
-    if (cost > best_cost) {
-      best_cost = cost;
-      best_cond = copy(cond);
-    }
-    r = Gist(r, cond, 1);
-
-    if (iter_count > max_iter_count)
-      throw codegen_error("guard condition too complex to handle");
-
-    iter_count++;
-  }
-
-  return best_cond;
-}
-
-
-Relation find_best_guard(const Relation &R, const std::vector<CG_loop *> &loops, int start, int end) {
-  std::pair<int, int> best_cost = std::make_pair(0, 0);
-  Relation best_cond = Relation::True(R.n_set());
-  
-  Relation r = copy(R);
-  int max_iter_count = 2*(r.single_conjunct()->n_EQs()) + r.single_conjunct()->n_GEQs();
-  int iter_count = 0;
-  while (!r.is_obvious_tautology()) {
-    std::pair<int, int> cost = std::make_pair(0, 0);
-    Relation cond = pick_one_guard(r);
-    int i = start;
-    for ( ; i < end; i++) {
-      if (Must_Be_Subset(copy(loops[i]->guard_), copy(cond)))
-        cost.first++;
-      else
-        break;
-    }
-    Relation complement_cond = Complement(copy(cond));
-    complement_cond.simplify();
-    for (int j = i; j < end; j++)
-      if (Must_Be_Subset(copy(loops[j]->guard_), copy(complement_cond)))
-        cost.second++;
-      else
-        break;
-    
-    if (cost > best_cost) {
-      best_cost = cost;
-      best_cond = copy(cond);
-    }
-    r = Gist(r, cond, 1);
-
-    if (iter_count > max_iter_count)
-      throw codegen_error("guard condition too complex to handle");
-
-    iter_count++;
-  }
-
-  return best_cond;
-}
-
-}
-
-bool bound_must_hit_stride(const GEQ_Handle &inequality, Variable_ID v, const EQ_Handle &stride_eq, Variable_ID wc, const Relation &bounds, const Relation &known) {
-  assert(inequality.get_coef(v) != 0 && abs(stride_eq.get_coef(v)) == 1 && wc->kind() == Wildcard_Var && abs(stride_eq.get_coef(wc)) > 1);
-
-  // if bound expression uses floor operation, bail out for now
-  // TODO: in the future, handle this
-  if (abs(inequality.get_coef(v)) != 1)
-    return false;
-  
-  coef_t stride = abs(stride_eq.get_coef(wc));
-  
-  Relation r1(known.n_set());
-  F_Exists *f_exists1 = r1.add_and()->add_exists();
-  F_And *f_root1 = f_exists1->add_and();
-  std::map<Variable_ID, Variable_ID> exists_mapping1;
-  EQ_Handle h1 = f_root1->add_EQ();
-  Relation r2(known.n_set());
-  F_Exists *f_exists2 = r2.add_and()->add_exists();
-  F_And *f_root2 = f_exists2->add_and();
-  std::map<Variable_ID, Variable_ID> exists_mapping2;
-  EQ_Handle h2 = f_root2->add_EQ();
-  for (Constr_Vars_Iter cvi(inequality); cvi; cvi++) {
-    Variable_ID v = cvi.curr_var();
-    switch (v->kind()) {
-    case Input_Var: 
-      h1.update_coef(r1.input_var(v->get_position()), cvi.curr_coef());
-      h2.update_coef(r2.input_var(v->get_position()), cvi.curr_coef());
-      break;
-    case Global_Var: {      
-      Global_Var_ID g = v->get_global_var();
-      Variable_ID v1, v2;
-      if (g->arity() == 0) {
-        v1 = r1.get_local(g);
-        v2 = r2.get_local(g);
-      }
-      else {
-        v1 = r1.get_local(g, v->function_of());
-        v2 = r2.get_local(g, v->function_of());
-      }
-      h1.update_coef(v1, cvi.curr_coef());
-      h2.update_coef(v2, cvi.curr_coef());
-      break;
-    }
-    case Wildcard_Var: {
-      Variable_ID v1 = replicate_floor_definition(bounds, v, r1, f_exists1, f_root1, exists_mapping1);
-      Variable_ID v2 = replicate_floor_definition(bounds, v, r2, f_exists2, f_root2, exists_mapping2);
-      h1.update_coef(v1, cvi.curr_coef());
-      h2.update_coef(v2, cvi.curr_coef());
-      break;
-    }
-    default:
-      assert(false);
-    }
-  }
-  h1.update_const(inequality.get_const());
-  h1.update_coef(f_exists1->declare(), stride);
-  h2.update_const(inequality.get_const());
-  r1.simplify();
-  r2.simplify();
-
-  Relation all_known = Intersection(copy(bounds), copy(known));
-  all_known.simplify();
-
-  if (Gist(r1, copy(all_known), 1).is_obvious_tautology()) {
-    Relation r3(known.n_set());
-    F_Exists *f_exists3 = r3.add_and()->add_exists();
-    F_And *f_root3 = f_exists3->add_and();
-    std::map<Variable_ID, Variable_ID> exists_mapping3;
-    EQ_Handle h3 = f_root3->add_EQ();
-    for (Constr_Vars_Iter cvi(stride_eq); cvi; cvi++) {
-      Variable_ID v= cvi.curr_var();
-      switch (v->kind()) {
-      case Input_Var:
-        h3.update_coef(r3.input_var(v->get_position()), cvi.curr_coef());
-        break;
-      case Global_Var: {
-        Global_Var_ID g = v->get_global_var();
-        Variable_ID v3;
-        if (g->arity() == 0)
-          v3 = r3.get_local(g);
-        else
-          v3 = r3.get_local(g, v->function_of());
-        h3.update_coef(v3, cvi.curr_coef());
-        break;
-      }
-      case Wildcard_Var:
-        if (v == wc)
-          h3.update_coef(f_exists3->declare(), cvi.curr_coef());
-        else {
-          Variable_ID v3 = replicate_floor_definition(bounds, v, r3, f_exists3, f_root3, exists_mapping3);
-          h3.update_coef(v3, cvi.curr_coef());
-        }
-        break;
-      default:
-        assert(false);
-      }
-    }
-    h3.update_const(stride_eq.get_const());
-    r3.simplify();
-    
-    if (Gist(r3, Intersection(r2, all_known), 1).is_obvious_tautology())
-      return true;
-    else
-      return false;
-  }
-  else    
-    return false;
-}
-
-
-//
-// output variable by its name, however if this variable need to be substituted,
-// return the substitution.
-//
-CG_outputRepr *output_ident(CG_outputBuilder *ocg, const Relation &R, Variable_ID v, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) {
-  const_cast<Relation &>(R).setup_names(); // hack
-  
-  if (v->kind() == Input_Var) {
-    int pos = v->get_position();
-    if (assigned_on_the_fly[pos-1].first != NULL)
-      return assigned_on_the_fly[pos-1].first->clone();
-    else
-      return ocg->CreateIdent(v->name());
-  }
-  else if (v->kind() == Global_Var) {
-    if (v->get_global_var()->arity() == 0)
-      return ocg->CreateIdent(v->name());
-    else {
-      /* This should be improved to take into account the possible elimination
-         of the set variables. */
-      int arity = v->get_global_var()->arity();
-      std::vector<CG_outputRepr *> argList;
-      for(int i = 1; i <= arity; i++)
-        argList.push_back(ocg->CreateIdent(const_cast<Relation &>(R).input_var(i)->name()));
-      CG_outputRepr *call = ocg->CreateInvoke(v->get_global_var()->base_name(), argList);
-      return call;
-    }
-  }
-  else
-    assert(false);
-}
-
-
-//
-// return pair<if condition, <assignment rhs, assignment cost> >
-//
-std::pair<CG_outputRepr *, std::pair<CG_outputRepr *, int> > output_assignment(CG_outputBuilder *ocg, const Relation &R, int level, const Relation &known, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) {
-  Variable_ID v = const_cast<Relation &>(R).set_var(level);
-  Conjunct *c = const_cast<Relation &>(R).single_conjunct();
-
-  std::pair<EQ_Handle, int> result = find_simplest_assignment(R, v, assigned_on_the_fly);
-
-  if (result.second == INT_MAX)
-    return std::make_pair(static_cast<CG_outputRepr *>(NULL), std::make_pair(static_cast<CG_outputRepr *>(NULL), INT_MAX));
-  
-  CG_outputRepr *if_repr = NULL;
-  CG_outputRepr *assign_repr = NULL;
-  // check whether to generate if-conditions from equality constraints
-  if (abs(result.first.get_coef(v)) != 1) {
-    Relation r(R.n_set());
-    F_Exists *f_exists = r.add_and()->add_exists();
-    F_And *f_root = f_exists->add_and();
-    std::map<Variable_ID, Variable_ID> exists_mapping;
-    exists_mapping[v] = f_exists->declare();
-
-    EQ_Handle h = f_root->add_EQ();
-    for (Constr_Vars_Iter cvi(result.first); cvi; cvi++)
-      switch (cvi.curr_var()->kind()) {
-      case Input_Var: {
-        if (cvi.curr_var() == v)
-          h.update_coef(exists_mapping[v], cvi.curr_coef());
-        else
-          h.update_coef(r.set_var(cvi.curr_var()->get_position()), cvi.curr_coef());
-        break;
-      }
-      case Global_Var: {            
-        Global_Var_ID g = cvi.curr_var()->get_global_var();
-        Variable_ID v2;
-        if (g->arity() == 0)
-          v2 = r.get_local(g);
-        else
-          v2 = r.get_local(g, cvi.curr_var()->function_of());
-        h.update_coef(v2, cvi.curr_coef());
-        break;
-      }
-      case Wildcard_Var: {
-        std::map<Variable_ID, Variable_ID>::iterator p = exists_mapping.find(cvi.curr_var());
-        Variable_ID v2;
-        if (p == exists_mapping.end()) {
-          v2 = f_exists->declare();
-          exists_mapping[cvi.curr_var()] = v2;
-        }
-        else
-          v2 = p->second;
-        h.update_coef(v2, cvi.curr_coef());
-        break;
-      }
-      default:
-        assert(0);
-      }
-    h.update_const(result.first.get_const());
-      
-    for (EQ_Iterator e(c->EQs()); e; e++)
-      if (!((*e) == result.first)) {
-        EQ_Handle h = f_root->add_EQ();
-        for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
-          switch (cvi.curr_var()->kind()) {
-          case Input_Var: {
-            assert(cvi.curr_var() != v);
-            h.update_coef(r.set_var(cvi.curr_var()->get_position()), cvi.curr_coef());
-            break;
-          }
-          case Global_Var: {            
-            Global_Var_ID g = cvi.curr_var()->get_global_var();
-            Variable_ID v2;
-            if (g->arity() == 0)
-              v2 = r.get_local(g);
-            else
-              v2 = r.get_local(g, cvi.curr_var()->function_of());
-            h.update_coef(v2, cvi.curr_coef());
-            break;
-          }
-          case Wildcard_Var: {
-            std::map<Variable_ID, Variable_ID>::iterator p = exists_mapping.find(cvi.curr_var());
-            Variable_ID v2;
-            if (p == exists_mapping.end()) {
-              v2 = f_exists->declare();
-              exists_mapping[cvi.curr_var()] = v2;
-            }
-            else
-              v2 = p->second;
-            h.update_coef(v2, cvi.curr_coef());
-            break;
-          }
-          default:
-            assert(0);
-          }
-        h.update_const((*e).get_const());
-      }
-        
-    for (GEQ_Iterator e(c->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()), cvi.curr_coef());
-          break;
-        }
-        case Global_Var: {            
-          Global_Var_ID g = cvi.curr_var()->get_global_var();
-          Variable_ID v2;
-          if (g->arity() == 0)
-            v2 = r.get_local(g);
-          else
-            v2 = r.get_local(g, cvi.curr_var()->function_of());
-          h.update_coef(v2, cvi.curr_coef());
-          break;
-        }
-        case Wildcard_Var: {
-          std::map<Variable_ID, Variable_ID>::iterator p = exists_mapping.find(cvi.curr_var());
-          Variable_ID v2;
-          if (p == exists_mapping.end()) {
-            v2 = f_exists->declare();
-            exists_mapping[cvi.curr_var()] = v2;
-          }
-          else
-            v2 = p->second;
-          h.update_coef(v2, cvi.curr_coef());
-          break;
-        }
-        default:
-          assert(0);
-        }
-      h.update_const((*e).get_const());
-    }
-      
-    r.simplify();
-    if (!Gist(r, copy(known), 1).is_obvious_tautology()) {
-      CG_outputRepr *lhs = output_substitution_repr(ocg, result.first, v, false, R, assigned_on_the_fly);  
-      if_repr = ocg->CreateEQ(ocg->CreateIntegerMod(lhs->clone(), ocg->CreateInt(abs(result.first.get_coef(v)))), ocg->CreateInt(0));
-      assign_repr = ocg->CreateDivide(lhs, ocg->CreateInt(abs(result.first.get_coef(v))));
-    }
-    else
-      assign_repr = output_substitution_repr(ocg, result.first, v, true, R, assigned_on_the_fly);
-  }
-  else
-    assign_repr = output_substitution_repr(ocg, result.first, v, true, R, assigned_on_the_fly);
-
-  if (assign_repr == NULL)
-    assign_repr = ocg->CreateInt(0);
-  
-  return std::make_pair(if_repr, std::make_pair(assign_repr, result.second));
-}
-
-
-//
-// return NULL if 0
-//
-CG_outputRepr *output_substitution_repr(CG_outputBuilder *ocg, const EQ_Handle &equality, Variable_ID v, bool apply_v_coef, const Relation &R, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) {
-  const_cast<Relation &>(R).setup_names(); // hack
-  
-  coef_t a = equality.get_coef(v);
-  assert(a != 0);
-  
-  CG_outputRepr *repr = NULL;
-  for (Constr_Vars_Iter cvi(equality); cvi; cvi++)
-    if (cvi.curr_var() != v) {
-      CG_outputRepr *t;
-      if (cvi.curr_var()->kind() == Wildcard_Var) {
-        std::pair<bool, GEQ_Handle> result = find_floor_definition(R, cvi.curr_var());
-        if (!result.first) {
-          delete repr;
-          throw codegen_error("can't output non floor defined wildcard");
-        }
-        t = output_inequality_repr(ocg, result.second, cvi.curr_var(), R, assigned_on_the_fly);
-      }
-      else
-        t = output_ident(ocg, R, cvi.curr_var(), assigned_on_the_fly);
-      coef_t coef = cvi.curr_coef();
-
-      if (a > 0) {
-        if (coef > 0) {
-          if (coef == 1)
-            repr = ocg->CreateMinus(repr, t);
-          else
-            repr = ocg->CreateMinus(repr, ocg->CreateTimes(ocg->CreateInt(coef), t));
-        }
-        else { // coef < 0
-          if (coef == -1)
-            repr = ocg->CreatePlus(repr, t);
-          else
-            repr = ocg->CreatePlus(repr, ocg->CreateTimes(ocg->CreateInt(-coef), t));
-        }          
-      }
-      else {
-        if (coef > 0) {
-          if (coef == 1)
-            repr = ocg->CreatePlus(repr, t);
-          else
-            repr = ocg->CreatePlus(repr, ocg->CreateTimes(ocg->CreateInt(coef), t));
-        }
-        else { // coef < 0
-          if (coef == -1)
-            repr = ocg->CreateMinus(repr, t);
-          else
-            repr = ocg->CreateMinus(repr, ocg->CreateTimes(ocg->CreateInt(-coef), t));
-        }        
-      }
-    }
-  
-  int c = equality.get_const();
-  if (a > 0) {
-    if (c > 0)
-      repr = ocg->CreateMinus(repr, ocg->CreateInt(c));
-    else if (c < 0)
-      repr = ocg->CreatePlus(repr, ocg->CreateInt(-c));
-  }
-  else {
-    if (c > 0)
-      repr = ocg->CreatePlus(repr, ocg->CreateInt(c));
-    else if (c < 0)
-      repr = ocg->CreateMinus(repr, ocg->CreateInt(-c));
-  }
-    
-  if (apply_v_coef && abs(a) != 1)
-    repr = ocg->CreateDivide(repr, ocg->CreateInt(abs(a)));
-
-  return repr;
-}
-
-
-//
-// original Substitutions class from omega can't handle integer
-// division, this is new way.
-//
-std::vector<CG_outputRepr*> output_substitutions(CG_outputBuilder *ocg, const Relation &R, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) {
-  std::vector<CG_outputRepr *> subs;
-    
-  for (int i = 1; i <= R.n_out(); i++) {
-    Relation mapping(R.n_out(), 1);
-    F_And *f_root = mapping.add_and();
-    EQ_Handle h = f_root->add_EQ();
-    h.update_coef(mapping.output_var(1), 1);
-    h.update_coef(mapping.input_var(i), -1);
-    Relation r = Composition(mapping, copy(R));
-    r.simplify();
-
-    Variable_ID v = r.output_var(1);
-    CG_outputRepr *repr = NULL;
-    std::pair<EQ_Handle, int> result = find_simplest_assignment(r, v, assigned_on_the_fly);
-    if (result.second < INT_MAX)
-      repr = output_substitution_repr(ocg, result.first, v, true, r, assigned_on_the_fly);
-    else {
-      std::pair<bool, GEQ_Handle> result = find_floor_definition(R, v);
-      if (result.first)
-        try {
-          repr = output_inequality_repr(ocg, result.second, v, R, assigned_on_the_fly);
-        }
-        catch (const codegen_error &) {
-        }
-    }
-
-    subs.push_back(repr);
-  }
-
-  return subs;
-}
-    
-
-//
-// handle floor definition wildcards in equality, the second in returned pair
-// is the cost.
-//
-std::pair<EQ_Handle, int> find_simplest_assignment(const Relation &R, Variable_ID v, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) {
-  Conjunct *c = const_cast<Relation &>(R).single_conjunct();
-
-  int min_cost = INT_MAX;
-  EQ_Handle eq;
-  for (EQ_Iterator e(c->EQs()); e; e++)
-    if (!(*e).has_wildcards() && (*e).get_coef(v) != 0) {
-      int cost = 0;
-
-      if (abs((*e).get_coef(v)) != 1)
-        cost += 4;  // divide cost
-
-      int num_var = 0;
-      for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
-        if (cvi.curr_var() != v) {
-          num_var++;
-          if (abs(cvi.curr_coef()) != 1)
-            cost += 2;  // multiply cost
-          if (cvi.curr_var()->kind() == Global_Var && cvi.curr_var()->get_global_var()->arity() > 0)
-            cost += 10;  // function cost
-          else if (cvi.curr_var()->kind() == Input_Var &&
-                   assigned_on_the_fly.size() >= cvi.curr_var()->get_position() &&
-                   assigned_on_the_fly[cvi.curr_var()->get_position()-1].first != NULL)
-            cost += assigned_on_the_fly[cvi.curr_var()->get_position()-1].second;  // substitution cost on record
-        }
-      if ((*e).get_const() != 0)
-        num_var++;
-      if (num_var > 1)
-        cost += num_var - 1; // addition cost
-
-      if (cost < min_cost) {
-        min_cost = cost;
-        eq = *e;
-      }
-    }
-    
-  if (min_cost < INT_MAX)
-    return std::make_pair(eq, min_cost);
-
-  for (EQ_Iterator e(c->EQs()); e; e++)
-    if ((*e).has_wildcards() && (*e).get_coef(v) != 0) {
-      bool is_assignment = true;
-      for (Constr_Vars_Iter cvi(*e, true); cvi; cvi++) {
-        std::pair<bool, GEQ_Handle> result = find_floor_definition(R, v);
-        if (!result.first) {
-          is_assignment = false;
-          break;
-        }
-      }
-      if (!is_assignment)
-        continue;
-
-      int cost = 0;
-      
-      if (abs((*e).get_coef(v)) != 1)
-        cost += 4;  // divide cost
-
-      int num_var = 0;
-      for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
-        if (cvi.curr_var() != v) {
-          num_var++;
-          if (abs(cvi.curr_coef()) != 1)
-            cost += 2;  // multiply cost
-          if (cvi.curr_var()->kind() == Wildcard_Var)
-            cost += 10; // floor operation cost
-          else if (cvi.curr_var()->kind() == Global_Var && cvi.curr_var()->get_global_var()->arity() > 0)
-            cost += 20;  // function cost
-          else if (cvi.curr_var()->kind() == Input_Var &&
-                   assigned_on_the_fly.size() >= cvi.curr_var()->get_position() &&
-                   assigned_on_the_fly[cvi.curr_var()->get_position()-1].first != NULL)
-            cost += assigned_on_the_fly[cvi.curr_var()->get_position()-1].second;  // substitution cost on record
-        }
-      if ((*e).get_const() != 0)
-        num_var++;
-      if (num_var > 1)
-        cost += num_var - 1; // addition cost
-
-      if (cost < min_cost) {
-        min_cost = cost;
-        eq = *e;
-      }
-    }
-
-  return std::make_pair(eq, min_cost);
-}
-
-
-//
-// find floor definition for variable v, e.g. m-c <= 4v <= m, (c is
-// constant and 0 <= c < 4). this translates to v = floor(m, 4) and
-// return 4v<=m in this case. All wildcards in such inequality are
-// also floor defined.
-//
-std::pair<bool, GEQ_Handle> find_floor_definition(const Relation &R, Variable_ID v, std::set<Variable_ID> excluded_floor_vars) {
-  Conjunct *c = const_cast<Relation &>(R).single_conjunct();
-
-  excluded_floor_vars.insert(v);
-  for (GEQ_Iterator e = c->GEQs(); e; e++) {
-    coef_t a = (*e).get_coef(v);
-    if (a >= -1)
-      continue;
-    a = -a;
-    
-    bool interested = true;
-    for (std::set<Variable_ID>::const_iterator i = excluded_floor_vars.begin(); i != excluded_floor_vars.end(); i++)
-      if ((*i) != v && (*e).get_coef(*i) != 0) {
-        interested = false;
-        break;
-      }
-    if (!interested)
-      continue;
-
-    // check if any wildcard is floor defined
-    bool has_undefined_wc = false;
-    for (Constr_Vars_Iter cvi(*e, true); cvi; cvi++) 
-      if (excluded_floor_vars.find(cvi.curr_var()) == excluded_floor_vars.end()) {
-        std::pair<bool, GEQ_Handle> result = find_floor_definition(R, cvi.curr_var(), excluded_floor_vars);
-        if (!result.first) {
-          has_undefined_wc = true;
-          break;
-        }
-      }
-    if (has_undefined_wc)
-      continue;
-
-    // find the matching upper bound for floor definition
-    for (GEQ_Iterator e2 = c->GEQs(); e2; e2++)
-      if ((*e2).get_coef(v) == a && (*e).get_const() + (*e2).get_const() < a) {
-        bool match = true;
-        for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
-          if ((*e2).get_coef(cvi.curr_var()) != -cvi.curr_coef()) {
-            match = false;
-            break;
-          }
-        if (!match)
-          continue;
-        for (Constr_Vars_Iter cvi(*e2); cvi; cvi++)
-          if ((*e).get_coef(cvi.curr_var()) != -cvi.curr_coef()) {
-            match = false;
-            break;
-          }
-        if (match)
-          return std::make_pair(true, *e);
-      }
-  }
-
-  return std::make_pair(false, GEQ_Handle());
-}
-
-//
-// find the stride involving the specified variable, the stride
-// equality can have other wildcards as long as they are defined as
-// floor variables.
-//
-std::pair<EQ_Handle, Variable_ID> find_simplest_stride(const Relation &R, Variable_ID v) {
-  int best_num_var = INT_MAX;
-  coef_t best_coef;
-  EQ_Handle best_eq;
-  Variable_ID best_stride_wc;
-  for (EQ_Iterator e(const_cast<Relation &>(R).single_conjunct()->EQs()); e; e++)
-    if ((*e).has_wildcards() && (*e).get_coef(v) != 0) {
-      bool is_stride = true;
-      bool found_free = false;
-      int num_var = 0;
-      int num_floor = 0;
-      Variable_ID stride_wc;
-      for (Constr_Vars_Iter cvi(*e); cvi; cvi++) {
-        switch (cvi.curr_var()->kind()) {
-        case Wildcard_Var: {
-          bool is_free = true;
-          for (GEQ_Iterator e2(const_cast<Relation &>(R).single_conjunct()->GEQs()); e2; e2++)
-            if ((*e2).get_coef(cvi.curr_var()) != 0) {
-              is_free = false;
-              break;
-            }
-          if (is_free) {
-            if (found_free)
-              is_stride = false;
-            else {
-              found_free = true;
-              stride_wc = cvi.curr_var();
-            }
-          }
-          else {
-            std::pair<bool, GEQ_Handle> result = find_floor_definition(R, cvi.curr_var());
-            if (result.first)
-              num_floor++;
-            else 
-              is_stride = false;
-          }
-          break;
-        }
-        case Input_Var:
-          num_var++;
-          break;
-        default:
-          ;
-        }
-        
-        if (!is_stride)
-          break;
-      }
-
-      if (is_stride) {
-        coef_t coef = abs((*e).get_coef(v));
-        if (best_num_var == INT_MAX || coef < best_coef ||
-            (coef == best_coef && num_var < best_num_var)) {
-          best_coef = coef;
-          best_num_var = num_var;
-          best_eq = *e;
-          best_stride_wc = stride_wc;
-        }
-      }
-    }
-
-  if (best_num_var != INT_MAX)
-    return std::make_pair(best_eq, best_stride_wc);
-  else
-    return std::make_pair(EQ_Handle(), static_cast<Variable_ID>(NULL));
-}
-            
-//
-// convert relation to if-condition
-//
-CG_outputRepr *output_guard(CG_outputBuilder *ocg, const Relation &R, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) {
-  assert(R.n_out()==0);
-
-  CG_outputRepr *result = NULL;
-  Conjunct *c = const_cast<Relation &>(R).single_conjunct();
-
-  // e.g. 4i=5*j
-  for (EQ_Iterator e = c->EQs(); e; e++)
-    if (!(*e).has_wildcards()) {
-      CG_outputRepr *lhs = NULL;
-      CG_outputRepr *rhs = NULL;
-      for (Constr_Vars_Iter cvi(*e); cvi; cvi++) {
-        CG_outputRepr *v = output_ident(ocg, R, cvi.curr_var(), assigned_on_the_fly);
-        coef_t coef = cvi.curr_coef();
-        if (coef > 0) {
-          if (coef == 1)
-            lhs = ocg->CreatePlus(lhs, v);
-          else
-            lhs = ocg->CreatePlus(lhs, ocg->CreateTimes(ocg->CreateInt(coef), v));
-        }
-        else { // coef < 0
-          if (coef == -1)
-            rhs = ocg->CreatePlus(rhs, v);
-          else
-            rhs = ocg->CreatePlus(rhs, ocg->CreateTimes(ocg->CreateInt(-coef), v));
-        }
-      }
-      coef_t c = (*e).get_const();
-      
-      CG_outputRepr *term;
-      if (lhs == NULL) 
-        term = ocg->CreateEQ(rhs, ocg->CreateInt(c));
-      else {
-        if (c > 0)
-          rhs = ocg->CreateMinus(rhs, ocg->CreateInt(c));
-        else if (c < 0)
-          rhs = ocg->CreatePlus(rhs, ocg->CreateInt(-c));
-        else if (rhs == NULL)
-          rhs = ocg->CreateInt(0);
-        term = ocg->CreateEQ(lhs, rhs);
-      }
-      result = ocg->CreateAnd(result, term);
-    }
-
-  // e.g. i>5j
-  for (GEQ_Iterator e = c->GEQs(); e; e++)
-    if (!(*e).has_wildcards()) {
-      CG_outputRepr *lhs = NULL;
-      CG_outputRepr *rhs = NULL;
-      for (Constr_Vars_Iter cvi(*e); cvi; cvi++) {
-        CG_outputRepr *v = output_ident(ocg, R, cvi.curr_var(), assigned_on_the_fly);
-        coef_t coef = cvi.curr_coef();
-        if (coef > 0) {
-          if (coef == 1)
-            lhs = ocg->CreatePlus(lhs, v);
-          else
-            lhs = ocg->CreatePlus(lhs, ocg->CreateTimes(ocg->CreateInt(coef), v));
-        }
-        else { // coef < 0
-          if (coef == -1)
-            rhs = ocg->CreatePlus(rhs, v);
-          else
-            rhs = ocg->CreatePlus(rhs, ocg->CreateTimes(ocg->CreateInt(-coef), v));
-        }
-      }
-      coef_t c = (*e).get_const();
-
-      CG_outputRepr *term;
-      if (lhs == NULL)
-        term = ocg->CreateLE(rhs, ocg->CreateInt(c));
-      else {
-        if (c > 0)
-          rhs = ocg->CreateMinus(rhs, ocg->CreateInt(c));
-        else if (c < 0)
-          rhs = ocg->CreatePlus(rhs, ocg->CreateInt(-c));
-        else if (rhs == NULL)
-          rhs = ocg->CreateInt(0);
-        term = ocg->CreateGE(lhs, rhs);
-      }
-      result = ocg->CreateAnd(result, term);
-    }
-
-  // e.g. 4i=5j+4alpha
-  for (EQ_Iterator e = c->EQs(); e; e++)
-    if ((*e).has_wildcards()) {
-      Variable_ID wc;
-      int num_wildcard = 0;
-      int num_positive = 0;
-      int num_negative = 0;
-      for (Constr_Vars_Iter cvi(*e); cvi; cvi++) {
-        if (cvi.curr_var()->kind() == Wildcard_Var) {
-          num_wildcard++;
-          wc = cvi.curr_var();
-        }
-        else {
-          if (cvi.curr_coef() > 0)
-            num_positive++;
-          else
-            num_negative++;
-        }
-      }
-
-      if (num_wildcard > 1) {
-        delete result;
-        throw codegen_error("Can't generate equality condition with multiple wildcards");
-      }
-      int sign = (num_positive>=num_negative)?1:-1;
-      
-      CG_outputRepr *lhs = NULL;
-      for (Constr_Vars_Iter cvi(*e); cvi; cvi++) {
-        if (cvi.curr_var() != wc) {
-          CG_outputRepr *v = output_ident(ocg, R, cvi.curr_var(), assigned_on_the_fly);
-          coef_t coef = cvi.curr_coef();
-          if (sign == 1) {
-            if (coef > 0) {
-              if (coef == 1)
-                lhs = ocg->CreatePlus(lhs, v);
-              else
-                lhs = ocg->CreatePlus(lhs, ocg->CreateTimes(ocg->CreateInt(coef), v));
-            }
-            else { // coef < 0
-              if (coef == -1)
-                lhs = ocg->CreateMinus(lhs, v);
-              else
-                lhs = ocg->CreateMinus(lhs, ocg->CreateTimes(ocg->CreateInt(-coef), v));
-            }
-          }
-          else {
-            if (coef > 0) {
-              if (coef == 1)
-                lhs = ocg->CreateMinus(lhs, v);
-              else
-                lhs = ocg->CreateMinus(lhs, ocg->CreateTimes(ocg->CreateInt(coef), v));
-            }
-            else { // coef < 0
-              if (coef == -1)
-                lhs = ocg->CreatePlus(lhs, v);
-              else
-                lhs = ocg->CreatePlus(lhs, ocg->CreateTimes(ocg->CreateInt(-coef), v));
-            }
-          }            
-        }
-      }
-      coef_t c = (*e).get_const();
-      if (sign == 1) {
-        if (c > 0)
-          lhs = ocg->CreatePlus(lhs, ocg->CreateInt(c));
-        else if (c < 0)
-          lhs = ocg->CreateMinus(lhs, ocg->CreateInt(-c));
-      }
-      else {
-        if (c > 0)
-          lhs = ocg->CreateMinus(lhs, ocg->CreateInt(c));
-        else if (c < 0)
-          lhs = ocg->CreatePlus(lhs, ocg->CreateInt(-c));
-      }
-
-      lhs = ocg->CreateIntegerMod(lhs, ocg->CreateInt(abs((*e).get_coef(wc))));
-      CG_outputRepr *term = ocg->CreateEQ(lhs, ocg->CreateInt(0));
-      result = ocg->CreateAnd(result, term);
-    }
-
-  // e.g. 4alpha<=i<=5alpha
-  for (GEQ_Iterator e = c->GEQs(); e; e++)
-    if ((*e).has_wildcards()) {
-      Variable_ID wc;
-      int num_wildcard = 0;
-      for (Constr_Vars_Iter cvi(*e, true); cvi; cvi++)
-        if (num_wildcard == 0) {
-          wc = cvi.curr_var();
-          num_wildcard = 1;
-        }
-        else
-          num_wildcard++;
-
-      if (num_wildcard > 1) {
-        delete result;
-        // e.g.  c*alpha - x >= 0              (*)
-        //       -d*alpha + y >= 0             (*)
-        //       e1*alpha + f1*beta + g1 >= 0  (**)
-        //       e2*alpha + f2*beta + g2 >= 0  (**)
-        //       ...
-        // TODO: should generate a testing loop for alpha using its lower and
-        // upper bounds from (*) constraints and do the same if-condition test
-        // for beta from each pair of opposite (**) constraints as above,
-        // and exit the loop when if-condition satisfied.
-        throw codegen_error("Can't generate multiple wildcard GEQ guards right now");
-      }
-
-      coef_t c = (*e).get_coef(wc);
-      int sign = (c>0)?1:-1;
-      
-      GEQ_Iterator e2 = e;
-      e2++;
-      for ( ; e2; e2++) {
-        coef_t c2 = (*e2).get_coef(wc);
-        if (c2 == 0)
-          continue;
-        int sign2 = (c2>0)?1:-1;
-        if (sign != -sign2)
-          continue;
-        int num_wildcard2 = 0;
-        for (Constr_Vars_Iter cvi(*e2, true); cvi; cvi++)
-          num_wildcard2++;
-        if (num_wildcard2 > 1)
-          continue;
-
-        GEQ_Handle lb, ub;
-        if (sign == 1) {
-          lb = (*e);
-          ub = (*e2);
-        }
-        else {
-          lb = (*e2);
-          ub = (*e);
-        }
-
-        CG_outputRepr *lhs = NULL;
-        for (Constr_Vars_Iter cvi(lb); cvi; cvi++)
-          if (cvi.curr_var() != wc) {
-            CG_outputRepr *v = output_ident(ocg, R, cvi.curr_var(), assigned_on_the_fly);
-            coef_t coef = cvi.curr_coef();
-            if (coef > 0) {
-              if (coef == 1)
-                lhs = ocg->CreateMinus(lhs, v);
-              else
-                lhs = ocg->CreateMinus(lhs, ocg->CreateTimes(ocg->CreateInt(coef), v));
-            }
-            else { // coef < 0
-              if (coef == -1)
-                lhs = ocg->CreatePlus(lhs, v);
-              else
-                lhs = ocg->CreatePlus(lhs, ocg->CreateTimes(ocg->CreateInt(-coef), v));
-            }
-          }
-        coef_t c = lb.get_const();
-        if (c > 0)
-          lhs = ocg->CreateMinus(lhs, ocg->CreateInt(c));
-        else if (c < 0)
-          lhs = ocg->CreatePlus(lhs, ocg->CreateInt(-c));
-
-        CG_outputRepr *rhs = NULL;
-        for (Constr_Vars_Iter cvi(ub); cvi; cvi++)
-          if (cvi.curr_var() != wc) {
-            CG_outputRepr *v = output_ident(ocg, R, cvi.curr_var(), assigned_on_the_fly);
-            coef_t coef = cvi.curr_coef();
-            if (coef > 0) {
-              if (coef == 1)
-                rhs = ocg->CreatePlus(rhs, v);
-              else
-                rhs = ocg->CreatePlus(rhs, ocg->CreateTimes(ocg->CreateInt(coef), v));
-            }
-            else { // coef < 0
-              if (coef == -1)
-                rhs = ocg->CreateMinus(rhs, v);
-              else
-                rhs = ocg->CreateMinus(rhs, ocg->CreateTimes(ocg->CreateInt(-coef), v));
-            }
-          }
-        c = ub.get_const();
-        if (c > 0)
-          rhs = ocg->CreatePlus(rhs, ocg->CreateInt(c));
-        else if (c < 0)
-          rhs = ocg->CreateMinus(rhs, ocg->CreateInt(-c));
-
-        rhs = ocg->CreateIntegerFloor(rhs, ocg->CreateInt(-ub.get_coef(wc)));
-        rhs = ocg->CreateTimes(ocg->CreateInt(lb.get_coef(wc)), rhs);
-        CG_outputRepr *term = ocg->CreateLE(lhs, rhs);
-        result = ocg->CreateAnd(result, term);
-      }
-    }
-  
-  return result;
-}
-
-
-//
-// return NULL if 0
-//
-CG_outputRepr *output_inequality_repr(CG_outputBuilder *ocg, const GEQ_Handle &inequality, Variable_ID v, const Relation &R, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly, std::set<Variable_ID> excluded_floor_vars) {
-  const_cast<Relation &>(R).setup_names(); // hack
-  
-  coef_t a = inequality.get_coef(v);
-  assert(a != 0);
-  excluded_floor_vars.insert(v);
-  
-  CG_outputRepr *repr = NULL;
-  for (Constr_Vars_Iter cvi(inequality); cvi; cvi++)
-    if (cvi.curr_var() != v) {
-      CG_outputRepr *t;
-      if (cvi.curr_var()->kind() == Wildcard_Var) {
-        std::pair<bool, GEQ_Handle> result = find_floor_definition(R, cvi.curr_var(), excluded_floor_vars);
-        if (!result.first) {
-          delete repr;
-          throw codegen_error("Can't generate bound expression with wildcard not involved in floor definition");
-        }
-        try {
-          t = output_inequality_repr(ocg, result.second, cvi.curr_var(), R, assigned_on_the_fly, excluded_floor_vars);
-        }
-        catch (const std::exception &e) {
-          delete repr;
-          throw e;
-        }
-      }
-      else
-        t = output_ident(ocg, R, cvi.curr_var(), assigned_on_the_fly);
-
-      coef_t coef = cvi.curr_coef();
-      if (a > 0) {
-        if (coef > 0) {
-          if (coef == 1)
-            repr = ocg->CreateMinus(repr, t);
-          else
-            repr = ocg->CreateMinus(repr, ocg->CreateTimes(ocg->CreateInt(coef), t));
-        }
-        else {
-          if (coef == -1)
-            repr = ocg->CreatePlus(repr, t);
-          else
-            repr = ocg->CreatePlus(repr, ocg->CreateTimes(ocg->CreateInt(-coef), t));
-        }
-      }
-      else {
-        if (coef > 0) {
-          if (coef == 1)
-            repr = ocg->CreatePlus(repr, t);
-          else
-            repr = ocg->CreatePlus(repr, ocg->CreateTimes(ocg->CreateInt(coef), t));
-        }
-        else {
-          if (coef == -1)
-            repr = ocg->CreateMinus(repr, t);
-          else
-            repr = ocg->CreateMinus(repr, ocg->CreateTimes(ocg->CreateInt(-coef), t));
-        }
-      }
-    }
-  coef_t c = inequality.get_const();
-  if (c > 0) {
-    if (a > 0)
-      repr = ocg->CreateMinus(repr, ocg->CreateInt(c));
-    else 
-      repr = ocg->CreatePlus(repr, ocg->CreateInt(c));
-  }
-  else if (c < 0) {
-    if (a > 0)
-      repr = ocg->CreatePlus(repr, ocg->CreateInt(-c));
-    else
-      repr = ocg->CreateMinus(repr, ocg->CreateInt(-c));
-  }    
-
-  if (abs(a) == 1)
-    return repr;
-  else if (a > 0)
-    return ocg->CreateIntegerCeil(repr, ocg->CreateInt(a));
-  else // a < 0
-    return ocg->CreateIntegerFloor(repr, ocg->CreateInt(-a));  
-}
-
-
-//
-// nothing special, just an alias
-//
-CG_outputRepr *output_upper_bound_repr(CG_outputBuilder *ocg, const GEQ_Handle &inequality, Variable_ID v, const Relation &R, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) {
-  assert(inequality.get_coef(v) < 0);
-  CG_outputRepr* zero_;
-
-  zero_ =  output_inequality_repr(ocg, inequality, v, R, assigned_on_the_fly);
-
-  if(!zero_)
-         zero_ = ocg->CreateInt(0);
-
-  return zero_;
-
-}
-
-
-//
-// output lower bound with respect to lattice
-//
-CG_outputRepr *output_lower_bound_repr(CG_outputBuilder *ocg, const GEQ_Handle &inequality, Variable_ID v, const EQ_Handle &stride_eq, Variable_ID wc, const Relation &R, const Relation &known, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) {
-  assert(inequality.get_coef(v) > 0);
-  CG_outputRepr* zero_;
-  if (wc == NULL || bound_must_hit_stride(inequality, v, stride_eq, wc, R, known)){
-    zero_ =  output_inequality_repr(ocg, inequality, v, R, assigned_on_the_fly);
-    if(!zero_)
-       zero_ = ocg->CreateInt(0);
-
-    return zero_;
-  }
-  CG_outputRepr *strideBoundRepr = NULL;
-  int sign = (stride_eq.get_coef(v)>0)?1:-1;
-  for (Constr_Vars_Iter cvi(stride_eq); cvi; cvi++) {
-    Variable_ID v2 = cvi.curr_var();
-    if (v2 == v || v2 == wc)
-      continue;
-
-    CG_outputRepr *v_repr;
-    if (v2->kind() == Input_Var || v2->kind() == Global_Var)
-      v_repr = output_ident(ocg, R, v2, assigned_on_the_fly);
-    else if (v2->kind() == Wildcard_Var) {
-      std::pair<bool, GEQ_Handle> result = find_floor_definition(R, v2);
-      assert(result.first);
-      v_repr = output_inequality_repr(ocg, result.second, v2, R, assigned_on_the_fly);
-    }
-
-    coef_t coef = cvi.curr_coef();
-    if (sign < 0) {
-      if (coef > 0) {
-        if (coef == 1)
-          strideBoundRepr = ocg->CreatePlus(strideBoundRepr, v_repr);
-        else
-          strideBoundRepr = ocg->CreatePlus(strideBoundRepr, ocg->CreateTimes(ocg->CreateInt(coef), v_repr));
-      }
-      else { // coef < 0
-        if (coef == -1)
-          strideBoundRepr = ocg->CreateMinus(strideBoundRepr, v_repr);
-        else
-          strideBoundRepr = ocg->CreateMinus(strideBoundRepr, ocg->CreateTimes(ocg->CreateInt(-coef), v_repr));
-      }
-    }
-    else {
-      if (coef > 0) {
-        if (coef == 1)
-          strideBoundRepr = ocg->CreateMinus(strideBoundRepr, v_repr);
-        else
-          strideBoundRepr = ocg->CreateMinus(strideBoundRepr, ocg->CreateTimes(ocg->CreateInt(coef), v_repr));
-      }
-      else { // coef < 0
-        if (coef == -1)
-          strideBoundRepr = ocg->CreatePlus(strideBoundRepr, v_repr);
-        else
-          strideBoundRepr = ocg->CreatePlus(strideBoundRepr, ocg->CreateTimes(ocg->CreateInt(-coef), v_repr));
-      }
-    }
-  }  
-  coef_t c = stride_eq.get_const();
-  if (c > 0) {
-    if (sign < 0)
-      strideBoundRepr = ocg->CreatePlus(strideBoundRepr, ocg->CreateInt(c));
-    else
-      strideBoundRepr = ocg->CreateMinus(strideBoundRepr, ocg->CreateInt(c));
-  }
-  else if (c < 0) {
-    if (sign < 0)
-      strideBoundRepr = ocg->CreateMinus(strideBoundRepr, ocg->CreateInt(-c));
-    else
-      strideBoundRepr = ocg->CreatePlus(strideBoundRepr, ocg->CreateInt(-c));
-  }
-
-  CG_outputRepr *repr = output_inequality_repr(ocg, inequality, v, R, assigned_on_the_fly);
-  CG_outputRepr *repr2 = ocg->CreateCopy(repr);
-  repr = ocg->CreatePlus(repr2, ocg->CreateIntegerMod(ocg->CreateMinus(strideBoundRepr, repr), ocg->CreateInt(abs(stride_eq.get_coef(wc)))));
-
-  return repr;
-}
-  
-
-//
-// return loop control structure only
-//
-CG_outputRepr *output_loop(CG_outputBuilder *ocg, const Relation &R, int level, const Relation &known, const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) {
-  std::pair<EQ_Handle, Variable_ID> result = find_simplest_stride(R, const_cast<Relation &>(R).set_var(level));
-  if (result.second != NULL)
-    assert(abs(result.first.get_coef(const_cast<Relation &>(R).set_var(level))) == 1);
-
-  std::vector<CG_outputRepr *> lbList, ubList;  
-  try {
-
-	coef_t const_lb = negInfinity, const_ub = posInfinity;
-
-    for (GEQ_Iterator e(const_cast<Relation &>(R).single_conjunct()->GEQs()); e; e++) {
-      coef_t coef = (*e).get_coef(const_cast<Relation &>(R).set_var(level));
-
-      if (coef > 0) {
-        CG_outputRepr *repr = output_lower_bound_repr(ocg, *e, const_cast<Relation &>(R).set_var(level), result.first, result.second, R, known, assigned_on_the_fly);
-          if (repr == NULL)
-           repr = ocg->CreateInt(0);
-        lbList.push_back(repr);
-
-        if ((*e).is_const(const_cast<Relation &>(R).set_var(level))){
-        	if(!result.second) {
-
-                //no variables but v in constr
-                coef_t L,m;
-                L = -((*e).get_const());
-
-                m = (*e).get_coef(const_cast<Relation &>(R).set_var(level));
-                coef_t sb  =  (int) (ceil(((float) L) /m));
-                set_max(const_lb, sb);
-            }
-        	else{
-
-        		coef_t L,m,s,c;
-        		        L = -((*e).get_const());
-        		        m = (*e).get_coef(const_cast<Relation &>(R).set_var(level));
-        		        s = abs(result.first.get_coef(result.second));
-        		        c = result.first.get_const();
-        		        coef_t sb  =  (s * (int) (ceil( (float) (L - (c * m)) /(s*m))))+ c;
-        		        set_max(const_lb, sb);
-
-        	}
-        }
-
-      }
-      else if (coef < 0) {
-        CG_outputRepr *repr = output_upper_bound_repr(ocg, *e, const_cast<Relation &>(R).set_var(level), R, assigned_on_the_fly);
-        if (repr == NULL)
-          repr = ocg->CreateInt(0);
-        ubList.push_back(repr);
-
-        if ((*e).is_const(const_cast<Relation &>(R).set_var(level))) {
-                // no variables but v in constraint
-                set_min(const_ub,-(*e).get_const()/(*e).get_coef(const_cast<Relation &>(R).set_var(level)));
-        }
-
-      }
-    }
-    
-    if(fillInBounds && lbList.size() == 1 && const_lb != negInfinity)
-       lowerBoundForLevel = const_lb;
-
-    if(fillInBounds && const_ub != posInfinity)
-       upperBoundForLevel = const_ub;
-    if (lbList.size() == 0)
-      throw codegen_error("missing lower bound at loop level " + to_string(level));
-    if (ubList.size() == 0)
-      throw codegen_error("missing upper bound at loop level " + to_string(level));
-  }
-  catch (const std::exception &e) {
-    for (int i = 0; i < lbList.size(); i++)
-      delete lbList[i];
-    for (int i = 0; i < ubList.size(); i++)
-      delete ubList[i];
-    throw e;
-  }
-
-  CG_outputRepr *lbRepr = NULL;
-  if (lbList.size() > 1)
-    lbRepr = ocg->CreateInvoke("max", lbList);
-  else // (lbList.size() == 1)
-    lbRepr = lbList[0];
-
-  CG_outputRepr *ubRepr = NULL;
-  if (ubList.size() > 1)
-    ubRepr = ocg->CreateInvoke("min", ubList);
-  else // (ubList.size() == 1)
-    ubRepr = ubList[0];
-
-  CG_outputRepr *stRepr;
-  if (result.second == NULL)
-    stRepr = ocg->CreateInt(1);
-  else
-    stRepr = ocg->CreateInt(abs(result.first.get_coef(result.second)));
-  CG_outputRepr *indexRepr = output_ident(ocg, R, const_cast<Relation &>(R).set_var(level), assigned_on_the_fly);
-  return ocg->CreateInductive(indexRepr, lbRepr, ubRepr, stRepr);
-}
-
-
-//
-// parameter f_root is inside f_exists, not the other way around.
-// return replicated variable in new relation, with all cascaded floor definitions
-// using wildcards defined in the same way as in the original relation.
-//
-Variable_ID replicate_floor_definition(const Relation &R, const Variable_ID floor_var,
-                                       Relation &r, F_Exists *f_exists, F_And *f_root,
-                                       std::map<Variable_ID, Variable_ID> &exists_mapping) {
-  assert(R.n_out() == 0 && r.n_out() == 0 && R.n_inp() == r.n_inp());
-
-  std::set<Variable_ID> excluded_floor_vars;
-  std::stack<Variable_ID> to_fill;
-  to_fill.push(floor_var);
-
-  while (!to_fill.empty()) {
-    Variable_ID v = to_fill.top();
-    to_fill.pop();
-    if (excluded_floor_vars.find(v) != excluded_floor_vars.end())
-      continue;
-    
-    std::pair<bool, GEQ_Handle> result = find_floor_definition(R, v, excluded_floor_vars);
-    assert(result.first);
-    excluded_floor_vars.insert(v);
-      
-    GEQ_Handle h1 = f_root->add_GEQ();
-    GEQ_Handle h2 = f_root->add_GEQ();
-    for (Constr_Vars_Iter cvi(result.second); cvi; cvi++) {
-      Variable_ID v2 = cvi.curr_var();
-      switch  (v2->kind()) {
-      case Input_Var: {
-        int pos = v2->get_position();
-        h1.update_coef(r.input_var(pos), cvi.curr_coef());
-        h2.update_coef(r.input_var(pos), -cvi.curr_coef());
-        break;
-      }
-      case Wildcard_Var: {
-        std::map<Variable_ID, Variable_ID>::iterator p = exists_mapping.find(v2);
-        Variable_ID v3;
-        if (p == exists_mapping.end()) {
-          v3 = f_exists->declare();
-          exists_mapping[v2] = v3;
-        }
-        else
-          v3 = p->second;
-        h1.update_coef(v3, cvi.curr_coef());
-        h2.update_coef(v3, -cvi.curr_coef());
-        if (v2 != v)
-          to_fill.push(v2);
-        break;
-      }
-      case Global_Var: {
-        Global_Var_ID g = v2->get_global_var();
-        Variable_ID v3;
-        if (g->arity() == 0)
-          v3 = r.get_local(g);
-        else
-          v3 = r.get_local(g, v2->function_of());
-        h1.update_coef(v3, cvi.curr_coef());
-        h2.update_coef(v3, -cvi.curr_coef());
-        break;
-      }
-      default:
-        assert(false);
-      }
-    }
-    h1.update_const(result.second.get_const());
-    h2.update_const(-result.second.get_const()-result.second.get_coef(v)-1);
-  }
-
-  if (floor_var->kind() == Input_Var)
-    return r.input_var(floor_var->get_position());
-  else if (floor_var->kind() == Wildcard_Var)
-    return exists_mapping[floor_var];
-  else
-    assert(false);
-}
-
-
-//
-// pick one guard condition from relation. it can involve multiple
-// constraints when involving wildcards, as long as its complement
-// is a single conjunct.
-//
-Relation pick_one_guard(const Relation &R, int level) {
-  assert(R.n_out()==0);
-  
-  Relation r = Relation::True(R.n_set());
-  
-  for (GEQ_Iterator e(const_cast<Relation &>(R).single_conjunct()->GEQs()); e; e++)
-    if (!(*e).has_wildcards()) {
-      r.and_with_GEQ(*e);
-      r.simplify();
-      r.copy_names(R);
-      r.setup_names();
-      return r;
-    }
-  
-  for (EQ_Iterator e(const_cast<Relation &>(R).single_conjunct()->EQs()); e; e++)
-    if (!(*e).has_wildcards()) {
-      r.and_with_GEQ(*e);
-      r.simplify();
-      r.copy_names(R);
-      r.setup_names();
-      return r;
-    }
-  
-  for (EQ_Iterator e(const_cast<Relation &>(R).single_conjunct()->EQs()); e; e++)
-    if ((*e).has_wildcards()) {
-      int num_wildcard = 0;
-      int max_level = 0;
-      for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
-        switch (cvi.curr_var()->kind()) {
-        case Wildcard_Var:
-          num_wildcard++;
-          break;
-        case Input_Var:
-          if (cvi.curr_var()->get_position() > max_level)
-            max_level = cvi.curr_var()->get_position();
-          break;
-        default:
-          ;
-        }
-          
-      if (num_wildcard == 1 && max_level != level-1) {
-        r.and_with_EQ(*e);
-        r.simplify();
-        r.copy_names(R);
-        r.setup_names();
-        return r;
-      }
-    }
-
-  for (GEQ_Iterator e(const_cast<Relation &>(R).single_conjunct()->GEQs()); e; e++)
-    if ((*e).has_wildcards()) {
-      int num_wildcard = 0;
-      int max_level = 0;
-      bool direction;
-      Variable_ID wc;
-      for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
-        switch (cvi.curr_var()->kind()) {
-        case Wildcard_Var:
-          num_wildcard++;
-          wc = cvi.curr_var();
-          direction = cvi.curr_coef()>0?true:false;
-          break;
-        case Input_Var:
-          if (cvi.curr_var()->get_position() > max_level)
-            max_level = cvi.curr_var()->get_position();
-          break;
-        default:
-          ;
-        }
-          
-      if (num_wildcard == 1 && max_level != level-1) {
-        // find the pairing inequality
-        GEQ_Iterator e2 = e;
-        e2++;
-        for ( ; e2; e2++) {
-          int num_wildcard2 = 0;
-          int max_level2 = 0;
-          bool direction2;
-          Variable_ID wc2;
-          for (Constr_Vars_Iter cvi(*e2); cvi; cvi++)
-            switch (cvi.curr_var()->kind()) {
-            case Wildcard_Var:
-              num_wildcard2++;
-              wc2 = cvi.curr_var();
-              direction2 = cvi.curr_coef()>0?true:false;
-              break;
-            case Input_Var:
-              if (cvi.curr_var()->get_position() > max_level2)
-                max_level2 = cvi.curr_var()->get_position();
-              break;
-            default:
-              ;
-            }
-
-          if (num_wildcard2 == 1 && max_level2 != level-1 && wc2 == wc && direction2 == not direction) {
-            F_Exists *f_exists = r.and_with_and()->add_exists();
-            Variable_ID wc3 = f_exists->declare();
-            F_And *f_root = f_exists->add_and();
-            GEQ_Handle h = f_root->add_GEQ();
-            for (Constr_Vars_Iter cvi(*e); cvi; cvi++) {
-              switch (cvi.curr_var()->kind()) {
-              case Wildcard_Var:
-                h.update_coef(wc3, cvi.curr_coef());
-                break;
-              case Input_Var:
-                h.update_coef(r.input_var(cvi.curr_var()->get_position()), 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());
-            
-            h = f_root->add_GEQ();
-            for (Constr_Vars_Iter cvi(*e2); cvi; cvi++) {
-              switch (cvi.curr_var()->kind()) {
-              case Wildcard_Var:
-                h.update_coef(wc3, cvi.curr_coef());
-                break;
-              case Input_Var:
-                h.update_coef(r.input_var(cvi.curr_var()->get_position()), 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((*e2).get_const());
-
-            r.simplify();
-            r.copy_names(R);
-            r.setup_names();
-            return r;
-          }
-        }
-      }
-    }
-}
-
-
-//
-// heavy lifting for code output for one leaf node
-//
-CG_outputRepr *leaf_print_repr(BoolSet<> active, const std::map<int, Relation> &guards, 
-                               CG_outputRepr *guard_repr, const Relation &known,
-                               int indent, CG_outputBuilder *ocg, const std::vector<int> &remap,
-                               const std::vector<Relation> &xforms, const std::vector<CG_outputRepr *> &stmts,
-                               const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) {
-  if (active.num_elem() == 0)
-    return NULL;
-  
-  CG_outputRepr *stmt_list = NULL;
-  for (BoolSet<>::iterator i = active.begin(); i != active.end(); i++) {
-    std::map<int, Relation>::const_iterator j = guards.find(*i);
-    if (j == guards.end() || Must_Be_Subset(copy(known), copy(j->second))) {
-      Relation mapping = Inverse(copy((xforms[remap[*i]])));
-      mapping.simplify();
-      mapping.setup_names();
-      std::vector<std::string> loop_vars;
-      for (int k = 1; k <= mapping.n_out(); k++) {
-        loop_vars.push_back(mapping.output_var(k)->name());
-//        std::cout << "CG_Utils:: " << k << ", " << mapping.output_var(k)->name().c_str() << "\n";
-      }
-      std::vector<CG_outputRepr *> sList = output_substitutions(ocg, mapping, assigned_on_the_fly);
-      stmt_list = ocg->StmtListAppend(stmt_list, ocg->CreateSubstitutedStmt((guard_repr==NULL)?indent:indent+1, stmts[remap[*i]]->clone(), loop_vars, sList));
-      active.unset(*i);
-    }
-  }
-
-  if (stmt_list != NULL) {
-    if (active.num_elem() != 0)
-      stmt_list = ocg->StmtListAppend(stmt_list, leaf_print_repr(active, guards, NULL, known, (guard_repr==NULL)?indent:indent+1, ocg, remap, xforms, stmts, assigned_on_the_fly));
-    if (guard_repr == NULL)
-      return stmt_list;
-    else
-      return ocg->CreateIf(indent, guard_repr, stmt_list, NULL);
-  }
-  else {
-    Relation then_cond = find_best_guard(const_cast<std::map<int, Relation> &>(guards)[*(active.begin())], active, guards);
-    assert(!then_cond.is_obvious_tautology());
-    Relation new_then_known = Intersection(copy(known), copy(then_cond));
-    new_then_known.simplify();
-    Relation else_cond = Complement(copy(then_cond));
-    else_cond.simplify();
-    Relation new_else_known = Intersection(copy(known), copy(else_cond));
-    new_else_known.simplify();
-    
-    BoolSet<> then_active(active.size()), else_active(active.size()), indep_active(active.size());
-    std::map<int, Relation> then_guards, else_guards;
-    for (BoolSet<>::iterator i = active.begin(); i != active.end(); i++) {
-      Relation &r = const_cast<std::map<int, Relation> &>(guards)[*i];
-      if (Must_Be_Subset(copy(r), copy(then_cond))) {
-        Relation r2 = Gist(copy(r), copy(then_cond), 1);
-        if (!r2.is_obvious_tautology())
-          then_guards[*i] = r2;
-        then_active.set(*i);
-      }
-      else if (Must_Be_Subset(copy(r), copy(else_cond))) {
-        Relation r2 = Gist(copy(r), copy(else_cond), 1);
-        if (!r2.is_obvious_tautology())
-          else_guards[*i] = r2;
-        else_active.set(*i);
-      }
-      else
-        indep_active.set(*i);
-    }
-    assert(!then_active.empty());
-    
-    CG_outputRepr *new_guard_repr = output_guard(ocg, then_cond, assigned_on_the_fly);
-    if (else_active.empty() && indep_active.empty()) {      
-      guard_repr = ocg->CreateAnd(guard_repr, new_guard_repr);
-      return leaf_print_repr(then_active, then_guards, guard_repr, new_then_known, indent, ocg, remap, xforms, stmts, assigned_on_the_fly);
-    }
-    else if (else_active.empty() && !indep_active.empty()) {
-      int new_indent = (guard_repr==NULL)?indent:indent+1;
-      stmt_list = leaf_print_repr(then_active, then_guards, new_guard_repr, new_then_known, new_indent, ocg, remap, xforms, stmts, assigned_on_the_fly);
-      stmt_list = ocg->StmtListAppend(stmt_list, leaf_print_repr(indep_active, guards, NULL, known, new_indent, ocg, remap, xforms, stmts, assigned_on_the_fly));
-      if (guard_repr == NULL)
-        return stmt_list;
-      else
-        return ocg->CreateIf(indent, guard_repr, stmt_list, NULL);
-    }
-    else { // (!else_active.empty())
-      int new_indent = (guard_repr==NULL)?indent:indent+1;
-      CG_outputRepr *then_stmt_list = leaf_print_repr(then_active, then_guards, NULL, new_then_known, new_indent+1, ocg, remap, xforms, stmts, assigned_on_the_fly);
-      CG_outputRepr *else_stmt_list = leaf_print_repr(else_active, else_guards, NULL, new_else_known, new_indent+1, ocg, remap, xforms, stmts, assigned_on_the_fly);
-      stmt_list = ocg->CreateIf(new_indent, new_guard_repr, then_stmt_list, else_stmt_list);
-      if (!indep_active.empty())
-        stmt_list = ocg->StmtListAppend(stmt_list, leaf_print_repr(indep_active, guards, NULL, known, new_indent, ocg, remap, xforms, stmts, assigned_on_the_fly));
-      if (guard_repr == NULL)
-        return stmt_list;
-      else
-        return ocg->CreateIf(indent, guard_repr, stmt_list, NULL);
-    }
-  }
-}
-
-
-//
-// heavy lifting for code output for one level of loop nodes
-//
-CG_outputRepr *loop_print_repr(const std::vector<CG_loop *> &loops, int start, int end,
-                               const Relation &guard, CG_outputRepr *guard_repr,
-                               int indent, CG_outputBuilder *ocg, const std::vector<CG_outputRepr *> &stmts,
-                               const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) {
-  if (start >= end)
-    return NULL;
-
-  Relation R = Gist(copy(loops[start]->guard_), copy(guard), 1);
-  if (Must_Be_Subset(Intersection(copy(loops[start]->known_), copy(guard)), copy(R))) {
-    int new_indent = (guard_repr==NULL)?indent:indent+1;
-    int i = start+1;
-    for ( ; i < end; i++)
-      if (!Gist(copy(loops[i]->guard_), copy(guard), 1).is_obvious_tautology())
-        break;
-    CG_outputRepr *stmt_list = NULL;
-    for (int j = start; j < i; j++)
-      stmt_list = ocg->StmtListAppend(stmt_list, loops[j]->printRepr(false, new_indent, ocg, stmts, assigned_on_the_fly));
-    stmt_list = ocg->StmtListAppend(stmt_list, loop_print_repr(loops, i, end, guard, NULL, new_indent, ocg, stmts, assigned_on_the_fly));
-    if (guard_repr == NULL)
-      return stmt_list;
-    else
-      return ocg->CreateIf(indent, guard_repr, stmt_list, NULL);
-  }
-
-  Relation then_cond = find_best_guard(R, loops, start, end);
-  assert(!then_cond.is_obvious_tautology());
-  Relation else_cond = Complement(copy(then_cond));
-  else_cond.simplify();
-  
-  std::vector<CG_loop *> then_loops, else_loops, indep_loops;
-  int i = start;
-  for ( ; i < end; i++)
-    if (!Must_Be_Subset(copy(loops[i]->guard_), copy(then_cond)))
-      break;
-  int j = i;
-  for ( ; j < end; j++)
-    if (!Must_Be_Subset(copy(loops[j]->guard_), copy(else_cond)))
-      break;
-  assert(i>start);
-
-  CG_outputRepr *new_guard_repr = output_guard(ocg, then_cond, assigned_on_the_fly);
-  if (j == i && end == j) {
-    guard_repr = ocg->CreateAnd(guard_repr, new_guard_repr);
-    Relation new_guard = Intersection(copy(guard), copy(then_cond));
-    new_guard.simplify();
-    return loop_print_repr(loops, start, end, new_guard, guard_repr, indent, ocg, stmts, assigned_on_the_fly);
-  }
-  else if (j == i && end > j) {
-    int new_indent = (guard_repr==NULL)?indent:indent+1;
-    Relation new_guard = Intersection(copy(guard), copy(then_cond));
-    new_guard.simplify();
-    CG_outputRepr *stmt_list = loop_print_repr(loops, start, i, new_guard, new_guard_repr, new_indent, ocg, stmts, assigned_on_the_fly);
-    stmt_list = ocg->StmtListAppend(stmt_list, loop_print_repr(loops, j, end, guard, NULL, new_indent, ocg, stmts, assigned_on_the_fly));
-    if (guard_repr == NULL)
-      return stmt_list;
-    else
-      return ocg->CreateIf(indent, guard_repr, stmt_list, NULL);
-  }
-  else { // (j > i)
-    int new_indent = (guard_repr==NULL)?indent:indent+1;
-    Relation then_new_guard = Intersection(copy(guard), copy(then_cond));
-    then_new_guard.simplify();
-    CG_outputRepr *then_stmt_list = loop_print_repr(loops, start, i, then_new_guard, NULL, new_indent+1, ocg, stmts, assigned_on_the_fly);
-    Relation else_new_guard = Intersection(copy(guard), copy(else_cond));
-    else_new_guard.simplify();
-    CG_outputRepr *else_stmt_list = loop_print_repr(loops, i, j, else_new_guard, NULL, new_indent+1, ocg, stmts, assigned_on_the_fly);
-    CG_outputRepr *stmt_list = ocg->CreateIf(new_indent, new_guard_repr, then_stmt_list, else_stmt_list);
-    stmt_list = ocg->StmtListAppend(stmt_list, loop_print_repr(loops, j, end, guard, NULL, new_indent, ocg, stmts, assigned_on_the_fly));
-    if (guard_repr == NULL)
-      return stmt_list;
-    else
-      return ocg->CreateIf(indent, guard_repr, stmt_list, NULL);
-  }
-}
-
-}
diff --git a/omegalib/codegen/src/codegen.cc b/omegalib/codegen/src/codegen.cc
deleted file mode 100755
index 92ca702..0000000
--- a/omegalib/codegen/src/codegen.cc
+++ /dev/null
@@ -1,378 +0,0 @@
-/*****************************************************************************
- Copyright (C) 1994-2000 the Omega Project Team
- Copyright (C) 2005-2011 Chun Chen
- All Rights Reserved.
-
- Purpose:
-   CodeGen class as entry point for code generation.
-
- Notes:
-   Loop variable name prefix should not cause any possible name conflicts
- with original loop variables wrapped in statement holder. This guarantees
- that variable substitution done correctly in the generated code.
-
- History:
-   04/24/96 MMGenerateCode, added by Fortran D people. Lei Zhou
-   09/17/08 loop overhead removal based on actual nesting depth -- by chun
-   03/05/11 fold MMGenerateCode into CodeGen class, Chun Chen
-*****************************************************************************/
-
-#include <typeinfo>
-#include <omega.h>
-#include <basic/util.h>
-#include <math.h>
-#include <vector>
-#include <algorithm>
-
-#include <code_gen/CG.h>
-#include <code_gen/codegen.h>
-#include <code_gen/CG_outputBuilder.h>
-#include <code_gen/codegen_error.h>
-
-namespace omega {
-
-const std::string CodeGen::loop_var_name_prefix = "t";
-const int CodeGen::var_substitution_threshold = 10;
-
-//Anand--adding stuff to make Chun's code work with Gabe's
-std::vector< std::vector<int> > smtNonSplitLevels;
-std::vector< std::vector<std::string> > loopIdxNames;//per stmt
-std::vector< std::pair<int, std::string> > syncs;
-
-
-
-CodeGen::CodeGen(const std::vector<Relation> &xforms, const std::vector<Relation> &IS, const Relation &known, std::vector< std::vector<int> > smtNonSplitLevels_ , std::vector< std::vector<std::string> > loopIdxNames_,  std::vector< std::pair<int, std::string> > syncs_) {
-  // check for sanity of parameters
-  int num_stmt = IS.size();
-  if (xforms.size() != num_stmt)
-    throw std::invalid_argument("number of iteration spaces does not match number of transformations");
-  known_ = copy(known);
-  if (known_.n_out() != 0)
-    throw std::invalid_argument("known condition must be a set relation");
-  if (known_.is_null())
-    known_ = Relation::True(0);
-  else
-    known_.simplify(2, 4);
-  if (!known_.is_upper_bound_satisfiable())
-    return;
-  if (known_.number_of_conjuncts() > 1)
-    throw std::invalid_argument("only one conjunct allowed in known condition");
-  xforms_ = xforms;
-  for (int i = 0; i < num_stmt; i++) {
-    xforms_[i].simplify();
-    if (!xforms_[i].has_single_conjunct())
-      throw std::invalid_argument("mapping relation must have only one conjunct");
-    if (xforms_[i].n_inp() != IS[i].n_inp() || IS[i].n_out() != 0)
-      throw std::invalid_argument("illegal iteration space or transformation arity");
-  }
-
-
-  //protonu--
-  //easier to handle this as a global
-  smtNonSplitLevels = smtNonSplitLevels_;
-  syncs = syncs_;
-  loopIdxNames = loopIdxNames_;
-  //end-protonu
-
-
-
-  // find the maximum iteration space dimension we are going to operate on
-  int num_level = known_.n_inp();
-  for (int i = 0; i < num_stmt; i++)
-    if (xforms_[i].n_out() > num_level)
-      num_level = xforms_[i].n_out();
-  known_ = Extend_Set(known_, num_level-known_.n_inp());
-  for (int i = 1; i <= num_level; i++)
-    known_.name_set_var(i, loop_var_name_prefix + to_string(i));
-  known_.setup_names();
-
-  // split disjoint conjunctions in original iteration spaces
-  std::vector<Relation> new_IS;
-  for (int i = 0; i < num_stmt; i++) {
-    for (int j = 1; j <= IS[i].n_inp(); j++)
-      xforms_[i].name_input_var(j, const_cast<std::vector<Relation> &>(IS)[i].input_var(j)->name());
-    for (int j = 1; j <= xforms_[i].n_out(); j++)
-      xforms_[i].name_output_var(j, loop_var_name_prefix + to_string(j));
-    xforms_[i].setup_names();
-
-    Relation R = Range(Restrict_Domain(copy(xforms_[i]), copy(IS[i])));
-    R = Intersection(Extend_Set(R, num_level-R.n_inp()), copy(known_));
-    R.simplify(2, 4);
-    if (R.is_inexact())
-      throw codegen_error("cannot generate code for inexact iteration spaces");
-
-    while(R.is_upper_bound_satisfiable()) {
-      DNF *dnf = R.query_DNF();
-      DNF_Iterator c(dnf);
-      Relation R2 = Relation(R, *c);
-      R2.simplify();
-      new_IS.push_back(copy(R2));
-      remap_.push_back(i);
-      c.next();
-      if (!c.live()) 
-        break;
-      Relation remainder(R, *c);
-      c.next();
-      while (c.live()) {
-        remainder = Union(remainder, Relation(R, *c));
-        c.next();
-      }
-      R = Difference(remainder, R2);
-      R.simplify(2, 4);
-    }
-  }
-
-  // number of new statements after splitting
-  num_stmt = new_IS.size();
-  if(!smtNonSplitLevels.empty())
-      smtNonSplitLevels.resize(num_stmt);
-  // assign a dummy value to loops created for the purpose of expanding to maximum dimension
-  for (int i = 0; i < num_stmt; i++) {
-    if (xforms[remap_[i]].n_out() < num_level) {
-      F_And *f_root = new_IS[i].and_with_and();
-      for (int j = xforms[remap_[i]].n_out()+1; j <= num_level; j++) {
-        EQ_Handle h = f_root->add_EQ();
-        h.update_coef(new_IS[i].set_var(j), 1);
-        h.update_const(posInfinity);
-      }
-      new_IS[i].simplify();
-    }   
-  }
-
-  // calculate projected subspaces for each loop level once and save for CG tree manipulation later
-  projected_IS_ = std::vector<std::vector<Relation> >(num_level);
-  for (int i = 0; i < num_level; i++)
-    projected_IS_[i] = std::vector<Relation>(num_stmt);
-  for (int i = 0; i < num_stmt; i++) {
-    if (num_level > 0)
-      projected_IS_[num_level-1][i] = new_IS[i];
-    for (int j = num_level-1; j >= 1; j--) {
-      projected_IS_[j-1][i] = Project(copy(projected_IS_[j][i]), j+1, Set_Var);
-      projected_IS_[j-1][i].simplify(2, 4);
-    }
-  }
-}
-
-
-CG_result *CodeGen::buildAST(int level, const BoolSet<> &active, bool split_on_const, const Relation &restriction) {
-  if (level > num_level())
-    return new CG_leaf(this, active);
-
-  int num_active_stmt = active.num_elem();
-  if (num_active_stmt == 0)
-    return NULL;
-  else if (num_active_stmt == 1)
-    return new CG_loop(this, active, level, buildAST(level+1, active, true, restriction));
-
-  // use estimated constant bounds for fast non-overlap iteration space splitting
-  if (split_on_const) {
-    std::vector<std::pair<std::pair<coef_t, coef_t>, int> > bounds;
-
-    for (BoolSet<>::const_iterator i = active.begin(); i != active.end(); i++) {
-      Relation r = Intersection(copy(projected_IS_[level-1][*i]), copy(restriction));
-      r.simplify(2, 4);
-      if (!r.is_upper_bound_satisfiable())
-        continue;
-      coef_t lb, ub;
-      r.single_conjunct()->query_variable_bounds(r.set_var(level),lb,ub);
-      bounds.push_back(std::make_pair(std::make_pair(lb, ub), *i));
-    }
-    sort(bounds.begin(), bounds.end());
-
-    std::vector<Relation> split_cond;
-    std::vector<CG_result *> split_child;
-
-    coef_t prev_val = -posInfinity;
-    coef_t next_val = bounds[0].first.second;
-    BoolSet<> next_active(active.size());
-    int i = 0;
-    while (i < bounds.size()) {
-      if (bounds[i].first.first <= next_val) {
-        next_active.set(bounds[i].second);
-        next_val = max(next_val, bounds[i].first.second);
-        i++;
-      }
-      else {
-        Relation r(num_level());
-        F_And *f_root = r.add_and();
-        if (prev_val != -posInfinity) {
-          GEQ_Handle h = f_root->add_GEQ();
-          h.update_coef(r.set_var(level), 1);
-          h.update_const(-prev_val-1);
-        }
-        if (next_val != posInfinity) {
-          GEQ_Handle h = f_root->add_GEQ();
-          h.update_coef(r.set_var(level), -1);
-          h.update_const(next_val);
-        }
-        r.simplify();
-
-        Relation new_restriction = Intersection(copy(r), copy(restriction));
-        new_restriction.simplify(2, 4);
-        CG_result *child = buildAST(level, next_active, false, new_restriction);
-        if (child != NULL) {
-          split_cond.push_back(copy(r));
-          split_child.push_back(child);
-        }
-        next_active.unset_all();
-        prev_val = next_val;
-        next_val = bounds[i].first.second;
-      }
-    }
-    if (!next_active.empty()) {
-      Relation r = Relation::True(num_level());
-      if (prev_val != -posInfinity) {
-        F_And *f_root = r.and_with_and();
-        GEQ_Handle h = f_root->add_GEQ();
-        h.update_coef(r.set_var(level), 1);
-        h.update_const(-prev_val-1);
-        r.simplify();
-      }
-      Relation new_restriction = Intersection(copy(r), copy(restriction));
-      new_restriction.simplify(2, 4);
-      CG_result *child = buildAST(level, next_active, false, new_restriction);
-      if (child != NULL) {
-        split_cond.push_back(copy(r));
-        split_child.push_back(child);
-      }
-    }
-
-    if (split_child.size() == 0)
-      return NULL;
-    else if (split_child.size() == 1)
-      return split_child[0];
-    else
-      return new CG_split(this, active, split_cond, split_child);
-  }
-  // check bound conditions exhaustively for non-overlap iteration space splitting
-  else {
-    std::vector<Relation> Rs(active.size());
-    for (BoolSet<>::const_iterator i = active.begin(); i != active.end(); i++) {
-      Rs[*i] = Intersection(Approximate(copy(projected_IS_[level-1][*i])), copy(restriction));
-      Rs[*i].simplify(2, 4);
-    }
-    Relation hull = SimpleHull(Rs);
-
-    //protonu-warn Chun about this change
-  //This does some fancy splitting of statements into loops with the
-  //fewest dimentions, but that's not necessarily what we want when
-  //code-gening for CUDA. smtNonSplitLevels keeps track per-statment of
-  //the levels that should not be split on.
-  bool checkForSplits = true;
- for (BoolSet<>::const_iterator i = active.begin(); i != active.end(); i++) {
-      if(*i  < smtNonSplitLevels.size())
-         for(int k = 0; k <smtNonSplitLevels[*i].size();  k++)
-           if(smtNonSplitLevels[*i][k] == (level-2)){
-               checkForSplits = false;
-              break;
-      }
-    }
-  
-
-
-
-    for (BoolSet<>::const_iterator i = active.begin(); i != active.end() && checkForSplits; i++) {
-      Relation r = Gist(copy(Rs[*i]), copy(hull), 1);
-      if (r.is_obvious_tautology())
-        continue;
-      r = EQs_to_GEQs(r);
-
-      for (GEQ_Iterator e = r.single_conjunct()->GEQs(); e; e++) {
-        if ((*e).has_wildcards())
-          continue;
-            
-        Relation cond = Relation::True(num_level());
-        BoolSet<> first_chunk(active.size());
-        BoolSet<> second_chunk(active.size());
-
-        if ((*e).get_coef(hull.set_var(level)) > 0) {
-          cond.and_with_GEQ(*e);
-          cond = Complement(cond);;
-          cond.simplify();
-          second_chunk.set(*i);
-        }
-        else if ((*e).get_coef(hull.set_var(level)) < 0) {
-          cond.and_with_GEQ(*e);
-          cond.simplify();
-          first_chunk.set(*i);
-        }
-        else
-          continue;
-
-        bool is_proper_split_cond = true;
-        for (BoolSet<>::const_iterator j = active.begin(); j != active.end(); j++)
-          if ( *j != *i) {
-          bool in_first = Intersection(copy(Rs[*j]), copy(cond)).is_upper_bound_satisfiable();
-          bool in_second = Difference(copy(Rs[*j]), copy(cond)).is_upper_bound_satisfiable();
-
-          if (in_first && in_second) {
-            is_proper_split_cond = false;
-            break;
-          }
-
-          if (in_first)
-            first_chunk.set(*j);
-          else if (in_second)
-            second_chunk.set(*j);
-          }
-
-        if (is_proper_split_cond && first_chunk.num_elem() != 0 && second_chunk.num_elem() != 0) {
-          CG_result *first_cg = buildAST(level, first_chunk, false, copy(cond));
-          CG_result *second_cg = buildAST(level, second_chunk, false, Complement(copy(cond)));
-          if (first_cg == NULL)
-            return second_cg;
-          else if (second_cg == NULL)
-            return first_cg;
-          else {
-            std::vector<Relation> split_cond;
-            std::vector<CG_result *> split_child;
-            split_cond.push_back(copy(cond));
-            split_child.push_back(first_cg);
-            split_cond.push_back(Complement(copy(cond)));
-            split_child.push_back(second_cg);
-
-            return new CG_split(this, active, split_cond, split_child);
-          }
-        }
-      }
-    }
-    return new CG_loop(this, active, level, buildAST(level+1, active, true, restriction));
-  }
-}
-
-
-CG_result *CodeGen::buildAST(int effort) {
-  if (remap_.size() == 0)
-    return NULL;
-
-  CG_result *cgr = buildAST(1, ~BoolSet<>(remap_.size()), true, Relation::True(num_level()));
-  if (cgr == NULL)
-    return NULL;
-
-
-  // break down the complete iteration space condition to levels of bound/guard condtions
-  cgr = cgr->recompute(cgr->active_, copy(known_), copy(known_));
-
-
-
-  if (cgr == NULL)
-    return NULL;
-
-  // calculate each loop's nesting depth
-  int depth = cgr->populateDepth();
-
-
-  // redistribute guard condition locations by additional splittings
-  std::pair<CG_result *, Relation> result = cgr->liftOverhead(min(effort,depth), false);
-
-  // since guard conditions are postponed for non-loop levels, hoist them now.
-  // this enables proper if-condition simplication when outputting actual code.
-  result.first->hoistGuard();
-
-
-
-
-  return result.first;
-}
-
-}
diff --git a/omegalib/codegen/src/rose_attributes.cc b/omegalib/codegen/src/rose_attributes.cc
deleted file mode 100644
index bb9681c..0000000
--- a/omegalib/codegen/src/rose_attributes.cc
+++ /dev/null
@@ -1,183 +0,0 @@
-#include <code_gen/rose_attributes.h>
-
-namespace omega {
-
-CodeInsertionAttribute* getOrCreateCodeInsertionAttribute(SgNode* node) {
-	CodeInsertionAttribute* attr;
-	if(node->attributeExists("code_insertion"))
-		return static_cast<CodeInsertionAttribute*>(node->getAttribute("code_insertion"));
-	attr = new CodeInsertionAttribute();
-	node->setAttribute("code_insertion", attr);
-	return attr;
-}
-
-void postProcessRoseCodeInsertion(SgProject* proj) {
-	//generatePDF(*proj);
-	CodeInsertionVisitor visitor = CodeInsertionVisitor();
-	visitor.initialize();
-	visitor.traverseInputFiles(proj);
-	visitor.insertCode();
-}
-
-// Swap a code insertion from one node (sn) to another (dn)
-// -- note that this function does not currently remove the insertion from the sn node
-void moveCodeInsertion(SgNode* sn, CodeInsertion* ci, SgNode* dn) {
-	CodeInsertionAttribute* new_attr;
-	// TODO in the near future: replace the above statement with 'new_attr = getOrCreateCodeInsertionAttribute(...)'
-	CodeInsertionAttribute* old_attr = static_cast<CodeInsertionAttribute*>(sn->getAttribute("code_insertion"));
-	if(dn->attributeExists("code_insertion")) {
-		new_attr = static_cast<CodeInsertionAttribute*>(dn->getAttribute("code_insertion"));
-	}
-	else {
-		new_attr = new CodeInsertionAttribute();
-		dn->setAttribute("code_insertion", new_attr);
-	}
-	new_attr->add(ci);
-}
-
-// A function that copies a specific attribute from one node to another
-// this function exists to get around a ROSE limitation that does not
-// copy attributes
-void copyAttribute(std::string attr_name, SgNode* s, SgNode* d) {
-	if(s->attributeExists(attr_name)) {
-		d->setAttribute(attr_name,s->getAttribute(attr_name));
-	}
-}
-
-// TODO: find all existng attributes and iterate over them instead of doing them
-//       individually
-void copyAttributes(SgNode* s, SgNode* d) {
-	copyAttribute("code_insertion", s, d);
-	//...any other attributes...
-}
-
-void CodeInsertionVisitor::initialize() {
-	this->loop_level = 0;
-	this->ci_marks = std::vector<CodeInsertionMark*>();
-}
-
-void CodeInsertionVisitor::markStmt(SgStatement* stmt, CodeInsertion* ci) {
-	// this check prevents multiple copies of stmts
-	// -- may be changed in the future
-	if(!ci->marked) {
-		CodeInsertionMark* pos = new CodeInsertionMark();
-		pos->stmt = stmt;
-		pos->ci = ci;
-		this->ci_marks.push_back(pos);
-		ci->marked = true;
-	}
-}
-
-// increase loop_level as the visitor descends
-void CodeInsertionVisitor::preOrderVisit(SgNode* n) {
-	if (isSgForStatement(n)) {
-		this->loop_level++;
-	}
-}
-
-void CodeInsertionVisitor::postOrderVisit(SgNode* n) {
-	if(isSgForStatement(n)) {
-		this->loop_level--;
-	}
-	if(isSgStatement(n)) {
-		if(n->attributeExists("code_insertion")) {
-			CodeInsertionAttribute *attr = static_cast<CodeInsertionAttribute*>(n->getAttribute("code_insertion"));
-			for(CodeInsertionPtrListItr itr = attr->begin(); itr != attr->end(); ++itr) {
-				CodeInsertion *insertion = *itr;
-				// check loop level -- if it is equivelent, mark statement for insertion
-				//                  -- else, move attribute up to parent
-				if(insertion->loop_level != this->loop_level) {
-					moveCodeInsertion(n, insertion, n->get_parent());
-				}
-				else {
-					this->markStmt(isSgStatement(n), insertion);
-				}
-			}
-		}
-	}
-}
-
-// final stage of algorithm that inserts marked statements
-void CodeInsertionVisitor::insertCode() {
-	for(std::vector<CodeInsertionMark*>::iterator itr = this->ci_marks.begin(); itr != this->ci_marks.end(); ++itr) {
-		CodeInsertionMark* mark = *itr;
-		SgScopeStatement* scope = static_cast<SgScopeStatement*>(mark->stmt->get_parent());
-		SageInterface::insertStatementBefore(mark->stmt, mark->ci->getStatement(scope));
-	}
-}
-
-SgStatement* PragmaInsertion::getStatement(SgScopeStatement* scopeStmt) {
-	SgStatement* stmt = SageBuilder::buildPragmaDeclaration(this->name);
-	return stmt;
-}
-
-//SgStatement* MMPrefetchInsertion::getStatement(SgScopeStatement* scopeStmt) {
-//	const SgName& name = SgName("_mm_prefetch");
-//	SgType* rtype = SageBuilder::buildVoidType();
-//	SgExpression* arr_arg = SageBuilder::buildVarRefExp(this->arrName);
-//	SgExpression* hint_arg = SageBuilder::buildShortVal(this->cacheHint);
-//	SgExprListExp* args = SageBuilder::buildExprListExp(arr_arg,hint_arg);
-//	SgStatement* stmt = SageBuilder::buildFunctionCallStmt(name, rtype, args, scopeStmt);
-//	return stmt;
-//}
-
-SgStatement* MMPrefetchInsertion::getStatement(SgScopeStatement* scopeStmt) {
-	const SgName fname = SgName("_mm_prefetch");
-	SgType* rtype = SageBuilder::buildVoidType();
-	SgExpression* arr_arg = this->buildArrArg(scopeStmt);
-	SgExpression* hint_arg = SageBuilder::buildShortVal(this->cacheHint);
-	SgExprListExp* args = SageBuilder::buildExprListExp(arr_arg, hint_arg);
-	return SageBuilder::buildFunctionCallStmt(fname, rtype, args, scopeStmt);
-}
-
-SgExpression* MMPrefetchInsertion::buildArrArg(SgScopeStatement* scopeStmt) {
-	// if there are no index arguments given, just return a variable reference
-	if(this->indexCount == 0) {
-		const SgName aname = SgName(this->arrName);
-		return SageBuilder::buildVarRefExp(aname, scopeStmt);
-	}
-	std::vector<SgExpression*> argList = std::vector<SgExpression*>();
-	// foreach dimension
-	for(int i = 0; i < this->indexCount; i++) {
-		argList.push_back(this->makeIndexExp(i, scopeStmt));
-	}
-	return SageBuilder::buildExprListExp(argList);
-}
-
-SgExpression* MMPrefetchInsertion::makeIndexExp(int dim, SgScopeStatement* scopeStmt) {
-	//(i + offset) or (offset) or (i)
-	std::string* indexer = this->indecies.at(dim);
-	int offset = this->offsets.at(dim);
-	if(indexer == NULL) {
-		return SageBuilder::buildIntVal(offset);
-	}
-	else {
-		const SgName name = SgName(*indexer);
-		SgVarRefExp* iref = SageBuilder::buildVarRefExp(name, scopeStmt);
-		if(offset == 0) {
-			return iref;
-		}
-		else {
-			return SageBuilder::buildAddOp(iref, SageBuilder::buildIntVal(offset));
-		}
-	}
-}
-
-void MMPrefetchInsertion::initialize(const std::string& arrName, int hint) {
-	this->arrName = std::string(arrName);
-	this->cacheHint = hint;
-	this->indecies = std::vector<std::string*>();
-	this->offsets = std::vector<int>();
-	this->indexCount = 0;
-}
-void MMPrefetchInsertion::addDim(int offset) {
-	this->offsets.push_back(offset);
-	this->indecies.push_back(NULL);
-	this->indexCount++;
-}
-void MMPrefetchInsertion::addDim(int offset, const std::string& indexer) {
-	this->offsets.push_back(offset);
-	this->indecies.push_back(new std::string(indexer));
-	this->indexCount++;
-}
-}
diff --git a/omegalib/doc/calculator.pdf b/omegalib/doc/calculator.pdf
deleted file mode 100755
index 5c307ab..0000000
Binary files a/omegalib/doc/calculator.pdf and /dev/null differ
diff --git a/omegalib/doc/interface.pdf b/omegalib/doc/interface.pdf
deleted file mode 100755
index 7f918ae..0000000
Binary files a/omegalib/doc/interface.pdf and /dev/null differ
diff --git a/omegalib/omega/CMakeLists.txt b/omegalib/omega/CMakeLists.txt
deleted file mode 100644
index 5bc7e0b..0000000
--- a/omegalib/omega/CMakeLists.txt
+++ /dev/null
@@ -1,69 +0,0 @@
-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
deleted file mode 100644
index 7f918ae..0000000
Binary files a/omegalib/omega/doc/interface.pdf and /dev/null differ
diff --git a/omegalib/omega/include/basic/Bag.h b/omegalib/omega/include/basic/Bag.h
deleted file mode 100644
index a3d07a0..0000000
--- a/omegalib/omega/include/basic/Bag.h
+++ /dev/null
@@ -1,405 +0,0 @@
-#if ! defined _Bag_h
-#define _Bag_h 1
-
-#include <stdio.h>
-#include <basic/Iterator.h>
-#include <basic/Collection.h>
-#include <basic/Link.h>
-#include <assert.h>
-
-namespace omega {
-
-template<class T> class Bag : public Collection<T> { 
-public:
-virtual ~Bag();
-	Bag();
-	Bag(const Bag<T>&);
-	Bag & operator=(const Bag<T>&);
-    //! add elements in b
-    virtual	void operator |= (const Bag<T> & 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();
-	Ordered_Bag(const Ordered_Bag<T>& B) : Bag<T>(B) {}
-	void insert(T);
-    //! add elements in b
-    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();
-	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
-    
-    //! add elements in b
-    virtual	void operator |= (const Set<T> & b);
-    //! add elements in b
-	void operator |= (const Ordered_Bag<T> & b);
-    //! add elements in b
-	void operator |= (const Bag<T> & b);
-
-    //! delete items also in b
-    void operator -= (const Set<T> & b);
-    //! delete items not in b
-    void operator &= (const Set<T> & b);
-    //! check for elements in common
-    bool operator & (const Set<T> &) const;
-};
-
-} // namespace
-
-#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)
-
-
-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
-
-#endif
diff --git a/omegalib/omega/include/basic/BoolSet.h b/omegalib/omega/include/basic/BoolSet.h
deleted file mode 100755
index a78af2e..0000000
--- a/omegalib/omega/include/basic/BoolSet.h
+++ /dev/null
@@ -1,641 +0,0 @@
-/*****************************************************************************
- 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 {
-
-    //!  BoolSet class, used as a set of integers from 0 to n-1 where n is a very small integer.
-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> &); 
-
-  //! 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> &, const BoolSet<TT> &);
-  //! complement
-  template<typename TT> friend BoolSet<TT> operator~(const BoolSet<TT> &);                 
-  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> &);
-
-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
deleted file mode 100644
index 80ddf48..0000000
--- a/omegalib/omega/include/basic/Collection.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#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;
-
-    /*! Y in X --> X[X.index(Y)] == Y */
-    virtual int index(const T &) const = 0;  };
-
-} // 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
deleted file mode 100644
index 1e68031..0000000
--- a/omegalib/omega/include/basic/Collections.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#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
deleted file mode 100644
index f149c9d..0000000
--- a/omegalib/omega/include/basic/ConstString.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#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/DynamicArray.h b/omegalib/omega/include/basic/DynamicArray.h
deleted file mode 100644
index 08f8b91..0000000
--- a/omegalib/omega/include/basic/DynamicArray.h
+++ /dev/null
@@ -1,318 +0,0 @@
-#ifndef Already_Included_DynamicArray
-#define Already_Included_DynamicArray
-
-#include <assert.h>
-
-namespace omega {
-
-template <class T> class DynamicArray2;
-template <class T> class DynamicArray3;
-template <class T> class DynamicArray4;
-
-template <class T, int d> class DynamicArray
-    {
-    public:
-	DynamicArray(DynamicArray<T,d> &D);
-        ~DynamicArray();
-
-    protected:
-	DynamicArray();
-	bool partial;
-	int *bounds;
-	T *elements;
-
-	void do_constr();
-	void do_destruct();
-    };
-
-
-template <class T> class DynamicArray1 : public DynamicArray<T,1>
-    {
-    public:
-	DynamicArray1(const char *s0 = 0);
-	DynamicArray1(int d0);
-	void resize(int d0);
-        T& operator[](int d);
-
-	friend class DynamicArray2<T>;
-
-    private:
-	void do_construct(int d0);
-    };
-
-
-template <class T> class DynamicArray2 : public DynamicArray<T,2>
-    {
-    public:
-	DynamicArray2(const char *s0 = 0, const char *s1 = 0);
-	DynamicArray2(int d0, int d1);
-	void resize(int d0, int d1);
-  	DynamicArray1<T> operator[](int d);
-
-	friend class DynamicArray3<T>;
-
-    private:
-	void do_construct(int d0, int d1);
-    };
-
-
-template <class T> class DynamicArray3 : public DynamicArray<T,3>
-    {
-    public:
-	DynamicArray3(const char *s0 = 0, const char *s1 = 0, const char *s2 = 0);
-	DynamicArray3(int d0, int d1, int d2);
-	void resize(int d0, int d1, int d2);
-  	DynamicArray2<T> operator[](int d);
-
-	friend class DynamicArray4<T>;
-
-    private:
-	void do_construct(int d0, int d1, int d2);
-    };
-
-template <class T> class DynamicArray4 : public DynamicArray<T,4>
-    {
-    public:
-	DynamicArray4(const char *s0 = 0, const char *s1 = 0, const char *s2 = 0, const char *s3 = 0);
-	DynamicArray4(int d0, int d1, int d2, int d3);
-	void resize(int d0, int d1, int d2, int d3);
-  	DynamicArray3<T> operator[](int d);
-
-    private:
-	void do_construct(int d0, int d1, int d2, int d3);
-    };
-
-} // namespace
-
-#define instantiate_DynamicArray1(T)	template class DynamicArray1<T>; \
-					template class DynamicArray<T,1>;
-
-#define instantiate_DynamicArray2(T)	template class DynamicArray2<T>;  \
-					template class DynamicArray<T,2>; \
-					instantiate_DynamicArray1(T);
-
-#define instantiate_DynamicArray3(T)	template class DynamicArray3<T>;  \
-					template class DynamicArray<T,3>; \
-					instantiate_DynamicArray2(T);
-
-#define instantiate_DynamicArray4(T)	template class DynamicArray4<T>;  \
-					template class DynamicArray<T,4>; \
-					instantiate_DynamicArray3(T);
-
-namespace omega {
-  
-template<class T, int d> void DynamicArray<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 DynamicArray1<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 DynamicArray2<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 DynamicArray3<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 DynamicArray4<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> DynamicArray<T,d>::DynamicArray()
-    {
-    do_constr();
-    }
-
-template<class T> DynamicArray1<T>::DynamicArray1(const char *)
-    {
-    this->do_constr();
-    }
-
-template<class T> DynamicArray2<T>::DynamicArray2(const char *,const char *)
-    {
-    this->do_constr();
-    }
-
-template<class T> DynamicArray3<T>::DynamicArray3(const char *,const char *,const char *)
-    {
-    this->do_constr();
-    }
-
-template<class T> DynamicArray4<T>::DynamicArray4(const char *,const char *,const char *,const char *)
-    {
-    this->do_constr();
-    }
-
-template<class T> DynamicArray1<T>::DynamicArray1(int d0)
-    {
-    do_construct(d0);
-    } 
-
-template<class T> DynamicArray2<T>::DynamicArray2(int d0, int d1)
-    {
-    do_construct(d0, d1);
-    }
-
-template<class T> DynamicArray3<T>::DynamicArray3(int d0,int d1,int d2)
-    {
-    do_construct(d0, d1, d2);
-    }
-
-template<class T> DynamicArray4<T>::DynamicArray4(int d0,int d1,int d2,int d3)
-    {
-    do_construct(d0, d1, d2, d3);
-    }
-
-
-template<class T, int d> void DynamicArray<T,d>::do_destruct()
-    {
-    if (! partial)
-	{
-        delete [] bounds;
-        delete [] elements;
-	}
-    }
-
-
-template<class T, int d> DynamicArray<T,d>::~DynamicArray()
-    {
-    do_destruct();
-    }
-
-
-template<class T> void DynamicArray1<T>::resize(int d0)
-    {
-    assert(!this->partial);
-    this->do_destruct();
-    if (d0 == 0)
-        this->do_constr();
-    else
-        do_construct(d0);
-    } 
-
-template<class T> void DynamicArray2<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 DynamicArray3<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 DynamicArray4<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& DynamicArray1<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>  DynamicArray1<T> DynamicArray2<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
-
-    DynamicArray1<T> result;
-    result.bounds = this->bounds+1;
-    result.elements = this->elements + this->bounds[1] * d0;
-    result.partial = true;
-    return result;
-    }
-
-template<class T>  DynamicArray2<T> DynamicArray3<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
-    DynamicArray2<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>  DynamicArray3<T> DynamicArray4<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
-
-    DynamicArray3<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> 
-    DynamicArray<T,d>::DynamicArray(DynamicArray<T,d> &D)
-    {
-    assert(D.elements != 0 && "Trying to copy an undefined array");
-    partial = true;
-    bounds = D.bounds;
-    elements = D.elements;
-    }
-
-} // namespace
-#endif
diff --git a/omegalib/omega/include/basic/Iterator.h b/omegalib/omega/include/basic/Iterator.h
deleted file mode 100644
index f62874c..0000000
--- a/omegalib/omega/include/basic/Iterator.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * 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)
-
-/*!
- * \brief 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
-/*! Values 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:
-    //! take over *p, *p MUST BE ON THE HEAP
-    Any_Iterator(Iterator<T> *p) { me = p; }
-    friend class Collection<T>;
-/* 
- *   // Couldn't make this work with g++258
- *   friend Any_Iterator<T> Collection<T>::any_iterator();
- */
-    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
deleted file mode 100644
index bdf169c..0000000
--- a/omegalib/omega/include/basic/Link.h
+++ /dev/null
@@ -1,97 +0,0 @@
-#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
-
-#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
-/*! 
- * \brief 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.
- */
-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.h b/omegalib/omega/include/basic/List.h
deleted file mode 100644
index 28ab1d5..0000000
--- a/omegalib/omega/include/basic/List.h
+++ /dev/null
@@ -1,233 +0,0 @@
-#if ! defined _List_h
-#define _List_h 1
-
-/*
- *  Linked lists with an interface like a bit of libg++'s SLList class
- */
-#include <stdio.h>  // for NULL
-#include <basic/Iterator.h>
-#include <basic/Collection.h>
-#include <basic/Link.h>
-#include <assert.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
-
-#define instantiate_List(T)	template class List<T>; \
-				template class List_Iterator<T>; \
-				instantiate_Only_List_Element(T) \
-				instantiate_Sequence(T)
-
-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
-#endif
diff --git a/omegalib/omega/include/basic/Map.h b/omegalib/omega/include/basic/Map.h
deleted file mode 100644
index 25a116d..0000000
--- a/omegalib/omega/include/basic/Map.h
+++ /dev/null
@@ -1,127 +0,0 @@
-#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
-
-#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)
-
-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
-#endif
diff --git a/omegalib/omega/include/basic/Section.h b/omegalib/omega/include/basic/Section.h
deleted file mode 100644
index 7a4d241..0000000
--- a/omegalib/omega/include/basic/Section.h
+++ /dev/null
@@ -1,138 +0,0 @@
-#if ! defined _Section_h
-#define _Section_h 1
-/*
-  Section of an existing collection viewed as a collection
-  */
-
-#include <basic/Collection.h>
-#include <assert.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
-
-#define instantiate_Section(T)	template class Section<T>; \
-				template class Section_Iterator<T>; \
-				instantiate_Sequence(T)
-#define instantiate_Section_Iterator(T)	  instantiate_Section(T)
-
-
-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
-#endif
diff --git a/omegalib/omega/include/basic/SimpleList.h b/omegalib/omega/include/basic/SimpleList.h
deleted file mode 100644
index 104390d..0000000
--- a/omegalib/omega/include/basic/SimpleList.h
+++ /dev/null
@@ -1,194 +0,0 @@
-#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
-
-#define instantiate_Simple_List(T)	template class Simple_List<T>;  \
-  template class Simple_List_Iterator<T>;                           \
-  instantiate_Only_List_Element(T)                                  \
-  instantiate_Sequence(T)
-
-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
-#endif
diff --git a/omegalib/omega/include/basic/Tuple.h b/omegalib/omega/include/basic/Tuple.h
deleted file mode 100644
index e9aae84..0000000
--- a/omegalib/omega/include/basic/Tuple.h
+++ /dev/null
@@ -1,336 +0,0 @@
-#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
-
-#define instantiate_Tuple(T)	template class Tuple<T>; \
-				template class Tuple_Iterator<T>; \
-				instantiate_Sequence(T)
-
-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
-#endif
diff --git a/omegalib/omega/include/basic/omega_error.h b/omegalib/omega/include/basic/omega_error.h
deleted file mode 100644
index e342efb..0000000
--- a/omegalib/omega/include/basic/omega_error.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#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
deleted file mode 100644
index 4e807cd..0000000
--- a/omegalib/omega/include/basic/util.h
+++ /dev/null
@@ -1,263 +0,0 @@
-#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
deleted file mode 100644
index 8aa2c08..0000000
--- a/omegalib/omega/include/omega.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*********************************************************************
- 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
deleted file mode 100644
index 3c11702..0000000
--- a/omegalib/omega/include/omega/RelBody.h
+++ /dev/null
@@ -1,165 +0,0 @@
-#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
deleted file mode 100644
index 5641cb3..0000000
--- a/omegalib/omega/include/omega/Rel_map.h
+++ /dev/null
@@ -1,161 +0,0 @@
-#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
deleted file mode 100644
index b41bef5..0000000
--- a/omegalib/omega/include/omega/Relation.h
+++ /dev/null
@@ -1,299 +0,0 @@
-#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
deleted file mode 100644
index 4fd81e6..0000000
--- a/omegalib/omega/include/omega/Relations.h
+++ /dev/null
@@ -1,88 +0,0 @@
-#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
deleted file mode 100644
index 67088dd..0000000
--- a/omegalib/omega/include/omega/closure.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#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
deleted file mode 100644
index a561f8c..0000000
--- a/omegalib/omega/include/omega/evac.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#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
deleted file mode 100644
index e77ed66..0000000
--- a/omegalib/omega/include/omega/farkas.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#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
deleted file mode 100644
index 928d0c6..0000000
--- a/omegalib/omega/include/omega/hull.h
+++ /dev/null
@@ -1,89 +0,0 @@
-#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
deleted file mode 100644
index e217ae9..0000000
--- a/omegalib/omega/include/omega/omega_core/debugging.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#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
deleted file mode 100644
index e4f5444..0000000
--- a/omegalib/omega/include/omega/omega_core/oc.h
+++ /dev/null
@@ -1,350 +0,0 @@
-#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
deleted file mode 100644
index 9533a40..0000000
--- a/omegalib/omega/include/omega/omega_core/oc_i.h
+++ /dev/null
@@ -1,79 +0,0 @@
-#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
deleted file mode 100644
index e5d9230..0000000
--- a/omegalib/omega/include/omega/omega_i.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#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
deleted file mode 100644
index fb3e6f0..0000000
--- a/omegalib/omega/include/omega/pres_cmpr.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#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
deleted file mode 100644
index 7b2d98d..0000000
--- a/omegalib/omega/include/omega/pres_cnstr.h
+++ /dev/null
@@ -1,192 +0,0 @@
-#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
deleted file mode 100644
index ea10a2c..0000000
--- a/omegalib/omega/include/omega/pres_conj.h
+++ /dev/null
@@ -1,299 +0,0 @@
-#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
deleted file mode 100644
index 7fec0bc..0000000
--- a/omegalib/omega/include/omega/pres_decl.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#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
deleted file mode 100644
index 93d5942..0000000
--- a/omegalib/omega/include/omega/pres_dnf.h
+++ /dev/null
@@ -1,87 +0,0 @@
-#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
deleted file mode 100644
index ed3258e..0000000
--- a/omegalib/omega/include/omega/pres_form.h
+++ /dev/null
@@ -1,112 +0,0 @@
-#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
deleted file mode 100644
index ba6a793..0000000
--- a/omegalib/omega/include/omega/pres_gen.h
+++ /dev/null
@@ -1,192 +0,0 @@
-#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
deleted file mode 100644
index 27c4553..0000000
--- a/omegalib/omega/include/omega/pres_logic.h
+++ /dev/null
@@ -1,90 +0,0 @@
-#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
deleted file mode 100644
index 98c30df..0000000
--- a/omegalib/omega/include/omega/pres_quant.h
+++ /dev/null
@@ -1,63 +0,0 @@
-#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
deleted file mode 100644
index 8a9ee92..0000000
--- a/omegalib/omega/include/omega/pres_subs.h
+++ /dev/null
@@ -1,88 +0,0 @@
-#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
deleted file mode 100644
index ad78ad0..0000000
--- a/omegalib/omega/include/omega/pres_tree.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#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
deleted file mode 100644
index bf60dcb..0000000
--- a/omegalib/omega/include/omega/pres_var.h
+++ /dev/null
@@ -1,230 +0,0 @@
-#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
deleted file mode 100644
index 76d7dee..0000000
--- a/omegalib/omega/include/omega/reach.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#if ! defined _reach_h
-#define _reach_h 1
-
-namespace omega {
-
-class reachable_information {
-public:
-	Tuple<std::string> node_names;
-	Tuple<int> node_arity;
-	DynamicArray1<Relation> start_nodes;
-	DynamicArray2<Relation> transitions;
-};
-
-
-DynamicArray1<Relation> *
-Reachable_Nodes(reachable_information * reachable_info);
-
-DynamicArray1<Relation> *
-I_Reachable_Nodes(reachable_information * reachable_info);
-
-} // namespace
-
-#endif
diff --git a/omegalib/omega/src/RelBody.cc b/omegalib/omega/src/RelBody.cc
deleted file mode 100644
index 825b153..0000000
--- a/omegalib/omega/src/RelBody.cc
+++ /dev/null
@@ -1,906 +0,0 @@
-/*****************************************************************************
- 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
deleted file mode 100644
index d9b977c..0000000
--- a/omegalib/omega/src/RelVar.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-#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
deleted file mode 100644
index 1cca43a..0000000
--- a/omegalib/omega/src/Relation.cc
+++ /dev/null
@@ -1,279 +0,0 @@
-/*****************************************************************************
- 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
deleted file mode 100644
index d7dbe86..0000000
--- a/omegalib/omega/src/Relations.cc
+++ /dev/null
@@ -1,2882 +0,0 @@
-/*****************************************************************************
- Copyright (C) 1994-2000 the Omega Project Team
- Copyright (C) 2005-2011 Chun Chen
- All Rights Reserved.
-
- Purpose:
-   Integer set and relation operations.
-
- Notes:
-
- History:
-   04/22/09 merge_rels, Chun Chen
-*****************************************************************************/
-
-#include <omega/Relation.h>
-#include <omega/Rel_map.h>
-#include <omega/pres_tree.h>
-#include <omega/pres_dnf.h>
-#include <omega/pres_conj.h>
-#include <omega/hull.h>
-#include <basic/Tuple.h>
-#include <basic/Map.h>
-#include <basic/util.h>
-#include <omega/omega_i.h>
-#if defined STUDY_EVACUATIONS
-#include <omega/evac.h>
-#endif
-#include <assert.h>
-
-namespace omega {
-
-#define CHECK_MAYBE_SUBSET 1
-
-int relation_debug=0;
-
-namespace {
-  int leave_pufs_untouched = 0;
-  Variable_ID_Tuple exists_ids; 
-  List<int> exists_numbers;
-  F_And * and_below_exists;
-}
-
-/* The following allows us to avoid warnings about passing 
-   temporaries as non-const references.  This is useful but 
-   has suddenly become illegal.  */
-
-Relation consume_and_regurgitate(NOT_CONST Relation &R) {
-  if(!R.is_null())
-    ((Relation &) R).finalize();
-  Relation S = (Relation &) R;
-  (Relation &) R = Relation::Null();
-  return S;
-}
-
-
-//
-//      r1 Union r2.
-//   align the input tuples (if any) for F and G
-//   align the output tuples (if any) for F and G
-//   match named variables in F and G
-//   formula is f | g
-//
-Relation Union(NOT_CONST Relation &input_r1, 
-               NOT_CONST Relation &input_r2) {
-  Relation r1 = consume_and_regurgitate(input_r1);
-  Relation r2 = consume_and_regurgitate(input_r2);
-  if (r1.is_null())
-    return r2;
-  else if (r2.is_null())
-    return r1;
-  if (r1.n_inp() != r2.n_inp() || r1.n_out() != r2.n_out())
-    throw std::invalid_argument("relation arity does not match");
-  
-  // skip_set_checks++;
-  // assert(r1.n_inp() == r2.n_inp());
-  // assert(r1.n_out() == r2.n_out());
-  // assert(!r1.is_null() && !r2.is_null());
-  int in = r1.n_inp(), out = r1.n_out();
-  // skip_set_checks--;
-
-  return MapAndCombineRel2(r1, r2, Mapping::Identity(in, out),
-                           Mapping::Identity(in,out), Comb_Or);
-}
-
-
-//
-//  F intersection G
-//   align the input tuples (if any) for F and G
-//   align the output tuples (if any) for F and G
-//   match named variables in F and G
-//   formula is f & g
-//
-Relation Intersection(NOT_CONST Relation &input_r1,
-                      NOT_CONST Relation &input_r2) {
-  Relation r1 = consume_and_regurgitate(input_r1);
-  Relation r2 = consume_and_regurgitate(input_r2);
-  if (r1.is_null())
-    return r2;
-  else if (r2.is_null())
-    return r1;
-  if (r1.n_inp() != r2.n_inp() || r1.n_out() != r2.n_out())
-    throw std::invalid_argument("relation arity does not match");
-
-  // skip_set_checks++;
-  // assert(r1.n_inp() == r2.n_inp());
-  // assert(r1.n_out() == r2.n_out());
-  // assert(!r1.is_null() && !r2.is_null());
-  int in = r1.n_inp(), out = r1.n_out();
-  // skip_set_checks--;
-
-  return MapAndCombineRel2(r1, r2, Mapping::Identity(in,out),
-                           Mapping::Identity(in,out), Comb_And);
-}
-
-
-//
-//  F \ G (the relation F restricted to domain G)
-//   align the input tuples for F and G
-//   match named variables in F and G
-//   formula is f & g
-//
-Relation Restrict_Domain(NOT_CONST Relation &input_r1,
-                         NOT_CONST Relation &input_r2) {
-  Relation r1 = consume_and_regurgitate(input_r1);
-  Relation r2 = consume_and_regurgitate(input_r2);
-  if (r1.is_null())
-    return r1;
-  else if (r2.is_null())
-    return r1;
-  if (r1.n_inp() != r2.n_set())
-    throw std::invalid_argument("relation arity does not match");
-
-  // assert(!r1.is_null() && !r2.is_null());
-  // skip_set_checks++;
-  // assert(r1.n_inp() == r2.n_set());
-  // assert(r2.is_set());
-  int in = r1.n_inp(), out = r1.n_out();
-  // skip_set_checks--;
-
-  int i;
-  Mapping m2(r2.n_set());
-  for(i=1; i<=r2.n_set(); i++) m2.set_map_set(i, Input_Var,i);
-
-  // skip_set_checks++;
-  assert(r2.query_guaranteed_leading_0s() == -1 &&
-         r2.query_possible_leading_0s() == -1);
-  // skip_set_checks--;
-
-  Relation result = MapAndCombineRel2(r1, r2, Mapping::Identity(in,out),
-                                      m2, Comb_And);
-  // FERD -- update leading 0's - the may close up?
-  //result.invalidate_leading_info();  // could do better
-  return result;
-}
-
-// 
-//  
-//  F / G (the relation F restricted to range G)
-//   align the output tuples for F and G
-//   match named variables in F and G
-//   formula is f & g
-//
-Relation Restrict_Range(NOT_CONST Relation &input_r1,
-                        NOT_CONST Relation &input_r2) {
-  Relation r1 = consume_and_regurgitate(input_r1);
-  Relation r2 = consume_and_regurgitate(input_r2);
-  if (r1.is_null())
-    return r1;
-  else if (r2.is_null())
-    return r1;
-  if (r1.n_out() != r2.n_set())
-    throw std::invalid_argument("relation arity does not match");
-   
-  // skip_set_checks++;
-  // assert(r1.n_out() == r2.n_set());
-  // assert(r2.is_set());
-  // assert(!r1.is_null() && !r2.is_null());
-  int in = r1.n_inp(), out = r1.n_out();
-  // skip_set_checks--;
-
-  int i;
-  Mapping m2(r2.n_set());
-  for(i=1; i<=r2.n_set(); i++) m2.set_map_set(i, Output_Var,i);
-
-  // skip_set_checks++;
-  assert(r2.query_guaranteed_leading_0s() == -1 &&
-         r2.query_possible_leading_0s() == -1);
-  // skip_set_checks--;
-
-  Relation result = MapAndCombineRel2(r1, r2, Mapping::Identity(in, out),
-                                      m2, Comb_And);
-  // FERD -- update leading 0's - the may close up?
-  // result.invalidate_leading_info();  // could do better
-  return result;
-}
-
-
-//
-// Add input variable to relation.
-//
-Relation Extend_Domain(NOT_CONST Relation &S) {
-  Relation R = consume_and_regurgitate(S);
-  if (R.is_null())
-    throw std::invalid_argument("cannot extend domain on null relation");
-  
-  // assert(!R.is_null() && (skip_set_checks || !R.is_set()));
-  // assert(!R.is_null());
-  Rel_Body *r = R.split();
-  r->In_Names.append(Const_String());
-  r->number_input++;
-  assert(!r->is_null());
-
-  if (r->number_input <= r->number_output)
-    R.invalidate_leading_info(r->number_input);
-
-  return R;
-}
-
-//
-// Add more input variables to relation.
-//
-Relation Extend_Domain(NOT_CONST Relation &S, int more) {
-  Relation R = consume_and_regurgitate(S);
-  if (R.is_null())
-    throw std::invalid_argument("cannot extend domain on null relation");
-  
-  // assert(!R.is_null());
-  R.split();
-  for (int i=1; i<=more; i++) R = Extend_Domain(R);
-  return R;
-}
-
-
-//
-// Add output variable to relation.
-//
-Relation Extend_Range(NOT_CONST Relation &S) {
-  Relation R = consume_and_regurgitate(S);
-  if (R.is_null())
-    throw std::invalid_argument("cannot extend range on null relation");
-
-  // assert(!R.is_null() && !R.is_set());
-  // assert(!R.is_null());
-  Rel_Body *r = R.split();
-  r->Out_Names.append(Const_String());
-  r->number_output++;
-  assert(!r->is_null());
-
-  if (r->number_output <= r->number_input)
-    R.invalidate_leading_info(r->number_output);
-
-  return R;
-}
-
-//
-// Add more output variables to relation.
-//
-Relation Extend_Range(NOT_CONST Relation &S, int more) {
-  Relation R = consume_and_regurgitate(S);
-
-  // assert(!R.is_null());
-  R.split();
-  for (int i=1; i<=more; i++) R = Extend_Range(R);
-  return R;
-}
-
-
-//
-// Add set variable to set.
-//
-Relation Extend_Set(NOT_CONST Relation &S) {
-  Relation R = consume_and_regurgitate(S);
-  if (R.is_null())
-    throw std::invalid_argument("cannot extend set on null relation");
-  if (R.n_out() > 0)
-    throw std::invalid_argument("relation must be a set");
-    
-  // assert(!R.is_null() && R.is_set());
-  Rel_Body *r = R.split();
-  r->In_Names.append(Const_String());
-  r->number_input++;
-  assert(!r->is_null());
-  return R;
-}
-
-//
-// Add more variables to set
-//
-Relation Extend_Set(NOT_CONST Relation &S, int more) {
-  Relation R = consume_and_regurgitate(S);
-  R.split();
-  for (int i=1; i<=more; i++) R = Extend_Set(R);
-  return R;
-}
-
-
-
-//
-// Domain and Range.
-// Make output (input) variables wildcards and simplify.
-// Move all UFS's to have have the remaining tuple as an argument,
-//   and maprel will move them to the set tuple
-// RESET all leading 0's
-//
-Relation Domain(NOT_CONST Relation &S) {
-  Relation r = consume_and_regurgitate(S);
-  if (r.is_null())
-    return r;
-  
-  // assert(!S.is_null());
-  // assert(!r.is_set());
-  // skip_set_checks++;
-  int i;
-  Mapping m1(r.n_inp(), r.n_out());
-  for(i=1; i<=r.n_inp(); i++) m1.set_map_in (i, Set_Var,i);
-  for(i=1; i<=r.n_out(); i++) m1.set_map_out(i, Exists_Var,i);
-  // skip_set_checks--;
-
-  int a = r.max_ufs_arity_of_out();
-  if (a > 0) {
-    // UFS's must evacuate from the output tuple
-    Variable_ID_Tuple remapped;
-
-    r.simplify();
-    DNF *d = r.split()->DNFize();
-    d->count_leading_0s();
-    // Any conjucts with leading_0s == -1 must have >= "a" leading 0s
-    // What a gross way to do this. Ferd
-
-    for (DNF_Iterator conj(d); conj; conj++) {
-#if defined STUDY_EVACUATIONS
-      study_evacuation(*conj, out_to_in, a);
-#endif
-
-      int cL0 = (*conj)->guaranteed_leading_0s;
-
-      for (Variable_ID_Iterator func((*conj)->mappedVars); func; func++)
-        if ((*func)->kind() == Global_Var) {
-          Global_Var_ID f = (*func)->get_global_var();
-          if (f->arity() > 0 && (*func)->function_of()==Output_Tuple) {
-            if (cL0 >= f->arity()) {
-              (*func)->remap = r.get_local(f, Input_Tuple);
-            }
-            else {
-              (*func)->remap = (*conj)->declare();
-              (*conj)->make_inexact();
-            }
-            remapped.append(*func);
-          }
-        }
-      (*conj)->remap();
-      reset_remap_field(remapped);
-      remapped.clear();
-     
-      (*conj)->guaranteed_leading_0s =  (*conj)->possible_leading_0s = -1;
-      (*conj)->leading_dir = 0;
-    }
-  }
-
-  MapRel1(r, m1, Comb_Id); //  this invalidates leading0s
-  assert(r.is_set() || m1.n_in() == 0);  // MapRel can't tell to make a set
-  r.markAsSet();                         // if there were no inputs.      
-
-  // skip_set_checks++;
-  assert(r.query_guaranteed_leading_0s() == -1 && r.query_possible_leading_0s() == -1);
-  // skip_set_checks--;
-
-  return r;
-}
-
-
-Relation Range(NOT_CONST Relation &S) {
-  Relation r = consume_and_regurgitate(S);
-  if (r.is_null())
-    return r;
-  
-  //assert(!r.is_null());
-  // skip_set_checks++;
-
-  int i;
-  Mapping m1(r.n_inp(), r.n_out());
-  for(i=1; i<=r.n_inp(); i++) m1.set_map_in (i, Exists_Var,i);
-  for(i=1; i<=r.n_out(); i++) m1.set_map_out(i, Set_Var,i);
-  // skip_set_checks--;
-
-  int a = r.max_ufs_arity_of_in();
-  if (a > 0) {
-    // UFS's must evacuate from the input tuple
-    Variable_ID_Tuple remapped;
-
-    r.simplify();
-    DNF *d = r.split()->DNFize();
-    d->count_leading_0s();
-    // Any conjucts with leading_0s == -1 must have >= "a" leading 0s
-    // What a gross way to do this. Ferd
-
-    for (DNF_Iterator conj(d); conj; conj++) {
-#if defined STUDY_EVACUATIONS
-      study_evacuation(*conj, in_to_out, a);
-#endif
-
-      int cL0 = (*conj)->guaranteed_leading_0s;
-      for (Variable_ID_Iterator func((*conj)->mappedVars); func; func++)
-        if ((*func)->kind() == Global_Var) {
-          Global_Var_ID f = (*func)->get_global_var();
-          if (f->arity() > 0 && (*func)->function_of()==Input_Tuple) {
-            if (cL0 >= f->arity()) {
-              (*func)->remap = r.get_local(f, Output_Tuple);
-            }
-            else {
-              (*func)->remap = (*conj)->declare();
-              (*conj)->make_inexact();
-            }
-            remapped.append(*func);
-          }
-        }
-      (*conj)->remap();
-      reset_remap_field(remapped);
-      remapped.clear();
-
-      (*conj)->guaranteed_leading_0s =  (*conj)->possible_leading_0s = -1;
-      (*conj)->leading_dir = 0;
-    }
-  }
-
-  MapRel1(r, m1, Comb_Id); // this invalidates leading0s
-  assert(r.is_set() || m1.n_out() == 0); // MapRel can't tell to make a set
-  r.markAsSet();                        // if there were no outputs.
-
-  // skip_set_checks++;
-  assert(r.query_guaranteed_leading_0s() == -1 && r.query_possible_leading_0s() == -1);
-  // skip_set_checks--;
-
-  return r;
-}
-
-
-//
-// Cross Product.  Give two sets, A and B, create a relation whose
-// domain is A and whose range is B.
-//
-Relation Cross_Product(NOT_CONST Relation &input_A,
-                       NOT_CONST Relation &input_B) {
-  Relation A = consume_and_regurgitate(input_A);
-  Relation B = consume_and_regurgitate(input_B);
-  if (A.is_null() || B.is_null())
-    throw std::invalid_argument("null relation");
-  if (!A.is_set() || !B.is_set())
-    throw std::invalid_argument("cross product must be on two set");
-  
-  // assert(A.is_set());
-  // assert(B.is_set());
-
-  // skip_set_checks++;
-  assert(A.query_guaranteed_leading_0s() == -1 &&
-         A.query_possible_leading_0s() == -1);
-  assert(B.query_guaranteed_leading_0s() == -1 &&
-         B.query_possible_leading_0s() == -1);
-  // skip_set_checks--;
-
-  Mapping mA(A.n_set());
-  Mapping mB(B.n_set()); 
-  int i;
-  for(i = 1; i <= B.n_set(); i++) mB.set_map_set(i, Output_Var,i);
-  for(i = 1; i <= A.n_set(); i++) mA.set_map_set(i, Input_Var,i);
-  return MapAndCombineRel2(A, B, mA, mB, Comb_And);
-}
-
-
-//
-//  inverse F
-//   reverse the input and output tuples
-//
-Relation Inverse(NOT_CONST Relation &S) {
-  Relation r = consume_and_regurgitate(S);
-  if (r.is_null())
-    return r;
-    
-  // assert(!r.is_null());
-  // assert(!r.is_set());
-  int i;
-
-  Mapping m1(r.n_inp(), r.n_out());
-  for(i=1; i<=r.n_inp(); i++) m1.set_map_in (i, Output_Var,i);
-  for(i=1; i<=r.n_out(); i++) m1.set_map_out(i, Input_Var,i);
-
-  MapRel1(r, m1, Comb_Id, -1, -1, false);
-
-  r.reverse_leading_dir_info();
-
-  return r;
-}
-
-Relation After(NOT_CONST Relation &input_S,
-               int carried_by, int new_output,int dir) {
-  Relation S = consume_and_regurgitate(input_S);
-  assert(!S.is_null());
-  assert(!S.is_set());
-  int i;
-  Relation r(*S.split(),42);
-
-  int a = r.max_ufs_arity_of_out();
-  int preserved_positions = min(carried_by-1,new_output);
-  if (a >= preserved_positions) {
-    // UFS's must evacuate from the output tuple
-    Variable_ID_Tuple remapped;
-
-    r.simplify();
-    DNF *d = r.split()->DNFize();
-    d->count_leading_0s();
-    // Any conjucts with leading_0s == -1 must have >= "a" leading 0s
-    // What a gross way to do this. Ferd
-
-    for (DNF_Iterator conj(d); conj; conj++) {
-      int cL0 = (*conj)->guaranteed_leading_0s;
-
-      for (Variable_ID_Iterator func((*conj)->mappedVars); func; func++)
-        if ((*func)->kind() == Global_Var) {
-          Global_Var_ID f = (*func)->get_global_var();
-          if (f->arity() > preserved_positions 
-              && (*func)->function_of()==Output_Tuple) {
-            if (cL0 >= f->arity()) {
-              (*func)->remap = r.get_local(f, Input_Tuple);
-            }
-            else {
-              (*func)->remap = (*conj)->declare();
-              (*conj)->make_inexact();
-            }
-            remapped.append(*func);
-          }
-        }
-      (*conj)->remap();
-      reset_remap_field(remapped);
-      remapped.clear();
-     
-      (*conj)->guaranteed_leading_0s =  
-        (*conj)->possible_leading_0s = -1;
-      (*conj)->leading_dir = 0;
-    }
-  }
-
-  Mapping m1(r.n_inp(), r.n_out());
-  for(i=1; i<=r.n_inp(); i++) m1.set_map_in (i, Input_Var,i);
-  if (carried_by > new_output) {
-    int preserve = min(new_output,r.n_out());
-    for(i=1; i<=preserve; i++) m1.set_map_out(i, Output_Var,i);
-    for(i=preserve+1; i<=r.n_out(); i++) m1.set_map_out(i, Exists_Var,-1);
-    MapRel1(r, m1, Comb_Id, -1, -1, true);
-    if (new_output > preserve)
-      r = Extend_Range(r,new_output-r.n_out());
-    return r;
-  }
-
-  for(i=1; i<carried_by; i++) m1.set_map_out(i, Output_Var,i);
-  m1.set_map_out(carried_by, Exists_Var,1);
-  for(i=carried_by+1; i<=r.n_out(); i++) m1.set_map_out(i, Exists_Var,-1);
-
-  MapRel1(r, m1, Comb_Id, -1, -1, true,false);
-
-  Rel_Body *body = r.split();
-  body->Out_Names.append(Const_String());
-  body->number_output++;
-  assert(body->n_out() <= input_vars.size());
-
-
-  GEQ_Handle h = and_below_exists->add_GEQ(0);
-  assert(carried_by < 128);
-  h.update_coef(exists_ids[1],-dir);
-  h.update_coef(r.output_var(carried_by),dir);
-  h.update_const(-1);
-  h.finalize();
-  r.finalize();
-  if (new_output > r.n_out())
-    r = Extend_Range(r,new_output-r.n_out());
-  return r;
-}
-
-//
-// Identity.
-//
-Relation Identity(int n_inp) {
-  Relation rr(n_inp, n_inp);
-  F_And *f = rr.add_and();
-  for(int i=1; i<=n_inp; i++) {
-    EQ_Handle e = f->add_EQ();
-    e.update_coef(rr.input_var(i), -1);
-    e.update_coef(rr.output_var(i), 1);
-    e.finalize();
-  }
-  rr.finalize();
-  assert(!rr.is_null());
-  return rr;
-}
-
-Relation Identity(NOT_CONST Relation &input_r) {
-  Relation   r = consume_and_regurgitate(input_r);
-  return Restrict_Domain(Identity(r.n_set()),r);
-}
-
-//
-// Deltas(F)
-//   Return a set such that the ith variable is old Out_i - In_i
-//   Delta variables are created as input variables.
-//   Then input and output variables are projected out.
-//
-Relation Deltas(NOT_CONST Relation &S) {
-  Relation R = consume_and_regurgitate(S);
-  assert(!R.is_null());
-  // skip_set_checks++;
-  assert(R.n_inp()==R.n_out());
-  int in = R.n_inp();
-  // skip_set_checks--;
-  return Deltas(R,in);
-}
-
-Relation Deltas(NOT_CONST Relation &S, int eq_no) {
-  Relation R = consume_and_regurgitate(S);
-  // skip_set_checks++;
-  assert(!R.is_null());
-  assert(eq_no<=R.n_inp());
-  assert(eq_no<=R.n_out());
-  // R.split();
-
-  int no_inp = R.n_inp();
-  int no_out = R.n_out();
-
-  if(relation_debug) {
-    fprintf(DebugFile,"Computing Deltas:\n");
-    R.prefix_print(DebugFile);
-  }
-  int a = R.max_ufs_arity();
-  if (a > 0) {
-    Variable_ID_Tuple remapped;
-      
-    // UFS's must evacuate from all tuples - we need to go to DNF
-    // to enumerate the variables, I think...
-    R.simplify();
-    if(relation_debug) {
-      fprintf(DebugFile,"Relation simplified:\n");
-      R.prefix_print(DebugFile);
-    }
-    DNF *d = R.split()->DNFize();
-
-    for (DNF_Iterator conj(d); conj; conj++) {
-      for (Variable_ID_Iterator func((*conj)->mappedVars); func; func++)
-        if ((*func)->kind() == Global_Var) {
-          Global_Var_ID f = (*func)->get_global_var();
-          if (f->arity() > 0) {
-            (*func)->remap = (*conj)->declare();
-            (*conj)->make_inexact();
-            remapped.append(*func);
-          }
-        }
-      (*conj)->remap();
-      reset_remap_field(remapped);
-      remapped.clear();
-    }
-  }
-
-  R = Extend_Domain(R, eq_no);                // add eq_no Delta vars
-  Mapping M(no_inp+eq_no, no_out);
-  int i;
-  for(i=1; i<=eq_no; i++) {          // Set up Deltas equalities
-    EQ_Handle E = R.and_with_EQ();
-    /* delta_i - w_i + r_i = 0 */
-    E.update_coef(R.input_var(i), 1);
-    E.update_coef(R.output_var(i), -1);
-    E.update_coef(R.input_var(no_inp+i), 1);
-    E.finalize();
-    M.set_map(Input_Var, no_inp+i, Set_Var, i);  // Result will be a set
-  }
-  for(i=1; i<=no_inp; i++) {          // project out input variables
-    M.set_map(Input_Var, i, Exists_Var, i);
-  }
-  for(i=1; i<=no_out; i++) {          // project out output variables
-    M.set_map(Output_Var, i, Exists_Var, no_inp+i);
-  }
-  MapRel1(R, M, Comb_Id, eq_no, 0);
-
-  if(relation_debug) {
-    fprintf(DebugFile,"Computing deltas:\n");
-    R.prefix_print(DebugFile);
-  };
-  R.finalize();
-  assert(R.is_set());  // Should be since we map things to Set_Var
-  assert(R.n_set() == eq_no);
-  // skip_set_checks--;
-  return R;
-}
-
-
-
-
-Relation DeltasToRelation(NOT_CONST Relation &D, int n_inputs, int n_outputs) {
-  Relation R = consume_and_regurgitate(D);
-
-  // skip_set_checks++;
-  assert(!R.is_null());
-  R.markAsRelation();
-  int common = R.n_inp();
-  assert(common <= n_inputs);
-  assert(common <= n_outputs);
-  R.split();
-
-  if (R.max_ufs_arity() > 0) {
-    assert(R.max_ufs_arity() == 0 &&
-           "'Deltas' not ready for UFS yet"); // FERD
-    fprintf(stderr, "'Deltas' not ready for UFS yet");
-    exit(1);
-  }
-
-  R = Extend_Domain(R, n_inputs);
-  R = Extend_Range(R, n_outputs);
-  Mapping M(common+n_inputs, n_outputs);
-  int i;
-  for(i=1; i<=common; i++) {          // Set up Deltas equalities
-    EQ_Handle E = R.and_with_EQ();
-    /* delta_i - w_i + r_i = 0 */
-    E.update_coef(R.input_var(i), 1);
-    E.update_coef(R.output_var(i), -1);
-    E.update_coef(R.input_var(common+i), 1);
-    E.finalize();
-    M.set_map(Input_Var, i, Exists_Var, i);  // Result will be a set
-  }
-  for(i=1; i<=n_inputs; i++) {           // project out input variables
-    M.set_map(Input_Var, common+i, Input_Var, i);
-  }
-  for(i=1; i<=n_outputs; i++) {          // project out output variables
-    M.set_map(Output_Var, i, Output_Var, i);
-  }
-  MapRel1(R, M, Comb_Id, n_inputs, n_outputs);
-
-  if(relation_debug) {
-    fprintf(DebugFile,"Computed DeltasToRelation:\n");
-    R.prefix_print(DebugFile);
-  }
-  R.finalize();
-  assert(!R.is_set());
-  // skip_set_checks--;
-  return R;
-}
-
-
-
-Relation Join(NOT_CONST Relation &G, NOT_CONST Relation &F) {
-  return Composition(F, G);
-}
-
-bool prepare_relations_for_composition(Relation &r1,Relation &r2) {
-  assert(!r2.is_null() && !r1.is_null());
-
-  if(r2.is_set()) {
-    int a1 = r1.max_ufs_arity_of_in(), a2 = r2.max_ufs_arity_of_set();
-
-    if (a1 == 0 && a2 == 0)
-      return true;
-    else {
-      assert(0 && "Can't compose relation and set with function symbols");
-      fprintf(stderr, "Can't compose relation and set with function symbols");
-      exit(1);
-      return false;  // make compiler shut up
-    }
-  }
-
-  assert(r2.n_out() == r1.n_inp());
-
-  int zeros = max(r1.query_guaranteed_leading_0s(),
-                  r2.query_guaranteed_leading_0s());
-  return (zeros >= r1.max_ufs_arity_of_in()
-          && zeros >= r2.max_ufs_arity_of_out());
-}
-
-//
-// Composition(F, G) = F o G, where F o G (x) = F(G(x))
-//   That is, if F = { [i] -> [j] : ... }
-//    and G = { [x] -> [y] : ... }
-//          then Composition(F, G) = { [x] -> [j] : ... }
-//
-//  align the output tuple for G and the input tuple for F,
-//   these become existensially quantified variables
-//  use the output tuple from F and the input tuple from G for the result
-//  match named variables in G and F
-//  formula is g & f
-//
-// If there are function symbols of arity > 0, we call special case
-// code to handle them.  This is not set up for the r2.is_set case yet.
-//
-
-Relation Composition(NOT_CONST Relation &input_r1, NOT_CONST Relation &input_r2) {
-  Relation r1 = consume_and_regurgitate(input_r1);
-  Relation r2 = consume_and_regurgitate(input_r2);
-  assert(!r2.is_null() && !r1.is_null());
-
-  if(r2.is_set()) {
-    int a1 = r1.max_ufs_arity_of_in(), a2 = r2.max_ufs_arity_of_set();
-    if (r2.n_set() != r1.n_inp()) {
-      fprintf(stderr,"Illegal composition/application, arities don't match\n");
-      fprintf(stderr,"Trying to compute r1(r2)\n");
-      fprintf(stderr,"arity of r2 must match input arity of r1\n");
-      fprintf(stderr,"r1: ");
-      r1.print_with_subs(stderr);
-      fprintf(stderr,"r2: ");
-      r2.print_with_subs(stderr);
-      fprintf(stderr,"\n");
-      assert(r2.n_set() == r1.n_inp());
-      exit(1);
-    }
-    // skip_set_checks++;
-    int i;
-    if (a1 == 0 && a2 == 0) {
-      int x = r1.n_out();
-      Mapping m1(r1.n_inp(), r1.n_out());
-      for(i=1; i<=r1.n_out(); i++) m1.set_map_out(i, Set_Var,i);
-      for(i=1; i<=r1.n_inp(); i++) m1.set_map_in (i, Exists_Var,i);
-      Mapping m2(r2.n_set());
-      for(i=1; i<=r2.n_set(); i++) m2.set_map_set(i, Exists_Var,i);
-      Relation R3 = MapAndCombineRel2(r2, r1, m2, m1, Comb_And);
-      // skip_set_checks--;
-      if (x == 0)
-        R3.markAsSet();
-      return R3;
-    }
-    else {
-      assert(0 &&
-             "Can't compose relation and set with function symbols");
-      fprintf(stderr,
-              "Can't compose relation and set with function symbols");
-      exit(1);
-      return Identity(0);  // make compiler shut up
-    }
-  }
-
-  if (r2.n_out() != r1.n_inp()) {
-    fprintf(stderr,"Illegal composition, arities don't match\n");
-    fprintf(stderr,"Trying to compute r1 compose r2\n");
-    fprintf(stderr,"Output arity of r2 must match input arity of r1\n");
-    fprintf(stderr,"r1: ");
-    r1.print_with_subs(stderr);
-    fprintf(stderr,"r2: ");
-    r2.print_with_subs(stderr);
-    fprintf(stderr,"\n");
-    assert(r2.n_out() == r1.n_inp());
-    exit(1);
-  }
-
-  int a1 = r1.max_ufs_arity_of_in(), a2 = r2.max_ufs_arity_of_out();
-
-  if (a1 == 0 && a2 == 0 && 0 /* FERD - leading 0's go wrong here */ ) {
-    // If no real UFS's, we can just use the general code:
-    int i;
-    Mapping m1(r1.n_inp(), r1.n_out());
-    for(i=1; i<=r1.n_inp(); i++) m1.set_map_in (i, Exists_Var,i);
-    for(i=1; i<=r1.n_out(); i++) m1.set_map_out(i, Output_Var,i);
-    Mapping m2(r2.n_inp(), r2.n_out());
-    for(i=1; i<=r2.n_inp(); i++) m2.set_map_in (i, Input_Var,i);
-    for(i=1; i<=r2.n_out(); i++) m2.set_map_out(i, Exists_Var,i);
-
-    return MapAndCombineRel2(r2, r1, m2, m1, Comb_And);
-  }
-  else {
-    Relation result(r2.n_inp(), r1.n_out());
-    int mid_size = r2.n_out();
-    int i;
-    for(i =1; i<=r2.n_inp(); i++)
-      result.name_input_var(i,r2.input_var(i)->base_name);
-    for(i =1; i<=r1.n_out(); i++)
-      result.name_output_var(i,r1.output_var(i)->base_name);
-
-    r1.simplify();
-    r2.simplify();
-
-    Rel_Body *b1 = r1.split(), *b2 = r2.split();
-
-    if (b1 == b2) {
-      assert(0 && "Compose: not ready to handle b1 == b2 yet.");
-      fprintf(stderr, "Compose: not ready to handle b1 == b2 yet.\n");
-      exit(1);
-    }
-
-    DNF *d1 = b1->DNFize();
-    DNF *d2 = b2->DNFize();
-      
-    d1->count_leading_0s();
-    d2->count_leading_0s();
-    // Any conjucts with leading_0s == -1 must have >= max_arity leading 0s
-    // What a gross way to do this.  Ferd
-
-    F_Exists *exists = result.add_exists();
-    Section<Variable_ID> middle_tuple = exists->declare_tuple(mid_size);
-    Map<Global_Var_ID, Variable_ID> lost_functions((Variable_ID)0);
-
-    F_Or *result_conjs = exists->add_or();
-
-    for (DNF_Iterator conj1(d1); conj1; conj1++)
-      for (DNF_Iterator conj2(d2); conj2; conj2++) {
-        // combine conj1 and conj2:
-        //   conj2's in becomes result's in; conj1's out becomes out
-        //   conj2's out and conj1's in get merged and exist. quant.
-        //   conj2's f(in) and conj1's f(out) become f(in) and f(out)
-        //   conj2's f(out) and conj1's f(in) get merged, evacuate:
-        //     if conj1 has f.arity leading 0s, they become f(out),
-        //     if conj2 has f.arity leading 0s, they become f(in)
-        //     if neither has enough 0s, they become a wildcard
-        //                               and the result is inexact
-        //   old wildcards stay wildcards
-
-#if defined STUDY_EVACUATIONS
-        study_evacuation(*conj1, *conj2, max(a1, a2));
-#endif
-
-        Conjunct *copy1, *copy2;
-        copy2 = (*conj2)->copy_conj_same_relation();
-        copy1 = (*conj1)->copy_conj_same_relation();
-
-        Variable_ID_Tuple remapped;
-
-        int c1L0 = copy1->guaranteed_leading_0s;
-        int c2L0 = copy2->guaranteed_leading_0s;
-
-        int inexact = 0;
-
-        // get rid of conj2's f(out)
-        {
-          for (Variable_ID_Iterator func(copy2->mappedVars); func; func++)
-            if ((*func)->kind() == Global_Var) {
-              Global_Var_ID f = (*func)->get_global_var();
-              if (f->arity() > 0 && (*func)->function_of()==Output_Tuple) {
-                if (c2L0 >= f->arity()) {
-                  (*func)->remap = r2.get_local(f, Input_Tuple);
-                  remapped.append(*func);
-                }
-                else if (c1L0 >= f->arity()) {
-                  // f->remap = copy1->get_local(f, Output_Tuple);
-                  // this should work with the current impl.
-                  // SHOULD BE A NO-OP?
-                  assert((*func)==r1.get_local(f,Output_Tuple));
-                }
-                else {
-                  Variable_ID f_quantified = lost_functions[f];
-                  if (!f_quantified) {
-                    f_quantified = exists->declare();
-                    lost_functions[f] = f_quantified;
-                  }
-                  inexact = 1;
-                  (*func)->remap = f_quantified;
-                  remapped.append(*func);
-                }
-              }
-            }     
-        }
-
-        // remap copy2's out
-        for (i=1; i<=mid_size; i++) {
-          r2.output_var(i)->remap = middle_tuple[i];
-        }
-
-        // do remapping for conj2, then reset everything so
-        // we can go on with conj1
-
-        copy2->remap();
-        reset_remap_field(remapped);
-        reset_remap_field(output_vars,mid_size);
-
-
-        remapped.clear();
-
-        // get rid of conj1's f(in)
-        {
-          for (Variable_ID_Iterator func(copy1->mappedVars); func; func++)
-            if ((*func)->kind() == Global_Var) {
-              Global_Var_ID f = (*func)->get_global_var();
-              if (f->arity() > 0 && (*func)->function_of()==Input_Tuple) {
-                if (c1L0 >= f->arity()) {
-                  (*func)->remap = r1.get_local(f,Output_Tuple);
-                  remapped.append(*func);
-                }
-                else if (c2L0 >= f->arity()) {
-                  // f->remap = copy2->get_local(f, Input_Tuple);
-                  // this should work with the current impl.
-                  // SHOULD BE A NO-OP?
-                  assert((*func)==r2.get_local(f,Input_Tuple));
-                }
-                else {
-                  Variable_ID f_quantified = lost_functions[f];
-                  if (!f_quantified) {
-                    f_quantified = exists->declare();
-                    lost_functions[f] = f_quantified;
-                  }
-                  inexact = 1;
-                  (*func)->remap = f_quantified;
-                  remapped.append(*func);
-                }
-              }
-            }      
-        }
-
-        // merge copy1's in with the already remapped copy2's out
-        for (i=1; i<=mid_size; i++) {
-          r1.input_var(i)->remap = middle_tuple[i];
-        }
-
-        copy1->remap();
-        reset_remap_field(remapped);
-        reset_remap_field(input_vars,mid_size);
-
-        Conjunct *conj3 = merge_conjs(copy1, copy2, MERGE_COMPOSE, exists->relation());
-        result_conjs->add_child(conj3);
-        delete copy1;
-        delete copy2;
-
-        // make sure all variables used in the conjunct
-        // are listed in the "result" relation
-
-        for (Variable_ID_Iterator func(conj3->mappedVars); func; func++)
-          if ((*func)->kind() == Global_Var) {
-            Global_Var_ID f = (*func)->get_global_var();
-            if (f->arity() > 0)
-              result.get_local(f, (*func)->function_of());
-            else
-              result.get_local(f);
-          }
-
-        if (inexact)
-          conj3->make_inexact();
-      }
-
-    // result.simplify(2, 4);  // can't really do that now, will cause failure in chill
-    result.finalize();
-    r1 = r2 = Relation();
-    return result;
-  }
-}
-
-
-
-bool Is_Obvious_Subset(NOT_CONST Relation &input_r1, NOT_CONST Relation &input_r2) {
-  Relation r1 = consume_and_regurgitate(input_r1);
-  Relation r2 = consume_and_regurgitate(input_r2);
-
-  assert(!r1.is_null() && !r2.is_null());
-  Rel_Body *rr1 = r1.split();
-  Rel_Body *rr2 = r2.split();
-  rr1->simplify();
-  rr2->simplify();
-  use_ugly_names++;
-
-  remap_DNF_vars(rr2, rr1);
-
-  for(DNF_Iterator pd1(rr1->query_DNF()); pd1.live(); pd1.next()) {
-    Conjunct *conj1 = pd1.curr();
-    int found = false;
-    for(DNF_Iterator pd2(rr2->query_DNF()); pd2.live(); pd2.next()) {
-      Conjunct *conj2 = pd2.curr();
-      if (!conj2->is_exact()) continue;
-    
-      Conjunct *cgist = merge_conjs(conj1, conj2, MERGE_GIST, conj2->relation());
-#ifndef NDEBUG
-      cgist->setup_names();
-#endif
-      if (cgist->redSimplifyProblem(2, 0) == noRed) {
-        delete cgist;
-        found = true;
-        break;
-      }
-      delete cgist;
-    }
-    if (! found)  {
-      use_ugly_names--;
-      r1 = r2 = Relation();
-      return false;
-    }
-  }
-  use_ugly_names--;
-  r1 = r2 = Relation();
-  return true;
-} /* Is_Obvious_Subset */
-
-
-bool do_subset_check(NOT_CONST Relation &input_r1,
-                     NOT_CONST Relation &input_r2);
-
-// do_subset_check really implements Must_Be_Subset anyway (due to 
-// correct handling of inexactness in the negation code), but
-// still take upper and lower bounds here
-bool Must_Be_Subset(NOT_CONST Relation &r1, NOT_CONST Relation &r2) {
-  Relation s1 = Upper_Bound(consume_and_regurgitate(r1));
-  Relation s2 = Lower_Bound(consume_and_regurgitate(r2));
-  return do_subset_check(s1,s2);
-}
-
-bool Might_Be_Subset(NOT_CONST Relation &r1, NOT_CONST Relation &r2) {
-  Relation s1 = Lower_Bound(consume_and_regurgitate(r1));
-  Relation s2 = Upper_Bound(consume_and_regurgitate(r2));
-  return do_subset_check(s1,s2);
-}
-
-bool May_Be_Subset(NOT_CONST Relation &r1, NOT_CONST Relation &r2){
-  return Might_Be_Subset(r1,r2);
-}
-
-
-
-
-//
-// F Must_Be_Subset G
-// Test that (f => g) === (~f | g) is a Tautology
-// or that (f & ~g) is unsatisfiable:
-//  align the input tuples (if any) for F and G
-//  align the output tuples (if any) for F and G
-// Special case: if r2 has a single conjunct then use HasRedQeuations.
-// 
-
-bool do_subset_check(NOT_CONST Relation &input_r1,
-                     NOT_CONST Relation &input_r2) {
-  Relation r1 = consume_and_regurgitate(input_r1);
-  Relation r2 = consume_and_regurgitate(input_r2);
-  if (r1.is_null() || r2.is_null())
-    throw std::invalid_argument("null relation");
-  if (r1.n_inp() != r2.n_inp() || r1.n_out() != r2.n_out())
-    throw std::invalid_argument("relation arity does not match");
-  
-  // assert(!r1.is_null() && !r2.is_null());
-  // skip_set_checks++;
-  // assert(r1.n_inp() == r2.n_inp());
-  // assert(r1.n_out() == r2.n_out());
-  // skip_set_checks--;
-  r1.simplify(1,0);
-  r2.simplify(2,2);
-  Rel_Body *rr1 = r1.split();
-
-  if(relation_debug) {
-    fprintf(DebugFile, "\n$$$ Must_Be_Subset IN $$$\n");
-  }
-
-  bool c = true;
-
-  // Check each conjunct separately
-  for(DNF_Iterator pd(rr1->query_DNF()); c &&  pd.live(); ) {
-    Relation tmp(r1,pd.curr());
-    pd.next();
-#ifndef CHECK_MAYBE_SUBSET
-    if (pd.live())
-      c = !Difference(tmp,copy(r2)).is_upper_bound_satisfiable();
-    else 
-      c = !Difference(tmp,r2).is_upper_bound_satisfiable();
-#else
-    Relation d=Difference(copy(tmp), copy(r2));
-    c=!d.is_upper_bound_satisfiable();
-    if (!c && !d.is_exact()) { // negation-induced inexactness
-      static int OMEGA_WHINGE = -1;
-      if (OMEGA_WHINGE < 0) {
-        OMEGA_WHINGE = getenv("OMEGA_WHINGE") ? atoi(getenv("OMEGA_WHINGE")) : 0;
-      }
-      if (OMEGA_WHINGE) {
-        fprintf(DebugFile,"\n===== r1 is maybe a Must_Be_Subset of r2 ========\n");
-        fprintf(DebugFile,"-------> r1:\n");
-        tmp.print_with_subs(DebugFile);
-        fprintf(DebugFile,"-------> r2:\n");
-        r2.print_with_subs(DebugFile);
-        fprintf(DebugFile,"-------> r1-r2:\n");
-        d.print_with_subs(DebugFile);
-      }
-    }
-#endif         
-  }
-
-  if(relation_debug) {
-    fprintf(DebugFile, "$$$ Must_Be_Subset OUT $$$\n");
-  }
-  r1 = r2 = Relation();
-  return c;
-}
-
-
-//
-//  F minus G
-//
-Relation Difference(NOT_CONST Relation &input_r1,
-                    NOT_CONST Relation &input_r2) {
-  Relation r1 = consume_and_regurgitate(input_r1);
-  Relation r2 = consume_and_regurgitate(input_r2);
-  if (r1.is_null() || r2.is_null())
-    return r1;
-  if (r1.n_inp() != r2.n_inp() || r1.n_out() != r2.n_out())
-    throw std::invalid_argument("relation arity does not match");
-  
-  //assert(!r1.is_null() && !r2.is_null());
-  // skip_set_checks++;
-  // assert(r1.n_inp() == r2.n_inp());
-  // assert(r1.n_out() == r2.n_out());
-
-  int i;
-  Mapping m1(r1.n_inp(), r1.n_out());
-  for(i=1; i<=r1.n_inp(); i++) m1.set_map_in (i, Input_Var,i);
-  for(i=1; i<=r1.n_out(); i++) m1.set_map_out(i, Output_Var,i);
-  Mapping m2(r2.n_inp(), r2.n_out());
-  for(i=1; i<=r2.n_inp(); i++) m2.set_map_in (i, Input_Var,i);
-  for(i=1; i<=r2.n_out(); i++) m2.set_map_out(i, Output_Var,i);
-  // skip_set_checks--;
-
-  return MapAndCombineRel2(r1, r2, m1, m2, Comb_AndNot);
-}
-
-//
-//  complement F
-//   not F
-//
-Relation Complement(NOT_CONST Relation &S) {
-  Relation r = consume_and_regurgitate(S);
-  if (r.is_null())
-    return r;
-  
-  // assert(!r.is_null());
-  // skip_set_checks++;  
-  int i;
-  Mapping m(r.n_inp(), r.n_out());
-  for(i=1; i<=r.n_inp(); i++) m.set_map_in (i, Input_Var,i);
-  for(i=1; i<=r.n_out(); i++) m.set_map_out(i, Output_Var,i);
-  // skip_set_checks--;
-
-  MapRel1(r, m, Comb_AndNot, -1, -1, false);
-  return r;
-}
-
-
-//
-// Compute (gist r1 given r2).
-// Currently we assume that r2 has only one conjunct.
-// r2 may have zero input and output OR may have # in/out vars equal to r1.
-//
-Relation GistSingleConjunct(NOT_CONST Relation &input_R1,
-                            NOT_CONST Relation &input_R2, int effort) {
-  Relation R1 = consume_and_regurgitate(input_R1);
-  Relation R2 = consume_and_regurgitate(input_R2);
-
-  // skip_set_checks++;
-  assert(!R1.is_null() && !R2.is_null());
-  assert((R1.n_inp() == R2.n_inp() && R1.n_out() == R2.n_out()) ||
-         (R2.n_inp() == 0 && R2.n_out() == 0));
-  R1.simplify();
-  R2.simplify();
-  Rel_Body *r1 = R1.split();
-  Rel_Body *r2 = R2.split();
-
-  if(relation_debug) {
-    fprintf(DebugFile, "\n### GIST computation start ### [\n");
-    R1.prefix_print(DebugFile);
-    R2.prefix_print(DebugFile);
-    fprintf(DebugFile, "### ###\n");
-  }
-
-
-//  The merged conjunct has to have the variables of either r1 or r2, but
-//  not both. Use r1's, since it'll be cheaper to remap r2's single conj.
-  remap_DNF_vars(r2, r1);
-  assert(r2->is_upper_bound_satisfiable() && "Gist: second operand is FALSE");
-  // skip_set_checks--;
-
-  Conjunct *known = r2->single_conjunct();
-  assert(known != NULL && "Gist: second operand has more than 1 conjunct");
-
-  DNF *new_dnf = new DNF();
-  for(DNF_Iterator pd(r1->simplified_DNF); pd.live(); pd.next()) {
-    Conjunct *conj = pd.curr();
-    Conjunct *cgist = merge_conjs(known, conj, MERGE_GIST, conj->relation()); // Uses r1's vars
-    cgist->set_relation(r1);   // Thinks it's part of r1 now, for var. purposes
-    if(simplify_conj(cgist, true, effort+1, EQ_RED)) {
-      /* Throw out black constraints, turn red constraints into black */
-      cgist->rm_color_constrs();
-      if(cgist->is_true()) {
-        delete new_dnf;
-        delete cgist;
-        // skip_set_checks++;
-        Relation retval = Relation::True(r1->n_inp(), r2->n_out());
-        // retval.finalize();
-        retval.simplify();
-        if(R1.is_set() && R2.is_set()) retval.markAsSet();
-        // skip_set_checks--;
-        return retval;
-      }
-      else {
-        // since modular equations might be changed, simplify again!
-        simplify_conj(cgist, true, effort+1, EQ_BLACK);
-        
-        new_dnf->add_conjunct(cgist);
-      }
-    }
-  }
-  delete r1->simplified_DNF;
-  r1->simplified_DNF = new_dnf;
-  assert(!r1->is_null());
-  R1.finalize();
-  if(relation_debug) {
-    fprintf(DebugFile, "] ### GIST computation end ###\n");
-    R1.prefix_print(DebugFile);
-    fprintf(DebugFile, "### ###\n");
-  }
-  return(R1);
-}
-
-
-//
-// Compute gist r1 given r2. r2 can have multiple conjuncts,
-// return result is always simplified.
-//
-Relation Gist(NOT_CONST Relation &input_R1,
-              NOT_CONST Relation &input_R2, int effort) {
-  Relation R1 = consume_and_regurgitate(input_R1);
-  Relation R2 = consume_and_regurgitate(input_R2);
-  if (R1.is_null())
-    return R1;
-  // change the Gist semantics to allow r2 be null -- by chun 07/30/2007
-  if (R2.is_null()) {
-    R1.simplify();
-    return R1;
-  }
-  if (!(R1.n_inp() == 0 && R2.n_out() == 0) &&
-      (R1.n_inp() != R2.n_inp() || R1.n_out() != R2.n_out()))
-    throw std::invalid_argument("relation arity does not match");
-
-  // skip_set_checks++;
-  // assert(!R1.is_null());
-  // assert(R2.is_null() ||
-  //       (R1.n_inp() == R2.n_inp() && R1.n_out() == R2.n_out()) ||
-  //       (R2.n_inp() == 0 && R2.n_out() == 0));
-  // skip_set_checks--;
-  R2.simplify();
-
-  if(relation_debug) {
-    fprintf(DebugFile, "\n### multi-GIST computation start ### [\n");
-    R1.prefix_print(DebugFile);
-    R2.prefix_print(DebugFile);
-    fprintf(DebugFile, "### ###\n");
-  }
-
-  if (!R2.is_upper_bound_satisfiable())
-    return Relation::True(R1);
-  if (R2.is_obvious_tautology()) {
-    R1.simplify();
-    return R1;
-  }
-  R1.simplify();
-
-  if (!Intersection(copy(R1), copy(R2)).is_upper_bound_satisfiable())
-    return Relation::False(R1);
-
-  int nconj1=0;
-  for (DNF_Iterator di(R1.simplified_DNF()); di.live(); di.next()) 
-    nconj1++;
-  int nconj2=0;
-  for (DNF_Iterator di2(R2.simplified_DNF()); di2.live(); di2.next()) 
-    nconj2++;
-
-  {  
-    static int OMEGA_WHINGE = -1;
-    if (OMEGA_WHINGE < 0) {
-      OMEGA_WHINGE = getenv("OMEGA_WHINGE") ? atoi(getenv("OMEGA_WHINGE")) : 0;
-    }
-    if (OMEGA_WHINGE && (nconj1 + nconj2 > 50)) {
-      fprintf(DebugFile,"WOW!!!! - Gist (%d conjuncts, %d conjuncts)!!!\n",
-              nconj1,nconj2);
-      fprintf(DebugFile,"Base:\n");
-      R1.prefix_print(DebugFile);
-      fprintf(DebugFile,"Context:\n");
-      R2.prefix_print(DebugFile);
-    }
-  }
-
-  if (nconj2==1)
-    return GistSingleConjunct(R1,R2, effort);
-  else { 
-    R1.simplify(0,1);
-    R2.simplify(0,1);
-    Relation G = Relation::True(R1); 
-    for (DNF_Iterator di2(R2.simplified_DNF()); di2.live(); di2.next()) {
-      Conjunct * c2 = di2.curr();
-      Relation G2 = Relation::False(R1); 
-      for (DNF_Iterator di1(R1.simplified_DNF()); di1.live(); di1.next()) {
-        Conjunct * c1 = di1.curr();
-        Relation G1=GistSingleConjunct(Relation(R1,c1), Relation(R2,c2),effort);
- 
-        if (G1.is_obvious_tautology()) {
-          G2 = G1;
-          break;
-        }
-        else if (!G1.is_upper_bound_satisfiable() || !G1.is_exact()) {
-          if(relation_debug) {
-            fprintf(DebugFile, "gist A given B is unsatisfiable\n");
-            fprintf(DebugFile, "A:\n");
-            Relation(R1,c1).prefix_print(DebugFile);
-            fprintf(DebugFile, "B:\n");
-            Relation(R2,c2).prefix_print(DebugFile);
-            fprintf(DebugFile, "\n");
-          }
-          //G1 = Relation(R1,c1);
-          return R1;
-        }
-        else if(0 && G1.is_exact() && !Must_Be_Subset(Relation(R1,c1),copy(G1))) {
-          fprintf(DebugFile,"Unexpected non-Must_Be_Subset gist result!\n");
-          fprintf(DebugFile,"base: \n");
-          Relation(R1,c1).prefix_print(DebugFile);
-          fprintf(DebugFile,"context: \n");
-          Relation(R2,c2).prefix_print(DebugFile);
-          fprintf(DebugFile,"result: \n");
-          G1.prefix_print(DebugFile);
-          fprintf(DebugFile,"base not subseteq result: \n");
-          assert(!G1.is_exact() || Must_Be_Subset(Relation(R1,c1),copy(G1)));
-        }
-        G2=Union(G2,G1); 
-      }
-      G2.simplify(0,1);
-      G = Intersection(G,G2);
-      G.simplify(0,1);
-      if(relation_debug) {
-        fprintf(DebugFile, "result so far is:\n");
-        G.prefix_print(DebugFile);
-      }
-    } 
-        
-    if(relation_debug) {
-      fprintf(DebugFile, "\n### end multi-GIST computation ### ]\n");
-      fprintf(DebugFile, "G is:\n");
-      G.prefix_print(DebugFile);
-      fprintf(DebugFile, "### ###\n");
-    }
-#if ! defined NDEBUG
-    Relation S1 = Intersection(copy(R1), copy(R2));
-    Relation S2 = Intersection(copy(G), copy(R2));
-
-
-    if(relation_debug) {
-      fprintf(DebugFile, "\n---->[Checking validity of the GIST result\n");
-      fprintf(DebugFile, "for G=gist R1 given R2:\n");
-      fprintf(DebugFile, "R1 intersect R2 is:\n");
-      S1.print_with_subs(DebugFile);
-      fprintf(DebugFile, "\nG intersect R2 is:\n");
-      S2.print_with_subs(DebugFile);
-      fprintf(DebugFile, "---->]\n");
-    }
-    assert (!S1.is_exact() || !S2.is_exact() || (Must_Be_Subset(copy(S1),copy(S2)) && Must_Be_Subset(copy(S2),copy(S1))));
-#endif   
-    return G;
-  }
-}  
-
-
-// Project away all input and output variables.
-Relation Project_On_Sym(NOT_CONST Relation &S,
-                        NOT_CONST Relation &input_context) {
-  Relation R = consume_and_regurgitate(S);
-  Relation context = consume_and_regurgitate(input_context);
-  int i;
-
-  // skip_set_checks++;
-  leave_pufs_untouched++;
-  int  in_arity = R.max_ufs_arity_of_in();
-  int  out_arity = R.max_ufs_arity_of_out();
-  assert(!R.is_null());
-  R.split();
-
-  int no_inp = R.n_inp();
-  int no_out = R.n_out();
-  Mapping M(no_inp, no_out);
-
-  for(i=1; i<=no_inp; i++) {          // project out input variables
-    M.set_map(Input_Var, i, Exists_Var, i);
-  }
-  for(i=1; i<=no_out; i++) {          // project out output variables
-    M.set_map(Output_Var, i, Exists_Var, no_inp+i);
-  }
-  MapRel1(R, M, Comb_Id, 0, 0);
-
-  R.finalize();
-  if (in_arity) R = Extend_Domain(R,in_arity);
-  if (out_arity) R = Extend_Range(R,out_arity);
-
-  int d = min(in_arity,out_arity);
-  if (d && !context.is_null()) {
-    int g = min(d,context.query_guaranteed_leading_0s());
-    int p = min(d,context.query_possible_leading_0s());
-    int dir = context.query_leading_dir();
-    R.enforce_leading_info(g,p,dir);
-  }
-
-  leave_pufs_untouched--;
-  // skip_set_checks--;
-  if(relation_debug) {
-    fprintf(DebugFile,"\nProjecting onto symbolic (%d,%d):\n",in_arity,out_arity);
-    R.prefix_print(DebugFile);
-  }
-  return R;
-}
-
-
-//
-// Project out global variable g from relation r
-//
-Relation Project(NOT_CONST Relation &S, Global_Var_ID g) {
-  Relation R = consume_and_regurgitate(S);
-  assert(!R.is_null());
-
-  skip_finalization_check++;
-
-  Rel_Body *r = R.split();
-  r->DNF_to_formula();
-  Formula *f = r->rm_formula();
-  F_Exists *ex = r->add_exists();
-  ex->add_child(f);
-    
-  if (g->arity() == 0) {
-    assert(R.has_local(g) && "Project: Relation doesn't contain variable to be projected");
-    Variable_ID v = R.get_local(g);
- 
-    bool rmd = rm_variable(r->Symbolic,v);
-    assert(rmd && "Project: Variable to be projected doesn't exist");
- 
-    v->remap = ex->declare(v->base_name);
-    f->remap();
-    v->remap = v;
-  }
-  else {
-    assert((R.has_local(g, Input_Tuple) || R.has_local(g, Output_Tuple)) && "Project: Relation doesn't contain variable to be projected");
-
-    if (R.has_local(g, Input_Tuple)) {
-      Variable_ID v = R.get_local(g, Input_Tuple);
- 
-      bool rmd = rm_variable(r->Symbolic,v);
-      assert(rmd && "Project: Variable to be projected doesn't exist");
- 
-      v->remap = ex->declare(v->base_name);
-      f->remap();
-      v->remap = v;
-    }
-    if (R.has_local(g, Output_Tuple)) {
-      Variable_ID v = R.get_local(g, Output_Tuple);
- 
-      bool rmd = rm_variable(r->Symbolic,v);
-      assert(rmd && "Project: Variable to be projected doesn't exist");
- 
-      v->remap = ex->declare(v->base_name);
-      f->remap();
-      v->remap = v;
-    }
-  }
-
-  skip_finalization_check--;
-    
-  R.finalize();
-  return R;
-}
-
-
-//
-// Project all symbolic variables from relation r
-//
-Relation Project_Sym(NOT_CONST Relation &S) {
-  Relation R = consume_and_regurgitate(S);
-  assert(!R.is_null());
-
-  Rel_Body *r = R.split();
-  r->DNF_to_formula();
-
-  Formula *f = r->rm_formula();
-
-  skip_finalization_check++;
-  F_Exists *ex = r->add_exists();
-  for(Variable_ID_Iterator R_Sym(r->Symbolic); R_Sym; R_Sym++) {
-    Variable_ID v = *R_Sym;
-    v->remap = ex->declare(v->base_name);
-  }
-  ex->add_child(f);
-  skip_finalization_check--;
-
-  f->remap();
-
-  reset_remap_field(r->Symbolic);
-  r->Symbolic.clear();
-
-  R.finalize();
-  return R;
-}
-
-//
-// Project specified variables, leaving those variables with no constraints.
-//
-Relation Project(NOT_CONST Relation &S, Sequence<Variable_ID> &s) {
-  // This is difficult to do with mappings.  This cheats, since it is
-  // much easier and more straightforward.
-
-  Relation R = consume_and_regurgitate(S);
-  assert(!R.is_null());
-
-  Rel_Body *r = R.split();
-  r->DNF_to_formula();
-  Formula *f = r->rm_formula();
-  bool need_symbolic_clear = false;
-    
-  skip_finalization_check++;
-  F_Exists *ex = r->add_exists();
-  for(int i = 1; i <= s.size(); i++) {
-    if (s[i]->kind() == Global_Var)
-      need_symbolic_clear = true;
-    s[i]->remap = ex->declare(s[i]->base_name);
-  }
-  ex->add_child(f);
-  skip_finalization_check--;
-
-  f->remap();
-
-  reset_remap_field(s);
-  if (need_symbolic_clear)
-    r->Symbolic.clear();
-
-  R.finalize();
-  return R;
-}
-
-Relation Project(NOT_CONST Relation &S, int pos, Var_Kind vkind) {
-  Variable_ID v = 0; // shut the compiler up
-  switch (vkind) {
-  case Input_Var:
-    v = input_vars[pos];
-    break;
-  case Output_Var:
-    v = output_vars[pos];
-    break;
-  // case Set_Var:
-  //   v = set_vars[pos];
-  //   break;
-  default:
-    assert(0);
-  }
-    
-  return Project(S, v);
-}
-
-Relation Project(NOT_CONST Relation &S, Variable_ID v) {
-  Tuple<Variable_ID> s;
-  s.append(v);
-  return Project(S, s);
-}
-  
-//
-// Variables in DNF of map_rel reference declarations of map_rel (or not).
-// remap_DNF_vars makes them to reference declarations of ref_rel.
-// Ref_rel can get new global variable declarations in the process.
-//
-void remap_DNF_vars(Rel_Body *map_rel, Rel_Body *ref_rel) {
-  // skip_set_checks++;
-  assert (map_rel->simplified_DNF);
-  assert (ref_rel->simplified_DNF);
-
-  // skip_set_checks++;
-
-  for(DNF_Iterator pd(map_rel->simplified_DNF); pd.live(); pd.next()) {
-    Conjunct *cc = pd.curr();
-    Variable_ID_Tuple &mvars = cc->mappedVars;
-    for(Variable_Iterator mvarsIter=mvars; mvarsIter; mvarsIter++) {
-      Variable_ID v = *mvarsIter;
-      switch(v->kind()) {
-      case Input_Var:
-        assert(ref_rel->n_inp() >= v->get_position());
-        break;
-      case Output_Var:
-        assert(ref_rel->n_out() >= v->get_position());
-        break;
-      case Global_Var:
-        // The assignment is a noop, but tells ref_rel that the global may be
-        // used inside it, which is required.
-        *mvarsIter = ref_rel->get_local(v->get_global_var(),v->function_of());
-        break;
-      case Wildcard_Var:
-        break;
-      default:
-        assert(0 && "bad variable kind");
-      }
-    }
-  }
-  // skip_set_checks--;
-}
-
-
-Relation projectOntoJust(Relation R, Variable_ID v) {
-  // skip_set_checks++;
-    
-  int ivars = R.n_inp(), ovars = R.n_out();
-  int ex_ivars= 0, ex_ovars = 0;
-    
-  assert(v->kind() == Input_Var || v->kind() == Output_Var);
-  if (v->kind() == Input_Var) {
-    ex_ivars = 1;
-    R = Extend_Domain(R,1);
-  }
-  else {
-    ex_ovars = 1;
-    R = Extend_Range(R,1);
-  }
-
-  // Project everything except v
-  Mapping m(ivars+ex_ivars,ovars+ex_ovars);
-  int j;
-  for(j = 1; j <=ivars+ex_ivars; j++) m.set_map_in(j, Exists_Var, j);
-  for(j = 1; j <=ovars+ex_ovars; j++) m.set_map_out(j, Exists_Var, j+ivars+ex_ivars);
-  m.set_map(v->kind(), v->get_position(), v->kind(), v->get_position());
-
-  MapRel1(R, m, Comb_Id,-1,-1);
-  R.finalize();
-  // skip_set_checks--;
-  return R;
-}
-
-//static 
-//void copyEQtoGEQ(GEQ_Handle &g, const EQ_Handle &e, bool negate) {
-//extern void copy_constraint(Constraint_Handle H, Constraint_Handle initial);
-//    copy_constraint(g, e);
-//}
-
-
-Relation EQs_to_GEQs(NOT_CONST Relation &S, bool excludeStrides) {
-  Relation R = consume_and_regurgitate(S);
-  assert(R.is_simplified());
-  use_ugly_names++;
-  for (DNF_Iterator s(R.query_DNF()); s.live(); s.next())
-    s.curr()->convertEQstoGEQs(excludeStrides);
-  use_ugly_names--;
-  return R;
-}
-
-
-// Tuple to find values for is input+output
-Relation Symbolic_Solution(NOT_CONST Relation &R) {
-  Relation S = consume_and_regurgitate(R);
-  Tuple<Variable_ID> vee;
-  // skip_set_checks++;
-  int i;
-  for(i = 1; i <= S.n_inp(); i++) vee.append(input_var(i));
-  for(i = 1; i <= S.n_out(); i++) vee.append(output_var(i));
-  // skip_set_checks--;
-
-  return Solution(S, vee);
-}
-
-
-// Tuple to find values for is given as arg, plus input and output
-Relation Symbolic_Solution(NOT_CONST Relation &R, Sequence<Variable_ID> &for_these){
-  Relation S = consume_and_regurgitate(R);
-  Tuple<Variable_ID> vee;
-  // skip_set_checks++;
-  int i;
-  for(Any_Iterator<Variable_ID> it(for_these); it; it++)
-    vee.append(*it);
-  for(i = 1; i <= S.n_inp(); i++) vee.append(input_var(i));
-  for(i = 1; i <= S.n_out(); i++) vee.append(output_var(i));
-  // skip_set_checks--;
-
-  return Solution(S, vee);
-}
-
-
-// Tuple to find values for is input+output+global_decls
-Relation Sample_Solution(NOT_CONST Relation &R) {
-  Relation S = consume_and_regurgitate(R);
-
-  Tuple<Variable_ID> vee;
-
-  // skip_set_checks++;
-  int i;
-  for(i = 1; i <= S.global_decls()->size(); i++)
-    vee.append((*S.global_decls())[i]);
-  for(i = 1; i <= S.n_inp(); i++) vee.append(input_var(i));
-  for(i = 1; i <= S.n_out(); i++) vee.append(output_var(i));
-  // skip_set_checks--;
-
-  return Solution(S,vee);
-}
-
-
-// Tuple to find values is given as arg
-Relation Solution(NOT_CONST Relation &S, Sequence<Variable_ID> &for_these ) {
-  Relation R = consume_and_regurgitate(S);
-  if (R.is_null())
-    return R;
-  
-  //assert(!R.is_null());
-
-  if(!R.is_upper_bound_satisfiable()) {
-    return Relation::False(R);
-  }
-    
-  bool inexactAnswer=false;
-  if(R.is_inexact()) {
-    if(R.is_lower_bound_satisfiable())
-      R = Lower_Bound(R); // a solution to LB is a solution to the relation
-    else {
-      // A solution to the UB may not be a solution to the relation:
-      // There may be a solution which satisfies all known constraints, but
-      // we have no way of knowing if it satisifies the unknown constraints.
-      inexactAnswer = true;
-      R = Upper_Bound(R);
-    }
-  }
-
-  Sequence<Variable_ID> &vee = for_these;
-  for (DNF_Iterator di(R.query_DNF()); di; di++) {      
-    Relation current(R, *di);
-    int i;
-    for(i = vee.size()-1; i >= 0; i--) {
-      bool some_constraints = false, one_stride = false;
- 
-      int current_var = vee.size()-i;
-      Section<Variable_ID> s(&vee,current_var+1,i); 
-
-      // Query variable in vee[current_var]
-      Relation projected = Project(copy(current), s);
-
-    retry_solution:    
-      assert(projected.has_single_conjunct());
-      DNF_Iterator one = projected.query_DNF();
-
-      // Look for candidate EQ's
-      EQ_Handle stride;
-      EQ_Iterator ei(*one);
-      for(; ei; ei++) {
-        if((*ei).get_coef(vee[current_var]) != 0) {
-          if(!Constr_Vars_Iter(*ei,true).live()) { // no wildcards
-            some_constraints = true;
-            // Add this constraint to the current as an EQ
-            current.and_with_EQ(*ei);
-            break;
-          }
-          else {
-            one_stride = !one_stride && !some_constraints;
-            stride = *ei;
-          }
-        }
-      }
-      if(ei) 
-        continue; // Found an EQ, skip to next variable
-      else if (one_stride && !some_constraints) { 
-        // if unconstrained except for a stride, pick stride as value
-        Constr_Vars_Iter cvi(stride,true);
-        assert(cvi.live());
-        cvi++;
-        if(!cvi) {  // Just one existentially quantified variable
-          Relation current_copy = current;
-          EQ_Handle eh = current_copy.and_with_EQ();
-          for(Constr_Vars_Iter si = stride; si; si++)
-            if((*si).var->kind() != Wildcard_Var){
-              // pick "0" for wildcard, don't set its coef
-              eh.update_coef((*si).var, (*si).coef);
-            }
-          eh.update_const(stride.get_const());
-          if(current_copy.is_upper_bound_satisfiable()){
-            current = current_copy;
-            continue; // skip to next var
-          }
-        }
-        some_constraints = true; // count the stride as a constraint
-      }
-
-      // Can we convert a GEQ?
-      GEQ_Iterator gi(*one);
-      for(; gi; gi++) {
-        if((*gi).get_coef(vee[current_var]) != 0) {
-          some_constraints = true;
-          if(!Constr_Vars_Iter(*gi,true).live()) { // no wildcards
-            Relation current_copy = current;
-            // Add this constraint to the current as an EQ & test
-            current_copy.and_with_EQ(*gi);
-            if (current_copy.is_upper_bound_satisfiable()) {
-              current = current_copy;
-              break;
-            }
-          }
-        }
-      }
-      if (gi) continue; // Turned a GEQ into EQ, skip to next
-
-      // Remove wildcards, try try again
-      Relation approx = Approximate(copy(projected));
-      assert(approx.has_single_conjunct());
-      DNF_Iterator d2 = approx.query_DNF();
-    
-      EQ_Iterator ei2(*d2);
-      for(; ei2; ei2++) {
-        if((*ei2).get_coef(vee[current_var]) != 0) {
-          some_constraints = true;
-          assert(!Constr_Vars_Iter(*ei2,true).live()); // no wildcards
-          Relation current_copy = current;
-          // Add this constraint to the current as an EQ & test
-          current_copy.and_with_EQ(*ei2);
-          if (current_copy.is_upper_bound_satisfiable()) {
-            current = current_copy;
-            break;
-          }
-        }
-      }
-      if(ei2) continue; // Found an EQ, skip to next variable
-
-      GEQ_Iterator gi2(*d2);
-      for(; gi2; gi2++) {
-        if((*gi2).get_coef(vee[current_var]) != 0) {
-          some_constraints = true;
-          assert(!Constr_Vars_Iter(*gi2,true).live()); // no wildcards
-          Relation current_copy = current;
-          // Add this constraint to the current as an EQ & test
-          current_copy.and_with_EQ(*gi2);
-          if (current_copy.is_upper_bound_satisfiable()) {
-            current = current_copy;
-            break;
-          }
-        }
-      }
-      if(gi2) continue;
- 
-      if(!some_constraints) { // No constraints on this variable were found
-        EQ_Handle e = current.and_with_EQ();
-        e.update_const(-42);  // Be creative
-        e.update_coef(vee[current_var], 1);
-        continue;
-      }
-      else { // What to do? Find a wildcard to discard
-        Variable_ID wild = NULL;
-      
-        for (GEQ_Iterator gi(*one); gi; gi++)
-          if ((*gi).get_coef(vee[current_var]) != 0 && (*gi).has_wildcards()) {
-            Constr_Vars_Iter cvi(*gi, true);
-            wild = (*cvi).var;
-            break;
-          }
-        if (wild == NULL)
-          for (EQ_Iterator ei(*one); ei; ei++)
-            if ((*ei).get_coef(vee[current_var]) != 0 && (*ei).has_wildcards()) {
-              Constr_Vars_Iter cvi(*ei, true);
-              wild = (*cvi).var;
-              break;
-            }
-
-        if (wild != NULL) {
-          // skip_set_checks++;
-          
-          Relation R2;
-          {
-            Tuple<Relation> r(1);
-            r[1] = projected;
-            Tuple<std::map<Variable_ID, std::pair<Var_Kind, int> > > mapping(1);
-            mapping[1][wild] = std::make_pair(vee[current_var]->kind(), vee[current_var]->get_position());
-            mapping[1][vee[current_var]] = std::make_pair(Exists_Var, 1);
-            Tuple<bool> inverse(1);
-            inverse[1] = false;
-            R2 = merge_rels(r, mapping, inverse, Comb_And);
-          }
-
-          Variable_ID R2_v;
-          switch (vee[current_var]->kind()) {
-          // case Set_Var:
-          case Input_Var: {
-            int pos = vee[current_var]->get_position();
-            R2_v = R2.input_var(pos);
-            break;
-          }
-          case Output_Var: {
-            int pos = vee[current_var]->get_position();
-            R2_v = R2.output_var(pos);
-            break;
-          }
-          case Global_Var: {
-            Global_Var_ID g = vee[current_var]->get_global_var();
-            if (g->arity() == 0)
-              R2_v = R2.get_local(g);
-            else
-              R2_v = R2.get_local(g, vee[current_var]->function_of());
-          }
-          default:
-            assert(0);
-          }
-
-          Relation S2;
-          {
-            Tuple<Variable_ID> vee;
-            vee.append(R2_v);
-            S2 = Solution(R2, vee);
-          }
-
-          Variable_ID S2_v;
-          switch (vee[current_var]->kind()) {
-          // case Set_Var:
-          case Input_Var: {
-            int pos = vee[current_var]->get_position();
-            S2_v = S2.input_var(pos);
-            break;
-          }
-          case Output_Var: {
-            int pos = vee[current_var]->get_position();
-            S2_v = S2.output_var(pos);
-            break;
-          }
-          case Global_Var: {
-            Global_Var_ID g = vee[current_var]->get_global_var();
-            if (g->arity() == 0)
-              S2_v = S2.get_local(g);
-            else
-              S2_v = S2.get_local(g, vee[current_var]->function_of());
-          }
-          default:
-            assert(0);
-          }
-
-          Relation R3;
-          {
-            Tuple<Relation> r(2);
-            r[1] = projected;
-            r[2] = S2;
-            Tuple<std::map<Variable_ID, std::pair<Var_Kind, int> > > mapping(2);
-            mapping[1][wild] = std::make_pair(Exists_Var, 1);
-            mapping[2][S2_v] = std::make_pair(Exists_Var, 1);
-            Tuple<bool> inverse(2);
-            inverse[1] = inverse[2] = false;
-            R3 = merge_rels(r, mapping, inverse, Comb_And);
-          }
-
-          // skip_set_checks--;
-          
-          if (R3.is_upper_bound_satisfiable()) {
-            projected = R3;
-            goto retry_solution;
-          }
-        }
-      }
-
-      // If we get here, we failed to find a suitable constraint for
-      // this variable at this conjunct, look for another conjunct.
-      break;
-    }
-    
-    if (i < 0) {  // solution found
-      if(inexactAnswer)
-        current.and_with_and()->add_unknown();
-      current.finalize();
-      return current;
-    }
-  }
-  
-  // No solution found for any conjunct, we bail out.
-  fprintf(stderr,"Couldn't find suitable constraint for variable\n");
-  return Relation::Unknown(R);  
-}
-
-
-Relation Approximate(NOT_CONST Relation &input_R, bool strides_allowed) {
-  Relation R = consume_and_regurgitate(input_R);
-  if (R.is_null())
-    return R;
-  
-  // assert(!R.is_null());
-  Rel_Body *r = R.split();
-
-  // approximate can be used to remove lambda variables from farkas,
-  // so be careful not to invoke simplification process for integers.
-  r->simplify(-1,-1);
-
-  if (pres_debug) {
-    fprintf(DebugFile,"Computing approximation ");
-    if (strides_allowed) fprintf(DebugFile,"with strides allowed ");
-    fprintf(DebugFile,"[ \n");
-    r->prefix_print(DebugFile);
-  }
-
-  use_ugly_names++; 
-  for (DNF_Iterator pd(r->simplified_DNF); pd.live(); ) {
-    Conjunct *C = pd.curr();
-    pd.next();
-
-    for(int i = 0; i < C->problem->nGEQs; i++) 
-      C->problem->GEQs[i].touched = 1;
-
-    C->reorder();
-    if(C->problem->simplifyApproximate(strides_allowed)==0) {
-      r->simplified_DNF->rm_conjunct(C);
-      delete C;
-    }
-    else {
-      C->simplifyProblem(1,0,1);
-    
-      free_var_decls(C->myLocals);  C->myLocals.clear();
-   
-      Problem *p = C->problem;
-      Variable_ID_Tuple new_mapped(0);  // This is expanded by "append"
-      for (int i = 1; i <= p->safeVars; i++) {
-        // what is now in column i used to be in column p->var[i]
-        Variable_ID v = C->mappedVars[p->var[i]];
-        assert (v->kind() != Wildcard_Var);
-        new_mapped.append(v);
-      }
-      assert(strides_allowed || C->problem->nVars == C->problem->safeVars);
-      C->mappedVars = new_mapped;  
-      for (int i = p->safeVars+1; i <= p->nVars; i++) {
-        Variable_ID v = C->declare();
-        C->mappedVars.append(v);
-      }
-
-   
-      // reset var and forwarding address if desired.
-      p->variablesInitialized = 0;
-      for(int i = 1; i < C->problem->nVars; i++)
-        C->problem->var[i] = C->problem->forwardingAddress[i] = i;
-    }
-  }
- 
-  if (pres_debug) 
-    fprintf(DebugFile,"] done Computing approximation\n");
-  use_ugly_names--; 
-  return R;
-}
-
-
-Relation Lower_Bound(NOT_CONST Relation &r) {
-  Relation s = consume_and_regurgitate(r);
-  s.interpret_unknown_as_false();
-  return s;
-}
-
-
-Relation Upper_Bound(NOT_CONST Relation &r) {
-  Relation s = consume_and_regurgitate(r);
-  s.interpret_unknown_as_true();
-  return s;
-}
-
-
-bool operator==(const Relation &, const Relation &) { 
-  assert(0 && "You rilly, rilly don't want to do this.\n");
-  abort();
-  return false;
-}
-
-
-namespace { // supporting stuff for MapRel1 and MapAndCombine2
-  // Determine if a mapping requires an f_exists node
-  bool has_existentials(const Mapping &m) { 
-    for(int i=1;i<=m.n_in();  i++) 
-      if (m.get_map_in_kind(i) == Exists_Var) return true;
-    for(int j=1;j<=m.n_out(); j++) 
-      if (m.get_map_out_kind(j) == Exists_Var) return true;
-    return false;
-  }
-
-  void get_relation_arity_from_one_mapping(const Mapping &m1,
-                                                  int &in_req, int &out_req) {
-    int j, i;
-    in_req = 0; out_req = 0;
-    for(i = 1;  i <= m1.n_in();  i++) {
-      j = m1.get_map_in_pos(i);
-      switch(m1.get_map_in_kind(i)) {
-      case Input_Var:  in_req = max(in_req, j);   break;
-      // case Set_Var:  in_req = max(in_req, j);   break;
-      case Output_Var: out_req = max(out_req, j); break;
-      default: break;
-      }
-    }
-    for(i = 1;  i <= m1.n_out();  i++) {
-      j = m1.get_map_out_pos(i);
-      switch(m1.get_map_out_kind(i)) {
-      case Input_Var:  in_req = max(in_req, j);   break;
-      // case Set_Var:  in_req = max(in_req, j);   break;
-      case Output_Var: out_req = max(out_req, j); break;
-      default: break;
-      }
-    }
-  }
-
-  // Scan mappings to see how many input and output variables they require. 
-  void get_relation_arity_from_mappings(const Mapping &m1,
-                                               const Mapping &m2,
-                                               int &in_req, int &out_req) {
-    int inreq1, inreq2, outreq1, outreq2;
-    get_relation_arity_from_one_mapping(m1, inreq1, outreq1);
-    get_relation_arity_from_one_mapping(m2, inreq2, outreq2);
-    in_req = max(inreq1, inreq2);
-    out_req = max(outreq1, outreq2);
-  }
-}
-
-
-//
-// Build lists of variables that need to be replaced in the given 
-// Formula.  Declare globals in new relation.  Then call
-// map_vars to do the replacements.
-//
-// Obnoxiously many arguments here:
-// Relation arguments contain declarations of symbolic and in/out vars.
-// F_Exists argument is where needed existentially quant. vars can be decl.
-//
-// Mapping specifies how in/out vars are mapped
-// Two lists are required to be able to map in/out variables from the first
-// and second relations to the same existentially quantified variable.
-//
-void align(Rel_Body *originalr, Rel_Body *newr, F_Exists *fe,
-           Formula *f, const Mapping &mapping, bool &newrIsSet,
-           List<int> &seen_exists, Variable_ID_Tuple &seen_exists_ids) {
-  int i, cur_ex = 0;  // initialize cur_ex to shut up the compiler
-
-  f->set_relation(newr);  // Might not need to do this anymore, if bugs were fixed
-  int input_remapped = 0;
-  int output_remapped = 0;
-  int sym_remapped = 0;
-  // skip_set_checks++;
-
-  Variable_ID new_var;
-  Const_String new_name;
-  int new_pos;
-
-  // MAP old input variables by setting their remap fields 
-  for(i = 1; i <= originalr->n_inp(); i++) { 
-    Variable_ID this_var = originalr->input_var(i), New_E;
-    Const_String this_name = originalr->In_Names[i];
-
-    switch (mapping.get_map_in_kind(i)) {
-    case Input_Var:
-    // case Set_Var:
-      // if (mapping.get_map_in_kind(i) == Set_Var)
-      //   newrIsSet = true;  // Don't mark it just yet; we still need to 
-      // // refer to its "input" vars internally
-
-      // assert((newrIsSet && mapping.get_map_in_kind(i) == Set_Var)
-      //        || ((!newrIsSet &&mapping.get_map_in_kind(i) == Input_Var)));
-
-      new_pos = mapping.get_map_in_pos(i);
-      new_var = newr->input_var(new_pos);
-      if (this_var != new_var) {
-        input_remapped = 1;
-        this_var->remap = new_var;
-      }
-      new_name = newr->In_Names[new_pos];
-      if (!this_name.null()) {                 // should we name this?
-        if (!new_name.null()) {            // already named, anonymize
-          if (new_name != this_name)
-            newr->name_input_var(new_pos, Const_String());
-        }
-        else
-          newr->name_input_var(new_pos, this_name);
-      }
-      break;
-    case Output_Var:
-      assert(!newr->is_set());
-      input_remapped = 1;
-      new_pos = mapping.get_map_in_pos(i);
-      this_var->remap = new_var = newr->output_var(new_pos);
-      new_name = newr->Out_Names[new_pos];
-      if (!this_name.null()) { 
-        if (!new_name.null()) {             // already named, anonymize
-          if (new_name != this_name)
-            newr->name_output_var(new_pos, Const_String());
-        }
-        else
-          newr->name_output_var(new_pos, this_name);
-      }
-      break;
-    case Exists_Var:
-      input_remapped = 1;
-      // check if we have declared it, use that if so.
-      // create it if not.  
-      if (mapping.get_map_in_pos(i) <= 0 ||
-          (cur_ex = seen_exists.index(mapping.get_map_in_pos(i))) == 0){
-        if (!this_name.null())
-          New_E = fe->declare(this_name);
-        else
-          New_E = fe->declare();
-        this_var->remap = New_E;
-        if (mapping.get_map_in_pos(i) > 0) {
-          seen_exists.append(mapping.get_map_in_pos(i));
-          seen_exists_ids.append(New_E);
-        }
-      }
-      else {
-        this_var->remap = new_var = seen_exists_ids[cur_ex];
-        if (!this_name.null()) {  // Have we already assigned a name?
-          if (!new_var->base_name.null()) {
-            if (new_var->base_name != this_name)
-              new_var->base_name = Const_String();
-          }
-          else {
-            new_var->base_name = this_name;
-            assert(!this_name.null());
-          }
-        }
-      }
-      break;
-    default:
-      assert(0 && "Unsupported var type in MapRel2");
-      break;
-    }
-  }
-
-  //  MAP old output variables.
-  for(i = 1; i <= originalr->n_out(); i++) {   
-    Variable_ID this_var = originalr->output_var(i), New_E;
-    Const_String this_name = originalr->Out_Names[i];
-
-    switch (mapping.get_map_out_kind(i)) {
-    case Input_Var:
-    // case Set_Var:
-      // if (mapping.get_map_out_kind(i) == Set_Var)
-      //   newrIsSet = true;  // Don't mark it just yet; we still need to refer to its "input" vars internally
-  
-      // assert((newrIsSet && mapping.get_map_out_kind(i) == Set_Var)
-      //        ||((!newrIsSet &&mapping.get_map_out_kind(i) == Input_Var)));
-
-      output_remapped = 1;
-      new_pos = mapping.get_map_out_pos(i);
-      this_var->remap = new_var = newr->input_var(new_pos);
-      new_name = newr->In_Names[new_pos];
-      if (!this_name.null()) {
-        if (!new_name.null()) {    // already named, anonymize
-          if (new_name != this_name)
-            newr->name_input_var(new_pos, Const_String());
-        }
-        else
-          newr->name_input_var(new_pos, this_name);
-      }
-      break;
-    case Output_Var:
-      assert(!newr->is_set());
-      new_pos = mapping.get_map_out_pos(i);
-      new_var = newr->output_var(new_pos);
-      if (new_var != this_var) {
-        output_remapped = 1;
-        this_var->remap = new_var;
-      }
-      new_name = newr->Out_Names[new_pos];
-      if (!this_name.null()) {
-        if (!new_name.null()) {    // already named, anonymize
-          if (new_name != this_name)
-            newr->name_output_var(new_pos, Const_String());
-        }
-        else
-          newr->name_output_var(new_pos, this_name);
-      }
-      break;
-    case Exists_Var:
-      // check if we have declared it, create it if not.  
-      output_remapped = 1;
-      if (mapping.get_map_out_pos(i) <= 0 ||
-          (cur_ex = seen_exists.index(mapping.get_map_out_pos(i))) == 0) {   // Declare it.
-        New_E = fe->declare(this_name);
-        this_var->remap = New_E;
-        if (mapping.get_map_out_pos(i) > 0) {
-          seen_exists.append(mapping.get_map_out_pos(i));
-          seen_exists_ids.append(New_E);
-        }
-      }
-      else {
-        this_var->remap = new_var = seen_exists_ids[cur_ex];
-        if (!this_name.null()) {
-          if (!new_var->base_name.null()) {
-            if (new_var->base_name != this_name)
-              new_var->base_name = Const_String(); 
-          }
-          else {
-            new_var->base_name = this_name;
-          }
-        }
-      }
-      break;
-    default:
-      assert(0 &&"Unsupported var type in MapRel2");
-      break;
-    }
-  }
-
-  Variable_ID_Tuple *oldSym = originalr->global_decls();
-  for(i=1; i<=(*oldSym).size(); i++) {
-    Variable_ID v = (*oldSym)[i];
-    assert(v->kind()==Global_Var);
-    if (v->get_global_var()->arity() > 0) {
-      Argument_Tuple new_of = v->function_of();
-      if (!leave_pufs_untouched) 
-        new_of = mapping.get_tuple_fate(new_of, v->get_global_var()->arity());
-      if (new_of == Unknown_Tuple) {
-        // hopefully v is not really used
-        // if we get here, f should have been in DNF,
-        //                 now an OR node with conjuncts below
-        // we just need to check that no conjunct uses v
-#if ! defined NDEBUG
-        if (f->node_type() == Op_Conjunct) {
-          assert(f->really_conjunct()->mappedVars.index(v)==0
-                 && "v unused");
-        }
-#if 0
-        else {
-          // assert(f->node_type() == Op_Or);
-          for (List_Iterator<Formula *> conj(f->children()); conj; conj++) {
-            assert((*conj)->really_conjunct()->mappedVars.index(v)==0
-                   && "v unused");
-          }
-        }
-#endif
-#endif
-        // since its not really used, don't bother adding it to
-        // the the global_vars list of the new relation
-        continue;
-      }
-      if (v->function_of() != new_of) {
-        Variable_ID new_v=newr->get_local(v->get_global_var(),new_of);
-        assert(v != new_v);
-        v->remap = new_v;
-        sym_remapped = 1;
-      }
-      else {
-        // add symbolic to symbolic list
-#if ! defined NDEBUG
-        Variable_ID new_v =
-#endif
-          newr->get_local(v->get_global_var(), v->function_of());
-#if ! defined NDEBUG
-        assert(v == new_v);
-#endif
-      }
-    }
-    else {
-      // add symbolic to symbolic list
-#if ! defined NDEBUG
-      Variable_ID new_v =
-#endif
-        newr->get_local(v->get_global_var());
-#if ! defined NDEBUG
-      assert(v == new_v);
-#endif
-    }
-  }
-
-  if (sym_remapped || input_remapped || output_remapped) {
-    f->remap();
-
-    // If 2 vars mapped to same variable, combine them
-    //There's a column to combine only when there are two equal remap fields.
-    Tuple<Variable_ID> vt(0);
-    bool combine = false;
-    Tuple_Iterator<Variable_ID> t(input_vars);
-    for(i=1; !combine && i<=originalr->n_inp(); t++, i++)
-      if (vt.index((*t)->remap))
-        combine = true;
-      else
-        vt.append((*t)->remap);
-    Tuple_Iterator<Variable_ID> t2(output_vars);
-    for(i=1; !combine && i <= originalr->n_out(); t2++, i++)
-      if (vt.index((*t2)->remap))
-        combine = true;
-      else
-        vt.append((*t2)->remap);
-    if (combine) f->combine_columns(); 
-
-    if (sym_remapped) 
-      reset_remap_field(originalr->Symbolic);
-    if (input_remapped) 
-      reset_remap_field(input_vars,originalr->n_inp());
-    if (output_remapped) 
-      reset_remap_field(output_vars,originalr->n_out());
-  }
-
-  // skip_set_checks--;
-
-#ifndef NDEBUG
-  if (fe)
-    foreach(v,Variable_ID,fe->myLocals,assert(v == v->remap));
-#endif
-}
-
-
-// MapRel1, MapAndCombineRel2 can be replaced by merge_rels
-void MapRel1(Relation &R, const Mapping &map, Combine_Type ctype,
-             int number_input, int number_output,
-             bool invalidate_resulting_leading_info,
-             bool finalize) {
-#if defined(INCLUDE_COMPRESSION)
-  assert(!R.is_compressed());
-#endif
-  assert(!R.is_null());
-   
-  Relation inputRel = R; 
-  R = Relation();
-  Rel_Body *inputRelBody = inputRel.split();
-
-  int in_req=0, out_req=0;
-  get_relation_arity_from_one_mapping(map, in_req, out_req);
-
-  R = Relation(number_input == -1 ? in_req : number_input,
-               number_output == -1 ? out_req : number_output);
-
-  Rel_Body *outputRelBody = R.split();
-
-  inputRelBody->DNF_to_formula();
-  Formula *f1 = inputRelBody->rm_formula();
-
-  F_Exists *fe;
-  Formula *f;
-  if (has_existentials(map)) {
-    f = fe = outputRelBody->add_exists();
-  }
-  else {
-    fe = NULL;
-    f = outputRelBody;
-  }
-  and_below_exists = NULL;
-  if (finalize) and_below_exists = NULL;
-  else f = and_below_exists = f->add_and();
-  if(ctype == Comb_AndNot) {
-    f = f->add_not();
-  }
-  f->add_child(f1);
-
-  exists_ids.clear();
-  exists_numbers.clear();
-
-  bool returnAsSet=false;
-  align(inputRelBody, outputRelBody, fe, f1, map, returnAsSet,
-        exists_numbers, exists_ids);
-
-  if (returnAsSet || 
-      (inputRelBody->is_set() && outputRelBody->n_out() == 0)) {
-    R.markAsSet();
-    R.invalidate_leading_info(); // nonsensical for a set
-  }
-
-  if (finalize) R.finalize();
-  inputRel = Relation();
-  if (invalidate_resulting_leading_info)
-    R.invalidate_leading_info();
-}
-
-
-Relation MapAndCombineRel2(Relation &R1, Relation &R2, const Mapping &mapping1,
-                           const Mapping &mapping2, Combine_Type ctype,
-                           int number_input, int number_output) {
-#if defined(INCLUDE_COMPRESSION)
-  assert(!R1.is_compressed());
-  assert(!R2.is_compressed());
-#endif
-  assert(!R1.is_null() && !R2.is_null());
-  Rel_Body *r1 = R1.split();
-  Rel_Body *r2 = R2.split();
-    
-  int in_req, out_req;      // Create the new relation
-  get_relation_arity_from_mappings(mapping1, mapping2, in_req, out_req);
-  Relation R3(number_input == -1 ? in_req : number_input,
-              number_output == -1 ? out_req : number_output);
-  Rel_Body *r3 = R3.split();  // This is just to get the pointer, it's cheap
-
-  /* permit the add_{exists,and} below, reset after they are done.*/
-  skip_finalization_check++;
-    
-  F_Exists *fe = NULL;
-  Formula *f;
-  if (has_existentials(mapping1) || has_existentials(mapping2)) {
-    fe = r3->add_exists();
-    f = fe;
-  }
-  else {
-    f = r3;
-  } 
-
-  r1->DNF_to_formula();
-  Formula *f1 = r1->rm_formula();
-  r2->DNF_to_formula();
-  Formula *f2 = r2->rm_formula();
-
-  // align: change r1 vars to r3 vars in formula f1 via map mapping1,
-  //        declaring needed exists vars in F_Exists *fe
-  // Also maps symbolic variables appropriately, sets relation ptrs in f1.
-  // In order to map variables of both relations to the same variables,
-  // we keep a list of new existentially quantified vars between calls.
-  // returnAsSet means mark r3 as set before return.  Don't mark it yet,
-  // because internally we need to refer to "input_vars" of a set, and that
-  // would blow assertions.
-
-  bool returnAsSet=false;
-  exists_ids.clear();
-  exists_numbers.clear();
-  align(r1, r3, fe, f1, mapping1, returnAsSet, exists_numbers, exists_ids);
-  // align: change r2 vars to r3 vars in formula f2 via map mapping2
-  align(r2, r3, fe, f2, mapping2, returnAsSet, exists_numbers, exists_ids);
-
-  switch (ctype) {
-  case Comb_Or:
-    if(f1->node_type() == Op_Or) {
-      f->add_child(f1); 
-      f = f1;
-    }
-    else {
-      f = f->add_or();
-      f->add_child(f1); 
-    }
-    break;
-  case Comb_And:
-  case Comb_AndNot:
-    if(f1->node_type() == Op_And) {
-      f->add_child(f1); 
-      f = f1;
-    }
-    else {
-      f = f->add_and();
-      f->add_child(f1); 
-    }
-    break;
-  default:
-    assert(0 && "Invalid combine type in MapAndCombineRel2");
-  }
-
-  Formula *c2;
-  if (ctype==Comb_AndNot) {
-    c2 = f->add_not();
-  }
-  else {
-    c2 = f;
-  }
-  c2->add_child(f2);
-
-  skip_finalization_check--;     /* Set this back for return */
-  R3.finalize(); 
-
-  if (returnAsSet ||
-      (R1.is_set() && R2.is_set() && R3.n_inp() >= 0 && R3.n_out() == 0)){
-    R3.markAsSet();
-    R3.invalidate_leading_info();
-  }
-  R1 = Relation();
-  R2 = Relation();
-  return R3;
-}
-
-
-//
-// Scramble each relation's variables and merge these relations
-// together. Support variable mapping to and from existentials.
-// Unspecified variables in mapping are mapped to themselves by
-// default. It intends to replace MapRel1 and MapAndCombineRel2
-// functions (the time saved by grafting formula tree might be
-// neglegible when compared to the simplification cost).
-//
-Relation merge_rels(Tuple<Relation> &R, const Tuple<std::map<Variable_ID, std::pair<Var_Kind, int> > > &mapping, const Tuple<bool> &inverse, Combine_Type ctype, int number_input, int number_output) {
-  const int m = R.size();
-  assert(mapping.size() == m && inverse.size() == m);
-  // skip_set_checks++;
-  
-  // if new relation's arity is not given, calculate it on demand
-  if (number_input == -1) {
-    number_input = 0;
-    for (int i = 1; i <= m; i++) {
-      for (int j = R[i].n_inp(); j >= 1; j--) {
-        Variable_ID v = R[i].input_var(j);
-        std::map<Variable_ID, std::pair<Var_Kind, int> >::const_iterator p = mapping[i].find(v);
-        if (p == mapping[i].end()) {
-          number_input = j;
-          break;
-        }
-      }
-      
-      for (std::map<Variable_ID, std::pair<Var_Kind, int> >::const_iterator j = mapping[i].begin(); j != mapping[i].end(); j++) {
-        if ((*j).second.first == Input_Var || (*j).second.first == Set_Var)
-          number_input = max(number_input, (*j).second.second);
-      }
-    }
-  }
-
-  if (number_output == -1) {
-    number_output = 0;
-    for (int i = 1; i <= m; i++) {
-      for (int j = R[i].n_out(); j >= 1; j--) {
-        Variable_ID v = R[i].output_var(j);
-        std::map<Variable_ID, std::pair<Var_Kind, int> >::const_iterator p = mapping[i].find(v);
-        if (p == mapping[i].end()) {
-          number_output = j;
-          break;
-        }
-      }
-      for (std::map<Variable_ID, std::pair<Var_Kind, int> >::const_iterator j = mapping[i].begin(); j != mapping[i].end(); j++) {
-        if ((*j).second.first == Output_Var)
-          number_output = max(number_output, (*j).second.second);
-      }
-    }
-  }
-
-  Relation R2(number_input, number_output);
-  F_Exists *fe = R2.add_exists();
-  Formula *f_root;
-  switch (ctype) {
-  case Comb_And:
-    f_root = fe->add_and();
-    break;
-  case Comb_Or:
-    f_root = fe->add_or();
-    break;
-  default:
-    assert(0);  // unsupported merge type
-  }
-  
-  std::map<int, Variable_ID> seen_exists_by_num;
-  std::map<Variable_ID, Variable_ID> seen_exists_by_id;
-
-  for (int i = 1; i <= m; i++) {
-    F_Or *fo;
-    if (inverse[i])
-      fo = f_root->add_not()->add_or();
-    else
-      fo = f_root->add_or();
-
-    for (DNF_Iterator di(R[i].query_DNF()); di; di++) {
-      F_And *f = fo->add_and();
-
-      for (GEQ_Iterator gi(*di); gi; gi++) {
-        GEQ_Handle h = f->add_GEQ();
-        for (Constr_Vars_Iter cvi(*gi); cvi; cvi++) {
-          Variable_ID v = cvi.curr_var();
-          std::map<Variable_ID, std::pair<Var_Kind, int> >::const_iterator p = mapping[i].find(v);
-          if (p == mapping[i].end()) {
-            switch (v->kind()) {
-            // case Set_Var:
-            case Input_Var: {
-              int pos = v->get_position();
-              h.update_coef(R2.input_var(pos), cvi.curr_coef());
-              break;
-            }
-            case Output_Var: {
-              int pos = v->get_position();
-              h.update_coef(R2.output_var(pos), cvi.curr_coef());
-              break;
-            }
-            case Exists_Var:
-            case Wildcard_Var: {
-              std::map<Variable_ID, Variable_ID>::iterator p2 = seen_exists_by_id.find(cvi.curr_var());
-              Variable_ID e;
-              if (p2 == seen_exists_by_id.end()) {
-                e = fe->declare();
-                seen_exists_by_id[cvi.curr_var()] = e;
-              }
-              else
-                e = (*p2).second;
-              h.update_coef(e, cvi.curr_coef());
-              break;
-            }
-            case Global_Var: {
-              Global_Var_ID g = v->get_global_var();
-              Variable_ID v2;
-              if (g->arity() == 0)
-                v2 = R2.get_local(g);
-              else
-                v2 = R2.get_local(g, v->function_of());
-              h.update_coef(v2, cvi.curr_coef());
-              break;
-            }
-            default:
-              assert(0);  // shouldn't happen if input relations are simplified
-            }
-          }
-          else {
-            switch ((*p).second.first) {
-            // case Set_Var:
-            case Input_Var: {
-              int pos = (*p).second.second;
-              h.update_coef(R2.input_var(pos), cvi.curr_coef());
-              break;
-            }
-            case Output_Var: {
-              int pos = (*p).second.second;
-              h.update_coef(R2.output_var(pos), cvi.curr_coef());
-              break;
-            }              
-            case Exists_Var:
-            case Wildcard_Var: {
-              int pos = (*p).second.second;
-              std::map<int, Variable_ID>::iterator p2 = seen_exists_by_num.find(pos);
-              Variable_ID e;
-              if (p2 == seen_exists_by_num.end()) { 
-                e = fe->declare();
-                seen_exists_by_num[pos] = e;
-              }
-              else
-                e = (*p2).second;
-              h.update_coef(e, cvi.curr_coef());
-              break;
-            }          
-            default:
-              assert(0);  // mapped to unsupported variable type
-            }
-          }
-        }
-        h.update_const((*gi).get_const());
-      }
-
-      for (EQ_Iterator ei(*di); ei; ei++) {
-        EQ_Handle h = f->add_EQ();
-        for (Constr_Vars_Iter cvi(*ei); cvi; cvi++) {
-          Variable_ID v = cvi.curr_var();
-          std::map<Variable_ID, std::pair<Var_Kind, int> >::const_iterator p = mapping[i].find(v);
-          if (p == mapping[i].end()) {
-            switch (v->kind()) {
-            // case Set_Var:
-            case Input_Var: {
-              int pos = v->get_position();
-              h.update_coef(R2.input_var(pos), cvi.curr_coef());
-              break;
-            }
-            case Output_Var: {
-              int pos = v->get_position();
-              h.update_coef(R2.output_var(pos), cvi.curr_coef());
-              break;
-            }
-            case Exists_Var:
-            case Wildcard_Var: {
-              std::map<Variable_ID, Variable_ID>::iterator p2 = seen_exists_by_id.find(v);
-              Variable_ID e;
-              if (p2 == seen_exists_by_id.end()) {
-                e = fe->declare();
-                seen_exists_by_id[v] = e;
-              }
-              else
-                e = (*p2).second;
-              h.update_coef(e, cvi.curr_coef());
-              break;
-            }
-            case Global_Var: {
-              Global_Var_ID g = v->get_global_var();
-              Variable_ID v2;
-              if (g->arity() == 0)
-                v2 = R2.get_local(g);
-              else
-                v2 = R2.get_local(g, v->function_of());
-              h.update_coef(v2, cvi.curr_coef());
-              break;
-            }
-            default:
-              assert(0);  // shouldn't happen if input relations are simplified
-            }
-          }
-          else {
-            switch ((*p).second.first) {
-            // case Set_Var:
-            case Input_Var: {
-              int pos = (*p).second.second;
-              h.update_coef(R2.input_var(pos), cvi.curr_coef());
-              break;
-            }
-            case Output_Var: {
-              int pos = (*p).second.second;
-              h.update_coef(R2.output_var(pos), cvi.curr_coef());
-              break;
-            }
-            case Exists_Var:
-            case Wildcard_Var: {
-              int pos = (*p).second.second;
-              std::map<int, Variable_ID>::iterator p2 = seen_exists_by_num.find(pos);
-              Variable_ID e;
-              if (p2 == seen_exists_by_num.end()) { 
-                e = fe->declare();
-                seen_exists_by_num[pos] = e;
-              }
-              else
-                e = (*p2).second;
-              h.update_coef(e, cvi.curr_coef());
-              break;
-            }          
-            default:
-              assert(0);  // mapped to unsupported variable type
-            }
-          }
-        }
-        h.update_const((*ei).get_const());
-      }
-    }
-  }
-          
-  // skip_set_checks--;
-
-  if (number_output == 0) {
-    R2.markAsSet();
-    // R2.invalidate_leading_info();
-  }
-    
-  return R2;  
-}
-
-} // namespace
diff --git a/omegalib/omega/src/basic/ConstString.cc b/omegalib/omega/src/basic/ConstString.cc
deleted file mode 100644
index 7d2ec1e..0000000
--- a/omegalib/omega/src/basic/ConstString.cc
+++ /dev/null
@@ -1,134 +0,0 @@
-#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
deleted file mode 100644
index 50b9441..0000000
--- a/omegalib/omega/src/basic/Link.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-#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
deleted file mode 100644
index 416a3e7..0000000
--- a/omegalib/omega/src/closure.cc
+++ /dev/null
@@ -1,2100 +0,0 @@
-/*****************************************************************************
- 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
deleted file mode 100644
index ff872c9..0000000
--- a/omegalib/omega/src/evac.cc
+++ /dev/null
@@ -1,339 +0,0 @@
-#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
deleted file mode 100644
index 1b3ef87..0000000
--- a/omegalib/omega/src/farkas.cc
+++ /dev/null
@@ -1,480 +0,0 @@
-/*****************************************************************************
- 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_legacy.cc b/omegalib/omega/src/hull_legacy.cc
deleted file mode 100755
index a59d34f..0000000
--- a/omegalib/omega/src/hull_legacy.cc
+++ /dev/null
@@ -1,1484 +0,0 @@
-/*****************************************************************************
- 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
deleted file mode 100755
index 62dcb26..0000000
--- a/omegalib/omega/src/hull_simple.cc
+++ /dev/null
@@ -1,1013 +0,0 @@
-/*****************************************************************************
- 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
deleted file mode 100644
index 0dc9b49..0000000
--- a/omegalib/omega/src/omega_core/oc.cc
+++ /dev/null
@@ -1,754 +0,0 @@
-/*****************************************************************************
- 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
deleted file mode 100644
index dc595ea..0000000
--- a/omegalib/omega/src/omega_core/oc_eq.cc
+++ /dev/null
@@ -1,653 +0,0 @@
-/*****************************************************************************
- 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
deleted file mode 100644
index fdb2718..0000000
--- a/omegalib/omega/src/omega_core/oc_exp_kill.cc
+++ /dev/null
@@ -1,297 +0,0 @@
-/*****************************************************************************
- 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
deleted file mode 100644
index 17d8a0c..0000000
--- a/omegalib/omega/src/omega_core/oc_global.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-#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
deleted file mode 100644
index 7934713..0000000
--- a/omegalib/omega/src/omega_core/oc_print.cc
+++ /dev/null
@@ -1,686 +0,0 @@
-#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
deleted file mode 100644
index 8b6e04c..0000000
--- a/omegalib/omega/src/omega_core/oc_problems.cc
+++ /dev/null
@@ -1,198 +0,0 @@
-#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
deleted file mode 100644
index 528b297..0000000
--- a/omegalib/omega/src/omega_core/oc_query.cc
+++ /dev/null
@@ -1,478 +0,0 @@
-#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
deleted file mode 100644
index 1b988d4..0000000
--- a/omegalib/omega/src/omega_core/oc_quick_kill.cc
+++ /dev/null
@@ -1,775 +0,0 @@
-/*****************************************************************************
- 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
deleted file mode 100644
index 0e492db..0000000
--- a/omegalib/omega/src/omega_core/oc_simple.cc
+++ /dev/null
@@ -1,1373 +0,0 @@
-/*****************************************************************************
- 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
deleted file mode 100644
index c25b6d0..0000000
--- a/omegalib/omega/src/omega_core/oc_solve.cc
+++ /dev/null
@@ -1,1378 +0,0 @@
-/*****************************************************************************
- 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
deleted file mode 100644
index a7d21be..0000000
--- a/omegalib/omega/src/omega_core/oc_util.cc
+++ /dev/null
@@ -1,327 +0,0 @@
-/*****************************************************************************
- 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
deleted file mode 100644
index c23962a..0000000
--- a/omegalib/omega/src/pres_beaut.cc
+++ /dev/null
@@ -1,235 +0,0 @@
-#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
deleted file mode 100644
index a8ebd15..0000000
--- a/omegalib/omega/src/pres_cnstr.cc
+++ /dev/null
@@ -1,450 +0,0 @@
-#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
deleted file mode 100644
index 1569116..0000000
--- a/omegalib/omega/src/pres_col.cc
+++ /dev/null
@@ -1,104 +0,0 @@
-#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
deleted file mode 100644
index f3f458d..0000000
--- a/omegalib/omega/src/pres_conj.cc
+++ /dev/null
@@ -1,1460 +0,0 @@
-/*****************************************************************************
- 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
deleted file mode 100644
index f5ac312..0000000
--- a/omegalib/omega/src/pres_decl.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-#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
deleted file mode 100644
index c9fd7e6..0000000
--- a/omegalib/omega/src/pres_dnf.cc
+++ /dev/null
@@ -1,1416 +0,0 @@
-/*****************************************************************************
- 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
deleted file mode 100644
index 82b710b..0000000
--- a/omegalib/omega/src/pres_form.cc
+++ /dev/null
@@ -1,147 +0,0 @@
-#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
deleted file mode 100644
index 0f05d40..0000000
--- a/omegalib/omega/src/pres_gen.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-#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
deleted file mode 100644
index 8ee90f1..0000000
--- a/omegalib/omega/src/pres_logic.cc
+++ /dev/null
@@ -1,226 +0,0 @@
-#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
deleted file mode 100644
index 4f2cd0d..0000000
--- a/omegalib/omega/src/pres_print.cc
+++ /dev/null
@@ -1,908 +0,0 @@
-#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
deleted file mode 100644
index 5483bad..0000000
--- a/omegalib/omega/src/pres_quant.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-#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
deleted file mode 100644
index 508959d..0000000
--- a/omegalib/omega/src/pres_rear.cc
+++ /dev/null
@@ -1,131 +0,0 @@
-#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
deleted file mode 100644
index 9854b09..0000000
--- a/omegalib/omega/src/pres_subs.cc
+++ /dev/null
@@ -1,131 +0,0 @@
-#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
deleted file mode 100644
index 0ec406f..0000000
--- a/omegalib/omega/src/pres_var.cc
+++ /dev/null
@@ -1,459 +0,0 @@
-#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
deleted file mode 100644
index 6569edb..0000000
--- a/omegalib/omega/src/reach.cc
+++ /dev/null
@@ -1,211 +0,0 @@
-#include <omega.h>
-#include <omega/Relations.h>
-#include <basic/DynamicArray.h>
-#include <omega/reach.h>
-
-namespace omega {
-
-typedef DynamicArray1<Relation> Rel_Array1;
-typedef DynamicArray2<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
diff --git a/src/chill_run.cc b/src/chill_run.cc
new file mode 100644
index 0000000..4eafe65
--- /dev/null
+++ b/src/chill_run.cc
@@ -0,0 +1,89 @@
+#include "chilldebug.h"
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include "loop.hh"
+#include <omega.h>
+#include "ir_code.hh"
+#include "ir_rose.hh"
+
+#include "chillmodule.hh" // Python wrapper functions for CHiLL
+
+//---
+// CHiLL globals
+//---
+Loop *myloop = NULL;
+IR_Code *ir_code = NULL;
+bool repl_stop = false;
+bool is_interactive = false;
+
+std::vector<IR_Control *> ir_controls;
+std::vector<int> loops;
+
+//---
+// CHiLL program main
+// Initialize state and run script or interactive mode
+//---
+int main( int argc, char* argv[] )
+{
+  DEBUG_PRINT("%s  main()\n", argv[0]);
+  if (argc > 2) {
+    fprintf(stderr, "Usage: %s [script_file]\n", argv[0]);
+    exit(-1);
+  }
+  
+  int fail = 0;
+  
+  // Create PYTHON interpreter
+  /* Pass argv[0] to the Python interpreter */
+  Py_SetProgramName(argv[0]);
+  
+  /* Initialize the Python interpreter.  Required. */
+  Py_Initialize();
+  
+  /* Add a static module */
+  initchill();
+  
+  if (argc == 2) {
+    FILE* f = fopen(argv[1], "r");
+    if(!f){
+      printf("can't open script file \"%s\"\n", argv[1]);
+      exit(-1);
+    }
+    PyRun_SimpleFile(f, argv[1]);
+    fclose(f);
+  }
+  if (argc == 1) {
+    //---
+    // Run a CHiLL interpreter
+    //---
+    printf("CHiLL v" CHILL_BUILD_VERSION " (built on " CHILL_BUILD_DATE ")\n");
+    printf("Copyright (C) 2008 University of Southern California\n");
+    printf("Copyright (C) 2009-2012 University of Utah\n");
+    //is_interactive = true; // let the lua interpreter know.
+    fflush(stdout);
+    // TODO: read lines of python code.
+    //Not sure if we should set fail from interactive mode
+    printf("CHiLL ending...\n");
+    fflush(stdout);
+  }
+
+  //printf("DONE with PyRun_SimpleString()\n");
+  
+  if (!fail && ir_code != NULL && myloop != NULL && myloop->stmt.size() != 0 && !myloop->stmt[0].xform.is_null()) {
+    int lnum_start;
+    int lnum_end;
+    lnum_start = get_loop_num_start();
+    lnum_end = get_loop_num_end();
+    DEBUG_PRINT("calling ROSE code gen?    loop num %d\n", lnum);
+    finalize_loop(lnum_start, lnum_end);
+    ((IR_roseCode*)(ir_code))->finalizeRose();
+    delete ir_code;
+  }
+  Py_Finalize();
+  return 0;
+}
diff --git a/src/chill_run_util.cc b/src/chill_run_util.cc
new file mode 100644
index 0000000..29568e7
--- /dev/null
+++ b/src/chill_run_util.cc
@@ -0,0 +1,120 @@
+#include <stdio.h>
+#include <string.h>
+#include "chill_run_util.hh"
+
+static std::string to_string(int ival) {
+  char buffer[4];
+  sprintf(buffer, "%d", ival);
+  return std::string(buffer);
+}
+
+simap_vec_t* make_prog(simap_vec_t* cond) {
+  return cond;
+}
+
+simap_vec_t* make_cond_gt(simap_t* lhs, simap_t* rhs) {
+  simap_vec_t* nvec = new simap_vec_t();
+  for(simap_t::iterator it = rhs->begin(); it != rhs->end(); it++)
+    (*lhs)[it->first] -= it->second;
+  (*lhs)[to_string(0)] -= 1;
+  nvec->push_back(*lhs);
+  delete rhs;
+  delete lhs;
+  return nvec;
+}
+
+simap_vec_t* make_cond_lt(simap_t* lhs, simap_t* rhs) {
+  return make_cond_gt(rhs, lhs);
+}
+
+simap_vec_t* make_cond_ge(simap_t* lhs, simap_t* rhs) {
+  simap_vec_t* nvec = new simap_vec_t();
+  for(simap_t::iterator it = rhs->begin(); it != rhs->end(); it++)
+    (*lhs)[it->first] -= it->second;
+  nvec->push_back(*lhs);
+  delete rhs;
+  delete lhs;
+  return nvec;
+}
+
+simap_vec_t* make_cond_le(simap_t* lhs, simap_t* rhs) {
+  return make_cond_ge(rhs, lhs);
+}
+
+simap_vec_t* make_cond_eq(simap_t* lhs, simap_t* rhs) {
+  simap_vec_t* nvec = new simap_vec_t();
+  for(simap_t::iterator it = lhs->begin(); it != lhs->end(); it++)
+    (*rhs)[it->first] -= it->second;
+  nvec->push_back(*rhs);
+  for(simap_t::iterator it = rhs->begin(); it != rhs->end(); it++)
+    it->second = -it->second;
+  nvec->push_back(*rhs);
+  delete rhs;
+  delete lhs;
+  return nvec;
+}
+
+simap_t* make_cond_item_add(simap_t* lhs, simap_t* rhs) {
+  for(simap_t::iterator it = lhs->begin(); it != lhs->end(); it++)
+    (*rhs)[it->first] += it->second;
+  delete lhs;
+  return rhs;
+}
+
+simap_t* make_cond_item_sub(simap_t* lhs, simap_t* rhs) {
+  for(simap_t::iterator it = lhs->begin(); it != lhs->end(); it++)
+    (*rhs)[it->first] -= it->second;
+  delete lhs;
+  return rhs;
+}
+
+simap_t* make_cond_item_mul(simap_t* lhs, simap_t* rhs) {
+  (*lhs)[to_string(0)] += 0;
+  (*rhs)[to_string(0)] += 0;
+  if(rhs->size() == 1) {
+    int t = (*rhs)[to_string(0)];
+    for(simap_t::iterator it = lhs->begin(); it != lhs->end(); it++)
+      it->second *= t;
+    delete rhs;
+    return lhs;
+  }
+  else if(rhs->size() == 1) {
+    int t = (*lhs)[to_string(0)];
+    for(simap_t::iterator it = rhs->begin(); it != rhs->end(); it++)
+      it->second *= t;
+    delete lhs;
+    return rhs;
+  }
+  else {
+    fprintf(stderr, "require Presburger formula");
+    delete lhs;
+    delete rhs;
+    // exit(2); <-- this may be a boost feature
+  }
+}
+
+simap_t* make_cond_item_neg(simap_t* expr) {
+  for (simap_t::iterator it = expr->begin(); it != expr->end(); it++) {
+    it->second = -(it->second);
+  }
+  return expr;
+}
+
+simap_t* make_cond_item_number(int n) {
+  simap_t* nmap = new simap_t();
+  (*nmap)[to_string(0)] = n;
+  return nmap;
+}
+
+simap_t* make_cond_item_variable(const char* var) {
+  simap_t* nmap = new simap_t();
+  (*nmap)[std::string(var)] = 1;
+  return nmap;
+}
+
+simap_t* make_cond_item_level(int n) {
+  simap_t* nmap = new simap_t();
+  (*nmap)[to_string(n)] = 1;
+  return nmap;
+}
+
diff --git a/src/chillmodule.cc b/src/chillmodule.cc
new file mode 100644
index 0000000..0e41f88
--- /dev/null
+++ b/src/chillmodule.cc
@@ -0,0 +1,795 @@
+#include "chilldebug.h"
+
+#include "chill_run_util.hh"
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <omega.h>
+#include "loop.hh"
+#include "ir_code.hh"
+#include "ir_rose.hh"
+
+#include "chillmodule.hh"
+
+using namespace omega;
+
+extern Loop *myloop;
+extern IR_Code *ir_code;
+extern bool is_interactive;
+extern bool repl_stop;
+
+std::string procedure_name;
+std::string source_filename;
+
+int loop_start_num;
+int loop_end_num;
+
+extern std::vector<IR_Control *> ir_controls;
+extern std::vector<int> loops;
+
+// ----------------------- //
+// CHiLL support functions //
+// ----------------------- //
+// not sure yet if this actually needs to be exposed to the python interface
+// these four functions are here to maintain similarity to the Lua interface
+int get_loop_num_start() {
+  return loop_start_num;
+}
+
+int get_loop_num_end() {
+  return loop_end_num;
+}
+
+static void set_loop_num_start(int start_num) {
+  loop_start_num = start_num;
+}
+
+static void set_loop_num_end(int end_num) {
+  loop_end_num = end_num;
+}
+
+// TODO: finalize_loop(int,int) and init_loop(int,int) are identical to thier Lua counterparts.
+// consider integrating them
+
+void finalize_loop(int loop_num_start, int loop_num_end) {
+  if (loop_num_start == loop_num_end) {
+    ir_code->ReplaceCode(ir_controls[loops[loop_num_start]], myloop->getCode());
+    ir_controls[loops[loop_num_start]] = NULL;
+  }
+  else {
+    std::vector<IR_Control *> parm;
+    for (int i = loops[loop_num_start]; i <= loops[loop_num_end]; i++)
+      parm.push_back(ir_controls[i]);
+    IR_Block *block = ir_code->MergeNeighboringControlStructures(parm);
+    ir_code->ReplaceCode(block, myloop->getCode());
+    for (int i = loops[loop_num_start]; i <= loops[loop_num_end]; i++) {
+      delete ir_controls[i];
+      ir_controls[i] = NULL;
+    }
+  }
+  delete myloop;
+}
+void finalize_loop() {
+  int loop_num_start = get_loop_num_start();
+  int loop_num_end = get_loop_num_end();
+  finalize_loop(loop_num_start, loop_num_end);
+}
+static void init_loop(int loop_num_start, int loop_num_end) {
+  if (source_filename.empty()) {
+    fprintf(stderr, "source file not set when initializing the loop");
+    if (!is_interactive)
+      exit(2);
+  }
+  else {
+    if (ir_code == NULL) {
+      if (procedure_name.empty())
+        procedure_name = "main";
+        
+      ir_code = new IR_roseCode(source_filename.c_str(), procedure_name.c_str());
+          
+      IR_Block *block = ir_code->GetCode();
+      ir_controls = ir_code->FindOneLevelControlStructure(block);
+      for (int i = 0; i < ir_controls.size(); i++) {
+        if (ir_controls[i]->type() == IR_CONTROL_LOOP)
+          loops.push_back(i);
+      }
+      delete block;
+    }
+    if (myloop != NULL && myloop->isInitialized()) {
+       finalize_loop();
+    }
+  }
+  set_loop_num_start(loop_num_start);
+  set_loop_num_end(loop_num_end);
+  if (loop_num_end < loop_num_start) {
+    fprintf(stderr, "the last loop must be after the start loop");
+    if (!is_interactive)
+      exit(2);
+  }              
+  if (loop_num_end >= loops.size()) {
+    fprintf(stderr, "loop %d does not exist", loop_num_end);
+    if (!is_interactive)
+      exit(2);
+  }
+  std::vector<IR_Control *> parm;
+  for (int i = loops[loop_num_start]; i <= loops[loop_num_end]; i++) {
+    if (ir_controls[i] == NULL) {
+      fprintf(stderr, "loop has already been processed");
+      if (!is_interactive)
+        exit(2);
+    }
+    parm.push_back(ir_controls[i]);
+  }
+  IR_Block *block = ir_code->MergeNeighboringControlStructures(parm);
+  myloop = new Loop(block);
+  delete block;  
+  //if (is_interactive) printf("%s ", PROMPT_STRING);
+}
+
+// ----------------------- //
+// Python support funcions //
+// ----------------------- //
+
+// -- CHiLL support -- //
+static void strict_arg_num(PyObject* args, int arg_num, const char* fname = NULL) {
+  int arg_given = PyTuple_Size(args);
+  char msg[128];
+  if(arg_num != arg_given) {
+    if(fname)
+      sprintf(msg, "%s: expected %i arguments, was given %i.", fname, arg_num, arg_given);
+    else
+      sprintf(msg, "Expected %i argumets, was given %i.", arg_num, arg_given);
+    throw std::runtime_error(msg);
+  }
+}
+
+static int strict_arg_range(PyObject* args, int arg_min, int arg_max, const char* fname = NULL) {
+  int arg_given = PyTuple_Size(args);
+  char msg[128];
+  if(arg_given < arg_min || arg_given > arg_max) {
+    if(fname)
+      sprintf(msg, "%s: expected %i to %i arguments, was given %i.", fname, arg_min, arg_max, arg_given);
+    else
+      sprintf(msg, "Expected %i to %i, argumets, was given %i.", arg_min, arg_max, arg_given);
+    throw std::runtime_error(msg);
+  }
+  return arg_given;
+}
+
+static int intArg(PyObject* args, int index, int dval = 0) {
+  if(PyTuple_Size(args) <= index)
+    return dval; 
+  int ival;
+  PyObject *item = PyTuple_GetItem(args, index); 
+  Py_INCREF(item);
+  if (PyInt_Check(item)) ival = PyInt_AsLong(item);
+  else {
+    fprintf(stderr, "argument at index %i is not an int\n", index);
+    exit(-1);
+  }
+  return ival;
+}
+
+static std::string strArg(PyObject* args, int index, const char* dval = NULL) {
+  if(PyTuple_Size(args) <= index)
+    return dval;
+  std::string strval;
+  PyObject *item = PyTuple_GetItem(args, index); 
+  Py_INCREF(item);
+  if (PyString_Check(item)) strval = strdup(PyString_AsString(item));
+  else {
+    fprintf(stderr, "argument at index %i is not an string\n", index);
+    exit(-1);
+  }
+  return strval;
+}
+
+static bool boolArg(PyObject* args, int index, bool dval = false) {
+  if(PyTuple_Size(args) <= index)
+    return dval;
+  bool bval;
+  PyObject* item = PyTuple_GetItem(args, index);
+  Py_INCREF(item);
+  return (bool)PyObject_IsTrue(item);
+}
+
+static bool tostringintmapvector(PyObject* args, int index, std::vector<std::map<std::string,int> >& vec) {
+  if(PyTuple_Size(args) <= index)
+    return false;
+  PyObject* seq = PyTuple_GetItem(args, index);
+  //TODO: Typecheck
+  int seq_len = PyList_Size(seq);
+  for(int i = 0; i < seq_len; i++) {
+    std::map<std::string,int> map;
+    PyObject* dict = PyList_GetItem(seq, i);
+    PyObject* keys = PyDict_Keys(dict);
+    //TODO: Typecheck
+    int dict_len = PyList_Size(keys);
+    for(int j = 0; j < dict_len; j++) {
+      PyObject* key = PyList_GetItem(keys, j);
+      PyObject* value = PyDict_GetItem(dict, key);
+      std::string str_key = strdup(PyString_AsString(key));
+      int int_value = PyInt_AsLong(value);
+      map[str_key] = int_value;
+    }
+    vec.push_back(map);
+  }
+  return true;
+}
+
+static bool tointvector(PyObject* seq, std::vector<int>& vec) {
+  //TODO: Typecheck
+  int seq_len = PyList_Size(seq);
+  for(int i = 0; i < seq_len; i++) {
+    PyObject* item = PyList_GetItem(seq, i);
+    vec.push_back(PyInt_AsLong(item));
+  }
+  return true;
+}
+
+static bool tointvector(PyObject* args, int index, std::vector<int>& vec) {
+  if(PyTuple_Size(args) <= index)
+    return false;
+  PyObject* seq = PyTuple_GetItem(args, index);
+  return tointvector(seq, vec);
+}
+
+static bool tointset(PyObject* args, int index, std::set<int>& set) {
+  if(PyTuple_Size(args) <= index)
+    return false;
+  PyObject* seq = PyTuple_GetItem(args, index);
+  //TODO: Typecheck
+  int seq_len = PyList_Size(seq);
+  for(int i = 0; i < seq_len; i++) {
+    PyObject* item = PyList_GetItem(seq, i);
+    set.insert(PyInt_AsLong(item));
+  }
+  return true;
+}
+static bool tointmatrix(PyObject* args, int index, std::vector<std::vector<int> >& mat) {
+  if(PyTuple_Size(args) <= index)
+    return false;
+  PyObject* seq_one = PyTuple_GetItem(args, index);
+  int seq_one_len = PyList_Size(seq_one);
+  for(int i = 0; i < seq_one_len; i++) {
+    std::vector<int> vec;
+    PyObject* seq_two = PyList_GetItem(seq_one, i);
+    int seq_two_len = PyList_Size(seq_two);
+    for(int j = 0; j < seq_two_len; j++) {
+      PyObject* item = PyList_GetItem(seq_two, j);
+      vec.push_back(PyInt_AsLong(item));
+    }
+    mat.push_back(vec);
+  }
+  return true;
+}
+
+// ------------------------- //
+// CHiLL interface functions //
+// ------------------------- //
+
+static PyObject* chill_source(PyObject* self, PyObject* args) {
+  strict_arg_num(args, 1, "source");
+  source_filename = strArg(args, 0);
+  Py_RETURN_NONE;
+}
+
+static PyObject* chill_procedure(PyObject* self, PyObject* args) {
+  if(!procedure_name.empty()) {
+    fprintf(stderr, "only one procedure can be handled in a script");
+    if(!is_interactive)
+      exit(2);
+  }
+  procedure_name = strArg(args, 0);
+  Py_RETURN_NONE;
+}
+
+static PyObject* chill_loop(PyObject* self, PyObject* args) {
+  // loop (n)
+  // loop (n:m)
+  
+  int nargs = PyTuple_Size(args);
+  int start_num;
+  int end_num;
+  if(nargs == 1) {
+    start_num = intArg(args, 0);
+    end_num = start_num;
+  }
+  else if(nargs == 2) {
+    start_num = intArg(args, 0);
+    end_num = intArg(args, 1);
+  }
+  else {
+    fprintf(stderr, "loop takes one or two arguments");
+    if(!is_interactive)
+      exit(2);
+  }
+  set_loop_num_start(start_num);
+  set_loop_num_end(end_num);
+  init_loop(start_num, end_num);
+  Py_RETURN_NONE;
+}
+
+static PyObject* chill_print_code(PyObject* self, PyObject* args) {
+  strict_arg_num(args, 0, "print_code");
+  myloop->printCode();
+  printf("\n");
+  Py_RETURN_NONE;
+}
+
+static PyObject* chill_print_dep(PyObject* self, PyObject* args) {
+  strict_arg_num(args, 0, "print_dep");
+  myloop->printDependenceGraph();
+  Py_RETURN_NONE;
+}
+
+static PyObject* chill_print_space(PyObject* self, PyObject* args) {
+  strict_arg_num(args, 0, "print_space");
+  myloop->printIterationSpace();
+  Py_RETURN_NONE;
+}
+
+static PyObject* chill_exit(PyObject* self, PyObject* args) {
+  strict_arg_num(args, 0, "exit");
+  repl_stop = true;
+  Py_RETURN_NONE;
+}
+
+static void add_known(std::string cond_expr) {
+  int num_dim = myloop->known.n_set();
+  std::vector<std::map<std::string, int> >* cond;
+  // TODO since we are using python, change this!
+  cond = parse_relation_vector(cond_expr.c_str());
+  
+  Relation rel(num_dim);
+  F_And *f_root = rel.add_and();
+  for (int j = 0; j < cond->size(); j++) {
+    GEQ_Handle h = f_root->add_GEQ();
+    for (std::map<std::string, int>::iterator it = (*cond)[j].begin(); it != (*cond)[j].end(); it++) {
+      try {
+        int dim = from_string<int>(it->first);
+        if (dim == 0)
+          h.update_const(it->second);
+        else
+          throw std::invalid_argument("only symbolic variables are allowed in known condition");
+      }
+      catch (std::ios::failure e) {
+        Free_Var_Decl *g = NULL;
+        for (unsigned i = 0; i < myloop->freevar.size(); i++) {
+          std::string name = myloop->freevar[i]->base_name();
+          if (name == it->first) {
+            g = myloop->freevar[i];
+            break;
+          }
+        }
+        if (g == NULL)
+          throw std::invalid_argument("symbolic variable " + it->first + " not found");
+        else
+          h.update_coef(rel.get_local(g), it->second);
+      }
+    }
+  }
+  myloop->addKnown(rel);
+}
+
+static PyObject* chill_known(PyObject* self, PyObject* args) {
+  strict_arg_num(args, 1, "known");
+  if (PyList_Check(PyTuple_GetItem(args, 0))) {
+    PyObject* list = PyTuple_GetItem(args, 0);
+    for (int i = 0; i < PyList_Size(list); i++) {
+      add_known(std::string(PyString_AsString(PyList_GetItem(list, i))));
+    }
+  }
+  else {
+    add_known(strArg(args, 0));
+  }
+  Py_RETURN_NONE;
+}
+
+static PyObject* chill_remove_dep(PyObject* self, PyObject* args) {
+  strict_arg_num(args, 0, "remove_dep");
+  int from = intArg(args, 0);
+  int to = intArg(args, 1);
+  myloop->removeDependence(from, to);
+  Py_RETURN_NONE;
+}
+
+static PyObject* chill_original(PyObject* self, PyObject* args) {
+  strict_arg_num(args, 0, "original");
+  myloop->original();
+  Py_RETURN_NONE;
+}
+
+static PyObject* chill_permute(PyObject* self, PyObject* args) {
+  int nargs = strict_arg_range(args, 1, 3, "permute");
+  if((nargs < 1) || (nargs > 3))
+    throw std::runtime_error("incorrect number of arguments in permute");
+  if(nargs == 1) {
+    // premute ( vector )
+     std::vector<int> pi;
+    if(!tointvector(args, 0, pi))
+      throw std::runtime_error("first arg in permute(pi) must be an int vector");
+    myloop->permute(pi);
+  }
+  else if (nargs == 2) {
+    // permute ( set, vector )
+    std::set<int> active;
+    std::vector<int> pi;
+    if(!tointset(args, 0, active))
+      throw std::runtime_error("the first argument in permute(active, pi) must be an int set");
+    if(!tointvector(args, 1, pi))
+      throw std::runtime_error("the second argument in permute(active, pi) must be an int vector");
+     myloop->permute(active, pi);
+  }
+  else if (nargs == 3) {
+    int stmt_num = intArg(args, 1);
+    int level = intArg(args, 2);
+    std::vector<int> pi;
+    if(!tointvector(args, 3, pi))
+      throw std::runtime_error("the third argument in permute(stmt_num, level, pi) must be an int vector");
+    myloop->permute(stmt_num, level, pi);
+  }
+  Py_RETURN_NONE;
+}
+
+static PyObject* chill_pragma(PyObject* self, PyObject* args) {
+  strict_arg_num(args, 3, "pragma");
+  int stmt_num = intArg(args, 1);
+  int level = intArg(args, 1);
+  std::string pragmaText = strArg(args, 2);
+  myloop->pragma(stmt_num, level, pragmaText);
+  Py_RETURN_NONE;
+}
+
+static PyObject* chill_prefetch(PyObject* self, PyObject* args) {
+  strict_arg_num(args, 3, "prefetch");
+  int stmt_num = intArg(args, 0);
+  int level = intArg(args, 1);
+  std::string prefetchText = strArg(args, 2);
+  int hint = intArg(args, 3);
+  myloop->prefetch(stmt_num, level, prefetchText, hint);
+  Py_RETURN_NONE;
+}
+
+static PyObject* chill_tile(PyObject* self, PyObject* args) {
+  int nargs = strict_arg_range(args, 3, 7, "tile");
+  int stmt_num = intArg(args, 0);
+  int level = intArg(args, 1);
+  int tile_size = intArg(args, 2);
+  if(nargs == 3) {
+    myloop->tile(stmt_num, level, tile_size);
+  }
+  else if(nargs >= 4) {
+    int outer_level = intArg(args, 3);
+    if(nargs >= 5) {
+      TilingMethodType method = StridedTile;
+      int imethod = intArg(args, 4, 2); //< don't know if a default value is needed
+      // check method input against expected values
+      if (imethod == 0)
+        method = StridedTile;
+      else if (imethod == 1)
+        method = CountedTile;
+      else
+        throw std::runtime_error("5th argument must be either strided or counted");
+      if(nargs >= 6) {
+        int alignment_offset = intArg(args, 5);
+        if(nargs == 7) {
+          int alignment_multiple = intArg(args, 6, 1);
+          myloop->tile(stmt_num, level, tile_size, outer_level, method, alignment_offset, alignment_multiple);
+        }
+        if(nargs == 6)
+          myloop->tile(stmt_num, level, tile_size, outer_level, method, alignment_offset);
+      }
+      if(nargs == 5)
+        myloop->tile(stmt_num, level, tile_size, outer_level, method);
+    }
+  if(nargs == 4)
+    myloop->tile(stmt_num, level, tile_size, outer_level);
+  }
+  Py_RETURN_NONE;
+}
+
+static void chill_datacopy_vec(PyObject* args) {
+  // Overload 1: bool datacopy(
+  //    const std::vector<std::pair<int, std::vector<int> > > &array_ref_nums,
+  //    int level,
+  //    bool allow_extra_read = false,
+  //    int fastest_changing_dimension = -1,
+  //    int padding_stride = 1,
+  //    int padding_alignment = 4,
+  //    int memory_type = 0);
+  std::vector<std::pair<int, std::vector<int> > > array_ref_nums;
+  // expect list(tuple(int,list(int)))
+  // or dict(int,list(int))
+  if(PyList_CheckExact(PyTuple_GetItem(args, 0))) {
+    PyObject* list = PyTuple_GetItem(args, 0);
+    for(int i = 0; i < PyList_Size(list); i ++) {
+      PyObject* tup = PyList_GetItem(list, i);
+      int index = PyLong_AsLong(PyTuple_GetItem(tup, 0));
+      std::vector<int> vec;
+      tointvector(PyTuple_GetItem(tup, 1), vec);
+      array_ref_nums.push_back(std::pair<int, std::vector<int> >(index, vec));
+    }
+  }
+  else if(PyList_CheckExact(PyTuple_GetItem(args, 0))) {
+    PyObject* dict = PyTuple_GetItem(args, 0);
+    PyObject* klist = PyDict_Keys(dict);
+    for(int ki = 0; ki < PyList_Size(klist); ki++) {
+      PyObject* index = PyList_GetItem(klist, ki);
+      std::vector<int> vec;
+      tointvector(PyDict_GetItem(dict,index), vec);
+      array_ref_nums.push_back(std::pair<int, std::vector<int> >(PyLong_AsLong(index), vec));
+    }
+    Py_DECREF(klist);
+  }
+  else {
+    //TODO: this should never happen
+  }
+  int level = intArg(args, 1);
+  bool allow_extra_read = boolArg(args, 2, false);
+  int fastest_changing_dimension = intArg(args, 3, -1);
+  int padding_stride = intArg(args, 4, 1);
+  int padding_alignment = intArg(args, 5, 4);
+  int memory_type = intArg(args, 6, 0);
+  myloop->datacopy(array_ref_nums, level, allow_extra_read, fastest_changing_dimension, padding_stride, padding_alignment, memory_type);
+}
+
+static void chill_datacopy_int(PyObject* args) {
+  int stmt_num = intArg(args, 0);
+  int level = intArg(args, 1);
+  std::string array_name = strArg(args,2,0);
+  bool allow_extra_read = boolArg(args,3,false);
+  int fastest_changing_dimension = intArg(args, 4, -1);
+  int padding_stride = intArg(args, 5, 1);
+  int padding_alignment = intArg(args, 6, 4);
+  int memory_type = intArg(args, 7, 0);
+  myloop->datacopy(stmt_num, level, array_name, allow_extra_read, fastest_changing_dimension, padding_stride, padding_alignment, memory_type);
+}
+
+static PyObject* chill_datacopy(PyObject* self, PyObject* args) {
+  // Overload 2: bool datacopy(int stmt_num, int level, const std::string &array_name, bool allow_extra_read = false, int fastest_changing_dimension = -1, int padding_stride = 1, int padding_alignment = 4, int memory_type = 0);
+  int nargs = strict_arg_range(args, 3, 7, "datacopy");
+  if(PyList_CheckExact(PyTuple_GetItem(args,0)) || PyDict_CheckExact(PyTuple_GetItem(args, 0))) {
+    chill_datacopy_vec(args);
+  }
+  else {
+    chill_datacopy_int(args);
+  }
+  Py_RETURN_NONE;
+}
+
+static PyObject* chill_datacopy_privatized(PyObject* self, PyObject* args) {
+  //  bool datacopy_privatized(int stmt_num, int level, const std::string &array_name, const std::vector<int> &privatized_levels, bool allow_extra_read = false, int fastest_changing_dimension = -1, int padding_stride = 1, int padding_alignment = 1, int memory_type = 0);
+  int nargs = strict_arg_range(args, 4, 9, "datacopy_privatized");
+  int stmt_num = intArg(args, 0);
+  int level = intArg(args, 1);
+  std::string array_name = strArg(args, 2);
+  std::vector<int> privatized_levels;
+  tointvector(args, 3, privatized_levels);
+  bool allow_extra_read = boolArg(args, 4, false);
+  int fastest_changing_dimension = intArg(args, 5, -1);
+  int padding_stride = intArg(args, 6, 1);
+  int padding_alignment = intArg(args, 7, 1);
+  int memory_type = intArg(args, 8);
+  myloop->datacopy_privatized(stmt_num, level, array_name, privatized_levels, allow_extra_read, fastest_changing_dimension, padding_stride, padding_alignment, memory_type);
+  Py_RETURN_NONE;
+}
+
+static PyObject* chill_unroll(PyObject* self, PyObject* args) {
+  int nargs = strict_arg_range(args, 3, 4, "unroll");
+  //std::set<int> unroll(int stmt_num, int level, int unroll_amount, std::vector< std::vector<std::string> >idxNames= std::vector< std::vector<std::string> >(), int cleanup_split_level = 0);
+  int stmt_num = intArg(args, 0);
+  int level = intArg(args, 1);
+  int unroll_amount = intArg(args, 2);
+  std::vector< std::vector<std::string> > idxNames = std::vector< std::vector<std::string> >();
+  int cleanup_split_level = intArg(args, 3);
+  myloop->unroll(stmt_num, level, unroll_amount, idxNames, cleanup_split_level);
+  Py_RETURN_NONE;
+}
+  
+static PyObject* chill_unroll_extra(PyObject* self, PyObject* args) {
+  int nargs = strict_arg_range(args, 3, 4, "unroll_extra");
+  int stmt_num = intArg(args, 0);
+  int level = intArg(args, 1);
+  int unroll_amount = intArg(args, 2);
+  int cleanup_split_level = intArg(args, 3, 0);
+  myloop->unroll_extra(stmt_num, level, unroll_amount, cleanup_split_level); 
+  Py_RETURN_NONE;
+}
+  
+static PyObject* chill_split(PyObject* self, PyObject* args) {
+  strict_arg_num(args, 3, "split");
+  int stmt_num = intArg(args, 0);
+  int level = intArg(args, 1);
+  int num_dim = myloop->stmt[stmt_num].xform.n_out();
+  
+  std::vector<std::map<std::string, int> >* cond;
+  std::string cond_expr = strArg(args, 2);
+  cond = parse_relation_vector(cond_expr.c_str());
+  
+  Relation rel((num_dim-1)/2);
+  F_And *f_root = rel.add_and();
+  for (int j = 0; j < cond->size(); j++) {
+    GEQ_Handle h = f_root->add_GEQ();
+    for (std::map<std::string, int>::iterator it = (*cond)[j].begin(); it != (*cond)[j].end(); it++) {
+      try {
+        int dim = from_string<int>(it->first);
+        if (dim == 0)
+          h.update_const(it->second);
+        else {
+          if (dim > (num_dim-1)/2)
+            throw std::invalid_argument("invalid loop level " + to_string(dim) + " in split condition");
+          h.update_coef(rel.set_var(dim), it->second);
+        }
+      }
+      catch (std::ios::failure e) {
+        Free_Var_Decl *g = NULL;
+        for (unsigned i = 0; i < myloop->freevar.size(); i++) {
+          std::string name = myloop->freevar[i]->base_name();
+          if (name == it->first) {
+            g = myloop->freevar[i];
+            break;
+          }
+        }
+        if (g == NULL)
+          throw std::invalid_argument("unrecognized variable " + to_string(it->first.c_str()));
+        h.update_coef(rel.get_local(g), it->second);
+      }
+    }
+  }
+  myloop->split(stmt_num,level,rel);
+  Py_RETURN_NONE;
+}
+
+static PyObject* chill_nonsingular(PyObject* self, PyObject* args) {
+  std::vector< std::vector<int> > mat;
+  tointmatrix(args, 0, mat);
+  myloop->nonsingular(mat);
+  Py_RETURN_NONE;
+}
+
+static PyObject* chill_skew(PyObject* self, PyObject* args) {
+  std::set<int> stmt_nums;
+  std::vector<int> skew_amounts;
+  int level = intArg(args, 1);
+  tointset(args, 0, stmt_nums);
+  tointvector(args, 2, skew_amounts);
+  myloop->skew(stmt_nums, level, skew_amounts);
+  Py_RETURN_NONE;
+}
+
+static PyObject* chill_scale(PyObject* self, PyObject* args) {
+  strict_arg_num(args, 3);
+  std::set<int> stmt_nums;
+  int level = intArg(args, 1);
+  int scale_amount = intArg(args, 2);
+  tointset(args, 0, stmt_nums);
+  myloop->scale(stmt_nums, level, scale_amount);
+  Py_RETURN_NONE;
+}
+
+static PyObject* chill_reverse(PyObject* self, PyObject* args) {
+  strict_arg_num(args, 2);
+  std::set<int> stmt_nums;
+  int level = intArg(args, 1);
+  tointset(args, 0, stmt_nums);
+  myloop->reverse(stmt_nums, level);
+  Py_RETURN_NONE;
+}
+
+static PyObject* chill_shift(PyObject* self, PyObject* args) {
+  strict_arg_num(args, 3);
+  std::set<int> stmt_nums;
+  int level = intArg(args, 1);
+  int shift_amount = intArg(args, 2);
+  tointset(args, 0, stmt_nums);
+  myloop->shift(stmt_nums, level, shift_amount);
+  Py_RETURN_NONE;
+}
+
+static PyObject* chill_shift_to(PyObject* self, PyObject* args) {
+  strict_arg_num(args, 3);
+  int stmt_num = intArg(args, 0);
+  int level = intArg(args, 1);
+  int absolute_pos = intArg(args, 2);
+  myloop->shift_to(stmt_num, level, absolute_pos);
+  Py_RETURN_NONE;
+}
+
+static PyObject* chill_peel(PyObject* self, PyObject* args) {
+  strict_arg_range(args, 2, 3);
+  int stmt_num = intArg(args, 0);
+  int level = intArg(args, 1);
+  int amount = intArg(args, 2);
+  myloop->peel(stmt_num, level, amount);
+  Py_RETURN_NONE;
+}
+
+static PyObject* chill_fuse(PyObject* self, PyObject* args) {
+  strict_arg_num(args, 2);
+  std::set<int> stmt_nums;
+  int level = intArg(args, 1);
+  tointset(args, 0, stmt_nums);
+  myloop->fuse(stmt_nums, level);
+  Py_RETURN_NONE;
+}
+
+static PyObject* chill_distribute(PyObject* self, PyObject* args) {
+  strict_arg_num(args, 2);
+  std::set<int> stmts;
+  int level = intArg(args, 1);
+  tointset(args, 0, stmts);
+  myloop->distribute(stmts, level);
+  Py_RETURN_NONE;
+}
+
+static PyObject *
+chill_num_statements(PyObject *self, PyObject *args)  
+{
+  //DEBUG_PRINT("\nC chill_num_statements() called from python\n"); 
+  int num = myloop->stmt.size();
+  //DEBUG_PRINT("C num_statement() = %d\n", num); 
+  return Py_BuildValue( "i", num ); // BEWARE "d" is DOUBLE, not int
+}
+
+static PyMethodDef ChillMethods[] = { 
+  
+  //python name           C routine                  parameter passing comment
+  {"source",              chill_source,                    METH_VARARGS,     "set source file for chill script"},
+  {"procedure",           chill_procedure,                 METH_VARARGS,     "set the name of the procedure"},
+  {"loop",                chill_loop,                      METH_VARARGS,     "indicate which loop to optimize"},
+  {"print_code",          chill_print_code,                METH_VARARGS,     "print generated code"},
+  {"print_dep",           chill_print_dep,                 METH_VARARGS,     "print the dependencies graph"},
+  {"print_space",         chill_print_space,               METH_VARARGS,     "print space"},
+  {"exit",                chill_exit,                      METH_VARARGS,     "exit the interactive consule"},
+  {"known",               chill_known,                     METH_VARARGS,     "knwon"},
+  {"remove_dep",          chill_remove_dep,                METH_VARARGS,     "remove dependency i suppose"},
+  {"original",            chill_original,                  METH_VARARGS,     "original"},
+  {"permute",             chill_permute,                   METH_VARARGS,     "permute"},
+  {"pragma",              chill_pragma,                    METH_VARARGS,     "pragma"},
+  {"prefetch",            chill_prefetch,                  METH_VARARGS,     "prefetch"},
+  {"tile",                chill_tile,                      METH_VARARGS,     "tile"},
+  {"datacopy",            chill_datacopy,                  METH_VARARGS,     "datacopy"},
+  {"datacopy_privitized", chill_datacopy_privatized,       METH_VARARGS,     "datacopy_privatized"},
+  {"unroll",              chill_unroll,                    METH_VARARGS,     "unroll"},
+  {"unroll_extra",        chill_unroll_extra,              METH_VARARGS,     "unroll_extra"},
+  {"split",               chill_split,                     METH_VARARGS,     "split"},
+  {"nonsingular",         chill_nonsingular,               METH_VARARGS,     "nonsingular"},
+  {"skew",                chill_skew,                      METH_VARARGS,     "skew"},
+  {"scale",               chill_scale,                     METH_VARARGS,     "scale"},
+  {"reverse",             chill_reverse,                   METH_VARARGS,     "reverse"},
+  {"shift",               chill_shift,                     METH_VARARGS,     "shift"},
+  {"shift_to",            chill_shift_to,                  METH_VARARGS,     "shift_to"},
+  {"peel",                chill_peel,                      METH_VARARGS,     "peel"},
+  {"fuse",                chill_fuse,                      METH_VARARGS,     "fuse"},
+  {"distribute",          chill_distribute,                METH_VARARGS,     "distribute"},
+  {"num_statements",      chill_num_statements,            METH_VARARGS,     "number of statements in the current loop"},
+  {NULL, NULL, 0, NULL}
+};
+
+static void register_globals(PyObject* m) {
+  // Preset globals
+  PyModule_AddStringConstant(m, "VERSION", CHILL_BUILD_VERSION);
+  PyModule_AddStringConstant(m, "dest", "C");
+  PyModule_AddStringConstant(m, "C", "C");
+  // Tile method
+  PyModule_AddIntConstant(m, "strided", 0);
+  PyModule_AddIntConstant(m, "counted", 1);
+  // Memory mode
+  PyModule_AddIntConstant(m, "global", 0);
+  PyModule_AddIntConstant(m, "shared", 1);
+  PyModule_AddIntConstant(m, "textured", 2);
+  // Bool flags
+  PyModule_AddIntConstant(m, "sync", 1);
+} 
+
+PyMODINIT_FUNC
+initchill(void)    // pass C methods to python 
+{
+  DEBUG_PRINT("in C, initchill() to set up C methods to be called from python\n");
+  PyObject* m = Py_InitModule("chill", ChillMethods);
+  register_globals(m);
+}
diff --git a/src/dep.cc b/src/dep.cc
new file mode 100644
index 0000000..a675d03
--- /dev/null
+++ b/src/dep.cc
@@ -0,0 +1,567 @@
+/*****************************************************************************
+ Copyright (C) 2008 University of Southern California
+ Copyright (C) 2009-2010 University of Utah
+ All Rights Reserved.
+
+ Purpose:
+ Data dependence vector and graph.
+
+ Notes:
+ All dependence vectors are normalized, i.e., the first non-zero distance
+ must be positve. Thus the correct dependence meaning can be given based on
+ source/destination pair's read/write type. Suppose for a dependence vector
+ 1, 0~5, -3), we want to permute the first and the second dimension,
+ the result would be two dependence vectors (0, 1, -3) and (1~5, 1, -3).
+ All operations on dependence vectors are non-destructive, i.e., new
+ dependence vectors are returned.
+
+ History:
+ 01/2006 Created by Chun Chen.
+ 03/2009 Use IR_Ref interface in source and destination arrays -chun
+*****************************************************************************/
+
+#include "dep.hh"
+
+//-----------------------------------------------------------------------------
+// Class: DependeceVector
+//-----------------------------------------------------------------------------
+
+std::ostream& operator<<(std::ostream &os, const DependenceVector &d) {
+  if (d.sym != NULL) {
+    os << d.sym->name();
+    os << ':';
+    if (d.quasi)
+      os << "_quasi";
+    
+  }
+  
+  switch (d.type) {
+  case DEP_W2R:
+    os << "true";
+    if (d.is_reduction)
+      os << "_reduction";
+    break;
+  case DEP_R2W:
+    os << "anti";
+    break;
+  case DEP_W2W:
+    os << "output";
+    break;
+  case DEP_R2R:
+    os << "input";
+    break;
+  case DEP_CONTROL:
+    os << "control";
+    break;
+  default:
+    os << "unknown";
+    break;
+  }
+  
+  os << '(';
+  
+  for (int i = 0; i < d.lbounds.size(); i++) {
+    omega::coef_t lbound = d.lbounds[i];
+    omega::coef_t ubound = d.ubounds[i];
+    
+    if (lbound == ubound)
+      os << lbound;
+    else {
+      if (lbound == -posInfinity)
+        if (ubound == posInfinity)
+          os << '*';
+        else {
+          if (ubound == -1)
+            os << '-';
+          else
+            os << ubound << '-';
+        }
+      else if (ubound == posInfinity) {
+        if (lbound == 1)
+          os << '+';
+        else
+          os << lbound << '+';
+      } else
+        os << lbound << '~' << ubound;
+    }
+    
+    if (i < d.lbounds.size() - 1)
+      os << ", ";
+  }
+  
+  os << ')';
+  
+  return os;
+}
+
+// DependenceVector::DependenceVector(int size):
+//   lbounds(std::vector<coef_t>(size, 0)),
+//   ubounds(std::vector<coef_t>(size, 0)) {
+//   src = NULL;
+//   dst = NULL;
+// }
+
+DependenceVector::DependenceVector(const DependenceVector &that) {
+  if (that.sym != NULL)
+    this->sym = that.sym->clone();
+  else
+    this->sym = NULL;
+  this->type = that.type;
+  this->lbounds = that.lbounds;
+  this->ubounds = that.ubounds;
+  quasi = that.quasi;
+  is_scalar_dependence = that.is_scalar_dependence;
+  is_reduction = that.is_reduction;
+}
+
+DependenceVector &DependenceVector::operator=(const DependenceVector &that) {
+  if (this != &that) {
+    delete this->sym;
+    if (that.sym != NULL)
+      this->sym = that.sym->clone();
+    else
+      this->sym = NULL;
+    this->type = that.type;
+    this->lbounds = that.lbounds;
+    this->ubounds = that.ubounds;
+    quasi = that.quasi;
+    is_scalar_dependence = that.is_scalar_dependence;
+    is_reduction = that.is_reduction;
+  }
+  return *this;
+}
+DependenceType DependenceVector::getType() const {
+  return type;
+}
+
+bool DependenceVector::is_data_dependence() const {
+  if (type == DEP_W2R || type == DEP_R2W || type == DEP_W2W
+      || type == DEP_R2R)
+    return true;
+  else
+    return false;
+}
+
+bool DependenceVector::is_control_dependence() const {
+  if (type == DEP_CONTROL)
+    return true;
+  else
+    return false;
+}
+
+bool DependenceVector::has_negative_been_carried_at(int dim) const {
+  if (!is_data_dependence())
+    throw std::invalid_argument("only works for data dependences");
+  
+  if (dim < 0 || dim >= lbounds.size())
+    return false;
+  
+  for (int i = 0; i < dim; i++)
+    if (lbounds[i] > 0 || ubounds[i] < 0)
+      return false;
+  
+  if (lbounds[dim] < 0)
+    return true;
+  else
+    return false;
+}
+
+
+bool DependenceVector::has_been_carried_at(int dim) const {
+  if (!is_data_dependence())
+    throw std::invalid_argument("only works for data dependences");
+  
+  if (dim < 0 || dim >= lbounds.size())
+    return false;
+  
+  for (int i = 0; i < dim; i++)
+    if (lbounds[i] > 0 || ubounds[i] < 0)
+      return false;
+  
+  if ((lbounds[dim] != 0)  || (ubounds[dim] !=0))
+    return true;
+  
+  return false;
+}
+
+bool DependenceVector::has_been_carried_before(int dim) const {
+  if (!is_data_dependence())
+    throw std::invalid_argument("only works for data dependences");
+  
+  if (dim < 0)
+    return false;
+  if (dim > lbounds.size())
+    dim = lbounds.size();
+  
+  for (int i = 0; i < dim; i++) {
+    if (lbounds[i] > 0)
+      return true;
+    if (ubounds[i] < 0)
+      return true;
+  }
+  
+  return false;
+}
+
+bool DependenceVector::isZero() const {
+  return isZero(lbounds.size() - 1);
+}
+
+bool DependenceVector::isZero(int dim) const {
+  if (dim >= lbounds.size())
+    throw std::invalid_argument("invalid dependence dimension");
+  
+  for (int i = 0; i <= dim; i++)
+    if (lbounds[i] != 0 || ubounds[i] != 0)
+      return false;
+  
+  return true;
+}
+
+bool DependenceVector::isPositive() const {
+  for (int i = 0; i < lbounds.size(); i++)
+    if (lbounds[i] != 0 || ubounds[i] != 0) {
+      if (lbounds[i] < 0)
+        return false;
+      else if (lbounds[i] > 0)
+        return true;
+    }
+  
+  return false;
+}
+
+bool DependenceVector::isNegative() const {
+  for (int i = 0; i < lbounds.size(); i++)
+    if (lbounds[i] != 0 || ubounds[i] != 0) {
+      if (ubounds[i] > 0)
+        return false;
+      else if (ubounds[i] < 0)
+        return true;
+    }
+  
+  return false;
+}
+
+bool DependenceVector::isAllPositive() const {
+  for (int i = 0; i < lbounds.size(); i++)
+    if (lbounds[i] < 0)
+      return false;
+  
+  return true;
+}
+
+bool DependenceVector::isAllNegative() const {
+  for (int i = 0; i < ubounds.size(); i++)
+    if (ubounds[i] > 0)
+      return false;
+  
+  return true;
+}
+
+bool DependenceVector::hasPositive(int dim) const {
+  if (dim >= lbounds.size())
+    throw std::invalid_argument("invalid dependence dimension");
+  
+  if (lbounds[dim] > 0)
+    //av: changed from ubounds to lbounds may have side effects
+    return true;
+  else
+    return false;
+}
+
+bool DependenceVector::hasNegative(int dim) const {
+  if (dim >= lbounds.size())
+    throw std::invalid_argument("invalid dependence dimension");
+  
+  if (ubounds[dim] < 0)
+    //av: changed from lbounds to ubounds may have side effects
+    return true;
+  else
+    return false;
+}
+
+bool DependenceVector::isCarried(int dim, omega::coef_t distance) const {
+  if (distance <= 0)
+    throw std::invalid_argument("invalid dependence distance size");
+  
+  if (dim > lbounds.size())
+    dim = lbounds.size();
+  
+  for (int i = 0; i < dim; i++)
+    if (lbounds[i] > 0)
+      return false;
+    else if (ubounds[i] < 0)
+      return false;
+  
+  if (dim >= lbounds.size())
+    return true;
+  
+  if (lbounds[dim] > distance)
+    return false;
+  else if (ubounds[dim] < -distance)
+    return false;
+  
+  return true;
+}
+
+bool DependenceVector::canPermute(const std::vector<int> &pi) const {
+  if (pi.size() != lbounds.size())
+    throw std::invalid_argument(
+      "permute dimensionality do not match dependence space");
+  
+  for (int i = 0; i < pi.size(); i++) {
+    if (lbounds[pi[i]] > 0)
+      return true;
+    else if (lbounds[pi[i]] < 0)
+      return false;
+  }
+  
+  return true;
+}
+
+std::vector<DependenceVector> DependenceVector::normalize() const {
+  std::vector<DependenceVector> result;
+  
+  DependenceVector dv(*this);
+  for (int i = 0; i < dv.lbounds.size(); i++) {
+    if (dv.lbounds[i] < 0 && dv.ubounds[i] >= 0) {
+      omega::coef_t t = dv.ubounds[i];
+      dv.ubounds[i] = -1;
+      result.push_back(dv);
+      dv.lbounds[i] = 0;
+      dv.ubounds[i] = t;
+    }
+    if (dv.lbounds[i] == 0 && dv.ubounds[i] > 0) {
+      dv.lbounds[i] = 1;
+      result.push_back(dv);
+      dv.lbounds[i] = 0;
+      dv.ubounds[i] = 0;
+    }
+    if (dv.lbounds[i] == 0 && dv.ubounds[i] == 0)
+      continue;
+    else
+      break;
+  }
+  
+  result.push_back(dv);
+  return result;
+}
+
+std::vector<DependenceVector> DependenceVector::permute(
+  const std::vector<int> &pi) const {
+  if (pi.size() != lbounds.size())
+    throw std::invalid_argument(
+      "permute dimensionality do not match dependence space");
+  
+  const int n = lbounds.size();
+  
+  DependenceVector dv(*this);
+  for (int i = 0; i < n; i++) {
+    dv.lbounds[i] = lbounds[pi[i]];
+    dv.ubounds[i] = ubounds[pi[i]];
+  }
+  
+  int violated = 0;
+  
+  for (int i = 0; i < n; i++) {
+    if (dv.lbounds[i] > 0)
+      break;
+    else if (dv.lbounds[i] < 0)
+      violated = 1;
+  }
+  
+  if (((violated == 1) && !quasi) && !is_scalar_dependence) {
+    throw ir_error("dependence violation");
+    
+  }
+  
+  return dv.normalize();
+}
+
+DependenceVector DependenceVector::reverse() const {
+  const int n = lbounds.size();
+  
+  DependenceVector dv(*this);
+  switch (type) {
+  case DEP_W2R:
+    dv.type = DEP_R2W;
+    break;
+  case DEP_R2W:
+    dv.type = DEP_W2R;
+    break;
+  default:
+    dv.type = type;
+  }
+  
+  for (int i = 0; i < n; i++) {
+    dv.lbounds[i] = -ubounds[i];
+    dv.ubounds[i] = -lbounds[i];
+  }
+  dv.quasi = true;
+  
+  return dv;
+}
+
+// std::vector<DependenceVector> DependenceVector::matrix(const std::vector<std::vector<int> > &M) const {
+//   if (M.size() != lbounds.size())
+//     throw std::invalid_argument("(non)unimodular transformation dimensionality does not match dependence space");
+
+//   const int n = lbounds.size();
+//   DependenceVector dv;
+//   if (sym != NULL)
+//     dv.sym = sym->clone();
+//   else
+//     dv.sym = NULL;
+//   dv.type = type;
+
+//   for (int i = 0; i < n; i++) {
+//     assert(M[i].size() == n+1 || M[i].size() == n);
+
+//     omega::coef_t lb, ub;
+//     if (M[i].size() == n+1)
+//       lb = ub = M[i][n];
+//     else
+//       lb = ub = 0;
+
+//     for (int j = 0; j < n; j++) {
+//       int c = M[i][j];
+//       if (c == 0)
+//         continue;
+
+//       if (c > 0) {
+//         if (lbounds[j] == -posInfinity)
+//           lb = -posInfinity;
+//         else if (lb != -posInfinity)
+//           lb += c * lbounds[j];
+//         if (ubounds[j] == posInfinity)
+//           ub = posInfinity;
+//         else if (ub != posInfinity)
+//           ub += c * ubounds[j];
+//       }
+//       else {
+//         if (ubounds[j] == posInfinity)
+//           lb = -posInfinity;
+//         else if (lb != -posInfinity)
+//           lb += c * ubounds[j];
+//         if (lbounds[j] == -posInfinity)
+//           ub = posInfinity;
+//         else if (ub != posInfinity)
+//           ub += c * lbounds[j];
+//       }
+//     }
+//     dv.lbounds.push_back(lb);
+//     dv.ubounds.push_back(ub);
+//   }
+//   dv.is_reduction = is_reduction;
+
+//   return dv.normalize();
+// }
+
+//-----------------------------------------------------------------------------
+// Class: DependenceGraph
+//-----------------------------------------------------------------------------
+
+DependenceGraph DependenceGraph::permute(const std::vector<int> &pi,
+                                         const std::set<int> &active) const {
+  DependenceGraph g;
+  
+  for (int i = 0; i < vertex.size(); i++)
+    g.insert(vertex[i].first);
+  
+  for (int i = 0; i < vertex.size(); i++)
+    for (EdgeList::const_iterator j = vertex[i].second.begin();
+         j != vertex[i].second.end(); j++) {
+      if (active.empty()
+          || (active.find(i) != active.end()
+              && active.find(j->first) != active.end())) {
+        for (int k = 0; k < j->second.size(); k++) {
+          std::vector<DependenceVector> dv = j->second[k].permute(pi);
+          g.connect(i, j->first, dv);
+        }
+      } else if (active.find(i) == active.end()
+                 && active.find(j->first) == active.end()) {
+        std::vector<DependenceVector> dv = j->second;
+        g.connect(i, j->first, dv);
+      } else {
+        std::vector<DependenceVector> dv = j->second;
+        for (int k = 0; k < dv.size(); k++)
+          for (int d = 0; d < pi.size(); d++)
+            if (pi[d] != d) {
+              dv[k].lbounds[d] = -posInfinity;
+              dv[k].ubounds[d] = posInfinity;
+            }
+        g.connect(i, j->first, dv);
+      }
+    }
+  
+  return g;
+}
+
+// DependenceGraph DependenceGraph::matrix(const std::vector<std::vector<int> > &M) const {
+//   DependenceGraph g;
+
+//   for (int i = 0; i < vertex.size(); i++)
+//     g.insert(vertex[i].first);
+
+//   for (int i = 0; i < vertex.size(); i++)
+//     for (EdgeList::const_iterator j = vertex[i].second.begin(); j != vertex[i].second.end(); j++)
+//       for (int k = 0; k < j->second.size(); k++)
+//         g.connect(i, j->first, j->second[k].matrix(M));
+
+//   return g;
+// }
+
+DependenceGraph DependenceGraph::subspace(int dim) const {
+  DependenceGraph g;
+  
+  for (int i = 0; i < vertex.size(); i++)
+    g.insert(vertex[i].first);
+  
+  for (int i = 0; i < vertex.size(); i++)
+    for (EdgeList::const_iterator j = vertex[i].second.begin();
+         j != vertex[i].second.end(); j++)
+      
+      for (int k = 0; k < j->second.size(); k++) {
+        if(j->second[k].type != DEP_CONTROL){
+          if (j->second[k].isCarried(dim))
+            g.connect(i, j->first, j->second[k]);
+        }else
+          g.connect(i, j->first, j->second[k]);
+        
+      }
+  
+  return g;
+}
+
+bool DependenceGraph::isPositive() const {
+  for (int i = 0; i < vertex.size(); i++)
+    for (EdgeList::const_iterator j = vertex[i].second.begin();
+         j != vertex[i].second.end(); j++)
+      for (int k = 0; k < j->second.size(); k++)
+        if (!j->second[k].isPositive())
+          return false;
+  
+  return true;
+}
+
+bool DependenceGraph::hasPositive(int dim) const {
+  for (int i = 0; i < vertex.size(); i++)
+    for (EdgeList::const_iterator j = vertex[i].second.begin();
+         j != vertex[i].second.end(); j++)
+      for (int k = 0; k < j->second.size(); k++)
+        if (!j->second[k].hasPositive(dim))
+          return false;
+  
+  return true;
+}
+
+bool DependenceGraph::hasNegative(int dim) const {
+  for (int i = 0; i < vertex.size(); i++)
+    for (EdgeList::const_iterator j = vertex[i].second.begin();
+         j != vertex[i].second.end(); j++)
+      for (int k = 0; k < j->second.size(); k++)
+        if (!j->second[k].hasNegative(dim))
+          return false;
+  
+  return true;
+}
diff --git a/src/ir_rose.cc b/src/ir_rose.cc
new file mode 100644
index 0000000..dc3eed8
--- /dev/null
+++ b/src/ir_rose.cc
@@ -0,0 +1,1756 @@
+/*****************************************************************************
+ Copyright (C) 2009-2010 University of Utah
+ All Rights Reserved.
+
+ Purpose:
+ CHiLL's rose interface.
+
+ Notes:
+ Array supports mixed pointer and array type in a single declaration.
+
+ History:
+ 02/23/2009 Created by Chun Chen.
+*****************************************************************************/
+#include <string>
+#include "ir_rose.hh"
+#include "ir_rose_utils.hh"
+#include "rose_attributes.h"
+#include "CG_roseRepr.h"
+#include "CG_roseBuilder.h"
+
+using namespace SageBuilder;
+using namespace SageInterface;
+using namespace omega;
+// ----------------------------------------------------------------------------
+// Class: IR_roseScalarSymbol
+// ----------------------------------------------------------------------------
+
+std::string IR_roseScalarSymbol::name() const {
+  return vs_->get_name().getString();
+}
+
+int IR_roseScalarSymbol::size() const {
+  return (vs_->get_type()->memoryUsage()) / (vs_->get_type()->numberOfNodes());
+}
+
+bool IR_roseScalarSymbol::operator==(const IR_Symbol &that) const {
+  if (typeid(*this) != typeid(that))
+    return false;
+  
+  const IR_roseScalarSymbol *l_that =
+    static_cast<const IR_roseScalarSymbol *>(&that);
+  return this->vs_ == l_that->vs_;
+}
+
+IR_Symbol *IR_roseScalarSymbol::clone() const {
+  return NULL;
+}
+
+// ----------------------------------------------------------------------------
+// Class: IR_roseArraySymbol
+// ----------------------------------------------------------------------------
+
+std::string IR_roseArraySymbol::name() const {
+  return (vs_->get_declaration()->get_name().getString());
+}
+
+int IR_roseArraySymbol::elem_size() const {
+  
+  SgType *tn = vs_->get_type();
+  SgType* arrType;
+  
+  int elemsize;
+  
+  if (arrType = isSgArrayType(tn)) {
+    while (isSgArrayType(arrType)) {
+      arrType = arrType->findBaseType();
+    }
+  } else if (arrType = isSgPointerType(tn)) {
+    while (isSgPointerType(arrType)) {
+      arrType = arrType->findBaseType();
+    }
+  }
+  
+  elemsize = (int) arrType->memoryUsage() / arrType->numberOfNodes();
+  return elemsize;
+}
+
+int IR_roseArraySymbol::n_dim() const {
+  int dim = 0;
+  SgType* arrType = isSgArrayType(vs_->get_type());
+  SgType* ptrType = isSgPointerType(vs_->get_type());
+  if (arrType != NULL) {
+    while (isSgArrayType(arrType)) {
+      arrType = isSgArrayType(arrType)->get_base_type();
+      dim++;
+    }
+  } else if (ptrType != NULL) {
+    while (isSgPointerType(ptrType)) {
+      ptrType = isSgPointerType(ptrType)->get_base_type();
+      dim++;
+    }
+  }
+
+  // Manu:: fortran support
+  if (static_cast<const IR_roseCode *>(ir_)->is_fortran_) {
+
+	  if (arrType != NULL) {
+		  dim = 0;
+		  SgExprListExp * dimList = isSgArrayType(vs_->get_type())->get_dim_info();
+		  SgExpressionPtrList::iterator it = dimList->get_expressions().begin();
+		  for(;it != dimList->get_expressions().end(); it++) {
+		    dim++;
+		  }
+	  } else if (ptrType != NULL) {
+		  //std::cout << "pntrType \n";
+		  ; // not sure if this case will happen
+	  }
+  }
+
+  return dim;
+}
+
+omega::CG_outputRepr *IR_roseArraySymbol::size(int dim) const {
+  
+  SgArrayType* arrType = isSgArrayType(vs_->get_type());
+  // SgExprListExp* dimList = arrType->get_dim_info();
+  int count = 0;
+  SgExpression* expr;
+  SgType* pntrType = isSgPointerType(vs_->get_type());
+  
+  if (arrType != NULL) {
+    SgExprListExp* dimList = arrType->get_dim_info();
+    if (!static_cast<const IR_roseCode *>(ir_)->is_fortran_) {
+      SgExpressionPtrList::iterator it =
+        dimList->get_expressions().begin();
+      
+      while ((it != dimList->get_expressions().end()) && (count < dim)) {
+        it++;
+        count++;
+      }
+      
+      expr = *it;
+    } else {
+      SgExpressionPtrList::reverse_iterator i =
+        dimList->get_expressions().rbegin();
+      for (; (i != dimList->get_expressions().rend()) && (count < dim);
+           i++) {
+        
+        count++;
+      }
+      
+      expr = *i;
+    }
+  } else if (pntrType != NULL) {
+    
+    while (count < dim) {
+      pntrType = (isSgPointerType(pntrType))->get_base_type();
+      count++;
+    }
+    if (isSgPointerType(pntrType))
+      expr = new SgExpression;
+  }
+  
+  if (!expr)
+    throw ir_error("Index variable is NULL!!");
+  
+  // Manu :: debug
+  std::cout << "---------- size :: " << isSgNode(expr)->unparseToString().c_str() << "\n";
+
+  return new omega::CG_roseRepr(expr);
+  
+}
+
+IR_ARRAY_LAYOUT_TYPE IR_roseArraySymbol::layout_type() const {
+  if (static_cast<const IR_roseCode *>(ir_)->is_fortran_)
+    return IR_ARRAY_LAYOUT_COLUMN_MAJOR;
+  else
+    return IR_ARRAY_LAYOUT_ROW_MAJOR;
+  
+}
+
+bool IR_roseArraySymbol::operator==(const IR_Symbol &that) const {
+  
+  if (typeid(*this) != typeid(that))
+    return false;
+  
+  const IR_roseArraySymbol *l_that =
+    static_cast<const IR_roseArraySymbol *>(&that);
+  return this->vs_ == l_that->vs_;
+  
+}
+
+IR_Symbol *IR_roseArraySymbol::clone() const {
+  return new IR_roseArraySymbol(ir_, vs_);
+}
+
+// ----------------------------------------------------------------------------
+// Class: IR_roseConstantRef
+// ----------------------------------------------------------------------------
+
+bool IR_roseConstantRef::operator==(const IR_Ref &that) const {
+  
+  if (typeid(*this) != typeid(that))
+    return false;
+  
+  const IR_roseConstantRef *l_that =
+    static_cast<const IR_roseConstantRef *>(&that);
+  
+  if (this->type_ != l_that->type_)
+    return false;
+  
+  if (this->type_ == IR_CONSTANT_INT)
+    return this->i_ == l_that->i_;
+  else
+    return this->f_ == l_that->f_;
+  
+}
+
+omega::CG_outputRepr *IR_roseConstantRef::convert() {
+  if (type_ == IR_CONSTANT_INT) {
+    omega::CG_roseRepr *result = new omega::CG_roseRepr(
+      isSgExpression(buildIntVal(static_cast<int>(i_))));
+    delete this;
+    return result;
+  } else
+    throw ir_error("constant type not supported");
+  
+}
+
+IR_Ref *IR_roseConstantRef::clone() const {
+  if (type_ == IR_CONSTANT_INT)
+    return new IR_roseConstantRef(ir_, i_);
+  else if (type_ == IR_CONSTANT_FLOAT)
+    return new IR_roseConstantRef(ir_, f_);
+  else
+    throw ir_error("constant type not supported");
+  
+}
+
+// ----------------------------------------------------------------------------
+// Class: IR_roseScalarRef
+// ----------------------------------------------------------------------------
+
+bool IR_roseScalarRef::is_write() const {
+  if (is_write_ == 1)
+    return true;
+  
+  return false;
+}
+
+IR_ScalarSymbol *IR_roseScalarRef::symbol() const {
+  return new IR_roseScalarSymbol(ir_, vs_->get_symbol());
+}
+
+bool IR_roseScalarRef::operator==(const IR_Ref &that) const {
+  if (typeid(*this) != typeid(that))
+    return false;
+  
+  const IR_roseScalarRef *l_that =
+    static_cast<const IR_roseScalarRef *>(&that);
+  
+  if (this->ins_pos_ == NULL)
+    return this->vs_ == l_that->vs_;
+  else
+    return this->ins_pos_ == l_that->ins_pos_
+      && this->op_pos_ == l_that->op_pos_;
+}
+
+omega::CG_outputRepr *IR_roseScalarRef::convert() {
+  omega::CG_roseRepr *result = new omega::CG_roseRepr(isSgExpression(vs_));
+  delete this;
+  return result;
+  
+}
+
+IR_Ref * IR_roseScalarRef::clone() const {
+  return new IR_roseScalarRef(ir_, vs_, this->is_write_);
+}
+
+// ----------------------------------------------------------------------------
+// Class: IR_roseArrayRef
+// ----------------------------------------------------------------------------
+
+bool IR_roseArrayRef::is_write() const {
+  SgAssignOp* assignment;
+  
+  if (is_write_ == 1 || is_write_ == 0)
+    return is_write_;
+  if (assignment = isSgAssignOp(ia_->get_parent())) {
+    if (assignment->get_lhs_operand() == ia_)
+      return true;
+  } else if (SgExprStatement* expr_stmt = isSgExprStatement(
+               ia_->get_parent())) {
+    SgExpression* exp = expr_stmt->get_expression();
+    
+    if (exp) {
+      if (assignment = isSgAssignOp(exp)) {
+        if (assignment->get_lhs_operand() == ia_)
+          return true;
+        
+      }
+    }
+    
+  }
+  return false;
+}
+
+omega::CG_outputRepr *IR_roseArrayRef::index(int dim) const {
+  
+  SgExpression *current = isSgExpression(ia_);
+  SgExpression* expr;
+  int count = 0;
+  
+  while (isSgPntrArrRefExp(current)) {
+    current = isSgPntrArrRefExp(current)->get_lhs_operand();
+    count++;
+  }
+  
+  current = ia_;
+  
+  while (count > dim) {
+    expr = isSgPntrArrRefExp(current)->get_rhs_operand();
+    current = isSgPntrArrRefExp(current)->get_lhs_operand();
+    count--;
+  }
+
+  // Manu:: fortran support
+  if (static_cast<const IR_roseCode *>(ir_)->is_fortran_) {
+	  expr = isSgPntrArrRefExp(ia_)->get_rhs_operand();
+	  count = 0;
+	  if (isSgExprListExp(expr)) {
+		  SgExpressionPtrList::iterator indexList = isSgExprListExp(expr)->get_expressions().begin();
+		  while (count < dim) {
+			  indexList++;
+			  count++;
+		  }
+		  expr = isSgExpression(*indexList);
+	  }
+  }
+
+  if (!expr)
+    throw ir_error("Index variable is NULL!!");
+
+
+  omega::CG_roseRepr* ind = new omega::CG_roseRepr(expr);
+  
+  return ind->clone();
+  
+}
+
+IR_ArraySymbol *IR_roseArrayRef::symbol() const {
+  
+  SgExpression *current = isSgExpression(ia_);
+  
+  SgVarRefExp* base;
+  SgVariableSymbol *arrSymbol;
+  while (isSgPntrArrRefExp(current) || isSgUnaryOp(current)) {
+    if (isSgPntrArrRefExp(current))
+      current = isSgPntrArrRefExp(current)->get_lhs_operand();
+    else if (isSgUnaryOp(current))
+      /* To handle support for addressof operator and pointer dereference
+       * both of which are unary ops
+       */
+      current = isSgUnaryOp(current)->get_operand();
+  }
+  if (base = isSgVarRefExp(current)) {
+    arrSymbol = (SgVariableSymbol*) (base->get_symbol());
+    std::string x = arrSymbol->get_name().getString();
+  } else
+    throw ir_error("Array Symbol is not a variable?!");
+  
+  return new IR_roseArraySymbol(ir_, arrSymbol);
+  
+}
+
+bool IR_roseArrayRef::operator==(const IR_Ref &that) const {
+  if (typeid(*this) != typeid(that))
+    return false;
+  
+  const IR_roseArrayRef *l_that = static_cast<const IR_roseArrayRef *>(&that);
+  
+  return this->ia_ == l_that->ia_;
+}
+
+omega::CG_outputRepr *IR_roseArrayRef::convert() {
+  omega::CG_roseRepr *temp = new omega::CG_roseRepr(
+    isSgExpression(this->ia_));
+  omega::CG_outputRepr *result = temp->clone();
+//  delete this;   // Commented by Manu
+  return result;
+}
+
+IR_Ref *IR_roseArrayRef::clone() const {
+  return new IR_roseArrayRef(ir_, ia_, is_write_);
+}
+
+// ----------------------------------------------------------------------------
+// Class: IR_roseLoop
+// ----------------------------------------------------------------------------
+
+IR_ScalarSymbol *IR_roseLoop::index() const {
+  SgForStatement *tf = isSgForStatement(tf_);
+  SgFortranDo *tfortran = isSgFortranDo(tf_);
+  SgVariableSymbol* vs = NULL;
+  if (tf) {
+    SgForInitStatement* list = tf->get_for_init_stmt();
+    SgStatementPtrList& initStatements = list->get_init_stmt();
+    SgStatementPtrList::const_iterator j = initStatements.begin();
+    
+    if (SgExprStatement *expr = isSgExprStatement(*j))
+      if (SgAssignOp* op = isSgAssignOp(expr->get_expression()))
+        if (SgVarRefExp* var_ref = isSgVarRefExp(op->get_lhs_operand()))
+          vs = var_ref->get_symbol();
+  } else if (tfortran) {
+    SgExpression* init = tfortran->get_initialization();
+    
+    if (SgAssignOp* op = isSgAssignOp(init))
+      if (SgVarRefExp* var_ref = isSgVarRefExp(op->get_lhs_operand()))
+        vs = var_ref->get_symbol();
+    
+  }
+  
+  if (vs == NULL)
+    throw ir_error("Index variable is NULL!!");
+  
+  return new IR_roseScalarSymbol(ir_, vs);
+}
+
+omega::CG_outputRepr *IR_roseLoop::lower_bound() const {
+  SgForStatement *tf = isSgForStatement(tf_);
+  SgFortranDo *tfortran = isSgFortranDo(tf_);
+  
+  SgExpression* lowerBound = NULL;
+  
+  if (tf) {
+    SgForInitStatement* list = tf->get_for_init_stmt();
+    SgStatementPtrList& initStatements = list->get_init_stmt();
+    SgStatementPtrList::const_iterator j = initStatements.begin();
+    
+    if (SgExprStatement *expr = isSgExprStatement(*j))
+      if (SgAssignOp* op = isSgAssignOp(expr->get_expression())) {
+        lowerBound = op->get_rhs_operand();
+        //Rose sometimes introduces an unnecessary cast which is a unary op
+        if (isSgUnaryOp(lowerBound))
+          lowerBound = isSgUnaryOp(lowerBound)->get_operand();
+        
+      }
+  } else if (tfortran) {
+    SgExpression* init = tfortran->get_initialization();
+    
+    if (SgAssignOp* op = isSgAssignOp(init))
+      lowerBound = op->get_rhs_operand();
+  }
+  
+  if (lowerBound == NULL)
+    throw ir_error("Lower Bound is NULL!!");
+  
+  return new omega::CG_roseRepr(lowerBound);
+}
+
+omega::CG_outputRepr *IR_roseLoop::upper_bound() const {
+  SgForStatement *tf = isSgForStatement(tf_);
+  SgFortranDo *tfortran = isSgFortranDo(tf_);
+  SgExpression* upperBound = NULL;
+  if (tf) {
+    SgBinaryOp* test_expr = isSgBinaryOp(tf->get_test_expr());
+    if (test_expr == NULL)
+      throw ir_error("Test Expression is NULL!!");
+    
+    upperBound = test_expr->get_rhs_operand();
+    //Rose sometimes introduces an unnecessary cast which is a unary op
+    if (isSgUnaryOp(upperBound))
+      upperBound = isSgUnaryOp(upperBound)->get_operand();
+    if (upperBound == NULL)
+      throw ir_error("Upper Bound is NULL!!");
+  } else if (tfortran) {
+    
+    upperBound = tfortran->get_bound();
+    
+  }
+  
+  return new omega::CG_roseRepr(upperBound);
+  
+}
+
+IR_CONDITION_TYPE IR_roseLoop::stop_cond() const {
+  SgForStatement *tf = isSgForStatement(tf_);
+  SgFortranDo *tfortran = isSgFortranDo(tf_);
+  
+  if (tf) {
+    SgExpression* stopCond = NULL;
+    SgExpression* test_expr = tf->get_test_expr();
+    
+    if (isSgLessThanOp(test_expr))
+      return IR_COND_LT;
+    else if (isSgLessOrEqualOp(test_expr))
+      return IR_COND_LE;
+    else if (isSgGreaterThanOp(test_expr))
+      return IR_COND_GT;
+    else if (isSgGreaterOrEqualOp(test_expr))
+      return IR_COND_GE;
+    
+    else
+      throw ir_error("loop stop condition unsupported");
+  } else if (tfortran) {
+    SgExpression* increment = tfortran->get_increment();
+    if (!isSgNullExpression(increment)) {
+      if (isSgMinusOp(increment)
+          && !isSgBinaryOp(isSgMinusOp(increment)->get_operand()))
+        return IR_COND_GE;
+      else
+        return IR_COND_LE;
+    } else {
+    	return IR_COND_LE; // Manu:: if increment is not present, assume it to be 1. Just a workaround, not sure if it will be correct for all cases.
+      SgExpression* lowerBound = NULL;
+      SgExpression* upperBound = NULL;
+      SgExpression* init = tfortran->get_initialization();
+      SgIntVal* ub;
+      SgIntVal* lb;
+      if (SgAssignOp* op = isSgAssignOp(init))
+        lowerBound = op->get_rhs_operand();
+      
+      upperBound = tfortran->get_bound();
+      
+      if ((upperBound != NULL) && (lowerBound != NULL)) {
+        
+        if ((ub = isSgIntVal(isSgValueExp(upperBound))) && (lb =
+                                                            isSgIntVal(isSgValueExp(lowerBound)))) {
+          if (ub->get_value() > lb->get_value())
+            return IR_COND_LE;
+          else
+            return IR_COND_GE;
+        } else
+          throw ir_error("loop stop condition unsupported");
+        
+      } else
+        throw ir_error("malformed fortran loop bounds!!");
+      
+    }
+  }
+  
+}
+
+IR_Block *IR_roseLoop::body() const {
+  SgForStatement *tf = isSgForStatement(tf_);
+  SgFortranDo *tfortran = isSgFortranDo(tf_);
+  SgNode* loop_body = NULL;
+  SgStatement* body_statements = NULL;
+  
+  if (tf) {
+    body_statements = tf->get_loop_body();
+  } else if (tfortran) {
+    body_statements = isSgStatement(tfortran->get_body());
+    
+  }
+  
+  loop_body = isSgNode(body_statements);
+  
+  SgStatementPtrList list;
+  if (isSgBasicBlock(loop_body)) {
+    list = isSgBasicBlock(loop_body)->get_statements();
+    
+    if (list.size() == 1)
+      loop_body = isSgNode(*(list.begin()));
+  }
+  
+  if (loop_body == NULL)
+    throw ir_error("for loop body is NULL!!");
+  
+  return new IR_roseBlock(ir_, loop_body);
+}
+
+int IR_roseLoop::step_size() const {
+  
+  SgForStatement *tf = isSgForStatement(tf_);
+  SgFortranDo *tfortran = isSgFortranDo(tf_);
+  
+  if (tf) {
+    SgExpression *increment = tf->get_increment();
+    
+    if (isSgPlusPlusOp(increment))
+      return 1;
+    if (isSgMinusMinusOp(increment))
+      return -1;
+    else if (SgAssignOp* assignment = isSgAssignOp(increment)) {
+      SgBinaryOp* stepsize = isSgBinaryOp(assignment->get_lhs_operand());
+      if (stepsize == NULL)
+        throw ir_error("Step size expression is NULL!!");
+      SgIntVal* step = isSgIntVal(stepsize->get_lhs_operand());
+      return step->get_value();
+    } else if (SgBinaryOp* inc = isSgPlusAssignOp(increment)) {
+      SgIntVal* step = isSgIntVal(inc->get_rhs_operand());
+      return (step->get_value());
+    } else if (SgBinaryOp * inc = isSgMinusAssignOp(increment)) {
+      SgIntVal* step = isSgIntVal(inc->get_rhs_operand());
+      return -(step->get_value());
+    } else if (SgBinaryOp * inc = isSgCompoundAssignOp(increment)) {
+      SgIntVal* step = isSgIntVal(inc->get_rhs_operand());
+      return (step->get_value());
+    }
+    
+  } else if (tfortran) {
+    
+    SgExpression* increment = tfortran->get_increment();
+    
+    if (!isSgNullExpression(increment)) {
+      if (isSgMinusOp(increment)) {
+        if (SgValueExp *inc = isSgValueExp(
+              isSgMinusOp(increment)->get_operand()))
+          if (isSgIntVal(inc))
+            return -(isSgIntVal(inc)->get_value());
+      } else {
+        if (SgValueExp* inc = isSgValueExp(increment))
+          if (isSgIntVal(inc))
+            return isSgIntVal(inc)->get_value();
+      }
+    } else {
+    	return 1; // Manu:: if increment is not present, assume it to be 1. Just a workaround, not sure if it will be correct for all cases.
+      SgExpression* lowerBound = NULL;
+      SgExpression* upperBound = NULL;
+      SgExpression* init = tfortran->get_initialization();
+      SgIntVal* ub;
+      SgIntVal* lb;
+      if (SgAssignOp* op = isSgAssignOp(init))
+        lowerBound = op->get_rhs_operand();
+      
+      upperBound = tfortran->get_bound();
+      
+      if ((upperBound != NULL) && (lowerBound != NULL)) {
+        
+        if ((ub = isSgIntVal(isSgValueExp(upperBound))) && (lb =
+                                                            isSgIntVal(isSgValueExp(lowerBound)))) {
+          if (ub->get_value() > lb->get_value())
+            return 1;
+          else
+            return -1;
+        } else
+          throw ir_error("loop stop condition unsupported");
+        
+      } else
+        throw ir_error("loop stop condition unsupported");
+      
+    }
+    
+  }
+  
+}
+
+IR_Block *IR_roseLoop::convert() {
+  const IR_Code *ir = ir_;
+  SgNode *tnl = isSgNode(tf_);
+  delete this;
+  return new IR_roseBlock(ir, tnl);
+}
+
+IR_Control *IR_roseLoop::clone() const {
+  
+  return new IR_roseLoop(ir_, tf_);
+  
+}
+
+// ----------------------------------------------------------------------------
+// Class: IR_roseBlock
+// ----------------------------------------------------------------------------
+
+omega::CG_outputRepr *IR_roseBlock::original() const {
+  
+  omega::CG_outputRepr * tnl;
+  
+  if (isSgBasicBlock(tnl_)) {
+    
+    SgStatementPtrList *bb = new SgStatementPtrList();
+    SgStatementPtrList::iterator it;
+    for (it = (isSgBasicBlock(tnl_)->get_statements()).begin();
+         it != (isSgBasicBlock(tnl_)->get_statements()).end()
+           && (*it != start_); it++)
+      ;
+    
+    if (it != (isSgBasicBlock(tnl_)->get_statements()).end()) {
+      for (; it != (isSgBasicBlock(tnl_)->get_statements()).end(); it++) {
+        bb->push_back(*it);
+        if ((*it) == end_)
+          break;
+      }
+    }
+    tnl = new omega::CG_roseRepr(bb);
+
+  } else {
+
+    tnl = new omega::CG_roseRepr(tnl_);
+
+  }
+  
+  return tnl;
+  
+}
+omega::CG_outputRepr *IR_roseBlock::extract() const {
+  
+  std::string x = tnl_->unparseToString();
+  
+  omega::CG_roseRepr * tnl;
+  
+  omega::CG_outputRepr* block;
+  
+  if (isSgBasicBlock(tnl_)) {
+    
+    SgStatementPtrList *bb = new SgStatementPtrList();
+    SgStatementPtrList::iterator it;
+    for (it = (isSgBasicBlock(tnl_)->get_statements()).begin();
+         it != (isSgBasicBlock(tnl_)->get_statements()).end()
+           && (*it != start_); it++)
+      ;
+    
+    if (it != (isSgBasicBlock(tnl_)->get_statements()).end()) {
+      for (; it != (isSgBasicBlock(tnl_)->get_statements()).end(); it++) {
+        bb->push_back(*it);
+        if ((*it) == end_)
+          break;
+      }
+    }
+    tnl = new omega::CG_roseRepr(bb);
+    block = tnl->clone();
+    
+  } else {
+    tnl = new omega::CG_roseRepr(tnl_);
+    
+    block = tnl->clone();
+  }
+  
+  delete tnl;
+  return block;
+}
+
+IR_Control *IR_roseBlock::clone() const {
+  return new IR_roseBlock(ir_, tnl_, start_, end_);
+  
+}
+// ----------------------------------------------------------------------------
+// Class: IR_roseIf
+// ----------------------------------------------------------------------------
+omega::CG_outputRepr *IR_roseIf::condition() const {
+  SgNode *tnl = isSgNode(isSgIfStmt(ti_)->get_conditional());
+  SgExpression* exp = NULL;
+  if (SgExprStatement* stmt = isSgExprStatement(tnl))
+    exp = stmt->get_expression();
+  if (exp == NULL)
+    return new omega::CG_roseRepr(tnl);
+  else
+    return new omega::CG_roseRepr(exp);
+}
+
+IR_Block *IR_roseIf::then_body() const {
+  SgNode *tnl = isSgNode(isSgIfStmt(ti_)->get_true_body());
+  
+  if (tnl == NULL)
+    return NULL;
+  
+  return new IR_roseBlock(ir_, tnl);
+}
+
+IR_Block *IR_roseIf::else_body() const {
+  SgNode *tnl = isSgNode(isSgIfStmt(ti_)->get_false_body());
+  
+  if (tnl == NULL)
+    return NULL;
+  
+  return new IR_roseBlock(ir_, tnl);
+}
+
+IR_Block *IR_roseIf::convert() {
+  const IR_Code *ir = ir_;
+  delete this;
+  return new IR_roseBlock(ir, ti_);
+}
+
+IR_Control *IR_roseIf::clone() const {
+  return new IR_roseIf(ir_, ti_);
+}
+
+// -----------------------------------------------------------y-----------------
+// Class: IR_roseCode_Global_Init
+// ----------------------------------------------------------------------------
+
+IR_roseCode_Global_Init *IR_roseCode_Global_Init::pinstance = 0;
+
+IR_roseCode_Global_Init * IR_roseCode_Global_Init::Instance(char** argv) {
+  if (pinstance == 0) {
+    pinstance = new IR_roseCode_Global_Init;
+    pinstance->project = frontend(2, argv);
+    
+  }
+  return pinstance;
+}
+
+// ----------------------------------------------------------------------------
+// Class: IR_roseCode
+// ----------------------------------------------------------------------------
+
+IR_roseCode::IR_roseCode(const char *filename, const char* proc_name) :
+  IR_Code() {
+  
+  SgProject* project;
+  
+  char* argv[2];
+  int counter = 0;
+  argv[0] = (char*) malloc(5 * sizeof(char));
+  argv[1] = (char*) malloc((strlen(filename) + 1) * sizeof(char));
+  strcpy(argv[0], "rose");
+  strcpy(argv[1], filename);
+  
+  project = (IR_roseCode_Global_Init::Instance(argv))->project;
+  firstScope = getFirstGlobalScope(project);
+  SgFilePtrList& file_list = project->get_fileList();
+  
+  for (SgFilePtrList::iterator it = file_list.begin(); it != file_list.end();
+       it++) {
+    file = isSgSourceFile(*it);
+    if (file->get_outputLanguage() == SgFile::e_Fortran_output_language)
+      is_fortran_ = true;
+    else
+      is_fortran_ = false;
+
+    root = file->get_globalScope();
+
+    if (!is_fortran_) { // Manu:: this macro should not be created if the input code is in fortran
+    	buildCpreprocessorDefineDeclaration(root,
+                                        "#define __rose_lt(x,y) ((x)<(y)?(x):(y))",
+                                        PreprocessingInfo::before);
+    	buildCpreprocessorDefineDeclaration(root,
+                                        "#define __rose_gt(x,y) ((x)>(y)?(x):(y))",
+                                        PreprocessingInfo::before);
+    }
+    
+    symtab_ = isSgScopeStatement(root)->get_symbol_table();
+    SgDeclarationStatementPtrList& declList = root->get_declarations();
+    
+    p = declList.begin();
+
+    while (p != declList.end()) {
+      func = isSgFunctionDeclaration(*p);
+      if (func) {
+        if (!strcmp((func->get_name().getString()).c_str(), proc_name))
+          break;
+        
+      }
+      p++;
+      counter++;
+    }
+    if (p != declList.end())
+      break;
+    
+  }
+  
+  symtab2_ = func->get_definition()->get_symbol_table();
+  symtab3_ = func->get_definition()->get_body()->get_symbol_table();
+  // Manu:: added is_fortran_ parameter
+  // TODO Substitute it with a better builder
+  ocg_ = new omega::CG_roseBuilder(is_fortran_, root, firstScope,
+                                   func->get_definition()->get_symbol_table(),
+                                   func->get_definition()->get_body()->get_symbol_table(),
+                                   isSgNode(func->get_definition()->get_body()));
+  
+  i_ = 0; /*i_ handling may need revision */
+  
+  free(argv[1]);
+  free(argv[0]);
+  
+}
+
+IR_roseCode::~IR_roseCode() {
+}
+
+void IR_roseCode::finalizeRose() {
+  SgProject* project = (IR_roseCode_Global_Init::Instance(NULL))->project;
+  project->unparse();
+}
+
+IR_ScalarSymbol *IR_roseCode::CreateScalarSymbol(const IR_Symbol *sym, int) {
+  char str1[14];
+  if (typeid(*sym) == typeid(IR_roseScalarSymbol)) {
+    SgType *tn =
+      static_cast<const IR_roseScalarSymbol *>(sym)->vs_->get_type();
+    sprintf(str1, "newVariable%i", i_);
+    SgVariableDeclaration* defn = buildVariableDeclaration(str1, tn);
+    i_++;
+    
+    SgInitializedNamePtrList& variables = defn->get_variables();
+    SgInitializedNamePtrList::const_iterator i = variables.begin();
+    SgInitializedName* initializedName = *i;
+    SgVariableSymbol* vs = new SgVariableSymbol(initializedName);
+    
+    prependStatement(defn,
+                     isSgScopeStatement(func->get_definition()->get_body()));
+    vs->set_parent(symtab_);
+    symtab_->insert(str1, vs);
+    
+    if (vs == NULL)
+      throw ir_error("in CreateScalarSymbol: vs is NULL!!");
+    
+    return new IR_roseScalarSymbol(this, vs);
+  } else if (typeid(*sym) == typeid(IR_roseArraySymbol)) {
+    SgType *tn1 =
+      static_cast<const IR_roseArraySymbol *>(sym)->vs_->get_type();
+    while (isSgArrayType(tn1) || isSgPointerType(tn1)) {
+      if (isSgArrayType(tn1))
+        tn1 = isSgArrayType(tn1)->get_base_type();
+      else if (isSgPointerType(tn1))
+        tn1 = isSgPointerType(tn1)->get_base_type();
+      else
+        throw ir_error(
+          "in CreateScalarSymbol: symbol not an array nor a pointer!");
+    }
+    
+    sprintf(str1, "newVariable%i", i_);
+    i_++;
+    
+    SgVariableDeclaration* defn1 = buildVariableDeclaration(str1, tn1);
+    SgInitializedNamePtrList& variables1 = defn1->get_variables();
+    
+    SgInitializedNamePtrList::const_iterator i1 = variables1.begin();
+    SgInitializedName* initializedName1 = *i1;
+    
+    SgVariableSymbol *vs1 = new SgVariableSymbol(initializedName1);
+    prependStatement(defn1,
+                     isSgScopeStatement(func->get_definition()->get_body()));
+    
+    vs1->set_parent(symtab_);
+    symtab_->insert(str1, vs1);
+    
+    if (vs1 == NULL)
+      throw ir_error("in CreateScalarSymbol: vs1 is NULL!!");
+    
+    return new IR_roseScalarSymbol(this, vs1);
+  } else
+    throw std::bad_typeid();
+  
+}
+
+IR_ArraySymbol *IR_roseCode::CreateArraySymbol(const IR_Symbol *sym,
+                                               std::vector<omega::CG_outputRepr *> &size, int) {
+  SgType *tn;
+  char str1[14];
+  
+  if (typeid(*sym) == typeid(IR_roseScalarSymbol)) {
+    tn = static_cast<const IR_roseScalarSymbol *>(sym)->vs_->get_type();
+  } else if (typeid(*sym) == typeid(IR_roseArraySymbol)) {
+    tn = static_cast<const IR_roseArraySymbol *>(sym)->vs_->get_type();
+    while (isSgArrayType(tn) || isSgPointerType(tn)) {
+      if (isSgArrayType(tn))
+        tn = isSgArrayType(tn)->get_base_type();
+      else if (isSgPointerType(tn))
+        tn = isSgPointerType(tn)->get_base_type();
+      else
+        throw ir_error(
+          "in CreateScalarSymbol: symbol not an array nor a pointer!");
+    }
+  } else
+    throw std::bad_typeid();
+
+  
+  // Manu:: Fortran support
+  std::vector<SgExpression *>exprs;
+  SgExprListExp *exprLstExp;
+  SgExpression* sizeExpression = new SgNullExpression();
+  SgArrayType* arrayType = new SgArrayType(tn,sizeExpression);
+  sizeExpression->set_parent(arrayType);
+
+  if (!is_fortran_) {
+	  for (int i = size.size() - 1; i >= 0; i--) {
+		tn = buildArrayType(tn,static_cast<omega::CG_roseRepr *>(size[i])->GetExpression());
+	  }
+  } else { // Manu:: required for fortran support
+	  for (int i = size.size() - 1; i >= 0; i--) {
+		exprs.push_back(static_cast<omega::CG_roseRepr *>(size[i])->GetExpression());
+	  }
+  }
+
+  if (is_fortran_) {
+	  exprLstExp = buildExprListExp(exprs);
+	  arrayType->set_dim_info(exprLstExp);
+ 	  exprLstExp->set_parent(arrayType);
+ 	  arrayType->set_rank(exprLstExp->get_expressions().size());
+  }
+
+  static int rose_array_counter = 1;
+  SgVariableDeclaration* defn2;
+  std::string s;
+  if (!is_fortran_) {
+	  s = std::string("_P") + omega::to_string(rose_array_counter++);
+	  defn2 = buildVariableDeclaration(const_cast<char *>(s.c_str()), tn);
+  } else {// Manu:: fortran support
+	  s = std::string("f_P") + omega::to_string(rose_array_counter++);
+	  defn2 = buildVariableDeclaration(const_cast<char *>(s.c_str()), arrayType);
+  }
+
+
+  SgInitializedNamePtrList& variables2 = defn2->get_variables();
+  
+  SgInitializedNamePtrList::const_iterator i2 = variables2.begin();
+  SgInitializedName* initializedName2 = *i2;
+  SgVariableSymbol *vs = new SgVariableSymbol(initializedName2);
+  
+  prependStatement(defn2,
+                   isSgScopeStatement(func->get_definition()->get_body()));
+  
+  vs->set_parent(symtab_);
+  symtab_->insert(SgName(s.c_str()), vs);
+  
+  return new IR_roseArraySymbol(this, vs);
+}
+
+IR_ScalarRef *IR_roseCode::CreateScalarRef(const IR_ScalarSymbol *sym) {
+  return new IR_roseScalarRef(this,
+                              buildVarRefExp(static_cast<const IR_roseScalarSymbol *>(sym)->vs_));
+  
+}
+
+IR_ArrayRef *IR_roseCode::CreateArrayRef(const IR_ArraySymbol *sym,
+                                         std::vector<omega::CG_outputRepr *> &index) {
+  
+  int t;
+  
+  if (sym->n_dim() != index.size())
+    throw std::invalid_argument("incorrect array symbol dimensionality");
+  
+  const IR_roseArraySymbol *l_sym =
+    static_cast<const IR_roseArraySymbol *>(sym);
+  
+  SgVariableSymbol *vs = l_sym->vs_;
+  SgExpression* ia1 = buildVarRefExp(vs);
+  
+
+
+  if (is_fortran_) { // Manu:: fortran support
+	  std::vector<SgExpression *>exprs;
+	  for (int i = 0 ; i < index.size(); i++) {
+		exprs.push_back(static_cast<omega::CG_roseRepr *>(index[i])->GetExpression());
+	  }
+	  SgExprListExp *exprLstExp;
+	  exprLstExp = buildExprListExp(exprs);
+	  ia1 = buildPntrArrRefExp(ia1,exprLstExp);
+  } else {
+     for (int i = 0; i < index.size(); i++) {
+
+        ia1 = buildPntrArrRefExp(ia1,
+                             static_cast<omega::CG_roseRepr *>(index[i])->GetExpression());
+    
+     }
+  }
+  
+  SgPntrArrRefExp *ia = isSgPntrArrRefExp(ia1);
+  
+  return new IR_roseArrayRef(this, ia, -1);
+  
+}
+
+std::vector<IR_ScalarRef *> IR_roseCode::FindScalarRef(
+  const omega::CG_outputRepr *repr) const {
+  std::vector<IR_ScalarRef *> scalars;
+  SgNode *tnl = static_cast<const omega::CG_roseRepr *>(repr)->GetCode();
+  SgStatementPtrList *list =
+    static_cast<const omega::CG_roseRepr *>(repr)->GetList();
+  SgStatement* stmt;
+  SgExpression * exp;
+  
+  if (list != NULL) {
+    for (SgStatementPtrList::iterator it = (*list).begin();
+         it != (*list).end(); it++) {
+      omega::CG_roseRepr *r = new omega::CG_roseRepr(isSgNode(*it));
+      std::vector<IR_ScalarRef *> a = FindScalarRef(r);
+      delete r;
+      std::copy(a.begin(), a.end(), back_inserter(scalars));
+    }
+  }
+  
+  else if (tnl != NULL) {
+    if (stmt = isSgStatement(tnl)) {
+      if (isSgBasicBlock(stmt)) {
+        SgStatementPtrList& stmts =
+          isSgBasicBlock(stmt)->get_statements();
+        for (int i = 0; i < stmts.size(); i++) {
+          omega::CG_roseRepr *r = new omega::CG_roseRepr(
+            isSgNode(stmts[i]));
+          std::vector<IR_ScalarRef *> a = FindScalarRef(r);
+          delete r;
+          std::copy(a.begin(), a.end(), back_inserter(scalars));
+        }
+        
+      } else if (isSgForStatement(stmt)) {
+        
+        SgForStatement *tnf = isSgForStatement(stmt);
+        omega::CG_roseRepr *r = new omega::CG_roseRepr(
+          isSgStatement(tnf->get_loop_body()));
+        std::vector<IR_ScalarRef *> a = FindScalarRef(r);
+        delete r;
+        std::copy(a.begin(), a.end(), back_inserter(scalars));
+      } else if (isSgFortranDo(stmt)) {
+        SgFortranDo *tfortran = isSgFortranDo(stmt);
+        omega::CG_roseRepr *r = new omega::CG_roseRepr(
+          isSgStatement(tfortran->get_body()));
+        std::vector<IR_ScalarRef *> a = FindScalarRef(r);
+        delete r;
+        std::copy(a.begin(), a.end(), back_inserter(scalars));
+      } else if (isSgIfStmt(stmt)) {
+        SgIfStmt* tni = isSgIfStmt(stmt);
+        omega::CG_roseRepr *r = new omega::CG_roseRepr(
+          isSgNode(tni->get_conditional()));
+        std::vector<IR_ScalarRef *> a = FindScalarRef(r);
+        delete r;
+        std::copy(a.begin(), a.end(), back_inserter(scalars));
+        r = new omega::CG_roseRepr(isSgNode(tni->get_true_body()));
+        a = FindScalarRef(r);
+        delete r;
+        std::copy(a.begin(), a.end(), back_inserter(scalars));
+        r = new omega::CG_roseRepr(isSgNode(tni->get_false_body()));
+        a = FindScalarRef(r);
+        delete r;
+        std::copy(a.begin(), a.end(), back_inserter(scalars));
+      } else if (isSgExprStatement(stmt)) {
+        omega::CG_roseRepr *r = new omega::CG_roseRepr(
+          isSgExpression(
+            isSgExprStatement(stmt)->get_expression()));
+        std::vector<IR_ScalarRef *> a = FindScalarRef(r);
+        delete r;
+        std::copy(a.begin(), a.end(), back_inserter(scalars));
+        
+      }
+    }
+  } else {
+    SgExpression* op =
+      static_cast<const omega::CG_roseRepr *>(repr)->GetExpression();
+    if (isSgVarRefExp(op)
+        && (!isSgArrayType(isSgVarRefExp(op)->get_type()))) {
+      if (SgBinaryOp* op_ = isSgBinaryOp(
+            isSgVarRefExp(op)->get_parent())) {
+        if (SgCompoundAssignOp *op__ = isSgCompoundAssignOp(op_)) {
+          if (isSgCompoundAssignOp(op_)->get_lhs_operand()
+              == isSgVarRefExp(op)) {
+            scalars.push_back(
+              new IR_roseScalarRef(this, isSgVarRefExp(op),
+                                   1));
+            scalars.push_back(
+              new IR_roseScalarRef(this, isSgVarRefExp(op),
+                                   0));
+          }
+        }
+      } else if (SgAssignOp* assmt = isSgAssignOp(
+                   isSgVarRefExp(op)->get_parent())) {
+        
+        if (assmt->get_lhs_operand() == isSgVarRefExp(op))
+          scalars.push_back(
+            new IR_roseScalarRef(this, isSgVarRefExp(op), 1));
+      } else if (SgAssignOp * assmt = isSgAssignOp(
+                   isSgVarRefExp(op)->get_parent())) {
+        
+        if (assmt->get_rhs_operand() == isSgVarRefExp(op))
+          scalars.push_back(
+            new IR_roseScalarRef(this, isSgVarRefExp(op), 0));
+      } else
+        scalars.push_back(
+          new IR_roseScalarRef(this, isSgVarRefExp(op), 0));
+    } else if (isSgAssignOp(op)) {
+      omega::CG_roseRepr *r1 = new omega::CG_roseRepr(
+        isSgAssignOp(op)->get_lhs_operand());
+      std::vector<IR_ScalarRef *> a1 = FindScalarRef(r1);
+      delete r1;
+      std::copy(a1.begin(), a1.end(), back_inserter(scalars));
+      omega::CG_roseRepr *r2 = new omega::CG_roseRepr(
+        isSgAssignOp(op)->get_rhs_operand());
+      std::vector<IR_ScalarRef *> a2 = FindScalarRef(r2);
+      delete r2;
+      std::copy(a2.begin(), a2.end(), back_inserter(scalars));
+      
+    } else if (isSgBinaryOp(op)) {
+      omega::CG_roseRepr *r1 = new omega::CG_roseRepr(
+        isSgBinaryOp(op)->get_lhs_operand());
+      std::vector<IR_ScalarRef *> a1 = FindScalarRef(r1);
+      delete r1;
+      std::copy(a1.begin(), a1.end(), back_inserter(scalars));
+      omega::CG_roseRepr *r2 = new omega::CG_roseRepr(
+        isSgBinaryOp(op)->get_rhs_operand());
+      std::vector<IR_ScalarRef *> a2 = FindScalarRef(r2);
+      delete r2;
+      std::copy(a2.begin(), a2.end(), back_inserter(scalars));
+    } else if (isSgUnaryOp(op)) {
+      omega::CG_roseRepr *r1 = new omega::CG_roseRepr(
+        isSgUnaryOp(op)->get_operand());
+      std::vector<IR_ScalarRef *> a1 = FindScalarRef(r1);
+      delete r1;
+      std::copy(a1.begin(), a1.end(), back_inserter(scalars));
+    }
+    
+  }
+  return scalars;
+  
+}
+
+std::vector<IR_ArrayRef *> IR_roseCode::FindArrayRef(
+  const omega::CG_outputRepr *repr) const {
+  std::vector<IR_ArrayRef *> arrays;
+  SgNode *tnl = static_cast<const omega::CG_roseRepr *>(repr)->GetCode();
+  SgStatementPtrList* list =
+    static_cast<const omega::CG_roseRepr *>(repr)->GetList();
+  SgStatement* stmt;
+  SgExpression * exp;
+  
+  if (list != NULL) {
+    for (SgStatementPtrList::iterator it = (*list).begin();
+         it != (*list).end(); it++) {
+      omega::CG_roseRepr *r = new omega::CG_roseRepr(isSgNode(*it));
+      std::vector<IR_ArrayRef *> a = FindArrayRef(r);
+      delete r;
+      std::copy(a.begin(), a.end(), back_inserter(arrays));
+    }
+  } else if (tnl != NULL) {
+    if (stmt = isSgStatement(tnl)) {
+      if (isSgBasicBlock(stmt)) {
+        SgStatementPtrList& stmts =
+          isSgBasicBlock(stmt)->get_statements();
+        for (int i = 0; i < stmts.size(); i++) {
+          omega::CG_roseRepr *r = new omega::CG_roseRepr(
+            isSgNode(stmts[i]));
+          std::vector<IR_ArrayRef *> a = FindArrayRef(r);
+          delete r;
+          std::copy(a.begin(), a.end(), back_inserter(arrays));
+        }
+        
+      } else if (isSgForStatement(stmt)) {
+        
+        SgForStatement *tnf = isSgForStatement(stmt);
+        omega::CG_roseRepr *r = new omega::CG_roseRepr(
+          isSgStatement(tnf->get_loop_body()));
+        std::vector<IR_ArrayRef *> a = FindArrayRef(r);
+        delete r;
+        std::copy(a.begin(), a.end(), back_inserter(arrays));
+      } else if (isSgFortranDo(stmt)) {
+        SgFortranDo *tfortran = isSgFortranDo(stmt);
+        omega::CG_roseRepr *r = new omega::CG_roseRepr(
+          isSgStatement(tfortran->get_body()));
+        std::vector<IR_ArrayRef *> a = FindArrayRef(r);
+        delete r;
+        std::copy(a.begin(), a.end(), back_inserter(arrays));
+      } else if (isSgIfStmt(stmt)) {
+        SgIfStmt* tni = isSgIfStmt(stmt);
+        omega::CG_roseRepr *r = new omega::CG_roseRepr(
+          isSgNode(tni->get_conditional()));
+        std::vector<IR_ArrayRef *> a = FindArrayRef(r);
+        delete r;
+        std::copy(a.begin(), a.end(), back_inserter(arrays));
+        r = new omega::CG_roseRepr(isSgNode(tni->get_true_body()));
+        a = FindArrayRef(r);
+        delete r;
+        std::copy(a.begin(), a.end(), back_inserter(arrays));
+        r = new omega::CG_roseRepr(isSgNode(tni->get_false_body()));
+        a = FindArrayRef(r);
+        delete r;
+        std::copy(a.begin(), a.end(), back_inserter(arrays));
+      } else if (isSgExprStatement(stmt)) {
+        omega::CG_roseRepr *r = new omega::CG_roseRepr(
+          isSgExpression(
+            isSgExprStatement(stmt)->get_expression()));
+        std::vector<IR_ArrayRef *> a = FindArrayRef(r);
+        delete r;
+        std::copy(a.begin(), a.end(), back_inserter(arrays));
+        
+      }
+    }
+  } else {
+    SgExpression* op =
+      static_cast<const omega::CG_roseRepr *>(repr)->GetExpression();
+    if (isSgPntrArrRefExp(op)) {
+      
+      SgVarRefExp* base;
+      SgExpression* op2;
+      if (isSgCompoundAssignOp(isSgPntrArrRefExp(op)->get_parent())) {
+        IR_roseArrayRef *ref1 = new IR_roseArrayRef(this,
+                                                    isSgPntrArrRefExp(op), 0);
+        arrays.push_back(ref1);
+        IR_roseArrayRef *ref2 = new IR_roseArrayRef(this,
+                                                    isSgPntrArrRefExp(op), 1);
+        arrays.push_back(ref2);
+      } else {
+        IR_roseArrayRef *ref3 = new IR_roseArrayRef(this,
+                                                    isSgPntrArrRefExp(op), -1);
+        arrays.push_back(ref3);
+        
+        while (isSgPntrArrRefExp(op)) {
+          op2 = isSgPntrArrRefExp(op)->get_rhs_operand();
+          op = isSgPntrArrRefExp(op)->get_lhs_operand();
+          omega::CG_roseRepr *r = new omega::CG_roseRepr(op2);
+          std::vector<IR_ArrayRef *> a = FindArrayRef(r);
+          delete r;
+          std::copy(a.begin(), a.end(), back_inserter(arrays));
+          
+        }
+      }
+    } else if (isSgAssignOp(op)) {
+      omega::CG_roseRepr *r1 = new omega::CG_roseRepr(
+        isSgAssignOp(op)->get_lhs_operand());
+      std::vector<IR_ArrayRef *> a1 = FindArrayRef(r1);
+      delete r1;
+      std::copy(a1.begin(), a1.end(), back_inserter(arrays));
+      omega::CG_roseRepr *r2 = new omega::CG_roseRepr(
+        isSgAssignOp(op)->get_rhs_operand());
+      std::vector<IR_ArrayRef *> a2 = FindArrayRef(r2);
+      delete r2;
+      std::copy(a2.begin(), a2.end(), back_inserter(arrays));
+      
+    } else if (isSgBinaryOp(op)) {
+      omega::CG_roseRepr *r1 = new omega::CG_roseRepr(
+        isSgBinaryOp(op)->get_lhs_operand());
+      std::vector<IR_ArrayRef *> a1 = FindArrayRef(r1);
+      delete r1;
+      std::copy(a1.begin(), a1.end(), back_inserter(arrays));
+      omega::CG_roseRepr *r2 = new omega::CG_roseRepr(
+        isSgBinaryOp(op)->get_rhs_operand());
+      std::vector<IR_ArrayRef *> a2 = FindArrayRef(r2);
+      delete r2;
+      std::copy(a2.begin(), a2.end(), back_inserter(arrays));
+    } else if (isSgUnaryOp(op)) {
+      omega::CG_roseRepr *r1 = new omega::CG_roseRepr(
+        isSgUnaryOp(op)->get_operand());
+      std::vector<IR_ArrayRef *> a1 = FindArrayRef(r1);
+      delete r1;
+      std::copy(a1.begin(), a1.end(), back_inserter(arrays));
+    }
+    
+  }
+  return arrays;
+}
+
+std::vector<IR_Control *> IR_roseCode::FindOneLevelControlStructure(
+  const IR_Block *block) const {
+
+  std::vector<IR_Control *> controls;
+  int i;
+  int j;
+  int begin;
+  int end;
+  SgNode* tnl_ =
+    ((static_cast<IR_roseBlock *>(const_cast<IR_Block *>(block)))->tnl_);
+  
+  if (isSgForStatement(tnl_))
+    controls.push_back(new IR_roseLoop(this, tnl_));
+  else if (isSgFortranDo(tnl_))
+	  controls.push_back(new IR_roseLoop(this, tnl_));
+  else if (isSgIfStmt(tnl_))
+    controls.push_back(new IR_roseIf(this, tnl_));
+  
+  else if (isSgBasicBlock(tnl_)) {
+    
+    SgStatementPtrList& stmts = isSgBasicBlock(tnl_)->get_statements();
+    
+    for (i = 0; i < stmts.size(); i++) {
+      if (isSgNode(stmts[i])
+          == ((static_cast<IR_roseBlock *>(const_cast<IR_Block *>(block)))->start_))
+        begin = i;
+      if (isSgNode(stmts[i])
+          == ((static_cast<IR_roseBlock *>(const_cast<IR_Block *>(block)))->end_))
+        end = i;
+    }
+    
+    SgNode* start = NULL;
+    SgNode* prev = NULL;
+    for (i = begin; i <= end; i++) {
+      if (isSgForStatement(stmts[i]) || isSgFortranDo(stmts[i])) {
+        if (start != NULL) {
+          controls.push_back(
+            new IR_roseBlock(this,
+                             (static_cast<IR_roseBlock *>(const_cast<IR_Block *>(block)))->tnl_,
+                             start, prev));
+          start = NULL;
+        }
+        controls.push_back(new IR_roseLoop(this, isSgNode(stmts[i])));
+      } else if (isSgIfStmt(stmts[i])) {
+        if (start != NULL) {
+          controls.push_back(
+            new IR_roseBlock(this,
+                             (static_cast<IR_roseBlock *>(const_cast<IR_Block *>(block)))->tnl_,
+                             start, prev));
+          start = NULL;
+        }
+        controls.push_back(new IR_roseIf(this, isSgNode(stmts[i])));
+        
+      } else if (start == NULL)
+        start = isSgNode(stmts[i]);
+      
+      prev = isSgNode(stmts[i]);
+    }
+    
+    if ((start != NULL) && (start != isSgNode(stmts[begin])))
+      controls.push_back(
+        new IR_roseBlock(this,
+                         (static_cast<IR_roseBlock *>(const_cast<IR_Block *>(block)))->tnl_,
+                         start, prev));
+  }
+  
+  return controls;
+  
+}
+
+IR_Block *IR_roseCode::MergeNeighboringControlStructures(
+  const std::vector<IR_Control *> &controls) const {
+  if (controls.size() == 0)
+    return NULL;
+  
+  SgNode *tnl = NULL;
+  SgNode *start, *end;
+  for (int i = 0; i < controls.size(); i++) {
+    switch (controls[i]->type()) {
+    case IR_CONTROL_LOOP: {
+      SgNode *tf = static_cast<IR_roseLoop *>(controls[i])->tf_;
+      if (tnl == NULL) {
+        tnl = tf->get_parent();
+        start = end = tf;
+      } else {
+        if (tnl != tf->get_parent())
+          throw ir_error("controls to merge not at the same level");
+        end = tf;
+      }
+      break;
+    }
+    case IR_CONTROL_BLOCK: {
+      if (tnl == NULL) {
+        tnl = static_cast<IR_roseBlock *>(controls[0])->tnl_;
+        start = static_cast<IR_roseBlock *>(controls[0])->start_;
+        end = static_cast<IR_roseBlock *>(controls[0])->end_;
+      } else {
+        if (tnl != static_cast<IR_roseBlock *>(controls[0])->tnl_)
+          throw ir_error("controls to merge not at the same level");
+        end = static_cast<IR_roseBlock *>(controls[0])->end_;
+      }
+      break;
+    }
+    default:
+      throw ir_error("unrecognized control to merge");
+    }
+  }
+  
+  return new IR_roseBlock(controls[0]->ir_, tnl, start, end);
+}
+
+IR_Block *IR_roseCode::GetCode() const {
+  SgFunctionDefinition* def = NULL;
+  SgBasicBlock* block = NULL;
+  if (func != 0) {
+    if (def = func->get_definition()) {
+      if (block = def->get_body())
+        return new IR_roseBlock(this,
+                                func->get_definition()->get_body());
+    }
+  }
+  
+  return NULL;
+  
+}
+
+void IR_roseCode::ReplaceCode(IR_Control *old, omega::CG_outputRepr *repr) {
+  /*    SgStatementPtrList *tnl =
+        static_cast<omega::CG_roseRepr *>(repr)->GetList();
+        SgNode *tf_old;
+  */
+  SgStatementPtrList *tnl =
+    static_cast<omega::CG_roseRepr *>(repr)->GetList();
+  SgNode* node_ = static_cast<omega::CG_roseRepr *>(repr)->GetCode();
+  SgNode * tf_old;
+  
+  /* May need future revision it tnl has more than one statement */
+  
+  switch (old->type()) {
+    
+  case IR_CONTROL_LOOP:
+    tf_old = static_cast<IR_roseLoop *>(old)->tf_;
+    break;
+  case IR_CONTROL_BLOCK:
+    tf_old = static_cast<IR_roseBlock *>(old)->start_;
+    break;
+    
+  default:
+    throw ir_error("control structure to be replaced not supported");
+    break;
+  }
+  
+  std::string y = tf_old->unparseToString();
+  SgStatement *s = isSgStatement(tf_old);
+  if (s != 0) {
+    SgStatement *p = isSgStatement(tf_old->get_parent());
+    
+    if (p != 0) {
+      SgStatement* temp = s;
+      if (tnl != NULL) {
+        SgStatementPtrList::iterator it = (*tnl).begin();
+        p->insert_statement(temp, *it, true);
+        temp = *it;
+        p->remove_statement(s);
+        it++;
+        for (; it != (*tnl).end(); it++) {
+          p->insert_statement(temp, *it, false);
+          temp = *it;
+        }
+      } else if (node_ != NULL) {
+        if (!isSgStatement(node_))
+          throw ir_error("Replacing Code not a statement!");
+        else {
+          SgStatement* replace_ = isSgStatement(node_);
+          p->insert_statement(s, replace_, true);
+          p->remove_statement(s);
+          
+        }
+      } else {
+        throw ir_error("Replacing Code not a statement!");
+      }
+    } else
+      throw ir_error("Replacing Code not a statement!");
+  } else
+    throw ir_error("Replacing Code not a statement!");
+  
+  delete old;
+  delete repr;
+  /* May need future revision it tnl has more than one statement */
+  /*
+    switch (old->type()) {
+    
+    case IR_CONTROL_LOOP:
+    tf_old = static_cast<IR_roseLoop *>(old)->tf_;
+    break;
+    case IR_CONTROL_BLOCK:
+    tf_old = static_cast<IR_roseBlock *>(old)->start_;
+    break;
+    
+    default:
+    throw ir_error("control structure to be replaced not supported");
+    break;
+    }
+    
+    // std::string y = tf_old->unparseToString();
+    SgStatement *s = isSgStatement(tf_old);
+    if (s != 0) {
+    SgStatement *p = isSgStatement(tf_old->get_parent());
+    
+    if (p != 0) {
+    //      SgStatement* it2 = isSgStatement(tnl);
+    
+    //   if(it2 != NULL){
+    p->replace_statement(s, *tnl);
+    //   }
+    //   else {
+    //          throw ir_error("Replacing Code not a statement!");
+    //      }
+    } else
+    throw ir_error("Replacing Code not a statement!");
+    } else
+    throw ir_error("Replacing Code not a statement!");
+    //  y = tnl->unparseToString();
+    delete old;
+    delete repr;
+  */
+}
+
+void IR_roseCode::ReplaceExpression(IR_Ref *old, omega::CG_outputRepr *repr) {
+  
+  SgExpression* op = static_cast<omega::CG_roseRepr *>(repr)->GetExpression();
+  
+  if (typeid(*old) == typeid(IR_roseArrayRef)) {
+    SgPntrArrRefExp* ia_orig = static_cast<IR_roseArrayRef *>(old)->ia_;
+    SgExpression* parent = isSgExpression(isSgNode(ia_orig)->get_parent());
+    std::string x = isSgNode(op)->unparseToString();
+    std::string y = isSgNode(ia_orig)->unparseToString();
+    if (parent != NULL) {
+      std::string z = isSgNode(parent)->unparseToString();
+      parent->replace_expression(ia_orig, op);
+      isSgNode(op)->set_parent(isSgNode(parent));
+      
+      /* if(isSgBinaryOp(parent))
+         {
+         if(isSgBinaryOp(parent)->get_lhs_operand() == ia_orig){
+         isSgBinaryOp(parent)->set_lhs_operand(op);   
+         }else if(isSgBinaryOp(parent)->get_rhs_operand() == ia_orig){
+         isSgBinaryOp(parent)->set_rhs_operand(op); 
+         
+         
+         } 
+         else
+         parent->replace_expression(ia_orig, op);
+      */
+    } else {
+      SgStatement* parent_stmt = isSgStatement(
+        isSgNode(ia_orig)->get_parent());
+      if (parent_stmt != NULL)
+        parent_stmt->replace_expression(ia_orig, op);
+      else
+        throw ir_error(
+          "ReplaceExpression: parent neither expression nor statement");
+    }
+  } else
+    throw ir_error("replacing a scalar variable not implemented");
+  
+  delete old;
+}
+
+IR_OPERATION_TYPE IR_roseCode::QueryExpOperation(
+  const omega::CG_outputRepr *repr) const {
+  SgExpression* op =
+    static_cast<const omega::CG_roseRepr *>(repr)->GetExpression();
+  
+  if (isSgValueExp(op))
+    return IR_OP_CONSTANT;
+  else if (isSgVarRefExp(op) || isSgPntrArrRefExp(op))
+    return IR_OP_VARIABLE;
+  else if (isSgAssignOp(op) || isSgCompoundAssignOp(op))
+    return IR_OP_ASSIGNMENT;
+  else if (isSgAddOp(op))
+    return IR_OP_PLUS;
+  else if (isSgSubtractOp(op))
+    return IR_OP_MINUS;
+  else if (isSgMultiplyOp(op))
+    return IR_OP_MULTIPLY;
+  else if (isSgDivideOp(op))
+    return IR_OP_DIVIDE;
+  else if (isSgMinusOp(op))
+    return IR_OP_NEGATIVE;
+  else if (isSgConditionalExp(op)) {
+    SgExpression* cond = isSgConditionalExp(op)->get_conditional_exp();
+    if (isSgGreaterThanOp(cond))
+      return IR_OP_MAX;
+    else if (isSgLessThanOp(cond))
+      return IR_OP_MIN;
+  } else if (isSgUnaryAddOp(op))
+    return IR_OP_POSITIVE;
+  else if (isSgNullExpression(op))
+    return IR_OP_NULL;
+  else
+    return IR_OP_UNKNOWN;
+}
+
+IR_CONDITION_TYPE IR_roseCode::QueryBooleanExpOperation(
+  const omega::CG_outputRepr *repr) const {
+  SgExpression* op2 =
+    static_cast<const omega::CG_roseRepr *>(repr)->GetExpression();
+  SgNode* op;
+  
+  if (op2 == NULL) {
+    op = static_cast<const omega::CG_roseRepr *>(repr)->GetCode();
+    
+    if (op != NULL) {
+      if (isSgExprStatement(op))
+        op2 = isSgExprStatement(op)->get_expression();
+      else
+        return IR_COND_UNKNOWN;
+    } else
+      return IR_COND_UNKNOWN;
+  }
+  
+  if (isSgEqualityOp(op2))
+    return IR_COND_EQ;
+  else if (isSgNotEqualOp(op2))
+    return IR_COND_NE;
+  else if (isSgLessThanOp(op2))
+    return IR_COND_LT;
+  else if (isSgLessOrEqualOp(op2))
+    return IR_COND_LE;
+  else if (isSgGreaterThanOp(op2))
+    return IR_COND_GT;
+  else if (isSgGreaterOrEqualOp(op2))
+    return IR_COND_GE;
+  
+  return IR_COND_UNKNOWN;
+  
+}
+
+std::vector<omega::CG_outputRepr *> IR_roseCode::QueryExpOperand(
+  const omega::CG_outputRepr *repr) const {
+  std::vector<omega::CG_outputRepr *> v;
+  SgExpression* op1;
+  SgExpression* op2;
+  SgExpression* op =
+    static_cast<const omega::CG_roseRepr *>(repr)->GetExpression();
+  omega::CG_roseRepr *repr1;
+  
+  if (isSgValueExp(op) || isSgVarRefExp(op)) {
+    omega::CG_roseRepr *repr = new omega::CG_roseRepr(op);
+    v.push_back(repr);
+  } else if (isSgAssignOp(op)) {
+    op1 = isSgAssignOp(op)->get_rhs_operand();
+    repr1 = new omega::CG_roseRepr(op1);
+    v.push_back(repr1);
+    /*may be a problem as assignOp is a binaryop destop might be needed */
+  } else if (isSgMinusOp(op)) {
+    op1 = isSgMinusOp(op)->get_operand();
+    repr1 = new omega::CG_roseRepr(op1);
+    v.push_back(repr1);
+  } else if (isSgUnaryAddOp(op)) {
+    op1 = isSgUnaryAddOp(op)->get_operand();
+    repr1 = new omega::CG_roseRepr(op1);
+    v.push_back(repr1);
+  } else if ((isSgAddOp(op) || isSgSubtractOp(op))
+             || (isSgMultiplyOp(op) || isSgDivideOp(op))) {
+    op1 = isSgBinaryOp(op)->get_lhs_operand();
+    repr1 = new omega::CG_roseRepr(op1);
+    v.push_back(repr1);
+    
+    op2 = isSgBinaryOp(op)->get_rhs_operand();
+    repr1 = new omega::CG_roseRepr(op2);
+    v.push_back(repr1);
+  } else if (isSgConditionalExp(op)) {
+    SgExpression* cond = isSgConditionalExp(op)->get_conditional_exp();
+    op1 = isSgBinaryOp(cond)->get_lhs_operand();
+    repr1 = new omega::CG_roseRepr(op1);
+    v.push_back(repr1);
+    
+    op2 = isSgBinaryOp(cond)->get_rhs_operand();
+    repr1 = new omega::CG_roseRepr(op2);
+    v.push_back(repr1);
+  } else if (isSgCompoundAssignOp(op)) {
+    SgExpression* cond = isSgCompoundAssignOp(op);
+    op1 = isSgBinaryOp(cond)->get_lhs_operand();
+    repr1 = new omega::CG_roseRepr(op1);
+    v.push_back(repr1);
+    
+    op2 = isSgBinaryOp(cond)->get_rhs_operand();
+    repr1 = new omega::CG_roseRepr(op2);
+    v.push_back(repr1);
+    
+  } else if (isSgBinaryOp(op)) {
+    
+    op1 = isSgBinaryOp(op)->get_lhs_operand();
+    repr1 = new omega::CG_roseRepr(op1);
+    v.push_back(repr1);
+    
+    op2 = isSgBinaryOp(op)->get_rhs_operand();
+    repr1 = new omega::CG_roseRepr(op2);
+    v.push_back(repr1);
+  }
+  
+  else
+    throw ir_error("operation not supported");
+  
+  return v;
+}
+
+IR_Ref *IR_roseCode::Repr2Ref(const omega::CG_outputRepr *repr) const {
+  SgExpression* op =
+    static_cast<const omega::CG_roseRepr *>(repr)->GetExpression();
+  
+  if (SgValueExp* im = isSgValueExp(op)) {
+    if (isSgIntVal(im))
+      return new IR_roseConstantRef(this,
+                                    static_cast<omega::coef_t>(isSgIntVal(im)->get_value()));
+    else if (isSgUnsignedIntVal(im))
+      return new IR_roseConstantRef(this,
+                                    static_cast<omega::coef_t>(isSgUnsignedIntVal(im)->get_value()));
+    else if (isSgLongIntVal(im))
+      return new IR_roseConstantRef(this,
+                                    static_cast<omega::coef_t>(isSgLongIntVal(im)->get_value()));
+    else if (isSgFloatVal(im))
+      return new IR_roseConstantRef(this, isSgFloatVal(im)->get_value());
+    else
+      assert(0);
+    
+  } else if (isSgVarRefExp(op))
+    return new IR_roseScalarRef(this, isSgVarRefExp(op));
+  else
+    assert(0);
+  
+}
+
diff --git a/src/ir_rose_utils.cc b/src/ir_rose_utils.cc
new file mode 100644
index 0000000..64b0891
--- /dev/null
+++ b/src/ir_rose_utils.cc
@@ -0,0 +1,67 @@
+/*****************************************************************************
+ Copyright (C) 2008 University of Southern California
+ Copyright (C) 2009 University of Utah
+ All Rights Reserved.
+
+ Purpose:
+   ROSE interface utilities.
+
+ Notes:
+
+ Update history:
+   01/2006 created by Chun Chen
+*****************************************************************************/
+
+#include "ir_rose_utils.hh"
+
+
+
+std::vector<SgForStatement *> find_loops(SgNode *tnl) {
+  std::vector<SgForStatement *> result;
+ 
+  SgStatementPtrList& blockStatements = isSgBasicBlock(tnl)->get_statements();
+  for(SgStatementPtrList::const_iterator j = blockStatements.begin(); j != blockStatements.end(); j++)
+    if(isSgForStatement(*j))
+      result.push_back(isSgForStatement(*j));
+  
+  return result;
+}
+
+std::vector<SgForStatement *> find_deepest_loops(SgStatementPtrList& tnl) {
+  
+  std::vector<SgForStatement *> loops;
+  
+  
+  
+  for(SgStatementPtrList::const_iterator j = tnl.begin(); j != tnl.end(); j++)
+  {
+    std::vector<SgForStatement *> t = find_deepest_loops(isSgNode(*j));
+    if (t.size() > loops.size())
+      loops = t;
+  }       
+  
+  
+  
+  return loops;
+  
+}
+
+std::vector<SgForStatement *> find_deepest_loops(SgNode *tn) {
+  if (isSgForStatement(tn)) {
+    std::vector<SgForStatement *> loops;
+    
+    SgForStatement *tnf = static_cast<SgForStatement*>(tn);
+    loops.insert(loops.end(), tnf);
+    std::vector<SgForStatement*> t = find_deepest_loops(isSgNode(tnf->get_loop_body()));
+    std::copy(t.begin(), t.end(), std::back_inserter(loops));
+    
+    return loops;
+  }
+  else if (isSgBasicBlock(tn)) {
+    SgBasicBlock *tnb = static_cast<SgBasicBlock*>(tn);
+    return find_deepest_loops(tnb->get_statements());
+  }
+  else 
+    return std::vector<SgForStatement *>();               
+}
+
diff --git a/src/irtools.cc b/src/irtools.cc
new file mode 100644
index 0000000..4ab6c85
--- /dev/null
+++ b/src/irtools.cc
@@ -0,0 +1,279 @@
+/*****************************************************************************
+ Copyright (C) 2010 University of Utah
+ All Rights Reserved.
+
+ Purpose:
+   Useful tools to analyze code in compiler IR format.
+
+ Notes:
+
+ History:
+   06/2010 Created by Chun Chen.
+*****************************************************************************/
+
+#include <iostream>
+#include <code_gen/CG_outputBuilder.h>
+#include "irtools.hh"
+#include "omegatools.hh"
+#include "chill_error.hh"
+
+using namespace omega;
+
+// Build IR tree from the source code.  Block type node can only be
+// leaf, i.e., there is no further structures inside a block allowed.
+std::vector<ir_tree_node *> build_ir_tree(IR_Control *control, ir_tree_node *parent) {
+  std::vector<ir_tree_node *> result;
+  
+  switch (control->type()) {
+  case IR_CONTROL_BLOCK: {
+    std::vector<IR_Control *> controls = control->ir_->FindOneLevelControlStructure(static_cast<IR_Block *>(control));
+    if (controls.size() == 0) {
+      ir_tree_node *node = new ir_tree_node;
+      node->content = control;
+      node->parent = parent;
+      node->payload = -1;
+      result.push_back(node);
+    }
+    else {
+      delete control;
+      for (int i = 0; i < controls.size(); i++)
+        switch (controls[i]->type()) {
+        case IR_CONTROL_BLOCK: {
+          std::vector<ir_tree_node *> t = build_ir_tree(controls[i], parent);
+          result.insert(result.end(), t.begin(), t.end());
+          break;
+        }
+        case IR_CONTROL_LOOP: {
+          ir_tree_node *node = new ir_tree_node;
+          node->content = controls[i];
+          node->parent = parent;
+          node->children = build_ir_tree(static_cast<IR_Loop *>(controls[i])->body(), node);
+          node->payload = -1;
+          result.push_back(node);
+          break;
+        }
+        case IR_CONTROL_IF: {
+          static int unique_if_identifier = 0;
+          
+          IR_Block *block = static_cast<IR_If *>(controls[i])->then_body();
+          if (block != NULL) {
+            ir_tree_node *node = new ir_tree_node;
+            node->content = controls[i];
+            node->parent = parent;
+            node->children = build_ir_tree(block, node);
+            node->payload = unique_if_identifier+1;
+            result.push_back(node);
+          }
+          
+          
+          block = static_cast<IR_If *>(controls[i])->else_body();
+          if ( block != NULL) {
+            ir_tree_node *node = new ir_tree_node;
+            node->content = controls[i]->clone();
+            node->parent = parent;
+            node->children = build_ir_tree(block, node);
+            node->payload = unique_if_identifier;
+            result.push_back(node);
+          }
+          
+          unique_if_identifier += 2;
+          break;
+        }
+        default:
+          ir_tree_node *node = new ir_tree_node;
+          node->content = controls[i];
+          node->parent = parent;
+          node->payload = -1;
+          result.push_back(node);
+          break;
+        }
+    }
+    break;
+  }
+  case IR_CONTROL_LOOP: {
+    ir_tree_node *node = new ir_tree_node;
+    node->content = control;
+    node->parent = parent;
+    node->children = build_ir_tree(static_cast<const IR_Loop *>(control)->body(), node);
+    node->payload = -1;
+    result.push_back(node);
+    break;
+  }
+  default:
+    ir_tree_node *node = new ir_tree_node;
+    node->content = control;
+    node->parent = parent;
+    node->payload = -1;
+    result.push_back(node);
+    break;
+  }
+  
+  return result;
+}
+
+
+// Extract statements from IR tree. Statements returned are ordered in
+// lexical order in the source code.
+std::vector<ir_tree_node *> extract_ir_stmts(const std::vector<ir_tree_node *> &ir_tree) {
+  std::vector<ir_tree_node *> result;
+  for (int i = 0; i < ir_tree.size(); i++)
+    switch (ir_tree[i]->content->type()) {
+    case IR_CONTROL_BLOCK:
+      result.push_back(ir_tree[i]);
+      break;
+    case IR_CONTROL_LOOP: {
+      // clear loop payload from previous unsuccessful initialization process
+      ir_tree[i]->payload = -1;
+      
+      std::vector<ir_tree_node *> t = extract_ir_stmts(ir_tree[i]->children);
+      result.insert(result.end(), t.begin(), t.end());
+      break;
+    }      
+    case IR_CONTROL_IF: {
+      std::vector<ir_tree_node *> t = extract_ir_stmts(ir_tree[i]->children);
+      result.insert(result.end(), t.begin(), t.end());
+      break;
+    }
+    default:
+      throw std::invalid_argument("invalid ir tree");
+    }
+  
+  return result;
+}
+
+
+bool is_dependence_valid(ir_tree_node *src_node, ir_tree_node *dst_node,
+                         const DependenceVector &dv, bool before) {
+  std::set<ir_tree_node *> loop_nodes;
+  ir_tree_node *itn = src_node;
+  
+  if (!dv.is_scalar_dependence) {
+    while (itn->parent != NULL) {
+      itn = itn->parent;
+      if (itn->content->type() == IR_CONTROL_LOOP)
+        loop_nodes.insert(itn);
+    }
+    
+    int last_dim = -1;
+    itn = dst_node;
+    while (itn->parent != NULL) {
+      itn = itn->parent;
+      if (itn->content->type() == IR_CONTROL_LOOP
+          && loop_nodes.find(itn) != loop_nodes.end()
+          && itn->payload > last_dim)
+        last_dim = itn->payload;
+    }
+    
+    if (last_dim == -1)
+      return true;
+    
+    for (int i = 0; i <= last_dim; i++) {
+      if (dv.lbounds[i] > 0)
+        return true;
+      else if (dv.lbounds[i] < 0)
+        return false;
+    }
+    
+    if (before)
+      return true;
+    else
+      return false;
+  }
+  
+  return true;
+  
+}
+
+
+
+// Test data dependences between two statements. The first statement
+// in parameter must be lexically before the second statement in
+// parameter.  Returned dependences are all lexicographically
+// positive. The first vector in returned pair is dependences from the
+// first statement to the second statement and the second vector in
+// returned pair is in reverse order.
+std::pair<std::vector<DependenceVector>, std::vector<DependenceVector> > test_data_dependences(
+  IR_Code *ir, const CG_outputRepr *repr1, const Relation &IS1,
+  const CG_outputRepr *repr2, const Relation &IS2,
+  std::vector<Free_Var_Decl*> &freevar, std::vector<std::string> index,
+  int i, int j) {
+  std::pair<std::vector<DependenceVector>, std::vector<DependenceVector> > result;
+  
+  if (repr1 == repr2) {
+    std::vector<IR_ArrayRef *> access = ir->FindArrayRef(repr1);
+    
+    for (int i = 0; i < access.size(); i++) {
+      IR_ArrayRef *a = access[i];
+      IR_ArraySymbol *sym_a = a->symbol();
+      for (int j = i; j < access.size(); j++) {
+        IR_ArrayRef *b = access[j];
+        IR_ArraySymbol *sym_b = b->symbol();
+        
+        if (*sym_a == *sym_b && (a->is_write() || b->is_write())) {
+          Relation r = arrays2relation(ir, freevar, a, IS1, b, IS2);
+          std::pair<std::vector<DependenceVector>,
+            std::vector<DependenceVector> > dv =
+            relation2dependences(a, b, r);
+          result.first.insert(result.first.end(), dv.first.begin(),
+                              dv.first.end());
+          result.second.insert(result.second.end(), dv.second.begin(),
+                               dv.second.end());
+        }
+        delete sym_b;
+      }
+      delete sym_a;
+      
+    }
+    
+    for (int i = 0; i < access.size(); i++)
+      delete access[i];
+  } else {
+    std::vector<IR_ArrayRef *> access1 = ir->FindArrayRef(repr1);
+    std::vector<IR_ArrayRef *> access2 = ir->FindArrayRef(repr2);
+    
+    for (int i = 0; i < access1.size(); i++) {
+      IR_ArrayRef *a = access1[i];
+      IR_ArraySymbol *sym_a = a->symbol();
+      
+      for (int j = 0; j < access2.size(); j++) {
+        IR_ArrayRef *b = access2[j];
+        IR_ArraySymbol *sym_b = b->symbol();
+        if (*sym_a == *sym_b && (a->is_write() || b->is_write())) {
+          Relation r = arrays2relation(ir, freevar, a, IS1, b, IS2);
+          std::pair<std::vector<DependenceVector>,
+            std::vector<DependenceVector> > dv =
+            relation2dependences(a, b, r);
+          
+          result.first.insert(result.first.end(), dv.first.begin(),
+                              dv.first.end());
+          result.second.insert(result.second.end(), dv.second.begin(),
+                               dv.second.end());
+        }
+        delete sym_b;
+      }
+      delete sym_a;
+    }
+    
+    for (int i = 0; i < access1.size(); i++)
+      delete access1[i];
+    for (int i = 0; i < access2.size(); i++)
+      delete access2[i];
+  }
+  /*std::pair<std::vector<DependenceVector>,
+    std::vector<DependenceVector> > dv =
+    ir->FindScalarDeps(repr1, repr2, index, i, j);
+    
+    
+    result.first.insert(result.first.end(), dv.first.begin(),
+    dv.first.end());
+    result.second.insert(result.second.end(), dv.second.begin(),
+    dv.second.end());*/
+  /*result.first.insert(result.first.end(), dv.first.begin(),
+    dv.first.end());
+    result.second.insert(result.second.end(), dv.second.begin(),
+    dv.second.end());
+  */
+  
+  return result;
+}
+
diff --git a/src/loop.cc b/src/loop.cc
new file mode 100644
index 0000000..f187a50
--- /dev/null
+++ b/src/loop.cc
@@ -0,0 +1,1859 @@
+/*****************************************************************************
+ Copyright (C) 2008 University of Southern California
+ Copyright (C) 2009-2010 University of Utah
+ All Rights Reserved.
+
+ Purpose:
+ Core loop transformation functionality.
+
+ Notes:
+ "level" (starting from 1) means loop level and it corresponds to "dim"
+ (starting from 0) in transformed iteration space [c_1,l_1,c_2,l_2,....,
+ c_n,l_n,c_(n+1)], e.g., l_2 is loop level 2 in generated code, dim 3
+ in transformed iteration space, and variable 4 in Omega relation.
+ All c's are constant numbers only and they will not show up as actual loops.
+ Formula:
+ dim = 2*level - 1
+ var = dim + 1
+
+ History:
+ 10/2005 Created by Chun Chen.
+ 09/2009 Expand tile functionality, -chun
+ 10/2009 Initialize unfusible loop nest without bailing out, -chun
+*****************************************************************************/
+
+#include <limits.h>
+#include <math.h>
+#include <code_gen/codegen.h>
+#include <code_gen/CG_utils.h>
+#include <iostream>
+#include <algorithm>
+#include <map>
+#include "loop.hh"
+#include "omegatools.hh"
+#include "irtools.hh"
+#include "chill_error.hh"
+#include <string.h>
+#include <list>
+using namespace omega;
+
+const std::string Loop::tmp_loop_var_name_prefix = std::string("chill_t"); // Manu:: In fortran, first character of a variable name must be a letter, so this change
+const std::string Loop::overflow_var_name_prefix = std::string("over");
+
+//-----------------------------------------------------------------------------
+// Class Loop
+//-----------------------------------------------------------------------------
+// --begin Anand: Added from CHiLL 0.2
+
+bool Loop::isInitialized() const {
+  return stmt.size() != 0 && !stmt[0].xform.is_null();
+}
+
+//--end Anand: added from CHiLL 0.2
+
+bool Loop::init_loop(std::vector<ir_tree_node *> &ir_tree,
+                     std::vector<ir_tree_node *> &ir_stmt) {
+
+  ir_stmt = extract_ir_stmts(ir_tree);
+  stmt_nesting_level_.resize(ir_stmt.size());
+  std::vector<int> stmt_nesting_level(ir_stmt.size());
+  for (int i = 0; i < ir_stmt.size(); i++) {
+    ir_stmt[i]->payload = i;
+    int t = 0;
+    ir_tree_node *itn = ir_stmt[i];
+    while (itn->parent != NULL) {
+      itn = itn->parent;
+      if (itn->content->type() == IR_CONTROL_LOOP)
+        t++;
+    }
+    stmt_nesting_level_[i] = t;
+    stmt_nesting_level[i] = t;
+  }
+  
+  stmt = std::vector<Statement>(ir_stmt.size());
+  int n_dim = -1;
+  int max_loc;
+  //std::vector<std::string> index;
+  for (int i = 0; i < ir_stmt.size(); i++) {
+    int max_nesting_level = -1;
+    int loc;
+    for (int j = 0; j < ir_stmt.size(); j++)
+      if (stmt_nesting_level[j] > max_nesting_level) {
+        max_nesting_level = stmt_nesting_level[j];
+        loc = j;
+      }
+    
+    // most deeply nested statement acting as a reference point
+    if (n_dim == -1) {
+      n_dim = max_nesting_level;
+      max_loc = loc;
+      
+      index = std::vector<std::string>(n_dim);
+      
+      ir_tree_node *itn = ir_stmt[loc];
+      int cur_dim = n_dim - 1;
+      while (itn->parent != NULL) {
+        itn = itn->parent;
+        if (itn->content->type() == IR_CONTROL_LOOP) {
+          index[cur_dim] =
+            static_cast<IR_Loop *>(itn->content)->index()->name();
+          itn->payload = cur_dim--;
+        }
+      }
+    }
+    
+    // align loops by names, temporary solution
+    ir_tree_node *itn = ir_stmt[loc];
+    int depth = stmt_nesting_level_[loc] - 1;
+    /*   while (itn->parent != NULL) {
+         itn = itn->parent;
+         if (itn->content->type() == IR_CONTROL_LOOP && itn->payload == -1) {
+         std::string name = static_cast<IR_Loop *>(itn->content)->index()->name();
+         for (int j = 0; j < n_dim; j++)
+         if (index[j] == name) {
+         itn->payload = j;
+         break;
+         }
+         if (itn->payload == -1)
+         throw loop_error("no complex alignment yet");
+         }
+         }
+    */
+    for (int t = depth; t >= 0; t--) {
+      int y = t;
+      ir_tree_node *itn = ir_stmt[loc];
+      
+      while ((itn->parent != NULL) && (y >= 0)) {
+        itn = itn->parent;
+        if (itn->content->type() == IR_CONTROL_LOOP)
+          y--;
+      }
+      
+      if (itn->content->type() == IR_CONTROL_LOOP && itn->payload == -1) {
+        CG_outputBuilder *ocg = ir->builder();
+        
+        itn->payload = depth - t;
+        
+        CG_outputRepr *code =
+          static_cast<IR_Block *>(ir_stmt[loc]->content)->extract();
+        
+        std::vector<CG_outputRepr *> index_expr;
+        std::vector<std::string> old_index;
+        CG_outputRepr *repl = ocg->CreateIdent(index[itn->payload]);
+        index_expr.push_back(repl);
+        old_index.push_back(
+          static_cast<IR_Loop *>(itn->content)->index()->name());
+        code = ocg->CreateSubstitutedStmt(0, code, old_index,
+                                          index_expr);
+        
+        replace.insert(std::pair<int, CG_outputRepr*>(loc, code));
+        //stmt[loc].code = code;
+        
+      }
+    }
+    
+    // set relation variable names
+    Relation r(n_dim);
+    F_And *f_root = r.add_and();
+    itn = ir_stmt[loc];
+    int temp_depth = depth;
+    while (itn->parent != NULL) {
+      
+      itn = itn->parent;
+      if (itn->content->type() == IR_CONTROL_LOOP) {
+        r.name_set_var(itn->payload + 1, index[temp_depth]);
+        
+        temp_depth--;
+      }
+      //static_cast<IR_Loop *>(itn->content)->index()->name());
+    }
+    
+    /*while (itn->parent != NULL) {
+      itn = itn->parent;
+      if (itn->content->type() == IR_CONTROL_LOOP)
+      r.name_set_var(itn->payload+1, static_cast<IR_Loop *>(itn->content)->index()->name());
+      }*/
+    
+    // extract information from loop/if structures
+    std::vector<bool> processed(n_dim, false);
+    std::vector<std::string> vars_to_be_reversed;
+    itn = ir_stmt[loc];
+    while (itn->parent != NULL) {
+      itn = itn->parent;
+      
+      switch (itn->content->type()) {
+      case IR_CONTROL_LOOP: {
+        IR_Loop *lp = static_cast<IR_Loop *>(itn->content);
+        Variable_ID v = r.set_var(itn->payload + 1);
+        int c;
+        
+        try {
+          c = lp->step_size();
+          if (c > 0) {
+            CG_outputRepr *lb = lp->lower_bound();
+            exp2formula(ir, r, f_root, freevar, lb, v, 's',
+                        IR_COND_GE, true);
+            CG_outputRepr *ub = lp->upper_bound();
+            IR_CONDITION_TYPE cond = lp->stop_cond();
+            if (cond == IR_COND_LT || cond == IR_COND_LE)
+              exp2formula(ir, r, f_root, freevar, ub, v, 's',
+                          cond, true);
+            else
+              throw ir_error("loop condition not supported");
+            
+          } else if (c < 0) {
+            CG_outputBuilder *ocg = ir->builder();
+            CG_outputRepr *lb = lp->lower_bound();
+            lb = ocg->CreateMinus(NULL, lb);
+            exp2formula(ir, r, f_root, freevar, lb, v, 's',
+                        IR_COND_GE, true);
+            CG_outputRepr *ub = lp->upper_bound();
+            ub = ocg->CreateMinus(NULL, ub);
+            IR_CONDITION_TYPE cond = lp->stop_cond();
+            if (cond == IR_COND_GE)
+              exp2formula(ir, r, f_root, freevar, ub, v, 's',
+                          IR_COND_LE, true);
+            else if (cond == IR_COND_GT)
+              exp2formula(ir, r, f_root, freevar, ub, v, 's',
+                          IR_COND_LT, true);
+            else
+              throw ir_error("loop condition not supported");
+            
+            vars_to_be_reversed.push_back(lp->index()->name());
+          } else
+            throw ir_error("loop step size zero");
+        } catch (const ir_error &e) {
+          for (int i = 0; i < itn->children.size(); i++)
+            delete itn->children[i];
+          itn->children = std::vector<ir_tree_node *>();
+          itn->content = itn->content->convert();
+          return false;
+        }
+        
+        if (abs(c) != 1) {
+          F_Exists *f_exists = f_root->add_exists();
+          Variable_ID e = f_exists->declare();
+          F_And *f_and = f_exists->add_and();
+          Stride_Handle h = f_and->add_stride(abs(c));
+          if (c > 0)
+            h.update_coef(e, 1);
+          else
+            h.update_coef(e, -1);
+          h.update_coef(v, -1);
+          CG_outputRepr *lb = lp->lower_bound();
+          exp2formula(ir, r, f_and, freevar, lb, e, 's', IR_COND_EQ,
+                      true);
+        }
+        
+        processed[itn->payload] = true;
+        break;
+      }
+      case IR_CONTROL_IF: {
+        CG_outputRepr *cond =
+          static_cast<IR_If *>(itn->content)->condition();
+        try {
+          if (itn->payload % 2 == 1)
+            exp2constraint(ir, r, f_root, freevar, cond, true);
+          else {
+            F_Not *f_not = f_root->add_not();
+            F_And *f_and = f_not->add_and();
+            exp2constraint(ir, r, f_and, freevar, cond, true);
+          }
+        } catch (const ir_error &e) {
+          std::vector<ir_tree_node *> *t;
+          if (itn->parent == NULL)
+            t = &ir_tree;
+          else
+            t = &(itn->parent->children);
+          int id = itn->payload;
+          int i = t->size() - 1;
+          while (i >= 0) {
+            if ((*t)[i] == itn) {
+              for (int j = 0; j < itn->children.size(); j++)
+                delete itn->children[j];
+              itn->children = std::vector<ir_tree_node *>();
+              itn->content = itn->content->convert();
+            } else if ((*t)[i]->payload >> 1 == id >> 1) {
+              delete (*t)[i];
+              t->erase(t->begin() + i);
+            }
+            i--;
+          }
+          return false;
+        }
+        
+        break;
+      }
+      default:
+        for (int i = 0; i < itn->children.size(); i++)
+          delete itn->children[i];
+        itn->children = std::vector<ir_tree_node *>();
+        itn->content = itn->content->convert();
+        return false;
+      }
+    }
+    
+    // add information for missing loops
+    for (int j = 0; j < n_dim; j++)
+      if (!processed[j]) {
+        ir_tree_node *itn = ir_stmt[max_loc];
+        while (itn->parent != NULL) {
+          itn = itn->parent;
+          if (itn->content->type() == IR_CONTROL_LOOP
+              && itn->payload == j)
+            break;
+        }
+        
+        Variable_ID v = r.set_var(j + 1);
+        if (loc < max_loc) {
+          
+          CG_outputBuilder *ocg = ir->builder();
+          
+          CG_outputRepr *lb =
+            static_cast<IR_Loop *>(itn->content)->lower_bound();
+          
+          exp2formula(ir, r, f_root, freevar, lb, v, 's', IR_COND_EQ,
+                      false);
+          
+          /*    if (ir->QueryExpOperation(
+                static_cast<IR_Loop *>(itn->content)->lower_bound())
+                == IR_OP_VARIABLE) {
+                IR_ScalarRef *ref =
+                static_cast<IR_ScalarRef *>(ir->Repr2Ref(
+                static_cast<IR_Loop *>(itn->content)->lower_bound()));
+                std::string name_ = ref->name();
+                
+                for (int i = 0; i < index.size(); i++)
+                if (index[i] == name_) {
+                exp2formula(ir, r, f_root, freevar, lb, v, 's',
+                IR_COND_GE, false);
+                
+                CG_outputRepr *ub =
+                static_cast<IR_Loop *>(itn->content)->upper_bound();
+                IR_CONDITION_TYPE cond =
+                static_cast<IR_Loop *>(itn->content)->stop_cond();
+                if (cond == IR_COND_LT || cond == IR_COND_LE)
+                exp2formula(ir, r, f_root, freevar, ub, v,
+                's', cond, false);
+                
+                
+                
+                }
+                
+                }
+          */
+          
+        } else { // loc > max_loc
+          
+          CG_outputBuilder *ocg = ir->builder();
+          CG_outputRepr *ub =
+            static_cast<IR_Loop *>(itn->content)->upper_bound();
+          
+          exp2formula(ir, r, f_root, freevar, ub, v, 's', IR_COND_EQ,
+                      false);
+          /*if (ir->QueryExpOperation(
+            static_cast<IR_Loop *>(itn->content)->upper_bound())
+            == IR_OP_VARIABLE) {
+            IR_ScalarRef *ref =
+            static_cast<IR_ScalarRef *>(ir->Repr2Ref(
+            static_cast<IR_Loop *>(itn->content)->upper_bound()));
+            std::string name_ = ref->name();
+            
+            for (int i = 0; i < index.size(); i++)
+            if (index[i] == name_) {
+            
+            CG_outputRepr *lb =
+            static_cast<IR_Loop *>(itn->content)->lower_bound();
+            
+            exp2formula(ir, r, f_root, freevar, lb, v, 's',
+            IR_COND_GE, false);
+            
+            CG_outputRepr *ub =
+            static_cast<IR_Loop *>(itn->content)->upper_bound();
+            IR_CONDITION_TYPE cond =
+            static_cast<IR_Loop *>(itn->content)->stop_cond();
+            if (cond == IR_COND_LT || cond == IR_COND_LE)
+            exp2formula(ir, r, f_root, freevar, ub, v,
+            's', cond, false);
+            
+            
+            }
+            }
+          */
+        }
+      }
+    
+    r.setup_names();
+    r.simplify();
+    
+    // insert the statement
+    CG_outputBuilder *ocg = ir->builder();
+    std::vector<CG_outputRepr *> reverse_expr;
+    for (int j = 1; j <= vars_to_be_reversed.size(); j++) {
+      CG_outputRepr *repl = ocg->CreateIdent(vars_to_be_reversed[j]);
+      repl = ocg->CreateMinus(NULL, repl);
+      reverse_expr.push_back(repl);
+    }
+    CG_outputRepr *code =
+      static_cast<IR_Block *>(ir_stmt[loc]->content)->extract();
+    code = ocg->CreateSubstitutedStmt(0, code, vars_to_be_reversed,
+                                      reverse_expr);
+    stmt[loc].code = code;
+    stmt[loc].IS = r;
+    stmt[loc].loop_level = std::vector<LoopLevel>(n_dim);
+    stmt[loc].ir_stmt_node = ir_stmt[loc];
+    for (int i = 0; i < n_dim; i++) {
+      stmt[loc].loop_level[i].type = LoopLevelOriginal;
+      stmt[loc].loop_level[i].payload = i;
+      stmt[loc].loop_level[i].parallel_level = 0;
+    }
+    
+    stmt_nesting_level[loc] = -1;
+  }
+  
+  return true;
+}
+
+Loop::Loop(const IR_Control *control) {
+
+  last_compute_cgr_ = NULL;
+  last_compute_cg_ = NULL;
+  
+  ir = const_cast<IR_Code *>(control->ir_);
+  init_code = NULL;
+  cleanup_code = NULL;
+  tmp_loop_var_name_counter = 1;
+  overflow_var_name_counter = 1;
+  known = Relation::True(0);
+  
+  ir_tree = build_ir_tree(control->clone(), NULL);
+  //    std::vector<ir_tree_node *> ir_stmt;
+  
+  while (!init_loop(ir_tree, ir_stmt)) {
+  }
+
+  
+  
+  for (int i = 0; i < stmt.size(); i++) {
+    std::map<int, CG_outputRepr*>::iterator it = replace.find(i);
+    
+    if (it != replace.end())
+      stmt[i].code = it->second;
+    else
+      stmt[i].code = stmt[i].code;
+  }
+  
+  if (stmt.size() != 0)
+    dep = DependenceGraph(stmt[0].IS.n_set());
+  else
+    dep = DependenceGraph(0);
+  // init the dependence graph
+  for (int i = 0; i < stmt.size(); i++)
+    dep.insert();
+  
+  for (int i = 0; i < stmt.size(); i++)
+    for (int j = i; j < stmt.size(); j++) {
+      std::pair<std::vector<DependenceVector>,
+        std::vector<DependenceVector> > dv = test_data_dependences(
+          ir, stmt[i].code, stmt[i].IS, stmt[j].code, stmt[j].IS,
+          freevar, index, stmt_nesting_level_[i],
+          stmt_nesting_level_[j]);
+      
+      for (int k = 0; k < dv.first.size(); k++) {
+        if (is_dependence_valid(ir_stmt[i], ir_stmt[j], dv.first[k],
+                                true))
+          dep.connect(i, j, dv.first[k]);
+        else {
+          dep.connect(j, i, dv.first[k].reverse());
+        }
+        
+      }
+      for (int k = 0; k < dv.second.size(); k++)
+        if (is_dependence_valid(ir_stmt[j], ir_stmt[i], dv.second[k],
+                                false))
+          dep.connect(j, i, dv.second[k]);
+        else {
+          dep.connect(i, j, dv.second[k].reverse());
+        }
+      // std::pair<std::vector<DependenceVector>,
+      //                std::vector<DependenceVector> > dv_ = test_data_dependences(
+      
+    }
+  
+
+
+  // init dumb transformation relations e.g. [i, j] -> [ 0, i, 0, j, 0]
+  for (int i = 0; i < stmt.size(); i++) {
+    int n = stmt[i].IS.n_set();
+    stmt[i].xform = Relation(n, 2 * n + 1);
+    F_And *f_root = stmt[i].xform.add_and();
+    
+    for (int j = 1; j <= n; j++) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(stmt[i].xform.output_var(2 * j), 1);
+      h.update_coef(stmt[i].xform.input_var(j), -1);
+    }
+    
+    for (int j = 1; j <= 2 * n + 1; j += 2) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(stmt[i].xform.output_var(j), 1);
+    }
+    stmt[i].xform.simplify();
+  }
+  
+  if (stmt.size() != 0)
+    num_dep_dim = stmt[0].IS.n_set();
+  else
+    num_dep_dim = 0;
+  // debug
+  /*for (int i = 0; i < stmt.size(); i++) {
+    std::cout << i << ": ";
+    //stmt[i].xform.print();
+    stmt[i].IS.print();
+    std::cout << std::endl;
+    
+    }*/
+  //end debug
+}
+
+Loop::~Loop() {
+  
+  delete last_compute_cgr_;
+  delete last_compute_cg_;
+  
+  for (int i = 0; i < stmt.size(); i++)
+    if (stmt[i].code != NULL) {
+      stmt[i].code->clear();
+      delete stmt[i].code;
+    }
+  
+  for (int i = 0; i < ir_tree.size(); i++)
+    delete ir_tree[i];
+  
+  if (init_code != NULL) {
+    init_code->clear();
+    delete init_code;
+  }
+  if (cleanup_code != NULL) {
+    cleanup_code->clear();
+    delete cleanup_code;
+  }
+}
+
+int Loop::get_dep_dim_of(int stmt_num, int level) const {
+  if (stmt_num < 0 || stmt_num >= stmt.size())
+    throw std::invalid_argument("invaid statement " + to_string(stmt_num));
+  
+  if (level < 1 || level > stmt[stmt_num].loop_level.size())
+    return -1;
+  
+  int trip_count = 0;
+  while (true) {
+    switch (stmt[stmt_num].loop_level[level - 1].type) {
+    case LoopLevelOriginal:
+      return stmt[stmt_num].loop_level[level - 1].payload;
+    case LoopLevelTile:
+      level = stmt[stmt_num].loop_level[level - 1].payload;
+      if (level < 1)
+        return -1;
+      if (level > stmt[stmt_num].loop_level.size())
+        throw loop_error(
+          "incorrect loop level information for statement "
+          + to_string(stmt_num));
+      break;
+    default:
+      throw loop_error(
+        "unknown loop level information for statement "
+        + to_string(stmt_num));
+    }
+    trip_count++;
+    if (trip_count >= stmt[stmt_num].loop_level.size())
+      throw loop_error(
+        "incorrect loop level information for statement "
+        + to_string(stmt_num));
+  }
+}
+
+int Loop::get_last_dep_dim_before(int stmt_num, int level) const {
+  if (stmt_num < 0 || stmt_num >= stmt.size())
+    throw std::invalid_argument("invaid statement " + to_string(stmt_num));
+  
+  if (level < 1)
+    return -1;
+  if (level > stmt[stmt_num].loop_level.size())
+    level = stmt[stmt_num].loop_level.size() + 1;
+  
+  for (int i = level - 1; i >= 1; i--)
+    if (stmt[stmt_num].loop_level[i - 1].type == LoopLevelOriginal)
+      return stmt[stmt_num].loop_level[i - 1].payload;
+  
+  return -1;
+}
+
+void Loop::print_internal_loop_structure() const {
+  for (int i = 0; i < stmt.size(); i++) {
+    std::vector<int> lex = getLexicalOrder(i);
+    std::cout << "s" << i + 1 << ": ";
+    for (int j = 0; j < stmt[i].loop_level.size(); j++) {
+      if (2 * j < lex.size())
+        std::cout << lex[2 * j];
+      switch (stmt[i].loop_level[j].type) {
+      case LoopLevelOriginal:
+        std::cout << "(dim:" << stmt[i].loop_level[j].payload << ")";
+        break;
+      case LoopLevelTile:
+        std::cout << "(tile:" << stmt[i].loop_level[j].payload << ")";
+        break;
+      default:
+        std::cout << "(unknown)";
+      }
+      std::cout << ' ';
+    }
+    for (int j = 2 * stmt[i].loop_level.size(); j < lex.size(); j += 2) {
+      std::cout << lex[j];
+      if (j != lex.size() - 1)
+        std::cout << ' ';
+    }
+    std::cout << std::endl;
+  }
+}
+
+CG_outputRepr *Loop::getCode(int effort) const {
+  const int m = stmt.size();
+  if (m == 0)
+    return NULL;
+  const int n = stmt[0].xform.n_out();
+  
+  if (last_compute_cg_ == NULL) {
+    std::vector<Relation> IS(m);
+    std::vector<Relation> xforms(m);
+    for (int i = 0; i < m; i++) {
+      IS[i] = stmt[i].IS;
+      xforms[i] = stmt[i].xform;
+    }
+    Relation known = Extend_Set(copy(this->known), n - this->known.n_set());
+    
+    last_compute_cg_ = new CodeGen(xforms, IS, known);
+    delete last_compute_cgr_;
+    last_compute_cgr_ = NULL;
+  }
+  
+  if (last_compute_cgr_ == NULL || last_compute_effort_ != effort) {
+    delete last_compute_cgr_;
+    last_compute_cgr_ = last_compute_cg_->buildAST(effort);
+    last_compute_effort_ = effort;
+  }
+  
+  std::vector<CG_outputRepr *> stmts(m);
+  for (int i = 0; i < m; i++)
+    stmts[i] = stmt[i].code;
+  CG_outputBuilder *ocg = ir->builder();
+  CG_outputRepr *repr = last_compute_cgr_->printRepr(ocg, stmts);
+  
+  if (init_code != NULL)
+    repr = ocg->StmtListAppend(init_code->clone(), repr);
+  if (cleanup_code != NULL)
+    repr = ocg->StmtListAppend(repr, cleanup_code->clone());
+  
+  return repr;
+}
+
+void Loop::printCode(int effort) const {
+  const int m = stmt.size();
+  if (m == 0)
+    return;
+  const int n = stmt[0].xform.n_out();
+  
+  if (last_compute_cg_ == NULL) {
+    std::vector<Relation> IS(m);
+    std::vector<Relation> xforms(m);
+    for (int i = 0; i < m; i++) {
+      IS[i] = stmt[i].IS;
+      xforms[i] = stmt[i].xform;
+    }
+    Relation known = Extend_Set(copy(this->known), n - this->known.n_set());
+    
+    last_compute_cg_ = new CodeGen(xforms, IS, known);
+    delete last_compute_cgr_;
+    last_compute_cgr_ = NULL;
+  }
+  
+  if (last_compute_cgr_ == NULL || last_compute_effort_ != effort) {
+    delete last_compute_cgr_;
+    last_compute_cgr_ = last_compute_cg_->buildAST(effort);
+    last_compute_effort_ = effort;
+  }
+  
+  std::string repr = last_compute_cgr_->printString();
+  std::cout << repr << std::endl;
+}
+
+void Loop::printIterationSpace() const {
+  for (int i = 0; i < stmt.size(); i++) {
+    std::cout << "s" << i << ": ";
+    Relation r = getNewIS(i);
+    for (int j = 1; j <= r.n_inp(); j++)
+      r.name_input_var(j, CodeGen::loop_var_name_prefix + to_string(j));
+    r.setup_names();
+    r.print();
+  }
+}
+
+void Loop::printDependenceGraph() const {
+  if (dep.edgeCount() == 0)
+    std::cout << "no dependence exists" << std::endl;
+  else {
+    std::cout << "dependence graph:" << std::endl;
+    std::cout << dep;
+  }
+}
+
+Relation Loop::getNewIS(int stmt_num) const {
+  Relation result;
+  
+  if (stmt[stmt_num].xform.is_null()) {
+    Relation known = Extend_Set(copy(this->known),
+                                stmt[stmt_num].IS.n_set() - this->known.n_set());
+    result = Intersection(copy(stmt[stmt_num].IS), known);
+  } else {
+    Relation known = Extend_Set(copy(this->known),
+                                stmt[stmt_num].xform.n_out() - this->known.n_set());
+    result = Intersection(
+      Range(
+        Restrict_Domain(copy(stmt[stmt_num].xform),
+                        copy(stmt[stmt_num].IS))), known);
+  }
+  
+  result.simplify(2, 4);
+  
+  return result;
+}
+
+std::vector<Relation> Loop::getNewIS() const {
+  const int m = stmt.size();
+  
+  std::vector<Relation> new_IS(m);
+  for (int i = 0; i < m; i++)
+    new_IS[i] = getNewIS(i);
+  
+  return new_IS;
+}
+
+void Loop::pragma(int stmt_num, int level, const std::string &pragmaText) {
+	// check sanity of parameters
+	if(stmt_num < 0)
+		throw std::invalid_argument("invalid statement " + to_string(stmt_num));
+	
+	CG_outputBuilder *ocg = ir->builder();
+	CG_outputRepr *code = stmt[stmt_num].code;
+	ocg->CreatePragmaAttribute(code, level, pragmaText);
+}
+
+void Loop::prefetch(int stmt_num, int level, const std::string &arrName, int hint) {
+	// check sanity of parameters
+	if(stmt_num < 0)
+		throw std::invalid_argument("invalid statement " + to_string(stmt_num));
+
+	CG_outputBuilder *ocg = ir->builder();
+	CG_outputRepr *code = stmt[stmt_num].code;
+	ocg->CreatePrefetchAttribute(code, level, arrName, hint);
+}
+
+std::vector<int> Loop::getLexicalOrder(int stmt_num) const {
+  assert(stmt_num < stmt.size());
+  
+  const int n = stmt[stmt_num].xform.n_out();
+  std::vector<int> lex(n, 0);
+  
+  for (int i = 0; i < n; i += 2)
+    lex[i] = get_const(stmt[stmt_num].xform, i, Output_Var);
+  
+  return lex;
+}
+
+// find the sub loop nest specified by stmt_num and level,
+// only iteration space satisfiable statements returned.
+std::set<int> Loop::getSubLoopNest(int stmt_num, int level) const {
+  assert(stmt_num >= 0 && stmt_num < stmt.size());
+  assert(level > 0 && level <= stmt[stmt_num].loop_level.size());
+  
+  std::set<int> working;
+  for (int i = 0; i < stmt.size(); i++)
+    if (const_cast<Loop *>(this)->stmt[i].IS.is_upper_bound_satisfiable()
+        && stmt[i].loop_level.size() >= level)
+      working.insert(i);
+  
+  for (int i = 1; i <= level; i++) {
+    int a = getLexicalOrder(stmt_num, i);
+    for (std::set<int>::iterator j = working.begin(); j != working.end();) {
+      int b = getLexicalOrder(*j, i);
+      if (b != a)
+        working.erase(j++);
+      else
+        ++j;
+    }
+  }
+  
+  return working;
+}
+
+int Loop::getLexicalOrder(int stmt_num, int level) const {
+  assert(stmt_num >= 0 && stmt_num < stmt.size());
+  assert(level > 0 && level <= stmt[stmt_num].loop_level.size()+1);
+  
+  Relation &r = const_cast<Loop *>(this)->stmt[stmt_num].xform;
+  for (EQ_Iterator e(r.single_conjunct()->EQs()); e; e++)
+    if (abs((*e).get_coef(r.output_var(2 * level - 1))) == 1) {
+      bool is_const = true;
+      for (Constr_Vars_Iter cvi(*e); cvi; cvi++)
+        if (cvi.curr_var() != r.output_var(2 * level - 1)) {
+          is_const = false;
+          break;
+        }
+      if (is_const) {
+        int t = static_cast<int>((*e).get_const());
+        return (*e).get_coef(r.output_var(2 * level - 1)) > 0 ? -t : t;
+      }
+    }
+  
+  throw loop_error(
+    "can't find lexical order for statement " + to_string(stmt_num)
+    + "'s loop level " + to_string(level));
+}
+
+std::set<int> Loop::getStatements(const std::vector<int> &lex, int dim) const {
+  const int m = stmt.size();
+  
+  std::set<int> same_loops;
+  for (int i = 0; i < m; i++) {
+    if (dim < 0)
+      same_loops.insert(i);
+    else {
+      std::vector<int> a_lex = getLexicalOrder(i);
+      int j;
+      for (j = 0; j <= dim; j += 2)
+        if (lex[j] != a_lex[j])
+          break;
+      if (j > dim)
+        same_loops.insert(i);
+    }
+    
+  }
+  
+  return same_loops;
+}
+
+void Loop::shiftLexicalOrder(const std::vector<int> &lex, int dim, int amount) {
+  const int m = stmt.size();
+  
+  if (amount == 0)
+    return;
+  
+  for (int i = 0; i < m; i++) {
+    std::vector<int> lex2 = getLexicalOrder(i);
+    
+    bool need_shift = true;
+    
+    for (int j = 0; j < dim; j++)
+      if (lex2[j] != lex[j]) {
+        need_shift = false;
+        break;
+      }
+    
+    if (!need_shift)
+      continue;
+    
+    if (amount > 0) {
+      if (lex2[dim] < lex[dim])
+        continue;
+    } else if (amount < 0) {
+      if (lex2[dim] > lex[dim])
+        continue;
+    }
+    
+    assign_const(stmt[i].xform, dim, lex2[dim] + amount);
+  }
+}
+
+std::vector<std::set<int> > Loop::sort_by_same_loops(std::set<int> active,
+                                                     int level) {
+  
+  std::set<int> not_nested_at_this_level;
+  std::map<ir_tree_node*, std::set<int> > sorted_by_loop;
+  std::map<int, std::set<int> > sorted_by_lex_order;
+  std::vector<std::set<int> > to_return;
+  bool lex_order_already_set = false;
+  for (std::set<int>::iterator it = active.begin(); it != active.end();
+       it++) {
+    
+    if (stmt[*it].ir_stmt_node == NULL)
+      lex_order_already_set = true;
+  }
+  
+  if (lex_order_already_set) {
+    
+    for (std::set<int>::iterator it = active.begin(); it != active.end();
+         it++) {
+      std::map<int, std::set<int> >::iterator it2 =
+        sorted_by_lex_order.find(
+          get_const(stmt[*it].xform, 2 * (level - 1),
+                    Output_Var));
+      
+      if (it2 != sorted_by_lex_order.end())
+        it2->second.insert(*it);
+      else {
+        
+        std::set<int> to_insert;
+        
+        to_insert.insert(*it);
+        
+        sorted_by_lex_order.insert(
+          std::pair<int, std::set<int> >(
+            get_const(stmt[*it].xform, 2 * (level - 1),
+                      Output_Var), to_insert));
+        
+      }
+      
+    }
+    
+    for (std::map<int, std::set<int> >::iterator it2 =
+           sorted_by_lex_order.begin(); it2 != sorted_by_lex_order.end();
+         it2++)
+      to_return.push_back(it2->second);
+    
+  } else {
+    
+    for (std::set<int>::iterator it = active.begin(); it != active.end();
+         it++) {
+      
+      ir_tree_node* itn = stmt[*it].ir_stmt_node;
+      itn = itn->parent;
+      while ((itn != NULL) && (itn->payload != level - 1))
+        itn = itn->parent;
+      
+      if (itn == NULL)
+        not_nested_at_this_level.insert(*it);
+      else {
+        std::map<ir_tree_node*, std::set<int> >::iterator it2 =
+          sorted_by_loop.find(itn);
+        
+        if (it2 != sorted_by_loop.end())
+          it2->second.insert(*it);
+        else {
+          std::set<int> to_insert;
+          
+          to_insert.insert(*it);
+          
+          sorted_by_loop.insert(
+            std::pair<ir_tree_node*, std::set<int> >(itn,
+                                                     to_insert));
+          
+        }
+        
+      }
+      
+    }
+    if (not_nested_at_this_level.size() > 0) {
+      for (std::set<int>::iterator it = not_nested_at_this_level.begin();
+           it != not_nested_at_this_level.end(); it++) {
+        std::set<int> temp;
+        temp.insert(*it);
+        to_return.push_back(temp);
+        
+      }
+    }
+    for (std::map<ir_tree_node*, std::set<int> >::iterator it2 =
+           sorted_by_loop.begin(); it2 != sorted_by_loop.end(); it2++)
+      to_return.push_back(it2->second);
+  }
+  return to_return;
+}
+
+void update_successors(int n, int node_num[], int cant_fuse_with[],
+                       Graph<std::set<int>, bool> &g, std::list<int> &work_list) {
+  
+  std::set<int> disconnect;
+  for (Graph<std::set<int>, bool>::EdgeList::iterator i =
+         g.vertex[n].second.begin(); i != g.vertex[n].second.end(); i++) {
+    int m = i->first;
+    
+    if (node_num[m] != -1)
+      throw loop_error("Graph input for fusion has cycles not a DAG!!");
+    
+    std::vector<bool> check_ = g.getEdge(n, m);
+    
+    bool has_bad_edge_path = false;
+    for (int i = 0; i < check_.size(); i++)
+      if (!check_[i]) {
+        has_bad_edge_path = true;
+        break;
+      }
+    if (has_bad_edge_path)
+      cant_fuse_with[m] = std::max(cant_fuse_with[m], node_num[n]);
+    else
+      cant_fuse_with[m] = std::max(cant_fuse_with[m], cant_fuse_with[n]);
+    disconnect.insert(m);
+  }
+  
+  
+  for (std::set<int>::iterator i = disconnect.begin(); i != disconnect.end();
+       i++) {
+    g.disconnect(n, *i);
+    
+    bool no_incoming_edges = true;
+    for (int j = 0; j < g.vertex.size(); j++)
+      if (j != *i)
+        if (g.hasEdge(j, *i)) {
+          no_incoming_edges = false;
+          break;
+        }
+    
+    
+    if (no_incoming_edges)
+      work_list.push_back(*i);
+  }
+  
+}
+
+Graph<std::set<int>, bool> Loop::construct_induced_graph_at_level(
+  std::vector<std::set<int> > s, DependenceGraph dep, int dep_dim) {
+  Graph<std::set<int>, bool> g;
+  
+  for (int i = 0; i < s.size(); i++)
+    g.insert(s[i]);
+  
+  for (int i = 0; i < s.size(); i++) {
+    
+    for (int j = i + 1; j < s.size(); j++) {
+      bool has_true_edge_i_to_j = false;
+      bool has_true_edge_j_to_i = false;
+      bool is_connected_i_to_j = false;
+      bool is_connected_j_to_i = false;
+      for (std::set<int>::iterator ii = s[i].begin(); ii != s[i].end();
+           ii++) {
+        
+        for (std::set<int>::iterator jj = s[j].begin();
+             jj != s[j].end(); jj++) {
+          
+          std::vector<DependenceVector> dvs = dep.getEdge(*ii, *jj);
+          for (int k = 0; k < dvs.size(); k++)
+            if (dvs[k].is_control_dependence()
+                || (dvs[k].is_data_dependence()
+                    && dvs[k].has_been_carried_at(dep_dim))) {
+              
+              if (dvs[k].is_data_dependence()
+                  && dvs[k].has_negative_been_carried_at(
+                    dep_dim)) {
+                //g.connect(i, j, false);
+                is_connected_i_to_j = true;
+                break;
+              } else {
+                //g.connect(i, j, true);
+                
+                has_true_edge_i_to_j = true;
+                //break
+              }
+            }
+          
+          //if (is_connected)
+          
+          //    break;
+          //        if (has_true_edge_i_to_j && !is_connected_i_to_j)
+          //                g.connect(i, j, true);
+          dvs = dep.getEdge(*jj, *ii);
+          for (int k = 0; k < dvs.size(); k++)
+            if (dvs[k].is_control_dependence()
+                || (dvs[k].is_data_dependence()
+                    && dvs[k].has_been_carried_at(dep_dim))) {
+              
+              if (is_connected_i_to_j || has_true_edge_i_to_j)
+                throw loop_error(
+                  "Graph input for fusion has cycles not a DAG!!");
+              
+              if (dvs[k].is_data_dependence()
+                  && dvs[k].has_negative_been_carried_at(
+                    dep_dim)) {
+                //g.connect(i, j, false);
+                is_connected_j_to_i = true;
+                break;
+              } else {
+                //g.connect(i, j, true);
+                
+                has_true_edge_j_to_i = true;
+                //break;
+              }
+            }
+          
+          //    if (is_connected)
+          //break;
+          //    if (is_connected)
+          //break;
+        }
+        
+        
+        //if (is_connected)
+        //  break;
+      }
+      
+      
+      if (is_connected_i_to_j)
+        g.connect(i, j, false);
+      else if (has_true_edge_i_to_j)
+        g.connect(i, j, true);
+      
+      if (is_connected_j_to_i)
+        g.connect(j, i, false);
+      else if (has_true_edge_j_to_i)
+        g.connect(j, i, true);
+      
+      
+    }
+  }
+  return g;
+}
+
+std::vector<std::set<int> > Loop::typed_fusion(Graph<std::set<int>, bool> g) {
+  
+  bool roots[g.vertex.size()];
+  
+  for (int i = 0; i < g.vertex.size(); i++)
+    roots[i] = true;
+  
+  for (int i = 0; i < g.vertex.size(); i++)
+    for (int j = i + 1; j < g.vertex.size(); j++) {
+      
+      if (g.hasEdge(i, j))
+        roots[j] = false;
+      
+      if (g.hasEdge(j, i))
+        roots[i] = false;
+      
+    }
+  
+  std::list<int> work_list;
+  int cant_fuse_with[g.vertex.size()];
+  std::vector<std::set<int> > s;
+  //Each Fused set's representative node
+  
+  int node_to_fused_nodes[g.vertex.size()];
+  int node_num[g.vertex.size()];
+  for (int i = 0; i < g.vertex.size(); i++) {
+    if (roots[i] == true)
+      work_list.push_back(i);
+    cant_fuse_with[i] = 0;
+    node_to_fused_nodes[i] = 0;
+    node_num[i] = -1;
+  }
+  // topological sort according to chun's permute algorithm
+  //   std::vector<std::set<int> > s = g.topoSort();
+  std::vector<std::set<int> > s2 = g.topoSort();
+  if (work_list.empty() || (s2.size() != g.vertex.size())) {
+    
+    std::cout << s2.size() << "\t" << g.vertex.size() << std::endl;
+    throw loop_error("Input for fusion not a DAG!!");
+    
+    
+  }
+  int fused_nodes_counter = 0;
+  while (!work_list.empty()) {
+    int n = work_list.front();
+    //int n_ = g.vertex[n].first;
+    work_list.pop_front();
+    int node;
+    if (cant_fuse_with[n] == 0)
+      node = 0;
+    else
+      node = cant_fuse_with[n];
+    
+    if ((fused_nodes_counter != 0) && (node != fused_nodes_counter)) {
+      int rep_node = node_to_fused_nodes[node];
+      node_num[n] = node_num[rep_node];
+      
+      try {
+        update_successors(n, node_num, cant_fuse_with, g, work_list);
+      } catch (const loop_error &e) {
+        
+        throw loop_error(
+          "statements cannot be fused together due to negative dependence");
+        
+        
+      }
+      for (std::set<int>::iterator it = g.vertex[n].first.begin();
+           it != g.vertex[n].first.end(); it++)
+        s[node].insert(*it);
+    } else {
+      //std::set<int> new_node;
+      //new_node.insert(n_);
+      s.push_back(g.vertex[n].first);
+      node_to_fused_nodes[node] = n;
+      node_num[n] = ++node;
+      try {
+        update_successors(n, node_num, cant_fuse_with, g, work_list);
+      } catch (const loop_error &e) {
+        
+        throw loop_error(
+          "statements cannot be fused together due to negative dependence");
+        
+        
+      }
+      fused_nodes_counter++;
+    }
+  }
+  
+  return s;
+}
+
+void Loop::setLexicalOrder(int dim, const std::set<int> &active,
+                           int starting_order, std::vector<std::vector<std::string> > idxNames) {
+  if (active.size() == 0)
+    return;
+  
+  // check for sanity of parameters
+  if (dim < 0 || dim % 2 != 0)
+    throw std::invalid_argument(
+      "invalid constant loop level to set lexicographical order");
+  std::vector<int> lex;
+  int ref_stmt_num;
+  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++) {
+    if ((*i) < 0 || (*i) >= stmt.size())
+      throw std::invalid_argument(
+        "invalid statement number " + to_string(*i));
+    if (dim >= stmt[*i].xform.n_out())
+      throw std::invalid_argument(
+        "invalid constant loop level to set lexicographical order");
+    if (i == active.begin()) {
+      lex = getLexicalOrder(*i);
+      ref_stmt_num = *i;
+    } else {
+      std::vector<int> lex2 = getLexicalOrder(*i);
+      for (int j = 0; j < dim; j += 2)
+        if (lex[j] != lex2[j])
+          throw std::invalid_argument(
+            "statements are not in the same sub loop nest");
+    }
+  }
+  
+  // sepearate statements by current loop level types
+  int level = (dim + 2) / 2;
+  std::map<std::pair<LoopLevelType, int>, std::set<int> > active_by_level_type;
+  std::set<int> active_by_no_level;
+  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++) {
+    if (level > stmt[*i].loop_level.size())
+      active_by_no_level.insert(*i);
+    else
+      active_by_level_type[std::make_pair(
+          stmt[*i].loop_level[level - 1].type,
+          stmt[*i].loop_level[level - 1].payload)].insert(*i);
+  }
+  
+  // further separate statements due to control dependences
+  std::vector<std::set<int> > active_by_level_type_splitted;
+  for (std::map<std::pair<LoopLevelType, int>, std::set<int> >::iterator i =
+         active_by_level_type.begin(); i != active_by_level_type.end(); i++)
+    active_by_level_type_splitted.push_back(i->second);
+  for (std::set<int>::iterator i = active_by_no_level.begin();
+       i != active_by_no_level.end(); i++)
+    for (int j = active_by_level_type_splitted.size() - 1; j >= 0; j--) {
+      std::set<int> controlled, not_controlled;
+      for (std::set<int>::iterator k =
+             active_by_level_type_splitted[j].begin();
+           k != active_by_level_type_splitted[j].end(); k++) {
+        std::vector<DependenceVector> dvs = dep.getEdge(*i, *k);
+        bool is_controlled = false;
+        for (int kk = 0; kk < dvs.size(); kk++)
+          if (dvs[kk].type = DEP_CONTROL) {
+            is_controlled = true;
+            break;
+          }
+        if (is_controlled)
+          controlled.insert(*k);
+        else
+          not_controlled.insert(*k);
+      }
+      if (controlled.size() != 0 && not_controlled.size() != 0) {
+        active_by_level_type_splitted.erase(
+          active_by_level_type_splitted.begin() + j);
+        active_by_level_type_splitted.push_back(controlled);
+        active_by_level_type_splitted.push_back(not_controlled);
+      }
+    }
+  
+  // set lexical order separating loops with different loop types first
+  if (active_by_level_type_splitted.size() + active_by_no_level.size() > 1) {
+    int dep_dim = get_last_dep_dim_before(ref_stmt_num, level) + 1;
+    
+    Graph<std::set<int>, Empty> g;
+    for (std::vector<std::set<int> >::iterator i =
+           active_by_level_type_splitted.begin();
+         i != active_by_level_type_splitted.end(); i++)
+      g.insert(*i);
+    for (std::set<int>::iterator i = active_by_no_level.begin();
+         i != active_by_no_level.end(); i++) {
+      std::set<int> t;
+      t.insert(*i);
+      g.insert(t);
+    }
+    for (int i = 0; i < g.vertex.size(); i++)
+      for (int j = i + 1; j < g.vertex.size(); j++) {
+        bool connected = false;
+        for (std::set<int>::iterator ii = g.vertex[i].first.begin();
+             ii != g.vertex[i].first.end(); ii++) {
+          for (std::set<int>::iterator jj = g.vertex[j].first.begin();
+               jj != g.vertex[j].first.end(); jj++) {
+            std::vector<DependenceVector> dvs = dep.getEdge(*ii,
+                                                            *jj);
+            for (int k = 0; k < dvs.size(); k++)
+              if (dvs[k].is_control_dependence()
+                  || (dvs[k].is_data_dependence()
+                      && !dvs[k].has_been_carried_before(
+                        dep_dim))) {
+                g.connect(i, j);
+                connected = true;
+                break;
+              }
+            if (connected)
+              break;
+          }
+          if (connected)
+            break;
+        }
+        connected = false;
+        for (std::set<int>::iterator ii = g.vertex[i].first.begin();
+             ii != g.vertex[i].first.end(); ii++) {
+          for (std::set<int>::iterator jj = g.vertex[j].first.begin();
+               jj != g.vertex[j].first.end(); jj++) {
+            std::vector<DependenceVector> dvs = dep.getEdge(*jj,
+                                                            *ii);
+            // find the sub loop nest specified by stmt_num and level,
+            // only iteration space satisfiable statements returned.
+            for (int k = 0; k < dvs.size(); k++)
+              if (dvs[k].is_control_dependence()
+                  || (dvs[k].is_data_dependence()
+                      && !dvs[k].has_been_carried_before(
+                        dep_dim))) {
+                g.connect(j, i);
+                connected = true;
+                break;
+              }
+            if (connected)
+              break;
+          }
+          if (connected)
+            break;
+        }
+      }
+    
+    std::vector<std::set<int> > s = g.topoSort();
+    if (s.size() != g.vertex.size())
+      throw loop_error(
+        "cannot separate statements with different loop types at loop level "
+        + to_string(level));
+    
+    // assign lexical order
+    int order = starting_order;
+    for (int i = 0; i < s.size(); i++) {
+      std::set<int> &cur_scc = g.vertex[*(s[i].begin())].first;
+      int sz = cur_scc.size();
+      if (sz == 1) {
+        int cur_stmt = *(cur_scc.begin());
+        assign_const(stmt[cur_stmt].xform, dim, order);
+        for (int j = dim + 2; j < stmt[cur_stmt].xform.n_out(); j += 2)
+          assign_const(stmt[cur_stmt].xform, j, 0);
+        order++;
+      } else {
+        setLexicalOrder(dim, cur_scc, order, idxNames);
+        order += sz;
+      }
+    }
+  }
+  // set lexical order seperating single iteration statements and loops
+  else {
+    std::set<int> true_singles;
+    std::set<int> nonsingles;
+    std::map<coef_t, std::set<int> > fake_singles;
+    std::set<int> fake_singles_;
+    
+    // sort out statements that do not require loops
+    for (std::set<int>::iterator i = active.begin(); i != active.end();
+         i++) {
+      Relation cur_IS = getNewIS(*i);
+      if (is_single_iteration(cur_IS, dim + 1)) {
+        bool is_all_single = true;
+        for (int j = dim + 3; j < stmt[*i].xform.n_out(); j += 2)
+          if (!is_single_iteration(cur_IS, j)) {
+            is_all_single = false;
+            break;
+          }
+        if (is_all_single)
+          true_singles.insert(*i);
+        else {
+          fake_singles_.insert(*i);
+          try {
+            fake_singles[get_const(cur_IS, dim + 1, Set_Var)].insert(
+              *i);
+          } catch (const std::exception &e) {
+            fake_singles[posInfinity].insert(*i);
+          }
+        }
+      } else
+        nonsingles.insert(*i);
+    }
+    
+    
+    // split nonsingles forcibly according to negative dependences present (loop unfusible)
+    int dep_dim = get_dep_dim_of(ref_stmt_num, level);
+    
+    if (dim < stmt[ref_stmt_num].xform.n_out() - 1) {
+      
+      bool dummy_level_found = false;
+      
+      std::vector<std::set<int> > s;
+      
+      s = sort_by_same_loops(active, level);
+      bool further_levels_exist = false;
+      
+      if (!idxNames.empty())
+        if (level <= idxNames[ref_stmt_num].size())
+          if (idxNames[ref_stmt_num][level - 1].length() == 0) {
+            //  && s.size() == 1) {
+            int order1 = 0;
+            dummy_level_found = true;
+            
+            for (int i = level; i < idxNames[ref_stmt_num].size();
+                 i++)
+              if (idxNames[ref_stmt_num][i].length() > 0)
+                further_levels_exist = true;
+            
+          }
+      
+      //if (!dummy_level_found) {
+      
+      if (s.size() > 1) {
+        
+        Graph<std::set<int>, bool> g = construct_induced_graph_at_level(
+          s, dep, dep_dim);
+        s = typed_fusion(g);
+      }
+      int order = 0;
+      for (int i = 0; i < s.size(); i++) {
+        
+        for (std::set<int>::iterator it = s[i].begin();
+             it != s[i].end(); it++)
+          assign_const(stmt[*it].xform, dim, order);
+        
+        if ((dim + 2) <= (stmt[ref_stmt_num].xform.n_out() - 1))
+          setLexicalOrder(dim + 2, s[i], order, idxNames);
+        
+        order++;
+      }
+      //}
+      /*    else {
+            
+            int order1 = 0;
+            int order = 0;
+            for (std::set<int>::iterator i = active.begin();
+            i != active.end(); i++) {
+            if (!further_levels_exist)
+            assign_const(stmt[*i].xform, dim, order1++);
+            else
+            assign_const(stmt[*i].xform, dim, order1);
+            
+            }
+            
+            if ((dim + 2) <= (stmt[ref_stmt_num].xform.n_out() - 1) && further_levels_exist)
+            setLexicalOrder(dim + 2, active, order, idxNames);
+            }
+      */
+    } else {
+      int dummy_order = 0;
+      for (std::set<int>::iterator i = active.begin(); i != active.end();
+           i++)
+        assign_const(stmt[*i].xform, dim, dummy_order++);
+    }
+    /*for (int i = 0; i < g2.vertex.size(); i++)
+      for (int j = i+1; j < g2.vertex.size(); j++) {
+      std::vector<DependenceVector> dvs = dep.getEdge(g2.vertex[i].first, g2.vertex[j].first);
+      for (int k = 0; k < dvs.size(); k++)
+      if (dvs[k].is_control_dependence() ||
+      (dvs[k].is_data_dependence() && dvs[k].has_negative_been_carried_at(dep_dim))) {
+      g2.connect(i, j);
+      break;
+      }
+      dvs = dep.getEdge(g2.vertex[j].first, g2.vertex[i].first);
+      for (int k = 0; k < dvs.size(); k++)
+      if (dvs[k].is_control_dependence() ||
+      (dvs[k].is_data_dependence() && dvs[k].has_negative_been_carried_at(dep_dim))) {
+      g2.connect(j, i);
+      break;
+      }
+      }
+      
+      std::vector<std::set<int> > s2 = g2.packed_topoSort();
+      
+      std::vector<std::set<int> > splitted_nonsingles;
+      for (int i = 0; i < s2.size(); i++) {
+      std::set<int> cur_scc;
+      for (std::set<int>::iterator j = s2[i].begin(); j != s2[i].end(); j++)
+      cur_scc.insert(g2.vertex[*j].first);
+      splitted_nonsingles.push_back(cur_scc);
+      }
+    */
+    //convert to dependence graph for grouped statements
+    //dep_dim = get_last_dep_dim_before(ref_stmt_num, level) + 1;
+    /*int order = 0;
+      for (std::set<int>::iterator j = active.begin(); j != active.end();
+      j++) {
+      std::set<int> continuous;
+      std::cout<< active.size()<<std::endl;
+      while (nonsingles.find(*j) != nonsingles.end() && j != active.end()) {
+      continuous.insert(*j);
+      j++;
+      }
+      
+      printf("continuous size is %d\n", continuous.size());
+      
+      
+      
+      if (continuous.size() > 0) {
+      std::vector<std::set<int> > s = typed_fusion(continuous, dep,
+      dep_dim);
+      
+      for (int i = 0; i < s.size(); i++) {
+      for (std::set<int>::iterator l = s[i].begin();
+      l != s[i].end(); l++) {
+      assign_const(stmt[*l].xform, dim + 2, order);
+      setLexicalOrder(dim + 2, s[i]);
+      }
+      order++;
+      }
+      }
+      
+      if (j != active.end()) {
+      assign_const(stmt[*j].xform, dim + 2, order);
+      
+      for (int k = dim + 4; k < stmt[*j].xform.n_out(); k += 2)
+      assign_const(stmt[*j].xform, k, 0);
+      order++;
+      }
+      
+      if( j == active.end())
+      break;
+      }
+    */
+    
+    
+    // assign lexical order
+    /*int order = starting_order;
+      for (int i = 0; i < s.size(); i++) {
+      // translate each SCC into original statements
+      std::set<int> cur_scc;
+      for (std::set<int>::iterator j = s[i].begin(); j != s[i].end(); j++)
+      copy(s[i].begin(), s[i].end(),
+      inserter(cur_scc, cur_scc.begin()));
+      
+      // now assign the constant
+      for (std::set<int>::iterator j = cur_scc.begin();
+      j != cur_scc.end(); j++)
+      assign_const(stmt[*j].xform, dim, order);
+      
+      if (cur_scc.size() > 1)
+      setLexicalOrder(dim + 2, cur_scc);
+      else if (cur_scc.size() == 1) {
+      int cur_stmt = *(cur_scc.begin());
+      for (int j = dim + 2; j < stmt[cur_stmt].xform.n_out(); j += 2)
+      assign_const(stmt[cur_stmt].xform, j, 0);
+      }
+      
+      if (cur_scc.size() > 0)
+      order++;
+      }
+    */
+  }
+}
+
+void Loop::apply_xform() {
+  std::set<int> active;
+  for (int i = 0; i < stmt.size(); i++)
+    active.insert(i);
+  apply_xform(active);
+}
+
+void Loop::apply_xform(int stmt_num) {
+  std::set<int> active;
+  active.insert(stmt_num);
+  apply_xform(active);
+}
+
+void Loop::apply_xform(std::set<int> &active) {
+  int max_n = 0;
+  
+  CG_outputBuilder *ocg = ir->builder();
+  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++) {
+    int n = stmt[*i].loop_level.size();
+    if (n > max_n)
+      max_n = n;
+    
+    std::vector<int> lex = getLexicalOrder(*i);
+    
+    Relation mapping(2 * n + 1, n);
+    F_And *f_root = mapping.add_and();
+    for (int j = 1; j <= n; j++) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(mapping.output_var(j), 1);
+      h.update_coef(mapping.input_var(2 * j), -1);
+    }
+    mapping = Composition(mapping, stmt[*i].xform);
+    mapping.simplify();
+    
+    // match omega input/output variables to variable names in the code
+    for (int j = 1; j <= stmt[*i].IS.n_set(); j++)
+      mapping.name_input_var(j, stmt[*i].IS.set_var(j)->name());
+    for (int j = 1; j <= n; j++)
+      mapping.name_output_var(j,
+                              tmp_loop_var_name_prefix
+                              + to_string(tmp_loop_var_name_counter + j - 1));
+    mapping.setup_names();
+    
+    Relation known = Extend_Set(copy(this->known),
+                                mapping.n_out() - this->known.n_set());
+    //stmt[*i].code = outputStatement(ocg, stmt[*i].code, 0, mapping, known, std::vector<CG_outputRepr *>(mapping.n_out(), NULL));
+    std::vector<std::string> loop_vars;
+    for (int j = 1; j <= stmt[*i].IS.n_set(); j++)
+      loop_vars.push_back(stmt[*i].IS.set_var(j)->name());
+    std::vector<CG_outputRepr *> subs = output_substitutions(ocg,
+                                                             Inverse(copy(mapping)),
+                                                             std::vector<std::pair<CG_outputRepr *, int> >(mapping.n_out(),
+                                                                                                           std::make_pair(static_cast<CG_outputRepr *>(NULL), 0)));
+    stmt[*i].code = ocg->CreateSubstitutedStmt(0, stmt[*i].code, loop_vars,
+                                               subs);
+    stmt[*i].IS = Range(Restrict_Domain(mapping, stmt[*i].IS));
+    stmt[*i].IS.simplify();
+    
+    // replace original transformation relation with straight 1-1 mapping
+    mapping = Relation(n, 2 * n + 1);
+    f_root = mapping.add_and();
+    for (int j = 1; j <= n; j++) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(mapping.output_var(2 * j), 1);
+      h.update_coef(mapping.input_var(j), -1);
+    }
+    for (int j = 1; j <= 2 * n + 1; j += 2) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(mapping.output_var(j), 1);
+      h.update_const(-lex[j - 1]);
+    }
+    stmt[*i].xform = mapping;
+  }
+  
+  tmp_loop_var_name_counter += max_n;
+}
+
+void Loop::addKnown(const Relation &cond) {
+  
+  // invalidate saved codegen computation
+  delete last_compute_cgr_;
+  last_compute_cgr_ = NULL;
+  delete last_compute_cg_;
+  last_compute_cg_ = NULL;
+  
+  int n1 = this->known.n_set();
+  
+  Relation r = copy(cond);
+  int n2 = r.n_set();
+  
+  if (n1 < n2)
+    this->known = Extend_Set(this->known, n2 - n1);
+  else if (n1 > n2)
+    r = Extend_Set(r, n1 - n2);
+  
+  this->known = Intersection(this->known, r);
+}
+
+void Loop::removeDependence(int stmt_num_from, int stmt_num_to) {
+  // check for sanity of parameters
+  if (stmt_num_from >= stmt.size())
+    throw std::invalid_argument(
+      "invalid statement number " + to_string(stmt_num_from));
+  if (stmt_num_to >= stmt.size())
+    throw std::invalid_argument(
+      "invalid statement number " + to_string(stmt_num_to));
+  
+  dep.disconnect(stmt_num_from, stmt_num_to);
+}
+
+void Loop::dump() const {
+  for (int i = 0; i < stmt.size(); i++) {
+    std::vector<int> lex = getLexicalOrder(i);
+    std::cout << "s" << i + 1 << ": ";
+    for (int j = 0; j < stmt[i].loop_level.size(); j++) {
+      if (2 * j < lex.size())
+        std::cout << lex[2 * j];
+      switch (stmt[i].loop_level[j].type) {
+      case LoopLevelOriginal:
+        std::cout << "(dim:" << stmt[i].loop_level[j].payload << ")";
+        break;
+      case LoopLevelTile:
+        std::cout << "(tile:" << stmt[i].loop_level[j].payload << ")";
+        break;
+      default:
+        std::cout << "(unknown)";
+      }
+      std::cout << ' ';
+    }
+    for (int j = 2 * stmt[i].loop_level.size(); j < lex.size(); j += 2) {
+      std::cout << lex[j];
+      if (j != lex.size() - 1)
+        std::cout << ' ';
+    }
+    std::cout << std::endl;
+  }
+}
+
+bool Loop::nonsingular(const std::vector<std::vector<int> > &T) {
+  if (stmt.size() == 0)
+    return true;
+  
+  // check for sanity of parameters
+  for (int i = 0; i < stmt.size(); i++) {
+    if (stmt[i].loop_level.size() != num_dep_dim)
+      throw std::invalid_argument(
+        "nonsingular loop transformations must be applied to original perfect loop nest");
+    for (int j = 0; j < stmt[i].loop_level.size(); j++)
+      if (stmt[i].loop_level[j].type != LoopLevelOriginal)
+        throw std::invalid_argument(
+          "nonsingular loop transformations must be applied to original perfect loop nest");
+  }
+  if (T.size() != num_dep_dim)
+    throw std::invalid_argument("invalid transformation matrix");
+  for (int i = 0; i < stmt.size(); i++)
+    if (T[i].size() != num_dep_dim + 1 && T[i].size() != num_dep_dim)
+      throw std::invalid_argument("invalid transformation matrix");
+  // invalidate saved codegen computation
+  delete last_compute_cgr_;
+  last_compute_cgr_ = NULL;
+  delete last_compute_cg_;
+  last_compute_cg_ = NULL;
+  // build relation from matrix
+  Relation mapping(2 * num_dep_dim + 1, 2 * num_dep_dim + 1);
+  F_And *f_root = mapping.add_and();
+  for (int i = 0; i < num_dep_dim; i++) {
+    EQ_Handle h = f_root->add_EQ();
+    h.update_coef(mapping.output_var(2 * (i + 1)), -1);
+    for (int j = 0; j < num_dep_dim; j++)
+      if (T[i][j] != 0)
+        h.update_coef(mapping.input_var(2 * (j + 1)), T[i][j]);
+    if (T[i].size() == num_dep_dim + 1)
+      h.update_const(T[i][num_dep_dim]);
+  }
+  for (int i = 1; i <= 2 * num_dep_dim + 1; i += 2) {
+    EQ_Handle h = f_root->add_EQ();
+    h.update_coef(mapping.output_var(i), -1);
+    h.update_coef(mapping.input_var(i), 1);
+  }
+  
+  // update transformation relations
+  for (int i = 0; i < stmt.size(); i++)
+    stmt[i].xform = Composition(copy(mapping), stmt[i].xform);
+  
+  // update dependence graph
+  for (int i = 0; i < dep.vertex.size(); i++)
+    for (DependenceGraph::EdgeList::iterator j =
+           dep.vertex[i].second.begin(); j != dep.vertex[i].second.end();
+         j++) {
+      std::vector<DependenceVector> dvs = j->second;
+      for (int k = 0; k < dvs.size(); k++) {
+        DependenceVector &dv = dvs[k];
+        switch (dv.type) {
+        case DEP_W2R:
+        case DEP_R2W:
+        case DEP_W2W:
+        case DEP_R2R: {
+          std::vector<coef_t> lbounds(num_dep_dim), ubounds(
+            num_dep_dim);
+          for (int p = 0; p < num_dep_dim; p++) {
+            coef_t lb = 0;
+            coef_t ub = 0;
+            for (int q = 0; q < num_dep_dim; q++) {
+              if (T[p][q] > 0) {
+                if (lb == -posInfinity
+                    || dv.lbounds[q] == -posInfinity)
+                  lb = -posInfinity;
+                else
+                  lb += T[p][q] * dv.lbounds[q];
+                if (ub == posInfinity
+                    || dv.ubounds[q] == posInfinity)
+                  ub = posInfinity;
+                else
+                  ub += T[p][q] * dv.ubounds[q];
+              } else if (T[p][q] < 0) {
+                if (lb == -posInfinity
+                    || dv.ubounds[q] == posInfinity)
+                  lb = -posInfinity;
+                else
+                  lb += T[p][q] * dv.ubounds[q];
+                if (ub == posInfinity
+                    || dv.lbounds[q] == -posInfinity)
+                  ub = posInfinity;
+                else
+                  ub += T[p][q] * dv.lbounds[q];
+              }
+            }
+            if (T[p].size() == num_dep_dim + 1) {
+              if (lb != -posInfinity)
+                lb += T[p][num_dep_dim];
+              if (ub != posInfinity)
+                ub += T[p][num_dep_dim];
+            }
+            lbounds[p] = lb;
+            ubounds[p] = ub;
+          }
+          dv.lbounds = lbounds;
+          dv.ubounds = ubounds;
+          
+          break;
+        }
+        default:
+          ;
+        }
+      }
+      j->second = dvs;
+    }
+  
+  // set constant loop values
+  std::set<int> active;
+  for (int i = 0; i < stmt.size(); i++)
+    active.insert(i);
+  setLexicalOrder(0, active);
+  
+  return true;
+}
+
+
+bool Loop::is_dependence_valid_based_on_lex_order(int i, int j,
+                                                  const DependenceVector &dv, bool before) {
+  std::vector<int> lex_i = getLexicalOrder(i);
+  std::vector<int> lex_j = getLexicalOrder(j);
+  int last_dim;
+  if (!dv.is_scalar_dependence) {
+    for (last_dim = 0;
+         last_dim < lex_i.size() && (lex_i[last_dim] == lex_j[last_dim]);
+         last_dim++)
+      ;
+    last_dim = last_dim / 2;
+    if (last_dim == 0)
+      return true;
+    
+    for (int i = 0; i < last_dim; i++) {
+      if (dv.lbounds[i] > 0)
+        return true;
+      else if (dv.lbounds[i] < 0)
+        return false;
+    }
+  }
+  if (before)
+    return true;
+  
+  return false;
+  
+}
+
diff --git a/src/loop_basic.cc b/src/loop_basic.cc
new file mode 100644
index 0000000..f5234b9
--- /dev/null
+++ b/src/loop_basic.cc
@@ -0,0 +1,1538 @@
+/*
+ * loop_basic.cc
+ *
+ *  Created on: Nov 12, 2012
+ *      Author: anand
+ */
+
+#include "loop.hh"
+#include "chill_error.hh"
+#include <omega.h>
+#include "omegatools.hh"
+#include <string.h>
+
+using namespace omega;
+
+void Loop::permute(const std::vector<int> &pi) {
+  std::set<int> active;
+  for (int i = 0; i < stmt.size(); i++)
+    active.insert(i);
+  
+  permute(active, pi);
+}
+
+void Loop::original() {
+  std::set<int> active;
+  for (int i = 0; i < stmt.size(); i++)
+    active.insert(i);
+  setLexicalOrder(0, active);
+}
+void Loop::permute(int stmt_num, int level, const std::vector<int> &pi) {
+  // check for sanity of parameters
+  int starting_order;
+  if (stmt_num < 0 || stmt_num >= stmt.size())
+    throw std::invalid_argument(
+      "invalid statement number " + to_string(stmt_num));
+  std::set<int> active;
+  if (level < 0 || level > stmt[stmt_num].loop_level.size())
+    throw std::invalid_argument("invalid loop level " + to_string(level));
+  else if (level == 0) {
+    for (int i = 0; i < stmt.size(); i++)
+      active.insert(i);
+    level = 1;
+    starting_order = 0;
+  } else {
+    std::vector<int> lex = getLexicalOrder(stmt_num);
+    active = getStatements(lex, 2 * level - 2);
+    starting_order = lex[2 * level - 2];
+    lex[2 * level - 2]++;
+    shiftLexicalOrder(lex, 2 * level - 2, active.size() - 1);
+  }
+  std::vector<int> pi_inverse(pi.size(), 0);
+  for (int i = 0; i < pi.size(); i++) {
+    if (pi[i] >= level + pi.size() || pi[i] < level
+        || pi_inverse[pi[i] - level] != 0)
+      throw std::invalid_argument("invalid permuation");
+    pi_inverse[pi[i] - level] = level + i;
+  }
+  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++)
+    if (level + pi.size() - 1 > stmt[*i].loop_level.size())
+      throw std::invalid_argument(
+        "invalid permutation for statement " + to_string(*i));
+  
+  // invalidate saved codegen computation
+  delete last_compute_cgr_;
+  last_compute_cgr_ = NULL;
+  delete last_compute_cg_;
+  last_compute_cg_ = NULL;
+  
+  // Update transformation relations
+  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++) {
+    int n = stmt[*i].xform.n_out();
+    Relation mapping(n, n);
+    F_And *f_root = mapping.add_and();
+    for (int j = 1; j <= 2 * level - 2; j++) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(mapping.output_var(j), 1);
+      h.update_coef(mapping.input_var(j), -1);
+    }
+    for (int j = level; j <= level + pi.size() - 1; j++) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(mapping.output_var(2 * j), 1);
+      h.update_coef(mapping.input_var(2 * pi[j - level]), -1);
+    }
+    for (int j = level; j <= level + pi.size() - 1; j++) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(mapping.output_var(2 * j - 1), 1);
+      h.update_coef(mapping.input_var(2 * j - 1), -1);
+    }
+    for (int j = 2 * (level + pi.size() - 1) + 1; j <= n; j++) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(mapping.output_var(j), 1);
+      h.update_coef(mapping.input_var(j), -1);
+    }
+    stmt[*i].xform = Composition(mapping, stmt[*i].xform);
+    stmt[*i].xform.simplify();
+  }
+  
+  // get the permuation for dependence vectors
+  std::vector<int> t;
+  for (int i = 0; i < pi.size(); i++)
+    if (stmt[stmt_num].loop_level[pi[i] - 1].type == LoopLevelOriginal)
+      t.push_back(stmt[stmt_num].loop_level[pi[i] - 1].payload);
+  int max_dep_dim = -1;
+  int min_dep_dim = dep.num_dim();
+  for (int i = 0; i < t.size(); i++) {
+    if (t[i] > max_dep_dim)
+      max_dep_dim = t[i];
+    if (t[i] < min_dep_dim)
+      min_dep_dim = t[i];
+  }
+  if (min_dep_dim > max_dep_dim)
+    return;
+  if (max_dep_dim - min_dep_dim + 1 != t.size())
+    throw loop_error("cannot update the dependence graph after permuation");
+  std::vector<int> dep_pi(dep.num_dim());
+  for (int i = 0; i < min_dep_dim; i++)
+    dep_pi[i] = i;
+  for (int i = min_dep_dim; i <= max_dep_dim; i++)
+    dep_pi[i] = t[i - min_dep_dim];
+  for (int i = max_dep_dim + 1; i < dep.num_dim(); i++)
+    dep_pi[i] = i;
+  
+  dep.permute(dep_pi, active);
+  
+  // update the dependence graph
+  DependenceGraph g(dep.num_dim());
+  for (int i = 0; i < dep.vertex.size(); i++)
+    g.insert();
+  for (int i = 0; i < dep.vertex.size(); i++)
+    for (DependenceGraph::EdgeList::iterator j =
+           dep.vertex[i].second.begin(); j != dep.vertex[i].second.end();
+         j++) {
+      if ((active.find(i) != active.end()
+           && active.find(j->first) != active.end())) {
+        std::vector<DependenceVector> dv = j->second;
+        for (int k = 0; k < dv.size(); k++) {
+          switch (dv[k].type) {
+          case DEP_W2R:
+          case DEP_R2W:
+          case DEP_W2W:
+          case DEP_R2R: {
+            std::vector<coef_t> lbounds(dep.num_dim());
+            std::vector<coef_t> ubounds(dep.num_dim());
+            for (int d = 0; d < dep.num_dim(); d++) {
+              lbounds[d] = dv[k].lbounds[dep_pi[d]];
+              ubounds[d] = dv[k].ubounds[dep_pi[d]];
+            }
+            dv[k].lbounds = lbounds;
+            dv[k].ubounds = ubounds;
+            break;
+          }
+          case DEP_CONTROL: {
+            break;
+          }
+          default:
+            throw loop_error("unknown dependence type");
+          }
+        }
+        g.connect(i, j->first, dv);
+      } else if (active.find(i) == active.end()
+                 && active.find(j->first) == active.end()) {
+        std::vector<DependenceVector> dv = j->second;
+        g.connect(i, j->first, dv);
+      } else {
+        std::vector<DependenceVector> dv = j->second;
+        for (int k = 0; k < dv.size(); k++)
+          switch (dv[k].type) {
+          case DEP_W2R:
+          case DEP_R2W:
+          case DEP_W2W:
+          case DEP_R2R: {
+            for (int d = 0; d < dep.num_dim(); d++)
+              if (dep_pi[d] != d) {
+                dv[k].lbounds[d] = -posInfinity;
+                dv[k].ubounds[d] = posInfinity;
+              }
+            break;
+          }
+          case DEP_CONTROL:
+            break;
+          default:
+            throw loop_error("unknown dependence type");
+          }
+        g.connect(i, j->first, dv);
+      }
+    }
+  dep = g;
+  
+  // update loop level information
+  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++) {
+    int cur_dep_dim = min_dep_dim;
+    std::vector<LoopLevel> new_loop_level(stmt[*i].loop_level.size());
+    for (int j = 1; j <= stmt[*i].loop_level.size(); j++)
+      if (j >= level && j < level + pi.size()) {
+        switch (stmt[*i].loop_level[pi_inverse[j - level] - 1].type) {
+        case LoopLevelOriginal:
+          new_loop_level[j - 1].type = LoopLevelOriginal;
+          new_loop_level[j - 1].payload = cur_dep_dim++;
+          new_loop_level[j - 1].parallel_level =
+            stmt[*i].loop_level[pi_inverse[j - level] - 1].parallel_level;
+          break;
+        case LoopLevelTile: {
+          new_loop_level[j - 1].type = LoopLevelTile;
+          int ref_level = stmt[*i].loop_level[pi_inverse[j - level]
+                                              - 1].payload;
+          if (ref_level >= level && ref_level < level + pi.size())
+            new_loop_level[j - 1].payload = pi_inverse[ref_level
+                                                       - level];
+          else
+            new_loop_level[j - 1].payload = ref_level;
+          new_loop_level[j - 1].parallel_level = stmt[*i].loop_level[j
+                                                                     - 1].parallel_level;
+          break;
+        }
+        default:
+          throw loop_error(
+            "unknown loop level information for statement "
+            + to_string(*i));
+        }
+      } else {
+        switch (stmt[*i].loop_level[j - 1].type) {
+        case LoopLevelOriginal:
+          new_loop_level[j - 1].type = LoopLevelOriginal;
+          new_loop_level[j - 1].payload =
+            stmt[*i].loop_level[j - 1].payload;
+          new_loop_level[j - 1].parallel_level = stmt[*i].loop_level[j
+                                                                     - 1].parallel_level;
+          break;
+        case LoopLevelTile: {
+          new_loop_level[j - 1].type = LoopLevelTile;
+          int ref_level = stmt[*i].loop_level[j - 1].payload;
+          if (ref_level >= level && ref_level < level + pi.size())
+            new_loop_level[j - 1].payload = pi_inverse[ref_level
+                                                       - level];
+          else
+            new_loop_level[j - 1].payload = ref_level;
+          new_loop_level[j - 1].parallel_level = stmt[*i].loop_level[j
+                                                                     - 1].parallel_level;
+          break;
+        }
+        default:
+          throw loop_error(
+            "unknown loop level information for statement "
+            + to_string(*i));
+        }
+      }
+    stmt[*i].loop_level = new_loop_level;
+  }
+  
+  setLexicalOrder(2 * level - 2, active, starting_order);
+}
+void Loop::permute(const std::set<int> &active, const std::vector<int> &pi) {
+  if (active.size() == 0 || pi.size() == 0)
+    return;
+  
+  // check for sanity of parameters
+  int level = pi[0];
+  for (int i = 1; i < pi.size(); i++)
+    if (pi[i] < level)
+      level = pi[i];
+  if (level < 1)
+    throw std::invalid_argument("invalid permuation");
+  std::vector<int> reverse_pi(pi.size(), 0);
+  for (int i = 0; i < pi.size(); i++)
+    if (pi[i] >= level + pi.size())
+      throw std::invalid_argument("invalid permutation");
+    else
+      reverse_pi[pi[i] - level] = i + level;
+  for (int i = 0; i < reverse_pi.size(); i++)
+    if (reverse_pi[i] == 0)
+      throw std::invalid_argument("invalid permuation");
+  int ref_stmt_num;
+  std::vector<int> lex;
+  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++) {
+    if (*i < 0 || *i >= stmt.size())
+      throw std::invalid_argument("invalid statement " + to_string(*i));
+    if (i == active.begin()) {
+      ref_stmt_num = *i;
+      lex = getLexicalOrder(*i);
+    } else {
+      if (level + pi.size() - 1 > stmt[*i].loop_level.size())
+        throw std::invalid_argument("invalid permuation");
+      std::vector<int> lex2 = getLexicalOrder(*i);
+      for (int j = 0; j < 2 * level - 3; j += 2)
+        if (lex[j] != lex2[j])
+          throw std::invalid_argument(
+            "statements to permute must be in the same subloop");
+      for (int j = 0; j < pi.size(); j++)
+        if (!(stmt[*i].loop_level[level + j - 1].type
+              == stmt[ref_stmt_num].loop_level[level + j - 1].type
+              && stmt[*i].loop_level[level + j - 1].payload
+              == stmt[ref_stmt_num].loop_level[level + j - 1].payload))
+          throw std::invalid_argument(
+            "permuted loops must have the same loop level types");
+    }
+  }
+  // invalidate saved codegen computation
+  delete last_compute_cgr_;
+  last_compute_cgr_ = NULL;
+  delete last_compute_cg_;
+  last_compute_cg_ = NULL;
+  
+  // Update transformation relations
+  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++) {
+    int n = stmt[*i].xform.n_out();
+    Relation mapping(n, n);
+    F_And *f_root = mapping.add_and();
+    for (int j = 1; j <= n; j += 2) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(mapping.output_var(j), 1);
+      h.update_coef(mapping.input_var(j), -1);
+    }
+    for (int j = 0; j < pi.size(); j++) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(mapping.output_var(2 * (level + j)), 1);
+      h.update_coef(mapping.input_var(2 * pi[j]), -1);
+    }
+    for (int j = 1; j < level; j++) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(mapping.output_var(2 * j), 1);
+      h.update_coef(mapping.input_var(2 * j), -1);
+    }
+    for (int j = level + pi.size(); j <= stmt[*i].loop_level.size(); j++) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(mapping.output_var(2 * j), 1);
+      h.update_coef(mapping.input_var(2 * j), -1);
+    }
+    
+    stmt[*i].xform = Composition(mapping, stmt[*i].xform);
+    stmt[*i].xform.simplify();
+  }
+  
+  // get the permuation for dependence vectors
+  std::vector<int> t;
+  for (int i = 0; i < pi.size(); i++)
+    if (stmt[ref_stmt_num].loop_level[pi[i] - 1].type == LoopLevelOriginal)
+      t.push_back(stmt[ref_stmt_num].loop_level[pi[i] - 1].payload);
+  int max_dep_dim = -1;
+  int min_dep_dim = num_dep_dim;
+  for (int i = 0; i < t.size(); i++) {
+    if (t[i] > max_dep_dim)
+      max_dep_dim = t[i];
+    if (t[i] < min_dep_dim)
+      min_dep_dim = t[i];
+  }
+  if (min_dep_dim > max_dep_dim)
+    return;
+  if (max_dep_dim - min_dep_dim + 1 != t.size())
+    throw loop_error("cannot update the dependence graph after permuation");
+  std::vector<int> dep_pi(num_dep_dim);
+  for (int i = 0; i < min_dep_dim; i++)
+    dep_pi[i] = i;
+  for (int i = min_dep_dim; i <= max_dep_dim; i++)
+    dep_pi[i] = t[i - min_dep_dim];
+  for (int i = max_dep_dim + 1; i < num_dep_dim; i++)
+    dep_pi[i] = i;
+  
+  dep.permute(dep_pi, active);
+  
+  // update the dependence graph
+  DependenceGraph g(dep.num_dim());
+  for (int i = 0; i < dep.vertex.size(); i++)
+    g.insert();
+  for (int i = 0; i < dep.vertex.size(); i++)
+    for (DependenceGraph::EdgeList::iterator j =
+           dep.vertex[i].second.begin(); j != dep.vertex[i].second.end();
+         j++) {         //
+      if ((active.find(i) != active.end()
+           && active.find(j->first) != active.end())) {
+        std::vector<DependenceVector> dv = j->second;
+        for (int k = 0; k < dv.size(); k++) {
+          switch (dv[k].type) {
+          case DEP_W2R:
+          case DEP_R2W:
+          case DEP_W2W:
+          case DEP_R2R: {
+            std::vector<coef_t> lbounds(num_dep_dim);
+            std::vector<coef_t> ubounds(num_dep_dim);
+            for (int d = 0; d < num_dep_dim; d++) {
+              lbounds[d] = dv[k].lbounds[dep_pi[d]];
+              ubounds[d] = dv[k].ubounds[dep_pi[d]];
+            }
+            dv[k].lbounds = lbounds;
+            dv[k].ubounds = ubounds;
+            break;
+          }
+          case DEP_CONTROL: {
+            break;
+          }
+          default:
+            throw loop_error("unknown dependence type");
+          }
+        }
+        g.connect(i, j->first, dv);
+      } else if (active.find(i) == active.end()
+                 && active.find(j->first) == active.end()) {
+        std::vector<DependenceVector> dv = j->second;
+        g.connect(i, j->first, dv);
+      } else {
+        std::vector<DependenceVector> dv = j->second;
+        for (int k = 0; k < dv.size(); k++)
+          switch (dv[k].type) {
+          case DEP_W2R:
+          case DEP_R2W:
+          case DEP_W2W:
+          case DEP_R2R: {
+            for (int d = 0; d < num_dep_dim; d++)
+              if (dep_pi[d] != d) {
+                dv[k].lbounds[d] = -posInfinity;
+                dv[k].ubounds[d] = posInfinity;
+              }
+            break;
+          }
+          case DEP_CONTROL:
+            break;
+          default:
+            throw loop_error("unknown dependence type");
+          }
+        g.connect(i, j->first, dv);
+      }
+    }
+  dep = g;
+  
+  // update loop level information
+  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++) {
+    int cur_dep_dim = min_dep_dim;
+    std::vector<LoopLevel> new_loop_level(stmt[*i].loop_level.size());
+    for (int j = 1; j <= stmt[*i].loop_level.size(); j++)
+      if (j >= level && j < level + pi.size()) {
+        switch (stmt[*i].loop_level[reverse_pi[j - level] - 1].type) {
+        case LoopLevelOriginal:
+          new_loop_level[j - 1].type = LoopLevelOriginal;
+          new_loop_level[j - 1].payload = cur_dep_dim++;
+          new_loop_level[j - 1].parallel_level =
+            stmt[*i].loop_level[reverse_pi[j - level] - 1].parallel_level;
+          break;
+        case LoopLevelTile: {
+          new_loop_level[j - 1].type = LoopLevelTile;
+          int ref_level = stmt[*i].loop_level[reverse_pi[j - level]
+                                              - 1].payload;
+          if (ref_level >= level && ref_level < level + pi.size())
+            new_loop_level[j - 1].payload = reverse_pi[ref_level
+                                                       - level];
+          else
+            new_loop_level[j - 1].payload = ref_level;
+          new_loop_level[j - 1].parallel_level =
+            stmt[*i].loop_level[reverse_pi[j - level] - 1].parallel_level;
+          break;
+        }
+        default:
+          throw loop_error(
+            "unknown loop level information for statement "
+            + to_string(*i));
+        }
+      } else {
+        switch (stmt[*i].loop_level[j - 1].type) {
+        case LoopLevelOriginal:
+          new_loop_level[j - 1].type = LoopLevelOriginal;
+          new_loop_level[j - 1].payload =
+            stmt[*i].loop_level[j - 1].payload;
+          new_loop_level[j - 1].parallel_level = stmt[*i].loop_level[j
+                                                                     - 1].parallel_level;
+          break;
+        case LoopLevelTile: {
+          new_loop_level[j - 1].type = LoopLevelTile;
+          int ref_level = stmt[*i].loop_level[j - 1].payload;
+          if (ref_level >= level && ref_level < level + pi.size())
+            new_loop_level[j - 1].payload = reverse_pi[ref_level
+                                                       - level];
+          else
+            new_loop_level[j - 1].payload = ref_level;
+          new_loop_level[j - 1].parallel_level = stmt[*i].loop_level[j
+                                                                     - 1].parallel_level;
+          break;
+        }
+        default:
+          throw loop_error(
+            "unknown loop level information for statement "
+            + to_string(*i));
+        }
+      }
+    stmt[*i].loop_level = new_loop_level;
+  }
+  
+  setLexicalOrder(2 * level - 2, active);
+}
+
+std::set<int> Loop::split(int stmt_num, int level, const Relation &cond) {
+  // check for sanity of parameters
+  if (stmt_num < 0 || stmt_num >= stmt.size())
+    throw std::invalid_argument("invalid statement " + to_string(stmt_num));
+  if (level <= 0 || level > stmt[stmt_num].loop_level.size())
+    throw std::invalid_argument("invalid loop level " + to_string(level));
+  
+  std::set<int> result;
+  int dim = 2 * level - 1;
+  std::vector<int> lex = getLexicalOrder(stmt_num);
+  std::set<int> same_loop = getStatements(lex, dim - 1);
+  
+  Relation cond2 = copy(cond);
+  cond2.simplify();
+  cond2 = EQs_to_GEQs(cond2);
+  Conjunct *c = cond2.single_conjunct();
+  int cur_lex = lex[dim - 1];
+  
+  for (GEQ_Iterator gi(c->GEQs()); gi; gi++) {
+    int max_level = (*gi).max_tuple_pos();
+    Relation single_cond(max_level);
+    single_cond.and_with_GEQ(*gi);
+    
+    // TODO: should decide where to place newly created statements with
+    // complementary split condition from dependence graph.
+    bool place_after;
+    if (max_level == 0)
+      place_after = true;
+    else if ((*gi).get_coef(cond2.set_var(max_level)) < 0)
+      place_after = true;
+    else
+      place_after = false;
+    
+    bool temp_place_after;      // = place_after;
+    bool assigned = false;
+    int part1_to_part2;
+    int part2_to_part1;
+    // original statements with split condition,
+    // new statements with complement of split condition
+    int old_num_stmt = stmt.size();
+    std::map<int, int> what_stmt_num;
+    apply_xform(same_loop);
+    for (std::set<int>::iterator i = same_loop.begin();
+         i != same_loop.end(); i++) {
+      int n = stmt[*i].IS.n_set();
+      Relation part1, part2;
+      if (max_level > n) {
+        part1 = copy(stmt[*i].IS);
+        part2 = Relation::False(0);
+      } else {
+        part1 = Intersection(copy(stmt[*i].IS),
+                             Extend_Set(copy(single_cond), n - max_level));
+        part2 = Intersection(copy(stmt[*i].IS),
+                             Extend_Set(Complement(copy(single_cond)),
+                                        n - max_level));
+      }
+      
+      //split dependence check
+      
+      if (max_level > level) {
+        
+        DNF_Iterator di1(stmt[*i].IS.query_DNF());
+        DNF_Iterator di2(part1.query_DNF());
+        for (; di1 && di2; di1++, di2++) {
+          //printf("In next conjunct,\n");
+          EQ_Iterator ei1 = (*di1)->EQs();
+          EQ_Iterator ei2 = (*di2)->EQs();
+          for (; ei1 && ei2; ei1++, ei2++) {
+            //printf(" In next equality constraint,\n");
+            Constr_Vars_Iter cvi1(*ei1);
+            Constr_Vars_Iter cvi2(*ei2);
+            int dimension = (*cvi1).var->get_position();
+            int same = 0;
+            bool identical = false;
+            if (identical = !strcmp((*cvi1).var->char_name(),
+                                    (*cvi2).var->char_name())) {
+              
+              for (; cvi1 && cvi2; cvi1++, cvi2++) {
+                
+                if (((*cvi1).coef != (*cvi2).coef
+                     || (*ei1).get_const()
+                     != (*ei2).get_const())
+                    || (strcmp((*cvi1).var->char_name(),
+                               (*cvi2).var->char_name()))) {
+                  
+                  same++;
+                }
+              }
+            }
+            if ((same != 0) || !identical) {
+              
+              dimension = dimension - 1;
+              
+              while (stmt[*i].loop_level[dimension].type
+                     == LoopLevelTile)
+                dimension =
+                  stmt[*i].loop_level[dimension].payload;
+              
+              dimension = stmt[*i].loop_level[dimension].payload;
+              
+              for (int i = 0; i < stmt.size(); i++) {
+                std::vector<std::pair<int, DependenceVector> > D;
+                for (DependenceGraph::EdgeList::iterator j =
+                       dep.vertex[i].second.begin();
+                     j != dep.vertex[i].second.end(); j++) {
+                  for (int k = 0; k < j->second.size(); k++) {
+                    DependenceVector dv = j->second[k];
+                    if (dv.type != DEP_CONTROL)
+                      if (dv.hasNegative(dimension)
+                          && !dv.quasi)
+                        throw loop_error(
+                          "loop error: Split is illegal, dependence violation!");
+                    
+                  }
+                }
+              }
+              
+            }
+            
+            GEQ_Iterator gi1 = (*di1)->GEQs();
+            GEQ_Iterator gi2 = (*di2)->GEQs();
+            
+            for (; gi1 && gi2; gi++, gi2++) {
+              
+              Constr_Vars_Iter cvi1(*gi1);
+              Constr_Vars_Iter cvi2(*gi2);
+              int dimension = (*cvi1).var->get_position();
+              int same = 0;
+              bool identical = false;
+              if (identical = !strcmp((*cvi1).var->char_name(),
+                                      (*cvi2).var->char_name())) {
+                
+                for (; cvi1 && cvi2; cvi1++, cvi2++) {
+                  
+                  if (((*cvi1).coef != (*cvi2).coef
+                       || (*gi1).get_const()
+                       != (*gi2).get_const())
+                      || (strcmp((*cvi1).var->char_name(),
+                                 (*cvi2).var->char_name()))) {
+                    
+                    same++;
+                  }
+                }
+              }
+              if ((same != 0) || !identical) {
+                dimension = dimension - 1;
+                
+                while (stmt[*i].loop_level[dimension].type
+                       == LoopLevelTile)
+                  stmt[*i].loop_level[dimension].payload;
+                
+                dimension =
+                  stmt[*i].loop_level[dimension].payload;
+                
+                for (int i = 0; i < stmt.size(); i++) {
+                  std::vector<std::pair<int, DependenceVector> > D;
+                  for (DependenceGraph::EdgeList::iterator j =
+                         dep.vertex[i].second.begin();
+                       j != dep.vertex[i].second.end();
+                       j++) {
+                    for (int k = 0; k < j->second.size();
+                         k++) {
+                      DependenceVector dv = j->second[k];
+                      if (dv.type != DEP_CONTROL)
+                        if (dv.hasNegative(dimension)
+                            && !dv.quasi)
+                          
+                          throw loop_error(
+                            "loop error: Split is illegal, dependence violation!");
+                      
+                    }
+                  }
+                }
+                
+              }
+              
+            }
+            
+          }
+          
+        }
+        
+        DNF_Iterator di3(stmt[*i].IS.query_DNF());
+        DNF_Iterator di4(part2.query_DNF());        //
+        for (; di3 && di4; di3++, di4++) {
+          EQ_Iterator ei1 = (*di3)->EQs();
+          EQ_Iterator ei2 = (*di4)->EQs();
+          for (; ei1 && ei2; ei1++, ei2++) {
+            Constr_Vars_Iter cvi1(*ei1);
+            Constr_Vars_Iter cvi2(*ei2);
+            int dimension = (*cvi1).var->get_position();
+            int same = 0;
+            bool identical = false;
+            if (identical = !strcmp((*cvi1).var->char_name(),
+                                    (*cvi2).var->char_name())) {
+              
+              for (; cvi1 && cvi2; cvi1++, cvi2++) {
+                
+                if (((*cvi1).coef != (*cvi2).coef
+                     || (*ei1).get_const()
+                     != (*ei2).get_const())
+                    || (strcmp((*cvi1).var->char_name(),
+                               (*cvi2).var->char_name()))) {
+                  
+                  same++;
+                }
+              }
+            }
+            if ((same != 0) || !identical) {
+              dimension = dimension - 1;
+              
+              while (stmt[*i].loop_level[dimension].type
+                     == LoopLevelTile)
+                stmt[*i].loop_level[dimension].payload;
+              
+              dimension = stmt[*i].loop_level[dimension].payload;
+              
+              for (int i = 0; i < stmt.size(); i++) {
+                std::vector<std::pair<int, DependenceVector> > D;
+                for (DependenceGraph::EdgeList::iterator j =
+                       dep.vertex[i].second.begin();
+                     j != dep.vertex[i].second.end(); j++) {
+                  for (int k = 0; k < j->second.size(); k++) {
+                    DependenceVector dv = j->second[k];
+                    if (dv.type != DEP_CONTROL)
+                      if (dv.hasNegative(dimension)
+                          && !dv.quasi)
+                        
+                        throw loop_error(
+                          "loop error: Split is illegal, dependence violation!");
+                    
+                  }
+                }
+              }
+              
+            }
+            
+          }
+          GEQ_Iterator gi1 = (*di3)->GEQs();
+          GEQ_Iterator gi2 = (*di4)->GEQs();
+          
+          for (; gi1 && gi2; gi++, gi2++) {
+            Constr_Vars_Iter cvi1(*gi1);
+            Constr_Vars_Iter cvi2(*gi2);
+            int dimension = (*cvi1).var->get_position();
+            int same = 0;
+            bool identical = false;
+            if (identical = !strcmp((*cvi1).var->char_name(),
+                                    (*cvi2).var->char_name())) {
+              
+              for (; cvi1 && cvi2; cvi1++, cvi2++) {
+                
+                if (((*cvi1).coef != (*cvi2).coef
+                     || (*gi1).get_const()
+                     != (*gi2).get_const())
+                    || (strcmp((*cvi1).var->char_name(),
+                               (*cvi2).var->char_name()))) {
+                  
+                  same++;
+                }
+              }
+            }
+            if ((same != 0) || !identical) {
+              dimension = dimension - 1;
+              
+              while (stmt[*i].loop_level[dimension].type        //
+                     == LoopLevelTile)
+                stmt[*i].loop_level[dimension].payload;
+              
+              dimension = stmt[*i].loop_level[dimension].payload;
+              
+              for (int i = 0; i < stmt.size(); i++) {
+                std::vector<std::pair<int, DependenceVector> > D;
+                for (DependenceGraph::EdgeList::iterator j =
+                       dep.vertex[i].second.begin();
+                     j != dep.vertex[i].second.end(); j++) {
+                  for (int k = 0; k < j->second.size(); k++) {
+                    DependenceVector dv = j->second[k];
+                    if (dv.type != DEP_CONTROL)
+                      if (dv.hasNegative(dimension)
+                          && !dv.quasi)
+                        
+                        throw loop_error(
+                          "loop error: Split is illegal, dependence violation!");
+                    
+                  }
+                }
+              }
+              
+            }
+            
+          }
+          
+        }
+        
+      }
+      
+      stmt[*i].IS = part1;
+      
+      if (Intersection(copy(part2),
+                       Extend_Set(copy(this->known), n - this->known.n_set())).is_upper_bound_satisfiable()) {
+        Statement new_stmt;
+        new_stmt.code = stmt[*i].code->clone();
+        new_stmt.IS = part2;
+        new_stmt.xform = copy(stmt[*i].xform);
+        new_stmt.ir_stmt_node = NULL;
+        new_stmt.loop_level = stmt[*i].loop_level;
+        
+        stmt_nesting_level_.push_back(stmt_nesting_level_[*i]);
+        
+        /*std::pair<std::vector<DependenceVector>,
+          std::vector<DependenceVector> > dv =
+          test_data_dependences(ir, stmt[*i].code, part1,
+          stmt[*i].code, part2, freevar, index,
+          stmt_nesting_level_[*i],
+          stmt_nesting_level_[stmt.size() - 1]);
+          
+          
+          
+          
+          for (int k = 0; k < dv.first.size(); k++)
+          part1_to_part2++;
+          if (part1_to_part2 > 0 && part2_to_part1 > 0)
+          throw loop_error(
+          "loop error: Aborting, split resulted in impossible dependence cycle!");
+          
+          for (int k = 0; k < dv.second.size(); k++)
+          part2_to_part1++;
+          
+          
+          
+          if (part1_to_part2 > 0 && part2_to_part1 > 0)
+          throw loop_error(
+          "loop error: Aborting, split resulted in impossible dependence cycle!");
+          
+          
+          
+          if (part2_to_part1 > 0){
+          temp_place_after = false;
+          assigned = true;
+          
+          }else if (part1_to_part2 > 0){
+          temp_place_after = true;
+          
+          assigned = true;
+          }
+          
+        */
+        
+        if (place_after)
+          assign_const(new_stmt.xform, dim - 1, cur_lex + 1);
+        else
+          assign_const(new_stmt.xform, dim - 1, cur_lex - 1);
+        
+        stmt.push_back(new_stmt);
+        dep.insert();
+        what_stmt_num[*i] = stmt.size() - 1;
+        if (*i == stmt_num)
+          result.insert(stmt.size() - 1);
+      }
+      
+    }
+    // make adjacent lexical number available for new statements
+    if (place_after) {
+      lex[dim - 1] = cur_lex + 1;
+      shiftLexicalOrder(lex, dim - 1, 1);
+    } else {
+      lex[dim - 1] = cur_lex - 1;
+      shiftLexicalOrder(lex, dim - 1, -1);
+    }
+    // update dependence graph
+    int dep_dim = get_dep_dim_of(stmt_num, level);
+    for (int i = 0; i < old_num_stmt; i++) {
+      std::vector<std::pair<int, std::vector<DependenceVector> > > D;
+      
+      for (DependenceGraph::EdgeList::iterator j =
+             dep.vertex[i].second.begin();
+           j != dep.vertex[i].second.end(); j++) {
+        if (same_loop.find(i) != same_loop.end()) {
+          if (same_loop.find(j->first) != same_loop.end()) {
+            if (what_stmt_num.find(i) != what_stmt_num.end()
+                && what_stmt_num.find(j->first)
+                != what_stmt_num.end())
+              dep.connect(what_stmt_num[i],
+                          what_stmt_num[j->first], j->second);
+            if (place_after
+                && what_stmt_num.find(j->first)
+                != what_stmt_num.end()) {
+              std::vector<DependenceVector> dvs;
+              for (int k = 0; k < j->second.size(); k++) {
+                DependenceVector dv = j->second[k];
+                if (dv.is_data_dependence() && dep_dim != -1) {
+                  dv.lbounds[dep_dim] = -posInfinity;
+                  dv.ubounds[dep_dim] = posInfinity;
+                }
+                dvs.push_back(dv);
+              }
+              if (dvs.size() > 0)
+                D.push_back(
+                  std::make_pair(what_stmt_num[j->first],
+                                 dvs));
+            } else if (!place_after
+                       && what_stmt_num.find(i)
+                       != what_stmt_num.end()) {
+              std::vector<DependenceVector> dvs;
+              for (int k = 0; k < j->second.size(); k++) {
+                DependenceVector dv = j->second[k];
+                if (dv.is_data_dependence() && dep_dim != -1) {
+                  dv.lbounds[dep_dim] = -posInfinity;
+                  dv.ubounds[dep_dim] = posInfinity;
+                }
+                dvs.push_back(dv);
+              }
+              if (dvs.size() > 0)
+                dep.connect(what_stmt_num[i], j->first, dvs);
+              
+            }
+          } else {
+            if (what_stmt_num.find(i) != what_stmt_num.end())
+              dep.connect(what_stmt_num[i], j->first, j->second);
+          }
+        } else if (same_loop.find(j->first) != same_loop.end()) {
+          if (what_stmt_num.find(j->first) != what_stmt_num.end())
+            D.push_back(
+              std::make_pair(what_stmt_num[j->first],
+                             j->second));
+        }
+      }
+      
+      for (int j = 0; j < D.size(); j++)
+        dep.connect(i, D[j].first, D[j].second);
+    }
+    
+  }
+  
+  return result;
+}
+
+void Loop::skew(const std::set<int> &stmt_nums, int level,
+                const std::vector<int> &skew_amount) {
+  if (stmt_nums.size() == 0)
+    return;
+  
+  // check for sanity of parameters
+  int ref_stmt_num = *(stmt_nums.begin());
+  for (std::set<int>::const_iterator i = stmt_nums.begin();
+       i != stmt_nums.end(); i++) {
+    if (*i < 0 || *i >= stmt.size())
+      throw std::invalid_argument(
+        "invalid statement number " + to_string(*i));
+    if (level < 1 || level > stmt[*i].loop_level.size())
+      throw std::invalid_argument(
+        "invalid loop level " + to_string(level));
+    for (int j = stmt[*i].loop_level.size(); j < skew_amount.size(); j++)
+      if (skew_amount[j] != 0)
+        throw std::invalid_argument("invalid skewing formula");
+  }
+  
+  // invalidate saved codegen computation
+  delete last_compute_cgr_;
+  last_compute_cgr_ = NULL;
+  delete last_compute_cg_;
+  last_compute_cg_ = NULL;
+  
+  // set trasformation relations
+  for (std::set<int>::const_iterator i = stmt_nums.begin();
+       i != stmt_nums.end(); i++) {
+    int n = stmt[*i].xform.n_out();
+    Relation r(n, n);
+    F_And *f_root = r.add_and();
+    for (int j = 1; j <= n; j++)
+      if (j != 2 * level) {
+        EQ_Handle h = f_root->add_EQ();
+        h.update_coef(r.input_var(j), 1);
+        h.update_coef(r.output_var(j), -1);
+      }
+    EQ_Handle h = f_root->add_EQ();
+    h.update_coef(r.output_var(2 * level), -1);
+    for (int j = 0; j < skew_amount.size(); j++)
+      if (skew_amount[j] != 0)
+        h.update_coef(r.input_var(2 * (j + 1)), skew_amount[j]);
+    
+    stmt[*i].xform = Composition(r, stmt[*i].xform);
+    stmt[*i].xform.simplify();
+  }
+  
+  // update dependence graph
+  if (stmt[ref_stmt_num].loop_level[level - 1].type == LoopLevelOriginal) {
+    int dep_dim = stmt[ref_stmt_num].loop_level[level - 1].payload;
+    for (std::set<int>::const_iterator i = stmt_nums.begin();
+         i != stmt_nums.end(); i++)
+      for (DependenceGraph::EdgeList::iterator j =
+             dep.vertex[*i].second.begin();
+           j != dep.vertex[*i].second.end(); j++)
+        if (stmt_nums.find(j->first) != stmt_nums.end()) {
+          // dependence between skewed statements
+          std::vector<DependenceVector> dvs = j->second;
+          for (int k = 0; k < dvs.size(); k++) {
+            DependenceVector &dv = dvs[k];
+            if (dv.is_data_dependence()) {
+              coef_t lb = 0;
+              coef_t ub = 0;
+              for (int kk = 0; kk < skew_amount.size(); kk++) {
+                int cur_dep_dim = get_dep_dim_of(*i, kk + 1);
+                if (skew_amount[kk] > 0) {
+                  if (lb != -posInfinity
+                      && stmt[*i].loop_level[kk].type
+                      == LoopLevelOriginal
+                      && dv.lbounds[cur_dep_dim]
+                      != -posInfinity)
+                    lb += skew_amount[kk]
+                      * dv.lbounds[cur_dep_dim];
+                  else {
+                    if (cur_dep_dim != -1
+                        && !(dv.lbounds[cur_dep_dim]
+                             == 0
+                             && dv.ubounds[cur_dep_dim]
+                             == 0))
+                      lb = -posInfinity;
+                  }
+                  if (ub != posInfinity
+                      && stmt[*i].loop_level[kk].type
+                      == LoopLevelOriginal
+                      && dv.ubounds[cur_dep_dim]
+                      != posInfinity)
+                    ub += skew_amount[kk]
+                      * dv.ubounds[cur_dep_dim];
+                  else {
+                    if (cur_dep_dim != -1
+                        && !(dv.lbounds[cur_dep_dim]
+                             == 0
+                             && dv.ubounds[cur_dep_dim]
+                             == 0))
+                      ub = posInfinity;
+                  }
+                } else if (skew_amount[kk] < 0) {
+                  if (lb != -posInfinity
+                      && stmt[*i].loop_level[kk].type
+                      == LoopLevelOriginal
+                      && dv.ubounds[cur_dep_dim]
+                      != posInfinity)
+                    lb += skew_amount[kk]
+                      * dv.ubounds[cur_dep_dim];
+                  else {
+                    if (cur_dep_dim != -1
+                        && !(dv.lbounds[cur_dep_dim]
+                             == 0
+                             && dv.ubounds[cur_dep_dim]
+                             == 0))
+                      lb = -posInfinity;
+                  }
+                  if (ub != posInfinity
+                      && stmt[*i].loop_level[kk].type
+                      == LoopLevelOriginal
+                      && dv.lbounds[cur_dep_dim]
+                      != -posInfinity)
+                    ub += skew_amount[kk]
+                      * dv.lbounds[cur_dep_dim];
+                  else {
+                    if (cur_dep_dim != -1
+                        && !(dv.lbounds[cur_dep_dim]
+                             == 0
+                             && dv.ubounds[cur_dep_dim]
+                             == 0))
+                      ub = posInfinity;
+                  }
+                }
+              }
+              dv.lbounds[dep_dim] = lb;
+              dv.ubounds[dep_dim] = ub;
+              if ((dv.isCarried(dep_dim)
+                   && dv.hasPositive(dep_dim)) && dv.quasi)
+                dv.quasi = false;
+              
+              if ((dv.isCarried(dep_dim)
+                   && dv.hasNegative(dep_dim)) && !dv.quasi)
+                throw loop_error(
+                  "loop error: Skewing is illegal, dependence violation!");
+              dv.lbounds[dep_dim] = lb;
+              dv.ubounds[dep_dim] = ub;
+              if ((dv.isCarried(dep_dim)
+                   && dv.hasPositive(dep_dim)) && dv.quasi)
+                dv.quasi = false;
+              
+              if ((dv.isCarried(dep_dim)
+                   && dv.hasNegative(dep_dim)) && !dv.quasi)
+                throw loop_error(
+                  "loop error: Skewing is illegal, dependence violation!");
+            }
+          }
+          j->second = dvs;
+        } else {
+          // dependence from skewed statement to unskewed statement becomes jumbled,
+          // put distance value at skewed dimension to unknown
+          std::vector<DependenceVector> dvs = j->second;
+          for (int k = 0; k < dvs.size(); k++) {
+            DependenceVector &dv = dvs[k];
+            if (dv.is_data_dependence()) {
+              dv.lbounds[dep_dim] = -posInfinity;
+              dv.ubounds[dep_dim] = posInfinity;
+            }
+          }
+          j->second = dvs;
+        }
+    for (int i = 0; i < dep.vertex.size(); i++)
+      if (stmt_nums.find(i) == stmt_nums.end())
+        for (DependenceGraph::EdgeList::iterator j =
+               dep.vertex[i].second.begin();
+             j != dep.vertex[i].second.end(); j++)
+          if (stmt_nums.find(j->first) != stmt_nums.end()) {
+            // dependence from unskewed statement to skewed statement becomes jumbled,
+            // put distance value at skewed dimension to unknown
+            std::vector<DependenceVector> dvs = j->second;
+            for (int k = 0; k < dvs.size(); k++) {
+              DependenceVector &dv = dvs[k];
+              if (dv.is_data_dependence()) {
+                dv.lbounds[dep_dim] = -posInfinity;
+                dv.ubounds[dep_dim] = posInfinity;
+              }
+            }
+            j->second = dvs;
+          }
+  }
+}
+
+
+void Loop::shift(const std::set<int> &stmt_nums, int level, int shift_amount) {
+  if (stmt_nums.size() == 0)
+    return;
+  
+  // check for sanity of parameters
+  int ref_stmt_num = *(stmt_nums.begin());
+  for (std::set<int>::const_iterator i = stmt_nums.begin();
+       i != stmt_nums.end(); i++) {
+    if (*i < 0 || *i >= stmt.size())
+      throw std::invalid_argument(
+        "invalid statement number " + to_string(*i));
+    if (level < 1 || level > stmt[*i].loop_level.size())
+      throw std::invalid_argument(
+        "invalid loop level " + to_string(level));
+  }
+  
+  // do nothing
+  if (shift_amount == 0)
+    return;
+  
+  // invalidate saved codegen computation
+  delete last_compute_cgr_;
+  last_compute_cgr_ = NULL;
+  delete last_compute_cg_;
+  last_compute_cg_ = NULL;
+  
+  // set trasformation relations
+  for (std::set<int>::const_iterator i = stmt_nums.begin();
+       i != stmt_nums.end(); i++) {
+    int n = stmt[*i].xform.n_out();
+    
+    Relation r(n, n);
+    F_And *f_root = r.add_and();
+    for (int j = 1; j <= n; j++) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(r.input_var(j), 1);
+      h.update_coef(r.output_var(j), -1);
+      if (j == 2 * level)
+        h.update_const(shift_amount);
+    }
+    
+    stmt[*i].xform = Composition(r, stmt[*i].xform);
+    stmt[*i].xform.simplify();
+  }
+  
+  // update dependence graph
+  if (stmt[ref_stmt_num].loop_level[level - 1].type == LoopLevelOriginal) {
+    int dep_dim = stmt[ref_stmt_num].loop_level[level - 1].payload;
+    for (std::set<int>::const_iterator i = stmt_nums.begin();
+         i != stmt_nums.end(); i++)
+      for (DependenceGraph::EdgeList::iterator j =
+             dep.vertex[*i].second.begin();
+           j != dep.vertex[*i].second.end(); j++)
+        if (stmt_nums.find(j->first) == stmt_nums.end()) {
+          // dependence from shifted statement to unshifted statement
+          std::vector<DependenceVector> dvs = j->second;
+          for (int k = 0; k < dvs.size(); k++) {
+            DependenceVector &dv = dvs[k];
+            if (dv.is_data_dependence()) {
+              if (dv.lbounds[dep_dim] != -posInfinity)
+                dv.lbounds[dep_dim] -= shift_amount;
+              if (dv.ubounds[dep_dim] != posInfinity)
+                dv.ubounds[dep_dim] -= shift_amount;
+            }
+          }
+          j->second = dvs;
+        }
+    for (int i = 0; i < dep.vertex.size(); i++)
+      if (stmt_nums.find(i) == stmt_nums.end())
+        for (DependenceGraph::EdgeList::iterator j =
+               dep.vertex[i].second.begin();
+             j != dep.vertex[i].second.end(); j++)
+          if (stmt_nums.find(j->first) != stmt_nums.end()) {
+            // dependence from unshifted statement to shifted statement
+            std::vector<DependenceVector> dvs = j->second;
+            for (int k = 0; k < dvs.size(); k++) {
+              DependenceVector &dv = dvs[k];
+              if (dv.is_data_dependence()) {
+                if (dv.lbounds[dep_dim] != -posInfinity)
+                  dv.lbounds[dep_dim] += shift_amount;
+                if (dv.ubounds[dep_dim] != posInfinity)
+                  dv.ubounds[dep_dim] += shift_amount;
+              }
+            }
+            j->second = dvs;
+          }
+  }
+}
+
+void Loop::scale(const std::set<int> &stmt_nums, int level, int scale_amount) {
+  std::vector<int> skew_amount(level, 0);
+  skew_amount[level - 1] = scale_amount;
+  skew(stmt_nums, level, skew_amount);
+}
+
+void Loop::reverse(const std::set<int> &stmt_nums, int level) {
+  scale(stmt_nums, level, -1);
+}
+
+void Loop::fuse(const std::set<int> &stmt_nums, int level) {
+  if (stmt_nums.size() == 0 || stmt_nums.size() == 1)
+    return;
+  
+  // invalidate saved codegen computation
+  delete last_compute_cgr_;
+  last_compute_cgr_ = NULL;
+  delete last_compute_cg_;
+  last_compute_cg_ = NULL;
+  
+  int dim = 2 * level - 1;
+  // check for sanity of parameters
+  std::vector<int> ref_lex;
+  int ref_stmt_num;
+  for (std::set<int>::const_iterator i = stmt_nums.begin();
+       i != stmt_nums.end(); i++) {
+    if (*i < 0 || *i >= stmt.size())
+      throw std::invalid_argument(
+        "invalid statement number " + to_string(*i));
+    if (level <= 0
+        || (level > (stmt[*i].xform.n_out() - 1) / 2
+            || level > stmt[*i].loop_level.size()))
+      throw std::invalid_argument(
+        "invalid loop level " + to_string(level));
+    if (ref_lex.size() == 0) {
+      ref_lex = getLexicalOrder(*i);
+      ref_stmt_num = *i;
+    } else {
+      std::vector<int> lex = getLexicalOrder(*i);
+      for (int j = 0; j < dim - 1; j += 2)
+        if (lex[j] != ref_lex[j])
+          throw std::invalid_argument(
+            "statements for fusion must be in the same level-"
+            + to_string(level - 1) + " subloop");
+    }
+  }
+  
+  // collect lexicographical order values from to-be-fused statements
+  std::set<int> lex_values;
+  for (std::set<int>::const_iterator i = stmt_nums.begin();
+       i != stmt_nums.end(); i++) {
+    std::vector<int> lex = getLexicalOrder(*i);
+    lex_values.insert(lex[dim - 1]);
+  }
+  if (lex_values.size() == 1)
+    return;
+  // negative dependence would prevent fusion
+  
+  int dep_dim = get_dep_dim_of(ref_stmt_num, level);
+  
+  for (std::set<int>::iterator i = lex_values.begin(); i != lex_values.end();
+       i++) {
+    ref_lex[dim - 1] = *i;
+    std::set<int> a = getStatements(ref_lex, dim - 1);
+    std::set<int>::iterator j = i;
+    j++;
+    for (; j != lex_values.end(); j++) {
+      ref_lex[dim - 1] = *j;
+      std::set<int> b = getStatements(ref_lex, dim - 1);
+      for (std::set<int>::iterator ii = a.begin(); ii != a.end(); ii++)
+        for (std::set<int>::iterator jj = b.begin(); jj != b.end();
+             jj++) {
+          std::vector<DependenceVector> dvs;
+          dvs = dep.getEdge(*ii, *jj);
+          for (int k = 0; k < dvs.size(); k++)
+            if (dvs[k].isCarried(dep_dim)
+                && dvs[k].hasNegative(dep_dim))
+              throw loop_error(
+                "loop error: statements " + to_string(*ii)
+                + " and " + to_string(*jj)
+                + " cannot be fused together due to negative dependence");
+          dvs = dep.getEdge(*jj, *ii);
+          for (int k = 0; k < dvs.size(); k++)
+            if (dvs[k].isCarried(dep_dim)
+                && dvs[k].hasNegative(dep_dim))
+              throw loop_error(
+                "loop error: statements " + to_string(*jj)
+                + " and " + to_string(*ii)
+                + " cannot be fused together due to negative dependence");
+        }
+    }
+  }
+  
+  std::set<int> same_loop = getStatements(ref_lex, dim - 3);
+  
+  std::vector<std::set<int> > s = sort_by_same_loops(same_loop, level);
+  
+  std::set<int> s1;
+  std::set<int> s2;
+  std::set<int> s4;
+  std::vector<std::set<int> > s3;
+  for (std::set<int>::iterator kk = stmt_nums.begin(); kk != stmt_nums.end();
+       kk++)
+    for (int i = 0; i < s.size(); i++)
+      if (s[i].find(*kk) != s[i].end()) {
+        s1.insert(s[i].begin(), s[i].end());
+        s2.insert(i);
+      }
+  
+  s3.push_back(s1);
+  for (int i = 0; i < s.size(); i++)
+    if (s2.find(i) == s2.end()) {
+      s3.push_back(s[i]);
+      s4.insert(s[i].begin(), s[i].end());
+    }
+  try {
+    std::vector<std::set<int> > s5;
+    s5.push_back(s1);
+    s5.push_back(s4);
+    
+    //Dependence Check for Ordering Constraint
+    //Graph<std::set<int>, bool> dummy = construct_induced_graph_at_level(s5,
+    //      dep, dep_dim);
+    
+    Graph<std::set<int>, bool> g = construct_induced_graph_at_level(s3, dep,
+                                                                    dep_dim);
+    
+    s = typed_fusion(g);
+  } catch (const loop_error &e) {
+    
+    throw loop_error(
+      "statements cannot be fused together due to negative dependence");
+    
+  }
+  
+  if (s3.size() == s.size()) {
+    int order = 0;
+    for (int i = 0; i < s.size(); i++) {
+      
+      for (std::set<int>::iterator it = s[i].begin(); it != s[i].end();
+           it++) {
+        
+        assign_const(stmt[*it].xform, 2 * level - 2, order);
+        
+      }
+      
+      order++;
+    }
+  } else if (s3.size() > s.size()) {
+    
+    int order = 0;
+    for (int j = 0; j < s.size(); j++) {
+      std::set<int>::iterator it3;
+      for (it3 = s1.begin(); it3 != s1.end(); it3++) {
+        if (s[j].find(*it3) != s[j].end())
+          break;
+      }
+      if (it3 != s1.end()) {
+        for (std::set<int>::iterator it = s1.begin(); it != s1.end();
+             it++)
+          assign_const(stmt[*it].xform, 2 * level - 2, order);
+        
+        order++;
+        
+      }
+      
+      for (int i = 0; i < s3.size(); i++) {
+        std::set<int>::iterator it2;
+        
+        for (it2 = s3[i].begin(); it2 != s3[i].end(); it2++) {
+          if (s[j].find(*it2) != s[j].end())
+            break;
+        }
+        
+        if (it2 != s3[i].end()) {
+          for (std::set<int>::iterator it = s3[i].begin();
+               it != s3[i].end(); it++)
+            assign_const(stmt[*it].xform, 2 * level - 2, order);
+          
+          order++;
+          
+        }
+      }
+    }
+    
+  } else
+    throw loop_error("Typed Fusion Error");
+  
+}
+
+
+
+void Loop::distribute(const std::set<int> &stmt_nums, int level) {
+  if (stmt_nums.size() == 0 || stmt_nums.size() == 1)
+    return;
+  
+  // invalidate saved codegen computation
+  delete last_compute_cgr_;
+  last_compute_cgr_ = NULL;
+  delete last_compute_cg_;
+  last_compute_cg_ = NULL;
+  int dim = 2 * level - 1;
+  int ref_stmt_num;
+  // check for sanity of parameters
+  std::vector<int> ref_lex;
+  for (std::set<int>::const_iterator i = stmt_nums.begin();
+       i != stmt_nums.end(); i++) {
+    if (*i < 0 || *i >= stmt.size())
+      throw std::invalid_argument(
+        "invalid statement number " + to_string(*i));
+    if (level < 1
+        || (level > (stmt[*i].xform.n_out() - 1) / 2
+            || level > stmt[*i].loop_level.size()))
+      throw std::invalid_argument(
+        "invalid loop level " + to_string(level));
+    if (ref_lex.size() == 0) {
+      ref_lex = getLexicalOrder(*i);
+      ref_stmt_num = *i;
+    } else {
+      std::vector<int> lex = getLexicalOrder(*i);
+      for (int j = 0; j <= dim - 1; j += 2)
+        if (lex[j] != ref_lex[j])
+          throw std::invalid_argument(
+            "statements for distribution must be in the same level-"
+            + to_string(level) + " subloop");
+    }
+  }
+  // find SCC in the to-be-distributed loop
+  int dep_dim = get_dep_dim_of(ref_stmt_num, level);
+  std::set<int> same_loop = getStatements(ref_lex, dim - 1);
+  Graph<int, Empty> g;
+  for (std::set<int>::iterator i = same_loop.begin(); i != same_loop.end();
+       i++)
+    g.insert(*i);
+  for (int i = 0; i < g.vertex.size(); i++)
+    for (int j = i + 1; j < g.vertex.size(); j++) {
+      std::vector<DependenceVector> dvs;
+      dvs = dep.getEdge(g.vertex[i].first, g.vertex[j].first);
+      for (int k = 0; k < dvs.size(); k++)
+        if (dvs[k].isCarried(dep_dim)) {
+          g.connect(i, j);
+          break;
+        }
+      dvs = dep.getEdge(g.vertex[j].first, g.vertex[i].first);
+      for (int k = 0; k < dvs.size(); k++)
+        if (dvs[k].isCarried(dep_dim)) {
+          g.connect(j, i);
+          break;
+        }
+    }
+  std::vector<std::set<int> > s = g.topoSort();
+  // find statements that cannot be distributed due to dependence cycle
+  Graph<std::set<int>, Empty> g2;
+  for (int i = 0; i < s.size(); i++) {
+    std::set<int> t;
+    for (std::set<int>::iterator j = s[i].begin(); j != s[i].end(); j++)
+      if (stmt_nums.find(g.vertex[*j].first) != stmt_nums.end())
+        t.insert(g.vertex[*j].first);
+    if (!t.empty())
+      g2.insert(t);
+  }
+  for (int i = 0; i < g2.vertex.size(); i++)
+    for (int j = i + 1; j < g2.vertex.size(); j++)
+      for (std::set<int>::iterator ii = g2.vertex[i].first.begin();
+           ii != g2.vertex[i].first.end(); ii++)
+        for (std::set<int>::iterator jj = g2.vertex[j].first.begin();
+             jj != g2.vertex[j].first.end(); jj++) {
+          std::vector<DependenceVector> dvs;
+          dvs = dep.getEdge(*ii, *jj);
+          for (int k = 0; k < dvs.size(); k++)
+            if (dvs[k].isCarried(dep_dim)) {
+              g2.connect(i, j);
+              break;
+            }
+          dvs = dep.getEdge(*jj, *ii);
+          for (int k = 0; k < dvs.size(); k++)
+            if (dvs[k].isCarried(dep_dim)) {
+              g2.connect(j, i);
+              break;
+            }
+        }
+  std::vector<std::set<int> > s2 = g2.topoSort();
+  // nothing to distribute
+  if (s2.size() == 1)
+    throw loop_error(
+      "loop error: no statement can be distributed due to dependence cycle");
+  std::vector<std::set<int> > s3;
+  for (int i = 0; i < s2.size(); i++) {
+    std::set<int> t;
+    for (std::set<int>::iterator j = s2[i].begin(); j != s2[i].end(); j++)
+      std::set_union(t.begin(), t.end(), g2.vertex[*j].first.begin(),
+                     g2.vertex[*j].first.end(), inserter(t, t.begin()));
+    s3.push_back(t);
+  }
+  // associate other affected statements with the right distributed statements
+  for (std::set<int>::iterator i = same_loop.begin(); i != same_loop.end();
+       i++)
+    if (stmt_nums.find(*i) == stmt_nums.end()) {
+      bool is_inserted = false;
+      int potential_insertion_point = 0;
+      for (int j = 0; j < s3.size(); j++) {
+        for (std::set<int>::iterator k = s3[j].begin();
+             k != s3[j].end(); k++) {
+          std::vector<DependenceVector> dvs;
+          dvs = dep.getEdge(*i, *k);
+          for (int kk = 0; kk < dvs.size(); kk++)
+            if (dvs[kk].isCarried(dep_dim)) {
+              s3[j].insert(*i);
+              is_inserted = true;
+              break;
+            }
+          dvs = dep.getEdge(*k, *i);
+          for (int kk = 0; kk < dvs.size(); kk++)
+            if (dvs[kk].isCarried(dep_dim))
+              potential_insertion_point = j;
+        }
+        if (is_inserted)
+          break;
+      }
+      if (!is_inserted)
+        s3[potential_insertion_point].insert(*i);
+    }
+  // set lexicographical order after distribution
+  int order = ref_lex[dim - 1];
+  shiftLexicalOrder(ref_lex, dim - 1, s3.size() - 1);
+  for (std::vector<std::set<int> >::iterator i = s3.begin(); i != s3.end();
+       i++) {
+    for (std::set<int>::iterator j = (*i).begin(); j != (*i).end(); j++)
+      assign_const(stmt[*j].xform, dim - 1, order);
+    order++;
+  }
+  // no need to update dependence graph
+  ;
+  return;
+}
+
diff --git a/src/loop_datacopy.cc b/src/loop_datacopy.cc
new file mode 100644
index 0000000..8d11b0a
--- /dev/null
+++ b/src/loop_datacopy.cc
@@ -0,0 +1,2166 @@
+/*****************************************************************************
+ Copyright (C) 2008 University of Southern California
+ Copyright (C) 2009-2010 University of Utah
+ All Rights Reserved.
+
+ Purpose:
+   Various data copy schemes.
+
+ Notes:
+
+ History:
+   02/20/09 Created by Chun Chen by splitting original datacopy from loop.cc
+*****************************************************************************/
+
+#include <code_gen/codegen.h>
+#include <code_gen/CG_utils.h>
+#include "loop.hh"
+#include "omegatools.hh"
+#include "ir_code.hh"
+#include "chill_error.hh"
+
+using namespace omega;
+
+//
+// data copy function by referring arrays by numbers.
+// e.g. A[i] = A[i-1] + B[i]
+//      parameter array_ref_num=[0,2] means to copy data touched by A[i-1] and A[i]
+//
+bool Loop::datacopy(const std::vector<std::pair<int, std::vector<int> > > &array_ref_nums, int level,
+                    bool allow_extra_read, int fastest_changing_dimension, int padding_stride, int padding_alignment, int memory_type) {
+  // check for sanity of parameters
+  std::set<int> same_loop;
+  for (int i = 0; i < array_ref_nums.size(); i++) {
+    int stmt_num = array_ref_nums[i].first;
+    if (stmt_num < 0 || stmt_num >= stmt.size())
+      throw std::invalid_argument("invalid statement number " + to_string(stmt_num));
+    if (level <= 0 || level > stmt[stmt_num].loop_level.size())
+      throw std::invalid_argument("invalid loop level " + to_string(level));
+    if (i == 0) {
+      std::vector<int> lex = getLexicalOrder(stmt_num);
+      same_loop = getStatements(lex, 2*level-2);
+    }
+    else if (same_loop.find(stmt_num) == same_loop.end())
+      throw std::invalid_argument("array references for data copy must be located in the same subloop");
+  }
+  
+  // convert array reference numbering scheme to actual array references
+  std::vector<std::pair<int, std::vector<IR_ArrayRef *> > > selected_refs;
+  for (int i = 0; i < array_ref_nums.size(); i++) {
+    if (array_ref_nums[i].second.size() == 0)
+      continue;
+    
+    int stmt_num = array_ref_nums[i].first;
+    selected_refs.push_back(std::make_pair(stmt_num, std::vector<IR_ArrayRef *>()));
+    std::vector<IR_ArrayRef *> refs = ir->FindArrayRef(stmt[stmt_num].code);
+    std::vector<bool> selected(refs.size(), false);
+    for (int j = 0; j < array_ref_nums[i].second.size(); j++) {
+      int ref_num = array_ref_nums[i].second[j];
+      if (ref_num < 0 || ref_num >= refs.size()) {
+        for (int k = 0; k < refs.size(); k++)
+          delete refs[k];
+        throw std::invalid_argument("invalid array reference number " + to_string(ref_num) + " in statement " + to_string(stmt_num));
+      }
+      selected_refs[selected_refs.size()-1].second.push_back(refs[ref_num]);
+      selected[ref_num] = true;
+    }
+    for (int j = 0; j < refs.size(); j++)
+      if (!selected[j])
+        delete refs[j];
+  }
+  if (selected_refs.size() == 0)
+    throw std::invalid_argument("found no array references to copy");
+  
+  // do the copy
+  return datacopy_privatized(selected_refs, level, std::vector<int>(), allow_extra_read, fastest_changing_dimension, padding_stride, padding_alignment, memory_type);
+}
+
+//
+// data copy function by referring arrays by name.
+// e.g. A[i] = A[i-1] + B[i]
+//      parameter array_name=A means to copy data touched by A[i-1] and A[i]
+//
+bool Loop::datacopy(int stmt_num, int level, const std::string &array_name,
+                    bool allow_extra_read, int fastest_changing_dimension, int padding_stride, int padding_alignment, int memory_type) {
+  // check for sanity of parameters
+  if (stmt_num < 0 || stmt_num >= stmt.size())
+    throw std::invalid_argument("invalid statement number " + to_string(stmt_num));
+  if (level <= 0 || level > stmt[stmt_num].loop_level.size())
+    throw std::invalid_argument("invalid loop level " + to_string(level));
+  
+  // collect array references by name
+  std::vector<int> lex = getLexicalOrder(stmt_num);
+  int dim = 2*level - 1;
+  std::set<int> same_loop = getStatements(lex, dim-1);
+  
+  std::vector<std::pair<int, std::vector<IR_ArrayRef *> > > selected_refs;
+  for (std::set<int>::iterator i = same_loop.begin(); i != same_loop.end(); i++) {
+    std::vector<IR_ArrayRef *> t;
+    std::vector<IR_ArrayRef *> refs = ir->FindArrayRef(stmt[*i].code);  
+    for (int j = 0; j < refs.size(); j++)
+      if (refs[j]->name() == array_name)
+        t.push_back(refs[j]);
+      else
+        delete refs[j];
+    if (t.size() != 0)
+      selected_refs.push_back(std::make_pair(*i, t)); 
+  }
+  if (selected_refs.size() == 0)
+    throw std::invalid_argument("found no array references with name " + to_string(array_name) + " to copy");
+  
+  // do the copy
+  return datacopy_privatized(selected_refs, level, std::vector<int>(), allow_extra_read, fastest_changing_dimension, padding_stride, padding_alignment, memory_type);
+}
+
+
+bool Loop::datacopy_privatized(int stmt_num, int level, const std::string &array_name, const std::vector<int> &privatized_levels,
+                               bool allow_extra_read, int fastest_changing_dimension, int padding_stride, int padding_alignment, int memory_type) {
+  // check for sanity of parameters
+  if (stmt_num < 0 || stmt_num >= stmt.size())
+    throw std::invalid_argument("invalid statement number " + to_string(stmt_num));
+  if (level <= 0 || level > stmt[stmt_num].loop_level.size())
+    throw std::invalid_argument("invalid loop level " + to_string(level));
+  
+  // collect array references by name
+  std::vector<int> lex = getLexicalOrder(stmt_num);
+  int dim = 2*level - 1;
+  std::set<int> same_loop = getStatements(lex, dim-1);
+  
+  std::vector<std::pair<int, std::vector<IR_ArrayRef *> > > selected_refs;
+  for (std::set<int>::iterator i = same_loop.begin(); i != same_loop.end(); i++) {
+    selected_refs.push_back(std::make_pair(*i, std::vector<IR_ArrayRef *>()));
+    
+    std::vector<IR_ArrayRef *> refs = ir->FindArrayRef(stmt[*i].code);  
+    for (int j = 0; j < refs.size(); j++)
+      if (refs[j]->name() == array_name)
+        selected_refs[selected_refs.size()-1].second.push_back(refs[j]);
+      else
+        delete refs[j];
+  }
+  if (selected_refs.size() == 0)
+    throw std::invalid_argument("found no array references with name " + to_string(array_name) + " to copy");
+  
+  // do the copy
+  return datacopy_privatized(selected_refs, level, privatized_levels, allow_extra_read, fastest_changing_dimension, padding_stride, padding_alignment, memory_type);
+}
+
+
+bool Loop::datacopy_privatized(const std::vector<std::pair<int, std::vector<int> > > &array_ref_nums, int level, const std::vector<int> &privatized_levels, bool allow_extra_read, int fastest_changing_dimension, int padding_stride, int padding_alignment, int memory_type) {
+  // check for sanity of parameters
+  std::set<int> same_loop;
+  for (int i = 0; i < array_ref_nums.size(); i++) {
+    int stmt_num = array_ref_nums[i].first;
+    if (stmt_num < 0 || stmt_num >= stmt.size())
+      throw std::invalid_argument("invalid statement number " + to_string(stmt_num));
+    if (level <= 0 || level > stmt[stmt_num].loop_level.size())
+      throw std::invalid_argument("invalid loop level " + to_string(level));
+    if (i == 0) {
+      std::vector<int> lex = getLexicalOrder(stmt_num);
+      same_loop = getStatements(lex, 2*level-2);
+    }
+    else if (same_loop.find(stmt_num) == same_loop.end())
+      throw std::invalid_argument("array references for data copy must be located in the same subloop");
+  }
+  
+  // convert array reference numbering scheme to actual array references
+  std::vector<std::pair<int, std::vector<IR_ArrayRef *> > > selected_refs;
+  for (int i = 0; i < array_ref_nums.size(); i++) {
+    if (array_ref_nums[i].second.size() == 0)
+      continue;
+    
+    int stmt_num = array_ref_nums[i].first;
+    selected_refs.push_back(std::make_pair(stmt_num, std::vector<IR_ArrayRef *>()));
+    std::vector<IR_ArrayRef *> refs = ir->FindArrayRef(stmt[stmt_num].code);
+    std::vector<bool> selected(refs.size(), false);
+    for (int j = 0; j < array_ref_nums[i].second.size(); j++) {
+      int ref_num = array_ref_nums[i].second[j];
+      if (ref_num < 0 || ref_num >= refs.size()) {
+        for (int k = 0; k < refs.size(); k++)
+          delete refs[k];
+        throw std::invalid_argument("invalid array reference number " + to_string(ref_num) + " in statement " + to_string(stmt_num));
+      }
+      selected_refs[selected_refs.size()-1].second.push_back(refs[ref_num]);
+      selected[ref_num] = true;
+    }
+    for (int j = 0; j < refs.size(); j++)
+      if (!selected[j])
+        delete refs[j];
+  }
+  if (selected_refs.size() == 0)
+    throw std::invalid_argument("found no array references to copy");
+  
+  // do the copy
+  return datacopy_privatized(selected_refs, level, privatized_levels, allow_extra_read, fastest_changing_dimension, padding_stride, padding_alignment, memory_type);
+}
+
+
+//
+// Implement low level datacopy function with lots of options.
+//
+/*bool Loop::datacopy_privatized(const std::vector<std::pair<int, std::vector<IR_ArrayRef *> > > &stmt_refs, int level,
+  const std::vector<int> &privatized_levels,
+  bool allow_extra_read, int fastest_changing_dimension,
+  int padding_stride, int padding_alignment, int memory_type) {
+  if (stmt_refs.size() == 0)
+  return true;
+  
+  // check for sanity of parameters
+  IR_ArraySymbol *sym = NULL;
+  std::vector<int> lex;
+  std::set<int> active;
+  if (level <= 0)
+  throw std::invalid_argument("invalid loop level " + to_string(level));
+  for (int i = 0; i < privatized_levels.size(); i++) {
+  if (i == 0) {
+  if (privatized_levels[i] < level)
+  throw std::invalid_argument("privatized loop levels must be no less than level " + to_string(level));
+  }
+  else if (privatized_levels[i] <= privatized_levels[i-1])
+  throw std::invalid_argument("privatized loop levels must be in ascending order");
+  }
+  for (int i = 0; i < stmt_refs.size(); i++) {
+  int stmt_num = stmt_refs[i].first;
+  active.insert(stmt_num);
+  if (stmt_num < 0 || stmt_num >= stmt.size())
+  throw std::invalid_argument("invalid statement number " + to_string(stmt_num));
+  if (privatized_levels.size() != 0) {
+  if (privatized_levels[privatized_levels.size()-1] > stmt[stmt_num].loop_level.size())
+  throw std::invalid_argument("invalid loop level " + to_string(privatized_levels[privatized_levels.size()-1]) + " for statement " + to_string(stmt_num));
+  }
+  else {
+  if (level > stmt[stmt_num].loop_level.size())
+  throw std::invalid_argument("invalid loop level " + to_string(level) + " for statement " + to_string(stmt_num));
+  }
+  for (int j = 0; j < stmt_refs[i].second.size(); j++) {
+  if (sym == NULL) {
+  sym = stmt_refs[i].second[j]->symbol();
+  lex = getLexicalOrder(stmt_num);
+  }
+  else {
+  IR_ArraySymbol *t = stmt_refs[i].second[j]->symbol();
+  if (t->name() != sym->name()) {
+  delete t;
+  delete sym;
+  throw std::invalid_argument("try to copy data from different arrays");
+  }
+  delete t;
+  }
+  }
+  }
+  if (!(fastest_changing_dimension >= -1 && fastest_changing_dimension < sym->n_dim()))
+  throw std::invalid_argument("invalid fastest changing dimension for the array to be copied");
+  if (padding_stride < 0)
+  throw std::invalid_argument("invalid temporary array stride requirement");
+  if (padding_alignment == -1 || padding_alignment == 0)
+  throw std::invalid_argument("invalid temporary array alignment requirement");
+  
+  int dim = 2*level - 1;
+  int n_dim = sym->n_dim();
+  
+  if (fastest_changing_dimension == -1)
+  switch (sym->layout_type()) {
+  case IR_ARRAY_LAYOUT_ROW_MAJOR:
+  fastest_changing_dimension = n_dim - 1;
+  break;
+  case IR_ARRAY_LAYOUT_COLUMN_MAJOR:
+  fastest_changing_dimension = 0;
+  break;
+  default:
+  throw loop_error("unsupported array layout");
+  }
+  
+  
+  // build iteration spaces for all reads and for all writes separately
+  apply_xform(active);
+  bool has_write_refs = false;
+  bool has_read_refs = false;
+  Relation wo_copy_is = Relation::False(level-1+privatized_levels.size()+n_dim);
+  Relation ro_copy_is = Relation::False(level-1+privatized_levels.size()+n_dim);
+  for (int i = 0; i < stmt_refs.size(); i++) {
+  int stmt_num = stmt_refs[i].first;
+  
+  for (int j = 0; j < stmt_refs[i].second.size(); j++) {
+  Relation mapping(stmt[stmt_num].IS.n_set(), level-1+privatized_levels.size()+n_dim);
+  for (int k = 1; k <= mapping.n_inp(); k++)
+  mapping.name_input_var(k, stmt[stmt_num].IS.set_var(k)->name());
+  mapping.setup_names();
+  F_And *f_root = mapping.add_and();
+  for (int k = 1; k <= level-1; k++) {
+  EQ_Handle h = f_root->add_EQ();
+  h.update_coef(mapping.input_var(k), 1);
+  h.update_coef(mapping.output_var(k), -1);
+  }
+  for (int k = 0; k < privatized_levels.size(); k++) {
+  EQ_Handle h = f_root->add_EQ();
+  h.update_coef(mapping.input_var(privatized_levels[k]), 1);
+  h.update_coef(mapping.output_var(level+k), -1);
+  }
+  for (int k = 0; k < n_dim; k++) {
+  CG_outputRepr *repr = stmt_refs[i].second[j]->index(k);
+  exp2formula(ir, mapping, f_root, freevar, repr, mapping.output_var(level-1+privatized_levels.size()+k+1), 'w', IR_COND_EQ, false);
+  repr->clear();
+  delete repr;
+  }
+  Relation r = Range(Restrict_Domain(mapping, Intersection(copy(stmt[stmt_num].IS), Extend_Set(copy(this->known), stmt[stmt_num].IS.n_set() - this->known.n_set()))));
+  if (stmt_refs[i].second[j]->is_write()) {
+  has_write_refs = true;
+  wo_copy_is = Union(wo_copy_is, r);
+  wo_copy_is.simplify(2, 4);
+  }
+  else {
+  has_read_refs = true;
+  //protonu--removing the next line for now
+  ro_copy_is = Union(ro_copy_is, r);
+  ro_copy_is.simplify(2, 4);
+  //ro_copy_is = ConvexRepresentation(Union(ro_copy_is, r));
+  
+  }
+  }
+  }
+  
+  if (allow_extra_read) {
+  Relation t = DecoupledConvexHull(copy(ro_copy_is));
+  if (t.number_of_conjuncts() > 1)
+  ro_copy_is = RectHull(ro_copy_is);
+  else
+  ro_copy_is = t;
+  }
+  else {
+  Relation t = ConvexRepresentation(copy(ro_copy_is));
+  if (t.number_of_conjuncts() > 1)
+  ro_copy_is = RectHull(ro_copy_is);
+  else
+  ro_copy_is = t;
+  }
+  wo_copy_is = ConvexRepresentation(wo_copy_is);
+  
+  if (allow_extra_read) {
+  Tuple<Relation> Rs;
+  Tuple<int> active;
+  for (DNF_Iterator di(ro_copy_is.query_DNF()); di; di++) {
+  Rs.append(Relation(ro_copy_is, di.curr()));
+  active.append(1);
+  }
+  Relation the_gcs = Relation::True(ro_copy_is.n_set());
+  for (int i = level-1+privatized_levels.size()+1; i <= level-1+privatized_levels.size()+n_dim; i++) {
+  Relation r = greatest_common_step(Rs, active, i, Relation::Null());
+  the_gcs = Intersection(the_gcs, r);
+  }
+  
+  ro_copy_is = Approximate(ro_copy_is);
+  ro_copy_is = ConvexRepresentation(ro_copy_is);
+  ro_copy_is = Intersection(ro_copy_is, the_gcs);
+  ro_copy_is.simplify();
+  }
+  
+  
+  
+  for (int i = 1; i < level; i++) {
+  std::string s = stmt[*active.begin()].IS.input_var(i)->name();
+  wo_copy_is.name_set_var(i, s);
+  ro_copy_is.name_set_var(i, s);
+  }
+  for (int i = 0; i < privatized_levels.size(); i++) {
+  std::string s = stmt[*active.begin()].IS.input_var(privatized_levels[i])->name();
+  wo_copy_is.name_set_var(level+i, s);
+  ro_copy_is.name_set_var(level+i, s);
+  }
+  for (int i = level+privatized_levels.size(); i < level+privatized_levels.size()+n_dim; i++) {
+  std::string s = tmp_loop_var_name_prefix + to_string(tmp_loop_var_name_counter+i-level-privatized_levels.size());
+  wo_copy_is.name_set_var(i, s);
+  ro_copy_is.name_set_var(i, s);
+  }
+  tmp_loop_var_name_counter += n_dim;
+  
+  //protonu--end change
+  
+  wo_copy_is.setup_names();
+  ro_copy_is.setup_names();
+  
+  // build merged iteration space for calculating temporary array size
+  bool already_use_recthull = false;
+  Relation untampered_copy_is = ConvexRepresentation(Union(copy(wo_copy_is), copy(ro_copy_is)));
+  Relation copy_is = untampered_copy_is;
+  if (copy_is.number_of_conjuncts() > 1) {
+  try {
+  copy_is = ConvexHull(copy(untampered_copy_is));
+  }
+  catch (const std::overflow_error &e) {
+  copy_is = RectHull(copy(untampered_copy_is));
+  already_use_recthull = true;
+  }
+  }
+  
+  
+  Retry_copy_is:
+  // extract temporary array information
+  CG_outputBuilder *ocg = ir->builder();
+  std::vector<CG_outputRepr *> index_lb(n_dim); // initialized to NULL
+  std::vector<coef_t> index_stride(n_dim, 1);
+  std::vector<bool> is_index_eq(n_dim, false);
+  std::vector<std::pair<int, CG_outputRepr *> > index_sz(0);  
+  Relation reduced_copy_is = copy(copy_is);
+  
+  for (int i = 0; i < n_dim; i++) {
+  if (i != 0)
+  reduced_copy_is = Project(reduced_copy_is, level-1+privatized_levels.size()+i, Set_Var);
+  Relation bound = get_loop_bound(reduced_copy_is, level-1+privatized_levels.size()+i);
+  
+  // extract stride
+  EQ_Handle stride_eq;
+  {
+  bool simple_stride = true;
+  int strides = countStrides(bound.query_DNF()->single_conjunct(), bound.set_var(level-1+privatized_levels.size()+i+1), stride_eq, simple_stride);
+  if (strides > 1) {
+  throw loop_error("too many strides");
+  }
+  else if (strides == 1) {
+  int sign = stride_eq.get_coef(bound.set_var(level-1+privatized_levels.size()+i+1));
+  Constr_Vars_Iter it(stride_eq, true);
+  index_stride[i] = abs((*it).coef/sign);
+  }
+  }
+  
+  // check if this arary index requires loop
+  Conjunct *c = bound.query_DNF()->single_conjunct();
+  for (EQ_Iterator ei(c->EQs()); ei; ei++) {
+  if ((*ei).has_wildcards())
+  continue;
+  
+  int coef = (*ei).get_coef(bound.set_var(level-1+privatized_levels.size()+i+1));
+  if (coef != 0) {
+  int sign = 1;
+  if (coef < 0) {
+  coef = -coef;
+  sign = -1;
+  }
+  
+  CG_outputRepr *op = NULL;
+  for (Constr_Vars_Iter ci(*ei); ci; ci++) {
+  switch ((*ci).var->kind()) {
+  case Input_Var:
+  {
+  if ((*ci).var != bound.set_var(level-1+privatized_levels.size()+i+1))
+  if ((*ci).coef*sign == 1)
+  op = ocg->CreateMinus(op, ocg->CreateIdent((*ci).var->name()));
+  else if ((*ci).coef*sign == -1)
+  op = ocg->CreatePlus(op, ocg->CreateIdent((*ci).var->name()));
+  else if ((*ci).coef*sign > 1)
+  op = ocg->CreateMinus(op, ocg->CreateTimes(ocg->CreateInt(abs((*ci).coef)), ocg->CreateIdent((*ci).var->name())));
+  else // (*ci).coef*sign < -1
+  op = ocg->CreatePlus(op, ocg->CreateTimes(ocg->CreateInt(abs((*ci).coef)), ocg->CreateIdent((*ci).var->name())));
+  break;
+  }
+  case Global_Var:
+  {
+  Global_Var_ID g = (*ci).var->get_global_var();
+  if ((*ci).coef*sign == 1)
+  op = ocg->CreateMinus(op, ocg->CreateIdent(g->base_name()));
+  else if ((*ci).coef*sign == -1)
+  op = ocg->CreatePlus(op, ocg->CreateIdent(g->base_name()));
+  else if ((*ci).coef*sign > 1)
+  op = ocg->CreateMinus(op, ocg->CreateTimes(ocg->CreateInt(abs((*ci).coef)), ocg->CreateIdent(g->base_name())));
+  else // (*ci).coef*sign < -1
+  op = ocg->CreatePlus(op, ocg->CreateTimes(ocg->CreateInt(abs((*ci).coef)), ocg->CreateIdent(g->base_name())));
+  break;
+  }
+  default:
+  throw loop_error("unsupported array index expression");
+  }
+  }
+  if ((*ei).get_const() != 0)
+  op = ocg->CreatePlus(op, ocg->CreateInt(-sign*((*ei).get_const())));
+  if (coef != 1)
+  op = ocg->CreateIntegerDivide(op, ocg->CreateInt(coef));
+  
+  index_lb[i] = op;
+  is_index_eq[i] = true;
+  break;
+  }
+  }
+  if (is_index_eq[i])
+  continue;
+  
+  // seperate lower and upper bounds
+  std::vector<GEQ_Handle> lb_list, ub_list;
+  for (GEQ_Iterator gi(c->GEQs()); gi; gi++) {
+  int coef = (*gi).get_coef(bound.set_var(level-1+privatized_levels.size()+i+1));
+  if (coef != 0 && (*gi).has_wildcards()) {
+  bool clean_bound = true;
+  GEQ_Handle h;
+  for (Constr_Vars_Iter cvi(*gi, true); gi; gi++)
+  if (!findFloorInequality(bound, (*cvi).var, h, bound.set_var(level-1+privatized_levels.size()+i+1))) {
+  clean_bound = false;
+  break;
+  }
+  if (!clean_bound)
+  continue;
+  }
+  
+  if (coef > 0)
+  lb_list.push_back(*gi);
+  else if (coef < 0)
+  ub_list.push_back(*gi);
+  }
+  if (lb_list.size() == 0 || ub_list.size() == 0)
+  if (already_use_recthull)
+  throw loop_error("failed to calcuate array footprint size");
+  else {
+  copy_is = RectHull(copy(untampered_copy_is));
+  already_use_recthull = true;
+  goto Retry_copy_is;
+  }
+  
+  // build lower bound representation
+  Tuple<CG_outputRepr *> lb_repr_list;
+  for (int j = 0; j < lb_list.size(); j++)
+  lb_repr_list.append(outputLBasRepr(ocg, lb_list[j], bound,
+  bound.set_var(level-1+privatized_levels.size()+i+1), 
+  index_stride[i], stride_eq, Relation::True(bound.n_set()),
+  std::vector<CG_outputRepr *>(bound.n_set())));
+  
+  if (lb_repr_list.size() > 1)
+  index_lb[i] = ocg->CreateInvoke("max", lb_repr_list);
+  else if (lb_repr_list.size() == 1)
+  index_lb[i] = lb_repr_list[1];
+  
+  // build temporary array size representation
+  {
+  Relation cal(copy_is.n_set(), 1);
+  F_And *f_root = cal.add_and();
+  for (int j = 0; j < ub_list.size(); j++)
+  for (int k = 0; k < lb_list.size(); k++) {
+  GEQ_Handle h = f_root->add_GEQ();
+  
+  for (Constr_Vars_Iter ci(ub_list[j]); ci; ci++) {
+  switch ((*ci).var->kind()) {
+  case Input_Var:
+  {
+  int pos = (*ci).var->get_position();
+  h.update_coef(cal.input_var(pos), (*ci).coef);
+  break;
+  }
+  case Global_Var:
+  {
+  Global_Var_ID g = (*ci).var->get_global_var();
+  Variable_ID v;
+  if (g->arity() == 0)
+  v = cal.get_local(g);
+  else
+  v = cal.get_local(g, (*ci).var->function_of());
+  h.update_coef(v, (*ci).coef);
+  break;
+  }
+  default:
+  throw loop_error("cannot calculate temporay array size statically");
+  }
+  }
+  h.update_const(ub_list[j].get_const());
+  
+  for (Constr_Vars_Iter ci(lb_list[k]); ci; ci++) {
+  switch ((*ci).var->kind()) {
+  case Input_Var:
+  {
+  int pos = (*ci).var->get_position();
+  h.update_coef(cal.input_var(pos), (*ci).coef);
+  break;
+  }
+  case Global_Var:
+  {
+  Global_Var_ID g = (*ci).var->get_global_var();
+  Variable_ID v;
+  if (g->arity() == 0)
+  v = cal.get_local(g);
+  else
+  v = cal.get_local(g, (*ci).var->function_of());
+  h.update_coef(v, (*ci).coef);
+  break;
+  }
+  default:
+  throw loop_error("cannot calculate temporay array size statically");
+  }
+  }
+  h.update_const(lb_list[k].get_const());
+  
+  h.update_const(1);
+  h.update_coef(cal.output_var(1), -1);
+  }
+  
+  cal = Restrict_Domain(cal, copy(copy_is));
+  for (int j = 1; j <= cal.n_inp(); j++)
+  cal = Project(cal, j, Input_Var);
+  cal.simplify();
+  
+  // pad temporary array size
+  // TODO: for variable array size, create padding formula
+  Conjunct *c = cal.query_DNF()->single_conjunct();
+  bool is_index_bound_const = false;
+  for (GEQ_Iterator gi(c->GEQs()); gi && !is_index_bound_const; gi++)
+  if ((*gi).is_const(cal.output_var(1))) {
+  coef_t size = (*gi).get_const() / (-(*gi).get_coef(cal.output_var(1)));
+  if (padding_stride != 0) {
+  size = (size + index_stride[i] - 1) / index_stride[i];
+  if (i == fastest_changing_dimension)
+  size = size * padding_stride;
+  }
+  if (i == fastest_changing_dimension) {
+  if (padding_alignment > 1) { // align to boundary for data packing
+  int residue = size % padding_alignment;
+  if (residue)
+  size = size+padding_alignment-residue;
+  }
+  else if (padding_alignment < -1) {  // un-alignment for memory bank conflicts
+  while (gcd(size, static_cast<coef_t>(-padding_alignment)) != 1)
+  size++;
+  }
+  }
+  index_sz.push_back(std::make_pair(i, ocg->CreateInt(size)));
+  is_index_bound_const = true;
+  }
+  
+  if (!is_index_bound_const) {
+  for (GEQ_Iterator gi(c->GEQs()); gi && !is_index_bound_const; gi++) {
+  int coef = (*gi).get_coef(cal.output_var(1));
+  if (coef < 0) {
+  CG_outputRepr *op = NULL;
+  for (Constr_Vars_Iter ci(*gi); ci; ci++) {
+  if ((*ci).var != cal.output_var(1)) {
+  switch((*ci).var->kind()) {
+  case Global_Var:
+  {
+  Global_Var_ID g = (*ci).var->get_global_var();
+  if ((*ci).coef == 1)
+  op = ocg->CreatePlus(op, ocg->CreateIdent(g->base_name()));
+  else if ((*ci).coef == -1)
+  op = ocg->CreateMinus(op, ocg->CreateIdent(g->base_name()));
+  else if ((*ci).coef > 1)
+  op = ocg->CreatePlus(op, ocg->CreateTimes(ocg->CreateInt((*ci).coef), ocg->CreateIdent(g->base_name())));
+  else // (*ci).coef < -1
+  op = ocg->CreateMinus(op, ocg->CreateTimes(ocg->CreateInt(-(*ci).coef), ocg->CreateIdent(g->base_name())));
+  break;
+  }
+  default:
+  throw loop_error("failed to generate array index bound code");
+  }
+  }
+  }
+  int c = (*gi).get_const();
+  if (c > 0)
+  op = ocg->CreatePlus(op, ocg->CreateInt(c));
+  else if (c < 0)
+  op = ocg->CreateMinus(op, ocg->CreateInt(-c));
+  if (padding_stride != 0) {
+  if (i == fastest_changing_dimension) {
+  coef_t g = gcd(index_stride[i], static_cast<coef_t>(padding_stride));
+  coef_t t1 = index_stride[i] / g;
+  if (t1 != 1)
+  op = ocg->CreateIntegerDivide(ocg->CreatePlus(op, ocg->CreateInt(t1-1)), ocg->CreateInt(t1));
+  coef_t t2 = padding_stride / g;
+  if (t2 != 1)
+  op = ocg->CreateTimes(op, ocg->CreateInt(t2));
+  }
+  else if (index_stride[i] != 1) {
+  op = ocg->CreateIntegerDivide(ocg->CreatePlus(op, ocg->CreateInt(index_stride[i]-1)), ocg->CreateInt(index_stride[i]));
+  }
+  }
+  
+  index_sz.push_back(std::make_pair(i, op));
+  break;
+  }
+  }
+  }
+  }
+  }
+  
+  // change the temporary array index order
+  for (int i = 0; i < index_sz.size(); i++)
+  if (index_sz[i].first == fastest_changing_dimension)
+  switch (sym->layout_type()) {
+  case IR_ARRAY_LAYOUT_ROW_MAJOR:
+  std::swap(index_sz[index_sz.size()-1], index_sz[i]);
+  break;
+  case IR_ARRAY_LAYOUT_COLUMN_MAJOR:
+  std::swap(index_sz[0], index_sz[i]);
+  break;
+  default:
+  throw loop_error("unsupported array layout");
+  }
+  
+  // declare temporary array or scalar
+  IR_Symbol *tmp_sym;
+  if (index_sz.size() == 0) {
+  tmp_sym = ir->CreateScalarSymbol(sym, memory_type);
+  }
+  else {
+  std::vector<CG_outputRepr *> tmp_array_size(index_sz.size());
+  for (int i = 0; i < index_sz.size(); i++)
+  tmp_array_size[i] = index_sz[i].second->clone();
+  tmp_sym = ir->CreateArraySymbol(sym, tmp_array_size, memory_type);
+  }
+  
+  // create temporary array read initialization code
+  CG_outputRepr *copy_code_read;
+  if (has_read_refs)
+  if (index_sz.size() == 0) {
+  IR_ScalarRef *tmp_scalar_ref = ir->CreateScalarRef(static_cast<IR_ScalarSymbol *>(tmp_sym));
+  
+  std::vector<CG_outputRepr *> rhs_index(n_dim);
+  for (int i = 0; i < index_lb.size(); i++)
+  if (is_index_eq[i])
+  rhs_index[i] = index_lb[i]->clone();
+  else
+  rhs_index[i] = ir->builder()->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+i+1)->name());
+  IR_ArrayRef *copied_array_ref = ir->CreateArrayRef(sym, rhs_index);
+  
+  copy_code_read = ir->builder()->CreateAssignment(0, tmp_scalar_ref->convert(), copied_array_ref->convert());
+  }
+  else {
+  std::vector<CG_outputRepr *> lhs_index(index_sz.size());
+  for (int i = 0; i < index_sz.size(); i++) {
+  int cur_index_num = index_sz[i].first;
+  CG_outputRepr *cur_index_repr = ocg->CreateMinus(ocg->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+cur_index_num+1)->name()), index_lb[cur_index_num]->clone());
+  if (padding_stride != 0) {
+  if (i == n_dim-1) {
+  coef_t g = gcd(index_stride[cur_index_num], static_cast<coef_t>(padding_stride));
+  coef_t t1 = index_stride[cur_index_num] / g;
+  if (t1 != 1)
+  cur_index_repr = ocg->CreateIntegerDivide(cur_index_repr, ocg->CreateInt(t1));
+  coef_t t2 = padding_stride / g;
+  if (t2 != 1)
+  cur_index_repr = ocg->CreateTimes(cur_index_repr, ocg->CreateInt(t2));
+  }
+  else if (index_stride[cur_index_num] != 1) {
+  cur_index_repr = ocg->CreateIntegerDivide(cur_index_repr, ocg->CreateInt(index_stride[cur_index_num]));
+  }
+  }
+  
+  if (ir->ArrayIndexStartAt() != 0)
+  cur_index_repr = ocg->CreatePlus(cur_index_repr, ocg->CreateInt(ir->ArrayIndexStartAt()));
+  lhs_index[i] = cur_index_repr;
+  }
+  
+  IR_ArrayRef *tmp_array_ref = ir->CreateArrayRef(static_cast<IR_ArraySymbol *>(tmp_sym), lhs_index);
+  
+  std::vector<CG_outputRepr *> rhs_index(n_dim);
+  for (int i = 0; i < index_lb.size(); i++)
+  if (is_index_eq[i])
+  rhs_index[i] = index_lb[i]->clone();
+  else
+  rhs_index[i] = ir->builder()->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+i+1)->name());
+  IR_ArrayRef *copied_array_ref = ir->CreateArrayRef(sym, rhs_index);
+  
+  copy_code_read = ir->builder()->CreateAssignment(0, tmp_array_ref->convert(), copied_array_ref->convert());
+  }
+  
+  // create temporary array write back code
+  CG_outputRepr *copy_code_write;
+  if (has_write_refs)
+  if (index_sz.size() == 0) {
+  IR_ScalarRef *tmp_scalar_ref = ir->CreateScalarRef(static_cast<IR_ScalarSymbol *>(tmp_sym));
+  
+  std::vector<CG_outputRepr *> rhs_index(n_dim);
+  for (int i = 0; i < index_lb.size(); i++)
+  if (is_index_eq[i])
+  rhs_index[i] = index_lb[i]->clone();
+  else
+  rhs_index[i] = ir->builder()->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+i+1)->name());
+  IR_ArrayRef *copied_array_ref = ir->CreateArrayRef(sym, rhs_index);
+  
+  copy_code_write = ir->builder()->CreateAssignment(0, copied_array_ref->convert(), tmp_scalar_ref->convert());
+  }
+  else {
+  std::vector<CG_outputRepr *> lhs_index(n_dim);
+  for (int i = 0; i < index_lb.size(); i++)
+  if (is_index_eq[i])
+  lhs_index[i] = index_lb[i]->clone();
+  else
+  lhs_index[i] = ir->builder()->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+i+1)->name());
+  IR_ArrayRef *copied_array_ref = ir->CreateArrayRef(sym, lhs_index);
+  
+  std::vector<CG_outputRepr *> rhs_index(index_sz.size());
+  for (int i = 0; i < index_sz.size(); i++) {
+  int cur_index_num = index_sz[i].first;
+  CG_outputRepr *cur_index_repr = ocg->CreateMinus(ocg->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+cur_index_num+1)->name()), index_lb[cur_index_num]->clone());
+  if (padding_stride != 0) {
+  if (i == n_dim-1) {
+  coef_t g = gcd(index_stride[cur_index_num], static_cast<coef_t>(padding_stride));
+  coef_t t1 = index_stride[cur_index_num] / g;
+  if (t1 != 1)
+  cur_index_repr = ocg->CreateIntegerDivide(cur_index_repr, ocg->CreateInt(t1));
+  coef_t t2 = padding_stride / g;
+  if (t2 != 1)
+  cur_index_repr = ocg->CreateTimes(cur_index_repr, ocg->CreateInt(t2));
+  }
+  else if (index_stride[cur_index_num] != 1) {
+  cur_index_repr = ocg->CreateIntegerDivide(cur_index_repr, ocg->CreateInt(index_stride[cur_index_num]));
+  }
+  }
+  
+  if (ir->ArrayIndexStartAt() != 0)
+  cur_index_repr = ocg->CreatePlus(cur_index_repr, ocg->CreateInt(ir->ArrayIndexStartAt()));
+  rhs_index[i] = cur_index_repr;
+  }
+  IR_ArrayRef *tmp_array_ref = ir->CreateArrayRef(static_cast<IR_ArraySymbol *>(tmp_sym), rhs_index);
+  
+  copy_code_write = ir->builder()->CreateAssignment(0, copied_array_ref->convert(), tmp_array_ref->convert());
+  }
+  
+  // now we can remove those loops for array indexes that are
+  // dependent on others
+  if (!(index_sz.size() == n_dim && (sym->layout_type() == IR_ARRAY_LAYOUT_ROW_MAJOR || n_dim <= 1))) {
+  Relation mapping(level-1+privatized_levels.size()+n_dim, level-1+privatized_levels.size()+index_sz.size());
+  F_And *f_root = mapping.add_and();
+  for (int i = 1; i <= level-1+privatized_levels.size(); i++) {
+  EQ_Handle h = f_root->add_EQ();
+  h.update_coef(mapping.input_var(i), 1);
+  h.update_coef(mapping.output_var(i), -1);
+  }
+  
+  int cur_index = 0;
+  std::vector<int> mapped_index(index_sz.size());
+  for (int i = 0; i < n_dim; i++)
+  if (!is_index_eq[i]) {
+  EQ_Handle h = f_root->add_EQ();
+  h.update_coef(mapping.input_var(level-1+privatized_levels.size()+i+1), 1);
+  switch (sym->layout_type()) {
+  case IR_ARRAY_LAYOUT_COLUMN_MAJOR: {
+  h.update_coef(mapping.output_var(level-1+privatized_levels.size()+index_sz.size()-cur_index), -1);
+  mapped_index[index_sz.size()-cur_index-1] = i;
+  break;
+  }
+  case IR_ARRAY_LAYOUT_ROW_MAJOR: {
+  h.update_coef(mapping.output_var(level-1+privatized_levels.size()+cur_index+1), -1);
+  mapped_index[cur_index] = i;
+  break;
+  }
+  default:
+  throw loop_error("unsupported array layout");
+  }
+  cur_index++;
+  }
+  
+  wo_copy_is = Range(Restrict_Domain(copy(mapping), wo_copy_is));
+  ro_copy_is = Range(Restrict_Domain(copy(mapping), ro_copy_is));
+  
+  // protonu--replacing Chun's old code 
+  for (int i = 1; i <= level-1+privatized_levels.size(); i++) {
+  wo_copy_is.name_set_var(i, copy_is.set_var(i)->name());
+  ro_copy_is.name_set_var(i, copy_is.set_var(i)->name());
+  }
+  
+  
+  
+  for (int i = 0; i < index_sz.size(); i++) {
+  wo_copy_is.name_set_var(level-1+privatized_levels.size()+i+1, copy_is.set_var(level-1+privatized_levels.size()+mapped_index[i]+1)->name());
+  ro_copy_is.name_set_var(level-1+privatized_levels.size()+i+1, copy_is.set_var(level-1+privatized_levels.size()+mapped_index[i]+1)->name());
+  }      
+  wo_copy_is.setup_names();
+  ro_copy_is.setup_names();
+  }
+  
+  // insert read copy statement
+  int old_num_stmt = stmt.size();
+  int ro_copy_stmt_num = -1;
+  if (has_read_refs) {
+  Relation copy_xform(ro_copy_is.n_set(), 2*ro_copy_is.n_set()+1);
+  {
+  F_And *f_root = copy_xform.add_and();
+  for (int i = 1; i <= ro_copy_is.n_set(); i++) {
+  EQ_Handle h = f_root->add_EQ();
+  h.update_coef(copy_xform.input_var(i), 1);
+  h.update_coef(copy_xform.output_var(2*i), -1);
+  }
+  for (int i = 1; i <= dim; i+=2) {
+  EQ_Handle h = f_root->add_EQ();
+  h.update_coef(copy_xform.output_var(i), -1);
+  h.update_const(lex[i-1]);
+  }
+  for (int i = dim+2; i <= copy_xform.n_out(); i+=2) {
+  EQ_Handle h = f_root->add_EQ();
+  h.update_coef(copy_xform.output_var(i), 1);
+  }
+  }
+  
+  Statement copy_stmt_read;
+  copy_stmt_read.IS = ro_copy_is;
+  copy_stmt_read.xform = copy_xform;
+  copy_stmt_read.code = copy_code_read;
+  copy_stmt_read.loop_level = std::vector<LoopLevel>(ro_copy_is.n_set());
+  copy_stmt_read.ir_stmt_node = NULL;
+  for (int i = 0; i < level-1; i++) {
+  copy_stmt_read.loop_level[i].type = stmt[*(active.begin())].loop_level[i].type;
+  if (stmt[*(active.begin())].loop_level[i].type == LoopLevelTile &&
+  stmt[*(active.begin())].loop_level[i].payload >= level) {
+  int j;
+  for (j = 0; j < privatized_levels.size(); j++)
+  if (privatized_levels[j] == stmt[*(active.begin())].loop_level[i].payload)
+  break;
+  if (j == privatized_levels.size())
+  copy_stmt_read.loop_level[i].payload = -1;
+  else
+  copy_stmt_read.loop_level[i].payload = level + j;
+  }
+  else
+  copy_stmt_read.loop_level[i].payload = stmt[*(active.begin())].loop_level[i].payload;
+  copy_stmt_read.loop_level[i].parallel_level = stmt[*(active.begin())].loop_level[i].parallel_level;
+  }
+  for (int i = 0; i < privatized_levels.size(); i++) {
+  copy_stmt_read.loop_level[level-1+i].type = stmt[*(active.begin())].loop_level[privatized_levels[i]].type;
+  copy_stmt_read.loop_level[level-1+i].payload = stmt[*(active.begin())].loop_level[privatized_levels[i]].payload;
+  copy_stmt_read.loop_level[level-1+i].parallel_level = stmt[*(active.begin())].loop_level[privatized_levels[i]].parallel_level;
+  }
+  int left_num_dim = num_dep_dim - (get_last_dep_dim_before(*(active.begin()), level) + 1);
+  for (int i = 0; i < min(left_num_dim, static_cast<int>(index_sz.size())); i++) {
+  copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].type = LoopLevelOriginal;
+  copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].payload = num_dep_dim-left_num_dim+i;
+  copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].parallel_level = 0;
+  }
+  for (int i = min(left_num_dim, static_cast<int>(index_sz.size())); i < index_sz.size(); i++) {
+  copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].type = LoopLevelUnknown;
+  copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].payload = -1;
+  copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].parallel_level = 0;
+  }
+  
+  shiftLexicalOrder(lex, dim-1, 1);
+  stmt.push_back(copy_stmt_read);
+  ro_copy_stmt_num = stmt.size() - 1;
+  dep.insert();
+  }
+  
+  // insert write copy statement
+  int wo_copy_stmt_num = -1;
+  if (has_write_refs) {
+  Relation copy_xform(wo_copy_is.n_set(), 2*wo_copy_is.n_set()+1);
+  {
+  F_And *f_root = copy_xform.add_and();
+  for (int i = 1; i <= wo_copy_is.n_set(); i++) {
+  EQ_Handle h = f_root->add_EQ();
+  h.update_coef(copy_xform.input_var(i), 1);
+  h.update_coef(copy_xform.output_var(2*i), -1);
+  }
+  for (int i = 1; i <= dim; i+=2) {
+  EQ_Handle h = f_root->add_EQ();
+  h.update_coef(copy_xform.output_var(i), -1);
+  h.update_const(lex[i-1]);
+  }
+  for (int i = dim+2; i <= copy_xform.n_out(); i+=2) {
+  EQ_Handle h = f_root->add_EQ();
+  h.update_coef(copy_xform.output_var(i), 1);
+  }
+  }
+  
+  Statement copy_stmt_write;
+  copy_stmt_write.IS = wo_copy_is;
+  copy_stmt_write.xform = copy_xform;
+  copy_stmt_write.code = copy_code_write;
+  copy_stmt_write.loop_level = std::vector<LoopLevel>(wo_copy_is.n_set());
+  copy_stmt_write.ir_stmt_node = NULL;
+  
+  for (int i = 0; i < level-1; i++) {
+  copy_stmt_write.loop_level[i].type = stmt[*(active.begin())].loop_level[i].type;
+  if (stmt[*(active.begin())].loop_level[i].type == LoopLevelTile &&
+  stmt[*(active.begin())].loop_level[i].payload >= level) {
+  int j;
+  for (j = 0; j < privatized_levels.size(); j++)
+  if (privatized_levels[j] == stmt[*(active.begin())].loop_level[i].payload)
+  break;
+  if (j == privatized_levels.size())
+  copy_stmt_write.loop_level[i].payload = -1;
+  else
+  copy_stmt_write.loop_level[i].payload = level + j;
+  }
+  else
+  copy_stmt_write.loop_level[i].payload = stmt[*(active.begin())].loop_level[i].payload;
+  copy_stmt_write.loop_level[i].parallel_level = stmt[*(active.begin())].loop_level[i].parallel_level;
+  }
+  for (int i = 0; i < privatized_levels.size(); i++) {
+  copy_stmt_write.loop_level[level-1+i].type = stmt[*(active.begin())].loop_level[privatized_levels[i]].type;
+  copy_stmt_write.loop_level[level-1+i].payload = stmt[*(active.begin())].loop_level[privatized_levels[i]].payload;
+  copy_stmt_write.loop_level[level-1+i].parallel_level = stmt[*(active.begin())].loop_level[privatized_levels[i]].parallel_level;
+  }
+  int left_num_dim = num_dep_dim - (get_last_dep_dim_before(*(active.begin()), level) + 1);
+  for (int i = 0; i < min(left_num_dim, static_cast<int>(index_sz.size())); i++) {
+  copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].type = LoopLevelOriginal;
+  copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].payload = num_dep_dim-left_num_dim+i;
+  copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].parallel_level = 0;
+  }
+  for (int i = min(left_num_dim, static_cast<int>(index_sz.size())); i < index_sz.size(); i++) {
+  copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].type = LoopLevelUnknown;
+  copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].payload = -1;
+  copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].parallel_level = 0;
+  }
+  
+  lex[dim-1]++;
+  shiftLexicalOrder(lex, dim-1, -2);
+  stmt.push_back(copy_stmt_write);
+  wo_copy_stmt_num = stmt.size() - 1;
+  dep.insert();
+  } 
+  
+  // replace original array accesses with temporary array accesses
+  for (int i =0; i < stmt_refs.size(); i++)
+  for (int j = 0; j < stmt_refs[i].second.size(); j++) {
+  if (index_sz.size() == 0) {
+  IR_ScalarRef *tmp_scalar_ref = ir->CreateScalarRef(static_cast<IR_ScalarSymbol *>(tmp_sym));
+  ir->ReplaceExpression(stmt_refs[i].second[j], tmp_scalar_ref->convert());
+  }
+  else {
+  std::vector<CG_outputRepr *> index_repr(index_sz.size());
+  for (int k = 0; k < index_sz.size(); k++) {
+  int cur_index_num = index_sz[k].first;
+  
+  CG_outputRepr *cur_index_repr = ocg->CreateMinus(stmt_refs[i].second[j]->index(cur_index_num), index_lb[cur_index_num]->clone());
+  if (padding_stride != 0) {
+  if (k == n_dim-1) {
+  coef_t g = gcd(index_stride[cur_index_num], static_cast<coef_t>(padding_stride));
+  coef_t t1 = index_stride[cur_index_num] / g;
+  if (t1 != 1)
+  cur_index_repr = ocg->CreateIntegerDivide(cur_index_repr, ocg->CreateInt(t1));
+  coef_t t2 = padding_stride / g;
+  if (t2 != 1)
+  cur_index_repr = ocg->CreateTimes(cur_index_repr, ocg->CreateInt(t2));
+  }
+  else if (index_stride[cur_index_num] != 1) {
+  cur_index_repr = ocg->CreateIntegerDivide(cur_index_repr, ocg->CreateInt(index_stride[cur_index_num]));
+  }
+  }
+  
+  if (ir->ArrayIndexStartAt() != 0)
+  cur_index_repr = ocg->CreatePlus(cur_index_repr, ocg->CreateInt(ir->ArrayIndexStartAt()));
+  index_repr[k] = cur_index_repr;
+  }
+  
+  IR_ArrayRef *tmp_array_ref = ir->CreateArrayRef(static_cast<IR_ArraySymbol *>(tmp_sym), index_repr);
+  ir->ReplaceExpression(stmt_refs[i].second[j], tmp_array_ref->convert());
+  }
+  }
+  
+  // update dependence graph
+  int dep_dim = get_last_dep_dim_before(*(active.begin()), level) + 1;
+  if (ro_copy_stmt_num != -1) {
+  for (int i = 0; i < old_num_stmt; i++) {
+  std::vector<std::vector<DependenceVector> > D;
+  
+  for (DependenceGraph::EdgeList::iterator j = dep.vertex[i].second.begin(); j != dep.vertex[i].second.end();) {
+  if (active.find(i) != active.end() && active.find(j->first) == active.end()) {
+  std::vector<DependenceVector> dvs1, dvs2;
+  for (int k = 0; k < j->second.size(); k++) {
+  DependenceVector dv = j->second[k];
+  if (dv.sym != NULL && dv.sym->name() == sym->name() && (dv.type == DEP_R2R || dv.type == DEP_R2W))
+  dvs1.push_back(dv);
+  else
+  dvs2.push_back(dv);
+  }
+  j->second = dvs2;
+  if (dvs1.size() > 0)
+  dep.connect(ro_copy_stmt_num, j->first, dvs1);
+  }
+  else if (active.find(i) == active.end() && active.find(j->first) != active.end()) {
+  std::vector<DependenceVector> dvs1, dvs2;
+  for (int k = 0; k < j->second.size(); k++) {
+  DependenceVector dv = j->second[k];
+  if (dv.sym != NULL && dv.sym->name() == sym->name() && (dv.type == DEP_R2R || dv.type == DEP_W2R))
+  dvs1.push_back(dv);
+  else
+  dvs2.push_back(dv);
+  }
+  j->second = dvs2;
+  if (dvs1.size() > 0)
+  D.push_back(dvs1);
+  }
+  
+  if (j->second.size() == 0)
+  dep.vertex[i].second.erase(j++);
+  else
+  j++;
+  }
+  
+  for (int j = 0; j < D.size(); j++)
+  dep.connect(i, ro_copy_stmt_num, D[j]);
+  }
+  
+  // insert dependences from copy statement loop to copied statements
+  DependenceVector dv;
+  dv.type = DEP_W2R;
+  dv.sym = tmp_sym->clone();
+  dv.lbounds = std::vector<coef_t>(num_dep_dim, 0);
+  dv.ubounds = std::vector<coef_t>(num_dep_dim, 0);
+  for (int i = dep_dim; i < num_dep_dim; i++) {
+  dv.lbounds[i] = -posInfinity;
+  dv.ubounds[i] = posInfinity;
+  } 
+  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++)
+  dep.connect(ro_copy_stmt_num, *i, dv);
+  }
+  
+  if (wo_copy_stmt_num != -1) {
+  for (int i = 0; i < old_num_stmt; i++) {
+  std::vector<std::vector<DependenceVector> > D;
+  
+  for (DependenceGraph::EdgeList::iterator j = dep.vertex[i].second.begin(); j != dep.vertex[i].second.end();) {
+  if (active.find(i) != active.end() && active.find(j->first) == active.end()) {
+  std::vector<DependenceVector> dvs1, dvs2;
+  for (int k = 0; k < j->second.size(); k++) {
+  DependenceVector dv = j->second[k];
+  if (dv.sym != NULL && dv.sym->name() == sym->name() && (dv.type == DEP_W2R || dv.type == DEP_W2W))
+  dvs1.push_back(dv);
+  else
+  dvs2.push_back(dv);
+  }
+  j->second = dvs2;
+  if (dvs1.size() > 0)
+  dep.connect(wo_copy_stmt_num, j->first, dvs1);
+  }
+  else if (active.find(i) == active.end() && active.find(j->first) != active.end()) {
+  std::vector<DependenceVector> dvs1, dvs2;
+  for (int k = 0; k < j->second.size(); k++) {
+  DependenceVector dv = j->second[k];
+  if (dv.sym != NULL && dv.sym->name() == sym->name() && (dv.type == DEP_R2W || dv.type == DEP_W2W))
+  dvs1.push_back(dv);
+  else
+  dvs2.push_back(dv);
+  }
+  j->second = dvs2;
+  if (dvs1.size() > 0)
+  D.push_back(dvs1);
+  }
+  
+  if (j->second.size() == 0)
+  dep.vertex[i].second.erase(j++);
+  else
+  j++;
+  }
+  
+  for (int j = 0; j < D.size(); j++)
+  dep.connect(i, wo_copy_stmt_num, D[j]);
+  }
+  
+  // insert dependences from copied statements to write statements
+  DependenceVector dv;
+  dv.type = DEP_W2R;
+  dv.sym = tmp_sym->clone();
+  dv.lbounds = std::vector<coef_t>(num_dep_dim, 0);
+  dv.ubounds = std::vector<coef_t>(num_dep_dim, 0);
+  for (int i = dep_dim; i < num_dep_dim; i++) {
+  dv.lbounds[i] = -posInfinity;
+  dv.ubounds[i] = posInfinity;
+  } 
+  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++)
+  dep.connect(*i, wo_copy_stmt_num, dv);
+  
+  }
+  
+  // update variable name for dependences among copied statements
+  for (int i = 0; i < old_num_stmt; i++) {
+  if (active.find(i) != active.end())
+  for (DependenceGraph::EdgeList::iterator j = dep.vertex[i].second.begin(); j != dep.vertex[i].second.end(); j++)
+  if (active.find(j->first) != active.end())
+  for (int k = 0; k < j->second.size(); k++) {
+  IR_Symbol *s = tmp_sym->clone();
+  j->second[k].sym = s;
+  }
+  }
+  
+  // insert anti-dependence from write statement to read statement
+  if (ro_copy_stmt_num != -1 && wo_copy_stmt_num != -1)
+  if (dep_dim >= 0) {
+  DependenceVector dv;
+  dv.type = DEP_R2W;
+  dv.sym = tmp_sym->clone();
+  dv.lbounds = std::vector<coef_t>(num_dep_dim, 0);
+  dv.ubounds = std::vector<coef_t>(num_dep_dim, 0);
+  for (int k = dep_dim; k < num_dep_dim; k++) {
+  dv.lbounds[k] = -posInfinity;
+  dv.ubounds[k] = posInfinity;
+  }
+  for (int k = 0; k < dep_dim; k++) {
+  if (k != 0) {
+  dv.lbounds[k-1] = 0;
+  dv.ubounds[k-1] = 0;
+  }
+  dv.lbounds[k] = 1;
+  dv.ubounds[k] = posInfinity;
+  dep.connect(wo_copy_stmt_num, ro_copy_stmt_num, dv);
+  }
+  }
+  
+  
+  // cleanup
+  delete sym;
+  delete tmp_sym;
+  for (int i = 0; i < index_lb.size(); i++) {
+  index_lb[i]->clear();
+  delete index_lb[i];
+  }
+  for (int i = 0; i < index_sz.size(); i++) {
+  index_sz[i].second->clear();
+  delete index_sz[i].second;
+  }
+  
+  return true;
+  }
+*/
+bool Loop::datacopy_privatized(const std::vector<std::pair<int, std::vector<IR_ArrayRef *> > > &stmt_refs, int level,
+                               const std::vector<int> &privatized_levels,
+                               bool allow_extra_read, int fastest_changing_dimension,
+                               int padding_stride, int padding_alignment, int memory_type) {
+  if (stmt_refs.size() == 0)
+    return true;
+  
+  // check for sanity of parameters
+  IR_ArraySymbol *sym = NULL;
+  std::vector<int> lex;
+  std::set<int> active;
+  if (level <= 0)
+    throw std::invalid_argument("invalid loop level " + to_string(level));
+  for (int i = 0; i < privatized_levels.size(); i++) {
+    if (i == 0) {
+      if (privatized_levels[i] < level)
+        throw std::invalid_argument("privatized loop levels must be no less than level " + to_string(level));
+    }
+    else if (privatized_levels[i] <= privatized_levels[i-1])
+      throw std::invalid_argument("privatized loop levels must be in ascending order");
+  }
+  for (int i = 0; i < stmt_refs.size(); i++) {
+    int stmt_num = stmt_refs[i].first;
+    active.insert(stmt_num);
+    if (stmt_num < 0 || stmt_num >= stmt.size())
+      throw std::invalid_argument("invalid statement number " + to_string(stmt_num));
+    if (privatized_levels.size() != 0) {
+      if (privatized_levels[privatized_levels.size()-1] > stmt[stmt_num].loop_level.size())
+        throw std::invalid_argument("invalid loop level " + to_string(privatized_levels[privatized_levels.size()-1]) + " for statement " + to_string(stmt_num));
+    }
+    else {
+      if (level > stmt[stmt_num].loop_level.size())
+        throw std::invalid_argument("invalid loop level " + to_string(level) + " for statement " + to_string(stmt_num));
+    }
+    for (int j = 0; j < stmt_refs[i].second.size(); j++) {
+      if (sym == NULL) {
+        sym = stmt_refs[i].second[j]->symbol();
+        lex = getLexicalOrder(stmt_num);
+      }
+      else {
+        IR_ArraySymbol *t = stmt_refs[i].second[j]->symbol();
+        if (t->name() != sym->name()) {
+          delete t;
+          delete sym;
+          throw std::invalid_argument("try to copy data from different arrays");
+        }
+        delete t;
+      }
+    }
+  }
+  if (!(fastest_changing_dimension >= -1 && fastest_changing_dimension < sym->n_dim()))
+    throw std::invalid_argument("invalid fastest changing dimension for the array to be copied");
+  if (padding_stride < 0)
+    throw std::invalid_argument("invalid temporary array stride requirement");
+  if (padding_alignment == -1 || padding_alignment == 0)
+    throw std::invalid_argument("invalid temporary array alignment requirement");
+  
+  int dim = 2*level - 1;
+  int n_dim = sym->n_dim();
+  
+
+  if (fastest_changing_dimension == -1)
+    switch (sym->layout_type()) {
+    case IR_ARRAY_LAYOUT_ROW_MAJOR:
+      fastest_changing_dimension = n_dim - 1;
+      break;
+    case IR_ARRAY_LAYOUT_COLUMN_MAJOR:
+      fastest_changing_dimension = 0;
+      break;
+    default:
+      throw loop_error("unsupported array layout");
+    }
+
+  
+  // invalidate saved codegen computation
+  delete last_compute_cgr_;
+  last_compute_cgr_ = NULL;
+  delete last_compute_cg_;
+  last_compute_cg_ = NULL;
+  
+  // build iteration spaces for all reads and for all writes separately
+  apply_xform(active);
+  
+  bool has_write_refs = false;
+  bool has_read_refs = false;
+  Relation wo_copy_is = Relation::False(level-1+privatized_levels.size()+n_dim);
+  Relation ro_copy_is = Relation::False(level-1+privatized_levels.size()+n_dim);
+  for (int i = 0; i < stmt_refs.size(); i++) {
+    int stmt_num = stmt_refs[i].first;
+    
+    for (int j = 0; j < stmt_refs[i].second.size(); j++) {
+      Relation mapping(stmt[stmt_num].IS.n_set(), level-1+privatized_levels.size()+n_dim);
+      for (int k = 1; k <= mapping.n_inp(); k++)
+        mapping.name_input_var(k, stmt[stmt_num].IS.set_var(k)->name());
+      mapping.setup_names();
+      F_And *f_root = mapping.add_and();
+      for (int k = 1; k <= level-1; k++) {
+        EQ_Handle h = f_root->add_EQ();
+        h.update_coef(mapping.input_var(k), 1);
+        h.update_coef(mapping.output_var(k), -1);
+      }
+      for (int k = 0; k < privatized_levels.size(); k++) {
+        EQ_Handle h = f_root->add_EQ();
+        h.update_coef(mapping.input_var(privatized_levels[k]), 1);
+        h.update_coef(mapping.output_var(level+k), -1);
+      }
+      for (int k = 0; k < n_dim; k++) {
+        CG_outputRepr *repr = stmt_refs[i].second[j]->index(k);
+        exp2formula(ir, mapping, f_root, freevar, repr, mapping.output_var(level-1+privatized_levels.size()+k+1), 'w', IR_COND_EQ, false);
+        repr->clear();
+        delete repr;
+      }
+      Relation r = Range(Restrict_Domain(mapping, Intersection(copy(stmt[stmt_num].IS), Extend_Set(copy(this->known), stmt[stmt_num].IS.n_set() - this->known.n_set()))));
+      if (stmt_refs[i].second[j]->is_write()) {
+        has_write_refs = true;
+        wo_copy_is = Union(wo_copy_is, r);
+        wo_copy_is.simplify(2, 4);
+        
+        
+      }
+      else {
+        has_read_refs = true;
+        ro_copy_is = Union(ro_copy_is, r);
+        ro_copy_is.simplify(2, 4);
+        
+      }
+    }
+  }
+  
+  // simplify read and write footprint iteration space
+  {
+    if (allow_extra_read)
+      ro_copy_is = SimpleHull(ro_copy_is, true, true);
+    else
+      ro_copy_is = ConvexRepresentation(ro_copy_is);
+    
+    wo_copy_is = ConvexRepresentation(wo_copy_is);
+    if (wo_copy_is.number_of_conjuncts() > 1) {
+      Relation t = SimpleHull(wo_copy_is, true, true);
+      if (Must_Be_Subset(copy(t), copy(ro_copy_is)))
+        wo_copy_is = t;
+      else if (Must_Be_Subset(copy(wo_copy_is), copy(ro_copy_is)))
+        wo_copy_is = ro_copy_is;
+    }
+  }
+  
+  // make copy statement variable names match the ones in the original statements which
+  // already have the same names due to apply_xform
+  {
+    int ref_stmt = *active.begin();
+    for (std::set<int>::iterator i = active.begin(); i != active.end(); i++)
+      if (stmt[*i].IS.n_set() > stmt[ref_stmt].IS.n_set())
+        ref_stmt = *i;
+    for (int i = 1; i < level; i++) {
+      std::string s = stmt[ref_stmt].IS.input_var(i)->name();
+      wo_copy_is.name_set_var(i, s);
+      ro_copy_is.name_set_var(i, s);
+    }
+    for (int i = 0; i < privatized_levels.size(); i++) {
+      std::string s = stmt[ref_stmt].IS.input_var(privatized_levels[i])->name();
+      wo_copy_is.name_set_var(level+i, s);
+      ro_copy_is.name_set_var(level+i, s);
+    }
+    for (int i = level+privatized_levels.size(); i < level+privatized_levels.size()+n_dim; i++) {
+      std::string s = tmp_loop_var_name_prefix + to_string(tmp_loop_var_name_counter+i-level-privatized_levels.size());
+      wo_copy_is.name_set_var(i, s);
+      ro_copy_is.name_set_var(i, s);
+    }
+    tmp_loop_var_name_counter += n_dim;
+    wo_copy_is.setup_names();
+    ro_copy_is.setup_names();
+  }
+  
+  // build merged footprint iteration space for calculating temporary array size
+  Relation copy_is = SimpleHull(Union(copy(ro_copy_is), copy(wo_copy_is)), true, true);
+  
+  // extract temporary array information
+  CG_outputBuilder *ocg = ir->builder();
+  std::vector<CG_outputRepr *> index_lb(n_dim); // initialized to NULL
+  std::vector<coef_t> index_stride(n_dim);
+  std::vector<bool> is_index_eq(n_dim, false);
+  std::vector<std::pair<int, CG_outputRepr *> > index_sz(0);
+  Relation reduced_copy_is = copy(copy_is);
+  
+  for (int i = 0; i < n_dim; i++) {
+    if (i != 0)
+      reduced_copy_is = Project(reduced_copy_is, level-1+privatized_levels.size()+i, Set_Var);
+    Relation bound = get_loop_bound(reduced_copy_is, level-1+privatized_levels.size()+i);
+    
+    // extract stride
+    std::pair<EQ_Handle, Variable_ID> result = find_simplest_stride(bound, bound.set_var(level-1+privatized_levels.size()+i+1));
+    if (result.second != NULL)
+      index_stride[i] = abs(result.first.get_coef(result.second))/gcd(abs(result.first.get_coef(result.second)), abs(result.first.get_coef(bound.set_var(level-1+privatized_levels.size()+i+1))));
+    else
+      index_stride[i] = 1;
+    
+    // check if this arary index requires loop
+    Conjunct *c = bound.query_DNF()->single_conjunct();
+    for (EQ_Iterator ei(c->EQs()); ei; ei++) {
+      if ((*ei).has_wildcards())
+        continue;
+      
+      int coef = (*ei).get_coef(bound.set_var(level-1+privatized_levels.size()+i+1));
+      if (coef != 0) {
+        int sign = 1;
+        if (coef < 0) {
+          coef = -coef;
+          sign = -1;
+        }
+        
+        CG_outputRepr *op = NULL;
+        for (Constr_Vars_Iter ci(*ei); ci; ci++) {
+          switch ((*ci).var->kind()) {
+          case Input_Var:
+          {
+            if ((*ci).var != bound.set_var(level-1+privatized_levels.size()+i+1))
+              if ((*ci).coef*sign == 1)
+                op = ocg->CreateMinus(op, ocg->CreateIdent((*ci).var->name()));
+              else if ((*ci).coef*sign == -1)
+                op = ocg->CreatePlus(op, ocg->CreateIdent((*ci).var->name()));
+              else if ((*ci).coef*sign > 1)
+                op = ocg->CreateMinus(op, ocg->CreateTimes(ocg->CreateInt(abs((*ci).coef)), ocg->CreateIdent((*ci).var->name())));
+              else // (*ci).coef*sign < -1
+                op = ocg->CreatePlus(op, ocg->CreateTimes(ocg->CreateInt(abs((*ci).coef)), ocg->CreateIdent((*ci).var->name())));
+            break;
+          }
+          case Global_Var:
+          {
+            Global_Var_ID g = (*ci).var->get_global_var();
+            if ((*ci).coef*sign == 1)
+              op = ocg->CreateMinus(op, ocg->CreateIdent(g->base_name()));
+            else if ((*ci).coef*sign == -1)
+              op = ocg->CreatePlus(op, ocg->CreateIdent(g->base_name()));
+            else if ((*ci).coef*sign > 1)
+              op = ocg->CreateMinus(op, ocg->CreateTimes(ocg->CreateInt(abs((*ci).coef)), ocg->CreateIdent(g->base_name())));
+            else // (*ci).coef*sign < -1
+              op = ocg->CreatePlus(op, ocg->CreateTimes(ocg->CreateInt(abs((*ci).coef)), ocg->CreateIdent(g->base_name())));
+            break;
+          }
+          default:
+            throw loop_error("unsupported array index expression");
+          }
+        }
+        if ((*ei).get_const() != 0)
+          op = ocg->CreatePlus(op, ocg->CreateInt(-sign*((*ei).get_const())));
+        if (coef != 1)
+          op = ocg->CreateIntegerFloor(op, ocg->CreateInt(coef));
+        
+        index_lb[i] = op;
+        is_index_eq[i] = true;
+        break;
+      }
+    }
+    if (is_index_eq[i])
+      continue;
+    
+    // seperate lower and upper bounds
+    std::vector<GEQ_Handle> lb_list, ub_list;
+    std::set<Variable_ID> excluded_floor_vars;
+    excluded_floor_vars.insert(bound.set_var(level-1+privatized_levels.size()+i+1));
+    for (GEQ_Iterator gi(c->GEQs()); gi; gi++) {
+      int coef = (*gi).get_coef(bound.set_var(level-1+privatized_levels.size()+i+1));
+      if (coef != 0 && (*gi).has_wildcards()) {
+        bool clean_bound = true;
+        GEQ_Handle h;
+        for (Constr_Vars_Iter cvi(*gi, true); gi; gi++)
+          if (!find_floor_definition(bound, (*cvi).var, excluded_floor_vars).first) {
+            clean_bound = false;
+            break;
+          }
+        if (!clean_bound)
+          continue;
+      }
+      
+      if (coef > 0)
+        lb_list.push_back(*gi);
+      else if (coef < 0)
+        ub_list.push_back(*gi);
+    }
+    if (lb_list.size() == 0 || ub_list.size() == 0)
+      throw loop_error("failed to calcuate array footprint size");
+    
+    // build lower bound representation
+    std::vector<CG_outputRepr *> lb_repr_list;
+    for (int j = 0; j < lb_list.size(); j++){
+      if(this->known.n_set() == 0)
+        lb_repr_list.push_back(output_lower_bound_repr(ocg, lb_list[j], bound.set_var(level-1+privatized_levels.size()+i+1), result.first, result.second, bound, Relation::True(bound.n_set()), std::vector<std::pair<CG_outputRepr *, int> >(bound.n_set(), std::make_pair(static_cast<CG_outputRepr *>(NULL), 0))));
+      else
+        lb_repr_list.push_back(output_lower_bound_repr(ocg, lb_list[j], bound.set_var(level-1+privatized_levels.size()+i+1), result.first, result.second, bound, this->known, std::vector<std::pair<CG_outputRepr *, int> >(bound.n_set(), std::make_pair(static_cast<CG_outputRepr *>(NULL), 0))));
+    }
+    if (lb_repr_list.size() > 1)
+      index_lb[i] = ocg->CreateInvoke("max", lb_repr_list);
+    else if (lb_repr_list.size() == 1)
+      index_lb[i] = lb_repr_list[0];
+    
+    // build temporary array size representation
+    {
+      Relation cal(copy_is.n_set(), 1);
+      F_And *f_root = cal.add_and();
+      for (int j = 0; j < ub_list.size(); j++)
+        for (int k = 0; k < lb_list.size(); k++) {
+          GEQ_Handle h = f_root->add_GEQ();
+          
+          for (Constr_Vars_Iter ci(ub_list[j]); ci; ci++) {
+            switch ((*ci).var->kind()) {
+            case Input_Var:
+            {
+              int pos = (*ci).var->get_position();
+              h.update_coef(cal.input_var(pos), (*ci).coef);
+              break;
+            }
+            case Global_Var:
+            {
+              Global_Var_ID g = (*ci).var->get_global_var();
+              Variable_ID v;
+              if (g->arity() == 0)
+                v = cal.get_local(g);
+              else
+                v = cal.get_local(g, (*ci).var->function_of());
+              h.update_coef(v, (*ci).coef);
+              break;
+            }
+            default:
+              throw loop_error("cannot calculate temporay array size statically");
+            }
+          }
+          h.update_const(ub_list[j].get_const());
+          
+          for (Constr_Vars_Iter ci(lb_list[k]); ci; ci++) {
+            switch ((*ci).var->kind()) {
+            case Input_Var:
+            {
+              int pos = (*ci).var->get_position();
+              h.update_coef(cal.input_var(pos), (*ci).coef);
+              break;
+            }
+            case Global_Var:
+            {
+              Global_Var_ID g = (*ci).var->get_global_var();
+              Variable_ID v;
+              if (g->arity() == 0)
+                v = cal.get_local(g);
+              else
+                v = cal.get_local(g, (*ci).var->function_of());
+              h.update_coef(v, (*ci).coef);
+              break;
+            }
+            default:
+              throw loop_error("cannot calculate temporay array size statically");
+            }
+          }
+          h.update_const(lb_list[k].get_const());
+          
+          h.update_const(1);
+          h.update_coef(cal.output_var(1), -1);
+        }
+      
+      cal = Restrict_Domain(cal, copy(copy_is));
+      for (int j = 1; j <= cal.n_inp(); j++)
+        cal = Project(cal, j, Input_Var);
+      cal.simplify();
+      
+      // pad temporary array size
+      // TODO: for variable array size, create padding formula
+      Conjunct *c = cal.query_DNF()->single_conjunct();
+      bool is_index_bound_const = false;
+      for (GEQ_Iterator gi(c->GEQs()); gi && !is_index_bound_const; gi++)
+        if ((*gi).is_const(cal.output_var(1))) {
+          coef_t size = (*gi).get_const() / (-(*gi).get_coef(cal.output_var(1)));
+          if (padding_stride != 0) {
+            size = (size + index_stride[i] - 1) / index_stride[i];
+            if (i == fastest_changing_dimension)
+              size = size * padding_stride;
+          }
+          if (i == fastest_changing_dimension) {
+            if (padding_alignment > 1) { // align to boundary for data packing
+              int residue = size % padding_alignment;
+              if (residue)
+                size = size+padding_alignment-residue;
+            }
+            else if (padding_alignment < -1) {  // un-alignment for memory bank conflicts
+              while (gcd(size, static_cast<coef_t>(-padding_alignment)) != 1)
+                size++;
+            }
+          }
+          index_sz.push_back(std::make_pair(i, ocg->CreateInt(size)));
+          is_index_bound_const = true;
+        }
+      
+      if (!is_index_bound_const) {
+        for (GEQ_Iterator gi(c->GEQs()); gi && !is_index_bound_const; gi++) {
+          int coef = (*gi).get_coef(cal.output_var(1));
+          if (coef < 0) {
+            CG_outputRepr *op = NULL;
+            for (Constr_Vars_Iter ci(*gi); ci; ci++) {
+              if ((*ci).var != cal.output_var(1)) {
+                switch((*ci).var->kind()) {
+                case Global_Var:
+                {
+                  Global_Var_ID g = (*ci).var->get_global_var();
+                  if ((*ci).coef == 1)
+                    op = ocg->CreatePlus(op, ocg->CreateIdent(g->base_name()));
+                  else if ((*ci).coef == -1)
+                    op = ocg->CreateMinus(op, ocg->CreateIdent(g->base_name()));
+                  else if ((*ci).coef > 1)
+                    op = ocg->CreatePlus(op, ocg->CreateTimes(ocg->CreateInt((*ci).coef), ocg->CreateIdent(g->base_name())));
+                  else // (*ci).coef < -1
+                    op = ocg->CreateMinus(op, ocg->CreateTimes(ocg->CreateInt(-(*ci).coef), ocg->CreateIdent(g->base_name())));
+                  break;
+                }
+                default:
+                  throw loop_error("failed to generate array index bound code");
+                }
+              }
+            }
+            int c = (*gi).get_const();
+            if (c > 0)
+              op = ocg->CreatePlus(op, ocg->CreateInt(c));
+            else if (c < 0)
+              op = ocg->CreateMinus(op, ocg->CreateInt(-c));
+            if (padding_stride != 0) {
+              if (i == fastest_changing_dimension) {
+                coef_t g = gcd(index_stride[i], static_cast<coef_t>(padding_stride));
+                coef_t t1 = index_stride[i] / g;
+                if (t1 != 1)
+                  op = ocg->CreateIntegerFloor(ocg->CreatePlus(op, ocg->CreateInt(t1-1)), ocg->CreateInt(t1));
+                coef_t t2 = padding_stride / g;
+                if (t2 != 1)
+                  op = ocg->CreateTimes(op, ocg->CreateInt(t2));
+              }
+              else if (index_stride[i] != 1) {
+                op = ocg->CreateIntegerFloor(ocg->CreatePlus(op, ocg->CreateInt(index_stride[i]-1)), ocg->CreateInt(index_stride[i]));
+              }
+            }
+            
+            index_sz.push_back(std::make_pair(i, op));
+            break;
+          }
+        }
+      }
+    }
+  }
+  
+  // change the temporary array index order
+  for (int i = 0; i < index_sz.size(); i++)
+    if (index_sz[i].first == fastest_changing_dimension)
+      switch (sym->layout_type()) {
+      case IR_ARRAY_LAYOUT_ROW_MAJOR:
+        std::swap(index_sz[index_sz.size()-1], index_sz[i]);
+        break;
+      case IR_ARRAY_LAYOUT_COLUMN_MAJOR:
+        std::swap(index_sz[0], index_sz[i]);
+        break;
+      default:
+        throw loop_error("unsupported array layout");
+      }
+  
+  // declare temporary array or scalar
+  IR_Symbol *tmp_sym;
+  if (index_sz.size() == 0) {
+    tmp_sym = ir->CreateScalarSymbol(sym, memory_type);
+  }
+  else {
+    std::vector<CG_outputRepr *> tmp_array_size(index_sz.size());
+    for (int i = 0; i < index_sz.size(); i++)
+      tmp_array_size[i] = index_sz[i].second->clone();
+    tmp_sym = ir->CreateArraySymbol(sym, tmp_array_size, memory_type);
+  }
+  
+  // create temporary array read initialization code
+  CG_outputRepr *copy_code_read;
+  if (has_read_refs)
+    if (index_sz.size() == 0) {
+      IR_ScalarRef *tmp_scalar_ref = ir->CreateScalarRef(static_cast<IR_ScalarSymbol *>(tmp_sym));
+      
+      std::vector<CG_outputRepr *> rhs_index(n_dim);
+      for (int i = 0; i < index_lb.size(); i++)
+        if (is_index_eq[i])
+          rhs_index[i] = index_lb[i]->clone();
+        else
+          rhs_index[i] = ir->builder()->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+i+1)->name());
+      IR_ArrayRef *copied_array_ref = ir->CreateArrayRef(sym, rhs_index);
+      
+      copy_code_read = ir->builder()->CreateAssignment(0, tmp_scalar_ref->convert(), copied_array_ref->convert());
+    }
+    else {
+      std::vector<CG_outputRepr *> lhs_index(index_sz.size());
+      for (int i = 0; i < index_sz.size(); i++) {
+        int cur_index_num = index_sz[i].first;
+        CG_outputRepr *cur_index_repr = ocg->CreateMinus(ocg->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+cur_index_num+1)->name()), index_lb[cur_index_num]->clone());
+        if (padding_stride != 0) {
+          if (i == n_dim-1) {
+            coef_t g = gcd(index_stride[cur_index_num], static_cast<coef_t>(padding_stride));
+            coef_t t1 = index_stride[cur_index_num] / g;
+            if (t1 != 1)
+              cur_index_repr = ocg->CreateIntegerFloor(cur_index_repr, ocg->CreateInt(t1));
+            coef_t t2 = padding_stride / g;
+            if (t2 != 1)
+              cur_index_repr = ocg->CreateTimes(cur_index_repr, ocg->CreateInt(t2));
+          }
+          else if (index_stride[cur_index_num] != 1) {
+            cur_index_repr = ocg->CreateIntegerFloor(cur_index_repr, ocg->CreateInt(index_stride[cur_index_num]));
+          }
+        }
+        
+        if (ir->ArrayIndexStartAt() != 0)
+          cur_index_repr = ocg->CreatePlus(cur_index_repr, ocg->CreateInt(ir->ArrayIndexStartAt()));
+        lhs_index[i] = cur_index_repr;
+      }
+      
+      IR_ArrayRef *tmp_array_ref = ir->CreateArrayRef(static_cast<IR_ArraySymbol *>(tmp_sym), lhs_index);
+      
+      std::vector<CG_outputRepr *> rhs_index(n_dim);
+      for (int i = 0; i < index_lb.size(); i++)
+        if (is_index_eq[i])
+          rhs_index[i] = index_lb[i]->clone();
+        else
+          rhs_index[i] = ir->builder()->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+i+1)->name());
+      IR_ArrayRef *copied_array_ref = ir->CreateArrayRef(sym, rhs_index);
+      
+      copy_code_read = ir->builder()->CreateAssignment(0, tmp_array_ref->convert(), copied_array_ref->convert());
+    }
+  
+  // create temporary array write back code
+  CG_outputRepr *copy_code_write;
+  if (has_write_refs)
+    if (index_sz.size() == 0) {
+      IR_ScalarRef *tmp_scalar_ref = ir->CreateScalarRef(static_cast<IR_ScalarSymbol *>(tmp_sym));
+      
+      std::vector<CG_outputRepr *> rhs_index(n_dim);
+      for (int i = 0; i < index_lb.size(); i++)
+        if (is_index_eq[i])
+          rhs_index[i] = index_lb[i]->clone();
+        else
+          rhs_index[i] = ir->builder()->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+i+1)->name());
+      IR_ArrayRef *copied_array_ref = ir->CreateArrayRef(sym, rhs_index);
+      
+      copy_code_write = ir->builder()->CreateAssignment(0, copied_array_ref->convert(), tmp_scalar_ref->convert());
+    }
+    else {
+      std::vector<CG_outputRepr *> lhs_index(n_dim);
+      for (int i = 0; i < index_lb.size(); i++)
+        if (is_index_eq[i])
+          lhs_index[i] = index_lb[i]->clone();
+        else
+          lhs_index[i] = ir->builder()->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+i+1)->name());
+      IR_ArrayRef *copied_array_ref = ir->CreateArrayRef(sym, lhs_index);
+      
+      std::vector<CG_outputRepr *> rhs_index(index_sz.size());
+      for (int i = 0; i < index_sz.size(); i++) {
+        int cur_index_num = index_sz[i].first;
+        CG_outputRepr *cur_index_repr = ocg->CreateMinus(ocg->CreateIdent(copy_is.set_var(level-1+privatized_levels.size()+cur_index_num+1)->name()), index_lb[cur_index_num]->clone());
+        if (padding_stride != 0) {
+          if (i == n_dim-1) {
+            coef_t g = gcd(index_stride[cur_index_num], static_cast<coef_t>(padding_stride));
+            coef_t t1 = index_stride[cur_index_num] / g;
+            if (t1 != 1)
+              cur_index_repr = ocg->CreateIntegerFloor(cur_index_repr, ocg->CreateInt(t1));
+            coef_t t2 = padding_stride / g;
+            if (t2 != 1)
+              cur_index_repr = ocg->CreateTimes(cur_index_repr, ocg->CreateInt(t2));
+          }
+          else if (index_stride[cur_index_num] != 1) {
+            cur_index_repr = ocg->CreateIntegerFloor(cur_index_repr, ocg->CreateInt(index_stride[cur_index_num]));
+          }
+        }
+        
+        if (ir->ArrayIndexStartAt() != 0)
+          cur_index_repr = ocg->CreatePlus(cur_index_repr, ocg->CreateInt(ir->ArrayIndexStartAt()));
+        rhs_index[i] = cur_index_repr;
+      }
+      IR_ArrayRef *tmp_array_ref = ir->CreateArrayRef(static_cast<IR_ArraySymbol *>(tmp_sym), rhs_index);
+      
+      copy_code_write = ir->builder()->CreateAssignment(0, copied_array_ref->convert(), tmp_array_ref->convert());
+    }
+  
+  // now we can remove those loops for array indexes that are
+  // dependent on others
+  if (!(index_sz.size() == n_dim && (sym->layout_type() == IR_ARRAY_LAYOUT_ROW_MAJOR || n_dim <= 1))) {
+    Relation mapping(level-1+privatized_levels.size()+n_dim, level-1+privatized_levels.size()+index_sz.size());
+    F_And *f_root = mapping.add_and();
+    for (int i = 1; i <= level-1+privatized_levels.size(); i++) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(mapping.input_var(i), 1);
+      h.update_coef(mapping.output_var(i), -1);
+    }
+    
+    int cur_index = 0;
+    std::vector<int> mapped_index(index_sz.size());
+    for (int i = 0; i < n_dim; i++)
+      if (!is_index_eq[i]) {
+        EQ_Handle h = f_root->add_EQ();
+        h.update_coef(mapping.input_var(level-1+privatized_levels.size()+i+1), 1);
+        switch (sym->layout_type()) {
+        case IR_ARRAY_LAYOUT_COLUMN_MAJOR: {
+          h.update_coef(mapping.output_var(level-1+privatized_levels.size()+index_sz.size()-cur_index), -1);
+          mapped_index[index_sz.size()-cur_index-1] = i;
+          break;
+        }
+        case IR_ARRAY_LAYOUT_ROW_MAJOR: {
+          h.update_coef(mapping.output_var(level-1+privatized_levels.size()+cur_index+1), -1);
+          mapped_index[cur_index] = i;
+          break;
+        }
+        default:
+          throw loop_error("unsupported array layout");
+        }
+        cur_index++;
+      }
+    
+    wo_copy_is = Range(Restrict_Domain(copy(mapping), wo_copy_is));
+    ro_copy_is = Range(Restrict_Domain(copy(mapping), ro_copy_is));
+    for (int i = 1; i <= level-1+privatized_levels.size(); i++) {
+      wo_copy_is.name_set_var(i, copy_is.set_var(i)->name());
+      ro_copy_is.name_set_var(i, copy_is.set_var(i)->name());
+    }
+    for (int i = 0; i < index_sz.size(); i++) {
+      wo_copy_is.name_set_var(level-1+privatized_levels.size()+i+1, copy_is.set_var(level-1+privatized_levels.size()+mapped_index[i]+1)->name());
+      ro_copy_is.name_set_var(level-1+privatized_levels.size()+i+1, copy_is.set_var(level-1+privatized_levels.size()+mapped_index[i]+1)->name());
+    }
+    wo_copy_is.setup_names();
+    ro_copy_is.setup_names();
+  }
+  
+  // insert read copy statement
+  int old_num_stmt = stmt.size();
+  int ro_copy_stmt_num = -1;
+  if (has_read_refs) {
+    Relation copy_xform(ro_copy_is.n_set(), 2*ro_copy_is.n_set()+1);
+    {
+      F_And *f_root = copy_xform.add_and();
+      for (int i = 1; i <= ro_copy_is.n_set(); i++) {
+        EQ_Handle h = f_root->add_EQ();
+        h.update_coef(copy_xform.input_var(i), 1);
+        h.update_coef(copy_xform.output_var(2*i), -1);
+      }
+      for (int i = 1; i <= dim; i+=2) {
+        EQ_Handle h = f_root->add_EQ();
+        h.update_coef(copy_xform.output_var(i), -1);
+        h.update_const(lex[i-1]);
+      }
+      for (int i = dim+2; i <= copy_xform.n_out(); i+=2) {
+        EQ_Handle h = f_root->add_EQ();
+        h.update_coef(copy_xform.output_var(i), 1);
+      }
+    }
+    
+    Statement copy_stmt_read;
+    copy_stmt_read.IS = ro_copy_is;
+    copy_stmt_read.xform = copy_xform;
+    copy_stmt_read.code = copy_code_read;
+    copy_stmt_read.loop_level = std::vector<LoopLevel>(ro_copy_is.n_set());
+    copy_stmt_read.ir_stmt_node = NULL;
+    for (int i = 0; i < level-1; i++) {
+      copy_stmt_read.loop_level[i].type = stmt[*(active.begin())].loop_level[i].type;
+      if (stmt[*(active.begin())].loop_level[i].type == LoopLevelTile &&
+          stmt[*(active.begin())].loop_level[i].payload >= level) {
+        int j;
+        for (j = 0; j < privatized_levels.size(); j++)
+          if (privatized_levels[j] == stmt[*(active.begin())].loop_level[i].payload)
+            break;
+        if (j == privatized_levels.size())
+          copy_stmt_read.loop_level[i].payload = -1;
+        else
+          copy_stmt_read.loop_level[i].payload = level + j;
+      }
+      else
+        copy_stmt_read.loop_level[i].payload = stmt[*(active.begin())].loop_level[i].payload;
+      copy_stmt_read.loop_level[i].parallel_level = stmt[*(active.begin())].loop_level[i].parallel_level;
+    }
+    for (int i = 0; i < privatized_levels.size(); i++) {
+      copy_stmt_read.loop_level[level-1+i].type = stmt[*(active.begin())].loop_level[privatized_levels[i]].type;
+      copy_stmt_read.loop_level[level-1+i].payload = stmt[*(active.begin())].loop_level[privatized_levels[i]].payload;
+      copy_stmt_read.loop_level[level-1+i].parallel_level = stmt[*(active.begin())].loop_level[privatized_levels[i]].parallel_level;
+    }
+    int left_num_dim = num_dep_dim - (get_last_dep_dim_before(*(active.begin()), level) + 1);
+    for (int i = 0; i < min(left_num_dim, static_cast<int>(index_sz.size())); i++) {
+      copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].type = LoopLevelOriginal;
+      copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].payload = num_dep_dim-left_num_dim+i;
+      copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].parallel_level = 0;
+    }
+    for (int i = min(left_num_dim, static_cast<int>(index_sz.size())); i < index_sz.size(); i++) {
+      copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].type = LoopLevelUnknown;
+      copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].payload = -1;
+      copy_stmt_read.loop_level[level-1+privatized_levels.size()+i].parallel_level = 0;
+    }
+    
+    
+    shiftLexicalOrder(lex, dim-1, 1);
+    stmt.push_back(copy_stmt_read);
+    ro_copy_stmt_num = stmt.size() - 1;
+    dep.insert();
+  }
+  
+  // insert write copy statement
+  int wo_copy_stmt_num = -1;
+  if (has_write_refs) {
+    Relation copy_xform(wo_copy_is.n_set(), 2*wo_copy_is.n_set()+1);
+    {
+      F_And *f_root = copy_xform.add_and();
+      for (int i = 1; i <= wo_copy_is.n_set(); i++) {
+        EQ_Handle h = f_root->add_EQ();
+        h.update_coef(copy_xform.input_var(i), 1);
+        h.update_coef(copy_xform.output_var(2*i), -1);
+      }
+      for (int i = 1; i <= dim; i+=2) {
+        EQ_Handle h = f_root->add_EQ();
+        h.update_coef(copy_xform.output_var(i), -1);
+        h.update_const(lex[i-1]);
+      }
+      for (int i = dim+2; i <= copy_xform.n_out(); i+=2) {
+        EQ_Handle h = f_root->add_EQ();
+        h.update_coef(copy_xform.output_var(i), 1);
+      }
+    }
+    
+    Statement copy_stmt_write;
+    copy_stmt_write.IS = wo_copy_is;
+    copy_stmt_write.xform = copy_xform;
+    copy_stmt_write.code = copy_code_write;
+    copy_stmt_write.loop_level = std::vector<LoopLevel>(wo_copy_is.n_set());
+    copy_stmt_write.ir_stmt_node = NULL;
+    
+    for (int i = 0; i < level-1; i++) {
+      copy_stmt_write.loop_level[i].type = stmt[*(active.begin())].loop_level[i].type;
+      if (stmt[*(active.begin())].loop_level[i].type == LoopLevelTile &&
+          stmt[*(active.begin())].loop_level[i].payload >= level) {
+        int j;
+        for (j = 0; j < privatized_levels.size(); j++)
+          if (privatized_levels[j] == stmt[*(active.begin())].loop_level[i].payload)
+            break;
+        if (j == privatized_levels.size())
+          copy_stmt_write.loop_level[i].payload = -1;
+        else
+          copy_stmt_write.loop_level[i].payload = level + j;
+      }
+      else
+        copy_stmt_write.loop_level[i].payload = stmt[*(active.begin())].loop_level[i].payload;
+      copy_stmt_write.loop_level[i].parallel_level = stmt[*(active.begin())].loop_level[i].parallel_level;
+    }
+    for (int i = 0; i < privatized_levels.size(); i++) {
+      copy_stmt_write.loop_level[level-1+i].type = stmt[*(active.begin())].loop_level[privatized_levels[i]].type;
+      copy_stmt_write.loop_level[level-1+i].payload = stmt[*(active.begin())].loop_level[privatized_levels[i]].payload;
+      copy_stmt_write.loop_level[level-1+i].parallel_level = stmt[*(active.begin())].loop_level[privatized_levels[i]].parallel_level;
+    }
+    int left_num_dim = num_dep_dim - (get_last_dep_dim_before(*(active.begin()), level) + 1);
+    for (int i = 0; i < min(left_num_dim, static_cast<int>(index_sz.size())); i++) {
+      copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].type = LoopLevelOriginal;
+      copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].payload = num_dep_dim-left_num_dim+i;
+      copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].parallel_level = 0;
+    }
+    for (int i = min(left_num_dim, static_cast<int>(index_sz.size())); i < index_sz.size(); i++) {
+      copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].type = LoopLevelUnknown;
+      copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].payload = -1;
+      copy_stmt_write.loop_level[level-1+privatized_levels.size()+i].parallel_level = 0;
+    }
+    lex[dim-1]++;
+    shiftLexicalOrder(lex, dim-1, -2);
+    stmt.push_back(copy_stmt_write);
+    wo_copy_stmt_num = stmt.size() - 1;
+    dep.insert();
+  }
+  
+  // replace original array accesses with temporary array accesses
+  for (int i =0; i < stmt_refs.size(); i++)
+    for (int j = 0; j < stmt_refs[i].second.size(); j++) {
+      if (index_sz.size() == 0) {
+        IR_ScalarRef *tmp_scalar_ref = ir->CreateScalarRef(static_cast<IR_ScalarSymbol *>(tmp_sym));
+        ir->ReplaceExpression(stmt_refs[i].second[j], tmp_scalar_ref->convert());
+      }
+      else {
+        std::vector<CG_outputRepr *> index_repr(index_sz.size());
+        for (int k = 0; k < index_sz.size(); k++) {
+          int cur_index_num = index_sz[k].first;
+          
+          CG_outputRepr *cur_index_repr = ocg->CreateMinus(stmt_refs[i].second[j]->index(cur_index_num), index_lb[cur_index_num]->clone());
+          if (padding_stride != 0) {
+            if (k == n_dim-1) {
+              coef_t g = gcd(index_stride[cur_index_num], static_cast<coef_t>(padding_stride));
+              coef_t t1 = index_stride[cur_index_num] / g;
+              if (t1 != 1)
+                cur_index_repr = ocg->CreateIntegerFloor(cur_index_repr, ocg->CreateInt(t1));
+              coef_t t2 = padding_stride / g;
+              if (t2 != 1)
+                cur_index_repr = ocg->CreateTimes(cur_index_repr, ocg->CreateInt(t2));
+            }
+            else if (index_stride[cur_index_num] != 1) {
+              cur_index_repr = ocg->CreateIntegerFloor(cur_index_repr, ocg->CreateInt(index_stride[cur_index_num]));
+            }
+          }
+          
+          if (ir->ArrayIndexStartAt() != 0)
+            cur_index_repr = ocg->CreatePlus(cur_index_repr, ocg->CreateInt(ir->ArrayIndexStartAt()));
+          index_repr[k] = cur_index_repr;
+        }
+        
+        IR_ArrayRef *tmp_array_ref = ir->CreateArrayRef(static_cast<IR_ArraySymbol *>(tmp_sym), index_repr);
+        ir->ReplaceExpression(stmt_refs[i].second[j], tmp_array_ref->convert());
+      }
+    }
+  
+  // update dependence graph
+  int dep_dim = get_last_dep_dim_before(*(active.begin()), level) + 1;
+  if (ro_copy_stmt_num != -1) {
+    for (int i = 0; i < old_num_stmt; i++) {
+      std::vector<std::vector<DependenceVector> > D;
+      
+      for (DependenceGraph::EdgeList::iterator j = dep.vertex[i].second.begin(); j != dep.vertex[i].second.end();) {
+        if (active.find(i) != active.end() && active.find(j->first) == active.end()) {
+          std::vector<DependenceVector> dvs1, dvs2;
+          for (int k = 0; k < j->second.size(); k++) {
+            DependenceVector dv = j->second[k];
+            if (dv.sym != NULL && dv.sym->name() == sym->name() && (dv.type == DEP_R2R || dv.type == DEP_R2W))
+              dvs1.push_back(dv);
+            else
+              dvs2.push_back(dv);
+          }
+          j->second = dvs2;
+          if (dvs1.size() > 0)
+            dep.connect(ro_copy_stmt_num, j->first, dvs1);
+        }
+        else if (active.find(i) == active.end() && active.find(j->first) != active.end()) {
+          std::vector<DependenceVector> dvs1, dvs2;
+          for (int k = 0; k < j->second.size(); k++) {
+            DependenceVector dv = j->second[k];
+            if (dv.sym != NULL && dv.sym->name() == sym->name() && (dv.type == DEP_R2R || dv.type == DEP_W2R))
+              dvs1.push_back(dv);
+            else
+              dvs2.push_back(dv);
+          }
+          j->second = dvs2;
+          if (dvs1.size() > 0)
+            D.push_back(dvs1);
+        }
+        
+        if (j->second.size() == 0)
+          dep.vertex[i].second.erase(j++);
+        else
+          j++;
+      }
+      
+      for (int j = 0; j < D.size(); j++)
+        dep.connect(i, ro_copy_stmt_num, D[j]);
+    }
+    
+    // insert dependences from copy statement loop to copied statements
+    DependenceVector dv;
+    dv.type = DEP_W2R;
+    dv.sym = tmp_sym->clone();
+    dv.lbounds = std::vector<coef_t>(dep.num_dim(), 0);
+    dv.ubounds = std::vector<coef_t>(dep.num_dim(), 0);
+    for (int i = dep_dim; i < dep.num_dim(); i++) {
+      dv.lbounds[i] = -posInfinity;
+      dv.ubounds[i] = posInfinity;
+    }
+    for (std::set<int>::iterator i = active.begin(); i != active.end(); i++)
+      dep.connect(ro_copy_stmt_num, *i, dv);
+  }
+  
+  if (wo_copy_stmt_num != -1) {
+    for (int i = 0; i < old_num_stmt; i++) {
+      std::vector<std::vector<DependenceVector> > D;
+      
+      for (DependenceGraph::EdgeList::iterator j = dep.vertex[i].second.begin(); j != dep.vertex[i].second.end();) {
+        if (active.find(i) != active.end() && active.find(j->first) == active.end()) {
+          std::vector<DependenceVector> dvs1, dvs2;
+          for (int k = 0; k < j->second.size(); k++) {
+            DependenceVector dv = j->second[k];
+            if (dv.sym != NULL && dv.sym->name() == sym->name() && (dv.type == DEP_W2R || dv.type == DEP_W2W))
+              dvs1.push_back(dv);
+            else
+              dvs2.push_back(dv);
+          }
+          j->second = dvs2;
+          if (dvs1.size() > 0)
+            dep.connect(wo_copy_stmt_num, j->first, dvs1);
+        }
+        else if (active.find(i) == active.end() && active.find(j->first) != active.end()) {
+          std::vector<DependenceVector> dvs1, dvs2;
+          for (int k = 0; k < j->second.size(); k++) {
+            DependenceVector dv = j->second[k];
+            if (dv.sym != NULL && dv.sym->name() == sym->name() && (dv.type == DEP_R2W || dv.type == DEP_W2W))
+              dvs1.push_back(dv);
+            else
+              dvs2.push_back(dv);
+          }
+          j->second = dvs2;
+          if (dvs1.size() > 0)
+            D.push_back(dvs1);
+        }
+        
+        if (j->second.size() == 0)
+          dep.vertex[i].second.erase(j++);
+        else
+          j++;
+      }
+      
+      for (int j = 0; j < D.size(); j++)
+        dep.connect(i, wo_copy_stmt_num, D[j]);
+    }
+    
+    // insert dependences from copied statements to write statements
+    DependenceVector dv;
+    dv.type = DEP_W2R;
+    dv.sym = tmp_sym->clone();
+    dv.lbounds = std::vector<coef_t>(dep.num_dim(), 0);
+    dv.ubounds = std::vector<coef_t>(dep.num_dim(), 0);
+    for (int i = dep_dim; i < dep.num_dim(); i++) {
+      dv.lbounds[i] = -posInfinity;
+      dv.ubounds[i] = posInfinity;
+    }
+    for (std::set<int>::iterator i = active.begin(); i != active.end(); i++)
+      dep.connect(*i, wo_copy_stmt_num, dv);
+    
+  }
+  
+  // update variable name for dependences among copied statements
+  for (int i = 0; i < old_num_stmt; i++) {
+    if (active.find(i) != active.end())
+      for (DependenceGraph::EdgeList::iterator j = dep.vertex[i].second.begin(); j != dep.vertex[i].second.end(); j++)
+        if (active.find(j->first) != active.end())
+          for (int k = 0; k < j->second.size(); k++) {
+            IR_Symbol *s = tmp_sym->clone();
+            j->second[k].sym = s;
+          }
+  }
+  
+  // insert anti-dependence from write statement to read statement
+  if (ro_copy_stmt_num != -1 && wo_copy_stmt_num != -1)
+    if (dep_dim >= 0) {
+      DependenceVector dv;
+      dv.type = DEP_R2W;
+      dv.sym = tmp_sym->clone();
+      dv.lbounds = std::vector<coef_t>(dep.num_dim(), 0);
+      dv.ubounds = std::vector<coef_t>(dep.num_dim(), 0);
+      for (int k = dep_dim; k < dep.num_dim(); k++) {
+        dv.lbounds[k] = -posInfinity;
+        dv.ubounds[k] = posInfinity;
+      }
+      for (int k = 0; k < dep_dim; k++) {
+        if (k != 0) {
+          dv.lbounds[k-1] = 0;
+          dv.ubounds[k-1] = 0;
+        }
+        dv.lbounds[k] = 1;
+        dv.ubounds[k] = posInfinity;
+        dep.connect(wo_copy_stmt_num, ro_copy_stmt_num, dv);
+      }
+    }
+  
+  // cleanup
+  delete sym;
+  delete tmp_sym;
+  for (int i = 0; i < index_lb.size(); i++) {
+    index_lb[i]->clear();
+    delete index_lb[i];
+  }
+  for (int i = 0; i < index_sz.size(); i++) {
+    index_sz[i].second->clear();
+    delete index_sz[i].second;
+  }
+  
+  return true;
+}
diff --git a/src/loop_extra.cc b/src/loop_extra.cc
new file mode 100644
index 0000000..dac05bf
--- /dev/null
+++ b/src/loop_extra.cc
@@ -0,0 +1,224 @@
+/*****************************************************************************
+ Copyright (C) 2010 University of Utah
+ All Rights Reserved.
+
+ Purpose:
+   Additional loop transformations.
+
+ Notes:
+
+ History:
+   07/31/10 Created by Chun Chen
+*****************************************************************************/
+
+#include <code_gen/codegen.h>
+#include <code_gen/CG_utils.h>
+#include "loop.hh"
+#include "omegatools.hh"
+#include "ir_code.hh"
+#include "chill_error.hh"
+
+using namespace omega;
+
+
+void Loop::shift_to(int stmt_num, int level, int absolute_position) {
+  // combo
+  tile(stmt_num, level, 1, level, CountedTile);
+  std::vector<int> lex = getLexicalOrder(stmt_num);
+  std::set<int> active = getStatements(lex, 2*level-2);
+  shift(active, level, absolute_position);
+  
+  // remove unnecessary tiled loop since tile size is one
+  for (std::set<int>::iterator i = active.begin(); i != active.end(); i++) {
+    int n = stmt[*i].xform.n_out();
+    Relation mapping(n, n-2);
+    F_And *f_root = mapping.add_and();
+    for (int j = 1; j <= 2*level; j++) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(mapping.output_var(j), 1);
+      h.update_coef(mapping.input_var(j), -1);
+    }
+    for (int j = 2*level+3; j <= n; j++) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(mapping.output_var(j-2), 1);
+      h.update_coef(mapping.input_var(j), -1);
+    }
+    stmt[*i].xform = Composition(mapping, stmt[*i].xform);
+    stmt[*i].xform.simplify();
+    
+    for (int j = 0; j < stmt[*i].loop_level.size(); j++)
+      if (j != level-1 &&
+          stmt[*i].loop_level[j].type == LoopLevelTile &&
+          stmt[*i].loop_level[j].payload >= level)
+        stmt[*i].loop_level[j].payload--;
+    
+    stmt[*i].loop_level.erase(stmt[*i].loop_level.begin()+level-1);
+  }
+}
+
+
+std::set<int> Loop::unroll_extra(int stmt_num, int level, int unroll_amount, int cleanup_split_level) {
+  std::set<int> cleanup_stmts = unroll(stmt_num, level, unroll_amount,std::vector< std::vector<std::string> >(), cleanup_split_level);
+  for (std::set<int>::iterator i = cleanup_stmts.begin(); i != cleanup_stmts.end(); i++)
+    unroll(*i, level, 0);
+  
+  return cleanup_stmts;
+}
+
+void Loop::peel(int stmt_num, int level, int peel_amount) {
+  // check for sanity of parameters
+  if (stmt_num < 0 || stmt_num >= stmt.size())
+    throw std::invalid_argument("invalid statement number " + to_string(stmt_num));
+  if (level <= 0 || level > stmt[stmt_num].loop_level.size())
+    throw std::invalid_argument("invalid loop level " + to_string(level));
+  
+  if (peel_amount == 0)
+    return;
+  
+  std::set<int> subloop = getSubLoopNest(stmt_num, level);
+  std::vector<Relation> Rs;
+  for (std::set<int>::iterator i = subloop.begin(); i != subloop.end(); i++) {
+    Relation r = getNewIS(*i);
+    Relation f(r.n_set(), level);
+    F_And *f_root = f.add_and();
+    for (int j = 1; j <= level; j++) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(f.input_var(2*j), 1);
+      h.update_coef(f.output_var(j), -1);
+    }
+    r = Composition(f, r);
+    r.simplify();
+    Rs.push_back(r);
+  }
+  Relation hull = SimpleHull(Rs);
+  
+  if (peel_amount > 0) {
+    GEQ_Handle bound_eq;
+    bool found_bound = false;
+    for (GEQ_Iterator e(hull.single_conjunct()->GEQs()); e; e++)
+      if (!(*e).has_wildcards() && (*e).get_coef(hull.set_var(level)) > 0) {
+        bound_eq = *e;
+        found_bound = true;
+        break;
+      }
+    if (!found_bound)
+      for (GEQ_Iterator e(hull.single_conjunct()->GEQs()); e; e++)
+        if ((*e).has_wildcards() && (*e).get_coef(hull.set_var(level)) > 0) {
+          bool is_bound = true;
+          for (Constr_Vars_Iter cvi(*e, true); cvi; cvi++) {
+            std::pair<bool, GEQ_Handle> result = find_floor_definition(hull, cvi.curr_var());
+            if (!result.first) {
+              is_bound = false;
+              break;
+            }
+          }
+          if (is_bound) {
+            bound_eq = *e;
+            found_bound = true;
+            break;
+          }
+        }
+    if (!found_bound)
+      throw loop_error("can't find lower bound for peeling at loop level " + to_string(level));
+    
+    for (int i = 1; i <= peel_amount; i++) {
+      Relation r(level);
+      F_Exists *f_exists = r.add_and()->add_exists();
+      F_And *f_root = f_exists->add_and();
+      GEQ_Handle h = f_root->add_GEQ();
+      std::map<Variable_ID, Variable_ID> exists_mapping;
+      for (Constr_Vars_Iter cvi(bound_eq); cvi; cvi++)
+        switch (cvi.curr_var()->kind()) {
+        case Input_Var:
+          h.update_coef(r.set_var(cvi.curr_var()->get_position()), cvi.curr_coef());
+          break;
+        case Wildcard_Var: {
+          Variable_ID v = replicate_floor_definition(hull, cvi.curr_var(), r, f_exists, f_root, exists_mapping);
+          h.update_coef(v, 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(bound_eq.get_const() - i);
+      r.simplify();
+      
+      split(stmt_num, level, r);
+    }
+  }
+  else { // peel_amount < 0
+    GEQ_Handle bound_eq;
+    bool found_bound = false;
+    for (GEQ_Iterator e(hull.single_conjunct()->GEQs()); e; e++)
+      if (!(*e).has_wildcards() && (*e).get_coef(hull.set_var(level)) < 0) {
+        bound_eq = *e;
+        found_bound = true;
+        break;
+      }
+    if (!found_bound)
+      for (GEQ_Iterator e(hull.single_conjunct()->GEQs()); e; e++)
+        if ((*e).has_wildcards() && (*e).get_coef(hull.set_var(level)) < 0) {
+          bool is_bound = true;
+          for (Constr_Vars_Iter cvi(*e, true); cvi; cvi++) {
+            std::pair<bool, GEQ_Handle> result = find_floor_definition(hull, cvi.curr_var());
+            if (!result.first) {
+              is_bound = false;
+              break;
+            }
+          }
+          if (is_bound) {
+            bound_eq = *e;
+            found_bound = true;
+            break;
+          }
+        }
+    if (!found_bound)
+      throw loop_error("can't find upper bound for peeling at loop level " + to_string(level));
+    
+    for (int i = 1; i <= -peel_amount; i++) {
+      Relation r(level);
+      F_Exists *f_exists = r.add_and()->add_exists();
+      F_And *f_root = f_exists->add_and();
+      GEQ_Handle h = f_root->add_GEQ();
+      std::map<Variable_ID, Variable_ID> exists_mapping;
+      for (Constr_Vars_Iter cvi(bound_eq); cvi; cvi++)
+        switch (cvi.curr_var()->kind()) {
+        case Input_Var:
+          h.update_coef(r.set_var(cvi.curr_var()->get_position()), cvi.curr_coef());
+          break;
+        case Wildcard_Var: {
+          Variable_ID v = replicate_floor_definition(hull, cvi.curr_var(), r, f_exists, f_root, exists_mapping);
+          h.update_coef(v, 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(bound_eq.get_const() - i);
+      r.simplify();
+      
+      split(stmt_num, level, r);
+    }
+  }
+}
+
diff --git a/src/loop_tile.cc b/src/loop_tile.cc
new file mode 100644
index 0000000..aae8dd8
--- /dev/null
+++ b/src/loop_tile.cc
@@ -0,0 +1,630 @@
+/*
+ * loop_tile.cc
+ *
+ *  Created on: Nov 12, 2012
+ *      Author: anand
+ */
+
+#include <code_gen/codegen.h>
+#include "loop.hh"
+#include "omegatools.hh"
+#include "ir_code.hh"
+#include "chill_error.hh"
+
+using namespace omega;
+
+
+
+
+void Loop::tile(int stmt_num, int level, int tile_size, int outer_level,
+                TilingMethodType method, int alignment_offset, int alignment_multiple) {
+  // check for sanity of parameters
+  if (tile_size < 0)
+    throw std::invalid_argument("invalid tile size");
+  if (alignment_multiple < 1 || alignment_offset < 0)
+    throw std::invalid_argument("invalid alignment for tile");
+  if (stmt_num < 0 || stmt_num >= stmt.size())
+    throw std::invalid_argument("invalid statement " + to_string(stmt_num));
+  if (level <= 0)
+    throw std::invalid_argument("invalid loop level " + to_string(level));
+  if (level > stmt[stmt_num].loop_level.size())
+    throw std::invalid_argument(
+      "there is no loop level " + to_string(level) + " for statement "
+      + to_string(stmt_num));
+  if (outer_level <= 0 || outer_level > level)
+    throw std::invalid_argument(
+      "invalid tile controlling loop level "
+      + to_string(outer_level));
+  
+  // invalidate saved codegen computation
+  delete last_compute_cgr_;
+  last_compute_cgr_ = NULL;
+  delete last_compute_cg_;
+  last_compute_cg_ = NULL;
+  
+  int dim = 2 * level - 1;
+  int outer_dim = 2 * outer_level - 1;
+  std::vector<int> lex = getLexicalOrder(stmt_num);
+  std::set<int> same_tiled_loop = getStatements(lex, dim - 1);
+  std::set<int> same_tile_controlling_loop = getStatements(lex,
+                                                           outer_dim - 1);
+  
+  for (std::set<int>::iterator i = same_tiled_loop.begin();
+       i != same_tiled_loop.end(); i++) {
+    for (DependenceGraph::EdgeList::iterator j =
+           dep.vertex[*i].second.begin(); j != dep.vertex[*i].second.end();
+         j++) {
+      if (same_tiled_loop.find(j->first) != same_tiled_loop.end())
+        for (int k = 0; k < j->second.size(); k++) {
+          DependenceVector dv = j->second[k];
+          int dim2 = level - 1;
+          if ((dv.type != DEP_CONTROL) && (dv.type != DEP_UNKNOWN)) {
+            while (stmt[*i].loop_level[dim2].type == LoopLevelTile) {
+              dim2 = stmt[*i].loop_level[dim2].payload - 1;
+            }
+            dim2 = stmt[*i].loop_level[dim2].payload;
+            
+            if (dv.hasNegative(dim2) && (!dv.quasi)) {
+              for (int l = outer_level; l < level; l++)
+                if (stmt[*i].loop_level[l - 1].type
+                    != LoopLevelTile) {
+                  if (dv.isCarried(
+                        stmt[*i].loop_level[l - 1].payload)
+                      && dv.hasPositive(
+                        stmt[*i].loop_level[l - 1].payload))
+                    throw loop_error(
+                      "loop error: Tiling is illegal, dependence violation!");
+                } else {
+                  
+                  int dim3 = l - 1;
+                  while (stmt[*i].loop_level[l - 1].type
+                         != LoopLevelTile) {
+                    dim3 =
+                      stmt[*i].loop_level[l - 1].payload
+                      - 1;
+                    
+                  }
+                  
+                  dim3 = stmt[*i].loop_level[l - 1].payload;
+                  if (dim3 < level - 1)
+                    if (dv.isCarried(dim3)
+                        && dv.hasPositive(dim3))
+                      throw loop_error(
+                        "loop error: Tiling is illegal, dependence violation!");
+                }
+            }
+          }
+        }
+    }
+  }
+  // special case for no tiling
+  if (tile_size == 0) {
+    for (std::set<int>::iterator i = same_tile_controlling_loop.begin();
+         i != same_tile_controlling_loop.end(); i++) {
+      Relation r(stmt[*i].xform.n_out(), stmt[*i].xform.n_out() + 2);
+      F_And *f_root = r.add_and();
+      for (int j = 1; j <= 2 * outer_level - 1; j++) {
+        EQ_Handle h = f_root->add_EQ();
+        h.update_coef(r.input_var(j), 1);
+        h.update_coef(r.output_var(j), -1);
+      }
+      EQ_Handle h1 = f_root->add_EQ();
+      h1.update_coef(r.output_var(2 * outer_level), 1);
+      EQ_Handle h2 = f_root->add_EQ();
+      h2.update_coef(r.output_var(2 * outer_level + 1), 1);
+      for (int j = 2 * outer_level; j <= stmt[*i].xform.n_out(); j++) {
+        EQ_Handle h = f_root->add_EQ();
+        h.update_coef(r.input_var(j), 1);
+        h.update_coef(r.output_var(j + 2), -1);
+      }
+      
+      stmt[*i].xform = Composition(copy(r), stmt[*i].xform);
+    }
+  }
+  // normal tiling
+  else {
+    std::set<int> private_stmt;
+    for (std::set<int>::iterator i = same_tile_controlling_loop.begin();
+         i != same_tile_controlling_loop.end(); i++) {
+//     if (same_tiled_loop.find(*i) == same_tiled_loop.end() && !is_single_iteration(getNewIS(*i), dim))
+//       same_tiled_loop.insert(*i);
+      
+      // should test dim's value directly but it is ok for now
+//    if (same_tiled_loop.find(*i) == same_tiled_loop.end() && get_const(stmt[*i].xform, dim+1, Output_Var) == posInfinity)
+      if (same_tiled_loop.find(*i) == same_tiled_loop.end()
+          && overflow.find(*i) != overflow.end())
+        private_stmt.insert(*i);
+    }
+    
+    // extract the union of the iteration space to be considered
+    Relation hull;
+    /*{
+      Tuple < Relation > r_list;
+      Tuple<int> r_mask;
+      
+      for (std::set<int>::iterator i = same_tile_controlling_loop.begin();
+      i != same_tile_controlling_loop.end(); i++)
+      if (private_stmt.find(*i) == private_stmt.end()) {
+      Relation r = project_onto_levels(getNewIS(*i), dim + 1,
+      true);
+      for (int j = outer_dim; j < dim; j++)
+      r = Project(r, j + 1, Set_Var);
+      for (int j = 0; j < outer_dim; j += 2)
+      r = Project(r, j + 1, Set_Var);
+      r_list.append(r);
+      r_mask.append(1);
+      }
+      
+      hull = Hull(r_list, r_mask, 1, true);
+      }*/
+    
+    {
+      std::vector<Relation> r_list;
+      
+      for (std::set<int>::iterator i = same_tile_controlling_loop.begin();
+           i != same_tile_controlling_loop.end(); i++)
+        if (private_stmt.find(*i) == private_stmt.end()) {
+          Relation r = getNewIS(*i);
+          for (int j = dim + 2; j <= r.n_set(); j++)
+            r = Project(r, r.set_var(j));
+          for (int j = outer_dim; j < dim; j++)
+            r = Project(r, j + 1, Set_Var);
+          for (int j = 0; j < outer_dim; j += 2)
+            r = Project(r, j + 1, Set_Var);
+          r.simplify(2, 4);
+          r_list.push_back(r);
+        }
+      
+      hull = SimpleHull(r_list);
+      // hull = Hull(r_list, std::vector<bool>(r_list.size(), true), 1, true);
+    }
+    
+    // extract the bound of the dimension to be tiled
+    Relation bound = get_loop_bound(hull, dim);
+    if (!bound.has_single_conjunct()) {
+      // further simplify the bound
+      hull = Approximate(hull);
+      bound = get_loop_bound(hull, dim);
+      
+      int i = outer_dim - 2;
+      while (!bound.has_single_conjunct() && i >= 0) {
+        hull = Project(hull, i + 1, Set_Var);
+        bound = get_loop_bound(hull, dim);
+        i -= 2;
+      }
+      
+      if (!bound.has_single_conjunct())
+        throw loop_error("cannot handle tile bounds");
+    }
+    
+    // separate lower and upper bounds
+    std::vector<GEQ_Handle> lb_list, ub_list;
+    {
+      Conjunct *c = bound.query_DNF()->single_conjunct();
+      for (GEQ_Iterator gi(c->GEQs()); gi; gi++) {
+        int coef = (*gi).get_coef(bound.set_var(dim + 1));
+        if (coef < 0)
+          ub_list.push_back(*gi);
+        else if (coef > 0)
+          lb_list.push_back(*gi);
+      }
+    }
+    if (lb_list.size() == 0)
+      throw loop_error(
+        "unable to calculate tile controlling loop lower bound");
+    if (ub_list.size() == 0)
+      throw loop_error(
+        "unable to calculate tile controlling loop upper bound");
+    
+    // find the simplest lower bound for StridedTile or simplest iteration count for CountedTile
+    int simplest_lb = 0, simplest_ub = 0;
+    if (method == StridedTile) {
+      int best_cost = INT_MAX;
+      for (int i = 0; i < lb_list.size(); i++) {
+        int cost = 0;
+        for (Constr_Vars_Iter ci(lb_list[i]); ci; ci++) {
+          switch ((*ci).var->kind()) {
+          case Input_Var: {
+            cost += 5;
+            break;
+          }
+          case Global_Var: {
+            cost += 2;
+            break;
+          }
+          default:
+            cost += 15;
+            break;
+          }
+        }
+        
+        if (cost < best_cost) {
+          best_cost = cost;
+          simplest_lb = i;
+        }
+      }
+    } else if (method == CountedTile) {
+      std::map<Variable_ID, coef_t> s1, s2, s3;
+      int best_cost = INT_MAX;
+      for (int i = 0; i < lb_list.size(); i++)
+        for (int j = 0; j < ub_list.size(); j++) {
+          int cost = 0;
+          
+          for (Constr_Vars_Iter ci(lb_list[i]); ci; ci++) {
+            switch ((*ci).var->kind()) {
+            case Input_Var: {
+              s1[(*ci).var] += (*ci).coef;
+              break;
+            }
+            case Global_Var: {
+              s2[(*ci).var] += (*ci).coef;
+              break;
+            }
+            case Exists_Var:
+            case Wildcard_Var: {
+              s3[(*ci).var] += (*ci).coef;
+              break;
+            }
+            default:
+              cost = INT_MAX - 2;
+              break;
+            }
+          }
+          
+          for (Constr_Vars_Iter ci(ub_list[j]); ci; ci++) {
+            switch ((*ci).var->kind()) {
+            case Input_Var: {
+              s1[(*ci).var] += (*ci).coef;
+              break;
+            }
+            case Global_Var: {
+              s2[(*ci).var] += (*ci).coef;
+              break;
+            }
+            case Exists_Var:
+            case Wildcard_Var: {
+              s3[(*ci).var] += (*ci).coef;
+              break;
+            }
+            default:
+              if (cost == INT_MAX - 2)
+                cost = INT_MAX - 1;
+              else
+                cost = INT_MAX - 3;
+              break;
+            }
+          }
+          
+          if (cost == 0) {
+            for (std::map<Variable_ID, coef_t>::iterator k =
+                   s1.begin(); k != s1.end(); k++)
+              if ((*k).second != 0)
+                cost += 5;
+            for (std::map<Variable_ID, coef_t>::iterator k =
+                   s2.begin(); k != s2.end(); k++)
+              if ((*k).second != 0)
+                cost += 2;
+            for (std::map<Variable_ID, coef_t>::iterator k =
+                   s3.begin(); k != s3.end(); k++)
+              if ((*k).second != 0)
+                cost += 15;
+          }
+          
+          if (cost < best_cost) {
+            best_cost = cost;
+            simplest_lb = i;
+            simplest_ub = j;
+          }
+        }
+    }
+    
+    // prepare the new transformation relations
+    for (std::set<int>::iterator i = same_tile_controlling_loop.begin();
+         i != same_tile_controlling_loop.end(); i++) {
+      Relation r(stmt[*i].xform.n_out(), stmt[*i].xform.n_out() + 2);
+      F_And *f_root = r.add_and();
+      for (int j = 0; j < outer_dim - 1; j++) {
+        EQ_Handle h = f_root->add_EQ();
+        h.update_coef(r.output_var(j + 1), 1);
+        h.update_coef(r.input_var(j + 1), -1);
+      }
+      
+      for (int j = outer_dim - 1; j < stmt[*i].xform.n_out(); j++) {
+        EQ_Handle h = f_root->add_EQ();
+        h.update_coef(r.output_var(j + 3), 1);
+        h.update_coef(r.input_var(j + 1), -1);
+      }
+      
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(r.output_var(outer_dim), 1);
+      h.update_const(-lex[outer_dim - 1]);
+      
+      stmt[*i].xform = Composition(r, stmt[*i].xform);
+    }
+    
+    // add tiling constraints.
+    for (std::set<int>::iterator i = same_tile_controlling_loop.begin();
+         i != same_tile_controlling_loop.end(); i++) {
+      F_And *f_super_root = stmt[*i].xform.and_with_and();
+      F_Exists *f_exists = f_super_root->add_exists();
+      F_And *f_root = f_exists->add_and();
+      
+      // create a lower bound variable for easy formula creation later
+      Variable_ID aligned_lb;
+      {
+        Variable_ID lb = f_exists->declare();
+        coef_t coef = lb_list[simplest_lb].get_coef(
+          bound.set_var(dim + 1));
+        if (coef == 1) { // e.g. if i >= m+5, then LB = m+5
+          EQ_Handle h = f_root->add_EQ();
+          h.update_coef(lb, 1);
+          for (Constr_Vars_Iter ci(lb_list[simplest_lb]); ci; ci++) {
+            switch ((*ci).var->kind()) {
+            case Input_Var: {
+              int pos = (*ci).var->get_position();
+              if (pos != dim + 1)
+                h.update_coef(stmt[*i].xform.output_var(pos),
+                              (*ci).coef);
+              break;
+            }
+            case Global_Var: {
+              Global_Var_ID g = (*ci).var->get_global_var();
+              Variable_ID v;
+              if (g->arity() == 0)
+                v = stmt[*i].xform.get_local(g);
+              else
+                v = stmt[*i].xform.get_local(g,
+                                             (*ci).var->function_of());
+              h.update_coef(v, (*ci).coef);
+              break;
+            }
+            default:
+              throw loop_error("cannot handle tile bounds");
+            }
+          }
+          h.update_const(lb_list[simplest_lb].get_const());
+        } else { // e.g. if 2i >= m+5, then m+5 <= 2*LB < m+5+2
+          GEQ_Handle h1 = f_root->add_GEQ();
+          GEQ_Handle h2 = f_root->add_GEQ();
+          for (Constr_Vars_Iter ci(lb_list[simplest_lb]); ci; ci++) {
+            switch ((*ci).var->kind()) {
+            case Input_Var: {
+              int pos = (*ci).var->get_position();
+              if (pos == dim + 1) {
+                h1.update_coef(lb, (*ci).coef);
+                h2.update_coef(lb, -(*ci).coef);
+              } else {
+                h1.update_coef(stmt[*i].xform.output_var(pos),
+                               (*ci).coef);
+                h2.update_coef(stmt[*i].xform.output_var(pos),
+                               -(*ci).coef);
+              }
+              break;
+            }
+            case Global_Var: {
+              Global_Var_ID g = (*ci).var->get_global_var();
+              Variable_ID v;
+              if (g->arity() == 0)
+                v = stmt[*i].xform.get_local(g);
+              else
+                v = stmt[*i].xform.get_local(g,
+                                             (*ci).var->function_of());
+              h1.update_coef(v, (*ci).coef);
+              h2.update_coef(v, -(*ci).coef);
+              break;
+            }
+            default:
+              throw loop_error("cannot handle tile bounds");
+            }
+          }
+          h1.update_const(lb_list[simplest_lb].get_const());
+          h2.update_const(-lb_list[simplest_lb].get_const());
+          h2.update_const(coef - 1);
+        }
+        
+        Variable_ID offset_lb;
+        if (alignment_offset == 0)
+          offset_lb = lb;
+        else {
+          EQ_Handle h = f_root->add_EQ();
+          offset_lb = f_exists->declare();
+          h.update_coef(offset_lb, 1);
+          h.update_coef(lb, -1);
+          h.update_const(alignment_offset);
+        }
+        
+        if (alignment_multiple == 1) { // trivial
+          aligned_lb = offset_lb;
+        } else { // e.g. to align at 4, aligned_lb = 4*alpha && LB-4 < 4*alpha <= LB
+          aligned_lb = f_exists->declare();
+          Variable_ID e = f_exists->declare();
+          
+          EQ_Handle h = f_root->add_EQ();
+          h.update_coef(aligned_lb, 1);
+          h.update_coef(e, -alignment_multiple);
+          
+          GEQ_Handle h1 = f_root->add_GEQ();
+          GEQ_Handle h2 = f_root->add_GEQ();
+          h1.update_coef(e, alignment_multiple);
+          h2.update_coef(e, -alignment_multiple);
+          h1.update_coef(offset_lb, -1);
+          h2.update_coef(offset_lb, 1);
+          h1.update_const(alignment_multiple - 1);
+        }
+      }
+      
+      // create an upper bound variable for easy formula creation later
+      Variable_ID ub = f_exists->declare();
+      {
+        coef_t coef = -ub_list[simplest_ub].get_coef(
+          bound.set_var(dim + 1));
+        if (coef == 1) { // e.g. if i <= m+5, then UB = m+5
+          EQ_Handle h = f_root->add_EQ();
+          h.update_coef(ub, -1);
+          for (Constr_Vars_Iter ci(ub_list[simplest_ub]); ci; ci++) {
+            switch ((*ci).var->kind()) {
+            case Input_Var: {
+              int pos = (*ci).var->get_position();
+              if (pos != dim + 1)
+                h.update_coef(stmt[*i].xform.output_var(pos),
+                              (*ci).coef);
+              break;
+            }
+            case Global_Var: {
+              Global_Var_ID g = (*ci).var->get_global_var();
+              Variable_ID v;
+              if (g->arity() == 0)
+                v = stmt[*i].xform.get_local(g);
+              else
+                v = stmt[*i].xform.get_local(g,
+                                             (*ci).var->function_of());
+              h.update_coef(v, (*ci).coef);
+              break;
+            }
+            default:
+              throw loop_error("cannot handle tile bounds");
+            }
+          }
+          h.update_const(ub_list[simplest_ub].get_const());
+        } else { // e.g. if 2i <= m+5, then m+5-2 < 2*UB <= m+5
+          GEQ_Handle h1 = f_root->add_GEQ();
+          GEQ_Handle h2 = f_root->add_GEQ();
+          for (Constr_Vars_Iter ci(ub_list[simplest_ub]); ci; ci++) {
+            switch ((*ci).var->kind()) {
+            case Input_Var: {
+              int pos = (*ci).var->get_position();
+              if (pos == dim + 1) {
+                h1.update_coef(ub, -(*ci).coef);
+                h2.update_coef(ub, (*ci).coef);
+              } else {
+                h1.update_coef(stmt[*i].xform.output_var(pos),
+                               -(*ci).coef);
+                h2.update_coef(stmt[*i].xform.output_var(pos),
+                               (*ci).coef);
+              }
+              break;
+            }
+            case Global_Var: {
+              Global_Var_ID g = (*ci).var->get_global_var();
+              Variable_ID v;
+              if (g->arity() == 0)
+                v = stmt[*i].xform.get_local(g);
+              else
+                v = stmt[*i].xform.get_local(g,
+                                             (*ci).var->function_of());
+              h1.update_coef(v, -(*ci).coef);
+              h2.update_coef(v, (*ci).coef);
+              break;
+            }
+            default:
+              throw loop_error("cannot handle tile bounds");
+            }
+          }
+          h1.update_const(-ub_list[simplest_ub].get_const());
+          h2.update_const(ub_list[simplest_ub].get_const());
+          h1.update_const(coef - 1);
+        }
+      }
+      
+      // insert tile controlling loop constraints
+      if (method == StridedTile) { // e.g. ii = LB + 32 * alpha && alpha >= 0
+        Variable_ID e = f_exists->declare();
+        GEQ_Handle h1 = f_root->add_GEQ();
+        h1.update_coef(e, 1);
+        
+        EQ_Handle h2 = f_root->add_EQ();
+        h2.update_coef(stmt[*i].xform.output_var(outer_dim + 1), 1);
+        h2.update_coef(e, -tile_size);
+        h2.update_coef(aligned_lb, -1);
+      } else if (method == CountedTile) { // e.g. 0 <= ii < ceiling((UB-LB+1)/32)
+        GEQ_Handle h1 = f_root->add_GEQ();
+        h1.update_coef(stmt[*i].xform.output_var(outer_dim + 1), 1);
+        
+        GEQ_Handle h2 = f_root->add_GEQ();
+        h2.update_coef(stmt[*i].xform.output_var(outer_dim + 1),
+                       -tile_size);
+        h2.update_coef(aligned_lb, -1);
+        h2.update_coef(ub, 1);
+      }
+      
+      // special care for private statements like overflow assignment
+      if (private_stmt.find(*i) != private_stmt.end()) { // e.g. ii <= UB
+        GEQ_Handle h = f_root->add_GEQ();
+        h.update_coef(stmt[*i].xform.output_var(outer_dim + 1), -1);
+        h.update_coef(ub, 1);
+      }
+      // if (private_stmt.find(*i) != private_stmt.end()) {
+      //   if (stmt[*i].xform.n_out() > dim+3) { // e.g. ii <= UB && i = ii
+      //     GEQ_Handle h = f_root->add_GEQ();
+      //     h.update_coef(stmt[*i].xform.output_var(outer_dim+1), -1);
+      //     h.update_coef(ub, 1);
+      
+      //     stmt[*i].xform = Project(stmt[*i].xform, dim+3, Output_Var);
+      //     f_root = stmt[*i].xform.and_with_and();
+      //     EQ_Handle h1 = f_root->add_EQ();
+      //     h1.update_coef(stmt[*i].xform.output_var(dim+3), 1);
+      //     h1.update_coef(stmt[*i].xform.output_var(outer_dim+1), -1);
+      //   }
+      //   else if (method == StridedTile) { // e.g. ii <= UB since i does not exist
+      //     GEQ_Handle h = f_root->add_GEQ();
+      //     h.update_coef(stmt[*i].xform.output_var(outer_dim+1), -1);
+      //     h.update_coef(ub, 1);
+      //   }
+      // }
+      
+      // restrict original loop index inside the tile
+      else {
+        if (method == StridedTile) { // e.g. ii <= i < ii + tile_size
+          GEQ_Handle h1 = f_root->add_GEQ();
+          h1.update_coef(stmt[*i].xform.output_var(dim + 3), 1);
+          h1.update_coef(stmt[*i].xform.output_var(outer_dim + 1),
+                         -1);
+          
+          GEQ_Handle h2 = f_root->add_GEQ();
+          h2.update_coef(stmt[*i].xform.output_var(dim + 3), -1);
+          h2.update_coef(stmt[*i].xform.output_var(outer_dim + 1), 1);
+          h2.update_const(tile_size - 1);
+        } else if (method == CountedTile) { // e.g. LB+32*ii <= i < LB+32*ii+tile_size
+          GEQ_Handle h1 = f_root->add_GEQ();
+          h1.update_coef(stmt[*i].xform.output_var(outer_dim + 1),
+                         -tile_size);
+          h1.update_coef(stmt[*i].xform.output_var(dim + 3), 1);
+          h1.update_coef(aligned_lb, -1);
+          
+          GEQ_Handle h2 = f_root->add_GEQ();
+          h2.update_coef(stmt[*i].xform.output_var(outer_dim + 1),
+                         tile_size);
+          h2.update_coef(stmt[*i].xform.output_var(dim + 3), -1);
+          h2.update_const(tile_size - 1);
+          h2.update_coef(aligned_lb, 1);
+        }
+      }
+    }
+  }
+  
+  // update loop level information
+  for (std::set<int>::iterator i = same_tile_controlling_loop.begin();
+       i != same_tile_controlling_loop.end(); i++) {
+    for (int j = 1; j <= stmt[*i].loop_level.size(); j++)
+      switch (stmt[*i].loop_level[j - 1].type) {
+      case LoopLevelOriginal:
+        break;
+      case LoopLevelTile:
+        if (stmt[*i].loop_level[j - 1].payload >= outer_level)
+          stmt[*i].loop_level[j - 1].payload++;
+        break;
+      default:
+        throw loop_error(
+          "unknown loop level type for statement "
+          + to_string(*i));
+      }
+    
+    LoopLevel ll;
+    ll.type = LoopLevelTile;
+    ll.payload = level + 1;
+    ll.parallel_level = 0;
+    stmt[*i].loop_level.insert(
+      stmt[*i].loop_level.begin() + (outer_level - 1), ll);
+  }
+}
+
diff --git a/src/loop_unroll.cc b/src/loop_unroll.cc
new file mode 100644
index 0000000..9bc6acf
--- /dev/null
+++ b/src/loop_unroll.cc
@@ -0,0 +1,1166 @@
+/*
+ * loop_unroll.cc
+ *
+ *  Created on: Nov 12, 2012
+ *      Author: anand
+ */
+
+#include <code_gen/codegen.h>
+#include <code_gen/CG_utils.h>
+#include "loop.hh"
+#include "omegatools.hh"
+#include "ir_code.hh"
+#include "chill_error.hh"
+#include <math.h>
+
+using namespace omega;
+
+
+std::set<int> Loop::unroll(int stmt_num, int level, int unroll_amount,
+                           std::vector<std::vector<std::string> > idxNames,
+                           int cleanup_split_level) {
+  // check for sanity of parameters
+  // check for sanity of parameters
+  if (unroll_amount < 0)
+    throw std::invalid_argument(
+      "invalid unroll amount " + to_string(unroll_amount));
+  if (stmt_num < 0 || stmt_num >= stmt.size())
+    throw std::invalid_argument("invalid statement " + to_string(stmt_num));
+  if (level <= 0 || level > stmt[stmt_num].loop_level.size())
+    throw std::invalid_argument("invalid loop level " + to_string(level));
+  
+  if (cleanup_split_level == 0)
+    cleanup_split_level = level;
+  if (cleanup_split_level > level)
+    throw std::invalid_argument(
+      "cleanup code must be split at or outside the unrolled loop level "
+      + to_string(level));
+  if (cleanup_split_level <= 0)
+    throw std::invalid_argument(
+      "invalid split loop level " + to_string(cleanup_split_level));
+  
+  // invalidate saved codegen computation
+  delete last_compute_cgr_;
+  last_compute_cgr_ = NULL;
+  delete last_compute_cg_;
+  last_compute_cg_ = NULL;
+  
+  int dim = 2 * level - 1;
+  std::vector<int> lex = getLexicalOrder(stmt_num);
+  std::set<int> same_loop = getStatements(lex, dim - 1);
+  
+  // nothing to do
+  if (unroll_amount == 1)
+    return std::set<int>();
+  
+  for (std::set<int>::iterator i = same_loop.begin(); i != same_loop.end();
+       i++) {
+    std::vector<std::pair<int, DependenceVector> > D;
+    int n = stmt[*i].xform.n_out();
+    for (DependenceGraph::EdgeList::iterator j =
+           dep.vertex[*i].second.begin(); j != dep.vertex[*i].second.end();
+         j++) {
+      if (same_loop.find(j->first) != same_loop.end())
+        for (int k = 0; k < j->second.size(); k++) {
+          DependenceVector dv = j->second[k];
+          int dim2 = level - 1;
+          if (dv.type != DEP_CONTROL) {
+            
+            while (stmt[*i].loop_level[dim2].type == LoopLevelTile) {
+              dim2 = stmt[*i].loop_level[dim2].payload - 1;
+            }
+            dim2 = stmt[*i].loop_level[dim2].payload;
+            
+            /*if (dv.isCarried(dim2)
+              && (dv.hasNegative(dim2) && !dv.quasi))
+              throw loop_error(
+              "loop error: Unrolling is illegal, dependence violation!");
+              
+              if (dv.isCarried(dim2)
+              && (dv.hasPositive(dim2) && dv.quasi))
+              throw loop_error(
+              "loop error: Unrolling is illegal, dependence violation!");
+            */
+            bool safe = false;
+            
+            if (dv.isCarried(dim2) && dv.hasPositive(dim2)) {
+              if (dv.quasi)
+                throw loop_error(
+                  "loop error: a quasi dependence with a positive carried distance");
+              if (!dv.quasi) {
+                if (dv.lbounds[dim2] != posInfinity) {
+                  //if (dv.lbounds[dim2] != negInfinity)
+                  if (dv.lbounds[dim2] > unroll_amount)
+                    safe = true;
+                } else
+                  safe = true;
+              }/* else {
+                  if (dv.ubounds[dim2] != negInfinity) {
+                  if (dv.ubounds[dim2] != posInfinity)
+                  if ((-(dv.ubounds[dim2])) > unroll_amount)
+                  safe = true;
+                  } else
+                  safe = true;
+                  }*/
+              
+              if (!safe) {
+                for (int l = level + 1; l <= (n - 1) / 2; l++) {
+                  int dim3 = l - 1;
+                  
+                  if (stmt[*i].loop_level[dim3].type
+                      != LoopLevelTile)
+                    dim3 =
+                      stmt[*i].loop_level[dim3].payload;
+                  else {
+                    while (stmt[*i].loop_level[dim3].type
+                           == LoopLevelTile) {
+                      dim3 =
+                        stmt[*i].loop_level[dim3].payload
+                        - 1;
+                    }
+                    dim3 =
+                      stmt[*i].loop_level[dim3].payload;
+                  }
+                  
+                  if (dim3 > dim2) {
+                    
+                    if (dv.hasPositive(dim3))
+                      break;
+                    else if (dv.hasNegative(dim3))
+                      throw loop_error(
+                        "loop error: Unrolling is illegal, dependence violation!");
+                  }
+                }
+              }
+            }
+          }
+        }
+    }
+  }
+  // extract the intersection of the iteration space to be considered
+  Relation hull = Relation::True(level);
+  apply_xform(same_loop);
+  for (std::set<int>::iterator i = same_loop.begin(); i != same_loop.end();
+       i++) {
+    if (stmt[*i].IS.is_upper_bound_satisfiable()) {
+      Relation mapping(stmt[*i].IS.n_set(), level);
+      F_And *f_root = mapping.add_and();
+      for (int j = 1; j <= level; j++) {
+        EQ_Handle h = f_root->add_EQ();
+        h.update_coef(mapping.input_var(j), 1);
+        h.update_coef(mapping.output_var(j), -1);
+      }
+      hull = Intersection(hull,
+                          Range(Restrict_Domain(mapping, copy(stmt[*i].IS))));
+      hull.simplify(2, 4);
+      
+    }
+  }
+  for (int i = 1; i <= level; i++) {
+    std::string name = tmp_loop_var_name_prefix + to_string(i);
+    hull.name_set_var(i, name);
+  }
+  hull.setup_names();
+  
+  // extract the exact loop bound of the dimension to be unrolled
+  if (is_single_loop_iteration(hull, level, this->known))
+    return std::set<int>();
+  Relation bound = get_loop_bound(hull, level, this->known);
+  if (!bound.has_single_conjunct() || !bound.is_satisfiable()
+      || bound.is_tautology())
+    throw loop_error("unable to extract loop bound for unrolling");
+  
+  // extract the loop stride
+  coef_t stride;
+  std::pair<EQ_Handle, Variable_ID> result = find_simplest_stride(bound,
+                                                                  bound.set_var(level));
+  if (result.second == NULL)
+    stride = 1;
+  else
+    stride = abs(result.first.get_coef(result.second))
+      / gcd(abs(result.first.get_coef(result.second)),
+            abs(result.first.get_coef(bound.set_var(level))));
+  
+  // separate lower and upper bounds
+  std::vector<GEQ_Handle> lb_list, ub_list;
+  {
+    Conjunct *c = bound.query_DNF()->single_conjunct();
+    for (GEQ_Iterator gi(c->GEQs()); gi; gi++) {
+      int coef = (*gi).get_coef(bound.set_var(level));
+      if (coef < 0)
+        ub_list.push_back(*gi);
+      else if (coef > 0)
+        lb_list.push_back(*gi);
+    }
+  }
+  
+  // simplify overflow expression for each pair of upper and lower bounds
+  std::vector<std::vector<std::map<Variable_ID, int> > > overflow_table(
+    lb_list.size(),
+    std::vector<std::map<Variable_ID, int> >(ub_list.size(),
+                                             std::map<Variable_ID, int>()));
+  bool is_overflow_simplifiable = true;
+  for (int i = 0; i < lb_list.size(); i++) {
+    if (!is_overflow_simplifiable)
+      break;
+    
+    for (int j = 0; j < ub_list.size(); j++) {
+      // lower bound or upper bound has non-unit coefficient, can't simplify
+      if (ub_list[j].get_coef(bound.set_var(level)) != -1
+          || lb_list[i].get_coef(bound.set_var(level)) != 1) {
+        is_overflow_simplifiable = false;
+        break;
+      }
+      
+      for (Constr_Vars_Iter ci(ub_list[j]); ci; ci++) {
+        switch ((*ci).var->kind()) {
+        case Input_Var: {
+          if ((*ci).var != bound.set_var(level))
+            overflow_table[i][j][(*ci).var] += (*ci).coef;
+          
+          break;
+        }
+        case Global_Var: {
+          Global_Var_ID g = (*ci).var->get_global_var();
+          Variable_ID v;
+          if (g->arity() == 0)
+            v = bound.get_local(g);
+          else
+            v = bound.get_local(g, (*ci).var->function_of());
+          overflow_table[i][j][(*ci).var] += (*ci).coef;
+          break;
+        }
+        default:
+          throw loop_error("failed to calculate overflow amount");
+        }
+      }
+      overflow_table[i][j][NULL] += ub_list[j].get_const();
+      
+      for (Constr_Vars_Iter ci(lb_list[i]); ci; ci++) {
+        switch ((*ci).var->kind()) {
+        case Input_Var: {
+          if ((*ci).var != bound.set_var(level)) {
+            overflow_table[i][j][(*ci).var] += (*ci).coef;
+            if (overflow_table[i][j][(*ci).var] == 0)
+              overflow_table[i][j].erase(
+                overflow_table[i][j].find((*ci).var));
+          }
+          break;
+        }
+        case Global_Var: {
+          Global_Var_ID g = (*ci).var->get_global_var();
+          Variable_ID v;
+          if (g->arity() == 0)
+            v = bound.get_local(g);
+          else
+            v = bound.get_local(g, (*ci).var->function_of());
+          overflow_table[i][j][(*ci).var] += (*ci).coef;
+          if (overflow_table[i][j][(*ci).var] == 0)
+            overflow_table[i][j].erase(
+              overflow_table[i][j].find((*ci).var));
+          break;
+        }
+        default:
+          throw loop_error("failed to calculate overflow amount");
+        }
+      }
+      overflow_table[i][j][NULL] += lb_list[i].get_const();
+      
+      overflow_table[i][j][NULL] += stride;
+      if (unroll_amount == 0
+          || (overflow_table[i][j].size() == 1
+              && overflow_table[i][j][NULL] / stride
+              < unroll_amount))
+        unroll_amount = overflow_table[i][j][NULL] / stride;
+    }
+  }
+  
+  // loop iteration count can't be determined, bail out gracefully
+  if (unroll_amount == 0)
+    return std::set<int>();
+  
+  // further simply overflow calculation using coefficients' modular
+  if (is_overflow_simplifiable) {
+    for (int i = 0; i < lb_list.size(); i++)
+      for (int j = 0; j < ub_list.size(); j++)
+        if (stride == 1) {
+          for (std::map<Variable_ID, int>::iterator k =
+                 overflow_table[i][j].begin();
+               k != overflow_table[i][j].end();)
+            if ((*k).first != NULL) {
+              int t = int_mod_hat((*k).second, unroll_amount);
+              if (t == 0) {
+                overflow_table[i][j].erase(k++);
+              } else {
+                int t2 = hull.query_variable_mod((*k).first,
+                                                 unroll_amount);
+                if (t2 != INT_MAX) {
+                  overflow_table[i][j][NULL] += t * t2;
+                  overflow_table[i][j].erase(k++);
+                } else {
+                  (*k).second = t;
+                  k++;
+                }
+              }
+            } else
+              k++;
+          
+          overflow_table[i][j][NULL] = int_mod_hat(
+            overflow_table[i][j][NULL], unroll_amount);
+          
+          // Since we don't have MODULO instruction in SUIF yet (only MOD), make all coef positive in the final formula
+          for (std::map<Variable_ID, int>::iterator k =
+                 overflow_table[i][j].begin();
+               k != overflow_table[i][j].end(); k++)
+            if ((*k).second < 0)
+              (*k).second += unroll_amount;
+        }
+  }
+  
+  // build overflow statement
+  CG_outputBuilder *ocg = ir->builder();
+  CG_outputRepr *overflow_code = NULL;
+  Relation cond_upper(level), cond_lower(level);
+  Relation overflow_constraint(0);
+  F_And *overflow_constraint_root = overflow_constraint.add_and();
+  std::vector<Free_Var_Decl *> over_var_list;
+  if (is_overflow_simplifiable && lb_list.size() == 1) {
+    for (int i = 0; i < ub_list.size(); i++) {
+      if (overflow_table[0][i].size() == 1) {
+        // upper splitting condition
+        GEQ_Handle h = cond_upper.and_with_GEQ(ub_list[i]);
+        h.update_const(
+          ((overflow_table[0][i][NULL] / stride) % unroll_amount)
+          * -stride);
+      } else {
+        // upper splitting condition
+        std::string over_name = overflow_var_name_prefix
+          + to_string(overflow_var_name_counter++);
+        Free_Var_Decl *over_free_var = new Free_Var_Decl(over_name);
+        over_var_list.push_back(over_free_var);
+        GEQ_Handle h = cond_upper.and_with_GEQ(ub_list[i]);
+        h.update_coef(cond_upper.get_local(over_free_var), -stride);
+        
+        // insert constraint 0 <= overflow < unroll_amount
+        Variable_ID v = overflow_constraint.get_local(over_free_var);
+        GEQ_Handle h1 = overflow_constraint_root->add_GEQ();
+        h1.update_coef(v, 1);
+        GEQ_Handle h2 = overflow_constraint_root->add_GEQ();
+        h2.update_coef(v, -1);
+        h2.update_const(unroll_amount - 1);
+        
+        // create overflow assignment
+        bound.setup_names(); // hack to fix omega relation variable names issue
+        CG_outputRepr *rhs = NULL;
+        bool is_split_illegal = false;
+        for (std::map<Variable_ID, int>::iterator j =
+               overflow_table[0][i].begin();
+             j != overflow_table[0][i].end(); j++)
+          if ((*j).first != NULL) {
+            if ((*j).first->kind() == Input_Var
+                && (*j).first->get_position()
+                >= cleanup_split_level)
+              is_split_illegal = true;
+            
+            CG_outputRepr *t = ocg->CreateIdent((*j).first->name());
+            if ((*j).second != 1)
+              t = ocg->CreateTimes(ocg->CreateInt((*j).second),
+                                   t);
+            rhs = ocg->CreatePlus(rhs, t);
+          } else if ((*j).second != 0)
+            rhs = ocg->CreatePlus(rhs, ocg->CreateInt((*j).second));
+        
+        if (is_split_illegal) {
+          rhs->clear();
+          delete rhs;
+          throw loop_error(
+            "cannot split cleanup code at loop level "
+            + to_string(cleanup_split_level)
+            + " due to overflow variable data dependence");
+        }
+        
+        if (stride != 1)
+          rhs = ocg->CreateIntegerCeil(rhs, ocg->CreateInt(stride));
+        rhs = ocg->CreateIntegerMod(rhs, ocg->CreateInt(unroll_amount));
+        
+        CG_outputRepr *lhs = ocg->CreateIdent(over_name);
+        init_code = ocg->StmtListAppend(init_code,
+                                        ocg->CreateAssignment(0, lhs, ocg->CreateInt(0)));
+        lhs = ocg->CreateIdent(over_name);
+        overflow_code = ocg->StmtListAppend(overflow_code,
+                                            ocg->CreateAssignment(0, lhs, rhs));
+      }
+    }
+    
+    // lower splitting condition
+    GEQ_Handle h = cond_lower.and_with_GEQ(lb_list[0]);
+  } else if (is_overflow_simplifiable && ub_list.size() == 1) {
+    for (int i = 0; i < lb_list.size(); i++) {
+      
+      if (overflow_table[i][0].size() == 1) {
+        // lower splitting condition
+        GEQ_Handle h = cond_lower.and_with_GEQ(lb_list[i]);
+        h.update_const(overflow_table[i][0][NULL] * -stride);
+      } else {
+        // lower splitting condition
+        std::string over_name = overflow_var_name_prefix
+          + to_string(overflow_var_name_counter++);
+        Free_Var_Decl *over_free_var = new Free_Var_Decl(over_name);
+        over_var_list.push_back(over_free_var);
+        GEQ_Handle h = cond_lower.and_with_GEQ(lb_list[i]);
+        h.update_coef(cond_lower.get_local(over_free_var), -stride);
+        
+        // insert constraint 0 <= overflow < unroll_amount
+        Variable_ID v = overflow_constraint.get_local(over_free_var);
+        GEQ_Handle h1 = overflow_constraint_root->add_GEQ();
+        h1.update_coef(v, 1);
+        GEQ_Handle h2 = overflow_constraint_root->add_GEQ();
+        h2.update_coef(v, -1);
+        h2.update_const(unroll_amount - 1);
+        
+        // create overflow assignment
+        bound.setup_names(); // hack to fix omega relation variable names issue
+        CG_outputRepr *rhs = NULL;
+        for (std::map<Variable_ID, int>::iterator j =
+               overflow_table[0][i].begin();
+             j != overflow_table[0][i].end(); j++)
+          if ((*j).first != NULL) {
+            CG_outputRepr *t = ocg->CreateIdent((*j).first->name());
+            if ((*j).second != 1)
+              t = ocg->CreateTimes(ocg->CreateInt((*j).second),
+                                   t);
+            rhs = ocg->CreatePlus(rhs, t);
+          } else if ((*j).second != 0)
+            rhs = ocg->CreatePlus(rhs, ocg->CreateInt((*j).second));
+        
+        if (stride != 1)
+          rhs = ocg->CreateIntegerCeil(rhs, ocg->CreateInt(stride));
+        rhs = ocg->CreateIntegerMod(rhs, ocg->CreateInt(unroll_amount));
+        
+        CG_outputRepr *lhs = ocg->CreateIdent(over_name);
+        init_code = ocg->StmtListAppend(init_code,
+                                        ocg->CreateAssignment(0, lhs, ocg->CreateInt(0)));
+        lhs = ocg->CreateIdent(over_name);
+        overflow_code = ocg->StmtListAppend(overflow_code,
+                                            ocg->CreateAssignment(0, lhs, rhs));
+      }
+    }
+    
+    // upper splitting condition
+    GEQ_Handle h = cond_upper.and_with_GEQ(ub_list[0]);
+  } else {
+    std::string over_name = overflow_var_name_prefix
+      + to_string(overflow_var_name_counter++);
+    Free_Var_Decl *over_free_var = new Free_Var_Decl(over_name);
+    over_var_list.push_back(over_free_var);
+    
+    std::vector<CG_outputRepr *> lb_repr_list, ub_repr_list;
+    for (int i = 0; i < lb_list.size(); i++) {
+      lb_repr_list.push_back(
+        output_lower_bound_repr(ocg, lb_list[i],
+                                bound.set_var(dim + 1), result.first, result.second,
+                                bound, Relation::True(bound.n_set()),
+                                std::vector<std::pair<CG_outputRepr *, int> >(
+                                  bound.n_set(),
+                                  std::make_pair(
+                                    static_cast<CG_outputRepr *>(NULL),
+                                    0))));
+      GEQ_Handle h = cond_lower.and_with_GEQ(lb_list[i]);
+    }
+    for (int i = 0; i < ub_list.size(); i++) {
+      ub_repr_list.push_back(
+        output_upper_bound_repr(ocg, ub_list[i],
+                                bound.set_var(dim + 1), bound,
+                                std::vector<std::pair<CG_outputRepr *, int> >(
+                                  bound.n_set(),
+                                  std::make_pair(
+                                    static_cast<CG_outputRepr *>(NULL),
+                                    0))));
+      GEQ_Handle h = cond_upper.and_with_GEQ(ub_list[i]);
+      h.update_coef(cond_upper.get_local(over_free_var), -stride);
+    }
+    
+    CG_outputRepr *lbRepr, *ubRepr;
+    if (lb_repr_list.size() > 1)
+      lbRepr = ocg->CreateInvoke("max", lb_repr_list);
+    else if (lb_repr_list.size() == 1)
+      lbRepr = lb_repr_list[0];
+    
+    if (ub_repr_list.size() > 1)
+      ubRepr = ocg->CreateInvoke("min", ub_repr_list);
+    else if (ub_repr_list.size() == 1)
+      ubRepr = ub_repr_list[0];
+    
+    // create overflow assignment
+    CG_outputRepr *rhs = ocg->CreatePlus(ocg->CreateMinus(ubRepr, lbRepr),
+                                         ocg->CreateInt(1));
+    if (stride != 1)
+      rhs = ocg->CreateIntegerFloor(rhs, ocg->CreateInt(stride));
+    rhs = ocg->CreateIntegerMod(rhs, ocg->CreateInt(unroll_amount));
+    CG_outputRepr *lhs = ocg->CreateIdent(over_name);
+    init_code = ocg->StmtListAppend(init_code,
+                                    ocg->CreateAssignment(0, lhs, ocg->CreateInt(0)));
+    lhs = ocg->CreateIdent(over_name);
+    overflow_code = ocg->CreateAssignment(0, lhs, rhs);
+    
+    // insert constraint 0 <= overflow < unroll_amount
+    Variable_ID v = overflow_constraint.get_local(over_free_var);
+    GEQ_Handle h1 = overflow_constraint_root->add_GEQ();
+    h1.update_coef(v, 1);
+    GEQ_Handle h2 = overflow_constraint_root->add_GEQ();
+    h2.update_coef(v, -1);
+    h2.update_const(unroll_amount - 1);
+  }
+  
+  // insert overflow statement
+  int overflow_stmt_num = -1;
+  if (overflow_code != NULL) {
+    // build iteration space for overflow statement
+    Relation mapping(level, cleanup_split_level - 1);
+    F_And *f_root = mapping.add_and();
+    for (int i = 1; i < cleanup_split_level; i++) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(mapping.output_var(i), 1);
+      h.update_coef(mapping.input_var(i), -1);
+    }
+    Relation overflow_IS = Range(Restrict_Domain(mapping, copy(hull)));
+    for (int i = 1; i < cleanup_split_level; i++)
+      overflow_IS.name_set_var(i, hull.set_var(i)->name());
+    overflow_IS.setup_names();
+    
+    // build dumb transformation relation for overflow statement
+    Relation overflow_xform(cleanup_split_level - 1,
+                            2 * (cleanup_split_level - 1) + 1);
+    f_root = overflow_xform.add_and();
+    for (int i = 1; i <= cleanup_split_level - 1; i++) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(overflow_xform.output_var(2 * i), 1);
+      h.update_coef(overflow_xform.input_var(i), -1);
+      
+      h = f_root->add_EQ();
+      h.update_coef(overflow_xform.output_var(2 * i - 1), 1);
+      h.update_const(-lex[2 * i - 2]);
+    }
+    EQ_Handle h = f_root->add_EQ();
+    h.update_coef(
+      overflow_xform.output_var(2 * (cleanup_split_level - 1) + 1),
+      1);
+    h.update_const(-lex[2 * (cleanup_split_level - 1)]);
+    
+    shiftLexicalOrder(lex, 2 * cleanup_split_level - 2, 1);
+    Statement overflow_stmt;
+    
+    overflow_stmt.code = overflow_code;
+    overflow_stmt.IS = overflow_IS;
+    overflow_stmt.xform = overflow_xform;
+    overflow_stmt.loop_level = std::vector<LoopLevel>(level - 1);
+    overflow_stmt.ir_stmt_node = NULL;
+    for (int i = 0; i < level - 1; i++) {
+      overflow_stmt.loop_level[i].type =
+        stmt[stmt_num].loop_level[i].type;
+      if (stmt[stmt_num].loop_level[i].type == LoopLevelTile
+          && stmt[stmt_num].loop_level[i].payload >= level)
+        overflow_stmt.loop_level[i].payload = -1;
+      else
+        overflow_stmt.loop_level[i].payload =
+          stmt[stmt_num].loop_level[i].payload;
+      overflow_stmt.loop_level[i].parallel_level =
+        stmt[stmt_num].loop_level[i].parallel_level;
+    }
+    
+    stmt.push_back(overflow_stmt);
+    dep.insert();
+    overflow_stmt_num = stmt.size() - 1;
+    overflow[overflow_stmt_num] = over_var_list;
+    
+    // update the global known information on overflow variable
+    this->known = Intersection(this->known,
+                               Extend_Set(copy(overflow_constraint),
+                                          this->known.n_set() - overflow_constraint.n_set()));
+    
+    // update dependence graph
+    DependenceVector dv;
+    dv.type = DEP_CONTROL;
+    for (std::set<int>::iterator i = same_loop.begin();
+         i != same_loop.end(); i++)
+      dep.connect(overflow_stmt_num, *i, dv);
+    dv.type = DEP_W2W;
+    {
+      IR_ScalarSymbol *overflow_sym = NULL;
+      std::vector<IR_ScalarRef *> scalars = ir->FindScalarRef(
+        overflow_code);
+      for (int i = scalars.size() - 1; i >= 0; i--)
+        if (scalars[i]->is_write()) {
+          overflow_sym = scalars[i]->symbol();
+          break;
+        }
+      for (int i = scalars.size() - 1; i >= 0; i--)
+        delete scalars[i];
+      dv.sym = overflow_sym;
+    }
+    dv.lbounds = std::vector<coef_t>(dep.num_dim(), 0);
+    dv.ubounds = std::vector<coef_t>(dep.num_dim(), 0);
+    int dep_dim = get_last_dep_dim_before(stmt_num, level);
+    for (int i = dep_dim + 1; i < dep.num_dim(); i++) {
+      dv.lbounds[i] = -posInfinity;
+      dv.ubounds[i] = posInfinity;
+    }
+    for (int i = 0; i <= dep_dim; i++) {
+      if (i != 0) {
+        dv.lbounds[i - 1] = 0;
+        dv.ubounds[i - 1] = 0;
+      }
+      dv.lbounds[i] = 1;
+      dv.ubounds[i] = posInfinity;
+      dep.connect(overflow_stmt_num, overflow_stmt_num, dv);
+    }
+  }
+  
+  // split the loop so it can be fully unrolled
+  std::set<int> new_stmts = split(stmt_num, cleanup_split_level, cond_upper);
+  std::set<int> new_stmts2 = split(stmt_num, cleanup_split_level, cond_lower);
+  new_stmts.insert(new_stmts2.begin(), new_stmts2.end());
+  
+  // check if unrolled statements can be trivially lumped together as one statement
+  bool can_be_lumped = true;
+  if (can_be_lumped) {
+    for (std::set<int>::iterator i = same_loop.begin();
+         i != same_loop.end(); i++)
+      if (*i != stmt_num) {
+        if (stmt[*i].loop_level.size()
+            != stmt[stmt_num].loop_level.size()) {
+          can_be_lumped = false;
+          break;
+        }
+        for (int j = 0; j < stmt[stmt_num].loop_level.size(); j++)
+          if (!(stmt[*i].loop_level[j].type
+                == stmt[stmt_num].loop_level[j].type
+                && stmt[*i].loop_level[j].payload
+                == stmt[stmt_num].loop_level[j].payload)) {
+            can_be_lumped = false;
+            break;
+          }
+        if (!can_be_lumped)
+          break;
+        std::vector<int> lex2 = getLexicalOrder(*i);
+        for (int j = 2 * level; j < lex.size() - 1; j += 2)
+          if (lex[j] != lex2[j]) {
+            can_be_lumped = false;
+            break;
+          }
+        if (!can_be_lumped)
+          break;
+      }
+  }
+  if (can_be_lumped) {
+    for (std::set<int>::iterator i = same_loop.begin();
+         i != same_loop.end(); i++)
+      if (is_inner_loop_depend_on_level(stmt[*i].IS, level,
+                                        this->known)) {
+        can_be_lumped = false;
+        break;
+      }
+  }
+  if (can_be_lumped) {
+    for (std::set<int>::iterator i = same_loop.begin();
+         i != same_loop.end(); i++)
+      if (*i != stmt_num) {
+        if (!(Must_Be_Subset(copy(stmt[*i].IS), copy(stmt[stmt_num].IS))
+              && Must_Be_Subset(copy(stmt[stmt_num].IS),
+                                copy(stmt[*i].IS)))) {
+          can_be_lumped = false;
+          break;
+        }
+      }
+  }
+  if (can_be_lumped) {
+    for (std::set<int>::iterator i = same_loop.begin();
+         i != same_loop.end(); i++) {
+      for (DependenceGraph::EdgeList::iterator j =
+             dep.vertex[*i].second.begin();
+           j != dep.vertex[*i].second.end(); j++)
+        if (same_loop.find(j->first) != same_loop.end()) {
+          for (int k = 0; k < j->second.size(); k++)
+            if (j->second[k].type == DEP_CONTROL
+                || j->second[k].type == DEP_UNKNOWN) {
+              can_be_lumped = false;
+              break;
+            }
+          if (!can_be_lumped)
+            break;
+        }
+      if (!can_be_lumped)
+        break;
+    }
+  }
+  
+  // insert unrolled statements
+  int old_num_stmt = stmt.size();
+  if (!can_be_lumped) {
+    std::map<int, std::vector<int> > what_stmt_num;
+    
+    for (int j = 1; j < unroll_amount; j++) {
+      for (std::set<int>::iterator i = same_loop.begin();
+           i != same_loop.end(); i++) {
+        Statement new_stmt;
+        
+        std::vector<std::string> loop_vars;
+        std::vector<CG_outputRepr *> subs;
+        loop_vars.push_back(stmt[*i].IS.set_var(level)->name());
+        subs.push_back(
+          ocg->CreatePlus(
+            ocg->CreateIdent(
+              stmt[*i].IS.set_var(level)->name()),
+            ocg->CreateInt(j * stride)));
+        new_stmt.code = ocg->CreateSubstitutedStmt(0,
+                                                   stmt[*i].code->clone(), loop_vars, subs);
+        
+        new_stmt.IS = adjust_loop_bound(stmt[*i].IS, level, j * stride);
+        add_loop_stride(new_stmt.IS, bound, level - 1,
+                        unroll_amount * stride);
+        
+        new_stmt.xform = copy(stmt[*i].xform);
+        
+        new_stmt.loop_level = stmt[*i].loop_level;
+        new_stmt.ir_stmt_node = NULL;
+        stmt.push_back(new_stmt);
+        dep.insert();
+        what_stmt_num[*i].push_back(stmt.size() - 1);
+      }
+    }
+    for (std::set<int>::iterator i = same_loop.begin();
+         i != same_loop.end(); i++)
+      add_loop_stride(stmt[*i].IS, bound, level - 1,
+                      unroll_amount * stride);
+    
+    // update dependence graph
+    if (stmt[stmt_num].loop_level[level - 1].type == LoopLevelOriginal) {
+      int dep_dim = stmt[stmt_num].loop_level[level - 1].payload;
+      int new_stride = unroll_amount * stride;
+      for (int i = 0; i < old_num_stmt; i++) {
+        std::vector<std::pair<int, DependenceVector> > D;
+        
+        for (DependenceGraph::EdgeList::iterator j =
+               dep.vertex[i].second.begin();
+             j != dep.vertex[i].second.end();) {
+          if (same_loop.find(i) != same_loop.end()) {
+            if (same_loop.find(j->first) != same_loop.end()) {
+              for (int k = 0; k < j->second.size(); k++) {
+                DependenceVector dv = j->second[k];
+                if (dv.type == DEP_CONTROL
+                    || dv.type == DEP_UNKNOWN) {
+                  D.push_back(std::make_pair(j->first, dv));
+                  for (int kk = 0; kk < unroll_amount - 1;
+                       kk++)
+                    if (what_stmt_num[i][kk] != -1
+                        && what_stmt_num[j->first][kk]
+                        != -1)
+                      dep.connect(what_stmt_num[i][kk],
+                                  what_stmt_num[j->first][kk],
+                                  dv);
+                } else {
+                  coef_t lb = dv.lbounds[dep_dim];
+                  coef_t ub = dv.ubounds[dep_dim];
+                  if (ub == lb
+                      && int_mod(lb,
+                                 static_cast<coef_t>(new_stride))
+                      == 0) {
+                    D.push_back(
+                      std::make_pair(j->first, dv));
+                    for (int kk = 0; kk < unroll_amount - 1;
+                         kk++)
+                      if (what_stmt_num[i][kk] != -1
+                          && what_stmt_num[j->first][kk]
+                          != -1)
+                        dep.connect(
+                          what_stmt_num[i][kk],
+                          what_stmt_num[j->first][kk],
+                          dv);
+                  } else if (lb == -posInfinity
+                             && ub == posInfinity) {
+                    D.push_back(
+                      std::make_pair(j->first, dv));
+                    for (int kk = 0; kk < unroll_amount;
+                         kk++)
+                      if (kk == 0)
+                        D.push_back(
+                          std::make_pair(j->first,
+                                         dv));
+                      else if (what_stmt_num[j->first][kk
+                                                       - 1] != -1)
+                        D.push_back(
+                          std::make_pair(
+                            what_stmt_num[j->first][kk
+                                                    - 1],
+                            dv));
+                    for (int t = 0; t < unroll_amount - 1;
+                         t++)
+                      if (what_stmt_num[i][t] != -1)
+                        for (int kk = 0;
+                             kk < unroll_amount;
+                             kk++)
+                          if (kk == 0)
+                            dep.connect(
+                              what_stmt_num[i][t],
+                              j->first, dv);
+                          else if (what_stmt_num[j->first][kk
+                                                           - 1] != -1)
+                            dep.connect(
+                              what_stmt_num[i][t],
+                              what_stmt_num[j->first][kk
+                                                      - 1],
+                              dv);
+                  } else {
+                    for (int kk = 0; kk < unroll_amount;
+                         kk++) {
+                      if (lb != -posInfinity) {
+                        if (kk * stride
+                            < int_mod(lb,
+                                      static_cast<coef_t>(new_stride)))
+                          dv.lbounds[dep_dim] =
+                            floor(
+                              static_cast<double>(lb)
+                              / new_stride)
+                            * new_stride
+                            + new_stride;
+                        else
+                          dv.lbounds[dep_dim] =
+                            floor(
+                              static_cast<double>(lb)
+                              / new_stride)
+                            * new_stride;
+                      }
+                      if (ub != posInfinity) {
+                        if (kk * stride
+                            > int_mod(ub,
+                                      static_cast<coef_t>(new_stride)))
+                          dv.ubounds[dep_dim] =
+                            floor(
+                              static_cast<double>(ub)
+                              / new_stride)
+                            * new_stride
+                            - new_stride;
+                        else
+                          dv.ubounds[dep_dim] =
+                            floor(
+                              static_cast<double>(ub)
+                              / new_stride)
+                            * new_stride;
+                      }
+                      if (dv.ubounds[dep_dim]
+                          >= dv.lbounds[dep_dim]) {
+                        if (kk == 0)
+                          D.push_back(
+                            std::make_pair(
+                              j->first,
+                              dv));
+                        else if (what_stmt_num[j->first][kk
+                                                         - 1] != -1)
+                          D.push_back(
+                            std::make_pair(
+                              what_stmt_num[j->first][kk
+                                                      - 1],
+                              dv));
+                      }
+                    }
+                    for (int t = 0; t < unroll_amount - 1;
+                         t++)
+                      if (what_stmt_num[i][t] != -1)
+                        for (int kk = 0;
+                             kk < unroll_amount;
+                             kk++) {
+                          if (lb != -posInfinity) {
+                            if (kk * stride
+                                < int_mod(
+                                  lb + t
+                                  + 1,
+                                  static_cast<coef_t>(new_stride)))
+                              dv.lbounds[dep_dim] =
+                                floor(
+                                  static_cast<double>(lb
+                                                      + (t
+                                                         + 1)
+                                                      * stride)
+                                  / new_stride)
+                                * new_stride
+                                + new_stride;
+                            else
+                              dv.lbounds[dep_dim] =
+                                floor(
+                                  static_cast<double>(lb
+                                                      + (t
+                                                         + 1)
+                                                      * stride)
+                                  / new_stride)
+                                * new_stride;
+                          }
+                          if (ub != posInfinity) {
+                            if (kk * stride
+                                > int_mod(
+                                  ub + t
+                                  + 1,
+                                  static_cast<coef_t>(new_stride)))
+                              dv.ubounds[dep_dim] =
+                                floor(
+                                  static_cast<double>(ub
+                                                      + (t
+                                                         + 1)
+                                                      * stride)
+                                  / new_stride)
+                                * new_stride
+                                - new_stride;
+                            else
+                              dv.ubounds[dep_dim] =
+                                floor(
+                                  static_cast<double>(ub
+                                                      + (t
+                                                         + 1)
+                                                      * stride)
+                                  / new_stride)
+                                * new_stride;
+                          }
+                          if (dv.ubounds[dep_dim]
+                              >= dv.lbounds[dep_dim]) {
+                            if (kk == 0)
+                              dep.connect(
+                                what_stmt_num[i][t],
+                                j->first,
+                                dv);
+                            else if (what_stmt_num[j->first][kk
+                                                             - 1] != -1)
+                              dep.connect(
+                                what_stmt_num[i][t],
+                                what_stmt_num[j->first][kk
+                                                        - 1],
+                                dv);
+                          }
+                        }
+                  }
+                }
+              }
+              
+              dep.vertex[i].second.erase(j++);
+            } else {
+              for (int kk = 0; kk < unroll_amount - 1; kk++)
+                if (what_stmt_num[i][kk] != -1)
+                  dep.connect(what_stmt_num[i][kk], j->first,
+                              j->second);
+              
+              j++;
+            }
+          } else {
+            if (same_loop.find(j->first) != same_loop.end())
+              for (int k = 0; k < j->second.size(); k++)
+                for (int kk = 0; kk < unroll_amount - 1; kk++)
+                  if (what_stmt_num[j->first][kk] != -1)
+                    D.push_back(
+                      std::make_pair(
+                        what_stmt_num[j->first][kk],
+                        j->second[k]));
+            j++;
+          }
+        }
+        
+        for (int j = 0; j < D.size(); j++)
+          dep.connect(i, D[j].first, D[j].second);
+      }
+    }
+    
+    // reset lexical order for the unrolled loop body
+    std::set<int> new_same_loop;
+    
+    int count = 0;
+    
+    for (std::map<int, std::vector<int> >::iterator i =
+           what_stmt_num.begin(); i != what_stmt_num.end(); i++) {
+      
+      new_same_loop.insert(i->first);
+      for (int k = dim + 1; k < stmt[i->first].xform.n_out(); k += 2)
+        assign_const(stmt[i->first].xform, k,
+                     get_const(stmt[(what_stmt_num.begin())->first].xform, k,
+                               Output_Var) + count);
+      count++;
+      for (int j = 0; j < i->second.size(); j++) {
+        new_same_loop.insert(i->second[j]);
+        for (int k = dim + 1; k < stmt[i->second[j]].xform.n_out(); k +=
+               2)
+          assign_const(stmt[i->second[j]].xform, k,
+                       get_const(
+                         stmt[(what_stmt_num.begin())->first].xform,
+                         k, Output_Var) + count);
+        count++;
+      }
+    }
+    setLexicalOrder(dim + 1, new_same_loop, 0, idxNames);
+  } else {
+    for (std::set<int>::iterator i = same_loop.begin();
+         i != same_loop.end(); i++)
+      add_loop_stride(stmt[*i].IS, bound, level - 1,
+                      unroll_amount * stride);
+    
+    int max_level = stmt[stmt_num].loop_level.size();
+    std::vector<std::pair<int, int> > stmt_order;
+    for (std::set<int>::iterator i = same_loop.begin();
+         i != same_loop.end(); i++)
+      stmt_order.push_back(
+        std::make_pair(
+          get_const(stmt[*i].xform, 2 * max_level,
+                    Output_Var), *i));
+    sort(stmt_order.begin(), stmt_order.end());
+    
+    Statement new_stmt;
+    new_stmt.code = NULL;
+    for (int j = 1; j < unroll_amount; j++)
+      for (int i = 0; i < stmt_order.size(); i++) {
+        std::vector<std::string> loop_vars;
+        std::vector<CG_outputRepr *> subs;
+        loop_vars.push_back(
+          stmt[stmt_order[i].second].IS.set_var(level)->name());
+        subs.push_back(
+          ocg->CreatePlus(
+            ocg->CreateIdent(
+              stmt[stmt_order[i].second].IS.set_var(
+                level)->name()),
+            ocg->CreateInt(j * stride)));
+        CG_outputRepr *code = ocg->CreateSubstitutedStmt(0,
+                                                         stmt[stmt_order[i].second].code->clone(), loop_vars,
+                                                         subs);
+        new_stmt.code = ocg->StmtListAppend(new_stmt.code, code);
+      }
+    
+    new_stmt.IS = copy(stmt[stmt_num].IS);
+    new_stmt.xform = copy(stmt[stmt_num].xform);
+    assign_const(new_stmt.xform, 2 * max_level,
+                 stmt_order[stmt_order.size() - 1].first + 1);
+    new_stmt.loop_level = stmt[stmt_num].loop_level;
+    new_stmt.ir_stmt_node = NULL;
+    stmt.push_back(new_stmt);
+    dep.insert();
+    
+    // update dependence graph
+    if (stmt[stmt_num].loop_level[level - 1].type == LoopLevelOriginal) {
+      int dep_dim = stmt[stmt_num].loop_level[level - 1].payload;
+      int new_stride = unroll_amount * stride;
+      for (int i = 0; i < old_num_stmt; i++) {
+        std::vector<std::pair<int, std::vector<DependenceVector> > > D;
+        
+        for (DependenceGraph::EdgeList::iterator j =
+               dep.vertex[i].second.begin();
+             j != dep.vertex[i].second.end();) {
+          if (same_loop.find(i) != same_loop.end()) {
+            if (same_loop.find(j->first) != same_loop.end()) {
+              std::vector<DependenceVector> dvs11, dvs12, dvs22,
+                dvs21;
+              for (int k = 0; k < j->second.size(); k++) {
+                DependenceVector dv = j->second[k];
+                if (dv.type == DEP_CONTROL
+                    || dv.type == DEP_UNKNOWN) {
+                  if (i == j->first) {
+                    dvs11.push_back(dv);
+                    dvs22.push_back(dv);
+                  } else
+                    throw loop_error(
+                      "unrolled statements lumped together illegally");
+                } else {
+                  coef_t lb = dv.lbounds[dep_dim];
+                  coef_t ub = dv.ubounds[dep_dim];
+                  if (ub == lb
+                      && int_mod(lb,
+                                 static_cast<coef_t>(new_stride))
+                      == 0) {
+                    dvs11.push_back(dv);
+                    dvs22.push_back(dv);
+                  } else {
+                    if (lb != -posInfinity)
+                      dv.lbounds[dep_dim] = ceil(
+                        static_cast<double>(lb)
+                        / new_stride)
+                        * new_stride;
+                    if (ub != posInfinity)
+                      dv.ubounds[dep_dim] = floor(
+                        static_cast<double>(ub)
+                        / new_stride)
+                        * new_stride;
+                    if (dv.ubounds[dep_dim]
+                        >= dv.lbounds[dep_dim])
+                      dvs11.push_back(dv);
+                    
+                    if (lb != -posInfinity)
+                      dv.lbounds[dep_dim] = ceil(
+                        static_cast<double>(lb)
+                        / new_stride)
+                        * new_stride;
+                    if (ub != posInfinity)
+                      dv.ubounds[dep_dim] = ceil(
+                        static_cast<double>(ub)
+                        / new_stride)
+                        * new_stride;
+                    if (dv.ubounds[dep_dim]
+                        >= dv.lbounds[dep_dim])
+                      dvs21.push_back(dv);
+                    
+                    if (lb != -posInfinity)
+                      dv.lbounds[dep_dim] = floor(
+                        static_cast<double>(lb)
+                        / new_stride)
+                        * new_stride;
+                    if (ub != posInfinity)
+                      dv.ubounds[dep_dim] = floor(
+                        static_cast<double>(ub
+                                            - stride)
+                        / new_stride)
+                        * new_stride;
+                    if (dv.ubounds[dep_dim]
+                        >= dv.lbounds[dep_dim])
+                      dvs12.push_back(dv);
+                    
+                    if (lb != -posInfinity)
+                      dv.lbounds[dep_dim] = floor(
+                        static_cast<double>(lb)
+                        / new_stride)
+                        * new_stride;
+                    if (ub != posInfinity)
+                      dv.ubounds[dep_dim] = ceil(
+                        static_cast<double>(ub
+                                            - stride)
+                        / new_stride)
+                        * new_stride;
+                    if (dv.ubounds[dep_dim]
+                        >= dv.lbounds[dep_dim])
+                      dvs22.push_back(dv);
+                  }
+                }
+              }
+              if (dvs11.size() > 0)
+                D.push_back(std::make_pair(i, dvs11));
+              if (dvs22.size() > 0)
+                dep.connect(old_num_stmt, old_num_stmt, dvs22);
+              if (dvs12.size() > 0)
+                D.push_back(
+                  std::make_pair(old_num_stmt, dvs12));
+              if (dvs21.size() > 0)
+                dep.connect(old_num_stmt, i, dvs21);
+              
+              dep.vertex[i].second.erase(j++);
+            } else {
+              dep.connect(old_num_stmt, j->first, j->second);
+              j++;
+            }
+          } else {
+            if (same_loop.find(j->first) != same_loop.end())
+              D.push_back(
+                std::make_pair(old_num_stmt, j->second));
+            j++;
+          }
+        }
+        
+        for (int j = 0; j < D.size(); j++)
+          dep.connect(i, D[j].first, D[j].second);
+      }
+    }
+  }
+  
+  return new_stmts;
+}
+
+
diff --git a/src/omegatools.cc b/src/omegatools.cc
new file mode 100644
index 0000000..3aac404
--- /dev/null
+++ b/src/omegatools.cc
@@ -0,0 +1,1185 @@
+/*****************************************************************************
+ Copyright (C) 2008 University of Southern California
+ Copyright (C) 2009-2010 University of Utah
+ All Rights Reserved.
+
+ Purpose:
+   Useful tools involving Omega manipulation.
+
+ Notes:
+
+ History:
+   01/2006 Created by Chun Chen.
+   03/2009 Upgrade Omega's interaction with compiler to IR_Code, by Chun Chen.
+*****************************************************************************/
+
+#include <code_gen/codegen.h>
+#include "omegatools.hh"
+#include "ir_code.hh"
+#include "chill_error.hh"
+
+using namespace omega;
+
+namespace {
+  struct DependenceLevel {
+    Relation r;
+    int level;
+    int dir; // direction upto current level:
+    // -1:negative, 0: undetermined, 1: postive
+    std::vector<coef_t> lbounds;
+    std::vector<coef_t> ubounds;
+    DependenceLevel(const Relation &_r, int _dims):
+      r(_r), level(0), dir(0), lbounds(_dims), ubounds(_dims) {}
+  };
+}
+
+
+
+
+std::string tmp_e() {
+  static int counter = 1;
+  return std::string("e")+to_string(counter++);
+}
+
+void exp2formula(IR_Code *ir, Relation &r, F_And *f_root, std::vector<Free_Var_Decl*> &freevars,
+                 CG_outputRepr *repr, Variable_ID lhs, char side, IR_CONDITION_TYPE rel, bool destroy) {
+  
+  switch (ir->QueryExpOperation(repr)) {
+  case IR_OP_CONSTANT:
+  {
+    std::vector<CG_outputRepr *> v = ir->QueryExpOperand(repr);
+    IR_ConstantRef *ref = static_cast<IR_ConstantRef *>(ir->Repr2Ref(v[0]));
+    if (!ref->is_integer())
+      throw ir_exp_error("non-integer constant coefficient");
+    
+    coef_t c = ref->integer();
+    if (rel == IR_COND_GE || rel == IR_COND_GT) {
+      GEQ_Handle h = f_root->add_GEQ();
+      h.update_coef(lhs, 1);
+      if (rel == IR_COND_GE)
+        h.update_const(-c);
+      else
+        h.update_const(-c-1);
+    }
+    else if (rel == IR_COND_LE || rel == IR_COND_LT) {
+      GEQ_Handle h = f_root->add_GEQ();
+      h.update_coef(lhs, -1);
+      if (rel == IR_COND_LE)
+        h.update_const(c);
+      else
+        h.update_const(c-1);
+    }
+    else if (rel == IR_COND_EQ) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(lhs, 1);
+      h.update_const(-c);
+    }
+    else
+      throw std::invalid_argument("unsupported condition type");
+    
+    delete v[0];
+    delete ref;
+    if (destroy)
+      delete repr;
+    break;
+  }
+  case IR_OP_VARIABLE:
+  {
+    std::vector<CG_outputRepr *> v = ir->QueryExpOperand(repr);
+    IR_ScalarRef *ref = static_cast<IR_ScalarRef *>(ir->Repr2Ref(v[0]));
+    
+    std::string s = ref->name();
+    Variable_ID e = find_index(r, s, side);
+    
+    if (e == NULL) { // must be free variable
+      Free_Var_Decl *t = NULL;
+      for (unsigned i = 0; i < freevars.size(); i++) {
+        std::string ss = freevars[i]->base_name();
+        if (s == ss) {
+          t = freevars[i];
+          break;
+        }
+      }
+      
+      if (t == NULL) {
+        t = new Free_Var_Decl(s);
+        freevars.insert(freevars.end(), t);
+      }
+      
+      e = r.get_local(t);
+    }
+    
+    if (rel == IR_COND_GE || rel == IR_COND_GT) {
+      GEQ_Handle h = f_root->add_GEQ();
+      h.update_coef(lhs, 1);
+      h.update_coef(e, -1);
+      if (rel == IR_COND_GT)
+        h.update_const(-1);
+    }
+    else if (rel == IR_COND_LE || rel == IR_COND_LT) {
+      GEQ_Handle h = f_root->add_GEQ();
+      h.update_coef(lhs, -1);
+      h.update_coef(e, 1);
+      if (rel == IR_COND_LT)
+        h.update_const(-1);
+    }
+    else if (rel == IR_COND_EQ) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(lhs, 1);
+      h.update_coef(e, -1);
+    }
+    else
+      throw std::invalid_argument("unsupported condition type");
+    
+    //  delete v[0];
+    delete ref;
+    if (destroy)
+      delete repr;
+    break;
+  }
+  case IR_OP_ASSIGNMENT:
+  {
+    std::vector<CG_outputRepr *> v = ir->QueryExpOperand(repr);
+    exp2formula(ir, r, f_root, freevars, v[0], lhs, side, rel, true);
+    if (destroy)
+      delete repr;
+    break;
+  }
+  case IR_OP_PLUS:
+  {
+    F_Exists *f_exists = f_root->add_exists();
+    Variable_ID e1 = f_exists->declare(tmp_e());
+    Variable_ID e2 = f_exists->declare(tmp_e());
+    F_And *f_and = f_exists->add_and();
+    
+    if (rel == IR_COND_GE || rel == IR_COND_GT) {
+      GEQ_Handle h = f_and->add_GEQ();
+      h.update_coef(lhs, 1);
+      h.update_coef(e1, -1);
+      h.update_coef(e2, -1);
+      if (rel == IR_COND_GT)
+        h.update_const(-1);
+    }
+    else if (rel == IR_COND_LE || rel == IR_COND_LT) {
+      GEQ_Handle h = f_and->add_GEQ();
+      h.update_coef(lhs, -1);
+      h.update_coef(e1, 1);
+      h.update_coef(e2, 1);
+      if (rel == IR_COND_LT)
+        h.update_const(-1);
+    }
+    else if (rel == IR_COND_EQ) {
+      EQ_Handle h = f_and->add_EQ();
+      h.update_coef(lhs, 1);
+      h.update_coef(e1, -1);
+      h.update_coef(e2, -1);
+    }
+    else
+      throw std::invalid_argument("unsupported condition type");
+    
+    std::vector<CG_outputRepr *> v = ir->QueryExpOperand(repr);
+    exp2formula(ir, r, f_and, freevars, v[0], e1, side, IR_COND_EQ, true);
+    exp2formula(ir, r, f_and, freevars, v[1], e2, side, IR_COND_EQ, true);
+    if (destroy)
+      delete repr;
+    break;
+  }
+  case IR_OP_MINUS:
+  {
+    F_Exists *f_exists = f_root->add_exists();
+    Variable_ID e1 = f_exists->declare(tmp_e());
+    Variable_ID e2 = f_exists->declare(tmp_e());
+    F_And *f_and = f_exists->add_and();
+    
+    if (rel == IR_COND_GE || rel == IR_COND_GT) {
+      GEQ_Handle h = f_and->add_GEQ();
+      h.update_coef(lhs, 1);
+      h.update_coef(e1, -1);
+      h.update_coef(e2, 1);
+      if (rel == IR_COND_GT)
+        h.update_const(-1);
+    }
+    else if (rel == IR_COND_LE || rel == IR_COND_LT) {
+      GEQ_Handle h = f_and->add_GEQ();
+      h.update_coef(lhs, -1);
+      h.update_coef(e1, 1);
+      h.update_coef(e2, -1);
+      if (rel == IR_COND_LT)
+        h.update_const(-1);
+    }
+    else if (rel == IR_COND_EQ) {
+      EQ_Handle h = f_and->add_EQ();
+      h.update_coef(lhs, 1);
+      h.update_coef(e1, -1);
+      h.update_coef(e2, 1);
+    }
+    else
+      throw std::invalid_argument("unsupported condition type");
+    
+    std::vector<CG_outputRepr *> v = ir->QueryExpOperand(repr);
+    exp2formula(ir, r, f_and, freevars, v[0], e1, side, IR_COND_EQ, true);
+    exp2formula(ir, r, f_and, freevars, v[1], e2, side, IR_COND_EQ, true);
+    if (destroy)
+      delete repr;
+    break;
+  }
+  case IR_OP_MULTIPLY:
+  {
+    std::vector<CG_outputRepr *> v = ir->QueryExpOperand(repr);
+    
+    coef_t coef;
+    CG_outputRepr *term;
+    if (ir->QueryExpOperation(v[0]) == IR_OP_CONSTANT) {
+      IR_ConstantRef *ref = static_cast<IR_ConstantRef *>(ir->Repr2Ref(v[0]));
+      coef = ref->integer();
+      delete v[0];
+      delete ref;
+      term = v[1];
+    }
+    else if (ir->QueryExpOperation(v[1]) == IR_OP_CONSTANT) {
+      IR_ConstantRef *ref = static_cast<IR_ConstantRef *>(ir->Repr2Ref(v[1]));
+      coef = ref->integer();
+      delete v[1];
+      delete ref;
+      term = v[0];
+    }
+    else
+      throw ir_exp_error("not presburger expression");
+    
+    F_Exists *f_exists = f_root->add_exists();
+    Variable_ID e = f_exists->declare(tmp_e());
+    F_And *f_and = f_exists->add_and();
+    
+    if (rel == IR_COND_GE || rel == IR_COND_GT) {
+      GEQ_Handle h = f_and->add_GEQ();
+      h.update_coef(lhs, 1);
+      h.update_coef(e, -coef);
+      if (rel == IR_COND_GT)
+        h.update_const(-1);
+    }
+    else if (rel == IR_COND_LE || rel == IR_COND_LT) {
+      GEQ_Handle h = f_and->add_GEQ();
+      h.update_coef(lhs, -1);
+      h.update_coef(e, coef);
+      if (rel == IR_COND_LT)
+        h.update_const(-1);
+    }
+    else if (rel == IR_COND_EQ) {
+      EQ_Handle h = f_and->add_EQ();
+      h.update_coef(lhs, 1);
+      h.update_coef(e, -coef);
+    }
+    else
+      throw std::invalid_argument("unsupported condition type");
+    
+    exp2formula(ir, r, f_and, freevars, term, e, side, IR_COND_EQ, true);
+    if (destroy)
+      delete repr;
+    break;
+  }
+  case IR_OP_DIVIDE:
+  {
+    std::vector<CG_outputRepr *> v = ir->QueryExpOperand(repr);
+    
+    assert(ir->QueryExpOperation(v[1]) == IR_OP_CONSTANT);
+    IR_ConstantRef *ref = static_cast<IR_ConstantRef *>(ir->Repr2Ref(v[1]));
+    coef_t coef = ref->integer();
+    delete v[1];
+    delete ref;
+    
+    F_Exists *f_exists = f_root->add_exists();
+    Variable_ID e = f_exists->declare(tmp_e());
+    F_And *f_and = f_exists->add_and();
+    
+    if (rel == IR_COND_GE || rel == IR_COND_GT) {
+      GEQ_Handle h = f_and->add_GEQ();
+      h.update_coef(lhs, coef);
+      h.update_coef(e, -1);
+      if (rel == IR_COND_GT)
+        h.update_const(-1);
+    }
+    else if (rel == IR_COND_LE || rel == IR_COND_LT) {
+      GEQ_Handle h = f_and->add_GEQ();
+      h.update_coef(lhs, -coef);
+      h.update_coef(e, 1);
+      if (rel == IR_COND_LT)
+        h.update_const(-1);
+    }
+    else if (rel == IR_COND_EQ) {
+      EQ_Handle h = f_and->add_EQ();
+      h.update_coef(lhs, coef);
+      h.update_coef(e, -1);
+    }
+    else
+      throw std::invalid_argument("unsupported condition type");
+    
+    exp2formula(ir, r, f_and, freevars, v[0], e, side, IR_COND_EQ, true);
+    if (destroy)
+      delete repr;
+    break;
+  }
+  case IR_OP_POSITIVE:
+  {
+    std::vector<CG_outputRepr *> v = ir->QueryExpOperand(repr);
+    
+    exp2formula(ir, r, f_root, freevars, v[0], lhs, side, rel, true);
+    if (destroy)
+      delete repr;
+    break;
+  }
+  case IR_OP_NEGATIVE:
+  {
+    std::vector<CG_outputRepr *> v = ir->QueryExpOperand(repr);
+    
+    F_Exists *f_exists = f_root->add_exists();
+    Variable_ID e = f_exists->declare(tmp_e());
+    F_And *f_and = f_exists->add_and();
+    
+    if (rel == IR_COND_GE || rel == IR_COND_GT) {
+      GEQ_Handle h = f_and->add_GEQ();
+      h.update_coef(lhs, 1);
+      h.update_coef(e, 1);
+      if (rel == IR_COND_GT)
+        h.update_const(-1);
+    }
+    else if (rel == IR_COND_LE || rel == IR_COND_LT) {
+      GEQ_Handle h = f_and->add_GEQ();
+      h.update_coef(lhs, -1);
+      h.update_coef(e, -1);
+      if (rel == IR_COND_LT)
+        h.update_const(-1);
+    }
+    else if (rel == IR_COND_EQ) {
+      EQ_Handle h = f_and->add_EQ();
+      h.update_coef(lhs, 1);
+      h.update_coef(e, 1);
+    }
+    else
+      throw std::invalid_argument("unsupported condition type");
+    
+    exp2formula(ir, r, f_and, freevars, v[0], e, side, IR_COND_EQ, true);
+    if (destroy)
+      delete repr;
+    break;
+  }
+  case IR_OP_MIN:
+  {
+    std::vector<CG_outputRepr *> v = ir->QueryExpOperand(repr);
+    
+    F_Exists *f_exists = f_root->add_exists();
+    
+    if (rel == IR_COND_GE || rel == IR_COND_GT) {
+      F_Or *f_or = f_exists->add_and()->add_or();
+      for (int i = 0; i < v.size(); i++) {
+        Variable_ID e = f_exists->declare(tmp_e());
+        F_And *f_and = f_or->add_and();
+        GEQ_Handle h = f_and->add_GEQ();
+        h.update_coef(lhs, 1);
+        h.update_coef(e, -1);
+        if (rel == IR_COND_GT)
+          h.update_const(-1);
+        
+        exp2formula(ir, r, f_and, freevars, v[i], e, side, IR_COND_EQ, true);
+      }
+    }
+    else if (rel == IR_COND_LE || rel == IR_COND_LT) {
+      F_And *f_and = f_exists->add_and();
+      for (int i = 0; i < v.size(); i++) {
+        Variable_ID e = f_exists->declare(tmp_e());        
+        GEQ_Handle h = f_and->add_GEQ();
+        h.update_coef(lhs, -1);
+        h.update_coef(e, 1);
+        if (rel == IR_COND_LT)
+          h.update_const(-1);
+        
+        exp2formula(ir, r, f_and, freevars, v[i], e, side, IR_COND_EQ, true);
+      }
+    }
+    else if (rel == IR_COND_EQ) {
+      F_Or *f_or = f_exists->add_and()->add_or();
+      for (int i = 0; i < v.size(); i++) {
+        Variable_ID e = f_exists->declare(tmp_e());
+        F_And *f_and = f_or->add_and();
+        
+        EQ_Handle h = f_and->add_EQ();
+        h.update_coef(lhs, 1);
+        h.update_coef(e, -1);
+        
+        exp2formula(ir, r, f_and, freevars, v[i], e, side, IR_COND_EQ, false);
+        
+        for (int j = 0; j < v.size(); j++)
+          if (j != i) {
+            Variable_ID e2 = f_exists->declare(tmp_e());
+            GEQ_Handle h2 = f_and->add_GEQ();
+            h2.update_coef(e, -1);
+            h2.update_coef(e2, 1);
+            
+            exp2formula(ir, r, f_and, freevars, v[j], e2, side, IR_COND_EQ, false);
+          }
+      }
+      
+      for (int i = 0; i < v.size(); i++)
+        delete v[i];
+    }
+    else
+      throw std::invalid_argument("unsupported condition type");
+    
+    if (destroy)
+      delete repr;
+  }
+  case IR_OP_MAX:
+  {
+    std::vector<CG_outputRepr *> v = ir->QueryExpOperand(repr);
+    
+    F_Exists *f_exists = f_root->add_exists();
+    
+    if (rel == IR_COND_LE || rel == IR_COND_LT) {
+      F_Or *f_or = f_exists->add_and()->add_or();
+      for (int i = 0; i < v.size(); i++) {
+        Variable_ID e = f_exists->declare(tmp_e());
+        F_And *f_and = f_or->add_and();
+        GEQ_Handle h = f_and->add_GEQ();
+        h.update_coef(lhs, -1);
+        h.update_coef(e, 1);
+        if (rel == IR_COND_LT)
+          h.update_const(-1);
+        
+        exp2formula(ir, r, f_and, freevars, v[i], e, side, IR_COND_EQ, true);
+      }
+    }
+    else if (rel == IR_COND_GE || rel == IR_COND_GT) {
+      F_And *f_and = f_exists->add_and();
+      for (int i = 0; i < v.size(); i++) {
+        Variable_ID e = f_exists->declare(tmp_e());        
+        GEQ_Handle h = f_and->add_GEQ();
+        h.update_coef(lhs, 1);
+        h.update_coef(e, -1);
+        if (rel == IR_COND_GT)
+          h.update_const(-1);
+        
+        exp2formula(ir, r, f_and, freevars, v[i], e, side, IR_COND_EQ, true);
+      }
+    }
+    else if (rel == IR_COND_EQ) {
+      F_Or *f_or = f_exists->add_and()->add_or();
+      for (int i = 0; i < v.size(); i++) {
+        Variable_ID e = f_exists->declare(tmp_e());
+        F_And *f_and = f_or->add_and();
+        
+        EQ_Handle h = f_and->add_EQ();
+        h.update_coef(lhs, 1);
+        h.update_coef(e, -1);
+        
+        exp2formula(ir, r, f_and, freevars, v[i], e, side, IR_COND_EQ, false);
+        
+        for (int j = 0; j < v.size(); j++)
+          if (j != i) {
+            Variable_ID e2 = f_exists->declare(tmp_e());
+            GEQ_Handle h2 = f_and->add_GEQ();
+            h2.update_coef(e, 1);
+            h2.update_coef(e2, -1);
+            
+            exp2formula(ir, r, f_and, freevars, v[j], e2, side, IR_COND_EQ, false);
+          }
+      }
+      
+      for (int i = 0; i < v.size(); i++)
+        delete v[i];
+    }
+    else
+      throw std::invalid_argument("unsupported condition type");
+    
+    if (destroy)
+      delete repr;
+  }
+  case IR_OP_NULL:
+    break;
+  default:
+    throw ir_exp_error("unsupported operand type");
+  }
+}
+
+Relation arrays2relation(IR_Code *ir, std::vector<Free_Var_Decl*> &freevars,
+                         const IR_ArrayRef *ref_src, const Relation &IS_w,
+                         const IR_ArrayRef *ref_dst, const Relation &IS_r) {
+  Relation &IS1 = const_cast<Relation &>(IS_w);
+  Relation &IS2 = const_cast<Relation &>(IS_r);
+  
+  Relation r(IS1.n_set(), IS2.n_set());
+  
+  for (int i = 1; i <= IS1.n_set(); i++)
+    r.name_input_var(i, IS1.set_var(i)->name());
+  
+  for (int i = 1; i <= IS2.n_set(); i++)
+    r.name_output_var(i, IS2.set_var(i)->name()+"'");
+  
+  IR_Symbol *sym_src = ref_src->symbol();
+  IR_Symbol *sym_dst = ref_dst->symbol();
+  if (*sym_src != *sym_dst) {
+    r.add_or(); // False Relation
+    delete sym_src;
+    delete sym_dst;
+    return r;
+  }
+  else {
+    delete sym_src;
+    delete sym_dst;
+  }
+  
+  F_And *f_root = r.add_and();
+  
+  for (int i = 0; i < ref_src->n_dim(); i++) {
+    F_Exists *f_exists = f_root->add_exists();
+    Variable_ID e1 = f_exists->declare(tmp_e());
+    Variable_ID e2 = f_exists->declare(tmp_e());
+    F_And *f_and = f_exists->add_and();
+    
+    CG_outputRepr *repr_src = ref_src->index(i);
+    CG_outputRepr *repr_dst = ref_dst->index(i);
+    
+    bool has_complex_formula = false;
+    try {
+      exp2formula(ir, r, f_and, freevars, repr_src, e1, 'w', IR_COND_EQ, false);
+      exp2formula(ir, r, f_and, freevars, repr_dst, e2, 'r', IR_COND_EQ, false);
+    }
+    catch (const ir_exp_error &e) {
+      has_complex_formula = true;
+    }
+    
+    if (!has_complex_formula) {
+      EQ_Handle h = f_and->add_EQ();
+      h.update_coef(e1, 1);
+      h.update_coef(e2, -1);
+    }
+    
+    repr_src->clear();
+    repr_dst->clear();
+    delete repr_src;
+    delete repr_dst;
+  }
+  
+  // add iteration space restriction
+  r = Restrict_Domain(r, copy(IS1));
+  r = Restrict_Range(r, copy(IS2));
+  
+  // reset the output variable names lost in restriction
+  for (int i = 1; i <= IS2.n_set(); i++)
+    r.name_output_var(i, IS2.set_var(i)->name()+"'");
+  
+  return r;
+}
+
+std::pair<std::vector<DependenceVector>, std::vector<DependenceVector> > relation2dependences (const IR_ArrayRef *ref_src, const IR_ArrayRef *ref_dst, const Relation &r) {
+  assert(r.n_inp() == r.n_out());
+  
+  std::vector<DependenceVector> dependences1, dependences2;  
+  std::stack<DependenceLevel> working;
+  working.push(DependenceLevel(r, r.n_inp()));
+  
+  while (!working.empty()) {
+    DependenceLevel dep = working.top();
+    working.pop();
+    
+    // No dependence exists, move on.
+    if (!dep.r.is_satisfiable())
+      continue;
+    
+    if (dep.level == r.n_inp()) {
+      DependenceVector dv;
+      
+      // for loop independent dependence, use lexical order to
+      // determine the correct source and destination
+      if (dep.dir == 0) {
+        if (*ref_src == *ref_dst)
+          continue; // trivial self zero-dependence
+        
+        if (ref_src->is_write()) {
+          if (ref_dst->is_write())
+            dv.type = DEP_W2W;
+          else
+            dv.type = DEP_W2R;
+        }
+        else {
+          if (ref_dst->is_write())
+            dv.type = DEP_R2W;
+          else
+            dv.type = DEP_R2R;
+        }
+        
+      }
+      else if (dep.dir == 1) {
+        if (ref_src->is_write()) {
+          if (ref_dst->is_write())
+            dv.type = DEP_W2W;
+          else
+            dv.type = DEP_W2R;
+        }
+        else {
+          if (ref_dst->is_write())
+            dv.type = DEP_R2W;
+          else
+            dv.type = DEP_R2R;
+        }
+      }
+      else { // dep.dir == -1
+        if (ref_dst->is_write()) {
+          if (ref_src->is_write())
+            dv.type = DEP_W2W;
+          else
+            dv.type = DEP_W2R;
+        }
+        else {
+          if (ref_src->is_write())
+            dv.type = DEP_R2W;
+          else
+            dv.type = DEP_R2R;
+        }
+      }
+      
+      dv.lbounds = dep.lbounds;
+      dv.ubounds = dep.ubounds;
+      dv.sym = ref_src->symbol();
+      
+      if (dep.dir == 0 || dep.dir == 1)
+        dependences1.push_back(dv);
+      else
+        dependences2.push_back(dv);
+    }
+    else {
+      // now work on the next dimension level
+      int level = ++dep.level;
+      
+      coef_t lbound, ubound;
+      Relation delta = Deltas(copy(dep.r));
+      delta.query_variable_bounds(delta.set_var(level), lbound, ubound);
+      
+      if (dep.dir == 0) {
+        if (lbound > 0) {
+          dep.dir = 1;
+          dep.lbounds[level-1] = lbound;
+          dep.ubounds[level-1] = ubound;
+          
+          working.push(dep);
+        }
+        else if (ubound < 0) {
+          dep.dir = -1;
+          dep.lbounds[level-1] = -ubound;
+          dep.ubounds[level-1] = -lbound;
+          
+          working.push(dep);
+        }
+        else {
+          // split the dependence vector into flow- and anti-dependence
+          // for the first non-zero distance, also separate zero distance
+          // at this level.
+          {
+            DependenceLevel dep2 = dep;
+            
+            dep2.lbounds[level-1] =  0;
+            dep2.ubounds[level-1] =  0;
+            
+            F_And *f_root = dep2.r.and_with_and();
+            EQ_Handle h = f_root->add_EQ();
+            h.update_coef(dep2.r.input_var(level), 1);
+            h.update_coef(dep2.r.output_var(level), -1);
+            
+            working.push(dep2);
+          }
+          
+          if (lbound < 0 && *ref_src != *ref_dst) {
+            DependenceLevel dep2 = dep;
+            
+            F_And *f_root = dep2.r.and_with_and();
+            GEQ_Handle h = f_root->add_GEQ();
+            h.update_coef(dep2.r.input_var(level), 1);
+            h.update_coef(dep2.r.output_var(level), -1);
+            h.update_const(-1);
+            
+            // get tighter bounds under new constraints
+            coef_t lbound, ubound;
+            delta = Deltas(copy(dep2.r));
+            delta.query_variable_bounds(delta.set_var(level),
+                                        lbound, ubound);
+            
+            dep2.dir = -1;            
+            dep2.lbounds[level-1] = max(-ubound,static_cast<coef_t>(1)); // use max() to avoid Omega retardness
+            dep2.ubounds[level-1] = -lbound;
+            
+            working.push(dep2);
+          }
+          
+          if (ubound > 0) {
+            DependenceLevel dep2 = dep;
+            
+            F_And *f_root = dep2.r.and_with_and();
+            GEQ_Handle h = f_root->add_GEQ();
+            h.update_coef(dep2.r.input_var(level), -1);
+            h.update_coef(dep2.r.output_var(level), 1);
+            h.update_const(-1);
+            
+            // get tighter bonds under new constraints
+            coef_t lbound, ubound;
+            delta = Deltas(copy(dep2.r));
+            delta.query_variable_bounds(delta.set_var(level),
+                                        lbound, ubound);
+            dep2.dir = 1;
+            dep2.lbounds[level-1] = max(lbound,static_cast<coef_t>(1)); // use max() to avoid Omega retardness
+            dep2.ubounds[level-1] = ubound;
+            
+            working.push(dep2);
+          }
+        }
+      }
+      // now deal with dependence vector with known direction
+      // determined at previous levels
+      else {
+        // For messy bounds, further test to see if the dependence distance
+        // can be reduced to positive/negative.  This is an omega hack.
+        if (lbound == negInfinity && ubound == posInfinity) {
+          {
+            Relation t = dep.r;
+            F_And *f_root = t.and_with_and();
+            GEQ_Handle h = f_root->add_GEQ();
+            h.update_coef(t.input_var(level), 1);
+            h.update_coef(t.output_var(level), -1);
+            h.update_const(-1);
+            
+            if (!t.is_satisfiable()) {
+              lbound = 0;
+            }
+          }
+          {
+            Relation t = dep.r;
+            F_And *f_root = t.and_with_and();
+            GEQ_Handle h = f_root->add_GEQ();
+            h.update_coef(t.input_var(level), -1);
+            h.update_coef(t.output_var(level), 1);
+            h.update_const(-1);
+            
+            if (!t.is_satisfiable()) {
+              ubound = 0;
+            }
+          }
+        }
+        
+        // Same thing as above, test to see if zero dependence
+        // distance possible.
+        if (lbound == 0 || ubound == 0) {
+          Relation t = dep.r;
+          F_And *f_root = t.and_with_and();
+          EQ_Handle h = f_root->add_EQ();
+          h.update_coef(t.input_var(level), 1);
+          h.update_coef(t.output_var(level), -1);
+          
+          if (!t.is_satisfiable()) {
+            if (lbound == 0)
+              lbound = 1;
+            if (ubound == 0)
+              ubound = -1;
+          }
+        }
+        
+        if (dep.dir == -1) {
+          dep.lbounds[level-1] = -ubound;
+          dep.ubounds[level-1] = -lbound;
+        }
+        else { // dep.dir == 1
+          dep.lbounds[level-1] = lbound;
+          dep.ubounds[level-1] = ubound;
+        }
+        
+        working.push(dep);
+      }
+    }
+  }
+  
+  return std::make_pair(dependences1, dependences2);
+}
+
+void exp2constraint(IR_Code *ir, Relation &r, F_And *f_root,
+                    std::vector<Free_Var_Decl *> &freevars,
+                    CG_outputRepr *repr, bool destroy) {
+  IR_CONDITION_TYPE cond = ir->QueryBooleanExpOperation(repr);
+  switch (cond) {
+  case IR_COND_LT:
+  case IR_COND_LE:
+  case IR_COND_EQ:
+  case IR_COND_GT:
+  case IR_COND_GE: {
+    F_Exists *f_exist = f_root->add_exists();
+    Variable_ID e = f_exist->declare();
+    F_And *f_and = f_exist->add_and();
+    std::vector<omega::CG_outputRepr *> op = ir->QueryExpOperand(repr);
+    exp2formula(ir, r, f_and, freevars, op[0], e, 's', IR_COND_EQ, true);
+    exp2formula(ir, r, f_and, freevars, op[1], e, 's', cond, true);
+    if (destroy)
+      delete repr;
+    break;
+  }
+  case IR_COND_NE: {
+    F_Exists *f_exist = f_root->add_exists();
+    Variable_ID e = f_exist->declare();
+    F_Or *f_or = f_exist->add_or();
+    F_And *f_and = f_or->add_and();
+    std::vector<omega::CG_outputRepr *> op = ir->QueryExpOperand(repr);
+    exp2formula(ir, r, f_and, freevars, op[0], e, 's', IR_COND_EQ, false);
+    exp2formula(ir, r, f_and, freevars, op[1], e, 's', IR_COND_GT, false);
+    
+    f_and = f_or->add_and();
+    exp2formula(ir, r, f_and, freevars, op[0], e, 's', IR_COND_EQ, true);
+    exp2formula(ir, r, f_and, freevars, op[1], e, 's', IR_COND_LT, true);
+    
+    if (destroy)
+      delete repr;
+    break;
+  }    
+  default:
+    throw ir_exp_error("unrecognized conditional expression");
+  }
+}
+
+bool is_single_loop_iteration(const Relation &r, int level, const Relation &known) {
+  int n = r.n_set();
+  Relation r1 = Intersection(copy(r), Extend_Set(copy(known), n-known.n_set()));
+  
+  Relation mapping(n, n);
+  F_And *f_root = mapping.add_and();
+  for (int i = 1; i <= level; i++) {
+    EQ_Handle h = f_root->add_EQ();
+    h.update_coef(mapping.input_var(i), 1);
+    h.update_coef(mapping.output_var(i), -1);
+  }
+  r1 = Range(Restrict_Domain(mapping, r1));
+  r1.simplify();
+  
+  Variable_ID v = r1.set_var(level);
+  for (DNF_Iterator di(r1.query_DNF()); di; di++) {
+    bool is_single = false;
+    for (EQ_Iterator ei((*di)->EQs()); ei; ei++)
+      if ((*ei).get_coef(v) != 0 && !(*ei).has_wildcards()) {
+        is_single = true;
+        break;
+      }
+    
+    if (!is_single)
+      return false;
+  }
+  
+  return true;
+}
+
+
+bool is_single_iteration(const Relation &r, int dim) {
+  assert(r.is_set());
+  const int n = r.n_set();
+  
+  if (dim >= n)
+    return true;
+  
+  Relation bound = get_loop_bound(r, dim);
+  
+  for (DNF_Iterator di(bound.query_DNF()); di; di++) {
+    bool is_single = false;
+    for (EQ_Iterator ei((*di)->EQs()); ei; ei++)
+      if (!(*ei).has_wildcards()) {
+        is_single = true;
+        break;
+      }
+    
+    if (!is_single)
+      return false;
+  }
+  
+  return true;
+}
+
+void assign_const(Relation &r, int dim, int val) {
+  const int n = r.n_out();
+  
+  Relation mapping(n, n);
+  F_And *f_root = mapping.add_and();
+  
+  for (int i = 1; i <= n; i++) {
+    if (i != dim+1) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(mapping.output_var(i), 1);
+      h.update_coef(mapping.input_var(i), -1);
+    }
+    else {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(mapping.output_var(i), 1);
+      h.update_const(-val);
+    }
+  }
+  
+  r = Composition(mapping, r);
+}
+
+
+int get_const(const Relation &r, int dim, Var_Kind type) {
+  Relation &rr = const_cast<Relation &>(r);
+  
+  Variable_ID v;
+  switch (type) {
+  case Input_Var:
+    v = rr.input_var(dim+1);
+    break;
+  case Output_Var:
+    v = rr.output_var(dim+1);
+    break;
+  default:
+    throw std::invalid_argument("unsupported variable type");
+  }
+  
+  for (DNF_Iterator di(rr.query_DNF()); di; di++)
+    for (EQ_Iterator ei = (*di)->EQs(); ei; ei++)
+      if ((*ei).is_const(v))
+        return (*ei).get_const();
+  
+  throw std::runtime_error("cannot get variable's constant value");
+}
+
+Relation get_loop_bound(const Relation &r, int dim) {
+  assert(r.is_set());
+  const int n = r.n_set();
+  
+  Relation mapping(n,n);
+  F_And *f_root = mapping.add_and();
+  for (int i = 1; i <= dim+1; i++) {
+    EQ_Handle h = f_root->add_EQ();
+    h.update_coef(mapping.input_var(i), 1);
+    h.update_coef(mapping.output_var(i), -1);
+  }
+  Relation r1 = Range(Restrict_Domain(mapping, copy(r)));
+  for (int i = 1; i <= n; i++)
+    r1.name_set_var(i, const_cast<Relation &>(r).set_var(i)->name());
+  r1.setup_names();
+  Relation r2 = Project(copy(r1), dim+1, Set_Var);
+  
+  return Gist(r1, r2, 1);
+}
+
+Relation get_loop_bound(const Relation &r, int level, const Relation &known) {
+  int n = r.n_set();
+  Relation r1 = Intersection(copy(r), Extend_Set(copy(known), n-known.n_set()));
+  
+  Relation mapping(n, n);
+  F_And *f_root = mapping.add_and();
+  for (int i = 1; i <= level; i++) {
+    EQ_Handle h = f_root->add_EQ();
+    h.update_coef(mapping.input_var(i), 1);
+    h.update_coef(mapping.output_var(i), -1);
+  }
+  r1 = Range(Restrict_Domain(mapping, r1));
+  Relation r2 = Project(copy(r1), level, Set_Var);
+  r1 = Gist(r1, r2, 1);
+  
+  for (int i = 1; i <= n; i++)
+    r1.name_set_var(i, const_cast<Relation &>(r).set_var(i)->name());
+  r1.setup_names();
+  
+  return r1;
+}
+
+
+
+Relation get_max_loop_bound(const std::vector<Relation> &r, int dim) {
+  if (r.size() == 0)
+    return Relation::Null();
+  
+  const int n = r[0].n_set();
+  Relation res(Relation::False(n));
+  for (int i = 0; i < r.size(); i++) {
+    Relation &t = const_cast<Relation &>(r[i]);
+    if (t.is_satisfiable())
+      res = Union(get_loop_bound(t, dim), res);
+  }
+  
+  res.simplify();
+  
+  return res;
+}
+
+Relation get_min_loop_bound(const std::vector<Relation> &r, int dim) {
+  if (r.size() == 0)
+    return Relation::Null();
+  
+  const int n = r[0].n_set();
+  Relation res(Relation::True(n));
+  for (int i = 0; i < r.size(); i++) {
+    Relation &t = const_cast<Relation &>(r[i]);
+    if (t.is_satisfiable())
+      res = Intersection(get_loop_bound(t, dim), res);
+  }
+  
+  res.simplify();
+  
+  return res;
+}
+
+void add_loop_stride(Relation &r, const Relation &bound_, int dim, int stride) {
+  F_And *f_root = r.and_with_and();
+  Relation &bound = const_cast<Relation &>(bound_);
+  for (DNF_Iterator di(bound.query_DNF()); di; di++) {
+    F_Exists *f_exists = f_root->add_exists();
+    Variable_ID e1 = f_exists->declare(tmp_e());
+    Variable_ID e2 = f_exists->declare(tmp_e());
+    F_And *f_and = f_exists->add_and();
+    EQ_Handle stride_eq = f_and->add_EQ();
+    stride_eq.update_coef(e1, 1);
+    stride_eq.update_coef(e2, stride);
+    if (!r.is_set())
+      stride_eq.update_coef(r.output_var(dim+1), -1);
+    else
+      stride_eq.update_coef(r.set_var(dim+1), -1);
+    F_Or *f_or = f_and->add_or();
+    
+    for (GEQ_Iterator gi = (*di)->GEQs(); gi; gi++) {
+      if ((*gi).get_coef(bound.set_var(dim+1)) > 0) {
+        // copy the lower bound constraint
+        EQ_Handle h1 = f_or->add_and()->add_EQ();
+        GEQ_Handle h2 = f_and->add_GEQ();
+        for (Constr_Vars_Iter ci(*gi); ci; ci++) {
+          switch ((*ci).var->kind()) {
+            // case Set_Var:
+          case Input_Var: {
+            int pos = (*ci).var->get_position();
+            if (pos == dim + 1) {
+              h1.update_coef(e1, (*ci).coef);
+              h2.update_coef(e1, (*ci).coef);
+            }
+            else {
+              if (!r.is_set()) {
+                h1.update_coef(r.output_var(pos), (*ci).coef);
+                h2.update_coef(r.output_var(pos), (*ci).coef);
+              }
+              else {
+                h1.update_coef(r.set_var(pos), (*ci).coef);
+                h2.update_coef(r.set_var(pos), (*ci).coef);
+              }                
+            }
+            break;
+          }
+          case Global_Var: {
+            Global_Var_ID g = (*ci).var->get_global_var();
+            h1.update_coef(r.get_local(g, (*ci).var->function_of()), (*ci).coef);
+            h2.update_coef(r.get_local(g, (*ci).var->function_of()), (*ci).coef);
+            break;
+          }
+          default:
+            break;
+          }
+        }
+        h1.update_const((*gi).get_const());
+        h2.update_const((*gi).get_const());
+      }
+    }
+  }
+}
+
+
+bool is_inner_loop_depend_on_level(const Relation &r, int level, const Relation &known) {
+  Relation r1 = Intersection(copy(r), Extend_Set(copy(known), r.n_set()-known.n_set()));
+  Relation r2 = copy(r1);
+  for (int i = level+1; i <= r2.n_set(); i++)
+    r2 = Project(r2, r2.set_var(i));
+  r2.simplify(2, 4);
+  Relation r3 = Gist(r1, r2);
+  
+  Variable_ID v = r3.set_var(level);
+  for (DNF_Iterator di(r3.query_DNF()); di; di++) {
+    for (EQ_Iterator ei = (*di)->EQs(); ei; ei++)
+      if ((*ei).get_coef(v) != 0)
+        return true;
+    
+    for (GEQ_Iterator gi = (*di)->GEQs(); gi; gi++)
+      if ((*gi).get_coef(v) != 0)
+        return true;
+  }
+  
+  return false;
+}
+
+Relation adjust_loop_bound(const Relation &r, int level, int adjustment) {
+  if (adjustment == 0)
+    return copy(r);
+  
+  const int n = r.n_set();
+  Relation r1 = copy(r);
+  for (int i = level+1; i <= r1.n_set(); i++)
+    r1 = Project(r1, r1.set_var(i));
+  r1.simplify(2, 4);
+  Relation r2 = Gist(copy(r), copy(r1));
+  
+  Relation mapping(n, n);
+  F_And *f_root = mapping.add_and();
+  for (int i = 1; i <= n; i++)
+    if (i == level) {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(mapping.input_var(level), -1);
+      h.update_coef(mapping.output_var(level), 1);
+      h.update_const(static_cast<coef_t>(adjustment));
+    }
+    else {
+      EQ_Handle h = f_root->add_EQ();
+      h.update_coef(mapping.input_var(i), -1);
+      h.update_coef(mapping.output_var(i), 1);
+    }
+  
+  r2 = Range(Restrict_Domain(mapping, r2));
+  r1 = Intersection(r1, r2);
+  r1.simplify();
+  
+  for (int i = 1; i <= n; i++)
+    r1.name_set_var(i, const_cast<Relation &>(r).set_var(i)->name());
+  r1.setup_names();
+  return r1;
+}
+
+Relation permute_relation(const std::vector<int> &pi) {
+  const int n = pi.size();
+  
+  Relation r(n, n);
+  F_And *f_root = r.add_and();
+  
+  for (int i = 0; i < n; i++) {    
+    EQ_Handle h = f_root->add_EQ();
+    h.update_coef(r.output_var(i+1), 1);
+    h.update_coef(r.input_var(pi[i]+1), -1);
+  }
+  
+  return r;
+}
+
+Variable_ID find_index(Relation &r, const std::string &s, char side) {
+  // Omega quirks: assure the names are propagated inside the relation
+  r.setup_names();
+  
+  if (r.is_set()) { // side == 's'
+    for (int i = 1; i <= r.n_set(); i++) {
+      std::string ss = r.set_var(i)->name();
+      if (s == ss) {
+        return r.set_var(i);
+      }
+    }
+  }
+  else if (side == 'w') {
+    for (int i = 1; i <= r.n_inp(); i++) {
+      std::string ss = r.input_var(i)->name();
+      if (s == ss) {
+        return r.input_var(i);
+      }
+    }
+  }
+  else { // side == 'r'
+    for (int i = 1; i <= r.n_out(); i++) {
+      std::string ss = r.output_var(i)->name();
+      if (s+"'" == ss) {
+        return r.output_var(i);
+      }
+    }
+  }
+  
+  return NULL;
+}
+
diff --git a/src/parse_expr.ll b/src/parse_expr.ll
new file mode 100644
index 0000000..a9b389f
--- /dev/null
+++ b/src/parse_expr.ll
@@ -0,0 +1,24 @@
+%{
+// some C++ code
+#include "chill_run_util.hh"
+#include "parse_expr.tab.hh"
+%}
+
+%option noyywrap
+
+%%
+[ \t]+                  /*ignore*/
+\n                      /*ignore*/
+L[0-9]+                 { yylval.val = atoi(&yytext[1]); return LEVEL; }
+[0-9]+                  { yylval.val = atoi(yytext); return NUMBER; }
+\<\=                    return LE;
+\>\=                    return GE;
+\=(\=)?                 return EQ;
+[a-zA-Z_][a-zA-Z_0-9]*  {
+                           yylval.str_val = new char[yyleng+1];
+                           strcpy(yylval.str_val, yytext);
+                           return VARIABLE;
+                         }
+.                        return (int)yytext[0];
+%%
+
diff --git a/src/parse_expr.yy b/src/parse_expr.yy
new file mode 100644
index 0000000..c2943c2
--- /dev/null
+++ b/src/parse_expr.yy
@@ -0,0 +1,85 @@
+%{
+#include "chill_run_util.hh"
+#include "parse_expr.ll.hh"
+
+extern int yydebug;
+
+void yyerror(const char*);
+int yyparse(simap_vec_t** rel);
+
+static simap_vec_t* return_rel; // used as the return value for yyparse
+
+%}
+
+%union {
+  int val;
+  char* str_val;
+  simap_t* cond_item;
+  simap_vec_t* cond;
+}
+
+%token <val> NUMBER
+%token <val> LEVEL
+%token <str_val> VARIABLE
+
+%left LE GE EQ '<' '>'
+%left '-' '+' '*' '/'
+
+/*the final output from this language should be an Omega Relation object*/
+%type <cond> cond prog
+%type <cond_item> expr add_expr mul_expr neg_expr
+
+%%
+prog : cond                      { return_rel = make_prog($1); }
+;
+
+cond : expr '>' expr             { $$ = make_cond_gt($1, $3); }
+     | expr '<' expr             { $$ = make_cond_lt($1, $3); }
+     | expr GE expr              { $$ = make_cond_ge($1, $3); }
+     | expr LE expr              { $$ = make_cond_le($1, $3); }
+     | expr EQ expr              { $$ = make_cond_eq($1, $3); }
+;
+
+expr : add_expr                  { $$ = $1; }
+;
+
+add_expr : add_expr '+' mul_expr { $$ = make_cond_item_add($1,$3); }
+         | add_expr '-' mul_expr { $$ = make_cond_item_sub($1,$3); }
+         | mul_expr              { $$ = $1; }
+;
+
+mul_expr : mul_expr '*' neg_expr { $$ = make_cond_item_mul($1,$3); }
+         | neg_expr              { $$ = $1; }
+;
+
+neg_expr : '-' neg_expr          { $$ = make_cond_item_neg($2); }
+         | '(' expr ')'          { $$ = $2; }
+         | NUMBER                { $$ = make_cond_item_number($1); }
+         | LEVEL                 { $$ = make_cond_item_level($1); }
+         | VARIABLE              { $$ = make_cond_item_variable($1); }
+;
+%%
+
+void yyerror(const char* msg) {
+  fprintf(stderr, "Parse error: %s", msg);
+}
+
+simap_vec_t* parse_relation_vector(const char* expr) {
+  yydebug=0;
+  YY_BUFFER_STATE state;
+  
+  //if(yylex_init()) {
+  //   TODO: error out or something
+  //}
+  
+  state = yy_scan_string(expr);
+  
+  if(yyparse()) {
+    // TODO: error out or something
+  }
+  
+  yy_delete_buffer(state);
+  yylex_destroy();
+  return return_rel;
+}
+
-- 
cgit v1.2.3-70-g09d2