@@ -16,16 +16,22 @@ Author: Daniel Kroening, dkr@amazon.com
1616
1717#include " bmc.h"
1818
19- bool has_low_completeness_threshold (const exprt &expr)
19+ // counting number of transitions
20+ std::optional<mp_integer> completeness_threshold (const exprt &expr)
2021{
2122 if (!has_temporal_operator (expr))
2223 {
23- return true ; // state predicate only
24+ return 0 ; // state predicate only
2425 }
2526 else if (expr.id () == ID_X)
2627 {
2728 // X p
28- return !has_temporal_operator (to_X_expr (expr).op ());
29+ // Increases the CT by one.
30+ auto ct_p = completeness_threshold (to_X_expr (expr).op ());
31+ if (ct_p.has_value ())
32+ return *ct_p + 1 ;
33+ else
34+ return {};
2935 }
3036 else if (
3137 expr.id () == ID_sva_nexttime || expr.id () == ID_sva_s_nexttime ||
@@ -38,66 +44,103 @@ bool has_low_completeness_threshold(const exprt &expr)
3844 {
3945 auto &always_expr = to_sva_ranged_always_expr (expr);
4046 if (has_temporal_operator (always_expr.op ()))
41- return false ;
42- else if (always_expr.to ().is_constant ())
47+ return {};
48+
49+ if (always_expr.is_range () && !always_expr.is_unbounded ())
4350 {
44- auto from_int = numeric_cast_v<mp_integer>(always_expr.from ());
4551 auto to_int =
4652 numeric_cast_v<mp_integer>(to_constant_expr (always_expr.to ()));
47- return from_int >= 0 && from_int <= 1 && to_int >= 0 && to_int <= 1 ;
53+
54+ // increases the CT by to_int
55+ auto ct_op = completeness_threshold (always_expr.op ());
56+ if (ct_op.has_value ())
57+ return *ct_op + to_int;
58+ else
59+ return {};
4860 }
4961 else
50- return false ;
62+ return {} ;
5163 }
5264 else if (expr.id () == ID_sva_s_always)
5365 {
5466 auto &s_always_expr = to_sva_s_always_expr (expr);
55- if (has_temporal_operator (s_always_expr.op ()))
56- return false ;
67+
68+ auto to_int = numeric_cast_v<mp_integer>(s_always_expr.to ());
69+
70+ if (to_int < 0 )
71+ return {};
72+
73+ // increases the CT by to_int
74+ auto ct_op = completeness_threshold (s_always_expr.op ());
75+ if (ct_op.has_value ())
76+ return *ct_op + to_int;
5777 else
58- {
59- auto from_int = numeric_cast_v<mp_integer>(s_always_expr.from ());
60- auto to_int = numeric_cast_v<mp_integer>(s_always_expr.to ());
61- return from_int >= 0 && from_int <= 1 && to_int >= 0 && to_int <= 1 ;
62- }
78+ return {};
6379 }
6480 else if (
6581 expr.id () == ID_sva_strong || expr.id () == ID_sva_weak ||
6682 expr.id () == ID_sva_implicit_strong || expr.id () == ID_sva_implicit_weak)
6783 {
6884 auto &sequence = to_sva_sequence_property_expr_base (expr).sequence ();
69- return has_low_completeness_threshold (sequence);
85+ return completeness_threshold (sequence);
7086 }
7187 else if (expr.id () == ID_sva_boolean)
7288 {
73- return true ;
89+ return 0 ; // state predicate only
7490 }
75- else if (expr.id () == ID_sva_or || expr. id () == ID_sva_and )
91+ else if (expr.id () == ID_sva_cycle_delay )
7692 {
77- for (auto &op : expr.operands ())
78- if (!has_low_completeness_threshold (op))
79- return false ;
80- return true ;
93+ auto &cycle_delay = to_sva_cycle_delay_expr (expr);
94+ mp_integer ct_lhs = 0 ;
95+
96+ if (cycle_delay.lhs ().is_not_nil ())
97+ {
98+ auto ct_lhs_opt = completeness_threshold (cycle_delay.lhs ());
99+ if (ct_lhs_opt.has_value ())
100+ ct_lhs = ct_lhs_opt.value ();
101+ else
102+ return {};
103+ }
104+
105+ if (cycle_delay.is_range ())
106+ return {};
107+ else // singleton
108+ {
109+ auto ct_rhs = completeness_threshold (cycle_delay.rhs ());
110+ if (ct_rhs.has_value ())
111+ return ct_lhs + numeric_cast_v<mp_integer>(cycle_delay.from ()) +
112+ *ct_rhs;
113+ else
114+ return {};
115+ }
81116 }
82117 else if (expr.id () == ID_sva_sequence_property)
83118 {
84119 PRECONDITION (false ); // should have been turned into implicit weak/strong
85120 }
86121 else
87- return false ;
122+ return {} ;
88123}
89124
90- bool has_low_completeness_threshold (const ebmc_propertiest::propertyt &property)
125+ std::optional<mp_integer>
126+ completeness_threshold (const ebmc_propertiest::propertyt &property)
91127{
92- return has_low_completeness_threshold (property.normalized_expr );
128+ return completeness_threshold (property.normalized_expr );
93129}
94130
95- bool have_low_completeness_threshold (const ebmc_propertiest &properties)
131+ std::optional<mp_integer>
132+ completeness_threshold (const ebmc_propertiest &properties)
96133{
134+ std::optional<mp_integer> max_ct;
135+
97136 for (auto &property : properties.properties )
98- if (has_low_completeness_threshold (property))
99- return true ;
100- return false ;
137+ {
138+ auto ct_opt = completeness_threshold (property);
139+ if (ct_opt.has_value ())
140+ max_ct = std::max (max_ct.value_or (0 ), *ct_opt);
141+ }
142+
143+ return max_ct;
101144}
102145
103146property_checker_resultt completeness_threshold (
@@ -107,14 +150,16 @@ property_checker_resultt completeness_threshold(
107150 const ebmc_solver_factoryt &solver_factory,
108151 message_handlert &message_handler)
109152{
110- // Do we have an eligibile property?
111- if (!have_low_completeness_threshold (properties))
153+ // Do we have an eligible property?
154+ auto ct_opt = completeness_threshold (properties);
155+
156+ if (!ct_opt.has_value ())
112157 return property_checker_resultt{properties}; // give up
113158
114- // Do BMC with two timeframes
159+ // Do BMC, using the CT as the bound
115160 auto result = bmc (
116- 1 , // bound
117- false , // convert_only
161+ numeric_cast_v<std:: size_t >(*ct_opt), // bound
162+ false , // convert_only
118163 cmdline.isset (" bmc-with-assumptions" ),
119164 transition_system,
120165 properties,
@@ -126,8 +171,9 @@ property_checker_resultt completeness_threshold(
126171 if (property.is_proved_with_bound ())
127172 {
128173 // Turn "PROVED up to bound k" into "PROVED" if k>=CT
129- if (has_low_completeness_threshold (property) && property.bound >= 1 )
130- property.proved (" CT=1" );
174+ auto property_ct_opt = completeness_threshold (property);
175+ if (property_ct_opt.has_value ())
176+ property.proved (" CT=" + integer2string (*property_ct_opt));
131177 else
132178 property.unknown ();
133179 }
0 commit comments