HAL  v4.5.0-83-g30c8f0afc
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_netlist(Netlist* nl, bool create_dummy_vertices, const std::function<bool(const Net*)>& filter)
45  {
46  if (!nl)
47  {
48  return ERR("netlist is a nullptr");
49  }
50 
51  auto graph = std::unique_ptr<NetlistGraph>(new NetlistGraph(nl));
52 
53  // count all edges as this number is needed to create a new graph
54  u32 edge_counter = 0;
55  for (const auto* net : graph->m_nl->get_nets(filter))
56  {
57  std::vector<Gate*> src_gates;
58  for (const auto* src_ep : net->get_sources())
59  {
60  src_gates.push_back(src_ep->get_gate());
61  }
62 
63  std::vector<Gate*> dst_gates;
64  for (const auto* dst_ep : net->get_destinations())
65  {
66  dst_gates.push_back(dst_ep->get_gate());
67  }
68 
69  if (src_gates.empty() && create_dummy_vertices)
70  {
71  // if no sources, add one dummy edge for every destination
72  // all dummy edges will come from the same dummy node
73  edge_counter += dst_gates.size();
74  }
75  else if (dst_gates.empty() && create_dummy_vertices)
76  {
77  // if no destinations, add one dummy edge for every source
78  // all dummy edges will go to the same dummy node
79  edge_counter += src_gates.size();
80  }
81  else
82  {
83  // add one edge for every source-destination pair
84  edge_counter += dst_gates.size() * src_gates.size();
85  }
86  }
87 
88  // initialize edge vector
89  igraph_vector_int_t edges;
90  auto err = igraph_vector_int_init(&edges, 2 * edge_counter);
91  if (err != IGRAPH_SUCCESS)
92  {
93  return ERR(igraph_strerror(err));
94  }
95 
96  // we need dummy gates for input/outputs
97  u32 node_counter = 0;
98  u32 edge_index = 0;
99 
100  for (auto* g : graph->m_nl->get_gates())
101  {
102  const u32 node = node_counter++;
103  graph->m_gates_to_nodes[g] = node;
104  graph->m_nodes_to_gates[node] = g;
105  }
106 
107  for (const auto* net : graph->m_nl->get_nets(filter))
108  {
109  std::vector<Gate*> src_gates;
110  for (const auto* src_ep : net->get_sources())
111  {
112  src_gates.push_back(src_ep->get_gate());
113  }
114 
115  std::vector<Gate*> dst_gates;
116  for (const auto* dst_ep : net->get_destinations())
117  {
118  dst_gates.push_back(dst_ep->get_gate());
119  }
120 
121  if (src_gates.empty() && create_dummy_vertices)
122  {
123  // if no sources, add one dummy node
124  const u32 dummy_node = node_counter++;
125  graph->m_nodes_to_gates[dummy_node] = nullptr;
126  for (auto* dst_gate : dst_gates)
127  {
128  VECTOR(edges)[edge_index++] = dummy_node;
129  VECTOR(edges)[edge_index++] = graph->m_gates_to_nodes.at(dst_gate);
130  }
131  }
132  else if (dst_gates.empty() && create_dummy_vertices)
133  {
134  // if no destinations, add one dummy node
135  const u32 dummy_node = node_counter++;
136  graph->m_nodes_to_gates[dummy_node] = nullptr;
137  for (auto* src_gate : src_gates)
138  {
139  VECTOR(edges)[edge_index++] = dummy_node;
140  VECTOR(edges)[edge_index++] = graph->m_gates_to_nodes.at(src_gate);
141  }
142  }
143  else
144  {
145  for (auto* dst_gate : dst_gates)
146  {
147  for (auto* src_gate : src_gates)
148  {
149  VECTOR(edges)[edge_index++] = graph->m_gates_to_nodes.at(src_gate);
150  VECTOR(edges)[edge_index++] = graph->m_gates_to_nodes.at(dst_gate);
151  }
152  }
153  }
154  }
155 
156  graph->m_graph_ptr = &(graph->m_graph);
157  err = igraph_create(graph->m_graph_ptr, &edges, node_counter, IGRAPH_DIRECTED);
158 
159  igraph_vector_int_destroy(&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 
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  const auto& graph_gates = gates.empty() ? graph->m_nl->get_gates() : gates;
181 
182  u32 node_counter = 0;
183  for (auto* g : graph_gates)
184  {
185  const u32 node = node_counter++;
186  graph->m_gates_to_nodes[g] = node;
187  graph->m_nodes_to_gates[node] = g;
188  }
189 
190  graph->m_graph_ptr = &(graph->m_graph);
191  auto err = igraph_empty(graph->m_graph_ptr, node_counter, IGRAPH_DIRECTED);
192  if (err != IGRAPH_SUCCESS)
193  {
194  return ERR(igraph_strerror(err));
195  }
196 
197  graph->m_graph_initialized = true;
198 
199  return OK(std::move(graph));
200  }
201 
203  {
204  auto graph = std::unique_ptr<NetlistGraph>(new NetlistGraph(m_nl));
205 
206  if (const auto res = igraph_copy(&(graph->m_graph), &(this->m_graph)); res != IGRAPH_SUCCESS)
207  {
208  return ERR(igraph_strerror(res));
209  }
210 
211  graph->m_graph_initialized = true;
212  graph->m_graph_ptr = &(graph->m_graph);
213  graph->m_gates_to_nodes = this->m_gates_to_nodes;
214  graph->m_nodes_to_gates = this->m_nodes_to_gates;
215 
216  return OK(std::move(graph));
217  }
218 
220  {
221  return m_nl;
222  }
223 
224  igraph_t* NetlistGraph::get_graph() const
225  {
226  return m_graph_ptr;
227  }
228 
229  Result<std::vector<Gate*>> NetlistGraph::get_gates_from_vertices(const std::vector<u32>& vertices) const
230  {
231  std::vector<Gate*> res;
232  for (const auto& vertex : vertices)
233  {
234  if (const auto it = m_nodes_to_gates.find(vertex); it != m_nodes_to_gates.end())
235  {
236  Gate* g = it->second;
237 
238  res.push_back(g);
239  if (!g)
240  {
241  log_warning("graph_algorithm", "no gate exists for dummy vertex {}, added nullptr", vertex);
242  }
243  }
244  else
245  {
246  return ERR("no gate for vertex " + std::to_string(vertex) + " exists in netlist with ID " + std::to_string(m_nl->get_id()));
247  }
248  }
249  return OK(res);
250  }
251 
253  {
254  std::vector<Gate*> res;
255  for (const auto& vertex : vertices)
256  {
257  if (const auto it = m_nodes_to_gates.find(vertex); it != m_nodes_to_gates.end())
258  {
259  Gate* g = it->second;
260 
261  res.push_back(g);
262  if (!g)
263  {
264  log_warning("graph_algorithm", "no gate exists for dummy vertex {}, added nullptr", vertex);
265  }
266  }
267  else
268  {
269  return ERR("no gate for vertex " + std::to_string(vertex) + " exists in netlist with ID " + std::to_string(m_nl->get_id()));
270  }
271  }
272  return OK(res);
273  }
274 
276  {
277  std::vector<Gate*> res;
278  const u32 num_vertices = igraph_vector_int_size(vertices);
279  for (u32 i = 0; i < num_vertices; i++)
280  {
281  u32 vertex = VECTOR(*vertices)[i];
282  if (const auto it = m_nodes_to_gates.find(vertex); it != m_nodes_to_gates.end())
283  {
284  Gate* g = it->second;
285 
286  res.push_back(g);
287  if (!g)
288  {
289  log_warning("graph_algorithm", "no gate exists for dummy vertex {}, added nullptr", vertex);
290  }
291  }
292  else
293  {
294  return ERR("no gate for vertex " + std::to_string(vertex) + " exists in netlist with ID " + std::to_string(m_nl->get_id()));
295  }
296  }
297  return OK(res);
298  }
299 
300  Result<std::set<Gate*>> NetlistGraph::get_gates_set_from_vertices(const std::vector<u32>& vertices) const
301  {
302  std::set<Gate*> res;
303  for (const auto& vertex : vertices)
304  {
305  if (const auto it = m_nodes_to_gates.find(vertex); it != m_nodes_to_gates.end())
306  {
307  Gate* g = it->second;
308 
309  if (!g)
310  {
311  log_warning("graph_algorithm", "no gate exists for dummy vertex {}, skipping vertex", vertex);
312  continue;
313  }
314  res.insert(g);
315  }
316  else
317  {
318  return ERR("no gate for vertex " + std::to_string(vertex) + " exists in netlist with ID " + std::to_string(m_nl->get_id()));
319  }
320  }
321  return OK(res);
322  }
323 
325  {
326  std::set<Gate*> res;
327  for (const auto& vertex : vertices)
328  {
329  if (const auto it = m_nodes_to_gates.find(vertex); it != m_nodes_to_gates.end())
330  {
331  Gate* g = it->second;
332 
333  if (!g)
334  {
335  log_warning("graph_algorithm", "no gate exists for dummy vertex {}, skipping vertex", vertex);
336  continue;
337  }
338  res.insert(g);
339  }
340  else
341  {
342  return ERR("no gate for vertex " + std::to_string(vertex) + " exists in netlist with ID " + std::to_string(m_nl->get_id()));
343  }
344  }
345  return OK(res);
346  }
347 
349  {
350  std::set<Gate*> res;
351  const u32 num_vertices = igraph_vector_int_size(vertices);
352  for (u32 i = 0; i < num_vertices; i++)
353  {
354  u32 vertex = VECTOR(*vertices)[i];
355  if (const auto it = m_nodes_to_gates.find(vertex); it != m_nodes_to_gates.end())
356  {
357  Gate* g = it->second;
358 
359  if (!g)
360  {
361  log_warning("graph_algorithm", "no gate exists for dummy vertex {}, skipping vertex", vertex);
362  continue;
363  }
364  res.insert(g);
365  }
366  else
367  {
368  return ERR("no gate for vertex " + std::to_string(vertex) + " exists in netlist with ID " + std::to_string(m_nl->get_id()));
369  }
370  }
371  return OK(res);
372  }
373 
375  {
376  const auto res = get_gates_from_vertices(std::vector<u32>({vertex}));
377  if (res.is_error())
378  {
379  return ERR(res.get_error());
380  }
381 
382  return OK(res.get().front());
383  }
384 
385  Result<std::vector<u32>> NetlistGraph::get_vertices_from_gates(const std::vector<Gate*>& gates) const
386  {
387  std::vector<u32> res;
388  for (u32 i = 0; i < gates.size(); i++)
389  {
390  auto* g = gates.at(i);
391 
392  if (!g)
393  {
394  return ERR("gate at index " + std::to_string(i) + " is a nullptr");
395  }
396 
397  if (const auto it = m_gates_to_nodes.find(g); it != m_gates_to_nodes.end())
398  {
399  res.push_back(it->second);
400  }
401  else
402  {
403  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()));
404  }
405  }
406  return OK(res);
407  }
408 
410  {
411  std::vector<u32> res;
412  for (auto* g : gates)
413  {
414  if (!g)
415  {
416  return ERR("set of gates contains a nullptr");
417  }
418 
419  if (const auto it = m_gates_to_nodes.find(g); it != m_gates_to_nodes.end())
420  {
421  res.push_back(it->second);
422  }
423  else
424  {
425  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()));
426  }
427  }
428  return OK(res);
429  }
430 
432  {
433  igraph_vector_int_t out;
434  if (auto res = igraph_vector_int_init(&out, gates.size()); res != IGRAPH_SUCCESS)
435  {
436  return ERR(igraph_strerror(res));
437  }
438 
439  for (u32 i = 0; i < gates.size(); i++)
440  {
441  auto* g = gates.at(i);
442 
443  if (!g)
444  {
445  return ERR("gate at index " + std::to_string(i) + " is a nullptr");
446  }
447 
448  if (const auto it = m_gates_to_nodes.find(g); it != m_gates_to_nodes.end())
449  {
450  VECTOR(out)[i] = it->second;
451  }
452  else
453  {
454  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()));
455  }
456  }
457  return OK(std::move(out));
458  }
459 
461  {
462  igraph_vector_int_t out;
463  if (auto res = igraph_vector_int_init(&out, gates.size()); res != IGRAPH_SUCCESS)
464  {
465  return ERR(igraph_strerror(res));
466  }
467 
468  u32 i = 0;
469  for (auto gates_it = gates.begin(); gates_it != gates.end(); gates_it++)
470  {
471  auto* g = *gates_it;
472 
473  if (!g)
474  {
475  return ERR("gate at index " + std::to_string(i) + " is a nullptr");
476  }
477 
478  if (const auto nodes_it = m_gates_to_nodes.find(g); nodes_it != m_gates_to_nodes.end())
479  {
480  VECTOR(out)[i] = nodes_it->second;
481  }
482  else
483  {
484  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()));
485  }
486 
487  i++;
488  }
489  return OK(std::move(out));
490  }
491 
493  {
494  const auto res = get_vertices_from_gates(std::vector<Gate*>({g}));
495  if (res.is_error())
496  {
497  return ERR(res.get_error());
498  }
499 
500  return OK(res.get().front());
501  }
502 
503  u32 NetlistGraph::get_num_vertices(bool only_connected) const
504  {
505  u32 num_vertices = igraph_vcount(&m_graph);
506 
507  if (!only_connected)
508  {
509  return num_vertices;
510  }
511  else
512  {
513  u32 num_connected_vertices = 0;
514 
515  igraph_vector_int_t degrees;
516  igraph_vector_int_init(&degrees, num_vertices);
517 
518  igraph_vs_t v_sel = igraph_vss_all();
519  igraph_degree(&m_graph, &degrees, v_sel, IGRAPH_ALL, IGRAPH_LOOPS);
520 
521  for (u32 i = 0; i < num_vertices; i++)
522  {
523  if (VECTOR(degrees)[i] != 0)
524  {
525  num_connected_vertices++;
526  }
527  }
528 
529  igraph_vector_int_destroy(&degrees);
530  igraph_vs_destroy(&v_sel);
531 
532  return num_connected_vertices;
533  }
534  }
535 
537  {
538  return igraph_ecount(&m_graph);
539  }
540 
542  {
543  u32 num_vertices = igraph_vcount(&m_graph);
544 
545  if (!only_connected)
546  {
547  std::vector<u32> vertices(num_vertices);
548  for (u32 i = 0; i < num_vertices; i++)
549  {
550  vertices[i] = i;
551  }
552  return OK(vertices);
553  }
554  else
555  {
556  std::vector<u32> vertices;
557 
558  igraph_vector_int_t degrees;
559  if (auto res = igraph_vector_int_init(&degrees, num_vertices); res != IGRAPH_SUCCESS)
560  {
561  return ERR(igraph_strerror(res));
562  }
563 
564  igraph_vs_t v_sel = igraph_vss_all();
565  if (auto res = igraph_degree(&m_graph, &degrees, v_sel, IGRAPH_ALL, IGRAPH_LOOPS); res != IGRAPH_SUCCESS)
566  {
567  igraph_vs_destroy(&v_sel);
568  igraph_vector_int_destroy(&degrees);
569  return ERR(igraph_strerror(res));
570  }
571 
572  for (u32 i = 0; i < num_vertices; i++)
573  {
574  if (VECTOR(degrees)[i] != 0)
575  {
576  vertices.push_back(i);
577  }
578  }
579 
580  igraph_vector_int_destroy(&degrees);
581  igraph_vs_destroy(&v_sel);
582 
583  return OK(vertices);
584  }
585  }
586 
588  {
589  const u32 ecount = igraph_ecount(&m_graph);
590 
591  igraph_vector_int_t edges;
592  if (auto res = igraph_vector_int_init(&edges, 2 * ecount); res != IGRAPH_SUCCESS)
593  {
594  return ERR(igraph_strerror(res));
595  }
596 
597  if (auto res = igraph_get_edgelist(&m_graph, &edges, false); res != IGRAPH_SUCCESS)
598  {
599  igraph_vector_int_destroy(&edges);
600  return ERR(igraph_strerror(res));
601  }
602 
603  std::vector<std::pair<u32, u32>> e_vec(ecount);
604  for (u32 i = 0; i < ecount; i++)
605  {
606  const u32 src_vertex = (u32)VECTOR(edges)[2 * i];
607  const u32 dst_vertex = (u32)VECTOR(edges)[2 * i + 1];
608 
609  e_vec[i] = std::make_pair(src_vertex, dst_vertex);
610  }
611 
612  return OK(e_vec);
613  }
614 
616  {
617  const u32 ecount = igraph_ecount(&m_graph);
618 
619  igraph_vector_int_t edges;
620  if (auto res = igraph_vector_int_init(&edges, 2 * ecount); res != IGRAPH_SUCCESS)
621  {
622  return ERR(igraph_strerror(res));
623  }
624 
625  if (auto res = igraph_get_edgelist(&m_graph, &edges, false); res != IGRAPH_SUCCESS)
626  {
627  igraph_vector_int_destroy(&edges);
628  return ERR(igraph_strerror(res));
629  }
630 
631  std::vector<std::pair<Gate*, Gate*>> e_vec(ecount);
632  for (u32 i = 0; i < ecount; i++)
633  {
634  const u32 src_vertex = (u32)VECTOR(edges)[2 * i];
635  const u32 dst_vertex = (u32)VECTOR(edges)[2 * i + 1];
636  Gate *src_gate, *dst_gate;
637 
638  if (const auto it = m_nodes_to_gates.find(src_vertex); it != m_nodes_to_gates.end())
639  {
640  src_gate = it->second;
641  if (src_gate == nullptr)
642  {
643  log_warning("graph_algorithm",
644  "ignored edge (" + std::to_string(src_vertex) + "," + std::to_string(dst_vertex) + ") at dummy source vertex '" + std::to_string(src_vertex) + "'");
645  continue;
646  }
647  }
648 
649  if (const auto it = m_nodes_to_gates.find(dst_vertex); it != m_nodes_to_gates.end())
650  {
651  dst_gate = it->second;
652  if (dst_gate == nullptr)
653  {
654  log_warning("graph_algorithm",
655  "ignored edge (" + std::to_string(src_vertex) + "," + std::to_string(dst_vertex) + ") at dummy destination vertex '" + std::to_string(dst_vertex) + "'");
656  continue;
657  }
658  }
659 
660  e_vec[i] = std::make_pair(src_gate, dst_gate);
661  }
662 
663  return OK(e_vec);
664  }
665 
666  Result<std::monostate> NetlistGraph::add_edges(const std::vector<std::pair<Gate*, Gate*>>& edges)
667  {
668  igraph_vector_int_t e_vec;
669  if (auto res = igraph_vector_int_init(&e_vec, 2 * edges.size()); res != IGRAPH_SUCCESS)
670  {
671  return ERR(igraph_strerror(res));
672  }
673 
674  u32 edge_index = 0;
675  for (const auto& [src_gate, dst_gate] : edges)
676  {
677  if (auto it = m_gates_to_nodes.find(src_gate); it != m_gates_to_nodes.end())
678  {
679  VECTOR(e_vec)[edge_index++] = it->second;
680  }
681  else
682  {
683  igraph_vector_int_destroy(&e_vec);
684  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 "
685  + std::to_string(m_nl->get_id()));
686  }
687 
688  if (auto it = m_gates_to_nodes.find(dst_gate); it != m_gates_to_nodes.end())
689  {
690  VECTOR(e_vec)[edge_index++] = it->second;
691  }
692  else
693  {
694  igraph_vector_int_destroy(&e_vec);
695  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 "
696  + std::to_string(m_nl->get_id()));
697  }
698  }
699 
700  if (auto res = igraph_add_edges(&m_graph, &e_vec, nullptr); res != IGRAPH_SUCCESS)
701  {
702  igraph_vector_int_destroy(&e_vec);
703  return ERR(igraph_strerror(res));
704  }
705 
706  return OK({});
707  }
708 
709  Result<std::monostate> NetlistGraph::add_edges(const std::vector<std::pair<u32, u32>>& edges)
710  {
711  igraph_vector_int_t e_vec;
712  if (auto err = igraph_vector_int_init(&e_vec, 2 * edges.size()); err != IGRAPH_SUCCESS)
713  {
714  return ERR(igraph_strerror(err));
715  }
716 
717  u32 vcount = igraph_vcount(&m_graph);
718 
719  u32 edge_index = 0;
720  for (const auto& [src_vertex, dst_vertex] : edges)
721  {
722  if (src_vertex >= vcount)
723  {
724  igraph_vector_int_destroy(&e_vec);
725  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()));
726  }
727  if (dst_vertex >= vcount)
728  {
729  igraph_vector_int_destroy(&e_vec);
730  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()));
731  }
732 
733  VECTOR(e_vec)[edge_index++] = src_vertex;
734  VECTOR(e_vec)[edge_index++] = dst_vertex;
735  }
736 
737  if (auto err = igraph_add_edges(&m_graph, &e_vec, nullptr); err != IGRAPH_SUCCESS)
738  {
739  igraph_vector_int_destroy(&e_vec);
740  return ERR(igraph_strerror(err));
741  }
742 
743  return OK({});
744  }
745 
746  Result<std::monostate> NetlistGraph::add_edges(const std::map<Gate*, std::set<Gate*>>& edges)
747  {
748  u32 edge_count = 0;
749  for (const auto& [_, dst_gates] : edges)
750  {
751  edge_count += dst_gates.size();
752  }
753 
754  igraph_vector_int_t e_vec;
755  if (auto err = igraph_vector_int_init(&e_vec, 2 * edge_count); err != IGRAPH_SUCCESS)
756  {
757  return ERR(igraph_strerror(err));
758  }
759 
760  u32 edge_index = 0;
761  for (const auto& [src_gate, dst_gates] : edges)
762  {
763  u32 src_vertex;
764  if (auto it = m_gates_to_nodes.find(src_gate); it != m_gates_to_nodes.end())
765  {
766  src_vertex = it->second;
767  }
768  else
769  {
770  igraph_vector_int_destroy(&e_vec);
771  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 "
772  + std::to_string(m_nl->get_id()));
773  }
774 
775  for (auto* dst_gate : dst_gates)
776  {
777  if (auto it = m_gates_to_nodes.find(dst_gate); it != m_gates_to_nodes.end())
778  {
779  VECTOR(e_vec)[edge_index++] = src_vertex;
780  VECTOR(e_vec)[edge_index++] = it->second;
781  }
782  else
783  {
784  igraph_vector_int_destroy(&e_vec);
785  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 "
786  + std::to_string(m_nl->get_id()));
787  }
788  }
789  }
790 
791  if (auto err = igraph_add_edges(&m_graph, &e_vec, nullptr); err != IGRAPH_SUCCESS)
792  {
793  igraph_vector_int_destroy(&e_vec);
794  return ERR(igraph_strerror(err));
795  }
796 
797  return OK({});
798  }
799 
800  Result<std::monostate> NetlistGraph::delete_edges(const std::vector<std::pair<Gate*, Gate*>>& edges)
801  {
802  igraph_vector_int_t e_vec;
803  if (auto err = igraph_vector_int_init(&e_vec, 2 * edges.size()); err != IGRAPH_SUCCESS)
804  {
805  return ERR(igraph_strerror(err));
806  }
807 
808  u32 vcount = igraph_vcount(&m_graph);
809 
810  u32 edge_index = 0;
811  for (const auto& [src_gate, dst_gate] : edges)
812  {
813  if (auto it = m_gates_to_nodes.find(src_gate); it != m_gates_to_nodes.end())
814  {
815  VECTOR(e_vec)[edge_index++] = it->second;
816  }
817  else
818  {
819  igraph_vector_int_destroy(&e_vec);
820  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 "
821  + std::to_string(m_nl->get_id()));
822  }
823 
824  if (auto it = m_gates_to_nodes.find(dst_gate); it != m_gates_to_nodes.end())
825  {
826  VECTOR(e_vec)[edge_index++] = it->second;
827  }
828  else
829  {
830  igraph_vector_int_destroy(&e_vec);
831  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 "
832  + std::to_string(m_nl->get_id()));
833  }
834  }
835 
836  igraph_es_t e_sel;
837  if (auto res = igraph_es_pairs(&e_sel, &e_vec, IGRAPH_DIRECTED); res != IGRAPH_SUCCESS)
838  {
839  igraph_vector_int_destroy(&e_vec);
840  return ERR(igraph_strerror(res));
841  }
842 
843  if (auto res = igraph_delete_edges(&m_graph, e_sel); res != IGRAPH_SUCCESS)
844  {
845  igraph_es_destroy(&e_sel);
846  igraph_vector_int_destroy(&e_vec);
847  return ERR(igraph_strerror(res));
848  }
849 
850  igraph_es_destroy(&e_sel);
851  igraph_vector_int_destroy(&e_vec);
852 
853  return OK({});
854  }
855 
856  Result<std::monostate> NetlistGraph::delete_edges(const std::vector<std::pair<u32, u32>>& edges)
857  {
858  igraph_vector_int_t e_vec;
859  if (auto err = igraph_vector_int_init(&e_vec, 2 * edges.size()); err != IGRAPH_SUCCESS)
860  {
861  return ERR(igraph_strerror(err));
862  }
863 
864  u32 vcount = igraph_vcount(&m_graph);
865 
866  u32 edge_index = 0;
867  for (const auto& [src_vertex, dst_vertex] : edges)
868  {
869  if (src_vertex >= vcount)
870  {
871  igraph_vector_int_destroy(&e_vec);
872  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()));
873  }
874  if (dst_vertex >= vcount)
875  {
876  igraph_vector_int_destroy(&e_vec);
877  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()));
878  }
879 
880  VECTOR(e_vec)[edge_index++] = src_vertex;
881  VECTOR(e_vec)[edge_index++] = dst_vertex;
882  }
883 
884  igraph_es_t e_sel;
885  if (auto res = igraph_es_pairs(&e_sel, &e_vec, IGRAPH_DIRECTED); res != IGRAPH_SUCCESS)
886  {
887  igraph_vector_int_destroy(&e_vec);
888  return ERR(igraph_strerror(res));
889  }
890 
891  if (auto res = igraph_delete_edges(&m_graph, e_sel); res != IGRAPH_SUCCESS)
892  {
893  igraph_es_destroy(&e_sel);
894  igraph_vector_int_destroy(&e_vec);
895  return ERR(igraph_strerror(res));
896  }
897 
898  igraph_es_destroy(&e_sel);
899  igraph_vector_int_destroy(&e_vec);
900 
901  return OK({});
902  }
903 
904  void NetlistGraph::print() const
905  {
906  igraph_write_graph_edgelist(&m_graph, stdout);
907  }
908  } // namespace graph_algorithm
909 
910  template<>
911  std::map<graph_algorithm::NetlistGraph::Direction, std::string> EnumStrings<graph_algorithm::NetlistGraph::Direction>::data = {{graph_algorithm::NetlistGraph::Direction::NONE, "NONE"},
915 } // namespace hal
Definition: gate.h:58
Definition: net.h:58
u32 get_id() const
Definition: netlist.cpp:75
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.
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.
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.
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.