HAL  v4.5.0-124-g47ab54673
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
netlist_graph.cpp
Go to the documentation of this file.
2 
5 #include "hal_core/netlist/net.h"
7 
8 namespace hal
9 {
10  namespace graph_algorithm
11  {
12 
13  NetlistGraph::NetlistGraph(Netlist* nl) : m_nl(nl)
14  {
15  }
16 
17  NetlistGraph::NetlistGraph(Netlist* nl, igraph_t&& graph, std::unordered_map<u32, Gate*>&& nodes_to_gates) : m_nl(nl), m_graph(std::move(graph)), m_nodes_to_gates(std::move(nodes_to_gates))
18  {
19  // This constructor receives an already-initialized graph and takes over its ownership. Note that
20  // `igraph_t` is a trivially copyable C struct, so the `std::move()` above is a bitwise copy and the
21  // caller's object is left holding the same pointers -- the caller must therefore not destroy it.
22  m_graph_initialized = true;
23  m_graph_ptr = &m_graph;
24 
25  for (const auto& [node, gate] : m_nodes_to_gates)
26  {
27  if (gate)
28  {
29  m_gates_to_nodes[gate] = node;
30  }
31  }
32  }
33 
35  {
36  // Guarded because the `NetlistGraph(Netlist*)` constructor leaves `m_graph` uninitialized and a
37  // factory may bail out before initializing it -- see `m_graph_initialized`.
38  if (m_graph_initialized)
39  {
40  igraph_destroy(&m_graph);
41  }
42  }
43 
44  Result<std::unique_ptr<NetlistGraph>> NetlistGraph::from_gates(const std::vector<Gate*>& gates, const std::set<Gate*>& split_gates, const std::function<bool(const Net*)>& filter)
45  {
46  if (gates.empty())
47  {
48  return ERR("no gates given");
49  }
50 
51  Netlist* nl = gates.front()->get_netlist();
52  std::unordered_set<Gate*> in_scope;
53  for (auto* g : gates)
54  {
55  if (g == nullptr)
56  {
57  return ERR("gate is a nullptr");
58  }
59  if (g->get_netlist() != nl)
60  {
61  return ERR("gates belong to different netlists");
62  }
63  if (!in_scope.insert(g).second)
64  {
65  return ERR("gate '" + g->get_name() + "' with ID " + std::to_string(g->get_id()) + " was given more than once");
66  }
67  }
68 
69  auto graph = std::unique_ptr<NetlistGraph>(new NetlistGraph(nl));
70 
71  // the primary node of a gate carries its outgoing edges, so it is the only node reachable by gate
72  u32 node_counter = 0;
73  for (auto* g : gates)
74  {
75  const u32 node = node_counter++;
76  graph->m_gates_to_nodes[g] = node;
77  graph->m_nodes_to_gates[node] = g;
78  }
79 
80  // collect the edges before creating the shadow nodes, as a gate only gets one if it has incoming edges
81  // within the graph. Nets are sorted by ID so that the graph does not depend on the addresses of the nets.
82  std::vector<Net*> nets;
83  std::unordered_set<Net*> visited_nets;
84  for (auto* g : gates)
85  {
86  for (auto* n : g->get_fan_out_nets())
87  {
88  if ((filter == nullptr || filter(n)) && visited_nets.insert(n).second)
89  {
90  nets.push_back(n);
91  }
92  }
93  }
94  std::sort(nets.begin(), nets.end(), [](const Net* lhs, const Net* rhs) { return lhs->get_id() < rhs->get_id(); });
95 
96  std::vector<std::pair<Gate*, Gate*>> edges;
97  std::unordered_set<Gate*> has_incoming_edge;
98  for (const auto* net : nets)
99  {
100  for (const auto* src_ep : net->get_sources())
101  {
102  auto* src_gate = src_ep->get_gate();
103  if (in_scope.find(src_gate) == in_scope.end())
104  {
105  continue;
106  }
107 
108  for (const auto* dst_ep : net->get_destinations())
109  {
110  auto* dst_gate = dst_ep->get_gate();
111  if (in_scope.find(dst_gate) == in_scope.end())
112  {
113  continue;
114  }
115 
116  edges.push_back({src_gate, dst_gate});
117  has_incoming_edge.insert(dst_gate);
118  }
119  }
120  }
121 
122  // a gate is only split if it actually has incoming edges, as an isolated shadow node would merely show up
123  // as a spurious connected component. Iterate `gates` rather than `split_gates` to keep node numbering
124  // independent of the addresses of the gates.
125  std::unordered_map<Gate*, u32> shadow_of;
126  for (auto* g : gates)
127  {
128  if (split_gates.find(g) == split_gates.end() || has_incoming_edge.find(g) == has_incoming_edge.end())
129  {
130  continue;
131  }
132 
133  const u32 shadow_node = node_counter++;
134  graph->m_nodes_to_gates[shadow_node] = g;
135  graph->m_shadow_nodes_to_nodes[shadow_node] = graph->m_gates_to_nodes.at(g);
136  shadow_of[g] = shadow_node;
137  }
138 
139  igraph_vector_int_t igraph_edges;
140  auto err = igraph_vector_int_init(&igraph_edges, 2 * edges.size());
141  if (err != IGRAPH_SUCCESS)
142  {
143  return ERR(igraph_strerror(err));
144  }
145 
146  // an edge always leaves the primary node of its source and arrives at the shadow node of its destination if
147  // there is one, which turns a split gate into a pure source plus a pure sink
148  u32 edge_index = 0;
149  for (const auto& [src_gate, dst_gate] : edges)
150  {
151  const auto shadow_it = shadow_of.find(dst_gate);
152  VECTOR(igraph_edges)[edge_index++] = graph->m_gates_to_nodes.at(src_gate);
153  VECTOR(igraph_edges)[edge_index++] = (shadow_it != shadow_of.end()) ? shadow_it->second : graph->m_gates_to_nodes.at(dst_gate);
154  }
155 
156  graph->m_graph_ptr = &(graph->m_graph);
157  err = igraph_create(graph->m_graph_ptr, &igraph_edges, node_counter, IGRAPH_DIRECTED);
158 
159  igraph_vector_int_destroy(&igraph_edges);
160 
161  if (err != IGRAPH_SUCCESS)
162  {
163  return ERR(igraph_strerror(err));
164  }
165 
166  graph->m_graph_initialized = true;
167 
168  return OK(std::move(graph));
169  }
170 
171  Result<std::unique_ptr<NetlistGraph>> NetlistGraph::from_netlist(Netlist* nl, bool create_dummy_vertices, const std::function<bool(const Net*)>& filter)
172  {
173  if (!nl)
174  {
175  return ERR("netlist is a nullptr");
176  }
177 
178  auto graph = std::unique_ptr<NetlistGraph>(new NetlistGraph(nl));
179 
180  // count all edges as this number is needed to create a new graph
181  u32 edge_counter = 0;
182  for (const auto* net : graph->m_nl->get_nets(filter))
183  {
184  std::vector<Gate*> src_gates;
185  for (const auto* src_ep : net->get_sources())
186  {
187  src_gates.push_back(src_ep->get_gate());
188  }
189 
190  std::vector<Gate*> dst_gates;
191  for (const auto* dst_ep : net->get_destinations())
192  {
193  dst_gates.push_back(dst_ep->get_gate());
194  }
195 
196  if (src_gates.empty() && create_dummy_vertices)
197  {
198  // if no sources, add one dummy edge for every destination
199  // all dummy edges will come from the same dummy node
200  edge_counter += dst_gates.size();
201  }
202  else if (dst_gates.empty() && create_dummy_vertices)
203  {
204  // if no destinations, add one dummy edge for every source
205  // all dummy edges will go to the same dummy node
206  edge_counter += src_gates.size();
207  }
208  else
209  {
210  // add one edge for every source-destination pair
211  edge_counter += dst_gates.size() * src_gates.size();
212  }
213  }
214 
215  // initialize edge vector
216  igraph_vector_int_t edges;
217  auto err = igraph_vector_int_init(&edges, 2 * edge_counter);
218  if (err != IGRAPH_SUCCESS)
219  {
220  return ERR(igraph_strerror(err));
221  }
222 
223  // we need dummy gates for input/outputs
224  u32 node_counter = 0;
225  u32 edge_index = 0;
226 
227  for (auto* g : graph->m_nl->get_gates())
228  {
229  const u32 node = node_counter++;
230  graph->m_gates_to_nodes[g] = node;
231  graph->m_nodes_to_gates[node] = g;
232  }
233 
234  for (const auto* net : graph->m_nl->get_nets(filter))
235  {
236  std::vector<Gate*> src_gates;
237  for (const auto* src_ep : net->get_sources())
238  {
239  src_gates.push_back(src_ep->get_gate());
240  }
241 
242  std::vector<Gate*> dst_gates;
243  for (const auto* dst_ep : net->get_destinations())
244  {
245  dst_gates.push_back(dst_ep->get_gate());
246  }
247 
248  if (src_gates.empty() && create_dummy_vertices)
249  {
250  // if no sources, add one dummy node
251  const u32 dummy_node = node_counter++;
252  graph->m_nodes_to_gates[dummy_node] = nullptr;
253  for (auto* dst_gate : dst_gates)
254  {
255  VECTOR(edges)[edge_index++] = dummy_node;
256  VECTOR(edges)[edge_index++] = graph->m_gates_to_nodes.at(dst_gate);
257  }
258  }
259  else if (dst_gates.empty() && create_dummy_vertices)
260  {
261  // if no destinations, add one dummy node
262  const u32 dummy_node = node_counter++;
263  graph->m_nodes_to_gates[dummy_node] = nullptr;
264  for (auto* src_gate : src_gates)
265  {
266  VECTOR(edges)[edge_index++] = dummy_node;
267  VECTOR(edges)[edge_index++] = graph->m_gates_to_nodes.at(src_gate);
268  }
269  }
270  else
271  {
272  for (auto* dst_gate : dst_gates)
273  {
274  for (auto* src_gate : src_gates)
275  {
276  VECTOR(edges)[edge_index++] = graph->m_gates_to_nodes.at(src_gate);
277  VECTOR(edges)[edge_index++] = graph->m_gates_to_nodes.at(dst_gate);
278  }
279  }
280  }
281  }
282 
283  graph->m_graph_ptr = &(graph->m_graph);
284  err = igraph_create(graph->m_graph_ptr, &edges, node_counter, IGRAPH_DIRECTED);
285 
286  igraph_vector_int_destroy(&edges);
287 
288  if (err != IGRAPH_SUCCESS)
289  {
290  return ERR(igraph_strerror(err));
291  }
292 
293  graph->m_graph_initialized = true;
294 
295  return OK(std::move(graph));
296  }
297 
299  {
300  if (!nl)
301  {
302  return ERR("netlist is a nullptr");
303  }
304 
305  auto graph = std::unique_ptr<NetlistGraph>(new NetlistGraph(nl));
306 
307  const auto& graph_gates = gates.empty() ? graph->m_nl->get_gates() : gates;
308 
309  u32 node_counter = 0;
310  for (auto* g : graph_gates)
311  {
312  const u32 node = node_counter++;
313  graph->m_gates_to_nodes[g] = node;
314  graph->m_nodes_to_gates[node] = g;
315  }
316 
317  graph->m_graph_ptr = &(graph->m_graph);
318  auto err = igraph_empty(graph->m_graph_ptr, node_counter, IGRAPH_DIRECTED);
319  if (err != IGRAPH_SUCCESS)
320  {
321  return ERR(igraph_strerror(err));
322  }
323 
324  graph->m_graph_initialized = true;
325 
326  return OK(std::move(graph));
327  }
328 
330  {
331  auto graph = std::unique_ptr<NetlistGraph>(new NetlistGraph(m_nl));
332 
333  if (const auto res = igraph_copy(&(graph->m_graph), &(this->m_graph)); res != IGRAPH_SUCCESS)
334  {
335  return ERR(igraph_strerror(res));
336  }
337 
338  graph->m_graph_initialized = true;
339  graph->m_graph_ptr = &(graph->m_graph);
340  graph->m_gates_to_nodes = this->m_gates_to_nodes;
341  graph->m_nodes_to_gates = this->m_nodes_to_gates;
342 
343  return OK(std::move(graph));
344  }
345 
347  {
348  return m_nl;
349  }
350 
351  igraph_t* NetlistGraph::get_graph() const
352  {
353  return m_graph_ptr;
354  }
355 
356  Result<std::vector<Gate*>> NetlistGraph::get_gates_from_vertices(const std::vector<u32>& vertices) const
357  {
358  std::vector<Gate*> res;
359  for (const auto& vertex : vertices)
360  {
361  if (const auto it = m_nodes_to_gates.find(vertex); it != m_nodes_to_gates.end())
362  {
363  Gate* g = it->second;
364 
365  res.push_back(g);
366  if (!g)
367  {
368  log_warning("graph_algorithm", "no gate exists for dummy vertex {}, added nullptr", vertex);
369  }
370  }
371  else
372  {
373  return ERR("no gate for vertex " + std::to_string(vertex) + " exists in netlist with ID " + std::to_string(m_nl->get_id()));
374  }
375  }
376  return OK(res);
377  }
378 
380  {
381  std::vector<Gate*> res;
382  for (const auto& vertex : vertices)
383  {
384  if (const auto it = m_nodes_to_gates.find(vertex); it != m_nodes_to_gates.end())
385  {
386  Gate* g = it->second;
387 
388  res.push_back(g);
389  if (!g)
390  {
391  log_warning("graph_algorithm", "no gate exists for dummy vertex {}, added nullptr", vertex);
392  }
393  }
394  else
395  {
396  return ERR("no gate for vertex " + std::to_string(vertex) + " exists in netlist with ID " + std::to_string(m_nl->get_id()));
397  }
398  }
399  return OK(res);
400  }
401 
403  {
404  std::vector<Gate*> res;
405  const u32 num_vertices = igraph_vector_int_size(vertices);
406  for (u32 i = 0; i < num_vertices; i++)
407  {
408  u32 vertex = VECTOR(*vertices)[i];
409  if (const auto it = m_nodes_to_gates.find(vertex); it != m_nodes_to_gates.end())
410  {
411  Gate* g = it->second;
412 
413  res.push_back(g);
414  if (!g)
415  {
416  log_warning("graph_algorithm", "no gate exists for dummy vertex {}, added nullptr", vertex);
417  }
418  }
419  else
420  {
421  return ERR("no gate for vertex " + std::to_string(vertex) + " exists in netlist with ID " + std::to_string(m_nl->get_id()));
422  }
423  }
424  return OK(res);
425  }
426 
427  Result<std::set<Gate*>> NetlistGraph::get_gates_set_from_vertices(const std::vector<u32>& vertices) const
428  {
429  std::set<Gate*> res;
430  for (const auto& vertex : vertices)
431  {
432  if (const auto it = m_nodes_to_gates.find(vertex); it != m_nodes_to_gates.end())
433  {
434  Gate* g = it->second;
435 
436  if (!g)
437  {
438  log_warning("graph_algorithm", "no gate exists for dummy vertex {}, skipping vertex", vertex);
439  continue;
440  }
441  res.insert(g);
442  }
443  else
444  {
445  return ERR("no gate for vertex " + std::to_string(vertex) + " exists in netlist with ID " + std::to_string(m_nl->get_id()));
446  }
447  }
448  return OK(res);
449  }
450 
452  {
453  std::set<Gate*> res;
454  for (const auto& vertex : vertices)
455  {
456  if (const auto it = m_nodes_to_gates.find(vertex); it != m_nodes_to_gates.end())
457  {
458  Gate* g = it->second;
459 
460  if (!g)
461  {
462  log_warning("graph_algorithm", "no gate exists for dummy vertex {}, skipping vertex", vertex);
463  continue;
464  }
465  res.insert(g);
466  }
467  else
468  {
469  return ERR("no gate for vertex " + std::to_string(vertex) + " exists in netlist with ID " + std::to_string(m_nl->get_id()));
470  }
471  }
472  return OK(res);
473  }
474 
476  {
477  std::set<Gate*> res;
478  const u32 num_vertices = igraph_vector_int_size(vertices);
479  for (u32 i = 0; i < num_vertices; i++)
480  {
481  u32 vertex = VECTOR(*vertices)[i];
482  if (const auto it = m_nodes_to_gates.find(vertex); it != m_nodes_to_gates.end())
483  {
484  Gate* g = it->second;
485 
486  if (!g)
487  {
488  log_warning("graph_algorithm", "no gate exists for dummy vertex {}, skipping vertex", vertex);
489  continue;
490  }
491  res.insert(g);
492  }
493  else
494  {
495  return ERR("no gate for vertex " + std::to_string(vertex) + " exists in netlist with ID " + std::to_string(m_nl->get_id()));
496  }
497  }
498  return OK(res);
499  }
500 
502  {
503  const auto res = get_gates_from_vertices(std::vector<u32>({vertex}));
504  if (res.is_error())
505  {
506  return ERR(res.get_error());
507  }
508 
509  return OK(res.get().front());
510  }
511 
512  Result<std::vector<u32>> NetlistGraph::get_vertices_from_gates(const std::vector<Gate*>& gates) const
513  {
514  std::vector<u32> res;
515  for (u32 i = 0; i < gates.size(); i++)
516  {
517  auto* g = gates.at(i);
518 
519  if (!g)
520  {
521  return ERR("gate at index " + std::to_string(i) + " is a nullptr");
522  }
523 
524  if (const auto it = m_gates_to_nodes.find(g); it != m_gates_to_nodes.end())
525  {
526  res.push_back(it->second);
527  }
528  else
529  {
530  return ERR("no node for gate '" + g->get_name() + "' with ID " + std::to_string(g->get_id()) + " exists in graph for netlist with ID " + std::to_string(m_nl->get_id()));
531  }
532  }
533  return OK(res);
534  }
535 
537  {
538  std::vector<u32> res;
539  for (auto* g : gates)
540  {
541  if (!g)
542  {
543  return ERR("set of gates contains a nullptr");
544  }
545 
546  if (const auto it = m_gates_to_nodes.find(g); it != m_gates_to_nodes.end())
547  {
548  res.push_back(it->second);
549  }
550  else
551  {
552  return ERR("no node for gate '" + g->get_name() + "' with ID " + std::to_string(g->get_id()) + " exists in graph for netlist with ID " + std::to_string(m_nl->get_id()));
553  }
554  }
555  return OK(res);
556  }
557 
559  {
560  igraph_vector_int_t out;
561  if (auto res = igraph_vector_int_init(&out, gates.size()); res != IGRAPH_SUCCESS)
562  {
563  return ERR(igraph_strerror(res));
564  }
565 
566  for (u32 i = 0; i < gates.size(); i++)
567  {
568  auto* g = gates.at(i);
569 
570  if (!g)
571  {
572  return ERR("gate at index " + std::to_string(i) + " is a nullptr");
573  }
574 
575  if (const auto it = m_gates_to_nodes.find(g); it != m_gates_to_nodes.end())
576  {
577  VECTOR(out)[i] = it->second;
578  }
579  else
580  {
581  return ERR("no node for gate '" + g->get_name() + "' with ID " + std::to_string(g->get_id()) + " exists in graph for netlist with ID " + std::to_string(m_nl->get_id()));
582  }
583  }
584  return OK(std::move(out));
585  }
586 
588  {
589  igraph_vector_int_t out;
590  if (auto res = igraph_vector_int_init(&out, gates.size()); res != IGRAPH_SUCCESS)
591  {
592  return ERR(igraph_strerror(res));
593  }
594 
595  u32 i = 0;
596  for (auto gates_it = gates.begin(); gates_it != gates.end(); gates_it++)
597  {
598  auto* g = *gates_it;
599 
600  if (!g)
601  {
602  return ERR("gate at index " + std::to_string(i) + " is a nullptr");
603  }
604 
605  if (const auto nodes_it = m_gates_to_nodes.find(g); nodes_it != m_gates_to_nodes.end())
606  {
607  VECTOR(out)[i] = nodes_it->second;
608  }
609  else
610  {
611  return ERR("no node for gate '" + g->get_name() + "' with ID " + std::to_string(g->get_id()) + " exists in graph for netlist with ID " + std::to_string(m_nl->get_id()));
612  }
613 
614  i++;
615  }
616  return OK(std::move(out));
617  }
618 
620  {
621  const auto res = get_vertices_from_gates(std::vector<Gate*>({g}));
622  if (res.is_error())
623  {
624  return ERR(res.get_error());
625  }
626 
627  return OK(res.get().front());
628  }
629 
630  bool NetlistGraph::is_shadow_vertex(const u32 vertex) const
631  {
632  return m_shadow_nodes_to_nodes.find(vertex) != m_shadow_nodes_to_nodes.end();
633  }
634 
636  {
637  const auto node_it = m_gates_to_nodes.find(g);
638  if (node_it == m_gates_to_nodes.end())
639  {
640  return ERR("no vertex exists for gate '" + g->get_name() + "' with ID " + std::to_string(g->get_id()));
641  }
642 
643  std::vector<u32> res = {node_it->second};
644  for (const auto& [shadow_node, node] : m_shadow_nodes_to_nodes)
645  {
646  if (node == node_it->second)
647  {
648  res.push_back(shadow_node);
649  }
650  }
651  return OK(res);
652  }
653 
654  u32 NetlistGraph::get_num_vertices(bool only_connected) const
655  {
656  u32 num_vertices = igraph_vcount(&m_graph);
657 
658  if (!only_connected)
659  {
660  return num_vertices;
661  }
662  else
663  {
664  u32 num_connected_vertices = 0;
665 
666  igraph_vector_int_t degrees;
667  igraph_vector_int_init(&degrees, num_vertices);
668 
669  igraph_vs_t v_sel = igraph_vss_all();
670  igraph_degree(&m_graph, &degrees, v_sel, IGRAPH_ALL, IGRAPH_LOOPS);
671 
672  for (u32 i = 0; i < num_vertices; i++)
673  {
674  if (VECTOR(degrees)[i] != 0)
675  {
676  num_connected_vertices++;
677  }
678  }
679 
680  igraph_vector_int_destroy(&degrees);
681  igraph_vs_destroy(&v_sel);
682 
683  return num_connected_vertices;
684  }
685  }
686 
688  {
689  return igraph_ecount(&m_graph);
690  }
691 
693  {
694  u32 num_vertices = igraph_vcount(&m_graph);
695 
696  if (!only_connected)
697  {
698  std::vector<u32> vertices(num_vertices);
699  for (u32 i = 0; i < num_vertices; i++)
700  {
701  vertices[i] = i;
702  }
703  return OK(vertices);
704  }
705  else
706  {
707  std::vector<u32> vertices;
708 
709  igraph_vector_int_t degrees;
710  if (auto res = igraph_vector_int_init(&degrees, num_vertices); res != IGRAPH_SUCCESS)
711  {
712  return ERR(igraph_strerror(res));
713  }
714 
715  igraph_vs_t v_sel = igraph_vss_all();
716  if (auto res = igraph_degree(&m_graph, &degrees, v_sel, IGRAPH_ALL, IGRAPH_LOOPS); res != IGRAPH_SUCCESS)
717  {
718  igraph_vs_destroy(&v_sel);
719  igraph_vector_int_destroy(&degrees);
720  return ERR(igraph_strerror(res));
721  }
722 
723  for (u32 i = 0; i < num_vertices; i++)
724  {
725  if (VECTOR(degrees)[i] != 0)
726  {
727  vertices.push_back(i);
728  }
729  }
730 
731  igraph_vector_int_destroy(&degrees);
732  igraph_vs_destroy(&v_sel);
733 
734  return OK(vertices);
735  }
736  }
737 
739  {
740  const u32 ecount = igraph_ecount(&m_graph);
741 
742  igraph_vector_int_t edges;
743  if (auto res = igraph_vector_int_init(&edges, 2 * ecount); res != IGRAPH_SUCCESS)
744  {
745  return ERR(igraph_strerror(res));
746  }
747 
748  if (auto res = igraph_get_edgelist(&m_graph, &edges, false); res != IGRAPH_SUCCESS)
749  {
750  igraph_vector_int_destroy(&edges);
751  return ERR(igraph_strerror(res));
752  }
753 
754  std::vector<std::pair<u32, u32>> e_vec(ecount);
755  for (u32 i = 0; i < ecount; i++)
756  {
757  const u32 src_vertex = (u32)VECTOR(edges)[2 * i];
758  const u32 dst_vertex = (u32)VECTOR(edges)[2 * i + 1];
759 
760  e_vec[i] = std::make_pair(src_vertex, dst_vertex);
761  }
762 
763  return OK(e_vec);
764  }
765 
767  {
768  const u32 ecount = igraph_ecount(&m_graph);
769 
770  igraph_vector_int_t edges;
771  if (auto res = igraph_vector_int_init(&edges, 2 * ecount); res != IGRAPH_SUCCESS)
772  {
773  return ERR(igraph_strerror(res));
774  }
775 
776  if (auto res = igraph_get_edgelist(&m_graph, &edges, false); res != IGRAPH_SUCCESS)
777  {
778  igraph_vector_int_destroy(&edges);
779  return ERR(igraph_strerror(res));
780  }
781 
782  std::vector<std::pair<Gate*, Gate*>> e_vec(ecount);
783  for (u32 i = 0; i < ecount; i++)
784  {
785  const u32 src_vertex = (u32)VECTOR(edges)[2 * i];
786  const u32 dst_vertex = (u32)VECTOR(edges)[2 * i + 1];
787  Gate *src_gate, *dst_gate;
788 
789  if (const auto it = m_nodes_to_gates.find(src_vertex); it != m_nodes_to_gates.end())
790  {
791  src_gate = it->second;
792  if (src_gate == nullptr)
793  {
794  log_warning("graph_algorithm",
795  "ignored edge (" + std::to_string(src_vertex) + "," + std::to_string(dst_vertex) + ") at dummy source vertex '" + std::to_string(src_vertex) + "'");
796  continue;
797  }
798  }
799 
800  if (const auto it = m_nodes_to_gates.find(dst_vertex); it != m_nodes_to_gates.end())
801  {
802  dst_gate = it->second;
803  if (dst_gate == nullptr)
804  {
805  log_warning("graph_algorithm",
806  "ignored edge (" + std::to_string(src_vertex) + "," + std::to_string(dst_vertex) + ") at dummy destination vertex '" + std::to_string(dst_vertex) + "'");
807  continue;
808  }
809  }
810 
811  e_vec[i] = std::make_pair(src_gate, dst_gate);
812  }
813 
814  return OK(e_vec);
815  }
816 
817  Result<std::monostate> NetlistGraph::add_edges(const std::vector<std::pair<Gate*, Gate*>>& edges)
818  {
819  igraph_vector_int_t e_vec;
820  if (auto res = igraph_vector_int_init(&e_vec, 2 * edges.size()); res != IGRAPH_SUCCESS)
821  {
822  return ERR(igraph_strerror(res));
823  }
824 
825  u32 edge_index = 0;
826  for (const auto& [src_gate, dst_gate] : edges)
827  {
828  if (auto it = m_gates_to_nodes.find(src_gate); it != m_gates_to_nodes.end())
829  {
830  VECTOR(e_vec)[edge_index++] = it->second;
831  }
832  else
833  {
834  igraph_vector_int_destroy(&e_vec);
835  return ERR("no node for gate '" + src_gate->get_name() + "' with ID " + std::to_string(src_gate->get_id()) + " exists in graph for netlist with ID "
836  + std::to_string(m_nl->get_id()));
837  }
838 
839  if (auto it = m_gates_to_nodes.find(dst_gate); it != m_gates_to_nodes.end())
840  {
841  VECTOR(e_vec)[edge_index++] = it->second;
842  }
843  else
844  {
845  igraph_vector_int_destroy(&e_vec);
846  return ERR("no node for gate '" + dst_gate->get_name() + "' with ID " + std::to_string(dst_gate->get_id()) + " exists in graph for netlist with ID "
847  + std::to_string(m_nl->get_id()));
848  }
849  }
850 
851  if (auto res = igraph_add_edges(&m_graph, &e_vec, nullptr); res != IGRAPH_SUCCESS)
852  {
853  igraph_vector_int_destroy(&e_vec);
854  return ERR(igraph_strerror(res));
855  }
856 
857  return OK({});
858  }
859 
860  Result<std::monostate> NetlistGraph::add_edges(const std::vector<std::pair<u32, u32>>& edges)
861  {
862  igraph_vector_int_t e_vec;
863  if (auto err = igraph_vector_int_init(&e_vec, 2 * edges.size()); err != IGRAPH_SUCCESS)
864  {
865  return ERR(igraph_strerror(err));
866  }
867 
868  u32 vcount = igraph_vcount(&m_graph);
869 
870  u32 edge_index = 0;
871  for (const auto& [src_vertex, dst_vertex] : edges)
872  {
873  if (src_vertex >= vcount)
874  {
875  igraph_vector_int_destroy(&e_vec);
876  return ERR("source vertex '" + std::to_string(src_vertex) + "' does not exist in graph for netlist with ID " + std::to_string(m_nl->get_id()));
877  }
878  if (dst_vertex >= vcount)
879  {
880  igraph_vector_int_destroy(&e_vec);
881  return ERR("destination vertex '" + std::to_string(dst_vertex) + "' does not exist in graph for netlist with ID " + std::to_string(m_nl->get_id()));
882  }
883 
884  VECTOR(e_vec)[edge_index++] = src_vertex;
885  VECTOR(e_vec)[edge_index++] = dst_vertex;
886  }
887 
888  if (auto err = igraph_add_edges(&m_graph, &e_vec, nullptr); err != IGRAPH_SUCCESS)
889  {
890  igraph_vector_int_destroy(&e_vec);
891  return ERR(igraph_strerror(err));
892  }
893 
894  return OK({});
895  }
896 
897  Result<std::monostate> NetlistGraph::add_edges(const std::map<Gate*, std::set<Gate*>>& edges)
898  {
899  u32 edge_count = 0;
900  for (const auto& [_, dst_gates] : edges)
901  {
902  edge_count += dst_gates.size();
903  }
904 
905  igraph_vector_int_t e_vec;
906  if (auto err = igraph_vector_int_init(&e_vec, 2 * edge_count); err != IGRAPH_SUCCESS)
907  {
908  return ERR(igraph_strerror(err));
909  }
910 
911  u32 edge_index = 0;
912  for (const auto& [src_gate, dst_gates] : edges)
913  {
914  u32 src_vertex;
915  if (auto it = m_gates_to_nodes.find(src_gate); it != m_gates_to_nodes.end())
916  {
917  src_vertex = it->second;
918  }
919  else
920  {
921  igraph_vector_int_destroy(&e_vec);
922  return ERR("no node for gate '" + src_gate->get_name() + "' with ID " + std::to_string(src_gate->get_id()) + " exists in graph for netlist with ID "
923  + std::to_string(m_nl->get_id()));
924  }
925 
926  for (auto* dst_gate : dst_gates)
927  {
928  if (auto it = m_gates_to_nodes.find(dst_gate); it != m_gates_to_nodes.end())
929  {
930  VECTOR(e_vec)[edge_index++] = src_vertex;
931  VECTOR(e_vec)[edge_index++] = it->second;
932  }
933  else
934  {
935  igraph_vector_int_destroy(&e_vec);
936  return ERR("no node for gate '" + dst_gate->get_name() + "' with ID " + std::to_string(dst_gate->get_id()) + " exists in graph for netlist with ID "
937  + std::to_string(m_nl->get_id()));
938  }
939  }
940  }
941 
942  if (auto err = igraph_add_edges(&m_graph, &e_vec, nullptr); err != IGRAPH_SUCCESS)
943  {
944  igraph_vector_int_destroy(&e_vec);
945  return ERR(igraph_strerror(err));
946  }
947 
948  return OK({});
949  }
950 
951  Result<std::monostate> NetlistGraph::delete_edges(const std::vector<std::pair<Gate*, Gate*>>& edges)
952  {
953  igraph_vector_int_t e_vec;
954  if (auto err = igraph_vector_int_init(&e_vec, 2 * edges.size()); err != IGRAPH_SUCCESS)
955  {
956  return ERR(igraph_strerror(err));
957  }
958 
959  u32 vcount = igraph_vcount(&m_graph);
960 
961  u32 edge_index = 0;
962  for (const auto& [src_gate, dst_gate] : edges)
963  {
964  if (auto it = m_gates_to_nodes.find(src_gate); it != m_gates_to_nodes.end())
965  {
966  VECTOR(e_vec)[edge_index++] = it->second;
967  }
968  else
969  {
970  igraph_vector_int_destroy(&e_vec);
971  return ERR("no node for gate '" + src_gate->get_name() + "' with ID " + std::to_string(src_gate->get_id()) + " exists in graph for netlist with ID "
972  + std::to_string(m_nl->get_id()));
973  }
974 
975  if (auto it = m_gates_to_nodes.find(dst_gate); it != m_gates_to_nodes.end())
976  {
977  VECTOR(e_vec)[edge_index++] = it->second;
978  }
979  else
980  {
981  igraph_vector_int_destroy(&e_vec);
982  return ERR("no node for gate '" + dst_gate->get_name() + "' with ID " + std::to_string(dst_gate->get_id()) + " exists in graph for netlist with ID "
983  + std::to_string(m_nl->get_id()));
984  }
985  }
986 
987  igraph_es_t e_sel;
988  if (auto res = igraph_es_pairs(&e_sel, &e_vec, IGRAPH_DIRECTED); res != IGRAPH_SUCCESS)
989  {
990  igraph_vector_int_destroy(&e_vec);
991  return ERR(igraph_strerror(res));
992  }
993 
994  if (auto res = igraph_delete_edges(&m_graph, e_sel); res != IGRAPH_SUCCESS)
995  {
996  igraph_es_destroy(&e_sel);
997  igraph_vector_int_destroy(&e_vec);
998  return ERR(igraph_strerror(res));
999  }
1000 
1001  igraph_es_destroy(&e_sel);
1002  igraph_vector_int_destroy(&e_vec);
1003 
1004  return OK({});
1005  }
1006 
1007  Result<std::monostate> NetlistGraph::delete_edges(const std::vector<std::pair<u32, u32>>& edges)
1008  {
1009  igraph_vector_int_t e_vec;
1010  if (auto err = igraph_vector_int_init(&e_vec, 2 * edges.size()); err != IGRAPH_SUCCESS)
1011  {
1012  return ERR(igraph_strerror(err));
1013  }
1014 
1015  u32 vcount = igraph_vcount(&m_graph);
1016 
1017  u32 edge_index = 0;
1018  for (const auto& [src_vertex, dst_vertex] : edges)
1019  {
1020  if (src_vertex >= vcount)
1021  {
1022  igraph_vector_int_destroy(&e_vec);
1023  return ERR("source vertex '" + std::to_string(src_vertex) + "' does not exist in graph for netlist with ID " + std::to_string(m_nl->get_id()));
1024  }
1025  if (dst_vertex >= vcount)
1026  {
1027  igraph_vector_int_destroy(&e_vec);
1028  return ERR("destination vertex '" + std::to_string(dst_vertex) + "' does not exist in graph for netlist with ID " + std::to_string(m_nl->get_id()));
1029  }
1030 
1031  VECTOR(e_vec)[edge_index++] = src_vertex;
1032  VECTOR(e_vec)[edge_index++] = dst_vertex;
1033  }
1034 
1035  igraph_es_t e_sel;
1036  if (auto res = igraph_es_pairs(&e_sel, &e_vec, IGRAPH_DIRECTED); res != IGRAPH_SUCCESS)
1037  {
1038  igraph_vector_int_destroy(&e_vec);
1039  return ERR(igraph_strerror(res));
1040  }
1041 
1042  if (auto res = igraph_delete_edges(&m_graph, e_sel); res != IGRAPH_SUCCESS)
1043  {
1044  igraph_es_destroy(&e_sel);
1045  igraph_vector_int_destroy(&e_vec);
1046  return ERR(igraph_strerror(res));
1047  }
1048 
1049  igraph_es_destroy(&e_sel);
1050  igraph_vector_int_destroy(&e_vec);
1051 
1052  return OK({});
1053  }
1054 
1055  void NetlistGraph::print() const
1056  {
1057  igraph_write_graph_edgelist(&m_graph, stdout);
1058  }
1059  } // namespace graph_algorithm
1060 
1061  template<>
1062  std::map<graph_algorithm::NetlistGraph::Direction, std::string> EnumStrings<graph_algorithm::NetlistGraph::Direction>::data = {{graph_algorithm::NetlistGraph::Direction::NONE, "NONE"},
1066 } // namespace hal
Definition: gate.h:58
const std::string & get_name() const
Definition: gate.cpp:105
u32 get_id() const
Definition: gate.cpp:95
Definition: net.h:58
u32 get_id() const
Definition: netlist.cpp:77
A directed graph corresponding to a netlist.
Definition: netlist_graph.h:60
Netlist * get_netlist() const
Get the netlist associated with the netlist graph.
u32 get_num_vertices(bool only_connected=false) const
Get the number of vertices in the netlist graph.
bool is_shadow_vertex(const u32 vertex) const
Check whether the specified vertex is a shadow vertex.
Result< std::vector< Gate * > > get_gates_from_vertices(const std::vector< u32 > &vertices) const
Get the gates corresponding to the specified vertices.
static Result< std::unique_ptr< NetlistGraph > > from_netlist(Netlist *nl, bool create_dummy_vertices=false, const std::function< bool(const Net *)> &filter=nullptr)
Create a directed graph from a netlist.
Result< Gate * > get_gate_from_vertex(const u32 vertex) const
Get the gate corresponding to the specified vertex.
Result< std::unique_ptr< NetlistGraph > > copy() const
Create a deep copy of the netlist graph.
Result< std::set< Gate * > > get_gates_set_from_vertices(const std::vector< u32 > &vertices) const
Get the gates corresponding to the specified vertices.
~NetlistGraph()
Default destructor for NetlistGraph.
Result< std::set< Gate * > > get_gates_set_from_vertices_igraph(const igraph_vector_int_t *vertices) const
Get the gates corresponding to the specified vertices.
@ ALL
Explore in both directions, i.e., treat the graph as undirected.
@ NONE
No direction, invalid default setting.
@ IN
Explore through the inputs of the current node, i.e., traverse backwards.
@ OUT
Explore through the outputs of the current node, i.e., traverse forwards.
Result< u32 > get_vertex_from_gate(Gate *g) const
Get the vertex corresponding to the specified gate.
Result< igraph_vector_int_t > get_vertices_from_gates_igraph(const std::vector< Gate * > &gates) const
Get the vertices corresponding to the specified gates.
Result< std::vector< u32 > > get_vertices_from_gates(const std::vector< Gate * > &gates) const
Get the vertices corresponding to the specified gates.
static Result< std::unique_ptr< NetlistGraph > > from_gates(const std::vector< Gate * > &gates, const std::set< Gate * > &split_gates={}, const std::function< bool(const Net *)> &filter=nullptr)
Create a directed graph from a subset of the gates of a netlist.
Result< std::monostate > add_edges(const std::vector< std::pair< Gate *, Gate * >> &edges)
Add edges between the specified pairs of source and destination gates to the netlist graph.
void print() const
Print the edge list of the graph to stdout.
Result< std::vector< Gate * > > get_gates_from_vertices_igraph(const igraph_vector_int_t *vertices) const
Get the gates corresponding to the specified vertices.
Result< std::vector< std::pair< u32, u32 > > > get_edges() const
Get the edges between vertices in the netlist graph.
u32 get_num_edges() const
Get the number of edges in the netlist graph.
Result< std::vector< std::pair< Gate *, Gate * > > > get_edges_in_netlist() const
Get the edges between gates in the netlist corresponding to the netlist graph.
Result< std::monostate > delete_edges(const std::vector< std::pair< Gate *, Gate * >> &edges)
Delete edges between the specified pairs of source and destination gates from the netlist graph.
Result< std::vector< u32 > > get_vertices(bool only_connected=false) const
Get the vertices in the netlist graph.
static Result< std::unique_ptr< NetlistGraph > > from_netlist_no_edges(Netlist *nl, const std::vector< Gate * > &gates={})
Create an empty directed graph from a netlist.
Result< std::vector< u32 > > get_all_vertices_from_gate(Gate *g) const
Get all vertices corresponding to the specified gate, i.e., its primary vertex and,...
igraph_t * get_graph() const
Get the graph object of the netlist graph.
uint32_t u32
Definition: defines.h:41
#define log_warning(channel,...)
Definition: log.h:76
#define ERR(message)
Definition: result.h:60
#define OK(...)
Definition: result.h:56
Definition: defines.h:45
Net * net
This file contains the class that holds a netlist graph.