CBMC
Loading...
Searching...
No Matches
inductiveness.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Inductiveness
4
5Author: Daniel Kroening, dkr@amazon.com
6
7\*******************************************************************/
8
11
12#include "inductiveness.h"
13
14#include <util/console.h>
15#include <util/cout_message.h>
16#include <util/format_expr.h>
17
19
20#include "axioms.h"
21#include "bv_pointers_wide.h"
23#include "propagate.h"
24#include "solver.h"
25
26#include <algorithm>
27#include <iomanip>
28#include <iostream>
29
31 const std::unordered_set<exprt, irep_hash> &a1,
32 const std::unordered_set<exprt, irep_hash> &a2,
33 const std::unordered_set<exprt, irep_hash> &a3,
34 const exprt &b,
35 const std::unordered_set<symbol_exprt, irep_hash> &address_taken,
36 bool verbose,
37 const namespacet &ns)
38{
39 if(b.is_true())
40 return true; // anything subsumes 'true'
41
42 if(a1.find(false_exprt()) != a1.end())
43 return true; // 'false' subsumes anything
44
45 if(a1.find(b) != a1.end())
46 return true; // b is subsumed by a conjunct in a
47
48 cout_message_handlert message_handler;
49#if 0
50 message_handler.set_verbosity(verbose ? 10 : 1);
51#else
52 message_handler.set_verbosity(1);
53#endif
54 satcheckt satcheck(message_handler);
55 bv_pointers_widet solver(ns, satcheck, message_handler);
56 axiomst axioms(solver, address_taken, verbose, ns);
57
58 // check if a => b is valid,
59 // or (!a || b) is valid,
60 // or (a && !b) is unsat
61 for(auto &a_conjunct : a1)
62 axioms << a_conjunct;
63
64 for(auto &a_conjunct : a2)
65 axioms << a_conjunct;
66
67 for(auto &a_conjunct : a3)
68 axioms << a_conjunct;
69
70 axioms.set_to_false(b);
71
72 // instantiate our axioms
73 axioms.emit();
74
75 // now run solver
76 switch(solver())
77 {
79 if(verbose)
81 return false;
83 return true;
85 throw "error reported by solver";
86 }
87
88 UNREACHABLE; // to silence a warning
89}
90
91std::size_t count_frame(const workt::patht &path, frame_reft f)
92{
93 return std::count_if(path.begin(), path.end(), [f](const frame_reft &frame) {
94 return f == frame;
95 });
96}
97
99 std::vector<framet> &frames,
100 const std::unordered_set<symbol_exprt, irep_hash> &address_taken,
102 const namespacet &ns,
103 std::vector<propertyt> &properties,
104 std::size_t property_index)
105{
106 const auto frame_map = build_frame_map(frames);
107 auto &property = properties[property_index];
108
109 // add properties proven so far as auxiliaries
110 for(std::size_t i = 0; i < property_index; i++)
111 {
112 const auto &p = properties[i];
113 if(p.status == propertyt::PASS)
114 frames[p.frame.index].add_auxiliary(p.condition);
115 }
116
117 std::vector<workt> queue;
118 std::vector<workt> dropped;
119
120 auto propagator =
121 [&frames,
122 &frame_map,
123 &queue,
124 &dropped,
127 &ns](
128 const symbol_exprt &symbol, exprt invariant, const workt::patht &path) {
129 auto frame_ref = find_frame(frame_map, symbol);
130 auto &f = frames[frame_ref.index];
131
132#if 0
133 if(solver_options.verbose)
134 {
135 std::cout << "F: " << format(symbol) << " <- " << format(invariant)
136 << '\n';
137 }
138#endif
139
140 if(solver_options.verbose)
141 {
142 // print the current invariants and obligations in the frame
143 for(const auto &invariant : f.invariants)
144 {
145 std::cout << consolet::faint << consolet::blue;
146 std::cout << 'I' << std::setw(2) << frame_ref.index << ' ';
147 std::cout << format(invariant);
148 std::cout << consolet::reset << '\n';
149 }
150 for(const auto &obligation : f.obligations)
151 {
152 std::cout << consolet::faint << consolet::blue;
153 std::cout << 'O' << std::setw(2) << frame_ref.index << ' ';
154 std::cout << format(obligation);
155 std::cout << consolet::reset << '\n';
156 }
157 }
158
159 if(solver_options.verbose)
160 std::cout << "\u2192" << consolet::faint << std::setw(2)
161 << frame_ref.index << consolet::reset << ' ';
162
163 // trivially true?
164 if(invariant.is_true())
165 {
166 if(solver_options.verbose)
167 std::cout << "trivial\n";
168 }
169 else if(is_subsumed(
170 f.invariants_set,
171 f.obligations_set,
172 f.auxiliaries_set,
173 invariant,
175 solver_options.verbose,
176 ns))
177 {
178 if(solver_options.verbose)
179 std::cout << "subsumed " << format(invariant) << '\n';
180 }
181 else if(count_frame(path, frame_ref) > solver_options.loop_limit)
182 {
183 // loop limit exceeded, drop it
184 if(solver_options.verbose)
185 std::cout << consolet::red << "dropped" << consolet::reset << ' '
186 << format(invariant) << '\n';
187 dropped.emplace_back(frame_ref, invariant, path);
188 }
189 else
190 {
191 // propagate
192 if(solver_options.verbose)
193 std::cout << format(invariant) << '\n';
194
195 // store in frame
196 frames[frame_ref.index].add_obligation(invariant);
197
198 // add to queue
199 auto new_path = path;
200 new_path.push_back(frame_ref);
201 queue.emplace_back(f.ref, std::move(invariant), std::move(new_path));
202 }
203 };
204
205 // stick invariants into the queue
206 for(std::size_t frame_index = 0; frame_index < frames.size(); frame_index++)
207 {
209 for(auto &cond : frames[frame_index].invariants)
210 queue.emplace_back(frame_ref, cond, workt::patht{frame_ref});
211 }
212
213 // clean up the obligations
214 for(auto &frame : frames)
215 {
216 frame.obligations.clear();
217 frame.obligations_set.clear();
218 }
219
220 while(!queue.empty())
221 {
222 auto work = queue.back();
223 queue.pop_back();
224
225#if 0
226 if(solver_options.verbose)
227 {
228 dump(frames, property, true, true);
229 std::cout << '\n';
230 }
231#endif
232
234 frames, work, address_taken, solver_options.verbose, ns);
235
237 {
238 property.trace = counterexample_found.value();
239 return inductiveness_resultt::base_case_fail(std::move(work));
240 }
241
242 propagate(
243 frames, work, address_taken, solver_options.verbose, ns, propagator);
244
245 // did we drop anything?
246 if(!dropped.empty())
247 return inductiveness_resultt::step_case_fail(std::move(dropped.front()));
248 }
249
250 // done, saturated
252}
std::unordered_set< symbol_exprt, irep_hash > address_taken(const std::vector< exprt > &src)
Axioms.
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
void emit()
Definition axioms.cpp:749
void set_to_false(exprt)
Definition axioms.cpp:34
static std::ostream & blue(std::ostream &)
Definition console.cpp:104
static std::ostream & reset(std::ostream &)
Definition console.cpp:176
static std::ostream & faint(std::ostream &)
Definition console.cpp:160
static std::ostream & red(std::ostream &)
Definition console.cpp:128
Base class for all expressions.
Definition expr.h:56
The Boolean constant false.
Definition std_expr.h:3200
static inductiveness_resultt inductive()
static inductiveness_resultt step_case_fail(workt dropped)
static inductiveness_resultt base_case_fail(workt refuted)
void set_verbosity(unsigned _verbosity)
Definition message.h:52
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition namespace.h:91
Expression to hold a symbol (variable)
Definition std_expr.h:131
Console.
std::optional< propertyt::tracet > counterexample_found(const std::vector< framet > &frames, const workt &work, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, bool verbose, const namespacet &ns)
void show_assignment(const bv_pointers_widet &solver)
Counterexample Found.
static format_containert< T > format(const T &o)
Definition format.h:37
inductiveness_resultt inductiveness_check(std::vector< framet > &frames, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const solver_optionst &solver_options, const namespacet &ns, std::vector< propertyt > &properties, std::size_t property_index)
std::size_t count_frame(const workt::patht &path, frame_reft f)
bool is_subsumed(const std::unordered_set< exprt, irep_hash > &a1, const std::unordered_set< exprt, irep_hash > &a2, const std::unordered_set< exprt, irep_hash > &a3, const exprt &b, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, bool verbose, const namespacet &ns)
Inductiveness.
void propagate(const std::vector< framet > &frames, const workt &work, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, bool verbose, const namespacet &ns, const std::function< void(const symbol_exprt &, exprt, const workt::patht &)> &propagator)
Definition propagate.cpp:24
Propagate.
void solver(std::vector< framet > &frames, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const solver_optionst &solver_options, const namespacet &ns, std::vector< propertyt > &properties, std::size_t property_index)
Definition solver.cpp:44
Equality Propagation.
frame_reft find_frame(const frame_mapt &frame_map, const symbol_exprt &frame_symbol)
frame_mapt build_frame_map(const std::vector< framet > &frames)
void dump(const std::vector< framet > &frames, const propertyt &property, bool values, bool implications)
#define UNREACHABLE
This should be used to mark dead code.
Definition invariant.h:525
std::vector< frame_reft > patht