Skip to content

Commit

Permalink
adding plugin for local search strings
Browse files Browse the repository at this point in the history
  • Loading branch information
NikolajBjorner committed Nov 22, 2024
1 parent 3672575 commit b4e768c
Show file tree
Hide file tree
Showing 4 changed files with 389 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/ast/sls/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ z3_add_component(ast_sls
sls_context.cpp
sls_datatype_plugin.cpp
sls_euf_plugin.cpp
sls_seq_plugin.cpp
sls_smt_plugin.cpp
sls_smt_solver.cpp
COMPONENT_DEPENDENCIES
Expand Down
306 changes: 306 additions & 0 deletions src/ast/sls/sls_seq_plugin.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,306 @@
/*++
Copyright (c) 2024 Microsoft Corporation
Module Name:
sls_seq_plugin.cpp
Abstract:
Sequence/String SLS
Author:
Nikolaj Bjorner (nbjorner) 2024-11-22
--*/

#include "ast/sls/sls_seq_plugin.h"
#include "ast/sls/sls_context.h"


namespace sls {

seq_plugin::seq_plugin(context& c):
plugin(c),
seq(c.get_manager())
{}

void seq_plugin::propagate_literal(sat::literal lit) {
}

expr_ref seq_plugin::get_value(expr* e) {
return expr_ref(m);
}

bool seq_plugin::propagate() {
return false;
}

bool seq_plugin::is_sat() {
return true;
}

void seq_plugin::register_term(expr* e) {
}

std::ostream& seq_plugin::display(std::ostream& out) const {
return out;
}

bool seq_plugin::set_value(expr* e, expr* v) {
return false;
}

zstring& seq_plugin::strval0(expr* e) {
SASSERT(seq.is_string(e->get_sort()));
unsigned id = e->get_id();
m_values.reserve(id + 1);
if (!m_values[id])
m_values.set(id, alloc(eval, m));
return m_values[id]->val0.svalue;
}

bool seq_plugin::bval1(expr* e) {
SASSERT(is_app(e));
if (to_app(e)->get_family_id() == seq.get_family_id())
return bval1_seq(to_app(e));

NOT_IMPLEMENTED_YET();
return false;
}

bool seq_plugin::bval1_seq(app* e) {
expr* a, *b;
switch (e->get_decl_kind()) {
case OP_SEQ_CONTAINS: {
VERIFY(seq.str.is_contains(e, a, b));
if (seq.is_string(a->get_sort()))
return strval0(a).contains(strval0(b));
else {
NOT_IMPLEMENTED_YET();
}
break;
}
case OP_SEQ_PREFIX:
case OP_SEQ_SUFFIX:
case OP_SEQ_NTH:
case OP_SEQ_NTH_I:
case OP_SEQ_NTH_U:
case OP_SEQ_IN_RE:
case OP_SEQ_FOLDL:
case OP_SEQ_FOLDLI:
case OP_STRING_LT:
case OP_STRING_LE:
case OP_STRING_IS_DIGIT:
NOT_IMPLEMENTED_YET();
break;
default:
break;
}
return false;
}

zstring const& seq_plugin::strval1(expr* e) {
SASSERT(is_app(e));
SASSERT(seq.is_string(e->get_sort()));
if (to_app(e)->get_family_id() == seq.get_family_id()) {
switch (to_app(e)->get_decl_kind()) {
case OP_SEQ_UNIT:
case OP_SEQ_EMPTY:
case OP_SEQ_CONCAT:
case OP_SEQ_EXTRACT:
case OP_SEQ_REPLACE:
case OP_SEQ_AT:
case OP_SEQ_NTH:
case OP_SEQ_NTH_I:
case OP_SEQ_NTH_U:
case OP_SEQ_LENGTH:
case OP_SEQ_INDEX:
case OP_SEQ_LAST_INDEX:
case OP_SEQ_TO_RE:
case OP_SEQ_IN_RE:
case OP_SEQ_REPLACE_RE_ALL:
case OP_SEQ_REPLACE_RE:
case OP_SEQ_REPLACE_ALL:
case OP_SEQ_MAP:
case OP_SEQ_MAPI:
case OP_SEQ_FOLDL:
case OP_SEQ_FOLDLI:
case OP_RE_PLUS:
case OP_RE_STAR:
case OP_RE_OPTION:
case OP_RE_RANGE:
case OP_RE_CONCAT:
case OP_RE_UNION:
case OP_RE_DIFF:
case OP_RE_INTERSECT:
case OP_RE_LOOP:
case OP_RE_POWER:
case OP_RE_COMPLEMENT:
case OP_RE_EMPTY_SET:
case OP_RE_FULL_SEQ_SET:
case OP_RE_FULL_CHAR_SET:
case OP_RE_OF_PRED:
case OP_RE_REVERSE:
case OP_RE_DERIVATIVE:
case OP_STRING_CONST:
case OP_STRING_ITOS:
case OP_STRING_STOI:
case OP_STRING_UBVTOS:
case OP_STRING_SBVTOS:
case OP_STRING_LT:
case OP_STRING_LE:
case OP_STRING_IS_DIGIT:
case OP_STRING_TO_CODE:
case OP_STRING_FROM_CODE:
NOT_IMPLEMENTED_YET();
break;
default:
UNREACHABLE();
break;
}
}
auto const& v = strval0(e);
m_values[e->get_id()]->val1.svalue = v;
return m_values[e->get_id()]->val1.svalue;
}

void seq_plugin::repair_up(app* e) {
}

bool seq_plugin::repair_down(app* e) {
switch (e->get_decl_kind()) {
case OP_SEQ_UNIT:
case OP_SEQ_EMPTY:
case OP_SEQ_CONCAT:
case OP_SEQ_PREFIX:
case OP_SEQ_SUFFIX:
case OP_SEQ_CONTAINS:
return repair_contains(e);
case OP_SEQ_EXTRACT:
case OP_SEQ_REPLACE:
case OP_SEQ_AT:
case OP_SEQ_NTH:
case OP_SEQ_NTH_I:
case OP_SEQ_NTH_U:
case OP_SEQ_LENGTH:
case OP_SEQ_INDEX:
case OP_SEQ_LAST_INDEX:
case OP_SEQ_TO_RE:
case OP_SEQ_IN_RE:
case OP_SEQ_REPLACE_RE_ALL:
case OP_SEQ_REPLACE_RE:
case OP_SEQ_REPLACE_ALL:
case OP_SEQ_MAP:
case OP_SEQ_MAPI:
case OP_SEQ_FOLDL:
case OP_SEQ_FOLDLI:
case OP_RE_PLUS:
case OP_RE_STAR:
case OP_RE_OPTION:
case OP_RE_RANGE:
case OP_RE_CONCAT:
case OP_RE_UNION:
case OP_RE_DIFF:
case OP_RE_INTERSECT:
case OP_RE_LOOP:
case OP_RE_POWER:
case OP_RE_COMPLEMENT:
case OP_RE_EMPTY_SET:
case OP_RE_FULL_SEQ_SET:
case OP_RE_FULL_CHAR_SET:
case OP_RE_OF_PRED:
case OP_RE_REVERSE:
case OP_RE_DERIVATIVE:
case OP_STRING_CONST:
case OP_STRING_ITOS:
case OP_STRING_STOI:
case OP_STRING_UBVTOS:
case OP_STRING_SBVTOS:
case OP_STRING_LT:
case OP_STRING_LE:
case OP_STRING_IS_DIGIT:
case OP_STRING_TO_CODE:
case OP_STRING_FROM_CODE:
default:
break;
}
return false;
}

bool seq_plugin::repair_contains(expr* e) {
expr* a, *b;
VERIFY(seq.str.is_contains(e, a, b));
zstring sa = strval0(a);
zstring sb = strval0(b);
unsigned lena = sa.length();
unsigned lenb = sb.length();

m_str_updates.reset();
if (ctx.is_true(e)) {
// add b to a in front
// add b to a in back
// add part of b to a front/back
// take random subsequence of a and set it to b
// reduce size of b

m_str_updates.push_back({ a, sb + sa, 1 });
m_str_updates.push_back({ a, sa + sb, 1 });
if (lena > 1) {
unsigned mid = ctx.rand(lena-2) + 1;
zstring sa1 = sa.extract(0, mid);
zstring sa2 = sa.extract(mid, lena - mid);
m_str_updates.push_back({ a, sa1 + sb + sa2, 1});
}
if (lenb > 0) {
m_str_updates.push_back({ b, sb.extract(0, lenb-1), 1});
m_str_updates.push_back({ b, sb.extract(1, lenb-1), 1});
}
}
else {
// remove occurrences of b in a, if b is non-empty
// append character to b
// set b to be a + character
//
}
return apply_str_update();
}

bool seq_plugin::apply_str_update() {
double sum_scores = 0;
for (auto const& [e, val, score] : m_str_updates)
sum_scores += score;

while (!m_str_updates.empty()) {
unsigned i = m_str_updates.size();
double lim = sum_scores * ((double)ctx.rand() / random_gen().max_value());
do {
lim -= m_str_updates[--i].m_score;
}
while (lim >= 0 && i > 0);

auto [e, value, score] = m_str_updates[i];

if (update(e, value))
return true;

sum_scores -= score;
m_str_updates[i] = m_str_updates.back();
m_str_updates.pop_back();
}

return false;
}

bool seq_plugin::update(expr* e, zstring const& value) {
strval0(e) = value;
ctx.new_value_eh(e);
return true;
}


void seq_plugin::repair_literal(sat::literal lit) {
}

}
81 changes: 81 additions & 0 deletions src/ast/sls/sls_seq_plugin.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*++
Copyright (c) 2024 Microsoft Corporation
Module Name:
sls_seq_plugin.h
Abstract:
Sequence/String SLS
Author:
Nikolaj Bjorner (nbjorner) 2024-11-22
--*/
#pragma once

#include "ast/sls/sls_context.h"
#include "ast/seq_decl_plugin.h"


namespace sls {

class seq_plugin : public plugin {
struct value {
value(ast_manager& m): evalue(m) {}
zstring svalue;
expr_ref evalue;
};

struct eval {
eval(ast_manager& m):
val0(m), val1(m) {}
value val0;
value val1;
};

seq_util seq;
scoped_ptr_vector<eval> m_values;

struct str_update {
expr* e;
zstring value;
unsigned m_score;
};
vector<str_update> m_str_updates;
bool apply_str_update();
bool update(expr* e, zstring const& value);

bool bval1(expr* e);
bool bval1_seq(app* e);
zstring& strval0(expr* e);
zstring const& strval1(expr* e);

bool repair_contains(expr* e);

public:
seq_plugin(context& c);
~seq_plugin() override {}
expr_ref get_value(expr* e) override;
void initialize() override {}
void start_propagation() override {}
void propagate_literal(sat::literal lit) override;
bool propagate() override;
bool is_sat() override;
void register_term(expr* e) override;
std::ostream& display(std::ostream& out) const override;
bool set_value(expr* e, expr* v) override;
bool include_func_interp(func_decl* f) const override { return true; }

void repair_up(app* e) override;
bool repair_down(app* e) override;
void repair_literal(sat::literal lit) override;

void collect_statistics(statistics& st) const override {}
void reset_statistics() override {}

};

}
Loading

0 comments on commit b4e768c

Please sign in to comment.