Skip to content

Commit f078234

Browse files
committed
SCC-based candidate detection
1 parent a3c102e commit f078234

File tree

1 file changed

+236
-38
lines changed

1 file changed

+236
-38
lines changed

plugins/hawkeye/src/candidate_search.cpp

Lines changed: 236 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ namespace hal
8080
igraph_integer_t i, j, k;
8181
igraph_bool_t* added;
8282
igraph_vector_int_t current_hood, previous_hood;
83-
igraph_vector_int_t* chp = &current_hood;
84-
igraph_vector_int_t* php = &previous_hood;
83+
igraph_vector_int_t* current_hood_p = &current_hood;
84+
igraph_vector_int_t* previous_hood_p = &previous_hood;
8585
igraph_vector_int_t tmp;
8686

8787
if (timeout < 0)
@@ -93,34 +93,34 @@ namespace hal
9393
IGRAPH_CHECK_OOM(added, "Cannot calculate neighborhood size.");
9494
IGRAPH_FINALLY(igraph_free, added);
9595

96-
IGRAPH_VECTOR_INT_INIT_FINALLY(chp, 0);
97-
IGRAPH_VECTOR_INT_INIT_FINALLY(php, 0);
96+
IGRAPH_VECTOR_INT_INIT_FINALLY(current_hood_p, 0);
97+
IGRAPH_VECTOR_INT_INIT_FINALLY(previous_hood_p, 0);
9898
IGRAPH_VECTOR_INT_INIT_FINALLY(&tmp, 0);
9999

100100
IGRAPH_CHECK(igraph_vector_int_init(in_set, 0));
101101
IGRAPH_CHECK(igraph_vector_int_init(out_set, 0));
102102
igraph_vector_int_clear(in_set);
103103
igraph_vector_int_clear(out_set);
104104

105-
IGRAPH_CHECK(igraph_vector_int_push_back(chp, node));
105+
IGRAPH_CHECK(igraph_vector_int_push_back(current_hood_p, node));
106106

107107
igraph_integer_t previous_size, current_size;
108108

109109
for (i = 0; i < timeout; i++)
110110
{
111-
previous_size = igraph_vector_int_size(php);
112-
current_size = igraph_vector_int_size(chp);
111+
previous_size = igraph_vector_int_size(previous_hood_p);
112+
current_size = igraph_vector_int_size(current_hood_p);
113113

114114
if (previous_size < current_size)
115115
{
116-
IGRAPH_CHECK(igraph_vector_int_swap(php, chp));
117-
igraph_vector_int_clear(chp);
116+
IGRAPH_CHECK(igraph_vector_int_swap(previous_hood_p, current_hood_p));
117+
igraph_vector_int_clear(current_hood_p);
118118

119119
memset(added, false, no_of_nodes * sizeof(igraph_bool_t));
120120

121121
for (j = 0; j < current_size; j++)
122122
{
123-
igraph_integer_t actnode = VECTOR(*php)[j];
123+
igraph_integer_t actnode = VECTOR(*previous_hood_p)[j];
124124
igraph_vector_int_clear(&tmp);
125125
IGRAPH_CHECK(igraph_neighbors(graph, &tmp, actnode, IGRAPH_OUT));
126126

@@ -130,7 +130,7 @@ namespace hal
130130
if (!added[nei])
131131
{
132132
added[nei] = true;
133-
IGRAPH_CHECK(igraph_vector_int_push_back(chp, nei));
133+
IGRAPH_CHECK(igraph_vector_int_push_back(current_hood_p, nei));
134134
}
135135
}
136136
}
@@ -139,22 +139,172 @@ namespace hal
139139
{
140140
if (previous_size == current_size)
141141
{
142-
IGRAPH_CHECK(igraph_vector_int_update(in_set, php));
143-
IGRAPH_CHECK(igraph_vector_int_update(out_set, chp));
142+
IGRAPH_CHECK(igraph_vector_int_update(in_set, previous_hood_p));
143+
IGRAPH_CHECK(igraph_vector_int_update(out_set, current_hood_p));
144144
}
145145

146146
break;
147147
}
148148
}
149149

150-
igraph_vector_int_destroy(chp);
151-
igraph_vector_int_destroy(php);
150+
igraph_vector_int_destroy(current_hood_p);
151+
igraph_vector_int_destroy(previous_hood_p);
152152
igraph_vector_int_destroy(&tmp);
153153
IGRAPH_FREE(added);
154154
IGRAPH_FINALLY_CLEAN(4);
155155

156156
return IGRAPH_SUCCESS;
157157
}
158+
159+
igraph_error_t get_saturating_neighborhoods_scc(const igraph_t* graph,
160+
igraph_vector_int_t* in_set,
161+
igraph_vector_int_t* out_set,
162+
igraph_integer_t node,
163+
igraph_integer_t timeout,
164+
std::map<std::set<u32>, igraph_vector_int_t*>& cache)
165+
{
166+
igraph_integer_t no_of_nodes = igraph_vcount(graph);
167+
igraph_integer_t i, j, k;
168+
igraph_bool_t* added;
169+
igraph_vector_int_t current_hood, previous_hood;
170+
igraph_vector_int_t current_component, previous_component;
171+
igraph_vector_int_t* current_hood_p = &current_hood;
172+
igraph_vector_int_t* previous_hood_p = &previous_hood;
173+
igraph_vector_int_t* current_component_p = &current_component;
174+
igraph_vector_int_t* previous_component_p = &previous_component;
175+
igraph_vector_int_t tmp;
176+
177+
if (timeout < 0)
178+
{
179+
IGRAPH_ERROR("Negative timeout", IGRAPH_EINVAL);
180+
}
181+
182+
added = IGRAPH_CALLOC(no_of_nodes, igraph_bool_t);
183+
IGRAPH_CHECK_OOM(added, "Cannot calculate neighborhood size.");
184+
IGRAPH_FINALLY(igraph_free, added);
185+
186+
IGRAPH_VECTOR_INT_INIT_FINALLY(current_hood_p, 0);
187+
IGRAPH_VECTOR_INT_INIT_FINALLY(previous_hood_p, 0);
188+
IGRAPH_VECTOR_INT_INIT_FINALLY(current_component_p, 0);
189+
IGRAPH_VECTOR_INT_INIT_FINALLY(previous_component_p, 0);
190+
IGRAPH_VECTOR_INT_INIT_FINALLY(&tmp, 0);
191+
192+
IGRAPH_CHECK(igraph_vector_int_init(in_set, 0));
193+
IGRAPH_CHECK(igraph_vector_int_init(out_set, 0));
194+
igraph_vector_int_clear(in_set);
195+
igraph_vector_int_clear(out_set);
196+
197+
IGRAPH_CHECK(igraph_vector_int_push_back(current_hood_p, node));
198+
IGRAPH_CHECK(igraph_vector_int_push_back(current_component_p, node));
199+
200+
igraph_integer_t previous_size, current_size;
201+
202+
for (i = 0; i < timeout; i++)
203+
{
204+
previous_size = igraph_vector_int_size(previous_component_p);
205+
current_size = igraph_vector_int_size(current_component_p);
206+
u32 current_hood_size = igraph_vector_int_size(current_hood_p);
207+
208+
if (previous_size < current_size || current_size == 1)
209+
{
210+
// move current objects to previous
211+
IGRAPH_CHECK(igraph_vector_int_swap(previous_hood_p, current_hood_p));
212+
IGRAPH_CHECK(igraph_vector_int_swap(previous_component_p, current_component_p));
213+
igraph_vector_int_clear(current_hood_p);
214+
igraph_vector_int_clear(current_component_p);
215+
216+
// clear flags of added vertices
217+
memset(added, false, no_of_nodes * sizeof(igraph_bool_t));
218+
219+
std::set<u32> cache_key;
220+
for (j = 0; j < current_hood_size; j++)
221+
{
222+
igraph_integer_t actnode = VECTOR(*previous_hood_p)[j];
223+
igraph_vector_int_clear(&tmp);
224+
IGRAPH_CHECK(igraph_neighbors(graph, &tmp, actnode, IGRAPH_OUT));
225+
226+
for (k = 0; k < igraph_vector_int_size(&tmp); k++)
227+
{
228+
igraph_integer_t nei = VECTOR(tmp)[k];
229+
if (!added[nei])
230+
{
231+
added[nei] = true;
232+
IGRAPH_CHECK(igraph_vector_int_push_back(current_hood_p, nei));
233+
cache_key.insert(nei);
234+
}
235+
}
236+
}
237+
238+
if (k == 0)
239+
{
240+
continue;
241+
}
242+
243+
if (const auto cache_it = cache.find(cache_key); cache_it != cache.end())
244+
{
245+
IGRAPH_CHECK(igraph_vector_int_update(current_component_p, cache_it->second));
246+
}
247+
else
248+
{
249+
igraph_t subgraph;
250+
igraph_vs_t subgraph_vertices = igraph_vss_vector(current_hood_p);
251+
IGRAPH_FINALLY(igraph_vs_destroy, &subgraph_vertices);
252+
igraph_vector_int_t vertex_map;
253+
IGRAPH_VECTOR_INT_INIT_FINALLY(&vertex_map, igraph_vector_int_size(current_hood_p));
254+
IGRAPH_CHECK(igraph_induced_subgraph_map(graph, &subgraph, subgraph_vertices, IGRAPH_SUBGRAPH_CREATE_FROM_SCRATCH, nullptr, &vertex_map));
255+
IGRAPH_FINALLY(igraph_destroy, &subgraph);
256+
257+
igraph_vector_int_t membership, csize;
258+
IGRAPH_VECTOR_INT_INIT_FINALLY(&membership, 0);
259+
IGRAPH_VECTOR_INT_INIT_FINALLY(&csize, 0);
260+
IGRAPH_CHECK(igraph_connected_components(&subgraph, &membership, &csize, nullptr, IGRAPH_STRONG));
261+
262+
u32 max_id = igraph_vector_int_which_max(&csize);
263+
u32 num_subgraph_vertices = igraph_vcount(&subgraph);
264+
for (i32 i = 0; i < num_subgraph_vertices; i++)
265+
{
266+
u32 cid = VECTOR(membership)[i];
267+
if (cid == max_id)
268+
{
269+
IGRAPH_CHECK(igraph_vector_int_push_back(current_component_p, VECTOR(vertex_map)[i]));
270+
}
271+
}
272+
273+
igraph_vs_destroy(&subgraph_vertices);
274+
igraph_vector_int_destroy(&vertex_map);
275+
igraph_vector_int_destroy(&membership);
276+
igraph_vector_int_destroy(&csize);
277+
igraph_destroy(&subgraph);
278+
IGRAPH_FINALLY_CLEAN(5);
279+
280+
igraph_vector_int_t* cache_tmp = new igraph_vector_int_t;
281+
IGRAPH_CHECK(igraph_vector_int_init(cache_tmp, 0)); // cleanup handled by caller
282+
IGRAPH_CHECK(igraph_vector_int_update(cache_tmp, current_component_p));
283+
cache[cache_key] = cache_tmp;
284+
}
285+
}
286+
else
287+
{
288+
if (previous_size == current_size)
289+
{
290+
IGRAPH_CHECK(igraph_vector_int_update(in_set, previous_component_p));
291+
IGRAPH_CHECK(igraph_vector_int_update(out_set, current_component_p));
292+
}
293+
294+
break;
295+
}
296+
}
297+
298+
igraph_vector_int_destroy(current_hood_p);
299+
igraph_vector_int_destroy(previous_hood_p);
300+
igraph_vector_int_destroy(current_component_p);
301+
igraph_vector_int_destroy(previous_component_p);
302+
igraph_vector_int_destroy(&tmp);
303+
IGRAPH_FREE(added);
304+
IGRAPH_FINALLY_CLEAN(6);
305+
306+
return IGRAPH_SUCCESS;
307+
}
158308
} // namespace
159309

160310
Result<std::vector<Candidate>> detect_candidates(Netlist* nl, const std::vector<DetectionConfiguration>& configs, u32 min_state_size, const std::vector<Gate*>& start_ffs)
@@ -199,7 +349,7 @@ namespace hal
199349
}
200350
auto base_graph = res.get();
201351

202-
const auto start_vertices_res = base_graph->get_vertices_from_gates(start_gates);
352+
const auto start_vertices_res = base_graph->get_vertices_from_gates(start_ffs.empty() ? start_gates : start_ffs);
203353
if (start_vertices_res.is_error())
204354
{
205355
return ERR(start_vertices_res.get_error());
@@ -358,35 +508,85 @@ namespace hal
358508
}
359509

360510
std::set<GraphCandidate> graph_candidates;
361-
for (const auto v : start_vertices)
362-
{
363-
igraph_vector_int_clear(&in_set);
364-
igraph_vector_int_clear(&out_set);
365511

366-
if (const auto res = get_saturating_neighborhoods(tmp_graph->get_graph(), &in_set, &out_set, v, config.timeout); res != IGRAPH_SUCCESS)
512+
if (config.components == DetectionConfiguration::Components::NONE)
513+
{
514+
for (const auto v : start_vertices)
367515
{
368-
igraph_vector_int_destroy(&in_set);
369-
igraph_vector_int_destroy(&out_set);
370-
return ERR(igraph_strerror(res));
371-
}
516+
igraph_vector_int_clear(&in_set);
517+
igraph_vector_int_clear(&out_set);
372518

373-
u32 size = igraph_vector_int_size(&out_set);
374-
if (size < config.min_register_size)
375-
{
376-
continue;
519+
if (const auto res = get_saturating_neighborhoods(tmp_graph->get_graph(), &in_set, &out_set, v, config.timeout); res != IGRAPH_SUCCESS)
520+
{
521+
igraph_vector_int_destroy(&in_set);
522+
igraph_vector_int_destroy(&out_set);
523+
return ERR(igraph_strerror(res));
524+
}
525+
526+
u32 size = igraph_vector_int_size(&out_set);
527+
if (size < config.min_register_size)
528+
{
529+
continue;
530+
}
531+
532+
GraphCandidate c;
533+
c.size = size;
534+
for (u32 i = 0; i < igraph_vector_int_size(&in_set); i++)
535+
{
536+
c.in_reg.insert(VECTOR(in_set)[i]);
537+
}
538+
for (u32 i = 0; i < igraph_vector_int_size(&out_set); i++)
539+
{
540+
c.out_reg.insert(VECTOR(out_set)[i]);
541+
}
542+
graph_candidates.insert(c);
377543
}
544+
}
545+
else if (config.components == DetectionConfiguration::Components::CHECK_SCC)
546+
{
547+
std::map<std::set<u32>, igraph_vector_int_t*> scc_cache;
378548

379-
GraphCandidate c;
380-
c.size = size;
381-
for (u32 i = 0; i < igraph_vector_int_size(&in_set); i++)
549+
for (const auto v : start_vertices)
382550
{
383-
c.in_reg.insert(VECTOR(in_set)[i]);
551+
igraph_vector_int_clear(&in_set);
552+
igraph_vector_int_clear(&out_set);
553+
554+
if (const auto res = get_saturating_neighborhoods_scc(tmp_graph->get_graph(), &in_set, &out_set, v, config.timeout, scc_cache); res != IGRAPH_SUCCESS)
555+
{
556+
igraph_vector_int_destroy(&in_set);
557+
igraph_vector_int_destroy(&out_set);
558+
for (auto& [_, comp] : scc_cache)
559+
{
560+
igraph_vector_int_destroy(comp);
561+
delete comp;
562+
}
563+
return ERR(igraph_strerror(res));
564+
}
565+
566+
u32 size = igraph_vector_int_size(&out_set);
567+
if (size < config.min_register_size)
568+
{
569+
continue;
570+
}
571+
572+
GraphCandidate c;
573+
c.size = size;
574+
for (u32 i = 0; i < igraph_vector_int_size(&in_set); i++)
575+
{
576+
c.in_reg.insert(VECTOR(in_set)[i]);
577+
}
578+
for (u32 i = 0; i < igraph_vector_int_size(&out_set); i++)
579+
{
580+
c.out_reg.insert(VECTOR(out_set)[i]);
581+
}
582+
graph_candidates.insert(c);
384583
}
385-
for (u32 i = 0; i < igraph_vector_int_size(&out_set); i++)
584+
585+
for (auto& [_, comp] : scc_cache)
386586
{
387-
c.out_reg.insert(VECTOR(out_set)[i]);
587+
igraph_vector_int_destroy(comp);
588+
delete comp;
388589
}
389-
graph_candidates.insert(c);
390590
}
391591

392592
igraph_vector_int_destroy(&in_set);
@@ -426,8 +626,6 @@ namespace hal
426626

427627
duration_in_seconds = std::chrono::duration<double>(std::chrono::system_clock::now() - start_inner).count();
428628
log_info("hawkeye", "successfully completed neighborhood discovery in {} seconds", duration_in_seconds);
429-
430-
// TODO implement SCC method
431629
}
432630

433631
duration_in_seconds = std::chrono::duration<double>(std::chrono::system_clock::now() - start).count();

0 commit comments

Comments
 (0)