Skip to content

Commit b614667

Browse files
committed
SMT2: support onehot and onehot0
This adds support for the onehot and onehot0 predicates to the SMT2 backend.
1 parent c902db3 commit b614667

File tree

4 files changed

+111
-2
lines changed

4 files changed

+111
-2
lines changed

src/solvers/flattening/boolbv.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -412,8 +412,10 @@ literalt boolbvt::convert_rest(const exprt &expr)
412412
expr.id()==ID_reduction_nor || expr.id()==ID_reduction_nand ||
413413
expr.id()==ID_reduction_xor || expr.id()==ID_reduction_xnor)
414414
return convert_reduction(to_unary_expr(expr));
415-
else if(expr.id()==ID_onehot || expr.id()==ID_onehot0)
416-
return convert_onehot(to_unary_expr(expr));
415+
else if(expr.id() == ID_onehot)
416+
return convert_onehot(to_onehot_expr(expr));
417+
else if(expr.id() == ID_onehot0)
418+
return convert_onehot(to_onehot0_expr(expr));
417419
else if(
418420
const auto binary_overflow =
419421
expr_try_dynamic_cast<binary_overflow_exprt>(expr))

src/solvers/smt2/smt2_conv.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -1831,6 +1831,10 @@ void smt2_convt::convert_expr(const exprt &expr)
18311831
out << ")) #b1)"; // bvlshr, extract, =
18321832
}
18331833
}
1834+
else if(expr.id() == ID_onehot)
1835+
{
1836+
convert_expr(to_onehot_expr(expr).lower());
1837+
}
18341838
else if(expr.id()==ID_extractbits)
18351839
{
18361840
const extractbits_exprt &extractbits_expr = to_extractbits_expr(expr);

src/util/bitvector_expr.cpp

+35
Original file line numberDiff line numberDiff line change
@@ -306,3 +306,38 @@ exprt zero_extend_exprt::lower() const
306306
return extractbits_exprt{op(), 0, type()};
307307
}
308308
}
309+
310+
static std::pair<exprt, exprt> onehot_lowering(const exprt &expr)
311+
{
312+
exprt one_seen = false_exprt{};
313+
const auto width = to_bitvector_type(expr.type()).get_width();
314+
exprt::operandst more_than_one_seen_disjuncts;
315+
316+
for(std::size_t i = 0; i < width; i++)
317+
{
318+
auto bit = extractbit_exprt{expr, i};
319+
more_than_one_seen_disjuncts.push_back(and_exprt{bit, one_seen});
320+
one_seen = or_exprt{one_seen, bit};
321+
}
322+
323+
auto more_than_one_seen = disjunction(more_than_one_seen_disjuncts);
324+
325+
return {one_seen, more_than_one_seen};
326+
}
327+
328+
exprt onehot_exprt::lower() const
329+
{
330+
auto symbol = symbol_exprt{"onehot-op", op().type()};
331+
auto onehot_lowering = ::onehot_lowering(symbol);
332+
333+
return let_exprt{
334+
symbol,
335+
op(),
336+
and_exprt{onehot_lowering.first, not_exprt{onehot_lowering.second}}};
337+
}
338+
339+
exprt onehot0_exprt::lower() const
340+
{
341+
auto symbol = symbol_exprt{"onehot-op", op().type()};
342+
return let_exprt{symbol, op(), not_exprt{::onehot_lowering(op()).second}};
343+
}

src/util/bitvector_expr.h

+68
Original file line numberDiff line numberDiff line change
@@ -1742,4 +1742,72 @@ inline zero_extend_exprt &to_zero_extend_expr(exprt &expr)
17421742
return static_cast<zero_extend_exprt &>(expr);
17431743
}
17441744

1745+
/// \brief A Boolean expression returning true iff the given
1746+
/// operand consists of exactly one '1' and '0' otherwise.
1747+
class onehot_exprt : public unary_predicate_exprt
1748+
{
1749+
public:
1750+
onehot_exprt(exprt _op) : unary_predicate_exprt(ID_onehot, std::move(_op))
1751+
{
1752+
}
1753+
1754+
/// lowering to extractbit
1755+
exprt lower() const;
1756+
};
1757+
1758+
/// \brief Cast an exprt to a \ref onehot_exprt
1759+
///
1760+
/// \a expr must be known to be \ref onehot_exprt.
1761+
///
1762+
/// \param expr: Source expression
1763+
/// \return Object of type \ref onehot_exprt
1764+
inline const onehot_exprt &to_onehot_expr(const exprt &expr)
1765+
{
1766+
PRECONDITION(expr.id() == ID_onehot);
1767+
onehot_exprt::check(expr);
1768+
return static_cast<const onehot_exprt &>(expr);
1769+
}
1770+
1771+
/// \copydoc to_onehot_expr(const exprt &)
1772+
inline onehot_exprt &to_onehot_expr(exprt &expr)
1773+
{
1774+
PRECONDITION(expr.id() == ID_onehot);
1775+
onehot_exprt::check(expr);
1776+
return static_cast<onehot_exprt &>(expr);
1777+
}
1778+
1779+
/// \brief A Boolean expression returning true iff the given
1780+
/// operand consists of exactly one '0' and '1' otherwise.
1781+
class onehot0_exprt : public unary_predicate_exprt
1782+
{
1783+
public:
1784+
onehot0_exprt(exprt _op) : unary_predicate_exprt(ID_onehot0, std::move(_op))
1785+
{
1786+
}
1787+
1788+
/// lowering to extractbit
1789+
exprt lower() const;
1790+
};
1791+
1792+
/// \brief Cast an exprt to a \ref onehot0_exprt
1793+
///
1794+
/// \a expr must be known to be \ref onehot0_exprt.
1795+
///
1796+
/// \param expr: Source expression
1797+
/// \return Object of type \ref onehot0_exprt
1798+
inline const onehot0_exprt &to_onehot0_expr(const exprt &expr)
1799+
{
1800+
PRECONDITION(expr.id() == ID_onehot0);
1801+
onehot0_exprt::check(expr);
1802+
return static_cast<const onehot0_exprt &>(expr);
1803+
}
1804+
1805+
/// \copydoc to_onehot0_expr(const exprt &)
1806+
inline onehot0_exprt &to_onehot0_expr(exprt &expr)
1807+
{
1808+
PRECONDITION(expr.id() == ID_onehot0);
1809+
onehot0_exprt::check(expr);
1810+
return static_cast<onehot0_exprt &>(expr);
1811+
}
1812+
17451813
#endif // CPROVER_UTIL_BITVECTOR_EXPR_H

0 commit comments

Comments
 (0)