3#ifndef LALA_POWER_TABLES_HPP
4#define LALA_POWER_TABLES_HPP
6#include "battery/vector.hpp"
7#include "battery/shared_ptr.hpp"
8#include "battery/dynamic_bitset.hpp"
9#include "lala/logic/logic.hpp"
10#include "lala/universes/primitive_upset.hpp"
11#include "lala/abstract_deps.hpp"
15template <
class A,
class U,
class Alloc>
class Table;
18 struct is_table_like {
19 static constexpr bool value =
false;
21 template<
class A,
class U,
class Alloc>
22 struct is_table_like<Table<A, U, Alloc>> {
23 static constexpr bool value =
true;
31template <
class A,
class U =
typename A::universe_type,
class Allocator =
typename A::allocator_type>
46 constexpr static const bool sequential = sub_type::sequential;
55 constexpr static const char*
name =
"Table";
57 using table_type = battery::vector<universe_type, allocator_type>;
58 using bitset_type = battery::dynamic_bitset<memory_type, allocator_type>;
66 battery::vector<battery::vector<AVar, allocator_type>,
allocator_type> headers;
69 battery::vector<bitset_type, allocator_type> eliminated_rows;
73 battery::vector<bitset_type, allocator_type> bitset_store;
76 template <
class Alloc>
82 battery::vector<battery::vector<AVar, Alloc>, Alloc>
headers;
98 template <
class TableTellType>
99 CUDA NI
tell_type(
const TableTellType& other,
const Alloc& alloc = Alloc{})
107 return headers.get_allocator();
110 template <
class Alloc2>
114 template <
class Alloc>
119 battery::vector<battery::vector<AVar, Alloc>, Alloc>
headers;
132 template <
class TableAskType>
133 CUDA NI
ask_type(
const TableAskType& other,
const Alloc& alloc = Alloc{})
140 return headers.get_allocator();
143 template <
class Alloc2>
147 template <
class A2,
class U2,
class Alloc2>
153 , store_aty(store_aty)
154 , sub(std::move(sub))
158 , eliminated_rows(alloc)
162 :
Table(uid, sub->
aty(), sub, alloc)
165 template<
class A2,
class U2,
class Alloc2,
class... Allocators>
168 , store_aty(other.store_aty)
169 , sub(deps.template clone<
sub_type>(other.sub))
181 return headers.get_allocator();
189 return tell_table.size() == 0 && sub->is_bot();
193 for(
int i = 0; i < eliminated_rows.size(); ++i) {
194 if(eliminated_rows[i].count() == tell_table.size()) {
198 return sub->is_top();
202 AType atype_sub = UNTYPED,
206 return Table{atype, battery::allocate_shared<sub_type>(alloc, sub_type::bot(atype_sub, sub_alloc)), alloc};
211 AType atype_sub = UNTYPED,
215 return Table{atype, battery::allocate_shared<sub_type>(sub_alloc, sub_type::top(atype_sub, sub_alloc)), alloc};
223 AType atype_sub = env.extends_abstract_dom();
224 AType atype = env.extends_abstract_dom();
225 return bot(atype, atype_sub, alloc, sub_alloc);
233 AType atype_sub = env.extends_abstract_dom();
234 AType atype = env.extends_abstract_dom();
235 return top(atype, atype_sub, alloc, sub_alloc);
238 template <
class Alloc2>
249 template <
class SnapshotType>
250 CUDA
snapshot_type(
const SnapshotType& other,
const Alloc2& alloc = Alloc2())
261 template <
class Alloc2 = allocator_type>
266 template <
class Alloc2>
271 tell_table.resize(0);
275 for(
int i = 0; i < eliminated_rows.size(); ++i) {
276 eliminated_rows[i].reset();
281 CUDA
void flatten_and(
const F& f,
typename F::Sequence& conjuncts)
const {
282 if(f.is(F::Seq) && f.sig() == AND) {
283 for(
int i = 0; i < f.seq().size(); ++i) {
288 conjuncts.push_back(f);
293 CUDA
void flatten_or(
const F& f,
typename F::Sequence& disjuncts)
const {
294 if(f.is(F::Seq) && f.sig() == OR) {
295 for(
int i = 0; i < f.seq().size(); ++i) {
300 typename F::Sequence conjuncts{disjuncts.get_allocator()};
302 if(conjuncts.size() > 1) {
303 disjuncts.push_back(F::make_nary(AND, std::move(conjuncts)));
306 disjuncts.push_back(std::move(conjuncts[0]));
312 CUDA F
flatten(
const F& f,
const typename F::allocator_type& alloc)
const {
313 typename F::Sequence disjuncts{alloc};
315 if(disjuncts.size() > 1) {
316 return F::make_nary(OR, std::move(disjuncts));
319 return std::move(disjuncts[0]);
323 template <IKind kind,
bool diagnose = false,
class F,
class Env,
class Alloc>
325 battery::vector<AVar, Alloc>& header,
326 battery::vector<battery::vector<local_universe, Alloc>, Alloc>& tell_table2,
327 battery::vector<battery::vector<local_universe, Alloc>, Alloc>& ask_table2,
328 const F& f, Env& env, IDiagnostics& diagnostics)
const
330 if(num_vars(f) != 1) {
331 RETURN_INTERPRETATION_ERROR(
"Only unary formulas are supported in the cell of the table.");
334 auto x_opt = var_in(f, env);
335 if(!x_opt.has_value() || !x_opt->get().avar_of(store_aty).has_value()) {
336 RETURN_INTERPRETATION_ERROR(
"Undeclared variable.");
338 AVar x = x_opt->get().avar_of(store_aty).value();
340 for(; idx < header.size() && header[idx] != x; ++idx) {}
342 if(idx == header.size()) {
344 for(
int i = 0; i < tell_table2.size(); ++i) {
345 if constexpr(kind == IKind::TELL) {
346 tell_table2[i].push_back(local_universe::bot());
348 ask_table2[i].push_back(local_universe::bot());
352 if(ginterpret_in<IKind::ASK, diagnose>(f, env, ask_u, diagnostics)) {
353 ask_table2.back()[idx].tell(ask_u);
354 if constexpr(kind == IKind::TELL) {
356 if(ginterpret_in<IKind::TELL, diagnose>(f, env, tell_u, diagnostics)) {
357 tell_table2.back()[idx].tell(tell_u);
371 template <
class Alloc1,
class Alloc2>
373 const battery::vector<battery::vector<local_universe, Alloc1>, Alloc1>& table,
const Alloc2& alloc)
const
375 if(table.size() == 0) {
return battery::vector<local_universe, Alloc2>(alloc);}
376 battery::vector<local_universe, Alloc2> res(alloc);
377 res.reserve(table.size() * table[0].size());
378 for(
int i = 0; i < table.size(); ++i) {
379 for(
int j = 0; j < table[i].size(); ++j) {
380 res.push_back(table[i][j]);
383 return std::move(res);
387 template <IKind kind,
bool diagnose = false,
class F,
class Env,
class I>
388 CUDA NI
bool interpret(
const F& f2, Env& env, I& intermediate, IDiagnostics& diagnostics)
const {
389 F f =
flatten(f2, env.get_allocator());
390 using Alloc =
typename I::allocator_type;
391 if(f.is(F::Seq) && f.sig() == OR) {
392 battery::vector<AVar, Alloc> header(intermediate.get_allocator());
393 battery::vector<battery::vector<local_universe, Alloc>, Alloc> tell_table2(intermediate.get_allocator());
394 battery::vector<battery::vector<local_universe, Alloc>, Alloc> ask_table2(intermediate.get_allocator());
395 for(
int i = 0; i < f.seq().size(); ++i) {
397 tell_table2.push_back(battery::vector<local_universe, Alloc>(header.size(), local_universe::bot(), intermediate.get_allocator()));
398 ask_table2.push_back(battery::vector<local_universe, Alloc>(header.size(), local_universe::bot(), intermediate.get_allocator()));
399 if(f.seq(i).is(F::Seq) && f.seq(i).sig() == AND) {
400 const auto& row = f.seq(i).seq();
401 for(
int j = 0; j < row.size(); ++j) {
402 size_t error_ctx = diagnostics.num_suberrors();
407 diagnostics.cut(error_ctx);
413 size_t error_ctx = diagnostics.num_suberrors();
418 diagnostics.cut(error_ctx);
424 if(header.size() > 1) {
425 auto ask_table2_flatten =
flatten_table(ask_table2, ask_table2.get_allocator());
426 if((intermediate.ask_table.size() == 0 || intermediate.ask_table == ask_table2_flatten) &&
427 (ask_table.size() == 0 || ask_table == ask_table2_flatten))
429 intermediate.headers.push_back(std::move(header));
430 if(intermediate.ask_table.size() == 0 && ask_table.size() == 0) {
431 if constexpr(kind == IKind::TELL) {
432 intermediate.tell_table =
flatten_table(tell_table2, tell_table2.get_allocator());
434 intermediate.ask_table = std::move(ask_table2_flatten);
439 RETURN_INTERPRETATION_ERROR(
"This abstract domain can only represent multiple tables over a same matrix of values, but a difference was detected.");
446 template <
bool diagnose = false,
class F,
class Env,
class Alloc>
451 template <
bool diagnose = false,
class F,
class Env,
class Alloc>
465 return headers.size();
469 template <IKind kind>
471 if constexpr(std::is_same_v<universe_type, sub_universe_type>) {
475 VarEnv<battery::standard_allocator> env;
476 IDiagnostics diagnostics;
478 bool succeed = ginterpret_in<kind>(x.deinterpret(AVar{}, env), env, v, diagnostics);
484 CUDA
size_t num_columns()
const {
485 return headers[0].size();
488 CUDA
size_t num_rows()
const {
489 return tell_table.size() / num_columns();
493 template <
class Alloc,
class Mem>
496 has_changed.tell_top();
502 assert(tell_table.size() == 0);
507 for(
int i = 0; i < t.
headers.size(); ++i) {
515 template <
class Alloc>
517 local::BInc has_changed;
518 return tell(t, has_changed);
528 sub->
tell(x, dom, has_changed);
532 CUDA
size_t to1D(
int i,
int j)
const {
return i * num_columns() + j; }
535 template <
class Alloc>
536 CUDA local::BInc ask(
const battery::vector<battery::vector<AVar, Alloc>, Alloc>& headers)
const
538 for(
int i = 0; i < headers.size(); ++i) {
539 bool row_entailed =
false;
540 for(
int j = 0; j < num_rows(); ++j) {
542 for(
int k = 0; k < num_columns(); ++k) {
543 if(!(sub->project(headers[i][k]) >= convert<IKind::ASK>(ask_table[
to1D(j,k)]))) {
544 row_entailed =
false;
552 if(!row_entailed) {
return false; }
558 template <
class Alloc>
565 CUDA
void refine(
size_t table_num,
size_t col, BInc<Mem>& has_changed) {
567 for(
int j = 0; j < num_rows(); ++j) {
568 auto r = convert<IKind::TELL>(tell_table[
to1D(j,col)]);
569 if(!eliminated_rows[table_num].test(j)) {
570 if(join(r, sub->project(headers[table_num][col])).is_top()) {
571 eliminated_rows[table_num].set(j);
572 has_changed.tell_top();
579 sub->tell(headers[table_num][col], u, has_changed);
585 sub->num_refinements() +
586 headers.size() * num_columns();
590 CUDA
void refine(
size_t i, BInc<Mem>& has_changed) {
593 sub->refine(i, has_changed);
596 i -= sub->num_refinements();
598 refine(i % headers.size(), i / headers.size(), has_changed);
602 template <
class ExtractionStrategy = NonAtomicExtraction>
603 CUDA
bool is_extractable(
const ExtractionStrategy& strategy = ExtractionStrategy())
const {
605 return ask(headers) && sub->is_extractable(strategy);
612 if constexpr(impl::is_table_like<B>::value) {
613 sub->extract(*ua.sub);
621 return sub->project(x);
625 CUDA NI TFormula<typename Env::allocator_type>
deinterpret(
const Env& env)
const {
626 using F = TFormula<typename Env::allocator_type>;
627 F sub_f = sub->deinterpret(env);
628 typename F::Sequence seq{env.get_allocator()};
629 if(sub_f.is(F::Seq) && sub_f.sig() == AND) {
630 seq = std::move(sub_f.seq());
633 seq.push_back(std::move(sub_f));
635 for(
int i = 0; i < headers.size(); ++i) {
636 typename F::Sequence disjuncts{env.get_allocator()};
637 for(
int j = 0; j < num_rows(); ++j) {
638 if(!eliminated_rows[i].test(j)) {
639 typename F::Sequence conjuncts{env.get_allocator()};
640 for(
int k = 0; k < num_columns(); ++k) {
641 if(!(sub->project(headers[i][k]) >= convert<IKind::ASK>(ask_table[
to1D(j,k)]))) {
642 conjuncts.push_back(tell_table[
to1D(j,k)].
deinterpret(headers[i][k], env));
645 disjuncts.push_back(F::make_nary(AND, std::move(conjuncts),
aty()));
648 seq.push_back(F::make_nary(OR, std::move(disjuncts),
aty()));
650 return F::make_nary(AND, std::move(seq));
battery::vector< universe_type, allocator_type > table_type
Definition table.hpp:57
CUDA NI Table(const Table< A2, U2, Alloc2 > &other, AbstractDeps< Allocators... > &deps)
Definition table.hpp:166
static CUDA this_type top(Env &env, const allocator_type &alloc=allocator_type(), const sub_allocator_type &sub_alloc=sub_allocator_type())
Definition table.hpp:229
CUDA NI bool interpret_atom(battery::vector< AVar, Alloc > &header, battery::vector< battery::vector< local_universe, Alloc >, Alloc > &tell_table2, battery::vector< battery::vector< local_universe, Alloc >, Alloc > &ask_table2, const F &f, Env &env, IDiagnostics &diagnostics) const
Definition table.hpp:324
static constexpr const bool is_totally_ordered
Definition table.hpp:47
CUDA Table(AType uid, AType store_aty, sub_ptr sub, const allocator_type &alloc=allocator_type())
Definition table.hpp:151
static constexpr const bool preserve_join
Definition table.hpp:51
CUDA size_t vars() const
Definition table.hpp:460
CUDA NI TFormula< typename Env::allocator_type > deinterpret(const Env &env) const
Definition table.hpp:625
CUDA this_type & tell(const tell_type< Alloc > &t, BInc< Mem > &has_changed)
Definition table.hpp:494
static constexpr const bool preserve_bot
Definition table.hpp:48
Allocator allocator_type
Definition table.hpp:34
CUDA sub_universe_type project(AVar x) const
Definition table.hpp:620
static CUDA this_type top(AType atype=UNTYPED, AType atype_sub=UNTYPED, const allocator_type &alloc=allocator_type(), const sub_allocator_type &sub_alloc=sub_allocator_type())
Definition table.hpp:210
abstract_ptr< sub_type > sub_ptr
Definition table.hpp:42
typename sub_universe_type::local_type sub_local_universe
Definition table.hpp:39
CUDA sub_ptr subdomain() const
Definition table.hpp:184
CUDA size_t num_tables() const
Definition table.hpp:464
static CUDA this_type bot(AType atype=UNTYPED, AType atype_sub=UNTYPED, const allocator_type &alloc=allocator_type(), const sub_allocator_type &sub_alloc=sub_allocator_type())
Definition table.hpp:201
typename universe_type::memory_type memory_type
Definition table.hpp:40
CUDA NI bool interpret_tell(const F &f, Env &env, tell_type< Alloc > &tell, IDiagnostics &diagnostics) const
Definition table.hpp:452
CUDA size_t to1D(int i, int j) const
Definition table.hpp:532
CUDA local::BInc is_top() const
Definition table.hpp:192
static constexpr const bool preserve_meet
Definition table.hpp:52
CUDA battery::vector< local_universe, Alloc2 > flatten_table(const battery::vector< battery::vector< local_universe, Alloc1 >, Alloc1 > &table, const Alloc2 &alloc) const
Definition table.hpp:372
static constexpr const char * name
Definition table.hpp:55
battery::dynamic_bitset< memory_type, allocator_type > bitset_type
Definition table.hpp:58
typename A::allocator_type sub_allocator_type
Definition table.hpp:35
typename universe_type::local_type local_universe
Definition table.hpp:37
CUDA allocator_type get_allocator() const
Definition table.hpp:180
typename A::universe_type sub_universe_type
Definition table.hpp:38
static constexpr const bool preserve_concrete_covers
Definition table.hpp:54
CUDA local::BInc ask(const ask_type< Alloc > &a) const
Definition table.hpp:559
CUDA NI bool interpret(const F &f2, Env &env, I &intermediate, IDiagnostics &diagnostics) const
Definition table.hpp:388
static constexpr const bool preserve_top
Definition table.hpp:49
A sub_type
Definition table.hpp:41
CUDA bool is_extractable(const ExtractionStrategy &strategy=ExtractionStrategy()) const
Definition table.hpp:603
CUDA snapshot_type< Alloc2 > snapshot(const Alloc2 &alloc=Alloc2()) const
Definition table.hpp:262
CUDA local::BDec is_bot() const
Definition table.hpp:188
CUDA AType aty() const
Definition table.hpp:176
static constexpr const bool is_abstract_universe
Definition table.hpp:45
static CUDA this_type bot(Env &env, const allocator_type &alloc=allocator_type(), const sub_allocator_type &sub_alloc=sub_allocator_type())
Definition table.hpp:219
CUDA const sub_universe_type & operator[](int x) const
Definition table.hpp:456
CUDA this_type & tell(AVar x, const sub_universe_type &dom)
Definition table.hpp:521
CUDA NI bool interpret_ask(const F &f, const Env &env, ask_type< Alloc > &ask, IDiagnostics &diagnostics) const
Definition table.hpp:447
CUDA Table(AType uid, sub_ptr sub, const allocator_type &alloc=allocator_type())
Definition table.hpp:161
CUDA void flatten_or(const F &f, typename F::Sequence &disjuncts) const
Definition table.hpp:293
CUDA this_type & tell(const tell_type< Alloc > &t)
Definition table.hpp:516
CUDA void refine(size_t i, BInc< Mem > &has_changed)
Definition table.hpp:590
CUDA size_t num_refinements() const
Definition table.hpp:583
CUDA this_type & tell(AVar x, const sub_universe_type &dom, BInc< Mem > &has_changed)
Definition table.hpp:527
U universe_type
Definition table.hpp:36
CUDA void extract(B &ua) const
Definition table.hpp:611
CUDA void restore(const snapshot_type< Alloc2 > &snap)
Definition table.hpp:267
static constexpr const bool sequential
Definition table.hpp:46
static constexpr const bool injective_concretization
Definition table.hpp:53
CUDA void flatten_and(const F &f, typename F::Sequence &conjuncts) const
Definition table.hpp:281
CUDA F flatten(const F &f, const typename F::allocator_type &alloc) const
Definition table.hpp:312
ask_type(ask_type &&)=default
ask_type & operator=(ask_type &&)=default
CUDA NI ask_type(const TableAskType &other, const Alloc &alloc=Alloc{})
Definition table.hpp:133
Alloc allocator_type
Definition table.hpp:116
CUDA ask_type(const Alloc &alloc=Alloc{})
Definition table.hpp:122
battery::vector< battery::vector< AVar, Alloc >, Alloc > headers
Definition table.hpp:119
battery::vector< universe_type, Alloc > ask_table
Definition table.hpp:120
ask_type(const ask_type &)=default
CUDA allocator_type get_allocator() const
Definition table.hpp:139
ask_type & operator=(const ask_type &)=default
A::template ask_type< Alloc > sub
Definition table.hpp:118
snapshot_type< Alloc2 > & operator=(const snapshot_type< Alloc2 > &)=default
sub_snap_type sub_snap
Definition table.hpp:241
CUDA snapshot_type(sub_snap_type &&sub_snap, size_t num_tables)
Definition table.hpp:255
sub_type::template snapshot_type< Alloc2 > sub_snap_type
Definition table.hpp:240
snapshot_type< Alloc2 > & operator=(snapshot_type< Alloc2 > &&)=default
snapshot_type(snapshot_type< Alloc2 > &&)=default
CUDA snapshot_type(const SnapshotType &other, const Alloc2 &alloc=Alloc2())
Definition table.hpp:250
snapshot_type(const snapshot_type< Alloc2 > &)=default
size_t num_tables
Definition table.hpp:242
A::template tell_type< Alloc > sub
Definition table.hpp:80
tell_type(const tell_type &)=default
CUDA NI tell_type(const TableTellType &other, const Alloc &alloc=Alloc{})
Definition table.hpp:99
Alloc allocator_type
Definition table.hpp:78
tell_type & operator=(tell_type &&)=default
battery::vector< universe_type, Alloc > ask_table
Definition table.hpp:85
tell_type(tell_type &&)=default
tell_type & operator=(const tell_type &)=default
CUDA allocator_type get_allocator() const
Definition table.hpp:106
battery::vector< battery::vector< AVar, Alloc >, Alloc > headers
Definition table.hpp:82
battery::vector< universe_type, Alloc > tell_table
Definition table.hpp:84
CUDA tell_type(const Alloc &alloc=Alloc{})
Definition table.hpp:87