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