#pragma once
#include "ast/arith_decl_plugin.h"
#include "ast/seq_decl_plugin.h"
#include "util/obj_hashtable.h"
namespace seq {
class parikh {
public:
struct config {
unsigned m_k = 2; unsigned m_n = 2; unsigned m_max_chars = 6; unsigned m_max_size = 25; unsigned m_max_counters = 5000;
};
private:
struct block {
expr* m_e = nullptr;
unsigned m_char = 0; bool m_is_char = false; bool m_unit = false; };
typedef std::pair<unsigned, unsigned> block_pair;
ast_manager& m;
seq_util m_util;
arith_util m_autil;
config m_config;
obj_hashtable<expr> m_defined;
expr_ref_vector m_pinned;
unsigned m_p = 0; unsigned m_mod = 1; unsigned_vector m_chars;
expr_ref mk_sk(char const* name, std::initializer_list<expr*> args, sort* range);
expr_ref num(int i);
expr_ref sum(expr_ref_vector const& args);
expr_ref conj(expr_ref_vector const& args);
void push_impl(expr_ref_vector& defs, expr* cond, expr* e);
bool fresh(expr* key);
rational num_grams(unsigned level) const;
unsigned char_index(unsigned ch) const;
bool has_char(expr_ref_vector const& side) const;
void collect_chars(expr_ref_vector const& side);
void collect_blocks(expr_ref_vector const& side, vector<block>& blocks);
static void adjacent(vector<block> const& blocks, svector<block_pair>& out);
expr_ref len(block const& b);
expr_ref is_empty(block const& b);
expr_ref first(block const& b, unsigned c);
expr_ref last(block const& b, unsigned c);
expr_ref count(block const& b, unsigned level, unsigned gram, unsigned r);
expr_ref window(block const& b, unsigned level, expr_ref_vector& defs);
expr_ref indicator(expr* cond, expr_ref_vector& defs);
expr_ref clock(expr* prefix_len, expr_ref_vector& defs);
expr_ref clock_is(expr* clk, unsigned v);
void define_block(block const& b, expr_ref_vector& defs);
void define_letters(block const& b, expr_ref_vector& defs);
void define_level(block const& b, unsigned level, expr_ref_vector& defs);
void define_flow(block const& b, expr_ref_vector& defs);
void totals(vector<block> const& blocks, unsigned level, expr_ref_vector& out, expr_ref_vector& defs);
void add_observer(vector<block> const& l, vector<block> const& r, unsigned mod,
expr_ref_vector& defs, expr_ref_vector& eqs);
bool over_budget(vector<block> const& l, vector<block> const& r, unsigned_vector const& moduli);
public:
parikh(ast_manager& m, config const& c);
void updt_config(config const& c);
bool operator()(expr_ref_vector const& l, expr_ref_vector const& r,
expr_ref_vector& defs, expr_ref_vector& eqs);
void membership_constraints(expr* str, expr* re, expr_ref_vector& out);
private:
unsigned compute_length_stride(expr* re);
public:
bool encode_length_set(expr* str, expr* re, expr_ref_vector& out);
private:
expr_ref mk_count_var(expr_ref_vector& out, expr* str_key, expr* root_re, unsigned& idx);
void push_zero_guard(expr_ref_vector& out, expr* count, expr* c1);
bool rec(expr* re, expr* count, expr* str_key, expr* root_re, unsigned& idx,
expr_ref_vector& out, expr_ref& contrib);
};
}