Skip to content

Commit 47bf680

Browse files
committed
extract per-node NNF computation for temporal logic from word-level BMC
The computation of per-node NNF done in the word-level BMC encoding is independent of the engine used, and should hence live in temporal-logic/
1 parent 2d3101a commit 47bf680

File tree

2 files changed

+11
-92
lines changed

2 files changed

+11
-92
lines changed

src/temporal-logic/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
SRC = negate_property.cpp \
2+
nnf.cpp \
23
normalize_property.cpp \
34
temporal_logic.cpp \
45
#empty line

src/trans-word-level/property.cpp

Lines changed: 10 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Author: Daniel Kroening, kroening@kroening.com
1717
#include <util/symbol_table.h>
1818

1919
#include <ebmc/ebmc_error.h>
20+
#include <temporal-logic/nnf.h>
2021
#include <temporal-logic/temporal_expr.h>
2122
#include <temporal-logic/temporal_logic.h>
2223
#include <verilog/sva_expr.h>
@@ -511,106 +512,23 @@ static obligationst property_obligations_rec(
511512
// We need NNF, try to eliminate the negation.
512513
auto &op = to_not_expr(property_expr).op();
513514

514-
if(op.id() == ID_U)
515-
{
516-
// ¬(φ U ψ) ≡ (¬φ R ¬ψ)
517-
auto &U = to_U_expr(op);
518-
auto R = R_exprt{not_exprt{U.lhs()}, not_exprt{U.rhs()}};
519-
return property_obligations_rec(R, current, no_timeframes);
520-
}
521-
else if(op.id() == ID_R)
522-
{
523-
// ¬(φ R ψ) ≡ (¬φ U ¬ψ)
524-
auto &R = to_R_expr(op);
525-
auto U = U_exprt{not_exprt{R.lhs()}, not_exprt{R.rhs()}};
526-
return property_obligations_rec(U, current, no_timeframes);
527-
}
528-
else if(op.id() == ID_G)
529-
{
530-
// ¬G φ ≡ F ¬φ
531-
auto &G = to_G_expr(op);
532-
auto F = F_exprt{not_exprt{G.op()}};
533-
return property_obligations_rec(F, current, no_timeframes);
534-
}
535-
else if(op.id() == ID_F)
536-
{
537-
// ¬F φ ≡ G ¬φ
538-
auto &F = to_F_expr(op);
539-
auto G = G_exprt{not_exprt{F.op()}};
540-
return property_obligations_rec(G, current, no_timeframes);
541-
}
542-
else if(op.id() == ID_X)
543-
{
544-
// ¬X φ ≡ X ¬φ
545-
auto &X = to_X_expr(op);
546-
auto negX = X_exprt{not_exprt{X.op()}};
547-
return property_obligations_rec(negX, current, no_timeframes);
548-
}
549-
else if(op.id() == ID_implies)
550-
{
551-
// ¬(a->b) --> a && ¬b
552-
auto &implies_expr = to_implies_expr(op);
553-
auto and_expr =
554-
and_exprt{implies_expr.lhs(), not_exprt{implies_expr.rhs()}};
555-
return property_obligations_rec(and_expr, current, no_timeframes);
556-
}
557-
else if(op.id() == ID_and)
558-
{
559-
auto operands = op.operands();
560-
for(auto &op : operands)
561-
op = not_exprt{op};
562-
auto or_expr = or_exprt{std::move(operands)};
563-
return property_obligations_rec(or_expr, current, no_timeframes);
564-
}
565-
else if(op.id() == ID_or)
566-
{
567-
auto operands = op.operands();
568-
for(auto &op : operands)
569-
op = not_exprt{op};
570-
auto and_expr = and_exprt{std::move(operands)};
571-
return property_obligations_rec(and_expr, current, no_timeframes);
572-
}
573-
else if(op.id() == ID_not)
515+
auto op_negated_opt = negate_property_node(op);
516+
517+
if(op_negated_opt.has_value())
574518
{
575519
return property_obligations_rec(
576-
to_not_expr(op).op(), current, no_timeframes);
577-
}
578-
else if(op.id() == ID_sva_until)
579-
{
580-
// ¬(φ W ψ) ≡ (¬φ strongR ¬ψ)
581-
auto &W = to_sva_until_expr(op);
582-
auto strong_R = strong_R_exprt{not_exprt{W.lhs()}, not_exprt{W.rhs()}};
583-
return property_obligations_rec(strong_R, current, no_timeframes);
520+
op_negated_opt.value(), current, no_timeframes);
584521
}
585-
else if(op.id() == ID_sva_s_until)
522+
else if(is_temporal_operator(op))
586523
{
587-
// ¬(φ U ψ) ≡ (¬φ R ¬ψ)
588-
auto &U = to_sva_s_until_expr(op);
589-
auto R = R_exprt{not_exprt{U.lhs()}, not_exprt{U.rhs()}};
590-
return property_obligations_rec(R, current, no_timeframes);
591-
}
592-
else if(op.id() == ID_sva_until_with)
593-
{
594-
// ¬(φ R ψ) ≡ (¬φ U ¬ψ)
595-
// Note LHS and RHS are swapped.
596-
auto &until_with = to_sva_until_with_expr(op);
597-
auto R = R_exprt{until_with.rhs(), until_with.lhs()};
598-
auto U = sva_until_exprt{not_exprt{R.lhs()}, not_exprt{R.rhs()}};
599-
return property_obligations_rec(U, current, no_timeframes);
600-
}
601-
else if(op.id() == ID_sva_s_until_with)
602-
{
603-
// ¬(φ strongR ψ) ≡ (¬φ W ¬ψ)
604-
// Note LHS and RHS are swapped.
605-
auto &s_until_with = to_sva_s_until_with_expr(op);
606-
auto strong_R = strong_R_exprt{s_until_with.rhs(), s_until_with.lhs()};
607-
auto W =
608-
weak_U_exprt{not_exprt{strong_R.lhs()}, not_exprt{strong_R.rhs()}};
609-
return property_obligations_rec(W, current, no_timeframes);
524+
throw ebmc_errort() << "failed to make NNF for " << op.id();
610525
}
611526
else
527+
{
528+
// state formula
612529
return obligationst{
613530
instantiate_property(property_expr, current, no_timeframes)};
531+
}
614532
}
615533
else
616534
{

0 commit comments

Comments
 (0)