Skip to content

Commit 636c366

Browse files
committed
Shortest path search heuristic
Shortest path search heuristic computes the shortest path from all program locations to a single property. This metric is used to guide the symex search. We also introduce randomized shortest path based search, which makes a random choice when picking the next state every 1000 choices in order to avoid local minima
1 parent f9a6ff9 commit 636c366

File tree

4 files changed

+90
-7
lines changed

4 files changed

+90
-7
lines changed

src/symex/path_search.cpp

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,51 @@ Author: Daniel Kroening, [email protected]
2020
#include <path-symex/path_symex.h>
2121
#include <path-symex/build_goto_trace.h>
2222

23+
#include "shortest_path_graph.h"
24+
2325
#include <random>
2426

27+
28+
void path_searcht::sort_queue()
29+
{
30+
debug()<< " get shortest path, queue.size = " <<queue.size() <<eom;
31+
if(queue.size()==1)
32+
{
33+
current_distance = queue.front().get_shortest_path();
34+
return;
35+
}
36+
37+
unsigned shortest_path = std::numeric_limits<unsigned>::max();
38+
39+
std::list<statet>::iterator it;
40+
std::list<statet>::iterator closest_state;
41+
42+
for(it=queue.begin(); it!=queue.end(); ++it)
43+
{
44+
if(it->get_shortest_path() < shortest_path)
45+
{
46+
shortest_path = it->get_shortest_path();
47+
closest_state = it;
48+
}
49+
}
50+
51+
if(shortest_path != std::numeric_limits<unsigned>::max())
52+
{
53+
current_distance = shortest_path;
54+
statet tmp = *closest_state;
55+
queue.erase(closest_state);
56+
queue.push_front(tmp);
57+
}
58+
else
59+
{
60+
error() << "all states have shortest path length = MAX_UNSIGNED_INT, "
61+
<< "try removing function pointers with goto-instrument next time."
62+
<< "randomly picking state instead"
63+
<< eom;
64+
shuffle_queue(queue);
65+
}
66+
}
67+
2568
void path_searcht::shuffle_queue(queuet &queue)
2669
{
2770
if(queue.size()<=1)
@@ -54,9 +97,8 @@ path_searcht::resultt path_searcht::operator()(
5497
// this is the container for the history-forest
5598
path_symex_historyt history;
5699

57-
queue.push_back(initial_state(var_map, locs, history));
58-
59100
// set up the statistics
101+
current_distance = std::numeric_limits<unsigned>::max();
60102
number_of_dropped_states=0;
61103
number_of_paths=0;
62104
number_of_VCCs=0;
@@ -72,6 +114,15 @@ path_searcht::resultt path_searcht::operator()(
72114
absolute_timet last_reported_time=start_time;
73115

74116
initialize_property_map(goto_functions);
117+
if(search_heuristic == search_heuristict::SHORTEST_PATH ||
118+
search_heuristic == search_heuristict::RAN_SHORTEST_PATH )
119+
{
120+
status()<<"Building shortest path graph" << eom;
121+
shortest_path_grapht shortest_path_graph(goto_functions, locs);
122+
}
123+
statet init_state = initial_state(var_map, locs, history);
124+
queue.push_back(init_state);
125+
initial_distance_to_property=init_state.get_shortest_path();
75126

76127
while(!queue.empty())
77128
{
@@ -135,8 +186,13 @@ path_searcht::resultt path_searcht::operator()(
135186
<< " thread " << state.get_current_thread()+1
136187
<< '/' << state.threads.size()
137188
<< " PC " << state.pc()
138-
<< " depth " << state.get_depth()
139-
<< " [" << number_of_steps << " steps, "
189+
<< " depth " << state.get_depth();
190+
191+
if(search_heuristic == search_heuristict::SHORTEST_PATH
192+
|| search_heuristic == search_heuristict::RAN_SHORTEST_PATH)
193+
status() << " distance to property " << state.get_shortest_path();
194+
195+
status() << " [" << number_of_steps << " steps, "
140196
<< running_time << "s]" << messaget::eom;
141197
}
142198
}
@@ -243,6 +299,15 @@ void path_searcht::pick_state()
243299
queue.splice(queue.begin(), queue, --queue.end(), queue.end());
244300
return;
245301

302+
case search_heuristict::RAN_SHORTEST_PATH:
303+
if(number_of_steps%1000==0)
304+
shuffle_queue(queue);
305+
else
306+
sort_queue();
307+
return;
308+
case search_heuristict::SHORTEST_PATH:
309+
sort_queue();
310+
return;
246311
case search_heuristict::LOCS:
247312
return;
248313
}

src/symex/path_search.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ class path_searcht:public safety_checkert
8080
bool stop_on_fail;
8181

8282
// statistics
83+
unsigned current_distance;
84+
unsigned initial_distance_to_property;
8385
std::size_t number_of_dropped_states;
8486
std::size_t number_of_paths;
8587
std::size_t number_of_steps;
@@ -110,6 +112,10 @@ class path_searcht:public safety_checkert
110112
void set_randomized_dfs() { search_heuristic=search_heuristict::RAN_DFS; }
111113
void set_bfs() { search_heuristic=search_heuristict::BFS; }
112114
void set_locs() { search_heuristic=search_heuristict::LOCS; }
115+
void set_shortest_path()
116+
{ search_heuristic=search_heuristict::SHORTEST_PATH; }
117+
void set_ran_shortest_path()
118+
{ search_heuristic=search_heuristict::RAN_SHORTEST_PATH; }
113119

114120
typedef std::map<irep_idt, property_entryt> property_mapt;
115121
property_mapt property_map;
@@ -124,6 +130,9 @@ class path_searcht:public safety_checkert
124130
/// Pick random element of queue and move to front
125131
/// \param queue queue to be shuffled
126132
void shuffle_queue(queuet &queue);
133+
/// Move element with shortest distance to property
134+
/// to the front of the queue
135+
void sort_queue();
127136
// search heuristic
128137
void pick_state();
129138

@@ -155,7 +164,7 @@ class path_searcht:public safety_checkert
155164
unsigned time_limit;
156165

157166
enum class search_heuristict
158-
{ DFS, RAN_DFS, BFS, LOCS } search_heuristic;
167+
{ DFS, RAN_DFS, BFS, LOCS, SHORTEST_PATH, RAN_SHORTEST_PATH } search_heuristic;
159168

160169
source_locationt last_source_location;
161170
};

src/symex/symex_parse_options.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,13 @@ int symex_parse_optionst::doit()
236236
if(cmdline.isset("locs"))
237237
path_search.set_locs();
238238

239+
if(cmdline.isset("shortest-path"))
240+
{
241+
if(cmdline.isset("randomize"))
242+
path_search.set_ran_shortest_path();
243+
else
244+
path_search.set_shortest_path();
245+
}
239246
if(cmdline.isset("show-vcc"))
240247
{
241248
path_search.show_vcc=true;
@@ -645,7 +652,9 @@ void symex_parse_optionst::help()
645652
" --max-search-time s limit search to approximately s seconds\n"
646653
" --dfs use depth first search\n"
647654
" --bfs use breadth first search\n"
648-
" --randomize used in conjunction with dfs, to search by randomized dfs\n" // NOLINT(*)
655+
"--shortest-path use shortest path guided search\n"
656+
" --randomize in conjunction with dfs to use randomized dfs\n" // NOLINT(*)
657+
" in conjunction with shortest path to use randomized shortest path guided search\n" // NOLINT(*)
649658
" --eager-infeasibility query solver early to determine whether a path is infeasible before searching it\n" // NOLINT(*)
650659
"\n"
651660
"Other options:\n"

src/symex/symex_parse_options.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class optionst;
3838
"(little-endian)(big-endian)" \
3939
"(error-label):(verbosity):(no-library)" \
4040
"(version)" \
41-
"(bfs)(dfs)(locs)" \
41+
"(bfs)(dfs)(locs)(shortest-path)" \
4242
"(randomize)" \
4343
"(cover):" \
4444
"(i386-linux)(i386-macos)(i386-win32)(win32)(winx64)(gcc)" \

0 commit comments

Comments
 (0)