1 /*++
2 Copyright (c) 2006 Microsoft Corporation
3 
4 Module Name:
5 
6     dl_relation_manager.cpp
7 
8 Abstract:
9 
10     <abstract>
11 
12 Author:
13 
14     Krystof Hoder (t-khoder) 2010-09-14.
15 
16 Revision History:
17 
18 --*/
19 
20 
21 #include <sstream>
22 #include "ast/ast_pp.h"
23 #include "muz/rel/dl_check_table.h"
24 #include "muz/base/dl_context.h"
25 #include "muz/rel/dl_finite_product_relation.h"
26 #include "muz/rel/dl_product_relation.h"
27 #include "muz/rel/dl_sieve_relation.h"
28 #include "muz/rel/dl_table_relation.h"
29 #include "muz/rel/dl_relation_manager.h"
30 
31 namespace datalog {
32 
~relation_manager()33     relation_manager::~relation_manager() {
34         reset();
35     }
36 
37 
reset_relations()38     void relation_manager::reset_relations() {
39         for (auto const& kv : m_relations) {
40             func_decl * pred = kv.m_key;
41             get_context().get_manager().dec_ref(pred); //inc_ref in get_relation
42             kv.m_value->deallocate();
43         }
44         m_relations.reset();
45     }
46 
reset()47     void relation_manager::reset() {
48         reset_relations();
49 
50         m_favourite_table_plugin   = static_cast<table_plugin *>(nullptr);
51         m_favourite_relation_plugin = static_cast<relation_plugin *>(nullptr);
52         dealloc_ptr_vector_content(m_table_plugins);
53         m_table_plugins.reset();
54         dealloc_ptr_vector_content(m_relation_plugins);
55         m_relation_plugins.reset();
56         m_next_table_fid = 0;
57         m_next_relation_fid = 0;
58     }
59 
get_decl_util() const60     dl_decl_util & relation_manager::get_decl_util() const {
61         return get_context().get_decl_util();
62     }
63 
get_next_relation_fid(relation_plugin & claimer)64     family_id relation_manager::get_next_relation_fid(relation_plugin & claimer) {
65         unsigned res = m_next_relation_fid++;
66         m_kind2plugin.insert(res, &claimer);
67         return res;
68     }
69 
set_predicate_kind(func_decl * pred,family_id kind)70     void relation_manager::set_predicate_kind(func_decl * pred, family_id kind) {
71         SASSERT(!m_relations.contains(pred));
72         m_pred_kinds.insert(pred, kind);
73     }
74 
get_requested_predicate_kind(func_decl * pred)75     family_id relation_manager::get_requested_predicate_kind(func_decl * pred) {
76         family_id res;
77         if(m_pred_kinds.find(pred, res)) {
78             return res;
79         }
80         else {
81             return null_family_id;
82         }
83     }
84 
get_relation(func_decl * pred)85     relation_base & relation_manager::get_relation(func_decl * pred) {
86         relation_base * res = try_get_relation(pred);
87         if(!res) {
88             relation_signature sig;
89             from_predicate(pred, sig);
90             family_id rel_kind = get_requested_predicate_kind(pred);
91             res = mk_empty_relation(sig, rel_kind);
92             store_relation(pred, res);
93         }
94         return *res;
95     }
96 
try_get_relation(func_decl * pred) const97     relation_base * relation_manager::try_get_relation(func_decl * pred) const {
98         relation_base * res = nullptr;
99         if(!m_relations.find(pred, res)) {
100             return nullptr;
101         }
102         SASSERT(res);
103         return res;
104     }
105 
store_relation(func_decl * pred,relation_base * rel)106     void relation_manager::store_relation(func_decl * pred, relation_base * rel) {
107         SASSERT(rel);
108         auto& value = m_relations.insert_if_not_there(pred, 0);
109         if (value) {
110             value->deallocate();
111         }
112         else {
113             get_context().get_manager().inc_ref(pred); //dec_ref in reset
114         }
115         value = rel;
116     }
117 
collect_predicates() const118     decl_set relation_manager::collect_predicates() const {
119         decl_set res;
120         for (auto const& kv : m_relations) {
121             res.insert(kv.m_key);
122         }
123         return res;
124     }
125 
collect_non_empty_predicates(decl_set & res) const126     void relation_manager::collect_non_empty_predicates(decl_set & res) const {
127         for (auto const& kv : m_relations) {
128             if (!kv.m_value->fast_empty()) {
129                 res.insert(kv.m_key);
130             }
131         }
132     }
133 
restrict_predicates(const decl_set & preds)134     void relation_manager::restrict_predicates(const decl_set & preds) {
135         ptr_vector<func_decl> to_remove;
136 
137         for (auto const& kv : m_relations) {
138             func_decl* pred = kv.m_key;
139             if (!preds.contains(pred)) {
140                 to_remove.insert(pred);
141             }
142         }
143 
144         for (func_decl* pred : to_remove) {
145             m_relations.find(pred)->deallocate();
146             m_relations.remove(pred);
147             get_context().get_manager().dec_ref(pred);
148         }
149 
150         set_intersection(m_saturated_rels, preds);
151     }
152 
register_plugin(table_plugin * plugin)153     void relation_manager::register_plugin(table_plugin * plugin) {
154         plugin->initialize(get_next_table_fid());
155         m_table_plugins.push_back(plugin);
156 
157         if(plugin->get_name()==get_context().default_table()) {
158             m_favourite_table_plugin = plugin;
159         }
160 
161         table_relation_plugin * tr_plugin = alloc(table_relation_plugin, *plugin, *this);
162         register_relation_plugin_impl(tr_plugin);
163         m_table_relation_plugins.insert(plugin, tr_plugin);
164 
165         if (plugin->get_name()==get_context().default_table()) {
166             m_favourite_table_plugin    = plugin;
167             m_favourite_relation_plugin = tr_plugin;
168         }
169 
170         symbol checker_name = get_context().default_table_checker();
171         if (get_context().default_table_checked() && get_table_plugin(checker_name)) {
172             if( m_favourite_table_plugin &&
173                 (plugin==m_favourite_table_plugin || plugin->get_name()==checker_name) ) {
174                 symbol checked_name = get_context().default_table();
175                 //the plugins we need to create the checking plugin were just added
176                 SASSERT(m_favourite_table_plugin->get_name()==get_context().default_table());
177                 table_plugin * checking_plugin = alloc(check_table_plugin, *this, checker_name, checked_name);
178                 register_plugin(checking_plugin);
179                 m_favourite_table_plugin = checking_plugin;
180             }
181             if (m_favourite_relation_plugin && m_favourite_relation_plugin->from_table()) {
182                 table_relation_plugin * fav_rel_plugin =
183                     static_cast<table_relation_plugin *>(m_favourite_relation_plugin);
184                 if(&fav_rel_plugin->get_table_plugin()==plugin || plugin->get_name()==checker_name) {
185                     //the plugins we need to create the checking table_relation_plugin were just added
186                     SASSERT(m_favourite_relation_plugin->get_name() ==
187                         get_context().default_relation());
188                     symbol checked_name = fav_rel_plugin->get_table_plugin().get_name();
189                     table_plugin * checking_plugin = alloc(check_table_plugin, *this, checker_name, checked_name);
190                     register_plugin(checking_plugin);
191 
192                     table_relation_plugin * checking_tr_plugin =
193                         alloc(table_relation_plugin, *checking_plugin, *this);
194                     register_relation_plugin_impl(checking_tr_plugin);
195                     m_table_relation_plugins.insert(checking_plugin, checking_tr_plugin);
196                     m_favourite_relation_plugin = checking_tr_plugin;
197                 }
198             }
199         }
200 
201     }
202 
register_relation_plugin_impl(relation_plugin * plugin)203     void relation_manager::register_relation_plugin_impl(relation_plugin * plugin) {
204         TRACE("dl", tout << "register: " << plugin->get_name() << "\n";);
205         m_relation_plugins.push_back(plugin);
206         plugin->initialize(get_next_relation_fid(*plugin));
207         if (plugin->get_name() == get_context().default_relation()) {
208             m_favourite_relation_plugin = plugin;
209         }
210         if(plugin->is_finite_product_relation()) {
211             finite_product_relation_plugin * fprp = static_cast<finite_product_relation_plugin *>(plugin);
212             relation_plugin * inner = &fprp->get_inner_plugin();
213             m_finite_product_relation_plugins.insert(inner, fprp);
214         }
215     }
216 
try_get_appropriate_plugin(const relation_signature & s)217     relation_plugin * relation_manager::try_get_appropriate_plugin(const relation_signature & s) {
218         if(m_favourite_relation_plugin && m_favourite_relation_plugin->can_handle_signature(s)) {
219             return m_favourite_relation_plugin;
220         }
221         for (auto * r : m_relation_plugins) {
222             if (r->can_handle_signature(s)) {
223                 return r;
224             }
225         }
226         return nullptr;
227     }
228 
get_appropriate_plugin(const relation_signature & s)229     relation_plugin & relation_manager::get_appropriate_plugin(const relation_signature & s) {
230         relation_plugin * res = try_get_appropriate_plugin(s);
231         if (!res) {
232             throw default_exception("no suitable plugin found for given relation signature");
233         }
234         return *res;
235     }
236 
try_get_appropriate_plugin(const table_signature & t)237     table_plugin * relation_manager::try_get_appropriate_plugin(const table_signature & t) {
238         if (m_favourite_table_plugin && m_favourite_table_plugin->can_handle_signature(t)) {
239             return m_favourite_table_plugin;
240         }
241         for (auto * a : m_table_plugins) {
242             if (a->can_handle_signature(t)) {
243                 return a;
244             }
245         }
246         return nullptr;
247     }
248 
get_appropriate_plugin(const table_signature & t)249     table_plugin & relation_manager::get_appropriate_plugin(const table_signature & t) {
250         table_plugin * res = try_get_appropriate_plugin(t);
251         if(!res) {
252             throw default_exception("no suitable plugin found for given table signature");
253         }
254         return *res;
255     }
256 
get_relation_plugin(symbol const & s)257     relation_plugin * relation_manager::get_relation_plugin(symbol const& s) {
258         for (auto* r : m_relation_plugins) {
259             if(r->get_name() == s) {
260                 return r;
261             }
262         }
263         return nullptr;
264     }
265 
get_relation_plugin(family_id kind)266     relation_plugin & relation_manager::get_relation_plugin(family_id kind) {
267         SASSERT(kind>=0);
268         SASSERT(kind<m_next_relation_fid);
269         relation_plugin * res = nullptr;
270         VERIFY(m_kind2plugin.find(kind, res));
271         return *res;
272     }
273 
get_table_plugin(symbol const & k)274     table_plugin * relation_manager::get_table_plugin(symbol const& k) {
275         for (table_plugin * tp : m_table_plugins) {
276             if (tp->get_name()==k) {
277                 return tp;
278             }
279         }
280         return nullptr;
281     }
282 
get_table_relation_plugin(table_plugin & tp)283     table_relation_plugin & relation_manager::get_table_relation_plugin(table_plugin & tp) {
284         table_relation_plugin * res = nullptr;
285         VERIFY( m_table_relation_plugins.find(&tp, res) );
286         return *res;
287     }
288 
try_get_finite_product_relation_plugin(const relation_plugin & inner,finite_product_relation_plugin * & res)289     bool relation_manager::try_get_finite_product_relation_plugin(const relation_plugin & inner,
290             finite_product_relation_plugin * & res) {
291         return m_finite_product_relation_plugins.find(&inner, res);
292     }
293 
mk_empty_table(const table_signature & s)294     table_base * relation_manager::mk_empty_table(const table_signature & s) {
295         return get_appropriate_plugin(s).mk_empty(s);
296     }
297 
298 
is_non_explanation(relation_signature const & s) const299     bool relation_manager::is_non_explanation(relation_signature const& s) const {
300         dl_decl_util & decl_util = get_context().get_decl_util();
301         unsigned n = s.size();
302         for(unsigned i = 0; i < n; i++) {
303             if(decl_util.is_rule_sort(s[i])) {
304                 return false;
305             }
306         }
307         return true;
308     }
309 
mk_empty_relation(const relation_signature & s,func_decl * pred)310     relation_base * relation_manager::mk_empty_relation(const relation_signature & s, func_decl* pred) {
311         return mk_empty_relation(s, get_requested_predicate_kind(pred));
312     }
313 
mk_empty_relation(const relation_signature & s,family_id kind)314     relation_base * relation_manager::mk_empty_relation(const relation_signature & s, family_id kind) {
315         if (kind != null_family_id) {
316             relation_plugin & plugin = get_relation_plugin(kind);
317             if (plugin.can_handle_signature(s, kind))
318                 return plugin.mk_empty(s, kind);
319         }
320         relation_base * res;
321         relation_plugin* p = m_favourite_relation_plugin;
322 
323         if (p && p->can_handle_signature(s)) {
324             return p->mk_empty(s);
325         }
326 
327         if (mk_empty_table_relation(s, res)) {
328             return res;
329         }
330 
331         for (relation_plugin* p1 : m_relation_plugins) {
332             if (p1->can_handle_signature(s)) {
333                 return p1->mk_empty(s);
334             }
335         }
336 
337         //If there is no plugin to handle the signature, we just create an empty product relation and
338         //stuff will be added to it by later operations.
339         TRACE("dl", s.output(get_context().get_manager(), tout << "empty product relation"); tout << "\n";);
340         return product_relation_plugin::get_plugin(*this).mk_empty(s);
341     }
342 
343     /**
344       The newly created object takes ownership of the \c table object.
345     */
mk_table_relation(const relation_signature & s,table_base * table)346     relation_base * relation_manager::mk_table_relation(const relation_signature & s, table_base * table) {
347         SASSERT(s.size()==table->get_signature().size());
348         return get_table_relation_plugin(table->get_plugin()).mk_from_table(s, table);
349     }
350 
mk_empty_table_relation(const relation_signature & s,relation_base * & result)351     bool relation_manager::mk_empty_table_relation(const relation_signature & s, relation_base * & result) {
352         table_signature tsig;
353         if(!relation_signature_to_table(s, tsig)) {
354             return false;
355         }
356         table_base * table = mk_empty_table(tsig);
357         result = mk_table_relation(s, table);
358         return true;
359     }
360 
361 
mk_full_relation(const relation_signature & s,func_decl * p,family_id kind)362     relation_base * relation_manager::mk_full_relation(const relation_signature & s, func_decl* p, family_id kind) {
363         if (kind != null_family_id) {
364             relation_plugin & plugin = get_relation_plugin(kind);
365             if (plugin.can_handle_signature(s, kind)) {
366                 return plugin.mk_full(p, s, kind);
367             }
368         }
369         return get_appropriate_plugin(s).mk_full(p, s, null_family_id);
370     }
371 
mk_full_relation(const relation_signature & s,func_decl * pred)372     relation_base * relation_manager::mk_full_relation(const relation_signature & s, func_decl* pred) {
373         family_id kind = get_requested_predicate_kind(pred);
374         return mk_full_relation(s, pred, kind);
375     }
376 
relation_to_table(const relation_sort & sort,const relation_element & from,table_element & to)377     void relation_manager::relation_to_table(const relation_sort & sort, const relation_element & from,
378             table_element & to) {
379         SASSERT(from->get_num_args()==0);
380         VERIFY(get_context().get_decl_util().is_numeral_ext(from, to));
381     }
382 
table_to_relation(const relation_sort & sort,const table_element & from,relation_element & to)383     void relation_manager::table_to_relation(const relation_sort & sort, const table_element & from,
384             relation_element & to) {
385         to = get_decl_util().mk_numeral(from, sort);
386     }
387 
table_to_relation(const relation_sort & sort,const table_element & from,relation_element_ref & to)388     void relation_manager::table_to_relation(const relation_sort & sort, const table_element & from,
389             relation_element_ref & to) {
390         relation_element rel_el;
391         table_to_relation(sort, from, rel_el);
392         to = rel_el;
393     }
394 
table_to_relation(const relation_sort & sort,const table_element & from,const relation_fact::el_proxy & to)395     void relation_manager::table_to_relation(const relation_sort & sort, const table_element & from,
396             const relation_fact::el_proxy & to) {
397         relation_element rel_el;
398         table_to_relation(sort, from, rel_el);
399         to = rel_el;
400     }
401 
relation_sort_to_table(const relation_sort & from,table_sort & to)402     bool relation_manager::relation_sort_to_table(const relation_sort & from, table_sort & to) {
403         return get_context().get_decl_util().try_get_size(from, to);
404     }
405 
from_predicate(func_decl * pred,unsigned arg_index,relation_sort & result)406     void relation_manager::from_predicate(func_decl * pred, unsigned arg_index, relation_sort & result) {
407         result = pred->get_domain(arg_index);
408     }
409 
from_predicate(func_decl * pred,relation_signature & result)410     void relation_manager::from_predicate(func_decl * pred, relation_signature & result) {
411         result.reset();
412         unsigned arg_num=pred->get_arity();
413         for(unsigned i=0;i<arg_num; i++) {
414             relation_sort rel_srt;
415             from_predicate(pred, i, rel_srt);
416             result.push_back(rel_srt);
417         }
418     }
419 
420 
relation_signature_to_table(const relation_signature & from,table_signature & to)421     bool relation_manager::relation_signature_to_table(const relation_signature & from, table_signature & to) {
422         unsigned n=from.size();
423         to.resize(n);
424         for(unsigned i=0; i<n; i++) {
425             if(!relation_sort_to_table(from[i], to[i])) {
426                 return false;
427             }
428         }
429         return true;
430     }
431 
relation_fact_to_table(const relation_signature & s,const relation_fact & from,table_fact & to)432     void relation_manager::relation_fact_to_table(const relation_signature & s, const relation_fact & from,
433             table_fact & to) {
434         SASSERT(s.size()==from.size());
435         unsigned n=from.size();
436         to.resize(n);
437         for(unsigned i=0;i<n;i++) {
438             relation_to_table(s[i], from[i], to[i]);
439         }
440     }
441 
table_fact_to_relation(const relation_signature & s,const table_fact & from,relation_fact & to)442     void relation_manager::table_fact_to_relation(const relation_signature & s, const table_fact & from,
443         relation_fact & to) {
444             SASSERT(s.size()==from.size());
445             unsigned n=from.size();
446             to.resize(n);
447             for(unsigned i=0;i<n;i++) {
448                 table_to_relation(s[i], from[i], to[i]);
449             }
450     }
451 
to_nice_string(const relation_element & el) const452     std::string relation_manager::to_nice_string(const relation_element & el) const {
453         uint64_t val;
454         std::stringstream stm;
455         if(get_context().get_decl_util().is_numeral_ext(el, val)) {
456             stm << val;
457         }
458         else {
459             stm << mk_pp(el, get_context().get_manager());
460         }
461         return stm.str();
462     }
463 
to_nice_string(const relation_sort & s,const relation_element & el) const464     std::string relation_manager::to_nice_string(const relation_sort & s, const relation_element & el) const {
465         std::stringstream stm;
466         uint64_t val;
467         if(get_context().get_decl_util().is_numeral_ext(el, val)) {
468             get_context().print_constant_name(s, val, stm);
469         }
470         else {
471             stm << mk_pp(el, get_context().get_manager());
472         }
473         return stm.str();
474     }
475 
to_nice_string(const relation_sort & s) const476     std::string relation_manager::to_nice_string(const relation_sort & s) const {
477         std::ostringstream strm;
478         strm << mk_pp(s, get_context().get_manager());
479         return strm.str();
480     }
481 
to_nice_string(const relation_signature & s) const482     std::string relation_manager::to_nice_string(const relation_signature & s) const {
483         std::string res("[");
484         bool first = true;
485         for (auto const& sig : s) {
486             if (first) {
487                 first = false;
488             }
489             else {
490                 res += ',';
491             }
492             res += to_nice_string(sig);
493         }
494         res += ']';
495 
496         return res;
497     }
498 
display(std::ostream & out) const499     void relation_manager::display(std::ostream & out) const {
500         for (auto const& kv : m_relations) {
501             out << "Table " << kv.m_key->get_name() << "\n";
502             kv.m_value->display(out);
503         }
504     }
505 
display_relation_sizes(std::ostream & out) const506     void relation_manager::display_relation_sizes(std::ostream & out) const {
507         for (auto const& kv : m_relations) {
508             out << "Relation " << kv.m_key->get_name() << " has size "
509                 << kv.m_value->get_size_estimate_rows() << "\n";
510         }
511     }
512 
display_output_tables(rule_set const & rules,std::ostream & out) const513     void relation_manager::display_output_tables(rule_set const& rules, std::ostream & out) const {
514         const decl_set & output_preds = rules.get_output_predicates();
515         for (func_decl * pred : output_preds) {
516             relation_base * rel = try_get_relation(pred);
517             if (!rel) {
518                 out << "Tuples in " << pred->get_name() << ": \n";
519                 continue;
520             }
521             rel->display_tuples(*pred, out);
522         }
523     }
524 
525 
526     // -----------------------------------
527     //
528     // relation operations
529     //
530     // -----------------------------------
531 
532     class relation_manager::empty_signature_relation_join_fn : public relation_join_fn {
533     public:
operator ()(const relation_base & r1,const relation_base & r2)534         relation_base * operator()(const relation_base & r1, const relation_base & r2) override {
535             TRACE("dl", tout << r1.get_plugin().get_name() << " " << r2.get_plugin().get_name() << "\n";);
536             if(r1.get_signature().empty()) {
537                 if(r1.empty()) {
538                     return r2.get_manager().mk_empty_relation(r2.get_signature(), r2.get_kind());
539                 }
540                 else {
541                     return r2.clone();
542                 }
543             }
544             else {
545                 SASSERT(r2.get_signature().empty());
546                 if(r2.empty()) {
547                     return r1.get_manager().mk_empty_relation(r1.get_signature(), r1.get_kind());
548                 }
549                 else {
550                     return r1.clone();
551                 }
552             }
553         }
554     };
555 
mk_join_fn(const relation_base & t1,const relation_base & t2,unsigned col_cnt,const unsigned * cols1,const unsigned * cols2,bool allow_product_relation)556     relation_join_fn * relation_manager::mk_join_fn(const relation_base & t1, const relation_base & t2,
557             unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, bool allow_product_relation) {
558         relation_plugin * p1 = &t1.get_plugin();
559         relation_plugin * p2 = &t2.get_plugin();
560 
561         relation_join_fn * res = p1->mk_join_fn(t1, t2, col_cnt, cols1, cols2);
562 
563         if(!res && p1!=p2) {
564             res = p2->mk_join_fn(t1, t2, col_cnt, cols1, cols2);
565         }
566 
567         if(!res && (t1.get_signature().empty() || t2.get_signature().empty())) {
568             res = alloc(empty_signature_relation_join_fn);
569         }
570 
571         finite_product_relation_plugin * fprp;
572         if(!res && p1->from_table() && try_get_finite_product_relation_plugin(*p2, fprp)) {
573             //we downcast here to relation_plugin so that we don't have to declare
574             //relation_manager as a friend class of finite_product_relation_plugin
575             res = static_cast<relation_plugin *>(fprp)->mk_join_fn(t1, t2, col_cnt, cols1, cols2);
576         }
577         if(!res && p2->from_table() && try_get_finite_product_relation_plugin(*p1, fprp)) {
578             res = static_cast<relation_plugin *>(fprp)->mk_join_fn(t1, t2, col_cnt, cols1, cols2);
579         }
580 
581         if(!res && allow_product_relation) {
582             relation_plugin & product_plugin = product_relation_plugin::get_plugin(*this);
583             res = product_plugin.mk_join_fn(t1, t2, col_cnt, cols1, cols2);
584         }
585 
586         return res;
587     }
588 
mk_project_fn(const relation_base & t,unsigned col_cnt,const unsigned * removed_cols)589     relation_transformer_fn * relation_manager::mk_project_fn(const relation_base & t, unsigned col_cnt,
590             const unsigned * removed_cols) {
591         return t.get_plugin().mk_project_fn(t, col_cnt, removed_cols);
592     }
593 
594     class relation_manager::default_relation_filter_interpreted_and_project_fn : public relation_transformer_fn {
595         scoped_ptr<relation_mutator_fn>     m_filter;
596         scoped_ptr<relation_transformer_fn> m_project;
597         unsigned_vector                     m_removed_cols;
598     public:
599         /**
600             This constructor should be used only if we know that the projection operation
601             exists for the result of the join.
602         */
default_relation_filter_interpreted_and_project_fn(relation_mutator_fn * filter,unsigned removed_col_cnt,const unsigned * removed_cols)603         default_relation_filter_interpreted_and_project_fn(
604             relation_mutator_fn* filter,
605             unsigned removed_col_cnt,
606             const unsigned * removed_cols)
607             : m_filter(filter),
608               m_project(nullptr),
609               m_removed_cols(removed_col_cnt, removed_cols) {}
610 
operator ()(const relation_base & t)611         relation_base * operator()(const relation_base & t) override {
612             scoped_rel<relation_base> t1 = t.clone();
613             (*m_filter)(*t1);
614             if( !m_project) {
615                 relation_manager & rmgr = t1->get_plugin().get_manager();
616                 m_project = rmgr.mk_project_fn(*t1, m_removed_cols.size(), m_removed_cols.data());
617                 if (!m_project) {
618                     throw default_exception("projection does not exist");
619                 }
620             }
621             return (*m_project)(*t1);
622         }
623     };
624 
mk_filter_interpreted_and_project_fn(const relation_base & t,app * condition,unsigned removed_col_cnt,const unsigned * removed_cols)625     relation_transformer_fn * relation_manager::mk_filter_interpreted_and_project_fn(
626         const relation_base & t, app * condition,
627         unsigned removed_col_cnt, const unsigned * removed_cols) {
628 
629         relation_transformer_fn* res =
630             t.get_plugin().mk_filter_interpreted_and_project_fn(
631                 t,
632                 condition,
633                 removed_col_cnt,
634                 removed_cols);
635 
636         if (!res) {
637             relation_mutator_fn* filter_fn = mk_filter_interpreted_fn(t, condition);
638             if (filter_fn) {
639                 res = alloc(default_relation_filter_interpreted_and_project_fn,
640                             filter_fn,
641                             removed_col_cnt,
642                             removed_cols);
643             }
644         }
645         return res;
646     }
647 
648     class relation_manager::default_relation_apply_sequential_fn : public relation_mutator_fn {
649         ptr_vector<relation_mutator_fn> m_mutators;
650     public:
default_relation_apply_sequential_fn(unsigned n,relation_mutator_fn ** mutators)651         default_relation_apply_sequential_fn(unsigned n, relation_mutator_fn ** mutators):
652             m_mutators(n, mutators) {
653         }
~default_relation_apply_sequential_fn()654         ~default_relation_apply_sequential_fn() override {
655             std::for_each(m_mutators.begin(), m_mutators.end(), delete_proc<relation_mutator_fn>());
656         }
657 
operator ()(relation_base & t)658         void operator()(relation_base& t) override {
659             for (unsigned i = 0; i < m_mutators.size(); ++i) {
660                 if (t.empty()) return;
661                 (*(m_mutators[i]))(t);
662             }
663         }
664     };
665 
mk_apply_sequential_fn(unsigned n,relation_mutator_fn ** mutators)666     relation_mutator_fn * relation_manager::mk_apply_sequential_fn(unsigned n, relation_mutator_fn ** mutators) {
667         return alloc(default_relation_apply_sequential_fn, n, mutators);
668     }
669 
670     class relation_manager::default_relation_join_project_fn : public relation_join_fn {
671         scoped_ptr<relation_join_fn> m_join;
672         scoped_ptr<relation_transformer_fn> m_project;
673 
674         unsigned_vector m_removed_cols;
675     public:
676         /**
677             This constructor should be used only if we know that the projection operation
678             exists for the result of the join.
679             */
default_relation_join_project_fn(join_fn * join,unsigned removed_col_cnt,const unsigned * removed_cols)680         default_relation_join_project_fn(join_fn * join, unsigned removed_col_cnt,
681             const unsigned * removed_cols)
682             : m_join(join), m_project(nullptr), m_removed_cols(removed_col_cnt, removed_cols) {}
683 
operator ()(const relation_base & t1,const relation_base & t2)684         relation_base * operator()(const relation_base & t1, const relation_base & t2) override {
685             scoped_rel<relation_base> aux = (*m_join)(t1, t2);
686             if(!m_project) {
687                 relation_manager & rmgr = aux->get_plugin().get_manager();
688                 m_project = rmgr.mk_project_fn(*aux, m_removed_cols.size(), m_removed_cols.data());
689                 if(!m_project) {
690                     throw default_exception("projection does not exist");
691                 }
692             }
693             relation_base * res = (*m_project)(*aux);
694             return res;
695         }
696     };
697 
698 
mk_join_project_fn(const relation_base & t1,const relation_base & t2,unsigned joined_col_cnt,const unsigned * cols1,const unsigned * cols2,unsigned removed_col_cnt,const unsigned * removed_cols,bool allow_product_relation_join)699     relation_join_fn * relation_manager::mk_join_project_fn(const relation_base & t1, const relation_base & t2,
700             unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2,
701             unsigned removed_col_cnt, const unsigned * removed_cols, bool allow_product_relation_join) {
702         relation_join_fn * res = t1.get_plugin().mk_join_project_fn(t1, t2, joined_col_cnt, cols1, cols2,
703             removed_col_cnt, removed_cols);
704         if(!res && &t1.get_plugin()!=&t2.get_plugin()) {
705             res = t2.get_plugin().mk_join_project_fn(t1, t2, joined_col_cnt, cols1, cols2, removed_col_cnt,
706                 removed_cols);
707         }
708         if(!res) {
709             relation_join_fn * join = mk_join_fn(t1, t2, joined_col_cnt, cols1, cols2, allow_product_relation_join);
710             if(join) {
711                 res = alloc(default_relation_join_project_fn, join, removed_col_cnt, removed_cols);
712             }
713         }
714         return res;
715 
716     }
717 
mk_rename_fn(const relation_base & t,unsigned permutation_cycle_len,const unsigned * permutation_cycle)718     relation_transformer_fn * relation_manager::mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len,
719             const unsigned * permutation_cycle) {
720         return t.get_plugin().mk_rename_fn(t, permutation_cycle_len, permutation_cycle);
721     }
722 
mk_permutation_rename_fn(const relation_base & t,const unsigned * permutation)723     relation_transformer_fn * relation_manager::mk_permutation_rename_fn(const relation_base & t,
724             const unsigned * permutation) {
725         relation_transformer_fn * res = t.get_plugin().mk_permutation_rename_fn(t, permutation);
726         if(!res) {
727             res = alloc(default_relation_permutation_rename_fn, t, permutation);
728         }
729         return res;
730     }
731 
732 
mk_union_fn(const relation_base & tgt,const relation_base & src,const relation_base * delta)733     relation_union_fn * relation_manager::mk_union_fn(const relation_base & tgt, const relation_base & src,
734             const relation_base * delta) {
735         relation_union_fn * res = tgt.get_plugin().mk_union_fn(tgt, src, delta);
736         if(!res && &tgt.get_plugin()!=&src.get_plugin()) {
737             res = src.get_plugin().mk_union_fn(tgt, src, delta);
738         }
739         if(!res && delta && &tgt.get_plugin()!=&delta->get_plugin() && &src.get_plugin()!=&delta->get_plugin()) {
740             res = delta->get_plugin().mk_union_fn(tgt, src, delta);
741         }
742         // TRACE("dl", tout << src.get_plugin().get_name() << " " << tgt.get_plugin().get_name() << " " << (res?"created":"not created") << "\n";);
743         return res;
744     }
745 
mk_widen_fn(const relation_base & tgt,const relation_base & src,const relation_base * delta)746     relation_union_fn * relation_manager::mk_widen_fn(const relation_base & tgt, const relation_base & src,
747             const relation_base * delta) {
748         relation_union_fn * res = tgt.get_plugin().mk_widen_fn(tgt, src, delta);
749         if(!res && &tgt.get_plugin()!=&src.get_plugin()) {
750             res = src.get_plugin().mk_widen_fn(tgt, src, delta);
751         }
752         if(!res && delta && &tgt.get_plugin()!=&delta->get_plugin() && &src.get_plugin()!=&delta->get_plugin()) {
753             res = delta->get_plugin().mk_widen_fn(tgt, src, delta);
754         }
755         if(!res) {
756             res = mk_union_fn(tgt, src, delta);
757         }
758         return res;
759     }
760 
mk_filter_identical_fn(const relation_base & t,unsigned col_cnt,const unsigned * identical_cols)761     relation_mutator_fn * relation_manager::mk_filter_identical_fn(const relation_base & t, unsigned col_cnt,
762             const unsigned * identical_cols) {
763         return t.get_plugin().mk_filter_identical_fn(t, col_cnt, identical_cols);
764     }
765 
mk_filter_equal_fn(const relation_base & t,const relation_element & value,unsigned col)766     relation_mutator_fn * relation_manager::mk_filter_equal_fn(const relation_base & t,
767             const relation_element & value, unsigned col) {
768 
769         return t.get_plugin().mk_filter_equal_fn(t, value, col);
770     }
771 
mk_filter_interpreted_fn(const relation_base & t,app * condition)772     relation_mutator_fn * relation_manager::mk_filter_interpreted_fn(const relation_base & t, app * condition) {
773         return t.get_plugin().mk_filter_interpreted_fn(t, condition);
774     }
775 
776     class relation_manager::default_relation_select_equal_and_project_fn : public relation_transformer_fn {
777         scoped_ptr<relation_mutator_fn> m_filter;
778         scoped_ptr<relation_transformer_fn> m_project;
779     public:
default_relation_select_equal_and_project_fn(relation_mutator_fn * filter,relation_transformer_fn * project)780         default_relation_select_equal_and_project_fn(relation_mutator_fn * filter, relation_transformer_fn * project)
781             : m_filter(filter), m_project(project) {}
782 
operator ()(const relation_base & t1)783         relation_base * operator()(const relation_base & t1) override {
784             TRACE("dl", tout << t1.get_plugin().get_name() << "\n";);
785             scoped_rel<relation_base> aux = t1.clone();
786             (*m_filter)(*aux);
787             relation_base * res = (*m_project)(*aux);
788             return res;
789         }
790     };
791 
mk_select_equal_and_project_fn(const relation_base & t,const relation_element & value,unsigned col)792     relation_transformer_fn * relation_manager::mk_select_equal_and_project_fn(const relation_base & t,
793             const relation_element & value, unsigned col) {
794         relation_transformer_fn * res = t.get_plugin().mk_select_equal_and_project_fn(t, value, col);
795         if(!res) {
796             relation_mutator_fn * selector = mk_filter_equal_fn(t, value, col);
797             if(selector) {
798                 relation_transformer_fn * projector = mk_project_fn(t, 1, &col);
799                 if(projector) {
800                     res = alloc(default_relation_select_equal_and_project_fn, selector, projector);
801                 }
802                 else {
803                     dealloc(selector);
804                 }
805             }
806         }
807         return res;
808     }
809 
810 
811     class relation_manager::default_relation_intersection_filter_fn : public relation_intersection_filter_fn {
812         scoped_ptr<relation_join_fn> m_join_fun;
813         scoped_ptr<relation_union_fn> m_union_fun;
814     public:
815 
default_relation_intersection_filter_fn(relation_join_fn * join_fun,relation_union_fn * union_fun)816         default_relation_intersection_filter_fn(relation_join_fn * join_fun, relation_union_fn * union_fun)
817             : m_join_fun(join_fun), m_union_fun(union_fun) {}
818 
operator ()(relation_base & tgt,const relation_base & intersected_obj)819         void operator()(relation_base & tgt, const relation_base & intersected_obj) override {
820             scoped_rel<relation_base> filtered_rel = (*m_join_fun)(tgt, intersected_obj);
821             TRACE("dl",
822                   tgt.display(tout << "tgt:\n");
823                   intersected_obj.display(tout << "intersected:\n");
824                   filtered_rel->display(tout << "filtered:\n");
825                   );
826             if(!m_union_fun) {
827                 SASSERT(tgt.can_swap(*filtered_rel));
828                 tgt.swap(*filtered_rel);
829             }
830             tgt.reset();
831             TRACE("dl", tgt.display(tout << "target reset:\n"); );
832             (*m_union_fun)(tgt, *filtered_rel);
833             TRACE("dl", tgt.display(tout << "intersected target:\n"); );
834         }
835 
836     };
837 
try_mk_default_filter_by_intersection_fn(const relation_base & tgt,const relation_base & src,unsigned joined_col_cnt,const unsigned * tgt_cols,const unsigned * src_cols)838     relation_intersection_filter_fn * relation_manager::try_mk_default_filter_by_intersection_fn(
839             const relation_base & tgt, const relation_base & src, unsigned joined_col_cnt,
840             const unsigned * tgt_cols, const unsigned * src_cols) {
841         TRACE("dl_verbose", tout << tgt.get_plugin().get_name() << "\n";);
842         unsigned_vector join_removed_cols;
843         add_sequence(tgt.get_signature().size(), src.get_signature().size(), join_removed_cols);
844         scoped_rel<relation_join_fn> join_fun = mk_join_project_fn(tgt, src, joined_col_cnt, tgt_cols, src_cols,
845             join_removed_cols.size(), join_removed_cols.data(), false);
846         if(!join_fun) {
847             return nullptr;
848         }
849         //we perform the join operation here to see what the result is
850         scoped_rel<relation_base> join_res = (*join_fun)(tgt, src);
851         if(tgt.can_swap(*join_res)) {
852             return alloc(default_relation_intersection_filter_fn, join_fun.release(), nullptr);
853         }
854         if(join_res->get_plugin().is_product_relation()) {
855             //we cannot have the product relation here, since it uses the intersection operation
856             //for unions and therefore we would get into an infinite recursion
857             return nullptr;
858         }
859         scoped_rel<relation_union_fn> union_fun = mk_union_fn(tgt, *join_res);
860         if(!union_fun) {
861             return nullptr;
862         }
863         return alloc(default_relation_intersection_filter_fn, join_fun.release(), union_fun.release());
864     }
865 
866 
mk_filter_by_intersection_fn(const relation_base & t,const relation_base & src,unsigned joined_col_cnt,const unsigned * t_cols,const unsigned * src_cols)867     relation_intersection_filter_fn * relation_manager::mk_filter_by_intersection_fn(const relation_base & t,
868             const relation_base & src, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * src_cols) {
869         TRACE("dl_verbose", tout << t.get_plugin().get_name() << "\n";);
870         relation_intersection_filter_fn * res = t.get_plugin().mk_filter_by_intersection_fn(t, src, joined_col_cnt,
871             t_cols, src_cols);
872         if(!res && &t.get_plugin()!=&src.get_plugin()) {
873             res = src.get_plugin().mk_filter_by_intersection_fn(t, src, joined_col_cnt, t_cols, src_cols);
874         }
875         if(!res) {
876             res = try_mk_default_filter_by_intersection_fn(t, src, joined_col_cnt, t_cols, src_cols);
877         }
878         return res;
879     }
880 
mk_filter_by_intersection_fn(const relation_base & tgt,const relation_base & src)881     relation_intersection_filter_fn * relation_manager::mk_filter_by_intersection_fn(const relation_base & tgt,
882             const relation_base & src) {
883         TRACE("dl_verbose", tout << tgt.get_plugin().get_name() << "\n";);
884         SASSERT(tgt.get_signature()==src.get_signature());
885         unsigned sz = tgt.get_signature().size();
886         unsigned_vector cols;
887         add_sequence(0, sz, cols);
888         return mk_filter_by_intersection_fn(tgt, src, cols, cols);
889     }
890 
891 
mk_filter_by_negation_fn(const relation_base & t,const relation_base & negated_obj,unsigned joined_col_cnt,const unsigned * t_cols,const unsigned * negated_cols)892     relation_intersection_filter_fn * relation_manager::mk_filter_by_negation_fn(const relation_base & t,
893             const relation_base & negated_obj, unsigned joined_col_cnt,
894             const unsigned * t_cols, const unsigned * negated_cols) {
895         TRACE("dl", tout << t.get_plugin().get_name() << "\n";);
896         relation_intersection_filter_fn * res = t.get_plugin().mk_filter_by_negation_fn(t, negated_obj, joined_col_cnt,
897             t_cols, negated_cols);
898         if(!res && &t.get_plugin()!=&negated_obj.get_plugin()) {
899             res = negated_obj.get_plugin().mk_filter_by_negation_fn(t, negated_obj, joined_col_cnt, t_cols,
900                 negated_cols);
901         }
902         return res;
903     }
904 
905 
906 
907 
908 
909     // -----------------------------------
910     //
911     // table operations
912     //
913     // -----------------------------------
914 
915     class relation_manager::default_table_join_fn : public convenient_table_join_fn {
916         unsigned m_col_cnt;
917     public:
default_table_join_fn(const table_signature & t1_sig,const table_signature & t2_sig,unsigned col_cnt,const unsigned * cols1,const unsigned * cols2)918         default_table_join_fn(const table_signature & t1_sig, const table_signature & t2_sig, unsigned col_cnt,
919             const unsigned * cols1, const unsigned * cols2)
920             : convenient_table_join_fn(t1_sig, t2_sig, col_cnt, cols1, cols2), m_col_cnt(col_cnt) {}
921 
operator ()(const table_base & t1,const table_base & t2)922         table_base * operator()(const table_base & t1, const table_base & t2) override {
923             table_plugin * plugin = &t1.get_plugin();
924 
925             const table_signature & res_sign = get_result_signature();
926             if (!plugin->can_handle_signature(res_sign)) {
927                 plugin = &t2.get_plugin();
928                 if (!plugin->can_handle_signature(res_sign)) {
929                     plugin = &t1.get_manager().get_appropriate_plugin(res_sign);
930                 }
931             }
932             SASSERT(plugin->can_handle_signature(res_sign));
933             table_base * res = plugin->mk_empty(res_sign);
934 
935             unsigned t1cols = t1.get_signature().size();
936             unsigned t2cols = t2.get_signature().size();
937             unsigned t1first_func = t1.get_signature().first_functional();
938             unsigned t2first_func = t2.get_signature().first_functional();
939 
940             table_base::iterator els1it = t1.begin();
941             table_base::iterator els1end = t1.end();
942             table_base::iterator els2end = t2.end();
943 
944             table_fact acc;
945 
946             for(; els1it!=els1end; ++els1it) {
947                 const table_base::row_interface & row1 = *els1it;
948 
949                 table_base::iterator els2it = t2.begin();
950                 for(; els2it!=els2end; ++els2it) {
951                     const table_base::row_interface & row2 = *els2it;
952 
953                     bool match=true;
954                     for(unsigned i=0; i<m_col_cnt; i++) {
955                         if(row1[m_cols1[i]]!=row2[m_cols2[i]]) {
956                             match=false;
957                             break;
958                         }
959                     }
960                     if(!match) {
961                         continue;
962                     }
963 
964                     acc.reset();
965                     for(unsigned i=0; i<t1first_func; i++) {
966                         acc.push_back(row1[i]);
967                     }
968                     for(unsigned i=0; i<t2first_func; i++) {
969                         acc.push_back(row2[i]);
970                     }
971                     for(unsigned i=t1first_func; i<t1cols; i++) {
972                         acc.push_back(row1[i]);
973                     }
974                     for(unsigned i=t2first_func; i<t2cols; i++) {
975                         acc.push_back(row2[i]);
976                     }
977                     res->add_fact(acc);
978                 }
979             }
980             return res;
981         }
982     };
983 
mk_join_fn(const table_base & t1,const table_base & t2,unsigned col_cnt,const unsigned * cols1,const unsigned * cols2)984     table_join_fn * relation_manager::mk_join_fn(const table_base & t1, const table_base & t2,
985             unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) {
986         table_join_fn * res = t1.get_plugin().mk_join_fn(t1, t2, col_cnt, cols1, cols2);
987         if(!res && &t1.get_plugin()!=&t2.get_plugin()) {
988             res = t2.get_plugin().mk_join_fn(t1, t2, col_cnt, cols1, cols2);
989         }
990         if(!res) {
991             table_signature sig;
992             table_signature::from_join(t1.get_signature(), t2.get_signature(),
993                 col_cnt, cols1, cols2, sig);
994             res = alloc(default_table_join_fn, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2);
995         }
996         return res;
997     }
998 
999     class relation_manager::auxiliary_table_transformer_fn {
1000         table_fact m_row;
1001     public:
~auxiliary_table_transformer_fn()1002         virtual ~auxiliary_table_transformer_fn() {}
1003         virtual const table_signature & get_result_signature() const = 0;
1004         virtual void modify_fact(table_fact & f) const = 0;
1005 
operator ()(const table_base & t)1006         table_base * operator()(const table_base & t) {
1007             table_plugin & plugin = t.get_plugin();
1008             const table_signature & res_sign = get_result_signature();
1009             SASSERT(plugin.can_handle_signature(res_sign));
1010             table_base * res = plugin.mk_empty(res_sign);
1011 
1012             for (table_base::row_interface& a : t) {
1013                 a.get_fact(m_row);
1014                 modify_fact(m_row);
1015                 res->add_fact(m_row);
1016             }
1017             return res;
1018         }
1019     };
1020 
1021     class relation_manager::default_table_project_fn
1022             : public convenient_table_project_fn, auxiliary_table_transformer_fn {
1023     public:
default_table_project_fn(const table_signature & orig_sig,unsigned removed_col_cnt,const unsigned * removed_cols)1024         default_table_project_fn(const table_signature & orig_sig, unsigned removed_col_cnt,
1025                 const unsigned * removed_cols)
1026             : convenient_table_project_fn(orig_sig, removed_col_cnt, removed_cols) {
1027                 SASSERT(removed_col_cnt>0);
1028         }
1029 
get_result_signature() const1030         const table_signature & get_result_signature() const override {
1031             return convenient_table_project_fn::get_result_signature();
1032         }
1033 
modify_fact(table_fact & f) const1034         void modify_fact(table_fact & f) const override {
1035             project_out_vector_columns(f, m_removed_cols);
1036         }
1037 
operator ()(const table_base & t)1038         table_base * operator()(const table_base & t) override {
1039             return auxiliary_table_transformer_fn::operator()(t);
1040         }
1041     };
1042 
1043     class relation_manager::null_signature_table_project_fn : public table_transformer_fn {
1044         const table_signature m_empty_sig;
1045     public:
null_signature_table_project_fn()1046         null_signature_table_project_fn() : m_empty_sig() {}
operator ()(const table_base & t)1047         table_base * operator()(const table_base & t) override {
1048             relation_manager & m = t.get_plugin().get_manager();
1049             table_base * res = m.mk_empty_table(m_empty_sig);
1050             if(!t.empty()) {
1051                 table_fact el;
1052                 res->add_fact(el);
1053             }
1054             return res;
1055         }
1056     };
1057 
1058 
1059 
mk_project_fn(const table_base & t,unsigned col_cnt,const unsigned * removed_cols)1060     table_transformer_fn * relation_manager::mk_project_fn(const table_base & t, unsigned col_cnt,
1061             const unsigned * removed_cols) {
1062         table_transformer_fn * res = t.get_plugin().mk_project_fn(t, col_cnt, removed_cols);
1063         if(!res && col_cnt==t.get_signature().size()) {
1064             //all columns are projected out
1065             res = alloc(null_signature_table_project_fn);
1066         }
1067         if(!res) {
1068             res = alloc(default_table_project_fn, t.get_signature(), col_cnt, removed_cols);
1069         }
1070         return res;
1071     }
1072 
1073 
1074     class relation_manager::default_table_join_project_fn : public convenient_table_join_project_fn {
1075         scoped_ptr<table_join_fn> m_join;
1076         scoped_ptr<table_transformer_fn> m_project;
1077 
1078         unsigned_vector m_removed_cols;
1079     public:
default_table_join_project_fn(join_fn * join,const table_base & t1,const table_base & t2,unsigned joined_col_cnt,const unsigned * cols1,const unsigned * cols2,unsigned removed_col_cnt,const unsigned * removed_cols)1080         default_table_join_project_fn(join_fn * join, const table_base & t1, const table_base & t2,
1081                 unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt,
1082                 const unsigned * removed_cols)
1083             : convenient_table_join_project_fn(t1.get_signature(), t2.get_signature(), joined_col_cnt, cols1,
1084                 cols2, removed_col_cnt, removed_cols),
1085             m_join(join),
1086             m_removed_cols(removed_col_cnt, removed_cols) {}
1087 
1088         class unreachable_reducer : public table_row_pair_reduce_fn {
operator ()(table_element * func_columns,const table_element * merged_func_columns)1089             void operator()(table_element * func_columns, const table_element * merged_func_columns) override {
1090                 //we do project_with_reduce only if we are sure there will be no reductions
1091                 //(see code of the table_signature::from_join_project function)
1092                 UNREACHABLE();
1093             }
1094         };
1095 
operator ()(const table_base & t1,const table_base & t2)1096         table_base * operator()(const table_base & t1, const table_base & t2) override {
1097             table_base * aux = (*m_join)(t1, t2);
1098             if(m_project==0) {
1099                 relation_manager & rmgr = aux->get_plugin().get_manager();
1100                 if(get_result_signature().functional_columns()!=0) {
1101                     //to preserve functional columns we need to do the project_with_reduction
1102                     unreachable_reducer * reducer = alloc(unreachable_reducer);
1103                     m_project = rmgr.mk_project_with_reduce_fn(*aux, m_removed_cols.size(), m_removed_cols.data(), reducer);
1104                 }
1105                 else {
1106                     m_project = rmgr.mk_project_fn(*aux, m_removed_cols);
1107                 }
1108                 if(!m_project) {
1109                     throw default_exception("projection for table does not exist");
1110                 }
1111             }
1112             table_base * res = (*m_project)(*aux);
1113             aux->deallocate();
1114             return res;
1115         }
1116     };
1117 
mk_join_project_fn(const table_base & t1,const table_base & t2,unsigned joined_col_cnt,const unsigned * cols1,const unsigned * cols2,unsigned removed_col_cnt,const unsigned * removed_cols)1118     table_join_fn * relation_manager::mk_join_project_fn(const table_base & t1, const table_base & t2,
1119             unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2,
1120             unsigned removed_col_cnt, const unsigned * removed_cols) {
1121         table_join_fn * res = t1.get_plugin().mk_join_project_fn(t1, t2, joined_col_cnt, cols1, cols2,
1122             removed_col_cnt, removed_cols);
1123         if(!res && &t1.get_plugin()!=&t2.get_plugin()) {
1124             res = t2.get_plugin().mk_join_project_fn(t1, t2, joined_col_cnt, cols1, cols2, removed_col_cnt,
1125                 removed_cols);
1126         }
1127         if(!res) {
1128             table_join_fn * join = mk_join_fn(t1, t2, joined_col_cnt, cols1, cols2);
1129             if(join) {
1130                 res = alloc(default_table_join_project_fn, join, t1, t2, joined_col_cnt, cols1, cols2,
1131                     removed_col_cnt, removed_cols);
1132             }
1133         }
1134         return res;
1135 
1136     }
1137 
1138     class relation_manager::default_table_rename_fn
1139             : public convenient_table_rename_fn, auxiliary_table_transformer_fn {
1140     public:
default_table_rename_fn(const table_signature & orig_sig,unsigned permutation_cycle_len,const unsigned * permutation_cycle)1141         default_table_rename_fn(const table_signature & orig_sig, unsigned permutation_cycle_len,
1142                     const unsigned * permutation_cycle)
1143                 : convenient_table_rename_fn(orig_sig, permutation_cycle_len, permutation_cycle) {
1144             SASSERT(permutation_cycle_len>=2);
1145         }
1146 
get_result_signature() const1147         const table_signature & get_result_signature() const override {
1148             return convenient_table_rename_fn::get_result_signature();
1149         }
1150 
modify_fact(table_fact & f) const1151         void modify_fact(table_fact & f) const override {
1152             permutate_by_cycle(f, m_cycle);
1153         }
1154 
operator ()(const table_base & t)1155         table_base * operator()(const table_base & t) override {
1156             return auxiliary_table_transformer_fn::operator()(t);
1157         }
1158 
1159     };
1160 
mk_rename_fn(const table_base & t,unsigned permutation_cycle_len,const unsigned * permutation_cycle)1161     table_transformer_fn * relation_manager::mk_rename_fn(const table_base & t, unsigned permutation_cycle_len,
1162             const unsigned * permutation_cycle) {
1163         table_transformer_fn * res = t.get_plugin().mk_rename_fn(t, permutation_cycle_len, permutation_cycle);
1164         if(!res) {
1165             res = alloc(default_table_rename_fn, t.get_signature(), permutation_cycle_len, permutation_cycle);
1166         }
1167         return res;
1168     }
1169 
mk_permutation_rename_fn(const table_base & t,const unsigned * permutation)1170     table_transformer_fn * relation_manager::mk_permutation_rename_fn(const table_base & t,
1171             const unsigned * permutation) {
1172         table_transformer_fn * res = t.get_plugin().mk_permutation_rename_fn(t, permutation);
1173         if(!res) {
1174             res = alloc(default_table_permutation_rename_fn, t, permutation);
1175         }
1176         return res;
1177     }
1178 
1179 
1180     class relation_manager::default_table_union_fn : public table_union_fn {
1181         table_fact m_row;
1182     public:
operator ()(table_base & tgt,const table_base & src,table_base * delta)1183         void operator()(table_base & tgt, const table_base & src, table_base * delta) override {
1184             for (table_base::row_interface& a : src) {
1185                 a.get_fact(m_row);
1186 
1187                 if (delta) {
1188                     if(!tgt.contains_fact(m_row)) {
1189                         tgt.add_new_fact(m_row);
1190                         delta->add_fact(m_row);
1191                     }
1192                 }
1193                 else {
1194                     //if there's no delta, we don't need to know whether we are actually adding a new fact
1195                     tgt.add_fact(m_row);
1196                 }
1197             }
1198         }
1199     };
1200 
mk_union_fn(const table_base & tgt,const table_base & src,const table_base * delta)1201     table_union_fn * relation_manager::mk_union_fn(const table_base & tgt, const table_base & src,
1202             const table_base * delta) {
1203         table_union_fn * res = tgt.get_plugin().mk_union_fn(tgt, src, delta);
1204         if(!res && &tgt.get_plugin()!=&src.get_plugin()) {
1205             res = src.get_plugin().mk_union_fn(tgt, src, delta);
1206         }
1207         if(!res && delta && &tgt.get_plugin()!=&delta->get_plugin() && &src.get_plugin()!=&delta->get_plugin()) {
1208             res = delta->get_plugin().mk_union_fn(tgt, src, delta);
1209         }
1210         if(!res) {
1211             res = alloc(default_table_union_fn);
1212         }
1213         return res;
1214     }
1215 
mk_widen_fn(const table_base & tgt,const table_base & src,const table_base * delta)1216     table_union_fn * relation_manager::mk_widen_fn(const table_base & tgt, const table_base & src,
1217             const table_base * delta) {
1218         table_union_fn * res = tgt.get_plugin().mk_widen_fn(tgt, src, delta);
1219         if(!res && &tgt.get_plugin()!=&src.get_plugin()) {
1220             res = src.get_plugin().mk_widen_fn(tgt, src, delta);
1221         }
1222         if(!res && delta && &tgt.get_plugin()!=&delta->get_plugin() && &src.get_plugin()!=&delta->get_plugin()) {
1223             res = delta->get_plugin().mk_widen_fn(tgt, src, delta);
1224         }
1225         if(!res) {
1226             res = mk_union_fn(tgt, src, delta);
1227         }
1228         return res;
1229     }
1230 
1231 
1232     /**
1233        An auixiliary class for functors that perform filtering. It performs the table traversal
1234        and only asks for each individual row whether it should be removed.
1235 
1236        When using this class in multiple inheritance, this class should not be inherited publicly
1237        and should be mentioned as last. This should ensure that deteletion of the object will
1238        go well when initiated from a pointer to the first ancestor.
1239     */
1240     class relation_manager::auxiliary_table_filter_fn {
1241         table_fact m_row;
1242         svector<table_element> m_to_remove;
1243     public:
~auxiliary_table_filter_fn()1244         virtual ~auxiliary_table_filter_fn() {}
1245         virtual bool should_remove(const table_fact & f) const = 0;
1246 
operator ()(table_base & r)1247         void operator()(table_base & r) {
1248             m_to_remove.reset();
1249             unsigned sz = 0;
1250             for (table_base::row_interface& a : r) {
1251                 a.get_fact(m_row);
1252                 if (should_remove(m_row)) {
1253                     m_to_remove.append(m_row.size(), m_row.data());
1254                     ++sz;
1255                 }
1256             }
1257             r.remove_facts(sz, m_to_remove.data());
1258         }
1259     };
1260 
1261     class relation_manager::default_table_filter_identical_fn : public table_mutator_fn, auxiliary_table_filter_fn {
1262         const unsigned m_col_cnt;
1263         const unsigned_vector m_identical_cols;
1264     public:
default_table_filter_identical_fn(unsigned col_cnt,const unsigned * identical_cols)1265         default_table_filter_identical_fn(unsigned col_cnt, const unsigned * identical_cols)
1266                 : m_col_cnt(col_cnt),
1267                 m_identical_cols(col_cnt, identical_cols) {
1268             SASSERT(col_cnt>=2);
1269         }
1270 
should_remove(const table_fact & f) const1271         bool should_remove(const table_fact & f) const override {
1272             table_element val=f[m_identical_cols[0]];
1273             for(unsigned i=1; i<m_col_cnt; i++) {
1274                 if(f[m_identical_cols[i]]!=val) {
1275                     return true;
1276                 }
1277             }
1278             return false;
1279         }
1280 
operator ()(table_base & t)1281         void operator()(table_base & t) override {
1282             auxiliary_table_filter_fn::operator()(t);
1283         }
1284 
1285     };
1286 
mk_filter_identical_fn(const table_base & t,unsigned col_cnt,const unsigned * identical_cols)1287     table_mutator_fn * relation_manager::mk_filter_identical_fn(const table_base & t, unsigned col_cnt,
1288             const unsigned * identical_cols) {
1289         table_mutator_fn * res = t.get_plugin().mk_filter_identical_fn(t, col_cnt, identical_cols);
1290         if(!res) {
1291             res = alloc(default_table_filter_identical_fn, col_cnt, identical_cols);
1292         }
1293         return res;
1294     }
1295 
1296 
1297 
1298     class relation_manager::default_table_filter_equal_fn : public table_mutator_fn, auxiliary_table_filter_fn {
1299         const table_element m_value;
1300         const unsigned m_col;
1301     public:
default_table_filter_equal_fn(const table_element & value,unsigned col)1302         default_table_filter_equal_fn(const table_element & value, unsigned col)
1303                 : m_value(value),
1304                 m_col(col) {}
1305 
should_remove(const table_fact & f) const1306         bool should_remove(const table_fact & f) const override {
1307             return f[m_col]!=m_value;
1308         }
1309 
operator ()(table_base & t)1310         void operator()(table_base & t) override {
1311             auxiliary_table_filter_fn::operator()(t);
1312         }
1313     };
1314 
mk_filter_equal_fn(const table_base & t,const table_element & value,unsigned col)1315     table_mutator_fn * relation_manager::mk_filter_equal_fn(const table_base & t,
1316             const table_element & value, unsigned col) {
1317         table_mutator_fn * res = t.get_plugin().mk_filter_equal_fn(t, value, col);
1318         if(!res) {
1319             res = alloc(default_table_filter_equal_fn, value, col);
1320         }
1321         return res;
1322     }
1323 
1324     class relation_manager::default_table_filter_not_equal_fn
1325             : public table_mutator_fn, auxiliary_table_filter_fn {
1326         unsigned      m_column;
1327         uint64_t      m_value;
1328     public:
default_table_filter_not_equal_fn(context & ctx,unsigned column,uint64_t value)1329         default_table_filter_not_equal_fn(context & ctx, unsigned column, uint64_t value)
1330             : m_column(column),
1331               m_value(value) {
1332         }
1333 
should_remove(const table_fact & f) const1334         bool should_remove(const table_fact & f) const override {
1335             return f[m_column] == m_value;
1336         }
1337 
operator ()(table_base & t)1338         void operator()(table_base & t) override {
1339             auxiliary_table_filter_fn::operator()(t);
1340         }
1341 
mk(context & ctx,expr * condition)1342         static table_mutator_fn* mk(context& ctx, expr* condition) {
1343             ast_manager& m = ctx.get_manager();
1344             if (!m.is_not(condition)) {
1345                 return nullptr;
1346             }
1347             condition = to_app(condition)->get_arg(0);
1348             if (!m.is_eq(condition)) {
1349                 return nullptr;
1350             }
1351             expr* x = to_app(condition)->get_arg(0);
1352             expr* y = to_app(condition)->get_arg(1);
1353             if (!is_var(x)) {
1354                 std::swap(x, y);
1355             }
1356             if (!is_var(x)) {
1357                 return nullptr;
1358             }
1359             dl_decl_util decl_util(m);
1360             uint64_t value = 0;
1361             if (!decl_util.is_numeral_ext(y, value)) {
1362                 return nullptr;
1363             }
1364             return alloc(default_table_filter_not_equal_fn, ctx, to_var(x)->get_idx(), value);
1365         }
1366     };
1367 
1368 
1369 
1370     class relation_manager::default_table_filter_interpreted_fn
1371             : public table_mutator_fn, auxiliary_table_filter_fn {
1372         ast_manager & m_ast_manager;
1373         var_subst & m_vs;
1374         dl_decl_util & m_decl_util;
1375         th_rewriter & m_simp;
1376         app_ref m_condition;
1377         expr_free_vars m_free_vars;
1378         mutable expr_ref_vector m_args;
1379     public:
default_table_filter_interpreted_fn(context & ctx,unsigned col_cnt,app * condition)1380         default_table_filter_interpreted_fn(context & ctx, unsigned col_cnt,  app* condition)
1381                 : m_ast_manager(ctx.get_manager()),
1382                   m_vs(ctx.get_var_subst()),
1383                   m_decl_util(ctx.get_decl_util()),
1384                   m_simp(ctx.get_rewriter()),
1385                   m_condition(condition, ctx.get_manager()),
1386                   m_args(ctx.get_manager()) {
1387             m_free_vars(m_condition);
1388         }
1389 
should_remove(const table_fact & f) const1390         bool should_remove(const table_fact & f) const override {
1391             expr_ref_vector& args = m_args;
1392 
1393             args.reset();
1394             //arguments need to be in reverse order for the substitution
1395             unsigned col_cnt = f.size();
1396             for(int i = col_cnt; i-- > 0;) {
1397                 if (!m_free_vars.contains(i)) {
1398                     args.push_back(nullptr);
1399                     continue; //this variable does not occur in the condition;
1400                 }
1401 
1402                 table_element el = f[i];
1403                 args.push_back(m_decl_util.mk_numeral(el, m_free_vars[i]));
1404             }
1405 
1406             expr_ref ground = m_vs(m_condition.get(), args);
1407             m_simp(ground);
1408 
1409             return m_ast_manager.is_false(ground);
1410         }
1411 
operator ()(table_base & t)1412         void operator()(table_base & t) override {
1413             auxiliary_table_filter_fn::operator()(t);
1414         }
1415     };
1416 
mk_filter_interpreted_fn(const table_base & t,app * condition)1417     table_mutator_fn * relation_manager::mk_filter_interpreted_fn(const table_base & t, app * condition) {
1418         context & ctx = get_context();
1419         table_mutator_fn * res = t.get_plugin().mk_filter_interpreted_fn(t, condition);
1420         if (!res) {
1421             res = default_table_filter_not_equal_fn::mk(ctx, condition);
1422         }
1423         if(!res) {
1424             res = alloc(default_table_filter_interpreted_fn, ctx, t.get_signature().size(), condition);
1425         }
1426         return res;
1427     }
1428 
1429 
1430     class relation_manager::default_table_filter_interpreted_and_project_fn
1431             : public table_transformer_fn {
1432         scoped_ptr<table_mutator_fn> m_filter;
1433         scoped_ptr<table_transformer_fn> m_project;
1434         app_ref m_condition;
1435         unsigned_vector m_removed_cols;
1436     public:
default_table_filter_interpreted_and_project_fn(context & ctx,table_mutator_fn * filter,app * condition,unsigned removed_col_cnt,const unsigned * removed_cols)1437         default_table_filter_interpreted_and_project_fn(context & ctx, table_mutator_fn * filter,
1438             app * condition, unsigned removed_col_cnt, const unsigned * removed_cols)
1439                 : m_filter(filter), m_condition(condition, ctx.get_manager()),
1440                 m_removed_cols(removed_col_cnt, removed_cols) {}
1441 
operator ()(const table_base & tb)1442         table_base* operator()(const table_base & tb) override {
1443             scoped_rel<table_base> t2 = tb.clone();
1444             (*m_filter)(*t2);
1445             if (!m_project) {
1446                 relation_manager & rmgr = t2->get_plugin().get_manager();
1447                 m_project = rmgr.mk_project_fn(*t2, m_removed_cols.size(), m_removed_cols.data());
1448                 if (!m_project) {
1449                     throw default_exception("projection does not exist");
1450                 }
1451             }
1452             return (*m_project)(*t2);
1453         }
1454     };
1455 
mk_filter_interpreted_and_project_fn(const table_base & t,app * condition,unsigned removed_col_cnt,const unsigned * removed_cols)1456     table_transformer_fn * relation_manager::mk_filter_interpreted_and_project_fn(const table_base & t,
1457         app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) {
1458         table_transformer_fn * res = t.get_plugin().mk_filter_interpreted_and_project_fn(t, condition, removed_col_cnt, removed_cols);
1459         if (res)
1460             return res;
1461 
1462         table_mutator_fn * filter = mk_filter_interpreted_fn(t, condition);
1463         SASSERT(filter);
1464         res = alloc(default_table_filter_interpreted_and_project_fn, get_context(), filter, condition, removed_col_cnt, removed_cols);
1465         return res;
1466     }
1467 
1468 
mk_filter_by_intersection_fn(const table_base & t,const table_base & src,unsigned joined_col_cnt,const unsigned * t_cols,const unsigned * src_cols)1469     table_intersection_filter_fn * relation_manager::mk_filter_by_intersection_fn(const table_base & t,
1470         const table_base & src, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * src_cols) {
1471         table_intersection_filter_fn * res = t.get_plugin().mk_filter_by_negation_fn(t, src, joined_col_cnt,
1472             t_cols, src_cols);
1473         if(!res && &t.get_plugin()!=&src.get_plugin()) {
1474             res = src.get_plugin().mk_filter_by_negation_fn(t, src, joined_col_cnt, t_cols, src_cols);
1475         }
1476         return res;
1477     }
1478 
1479 
1480 
1481     class relation_manager::default_table_negation_filter_fn : public convenient_table_negation_filter_fn,
1482                                              auxiliary_table_filter_fn {
1483         const table_base * m_negated_table;
1484         mutable table_fact m_aux_fact;
1485     public:
default_table_negation_filter_fn(const table_base & tgt,const table_base & neg_t,unsigned joined_col_cnt,const unsigned * t_cols,const unsigned * negated_cols)1486         default_table_negation_filter_fn(const table_base & tgt, const table_base & neg_t,
1487                     unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * negated_cols)
1488                 : convenient_table_negation_filter_fn(tgt, neg_t, joined_col_cnt, t_cols, negated_cols),
1489                 m_negated_table(nullptr) {
1490             m_aux_fact.resize(neg_t.get_signature().size());
1491         }
1492 
should_remove(const table_fact & f) const1493         bool should_remove(const table_fact & f) const override {
1494             if(!m_all_neg_bound || m_overlap) {
1495                 table_base::iterator nit = m_negated_table->begin();
1496                 table_base::iterator nend = m_negated_table->end();
1497                 for(; nit!=nend; ++nit) {
1498                     const table_base::row_interface & nrow = *nit;
1499                     if(bindings_match(nrow, f)) {
1500                         return true;
1501                     }
1502                 }
1503                 return false;
1504             }
1505             else {
1506                 make_neg_bindings<datalog::table_fact>(m_aux_fact, f);
1507                 return m_negated_table->contains_fact(m_aux_fact);
1508             }
1509         }
1510 
operator ()(table_base & tgt,const table_base & negated_table)1511         void operator()(table_base & tgt, const table_base & negated_table) override {
1512             SASSERT(m_negated_table==0);
1513             flet<const table_base *> flet_neg_table(m_negated_table, &negated_table);
1514             auxiliary_table_filter_fn::operator()(tgt);
1515         }
1516 
1517     };
1518 
mk_filter_by_negation_fn(const table_base & t,const table_base & negated_obj,unsigned joined_col_cnt,const unsigned * t_cols,const unsigned * negated_cols)1519     table_intersection_filter_fn * relation_manager::mk_filter_by_negation_fn(const table_base & t,
1520             const table_base & negated_obj, unsigned joined_col_cnt,
1521             const unsigned * t_cols, const unsigned * negated_cols) {
1522         table_intersection_filter_fn * res = t.get_plugin().mk_filter_by_negation_fn(t, negated_obj, joined_col_cnt,
1523             t_cols, negated_cols);
1524         if(!res && &t.get_plugin()!=&negated_obj.get_plugin()) {
1525             res = negated_obj.get_plugin().mk_filter_by_negation_fn(t, negated_obj, joined_col_cnt, t_cols,
1526                 negated_cols);
1527         }
1528         if(!res) {
1529             res = alloc(default_table_negation_filter_fn, t, negated_obj, joined_col_cnt, t_cols, negated_cols);
1530         }
1531         return res;
1532     }
1533 
1534 
mk_filter_by_negated_join_fn(const table_base & t,const table_base & src1,const table_base & src2,unsigned_vector const & t_cols,unsigned_vector const & src_cols,unsigned_vector const & src1_cols,unsigned_vector const & src2_cols)1535     table_intersection_join_filter_fn* relation_manager::mk_filter_by_negated_join_fn(
1536         const table_base & t,
1537         const table_base & src1,
1538         const table_base & src2,
1539         unsigned_vector const& t_cols,
1540         unsigned_vector const& src_cols,
1541         unsigned_vector const& src1_cols,
1542         unsigned_vector const& src2_cols) {
1543         return t.get_plugin().mk_filter_by_negated_join_fn(t, src1, src2, t_cols, src_cols, src1_cols, src2_cols);
1544     }
1545 
1546 
1547 
1548     class relation_manager::default_table_select_equal_and_project_fn : public table_transformer_fn {
1549         scoped_ptr<table_mutator_fn> m_filter;
1550         scoped_ptr<table_transformer_fn> m_project;
1551     public:
default_table_select_equal_and_project_fn(table_mutator_fn * filter,table_transformer_fn * project)1552         default_table_select_equal_and_project_fn(table_mutator_fn * filter, table_transformer_fn * project)
1553             : m_filter(filter), m_project(project) {}
1554 
operator ()(const table_base & t1)1555         table_base * operator()(const table_base & t1) override {
1556             TRACE("dl", tout << t1.get_plugin().get_name() << "\n";);
1557             scoped_rel<table_base> aux = t1.clone();
1558             (*m_filter)(*aux);
1559             return (*m_project)(*aux);
1560         }
1561     };
1562 
mk_select_equal_and_project_fn(const table_base & t,const table_element & value,unsigned col)1563     table_transformer_fn * relation_manager::mk_select_equal_and_project_fn(const table_base & t,
1564             const table_element & value, unsigned col) {
1565         table_transformer_fn * res = t.get_plugin().mk_select_equal_and_project_fn(t, value, col);
1566         if(!res) {
1567             table_mutator_fn * selector = mk_filter_equal_fn(t, value, col);
1568             SASSERT(selector);
1569             table_transformer_fn * projector = mk_project_fn(t, 1, &col);
1570             SASSERT(projector);
1571             res = alloc(default_table_select_equal_and_project_fn, selector, projector);
1572         }
1573         return res;
1574     }
1575 
1576 
1577     class relation_manager::default_table_map_fn : public table_mutator_fn {
1578         scoped_ptr<table_row_mutator_fn> m_mapper;
1579         unsigned m_first_functional;
1580         scoped_rel<table_base> m_aux_table;
1581         scoped_ptr<table_union_fn> m_union_fn;
1582         table_fact m_curr_fact;
1583     public:
default_table_map_fn(const table_base & t,table_row_mutator_fn * mapper)1584         default_table_map_fn(const table_base & t, table_row_mutator_fn * mapper)
1585                 : m_mapper(mapper), m_first_functional(t.get_signature().first_functional()) {
1586             SASSERT(t.get_signature().functional_columns()>0);
1587             table_plugin & plugin = t.get_plugin();
1588             m_aux_table = plugin.mk_empty(t.get_signature());
1589             m_union_fn = plugin.mk_union_fn(t, *m_aux_table, static_cast<table_base *>(nullptr));
1590         }
1591 
~default_table_map_fn()1592         ~default_table_map_fn() override {}
1593 
operator ()(table_base & t)1594         void operator()(table_base & t) override {
1595             SASSERT(t.get_signature()==m_aux_table->get_signature());
1596             if(!m_aux_table->empty()) {
1597                 m_aux_table->reset();
1598             }
1599 
1600             for (table_base::row_interface& a : t) {
1601                 a.get_fact(m_curr_fact);
1602                 if((*m_mapper)(m_curr_fact.data()+m_first_functional)) {
1603                     m_aux_table->add_fact(m_curr_fact);
1604                 }
1605             }
1606 
1607             t.reset();
1608             (*m_union_fn)(t, *m_aux_table, static_cast<table_base *>(nullptr));
1609         }
1610     };
1611 
mk_map_fn(const table_base & t,table_row_mutator_fn * mapper)1612     table_mutator_fn * relation_manager::mk_map_fn(const table_base & t, table_row_mutator_fn * mapper) {
1613         SASSERT(t.get_signature().functional_columns()>0);
1614         table_mutator_fn * res = t.get_plugin().mk_map_fn(t, mapper);
1615         if(!res) {
1616             res = alloc(default_table_map_fn, t, mapper);
1617         }
1618         return res;
1619     }
1620 
1621 
1622     class relation_manager::default_table_project_with_reduce_fn : public convenient_table_transformer_fn {
1623         unsigned_vector m_removed_cols;
1624         const unsigned m_inp_col_cnt;
1625         const unsigned m_removed_col_cnt;
1626         const unsigned m_result_col_cnt;
1627         scoped_ptr<table_row_pair_reduce_fn> m_reducer;
1628         unsigned m_res_first_functional;
1629         table_fact m_row;
1630         table_fact m_former_row;
1631     public:
default_table_project_with_reduce_fn(const table_signature & orig_sig,unsigned removed_col_cnt,const unsigned * removed_cols,table_row_pair_reduce_fn * reducer)1632         default_table_project_with_reduce_fn(const table_signature & orig_sig, unsigned removed_col_cnt,
1633                     const unsigned * removed_cols, table_row_pair_reduce_fn * reducer)
1634                 : m_removed_cols(removed_col_cnt, removed_cols),
1635                 m_inp_col_cnt(orig_sig.size()),
1636                 m_removed_col_cnt(removed_col_cnt),
1637                 m_result_col_cnt(orig_sig.size()-removed_col_cnt),
1638                 m_reducer(reducer) {
1639             SASSERT(removed_col_cnt>0);
1640             table_signature::from_project_with_reduce(orig_sig, removed_col_cnt, removed_cols,
1641                 get_result_signature());
1642             m_res_first_functional = get_result_signature().first_functional();
1643             m_row.resize(get_result_signature().size());
1644             m_former_row.resize(get_result_signature().size());
1645         }
1646 
~default_table_project_with_reduce_fn()1647         ~default_table_project_with_reduce_fn() override {}
1648 
modify_fact(table_fact & f) const1649         virtual void modify_fact(table_fact & f) const {
1650             unsigned ofs=1;
1651             unsigned r_i=1;
1652             for(unsigned i=m_removed_cols[0]+1; i<m_inp_col_cnt; i++) {
1653                 if(r_i!=m_removed_col_cnt && m_removed_cols[r_i]==i) {
1654                     r_i++;
1655                     ofs++;
1656                     continue;
1657                 }
1658                 f[i-ofs]=f[i];
1659             }
1660             SASSERT(r_i==m_removed_col_cnt);
1661             f.resize(m_result_col_cnt);
1662         }
1663 
mk_project(table_base::iterator & it)1664         void mk_project(table_base::iterator& it)  {
1665             for (unsigned i = 0, j = 0, r_i = 0; i < m_inp_col_cnt; ++i) {
1666                 if (r_i < m_removed_col_cnt && m_removed_cols[r_i] == i) {
1667                     ++r_i;
1668                 }
1669                 else {
1670                     m_row[j] = m_former_row[j] = (*it)[i];
1671                     ++j;
1672                 }
1673             }
1674         }
1675 
operator ()(const table_base & t)1676         table_base * operator()(const table_base & t) override {
1677             table_plugin & plugin = t.get_plugin();
1678             const table_signature & res_sign = get_result_signature();
1679             SASSERT(plugin.can_handle_signature(res_sign));
1680             table_base * res = plugin.mk_empty(res_sign);
1681 
1682             table_base::iterator it = t.begin(), end = t.end();
1683             for (; it != end; ++it) {
1684                 mk_project(it);
1685                 if (!res->suggest_fact(m_former_row)) {
1686                     (*m_reducer)(m_former_row.data()+m_res_first_functional, m_row.data()+m_res_first_functional);
1687                     res->ensure_fact(m_former_row);
1688                 }
1689             }
1690             return res;
1691         }
1692     };
1693 
mk_project_with_reduce_fn(const table_base & t,unsigned col_cnt,const unsigned * removed_cols,table_row_pair_reduce_fn * reducer)1694     table_transformer_fn * relation_manager::mk_project_with_reduce_fn(const table_base & t, unsigned col_cnt,
1695             const unsigned * removed_cols, table_row_pair_reduce_fn * reducer) {
1696         SASSERT(t.get_signature().functional_columns()>0);
1697         table_transformer_fn * res = t.get_plugin().mk_project_with_reduce_fn(t, col_cnt, removed_cols, reducer);
1698         if(!res) {
1699             res = alloc(default_table_project_with_reduce_fn, t.get_signature(), col_cnt, removed_cols, reducer);
1700         }
1701         return res;
1702     }
1703 
1704 };
1705 
1706