From 0516e6f21f9a99931f4cea789e4cf031e49656b5 Mon Sep 17 00:00:00 2001
From: Arie Gurfinkel <arie.gurfinkel@uwaterloo.ca>
Date: Tue, 24 Jul 2018 11:45:40 -0400
Subject: [PATCH] Integrating synchronize pass

---
 src/muz/transforms/dl_mk_synchronize.cpp | 174 +++++++++++------------
 src/muz/transforms/dl_mk_synchronize.h   |  30 ++--
 2 files changed, 105 insertions(+), 99 deletions(-)

diff --git a/src/muz/transforms/dl_mk_synchronize.cpp b/src/muz/transforms/dl_mk_synchronize.cpp
index f691b69d8..268c994d1 100644
--- a/src/muz/transforms/dl_mk_synchronize.cpp
+++ b/src/muz/transforms/dl_mk_synchronize.cpp
@@ -22,6 +22,8 @@ Revision History:
 
 namespace datalog {
 
+    typedef mk_synchronize::item_set_vector item_set_vector;
+
     mk_synchronize::mk_synchronize(context& ctx, unsigned priority):
         rule_transformer::plugin(priority, false),
         m_ctx(ctx),
@@ -29,15 +31,16 @@ namespace datalog {
         rm(ctx.get_rule_manager())
     {}
 
-    bool mk_synchronize::is_recursive_app(rule & r, app * app) const {
-        func_decl* head_decl = r.get_head()->get_decl();
-        func_decl* app_decl = app->get_decl();
-        if (head_decl == app_decl) {
-            return true;
-        }
-        rule_stratifier::comp_vector const & strata = m_stratifier->get_strats();
-        unsigned num_of_stratum = m_stratifier->get_predicate_strat(head_decl);
-        return strata[num_of_stratum]->contains(app_decl);
+    bool mk_synchronize::is_recursive(rule &r, func_decl &decl) const {
+        func_decl *hdecl = r.get_head()->get_decl();
+        // AG: shouldn't decl appear in the body?
+        if (hdecl == &decl)  return true;
+        auto & strata = m_stratifier->get_strats();
+        unsigned num_of_stratum = m_stratifier->get_predicate_strat(hdecl);
+        return strata[num_of_stratum]->contains(&decl);
+    }
+    bool mk_synchronize::is_recursive(rule &r, expr &e) const {
+        return is_app(&e) && is_recursive(r, *to_app(&e)->get_decl());
     }
 
     bool mk_synchronize::has_recursive_premise(app * app) const {
@@ -50,33 +53,29 @@ namespace datalog {
         return strata[num_of_stratum]->size() > 1;
     }
 
-    ptr_vector<rule_stratifier::item_set> mk_synchronize::add_merged_decls(ptr_vector<app> & apps) {
-        unsigned n = apps.size();
-        ptr_vector<rule_stratifier::item_set> merged_decls;
-        merged_decls.resize(n);
-        ptr_vector<func_decl> app_decls;
-        app_decls.resize(n);
-        for (unsigned j = 0; j < n; ++j) {
-            app_decls[j] = apps[j]->get_decl();
-        }
-        rule_stratifier::comp_vector const & strata = m_stratifier->get_strats();
-        for (unsigned j = 0; j < n; ++j) {
-            unsigned num_of_stratum = m_stratifier->get_predicate_strat(app_decls[j]);
-            merged_decls[j] = strata[num_of_stratum];
+    item_set_vector mk_synchronize::add_merged_decls(ptr_vector<app> & apps) {
+        unsigned sz = apps.size();
+        item_set_vector merged_decls;
+        merged_decls.resize(sz);
+        auto & strata = m_stratifier->get_strats();
+        for (unsigned j = 0; j < sz; ++j) {
+            unsigned nos;
+            nos = m_stratifier->get_predicate_strat(apps[j]->get_decl());
+            merged_decls[j] = strata[nos];
         }
         return merged_decls;
     }
 
-    void mk_synchronize::add_new_rel_symbols(unsigned idx, ptr_vector<rule_stratifier::item_set> const & decls,
-            ptr_vector<func_decl> & decls_buf, bool & was_added) {
+    void mk_synchronize::add_new_rel_symbols(unsigned idx,
+                                             item_set_vector const & decls,
+                                             ptr_vector<func_decl> & decls_buf,
+                                             bool & was_added) {
         if (idx >= decls.size()) {
             string_buffer<> buffer;
             ptr_vector<sort> domain;
-            ptr_vector<func_decl>::const_iterator it = decls_buf.begin(), end = decls_buf.end();
-            for (; it != end; ++it) {
-                buffer << (*it)->get_name();
-                buffer << "!!";
-                domain.append((*it)->get_arity(), (*it)->get_domain());
+            for (auto &d : decls_buf) {
+                buffer << d->get_name() << "!!";
+                domain.append(d->get_arity(), d->get_domain());
             }
 
             symbol new_name = symbol(buffer.c_str());
@@ -84,6 +83,7 @@ namespace datalog {
             if (!cache.contains(new_name)) {
                 was_added = true;
                 func_decl* orig = decls_buf[0];
+                // AG : is this ref counted
                 func_decl* product_pred = m_ctx.mk_fresh_head_predicate(new_name,
                     symbol::null, domain.size(), domain.c_ptr(), orig);
                 cache.insert(new_name, product_pred);
@@ -91,15 +91,16 @@ namespace datalog {
             return;
         }
 
-        rule_stratifier::item_set const & pred_decls = *decls[idx];
-        for (rule_stratifier::item_set::iterator it = pred_decls.begin(); it != pred_decls.end(); ++it) {
-            decls_buf[idx] = *it;
+        // AG: why recursive?
+        for (auto &p : *decls[idx]) {
+            decls_buf[idx] = p;
             add_new_rel_symbols(idx + 1, decls, decls_buf, was_added);
         }
     }
 
-    void mk_synchronize::replace_applications(rule & r, rule_set & rules, ptr_vector<app> & apps) {
-        app* replacing = product_application(apps);
+    void mk_synchronize::replace_applications(rule & r, rule_set & rules,
+                                              ptr_vector<app> & apps) {
+        app_ref replacing = product_application(apps);
 
         ptr_vector<app> new_tail;
         svector<bool> new_tail_neg;
@@ -135,7 +136,10 @@ namespace datalog {
         rules.replace_rule(&r, new_rule.get());
     }
 
-    rule_ref mk_synchronize::rename_bound_vars_in_rule(rule * r, unsigned & var_idx) {
+    rule_ref mk_synchronize::rename_bound_vars_in_rule(rule * r,
+                                                       unsigned & var_idx) {
+        // AG: shift all variables in a rule so that lowest var index is var_idx?
+        // AG: update var_idx in the process?
         ptr_vector<sort> sorts;
         r->get_vars(m, sorts);
         expr_ref_vector revsub(m);
@@ -152,17 +156,18 @@ namespace datalog {
         return new_rule;
     }
 
-    vector<rule_ref_vector> mk_synchronize::rename_bound_vars(ptr_vector<rule_stratifier::item_set> const & heads,
-            rule_set & rules) {
+    vector<rule_ref_vector> mk_synchronize::rename_bound_vars(item_set_vector const & heads,
+                                                              rule_set & rules) {
+        // AG: is every item_set in heads corresponds to rules that are merged?
+        // AG: why are bound variables renamed in the first place?
+        // AG: the data structure seems too complex
         vector<rule_ref_vector> result;
         unsigned var_idx = 0;
-        for (unsigned i = 0; i < heads.size(); ++i) {
+        for (auto item : heads) {
             rule_ref_vector dst_vector(rm);
-            for (rule_stratifier::item_set::iterator it = heads[i]->begin(); it != heads[i]->end(); ++it) {
-                func_decl * head = *it;
-                rule_vector const & src_rules = rules.get_predicate_rules(head);
-                for (unsigned j = 0; j < src_rules.size(); ++j) {
-                    rule_ref new_rule = rename_bound_vars_in_rule(src_rules[j], var_idx);
+            for (auto *head : *item) {
+                for (auto *r : rules.get_predicate_rules(head)) {
+                    rule_ref new_rule = rename_bound_vars_in_rule(r, var_idx);
                     dst_vector.push_back(new_rule.get());
                 }
             }
@@ -171,9 +176,11 @@ namespace datalog {
         return result;
     }
 
-    void mk_synchronize::add_rec_tail(vector< ptr_vector<app> > & recursive_calls, ptr_vector<app> & new_tail,
-            svector<bool> & new_tail_neg, unsigned & tail_idx) {
-        int max_size = recursive_calls[0].size();
+    void mk_synchronize::add_rec_tail(vector< ptr_vector<app> > & recursive_calls,
+                                      app_ref_vector & new_tail,
+                                      svector<bool> & new_tail_neg,
+                                      unsigned & tail_idx) {
+        int max_size = 0;
         unsigned n = recursive_calls.size();
         for (unsigned i = 0; i < n; ++i) {
             if (recursive_calls[i].size() > max_size) {
@@ -194,11 +201,12 @@ namespace datalog {
         }
     }
 
-    void mk_synchronize::add_non_rec_tail(rule & r, ptr_vector<app> & new_tail, svector<bool> & new_tail_neg,
-        unsigned & tail_idx) {
+    void mk_synchronize::add_non_rec_tail(rule & r, app_ref_vector & new_tail,
+                                          svector<bool> & new_tail_neg,
+                                          unsigned & tail_idx) {
         for (unsigned i = 0; i < r.get_positive_tail_size(); ++i) {
             app* tail = r.get_tail(i);
-            if (!is_recursive_app(r, tail)) {
+            if (!is_recursive(r, *tail)) {
                 ++tail_idx;
                 new_tail[tail_idx] = tail;
                 new_tail_neg[tail_idx] = false;
@@ -216,15 +224,14 @@ namespace datalog {
         }
     }
 
-    app* mk_synchronize::product_application(ptr_vector<app> const &apps) {
-        ptr_vector<app>::const_iterator it = apps.begin(), end = apps.end();
+    app_ref mk_synchronize::product_application(ptr_vector<app> const &apps) {
         unsigned args_num = 0;
         string_buffer<> buffer;
 
-        for (; it != end; ++it) {
-            buffer << (*it)->get_decl()->get_name();
-            buffer << "!!";
-            args_num += (*it)->get_num_args();
+        // AG: factor out into mk_name
+        for (auto *app : apps) {
+            buffer << app->get_decl()->get_name() << "!!";
+            args_num += app->get_num_args();
         }
 
         symbol name = symbol(buffer.c_str());
@@ -233,15 +240,13 @@ namespace datalog {
 
         ptr_vector<expr> args;
         args.resize(args_num);
-        it = apps.begin();
-        for (unsigned args_idx = 0; it != end; ++it) {
-            app* a = *it;
-            for (unsigned i = 0; i < a->get_num_args(); ++i, ++args_idx) {
-                args[args_idx] = a->get_arg(i);
-            }
+        unsigned idx = 0;
+        for (auto *a : apps) {
+            for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i, ++idx)
+                args[idx] = a->get_arg(i);
         }
 
-        return m.mk_app(pred, args_num, args.c_ptr());
+        return app_ref(m.mk_app(pred, args_num, args.c_ptr()), m);
     }
 
     rule_ref mk_synchronize::product_rule(rule_ref_vector const & rules) {
@@ -261,7 +266,7 @@ namespace datalog {
         for (unsigned i = 0; i < n; ++i) {
             heads[i] = rules[i]->get_head();
         }
-        app* product_head = product_application(heads);
+        app_ref product_head = product_application(heads);
         unsigned product_tail_length = 0;
         bool has_recursion = false;
         vector< ptr_vector<app> > recursive_calls;
@@ -271,7 +276,7 @@ namespace datalog {
             product_tail_length += rule.get_tail_size();
             for (unsigned j = 0; j < rule.get_positive_tail_size(); ++j) {
                 app* tail = rule.get_tail(j);
-                if (is_recursive_app(rule, tail)) {
+                if (is_recursive(rule, *tail)) {
                     has_recursion = true;
                     recursive_calls[i].push_back(tail);
                 }
@@ -281,7 +286,7 @@ namespace datalog {
             }
         }
 
-        ptr_vector<app> new_tail;
+        app_ref_vector new_tail(m);
         svector<bool> new_tail_neg;
         new_tail.resize(product_tail_length);
         new_tail_neg.resize(product_tail_length);
@@ -302,41 +307,36 @@ namespace datalog {
         return new_rule;
     }
 
-    void mk_synchronize::merge_rules(unsigned idx, rule_ref_vector & buf, vector<rule_ref_vector> const & merged_rules,
-            rule_set & all_rules) {
+    void mk_synchronize::merge_rules(unsigned idx, rule_ref_vector & buf,
+                                     vector<rule_ref_vector> const & merged_rules,
+                                     rule_set & all_rules) {
         if (idx >= merged_rules.size()) {
             rule_ref product = product_rule(buf);
             all_rules.add_rule(product.get());
             return;
         }
 
-        rule_ref_vector const & pred_rules = merged_rules[idx];
-        for (rule_ref_vector::iterator it = pred_rules.begin(); it != pred_rules.end(); ++it) {
-            buf[idx] = *it;
+        for (auto *r : merged_rules[idx]) {
+            buf[idx] = r;
             merge_rules(idx + 1, buf, merged_rules, all_rules);
         }
     }
 
     void mk_synchronize::merge_applications(rule & r, rule_set & rules) {
-        ptr_vector<app> non_recursive_applications;
+        ptr_vector<app> non_recursive_preds;
         obj_hashtable<app> apps;
         for (unsigned i = 0; i < r.get_positive_tail_size(); ++i) {
-            app* application = r.get_tail(i);
-            if (!is_recursive_app(r, application) && has_recursive_premise(application)) {
-                apps.insert(application);
+            app* t = r.get_tail(i);
+            if (!is_recursive(r, *t) && has_recursive_premise(t)) {
+                apps.insert(t);
             }
         }
-        if (apps.size() < 2) {
-            return;
-        }
+        if (apps.size() < 2) return;
+        for (auto *a : apps) non_recursive_preds.push_back(a);
 
-        for (obj_hashtable<app>::iterator it = apps.begin(); it != apps.end(); it++) {
-            non_recursive_applications.push_back(*it);
-        }
+        item_set_vector merged_decls = add_merged_decls(non_recursive_preds);
 
-        ptr_vector<rule_stratifier::item_set> merged_decls = add_merged_decls(non_recursive_applications);
-
-        unsigned n = non_recursive_applications.size();
+        unsigned n = non_recursive_preds.size();
         ptr_vector<func_decl> decls_buf;
         decls_buf.resize(n);
         bool was_added = false;
@@ -348,7 +348,7 @@ namespace datalog {
             merge_rules(0, rules_buf, renamed_rules, rules);
         }
 
-        replace_applications(r, rules, non_recursive_applications);
+        replace_applications(r, rules, non_recursive_preds);
         m_deps->populate(rules);
         m_stratifier = alloc(rule_stratifier, *m_deps);
     }
@@ -357,10 +357,7 @@ namespace datalog {
         rule_set* rules = alloc(rule_set, m_ctx);
         rules->inherit_predicates(source);
 
-        rule_set::iterator it = source.begin(), end = source.end();
-        for (; it != end; ++it) {
-            rules->add_rule(*it);
-        }
+        for (auto *r : source) { rules->add_rule(r); }
 
         m_deps = alloc(rule_dependencies, m_ctx);
         m_deps->populate(*rules);
@@ -372,6 +369,7 @@ namespace datalog {
             merge_applications(*r, *rules);
             ++current_rule;
         }
+
         return rules;
     }
 
diff --git a/src/muz/transforms/dl_mk_synchronize.h b/src/muz/transforms/dl_mk_synchronize.h
index e4ce7cad1..767f09f6e 100644
--- a/src/muz/transforms/dl_mk_synchronize.h
+++ b/src/muz/transforms/dl_mk_synchronize.h
@@ -52,6 +52,9 @@ namespace datalog {
        \brief Implements a synchronous product transformation.
     */
     class mk_synchronize : public rule_transformer::plugin {
+    public:
+        typedef ptr_vector<rule_stratifier::item_set> item_set_vector;
+    private:
         context&        m_ctx;
         ast_manager&    m;
         rule_manager&   rm;
@@ -59,25 +62,30 @@ namespace datalog {
         scoped_ptr<rule_dependencies> m_deps;
         scoped_ptr<rule_stratifier> m_stratifier;
         map<symbol, func_decl*, symbol_hash_proc, symbol_eq_proc> cache;
+        bool is_recursive(rule &r, func_decl &decl) const;
+        bool is_recursive(rule &r, expr &e) const;
 
-        bool is_recursive_app(rule & r, app * app) const;
         bool has_recursive_premise(app * app) const;
 
-        ptr_vector<rule_stratifier::item_set> add_merged_decls(ptr_vector<app> & apps);
-        void add_new_rel_symbols(unsigned idx, ptr_vector<rule_stratifier::item_set> const & decls,
-            ptr_vector<func_decl> & buf, bool & was_added);
+        item_set_vector add_merged_decls(ptr_vector<app> & apps);
+        void add_new_rel_symbols(unsigned idx, item_set_vector const & decls,
+                                 ptr_vector<func_decl> & buf, bool & was_added);
 
-        void replace_applications(rule & r, rule_set & rules, ptr_vector<app> & apps);
+        void replace_applications(rule & r, rule_set & rules,
+                                  ptr_vector<app> & apps);
 
         rule_ref rename_bound_vars_in_rule(rule * r, unsigned & var_idx);
-        vector<rule_ref_vector> rename_bound_vars(ptr_vector<rule_stratifier::item_set> const & heads, rule_set & rules);
+        vector<rule_ref_vector> rename_bound_vars(item_set_vector const & heads,
+                                                  rule_set & rules);
 
-        void add_rec_tail(vector< ptr_vector<app> > & recursive_calls, ptr_vector<app> & new_tail,
-            svector<bool> & new_tail_neg, unsigned & tail_idx);
-        void add_non_rec_tail(rule & r, ptr_vector<app> & new_tail, svector<bool> & new_tail_neg,
-            unsigned & tail_idx);
+        void add_rec_tail(vector< ptr_vector<app> > & recursive_calls,
+                          app_ref_vector & new_tail,
+                          svector<bool> & new_tail_neg, unsigned & tail_idx);
+        void add_non_rec_tail(rule & r, app_ref_vector & new_tail,
+                              svector<bool> & new_tail_neg,
+                              unsigned & tail_idx);
 
-        app* product_application(ptr_vector<app> const & apps);
+        app_ref product_application(ptr_vector<app> const & apps);
         rule_ref product_rule(rule_ref_vector const & rules);
 
         void merge_rules(unsigned idx, rule_ref_vector & buf,