Skip to content

Commit 18ba14c

Browse files
mtrberziNikolajBjorner
authored andcommitted
Z3str3: fix empty-string contradictions (#2538)
* z3str3: str.indexof second argument can be empty string without causing contradictions * z3str3: str.indexof second argument can be empty string without causing contradictions * z3str3: fixups for str.indexof * z3str3: str.indexof code cleanup
1 parent bc723fb commit 18ba14c

File tree

1 file changed

+65
-11
lines changed

1 file changed

+65
-11
lines changed

src/smt/theory_str.cpp

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,6 +1326,7 @@ namespace smt {
13261326

13271327
void theory_str::instantiate_axiom_Indexof(enode * e) {
13281328
context & ctx = get_context();
1329+
th_rewriter & rw = ctx.get_rewriter();
13291330
ast_manager & m = get_manager();
13301331

13311332
app * ex = e->get_owner();
@@ -1345,13 +1346,21 @@ namespace smt {
13451346
}
13461347
axiomatized_terms.insert(ex);
13471348

1349+
expr * exHaystack = nullptr;
1350+
expr * exNeedle = nullptr;
1351+
expr * exIndex = nullptr;
1352+
u.str.is_index(ex, exHaystack, exNeedle, exIndex);
1353+
13481354
TRACE("str", tout << "instantiate str.indexof axiom for " << mk_pp(ex, m) << std::endl;);
13491355

13501356
expr_ref x1(mk_str_var("x1"), m);
13511357
expr_ref x2(mk_str_var("x2"), m);
13521358
expr_ref indexAst(mk_int_var("index"), m);
13531359

1354-
expr_ref condAst(mk_contains(ex->get_arg(0), ex->get_arg(1)), m);
1360+
expr_ref condAst1(mk_contains(ex->get_arg(0), ex->get_arg(1)), m);
1361+
expr_ref condAst2(m.mk_not(ctx.mk_eq_atom(exNeedle, mk_string(""))), m);
1362+
expr_ref condAst(m.mk_and(condAst1, condAst2), m);
1363+
//expr_ref condAst(mk_contains(ex->get_arg(0), ex->get_arg(1)), m);
13551364
SASSERT(condAst);
13561365

13571366
// -----------------------
@@ -1376,7 +1385,11 @@ namespace smt {
13761385

13771386
// -----------------------
13781387
// false branch
1379-
expr_ref elseBranch(ctx.mk_eq_atom(indexAst, mk_int(-1)), m);
1388+
expr_ref elseBranch(m.mk_ite(
1389+
ctx.mk_eq_atom(exNeedle, mk_string("")),
1390+
ctx.mk_eq_atom(indexAst, mk_int(0)),
1391+
ctx.mk_eq_atom(indexAst, mk_int(-1))
1392+
), m);
13801393
SASSERT(elseBranch);
13811394

13821395
expr_ref breakdownAssert(m.mk_ite(condAst, thenBranch, elseBranch), m);
@@ -1386,7 +1399,7 @@ namespace smt {
13861399
SASSERT(reduceToIndex);
13871400

13881401
expr_ref finalAxiom(m.mk_and(breakdownAssert, reduceToIndex), m);
1389-
SASSERT(finalAxiom);
1402+
rw(finalAxiom);
13901403
assert_axiom(finalAxiom);
13911404

13921405
{
@@ -1408,6 +1421,7 @@ namespace smt {
14081421

14091422
void theory_str::instantiate_axiom_Indexof_extended(enode * _e) {
14101423
context & ctx = get_context();
1424+
th_rewriter & rw = ctx.get_rewriter();
14111425
ast_manager & m = get_manager();
14121426

14131427
app * e = _e->get_owner();
@@ -1436,6 +1450,7 @@ namespace smt {
14361450

14371451
expr_ref minus_one(m_autil.mk_numeral(rational::minus_one(), true), m);
14381452
expr_ref zero(m_autil.mk_numeral(rational::zero(), true), m);
1453+
expr_ref empty_string(mk_string(""), m);
14391454

14401455
// case split
14411456

@@ -1446,9 +1461,40 @@ namespace smt {
14461461
assert_implication(premise, conclusion);
14471462
}
14481463

1464+
// case 1.1: N == "" and i out of range
1465+
{
1466+
expr_ref premiseNEmpty(ctx.mk_eq_atom(N, empty_string), m);
1467+
// range check
1468+
expr_ref premiseRangeLower(m_autil.mk_le(i, minus_one), m);
1469+
expr_ref premiseRangeUpper(m_autil.mk_ge(m_autil.mk_add(i, m_autil.mk_mul(minus_one, mk_strlen(H))), zero), m);
1470+
expr_ref premiseRange(m.mk_or(premiseRangeLower, premiseRangeUpper), m);
1471+
expr_ref premise(m.mk_and(premiseNEmpty, premiseRange), m);
1472+
expr_ref conclusion(ctx.mk_eq_atom(e, minus_one), m);
1473+
expr_ref finalAxiom(rewrite_implication(premise, conclusion), m);
1474+
rw(finalAxiom);
1475+
assert_axiom(finalAxiom);
1476+
}
1477+
1478+
// case 1.2: N == "" and i within range
1479+
{
1480+
expr_ref premiseNEmpty(ctx.mk_eq_atom(N, empty_string), m);
1481+
// range check
1482+
expr_ref premiseRangeLower(m_autil.mk_le(i, minus_one), m);
1483+
expr_ref premiseRangeUpper(m_autil.mk_ge(m_autil.mk_add(i, m_autil.mk_mul(minus_one, mk_strlen(H))), zero), m);
1484+
expr_ref premiseRange(m.mk_not(m.mk_or(premiseRangeLower, premiseRangeUpper)), m);
1485+
expr_ref premise(m.mk_and(premiseNEmpty, premiseRange), m);
1486+
expr_ref conclusion(ctx.mk_eq_atom(e, i), m);
1487+
expr_ref finalAxiom(rewrite_implication(premise, conclusion), m);
1488+
rw(finalAxiom);
1489+
assert_axiom(finalAxiom);
1490+
}
1491+
14491492
// case 2: i = 0
14501493
{
1451-
expr_ref premise(ctx.mk_eq_atom(i, zero), m);
1494+
expr_ref premise1(ctx.mk_eq_atom(i, zero), m);
1495+
expr_ref premise2(m.mk_not(ctx.mk_eq_atom(N, empty_string)), m);
1496+
expr_ref premise(m.mk_and(premise1, premise2), m);
1497+
rw(premise);
14521498
// reduction to simpler case
14531499
expr_ref conclusion(ctx.mk_eq_atom(e, mk_indexof(H, N)), m);
14541500
assert_implication(premise, conclusion);
@@ -1459,7 +1505,10 @@ namespace smt {
14591505
//expr_ref premise(_premise);
14601506
//th_rewriter rw(m);
14611507
//rw(premise);
1462-
expr_ref premise(m_autil.mk_ge(m_autil.mk_add(i, m_autil.mk_mul(minus_one, mk_strlen(H))), zero), m);
1508+
expr_ref premise1(m_autil.mk_ge(m_autil.mk_add(i, m_autil.mk_mul(minus_one, mk_strlen(H))), zero), m);
1509+
expr_ref premise2(m.mk_not(ctx.mk_eq_atom(N, empty_string)), m);
1510+
expr_ref premise(m.mk_and(premise1, premise2), m);
1511+
rw(premise);
14631512
expr_ref conclusion(ctx.mk_eq_atom(e, minus_one), m);
14641513
assert_implication(premise, conclusion);
14651514
}
@@ -1469,15 +1518,21 @@ namespace smt {
14691518
expr_ref conclusion(ctx.mk_eq_atom(e, minus_one), m);
14701519
assert_implication(premise, conclusion);
14711520
}
1472-
// case 4: 0 < i < len(H) and H contains N
1521+
// case 4: 0 < i < len(H), N non-empty, and H contains N
14731522
{
14741523
expr_ref premise1(m_autil.mk_gt(i, zero), m);
14751524
//expr_ref premise2(m_autil.mk_lt(i, mk_strlen(H)), m);
14761525
expr_ref premise2(m.mk_not(m_autil.mk_ge(m_autil.mk_add(i, m_autil.mk_mul(minus_one, mk_strlen(H))), zero)), m);
14771526
expr_ref premise3(u.str.mk_contains(H, N), m);
1478-
expr_ref _premise(m.mk_and(premise1, premise2, premise3), m);
1527+
expr_ref premise4(m.mk_not(ctx.mk_eq_atom(N, mk_string(""))), m);
1528+
1529+
expr_ref_vector premises(m);
1530+
premises.push_back(premise1);
1531+
premises.push_back(premise2);
1532+
premises.push_back(premise3);
1533+
premises.push_back(premise4);
1534+
expr_ref _premise(mk_and(premises), m);
14791535
expr_ref premise(_premise);
1480-
th_rewriter rw(m);
14811536
rw(premise);
14821537

14831538
expr_ref hd(mk_str_var("hd"), m);
@@ -1500,9 +1555,8 @@ namespace smt {
15001555
expr_ref precondition1(m_autil.mk_gt(i, minus_one), m);
15011556
//expr_ref precondition2(m_autil.mk_lt(i, mk_strlen(H)), m);
15021557
expr_ref precondition2(m.mk_not(m_autil.mk_ge(m_autil.mk_add(i, m_autil.mk_mul(minus_one, mk_strlen(H))), zero)), m);
1503-
expr_ref _precondition(m.mk_and(precondition1, precondition2), m);
1504-
expr_ref precondition(_precondition);
1505-
th_rewriter rw(m);
1558+
expr_ref precondition3(m.mk_not(ctx.mk_eq_atom(N, mk_string(""))), m);
1559+
expr_ref precondition(m.mk_and(precondition1, precondition2, precondition3), m);
15061560
rw(precondition);
15071561

15081562
expr_ref premise(u.str.mk_contains(H, N), m);

0 commit comments

Comments
 (0)