Skip to content

Commit 558ef2f

Browse files
authored
Merge pull request #8718 from tautschnig/less-than-flattening
Improve bv_utilst less-than-or-less-or-equals
2 parents 4ed00e1 + e73c451 commit 558ef2f

File tree

1 file changed

+113
-62
lines changed

1 file changed

+113
-62
lines changed

src/solvers/flattening/bv_utils.cpp

Lines changed: 113 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1411,11 +1411,6 @@ literalt bv_utilst::lt_or_le(
14111411
#ifdef COMPACT_LT_OR_LE
14121412
if(prop.has_set_to() && prop.cnf_handled_well())
14131413
{
1414-
bvt compareBelow; // 1 if a compare is needed below this bit
1415-
literalt result;
1416-
size_t start;
1417-
size_t i;
1418-
14191414
if(rep == representationt::SIGNED)
14201415
{
14211416
literalt top0 = sign_bit(bv0), top1 = sign_bit(bv1);
@@ -1427,8 +1422,9 @@ literalt bv_utilst::lt_or_le(
14271422

14281423
INVARIANT(
14291424
bv0.size() >= 2, "signed bitvectors should have at least two bits");
1430-
compareBelow = prop.new_variables(bv0.size() - 1);
1431-
start = compareBelow.size() - 1;
1425+
// 1 if a compare is needed below this bit
1426+
bvt compareBelow = prop.new_variables(bv0.size() - 1);
1427+
size_t start = compareBelow.size() - 1;
14321428

14331429
literalt &firstComp = compareBelow[start];
14341430
if(top0.is_false())
@@ -1440,7 +1436,7 @@ literalt bv_utilst::lt_or_le(
14401436
else if(top1.is_true())
14411437
firstComp = top0;
14421438

1443-
result = prop.new_variable();
1439+
literalt result = prop.new_variable();
14441440

14451441
// When comparing signs we are comparing the top bit
14461442
// Four cases...
@@ -1452,70 +1448,130 @@ literalt bv_utilst::lt_or_le(
14521448
#ifdef INCLUDE_REDUNDANT_CLAUSES
14531449
prop.lcnf(top0, !top1, !firstComp);
14541450
prop.lcnf(!top0, top1, !firstComp);
1455-
#endif
1456-
}
1457-
else
1458-
{
1459-
// Unsigned is much easier
1460-
compareBelow = prop.new_variables(bv0.size() - 1);
1461-
compareBelow.push_back(const_literal(true));
1462-
start = compareBelow.size() - 1;
1463-
result = prop.new_variable();
1464-
}
1451+
# endif
14651452

1466-
// Determine the output
1467-
// \forall i . cb[i] & -a[i] & b[i] => result
1468-
// \forall i . cb[i] & a[i] & -b[i] => -result
1469-
i = start;
1470-
do
1471-
{
1472-
if(compareBelow[i].is_false())
1473-
continue;
1474-
else if(compareBelow[i].is_true())
1453+
// Determine the output
1454+
// \forall i . cb[i] & -a[i] & b[i] => result
1455+
// \forall i . cb[i] & a[i] & -b[i] => -result
1456+
size_t i = start;
1457+
do
14751458
{
1476-
if(bv0[i].is_false() && bv1[i].is_true())
1477-
return const_literal(true);
1478-
else if(bv0[i].is_true() && bv1[i].is_false())
1479-
return const_literal(false);
1459+
if(compareBelow[i].is_false())
1460+
continue;
1461+
1462+
prop.lcnf(!compareBelow[i], bv0[i], !bv1[i], result);
1463+
prop.lcnf(!compareBelow[i], !bv0[i], bv1[i], !result);
1464+
} while(i-- != 0);
1465+
1466+
// Chain the comparison bit
1467+
// \forall i != 0 . cb[i] & a[i] & b[i] => cb[i-1]
1468+
// \forall i != 0 . cb[i] & -a[i] & -b[i] => cb[i-1]
1469+
for(i = start; i > 0; i--)
1470+
{
1471+
prop.lcnf(!compareBelow[i], !bv0[i], !bv1[i], compareBelow[i - 1]);
1472+
prop.lcnf(!compareBelow[i], bv0[i], bv1[i], compareBelow[i - 1]);
14801473
}
14811474

1482-
prop.lcnf(!compareBelow[i], bv0[i], !bv1[i], result);
1483-
prop.lcnf(!compareBelow[i], !bv0[i], bv1[i], !result);
1484-
}
1485-
while(i-- != 0);
1475+
# ifdef INCLUDE_REDUNDANT_CLAUSES
1476+
// Optional zeroing of the comparison bit when not needed
1477+
// \forall i != 0 . -c[i] => -c[i-1]
1478+
// \forall i != 0 . c[i] & -a[i] & b[i] => -c[i-1]
1479+
// \forall i != 0 . c[i] & a[i] & -b[i] => -c[i-1]
1480+
for(i = start; i > 0; i--)
1481+
{
1482+
prop.lcnf(compareBelow[i], !compareBelow[i - 1]);
1483+
prop.lcnf(!compareBelow[i], bv0[i], !bv1[i], !compareBelow[i - 1]);
1484+
prop.lcnf(!compareBelow[i], !bv0[i], bv1[i], !compareBelow[i - 1]);
1485+
}
1486+
# endif
14861487

1487-
// Chain the comparison bit
1488-
// \forall i != 0 . cb[i] & a[i] & b[i] => cb[i-1]
1489-
// \forall i != 0 . cb[i] & -a[i] & -b[i] => cb[i-1]
1490-
for(i = start; i > 0; i--)
1491-
{
1492-
prop.lcnf(!compareBelow[i], !bv0[i], !bv1[i], compareBelow[i-1]);
1493-
prop.lcnf(!compareBelow[i], bv0[i], bv1[i], compareBelow[i-1]);
1494-
}
1488+
// The 'base case' of the induction is the case when they are equal
1489+
prop.lcnf(
1490+
!compareBelow[0], !bv0[0], !bv1[0], (or_equal) ? result : !result);
1491+
prop.lcnf(
1492+
!compareBelow[0], bv0[0], bv1[0], (or_equal) ? result : !result);
14951493

1494+
return result;
1495+
}
1496+
else
1497+
{
1498+
// Unsigned is much easier
1499+
// 1 if a compare is needed below this bit
1500+
bvt compareBelow;
1501+
literalt result;
1502+
size_t start = bv0.size() - 1;
1503+
1504+
// Determine the output
1505+
// \forall i . cb[i] & -a[i] & b[i] => result
1506+
// \forall i . cb[i] & a[i] & -b[i] => -result
1507+
bool same_prefix = true;
1508+
size_t i = start;
1509+
do
1510+
{
1511+
if(same_prefix)
1512+
{
1513+
if(i == 0)
1514+
{
1515+
if(or_equal)
1516+
return prop.lor(!bv0[0], bv1[0]);
1517+
else
1518+
return prop.land(!bv0[0], bv1[0]);
1519+
}
1520+
else if(bv0[i] == bv1[i])
1521+
continue;
1522+
else if(bv0[i].is_false() && bv1[i].is_true())
1523+
return const_literal(true);
1524+
else if(bv0[i].is_true() && bv1[i].is_false())
1525+
return const_literal(false);
1526+
else
1527+
{
1528+
same_prefix = false;
1529+
start = i;
1530+
compareBelow = prop.new_variables(i);
1531+
compareBelow.push_back(const_literal(true));
1532+
result = prop.new_variable();
1533+
}
1534+
}
1535+
1536+
prop.lcnf(!compareBelow[i], bv0[i], !bv1[i], result);
1537+
prop.lcnf(!compareBelow[i], !bv0[i], bv1[i], !result);
1538+
} while(i-- != 0);
1539+
1540+
// Chain the comparison bit
1541+
// \forall i != 0 . cb[i] & a[i] & b[i] => cb[i-1]
1542+
// \forall i != 0 . cb[i] & -a[i] & -b[i] => cb[i-1]
1543+
for(i = start; i > 0; i--)
1544+
{
1545+
prop.lcnf(!compareBelow[i], !bv0[i], !bv1[i], compareBelow[i - 1]);
1546+
prop.lcnf(!compareBelow[i], bv0[i], bv1[i], compareBelow[i - 1]);
1547+
}
14961548

14971549
#ifdef INCLUDE_REDUNDANT_CLAUSES
1498-
// Optional zeroing of the comparison bit when not needed
1499-
// \forall i != 0 . -c[i] => -c[i-1]
1500-
// \forall i != 0 . c[i] & -a[i] & b[i] => -c[i-1]
1501-
// \forall i != 0 . c[i] & a[i] & -b[i] => -c[i-1]
1502-
for(i = start; i > 0; i--)
1503-
{
1504-
prop.lcnf(compareBelow[i], !compareBelow[i-1]);
1505-
prop.lcnf(!compareBelow[i], bv0[i], !bv1[i], !compareBelow[i-1]);
1506-
prop.lcnf(!compareBelow[i], !bv0[i], bv1[i], !compareBelow[i-1]);
1507-
}
1550+
// Optional zeroing of the comparison bit when not needed
1551+
// \forall i != 0 . -c[i] => -c[i-1]
1552+
// \forall i != 0 . c[i] & -a[i] & b[i] => -c[i-1]
1553+
// \forall i != 0 . c[i] & a[i] & -b[i] => -c[i-1]
1554+
for(i = start; i > 0; i--)
1555+
{
1556+
prop.lcnf(compareBelow[i], !compareBelow[i - 1]);
1557+
prop.lcnf(!compareBelow[i], bv0[i], !bv1[i], !compareBelow[i - 1]);
1558+
prop.lcnf(!compareBelow[i], !bv0[i], bv1[i], !compareBelow[i - 1]);
1559+
}
15081560
#endif
15091561

1510-
// The 'base case' of the induction is the case when they are equal
1511-
prop.lcnf(!compareBelow[0], !bv0[0], !bv1[0], (or_equal)?result:!result);
1512-
prop.lcnf(!compareBelow[0], bv0[0], bv1[0], (or_equal)?result:!result);
1562+
// The 'base case' of the induction is the case when they are equal
1563+
prop.lcnf(
1564+
!compareBelow[0], !bv0[0], !bv1[0], (or_equal) ? result : !result);
1565+
prop.lcnf(
1566+
!compareBelow[0], bv0[0], bv1[0], (or_equal) ? result : !result);
15131567

1514-
return result;
1568+
return result;
1569+
}
15151570
}
15161571
else
15171572
#endif
15181573
{
1574+
// A <= B iff there is an overflow on A-B
15191575
literalt carry=
15201576
carry_out(bv0, inverted(bv1), const_literal(true));
15211577

@@ -1542,12 +1598,7 @@ literalt bv_utilst::unsigned_less_than(
15421598
const bvt &op0,
15431599
const bvt &op1)
15441600
{
1545-
#ifdef COMPACT_LT_OR_LE
15461601
return lt_or_le(false, op0, op1, representationt::UNSIGNED);
1547-
#else
1548-
// A <= B iff there is an overflow on A-B
1549-
return !carry_out(op0, inverted(op1), const_literal(true));
1550-
#endif
15511602
}
15521603

15531604
literalt bv_utilst::signed_less_than(

0 commit comments

Comments
 (0)