1#ifndef LALA_CORE_TERNARIZE_HPP 
    2#define LALA_CORE_TERNARIZE_HPP 
   12    std::string varname(x.lv().data());
 
   13    return varname.starts_with(
"__CONSTANT_");
 
 
   21  std::string varname(x.lv().data());
 
   22  varname = varname.substr(11);
 
   23  varname[0] = varname[0] == 
'm' ? 
'-' : varname[0];
 
   24  return std::stoi(varname);
 
 
   29  return f.is_binary() && f.seq(0).is_variable() &&
 
   30    (f.sig() == 
EQ || f.sig() == 
EQUIV) &&
 
   31    f.seq(1).is_binary() && f.seq(1).seq(0).is_variable() &&
 
   32    f.seq(1).seq(1).is_variable();
 
 
   37template <
class F, 
class Env>
 
   41  using allocator_type = battery::standard_allocator;
 
   44  static bool is_extended_ternary_form(
const F& f) {
 
   46    return (vars == 1 && (f.is(F::E) || (f.is_binary() && f.sig() != 
NEQ && f.sig() != 
IN && (f.seq(0).is_variable() || f.seq(1).is_variable()) && (f.seq(0).is_constant() || f.seq(1).is_constant())))) ||
 
   47      (vars == 3 && f.is_binary() && f.sig() == 
EQ &&
 
   48         ((f.seq(0).is_variable() && f.seq(1).is_binary() && is_ternary_op(f.seq(1).sig()) && f.seq(1).seq(0).is_variable() && f.seq(1).seq(1).is_variable())
 
   49       || (f.seq(1).is_variable() && f.seq(0).is_binary() && is_ternary_op(f.seq(0).sig()) && f.seq(0).seq(0).is_variable() && f.seq(0).seq(1).is_variable())));
 
   52  static bool is_ternary_op(
Sig sig) {
 
   57  void introduce_existing_var(
const std::string& varname) {
 
   58    if(varname.starts_with(
"__VAR_Z_")) {
 
   59      introduced_int_vars = std::max((
unsigned int)std::stoul(varname.substr(8))+1, introduced_int_vars);
 
   61    else if(varname.starts_with(
"__VAR_B_")) {
 
   62      introduced_bool_vars = std::max((
unsigned int)std::stoul(varname.substr(8))+1, introduced_bool_vars);
 
   68  Ternarizer(
const Env& env):
 
   69    introduced_int_vars(0),
 
   70    introduced_bool_vars(0),
 
   71    introduced_constants(0),
 
   75    for(
int i = 0; i < env.num_vars(); ++i) {
 
   76      introduce_existing_var(std::string(env[i].name.data()));
 
   82  battery::vector<F, allocator_type> conjunction;
 
   83  battery::vector<F, allocator_type> existentials;
 
   84  std::unordered_map<std::string, int> name2exists;
 
   85  unsigned int introduced_int_vars;
 
   86  unsigned int introduced_bool_vars;
 
   87  unsigned int introduced_constants;
 
   89  F introduce_var(
const std::string& name, 
auto sort, 
bool constant) {
 
   90    auto var_name = LVar<allocator_type>(name.data());
 
   91    assert(!env.contains(name.data()));
 
   92    existentials.push_back(F::make_exists(
UNTYPED, var_name, sort));
 
   93    assert(!name2exists.contains(name));
 
   94    name2exists[name] = existentials.size() - 1;
 
   95    if(constant) { introduced_constants++; }
 
   96    else if(sort.is_int()) { introduced_int_vars++; }
 
   97    else if(sort.is_bool()) { introduced_bool_vars++; }
 
   98    return F::make_lvar(
UNTYPED, var_name);
 
  101  F introduce_int_var() {
 
  102    std::string name = 
"__VAR_Z_" + std::to_string(introduced_int_vars);
 
  106  F introduce_bool_var() {
 
  107    std::string name = 
"__VAR_B_" + std::to_string(introduced_bool_vars);
 
  112  F ternarize_constant(
const F& f) {
 
  113    assert(f.is(F::Z) || f.is(F::B));
 
  114    auto index = f.to_z();
 
  115    std::string name = 
"__CONSTANT_" + (index < 0 ? std::string(
"m") : std::string(
"")) + std::to_string(abs(index));
 
  117    if (name2exists.contains(name) || env.contains(name.data())) {
 
  118      return F::make_lvar(
UNTYPED, LVar<allocator_type>(name.data()));
 
  120    auto var = introduce_var(name, f.sort().value(), 
true);
 
  121    conjunction.push_back(F::make_binary(var, 
EQ, f));
 
  127  bool simplify_to_unary(F x, F y, 
Sig sig, F z) {
 
  135        conjunction.push_back(F::make_binary(yv, 
GT, zv));
 
  138        conjunction.push_back(F::make_binary(yv, sig, zv));
 
  146  F push_ternary(F x, F y, 
Sig sig, F z) {
 
  147    if(simplify_to_unary(x,y,sig,z)) {
 
  152      conjunction.push_back(F::make_binary(y, 
EQ, F::make_binary(x, 
ADD, z)));
 
  156    conjunction.push_back(F::make_binary(x, 
EQ, F::make_binary(y, sig, z)));
 
  160  F ternarize_unary(
const F& f, 
bool toplevel = 
false) {
 
  165        F t = push_ternary(introduce_int_var(), 
ternarize(F::make_z(0)), 
SUB, x);
 
  167          return ternarize(F::make_binary(t, 
NEQ, F::make_z(0)), 
true);
 
  174        F t2 = introduce_int_var();
 
  175        compute(F::make_binary(t2, 
EQ, F::make_binary(x, 
MAX, t1)));
 
  176        compute(F::make_binary(t2, 
GEQ, F::make_z(0)));
 
  178          return ternarize(F::make_binary(t2, 
NEQ, F::make_z(0)), 
true);
 
  183      case NOT: 
return ternarize(F::make_binary(x, 
EQ, F::make_z(0)), toplevel);
 
  186        conjunction.push_back(F::make_unary(f.sig(), x));
 
  190        printf(
"%% Detected during ternarization (during preprocessing): Unary operator %s not supported\n", 
string_of_sig(f.sig()));
 
  191        printf(
"%% In formula: "); f.print(); printf(
"\n");
 
  197  bool is_boolean(
const F& f) {
 
  199    std::string varname(f.lv().data());
 
  200    if(name2exists.contains(varname)) {
 
  201      return battery::get<1>(existentials[name2exists[varname]].exists()).is_bool();
 
  204      auto var_opt = env.variable_of(varname.data());
 
  205      if(var_opt.has_value()) {
 
  206        return var_opt->get().sort.is_bool();
 
  216  F booleanize(
const F& t, 
Sig sig) {
 
  223  F ternarize_binary(F f, 
bool toplevel) {
 
  224    if(f.sig() == 
IN && f.is_binary() && f.seq(0).is_variable() && f.seq(1).is(F::S)) {
 
  230        if(f.seq(1).s().size() > 1) {
 
  231          conjunction.push_back(f);
 
  233        return F::make_true(); 
 
  245    bool almost_ternary = 
false;
 
  249    if((((f.seq(0).is_variable() || f.seq(0).is_constant()) && f.seq(1).is_binary())
 
  250     ||((f.seq(1).is_variable() || f.seq(1).is_constant()) && f.seq(0).is_binary()))
 
  251     && (f.sig() == 
EQUIV || f.sig() == 
EQ))
 
  253      int left = f.seq(0).is_binary();
 
  254      int right = f.seq(1).is_binary();
 
  256      if(f.seq(right).sig() == 
IN) {
 
  262      almost_ternary = 
true;
 
  265    t1 = booleanize(t1, f.sig());
 
  267    t2 = booleanize(t2, f.sig());
 
  268    if(!almost_ternary) {
 
  270      if(toplevel && (f.sig() == 
NEQ || f.sig() == 
XOR || f.sig() == 
IMPLY || f.sig() == 
GT || f.sig() == 
LT)) {}
 
  272        || ((f.sig() == 
MIN || f.sig() == 
MAX) && is_boolean(t1) && is_boolean(t2)))
 
  274        t0 = toplevel ? ternarize_constant(F::make_z(1)) : introduce_bool_var();
 
  277        t0 = toplevel ? ternarize_constant(F::make_z(1)) : introduce_int_var();
 
  282      case MIN: 
return push_ternary(t0, t1, 
MIN, t2);
 
  284      case MAX: 
return push_ternary(t0, t1, 
MAX, t2);
 
  286      case EQUIV: 
return push_ternary(t0, t1, 
EQ, t2);
 
  291          return push_ternary(ternarize_constant(F::make_z(0)), t1, 
EQ, t2);
 
  297      case LEQ: 
return push_ternary(t0, t1, 
LEQ, t2);
 
  299      case GEQ: 
return push_ternary(t0, t2, 
LEQ, t1);
 
  303          return push_ternary(ternarize_constant(F::make_z(0)), t1, 
LEQ, t2);
 
  311          return push_ternary(ternarize_constant(F::make_z(0)), t2, 
LEQ, t1);
 
  317        return push_ternary(t0, t1, f.sig(), t2);
 
  322  std::pair<F, F> binarize_middle(
const F& f) {
 
  323    assert(f.is(F::Seq) && f.seq().size() > 2);
 
  324    battery::vector<F, allocator_type> left;
 
  325    battery::vector<F, allocator_type> right;
 
  327    for(i = 0; i < f.seq().size() / 2; ++i) {
 
  328      left.push_back(f.seq(i));
 
  330    for(; i < f.seq().size(); ++i) {
 
  331      right.push_back(f.seq(i));
 
  334      ternarize(left.size() == 1 ? left.back() : F::make_nary(f.sig(), std::move(left))),
 
  335      ternarize(right.size() == 1 ? right.back() : F::make_nary(f.sig(), std::move(right)))};
 
  338  F ternarize_nary(
const F& f, 
bool toplevel) {
 
  340      auto [t1, t2] = binarize_middle(f);
 
  341      return ternarize(F::make_binary(t1, f.sig(), t2), toplevel);
 
  344      F tmp = 
ternarize(F::make_binary(f.seq(0), f.sig(), f.seq(1)));
 
  345      for (
int i = 2; i < f.seq().size() - 1; i++) {
 
  346        tmp = 
ternarize(F::make_binary(tmp, f.sig(), f.seq(i)));
 
  348      tmp = 
ternarize(F::make_binary(tmp, f.sig(), f.seq(f.seq().size() - 1)), toplevel);
 
  353  F 
ternarize(
const F& f, 
bool toplevel = 
false) {
 
  354    if (f.is_variable()) {
 
  356        return ternarize(F::make_binary(f, 
NEQ, F::make_z(0)), 
true);
 
  360    else if (f.is(F::Z) || f.is(F::B)) {
 
  362        return f.to_z() != 0 ? F::make_true() : F::make_false();
 
  364      return ternarize_constant(f);
 
  366    else if (f.is(F::S)) {
 
  369    else if (f.is_unary()) {
 
  370      return ternarize_unary(f, toplevel);
 
  372    else if (f.is_binary()) {
 
  373      return ternarize_binary(f, toplevel);
 
  375    else if (f.is(F::Seq) && f.seq().size() > 2) {
 
  376      return ternarize_nary(f, toplevel);
 
  378    printf(
"%% Detected during ternarization (during preprocessing): unsupported formula.");
 
  385  void compute(
const F& f) {
 
  386    if (f.is(F::Seq) && f.sig() == 
AND) {
 
  387      const auto& seq = f.seq();
 
  388      for (
int i = 0; i < seq.size(); ++i) {
 
  392    else if(f.is(F::E)) {
 
  393      existentials.push_back(f);
 
  394      std::string varname(battery::get<0>(f.exists()).data());
 
  395      name2exists[varname] = existentials.size() - 1;
 
  401      introduce_existing_var(varname);
 
  403    else if(!f.is(F::ESeq) && !is_extended_ternary_form(f)) {
 
  408      conjunction.push_back(f);
 
  413    auto ternarized_formula = std::move(existentials);
 
  414    for (
int i = 0; i < conjunction.size(); ++i) {
 
  415      ternarized_formula.push_back(std::move(conjunction[i]));
 
  417    if(ternarized_formula.size() == 1) {
 
  418      return std::move(ternarized_formula[0]);
 
  420    return F::make_nary(
AND, std::move(ternarized_formula), 
UNTYPED, 
false);
 
  432template <
class F, 
class Env = VarEnv<battery::standard_allocator>>
 
  433F 
ternarize(
const F& f, 
const Env& env = Env(), 
const std::vector<int>& constants = {}) {
 
  434  impl::Ternarizer<F, Env> ternarizer(env);
 
  435  for(
int c : constants) {
 
  436    ternarizer.ternarize_constant(F::make_z(c));
 
  438  ternarizer.compute(f);
 
  439  return std::move(ternarizer).create();
 
 
Definition abstract_deps.hpp:14
 
bool is_constant_var(const F &x)
Definition ternarize.hpp:10
 
int value_of_constant(const F &x)
Definition ternarize.hpp:19
 
CUDA NI constexpr bool is_associative(Sig sig)
Definition ast.hpp:242
 
@ XOR
Logical connector.
Definition ast.hpp:114
 
@ NEQ
Equality relations.
Definition ast.hpp:112
 
@ LEQ
Unary arithmetic function symbols.
Definition ast.hpp:113
 
@ NOT
Unary arithmetic function symbols.
Definition ast.hpp:114
 
@ IMPLY
Unary arithmetic function symbols.
Definition ast.hpp:114
 
@ OR
Unary arithmetic function symbols.
Definition ast.hpp:114
 
@ EQ
Unary arithmetic function symbols.
Definition ast.hpp:112
 
@ GEQ
Unary arithmetic function symbols.
Definition ast.hpp:113
 
@ ADD
Unary arithmetic function symbols.
Definition ast.hpp:97
 
@ IN
Set membership predicate.
Definition ast.hpp:108
 
@ MIN
Unary arithmetic function symbols.
Definition ast.hpp:97
 
@ GT
Arithmetic comparison predicates. When applied to set, it corresponds to the lexicographic ordering o...
Definition ast.hpp:113
 
@ MAX
Binary arithmetic function symbols.
Definition ast.hpp:97
 
@ LT
Unary arithmetic function symbols.
Definition ast.hpp:113
 
@ AND
Unary arithmetic function symbols.
Definition ast.hpp:114
 
@ MAXIMIZE
Unary "meta-predicate" indicating that its argument must be maximized, according to the increasing or...
Definition ast.hpp:116
 
@ MINIMIZE
Same as MAXIMIZE, but for minimization.
Definition ast.hpp:117
 
@ EQUIV
Unary arithmetic function symbols.
Definition ast.hpp:114
 
@ ABS
Unary arithmetic function symbols.
Definition ast.hpp:96
 
@ SUB
Unary arithmetic function symbols.
Definition ast.hpp:97
 
@ NEG
Unary arithmetic function symbols.
Definition ast.hpp:96
 
CUDA NI constexpr bool is_predicate(Sig sig)
Definition ast.hpp:260
 
CUDA NI const char * string_of_sig(Sig sig)
Definition ast.hpp:121
 
CUDA NI int num_vars(const F &f)
Definition algorithm.hpp:154
 
F ternarize(const F &f, const Env &env=Env(), const std::vector< int > &constants={})
Definition ternarize.hpp:433
 
CUDA NI constexpr bool is_logical(Sig sig)
Definition ast.hpp:256
 
CUDA bool is_tnf(const F &f)
Definition ternarize.hpp:28
 
CUDA F decompose_in_constraint(const F &f, const typename F::allocator_type &alloc=typename F::allocator_type())
Definition algorithm.hpp:944
 
#define UNTYPED
Definition sort.hpp:21
 
@ Bool
Definition sort.hpp:28
 
@ Int
Definition sort.hpp:29