yosys-master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
subcircuit.cc
Go to the documentation of this file.
1 /*
2  * SubCircuit -- An implementation of the Ullmann Subgraph Isomorphism
3  * algorithm for coarse grain logic networks
4  *
5  * Copyright (C) 2013 Clifford Wolf <clifford@clifford.at>
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  *
19  */
20 
21 #include "subcircuit.h"
22 
23 #include <algorithm>
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 
28 #ifdef _YOSYS_
29 # include "kernel/yosys.h"
30 # define my_printf YOSYS_NAMESPACE_PREFIX log
31 #else
32 # define my_printf printf
33 #endif
34 
35 using namespace SubCircuit;
36 
37 #ifndef _YOSYS_
38 static std::string my_stringf(const char *fmt, ...)
39 {
40  std::string string;
41  char *str = NULL;
42  va_list ap;
43 
44  va_start(ap, fmt);
45  if (vasprintf(&str, fmt, ap) < 0)
46  str = NULL;
47  va_end(ap);
48 
49  if (str != NULL) {
50  string = str;
51  free(str);
52  }
53 
54  return string;
55 }
56 #else
57 # define my_stringf YOSYS_NAMESPACE_PREFIX stringf
58 #endif
59 
60 SubCircuit::Graph::Graph(const Graph &other, const std::vector<std::string> &otherNodes)
61 {
62  allExtern = other.allExtern;
63 
64  std::map<int, int> other2this;
65  for (int i = 0; i < int(otherNodes.size()); i++) {
66  assert(other.nodeMap.count(otherNodes[i]) > 0);
67  other2this[other.nodeMap.at(otherNodes[i])] = i;
68  nodeMap[otherNodes[i]] = i;
69  }
70 
71  std::map<int, int> edges2this;
72  for (auto &i1 : other2this)
73  for (auto &i2 : other.nodes[i1.first].ports)
74  for (auto &i3 : i2.bits)
75  if (edges2this.count(i3.edgeIdx) == 0) {
76  int next_idx = edges2this.size();
77  edges2this[i3.edgeIdx] = next_idx;
78  }
79 
80  edges.resize(edges2this.size());
81  for (auto &it : edges2this) {
82  for (auto &bit : other.edges[it.first].portBits)
83  if (other2this.count(bit.nodeIdx) > 0)
84  edges[it.second].portBits.insert(BitRef(other2this[bit.nodeIdx], bit.portIdx, bit.bitIdx));
85  edges[it.second].constValue = other.edges[it.first].constValue;
86  edges[it.second].isExtern = other.edges[it.first].isExtern;
87  }
88 
89  nodes.resize(other2this.size());
90  for (auto &it : other2this) {
91  nodes[it.second] = other.nodes[it.first];
92  for (auto &i2 : nodes[it.second].ports)
93  for (auto &i3 : i2.bits)
94  i3.edgeIdx = edges2this.at(i3.edgeIdx);
95  }
96 }
97 
99 {
100  if (nodeIdx != other.nodeIdx)
101  return nodeIdx < other.nodeIdx;
102  if (portIdx != other.portIdx)
103  return portIdx < other.portIdx;
104  return bitIdx < other.bitIdx;
105 }
106 
107 void SubCircuit::Graph::createNode(std::string nodeId, std::string typeId, void *userData, bool shared)
108 {
109  assert(nodeMap.count(nodeId) == 0);
110  nodeMap[nodeId] = nodes.size();
111  nodes.push_back(Node());
112 
113  Node &newNode = nodes.back();
114  newNode.nodeId = nodeId;
115  newNode.typeId = typeId;
116  newNode.userData = userData;
117  newNode.shared = shared;
118 }
119 
120 void SubCircuit::Graph::createPort(std::string nodeId, std::string portId, int width, int minWidth)
121 {
122  assert(nodeMap.count(nodeId) != 0);
123  int nodeIdx = nodeMap[nodeId];
124  Node &node = nodes[nodeIdx];
125 
126  assert(node.portMap.count(portId) == 0);
127 
128  int portIdx = node.ports.size();
129  node.portMap[portId] = portIdx;
130  node.ports.push_back(Port());
131  Port &port = node.ports.back();
132 
133  port.portId = portId;
134  port.minWidth = minWidth < 0 ? width : minWidth;
135  port.bits.insert(port.bits.end(), width, PortBit());
136 
137  for (int i = 0; i < width; i++) {
138  port.bits[i].edgeIdx = edges.size();
139  edges.push_back(Edge());
140  edges.back().portBits.insert(BitRef(nodeIdx, portIdx, i));
141  }
142 }
143 
144 void SubCircuit::Graph::createConnection(std::string fromNodeId, std::string fromPortId, int fromBit, std::string toNodeId, std::string toPortId, int toBit, int width)
145 {
146  assert(nodeMap.count(fromNodeId) != 0);
147  assert(nodeMap.count(toNodeId) != 0);
148 
149  int fromNodeIdx = nodeMap[fromNodeId];
150  Node &fromNode = nodes[fromNodeIdx];
151 
152  int toNodeIdx = nodeMap[toNodeId];
153  Node &toNode = nodes[toNodeIdx];
154 
155  assert(fromNode.portMap.count(fromPortId) != 0);
156  assert(toNode.portMap.count(toPortId) != 0);
157 
158  int fromPortIdx = fromNode.portMap[fromPortId];
159  Port &fromPort = fromNode.ports[fromPortIdx];
160 
161  int toPortIdx = toNode.portMap[toPortId];
162  Port &toPort = toNode.ports[toPortIdx];
163 
164  if (width < 0) {
165  assert(fromBit == 0 && toBit == 0);
166  assert(fromPort.bits.size() == toPort.bits.size());
167  width = fromPort.bits.size();
168  }
169 
170  assert(fromBit >= 0 && toBit >= 0);
171  for (int i = 0; i < width; i++)
172  {
173  assert(fromBit + i < int(fromPort.bits.size()));
174  assert(toBit + i < int(toPort.bits.size()));
175 
176  int fromEdgeIdx = fromPort.bits[fromBit + i].edgeIdx;
177  int toEdgeIdx = toPort.bits[toBit + i].edgeIdx;
178 
179  if (fromEdgeIdx == toEdgeIdx)
180  continue;
181 
182  // merge toEdge into fromEdge
183  if (edges[toEdgeIdx].isExtern)
184  edges[fromEdgeIdx].isExtern = true;
185  if (edges[toEdgeIdx].constValue) {
186  assert(edges[fromEdgeIdx].constValue == 0);
187  edges[fromEdgeIdx].constValue = edges[toEdgeIdx].constValue;
188  }
189  for (const auto &ref : edges[toEdgeIdx].portBits) {
190  edges[fromEdgeIdx].portBits.insert(ref);
191  nodes[ref.nodeIdx].ports[ref.portIdx].bits[ref.bitIdx].edgeIdx = fromEdgeIdx;
192  }
193 
194  // remove toEdge (move last edge over toEdge if needed)
195  if (toEdgeIdx+1 != int(edges.size())) {
196  edges[toEdgeIdx] = edges.back();
197  for (const auto &ref : edges[toEdgeIdx].portBits)
198  nodes[ref.nodeIdx].ports[ref.portIdx].bits[ref.bitIdx].edgeIdx = toEdgeIdx;
199  }
200  edges.pop_back();
201  }
202 }
203 
204 void SubCircuit::Graph::createConnection(std::string fromNodeId, std::string fromPortId, std::string toNodeId, std::string toPortId)
205 {
206  createConnection(fromNodeId, fromPortId, 0, toNodeId, toPortId, 0, -1);
207 }
208 
209 void SubCircuit::Graph::createConstant(std::string toNodeId, std::string toPortId, int toBit, int constValue)
210 {
211  assert(nodeMap.count(toNodeId) != 0);
212  int toNodeIdx = nodeMap[toNodeId];
213  Node &toNode = nodes[toNodeIdx];
214 
215  assert(toNode.portMap.count(toPortId) != 0);
216  int toPortIdx = toNode.portMap[toPortId];
217  Port &toPort = toNode.ports[toPortIdx];
218 
219  assert(toBit >= 0 && toBit < int(toPort.bits.size()));
220  int toEdgeIdx = toPort.bits[toBit].edgeIdx;
221 
222  assert(edges[toEdgeIdx].constValue == 0);
223  edges[toEdgeIdx].constValue = constValue;
224 }
225 
226 void SubCircuit::Graph::createConstant(std::string toNodeId, std::string toPortId, int constValue)
227 {
228  assert(nodeMap.count(toNodeId) != 0);
229  int toNodeIdx = nodeMap[toNodeId];
230  Node &toNode = nodes[toNodeIdx];
231 
232  assert(toNode.portMap.count(toPortId) != 0);
233  int toPortIdx = toNode.portMap[toPortId];
234  Port &toPort = toNode.ports[toPortIdx];
235 
236  for (int i = 0; i < int(toPort.bits.size()); i++) {
237  int toEdgeIdx = toPort.bits[i].edgeIdx;
238  assert(edges[toEdgeIdx].constValue == 0);
239  edges[toEdgeIdx].constValue = constValue % 2 ? '1' : '0';
240  constValue = constValue >> 1;
241  }
242 }
243 
244 void SubCircuit::Graph::markExtern(std::string nodeId, std::string portId, int bit)
245 {
246  assert(nodeMap.count(nodeId) != 0);
247  Node &node = nodes[nodeMap[nodeId]];
248 
249  assert(node.portMap.count(portId) != 0);
250  Port &port = node.ports[node.portMap[portId]];
251 
252  if (bit < 0) {
253  for (const auto portBit : port.bits)
254  edges[portBit.edgeIdx].isExtern = true;
255  } else {
256  assert(bit < int(port.bits.size()));
257  edges[port.bits[bit].edgeIdx].isExtern = true;
258  }
259 }
260 
262 {
263  allExtern = true;
264 }
265 
267 {
268  for (int i = 0; i < int(nodes.size()); i++) {
269  const Node &node = nodes[i];
270  my_printf("NODE %d: %s (%s)\n", i, node.nodeId.c_str(), node.typeId.c_str());
271  for (int j = 0; j < int(node.ports.size()); j++) {
272  const Port &port = node.ports[j];
273  my_printf(" PORT %d: %s (%d/%d)\n", j, port.portId.c_str(), port.minWidth, int(port.bits.size()));
274  for (int k = 0; k < int(port.bits.size()); k++) {
275  int edgeIdx = port.bits[k].edgeIdx;
276  my_printf(" BIT %d (%d):", k, edgeIdx);
277  for (const auto &ref : edges[edgeIdx].portBits)
278  my_printf(" %d.%d.%d", ref.nodeIdx, ref.portIdx, ref.bitIdx);
279  if (edges[edgeIdx].isExtern)
280  my_printf(" [extern]");
281  my_printf("\n");
282  }
283  }
284  }
285 }
286 
288 {
289  // basic internal data structures
290 
291  typedef std::vector<std::map<int, int>> adjMatrix_t;
292 
293  struct GraphData {
294  std::string graphId;
297  std::vector<bool> usedNodes;
298  };
299 
300  static void printAdjMatrix(const adjMatrix_t &matrix)
301  {
302  my_printf("%7s", "");
303  for (int i = 0; i < int(matrix.size()); i++)
304  my_printf("%4d:", i);
305  my_printf("\n");
306  for (int i = 0; i < int(matrix.size()); i++) {
307  my_printf("%5d:", i);
308  for (int j = 0; j < int(matrix.size()); j++)
309  if (matrix.at(i).count(j) == 0)
310  my_printf("%5s", "-");
311  else
312  my_printf("%5d", matrix.at(i).at(j));
313  my_printf("\n");
314  }
315  }
316 
317  // helper functions for handling permutations
318 
319  static const int maxPermutationsLimit = 1000000;
320 
321  static int numberOfPermutations(const std::vector<std::string> &list)
322  {
323  int numPermutations = 1;
324  for (int i = 0; i < int(list.size()); i++) {
325  assert(numPermutations < maxPermutationsLimit);
326  numPermutations *= i+1;
327  }
328  return numPermutations;
329  }
330 
331  static void permutateVectorToMap(std::map<std::string, std::string> &map, const std::vector<std::string> &list, int idx)
332  {
333  // convert idx to a list.size() digits factoradic number
334 
335  std::vector<int> factoradicDigits;
336  for (int i = 0; i < int(list.size()); i++) {
337  factoradicDigits.push_back(idx % (i+1));
338  idx = idx / (i+1);
339  }
340 
341  // construct permutation
342 
343  std::vector<std::string> pool = list;
344  std::vector<std::string> permutation;
345 
346  while (!factoradicDigits.empty()) {
347  int i = factoradicDigits.back();
348  factoradicDigits.pop_back();
349  permutation.push_back(pool[i]);
350  pool.erase(pool.begin() + i);
351  }
352 
353  // update map
354 
355  for (int i = 0; i < int(list.size()); i++)
356  map[list[i]] = permutation[i];
357  }
358 
359  static int numberOfPermutationsArray(const std::vector<std::vector<std::string>> &list)
360  {
361  int numPermutations = 1;
362  for (const auto &it : list) {
363  int thisPermutations = numberOfPermutations(it);
364  assert(float(numPermutations) * float(thisPermutations) < maxPermutationsLimit);
365  numPermutations *= thisPermutations;
366  }
367  return numPermutations;
368  }
369 
370  static void permutateVectorToMapArray(std::map<std::string, std::string> &map, const std::vector<std::vector<std::string>> &list, int idx)
371  {
372  for (const auto &it : list) {
373  int thisPermutations = numberOfPermutations(it);
374  int thisIdx = idx % thisPermutations;
375  permutateVectorToMap(map, it, thisIdx);
376  idx /= thisPermutations;
377  }
378  }
379 
380  static void applyPermutation(std::map<std::string, std::string> &map, const std::map<std::string, std::string> &permutation)
381  {
382  std::vector<std::pair<std::string, std::string>> changeLog;
383  for (const auto &it : permutation)
384  if (map.count(it.second))
385  changeLog.push_back(std::pair<std::string, std::string>(it.first, map.at(it.second)));
386  else
387  changeLog.push_back(std::pair<std::string, std::string>(it.first, it.second));
388  for (const auto &it : changeLog)
389  map[it.first] = it.second;
390  }
391 
392  // classes for internal digraph representation
393 
394  struct DiBit
395  {
396  std::string fromPort, toPort;
398 
399  DiBit() : fromPort(), toPort(), fromBit(-1), toBit(-1) { }
400  DiBit(std::string fromPort, int fromBit, std::string toPort, int toBit) : fromPort(fromPort), toPort(toPort), fromBit(fromBit), toBit(toBit) { }
401 
402  bool operator < (const DiBit &other) const
403  {
404  if (fromPort != other.fromPort)
405  return fromPort < other.fromPort;
406  if (toPort != other.toPort)
407  return toPort < other.toPort;
408  if (fromBit != other.fromBit)
409  return fromBit < other.fromBit;
410  return toBit < other.toBit;
411  }
412 
413  std::string toString() const
414  {
415  return my_stringf("%s[%d]:%s[%d]", fromPort.c_str(), fromBit, toPort.c_str(), toBit);
416  }
417  };
418 
419  struct DiNode
420  {
421  std::string typeId;
422  std::map<std::string, int> portSizes;
423 
425  {
426  }
427 
428  DiNode(const Graph &graph, int nodeIdx)
429  {
430  const Graph::Node &node = graph.nodes.at(nodeIdx);
431  typeId = node.typeId;
432  for (const auto &port : node.ports)
433  portSizes[port.portId] = port.bits.size();
434  }
435 
436  bool operator < (const DiNode &other) const
437  {
438  if (typeId != other.typeId)
439  return typeId < other.typeId;
440  return portSizes < other.portSizes;
441  }
442 
443  std::string toString() const
444  {
445  std::string str;
446  bool firstPort = true;
447  for (const auto &it : portSizes) {
448  str += my_stringf("%s%s[%d]", firstPort ? "" : ",", it.first.c_str(), it.second);
449  firstPort = false;
450  }
451  return typeId + "(" + str + ")";
452  }
453  };
454 
455  struct DiEdge
456  {
458  std::set<DiBit> bits;
459  std::string userAnnotation;
460 
461  bool operator < (const DiEdge &other) const
462  {
463  if (fromNode < other.fromNode || other.fromNode < fromNode)
464  return fromNode < other.fromNode;
465  if (toNode < other.toNode || other.toNode < toNode)
466  return toNode < other.toNode;
467  if (bits < other.bits || other.bits < bits)
468  return bits < other.bits;
469  return userAnnotation < other.userAnnotation;
470  }
471 
472  bool compare(const DiEdge &other, const std::map<std::string, std::string> &mapFromPorts, const std::map<std::string, std::string> &mapToPorts) const
473  {
474  // Rules for matching edges:
475  //
476  // For all bits in the needle edge:
477  // - ignore if needle ports don't exist in haystack edge
478  // - otherwise: matching bit in haystack edge must exist
479  //
480  // There is no need to check in the other direction, as checking
481  // of the isExtern properties is already performed in node matching.
482  //
483  // Note: "this" is needle, "other" is haystack
484 
485  for (auto bit : bits)
486  {
487  if (mapFromPorts.count(bit.fromPort) > 0)
488  bit.fromPort = mapFromPorts.at(bit.fromPort);
489  if (mapToPorts.count(bit.toPort) > 0)
490  bit.toPort = mapToPorts.at(bit.toPort);
491 
492  if (other.fromNode.portSizes.count(bit.fromPort) == 0)
493  continue;
494  if (other.toNode.portSizes.count(bit.toPort) == 0)
495  continue;
496 
497  if (bit.fromBit >= other.fromNode.portSizes.at(bit.fromPort))
498  continue;
499  if (bit.toBit >= other.toNode.portSizes.at(bit.toPort))
500  continue;
501 
502  if (other.bits.count(bit) == 0)
503  return false;
504  }
505 
506  return true;
507  }
508 
509  bool compareWithFromAndToPermutations(const DiEdge &other, const std::map<std::string, std::string> &mapFromPorts, const std::map<std::string, std::string> &mapToPorts,
510  const std::map<std::string, std::set<std::map<std::string, std::string>>> &swapPermutations) const
511  {
512  if (swapPermutations.count(fromNode.typeId) > 0)
513  for (const auto &permutation : swapPermutations.at(fromNode.typeId)) {
514  std::map<std::string, std::string> thisMapFromPorts = mapFromPorts;
515  applyPermutation(thisMapFromPorts, permutation);
516  if (compareWithToPermutations(other, thisMapFromPorts, mapToPorts, swapPermutations))
517  return true;
518  }
519  return compareWithToPermutations(other, mapFromPorts, mapToPorts, swapPermutations);
520  }
521 
522  bool compareWithToPermutations(const DiEdge &other, const std::map<std::string, std::string> &mapFromPorts, const std::map<std::string, std::string> &mapToPorts,
523  const std::map<std::string, std::set<std::map<std::string, std::string>>> &swapPermutations) const
524  {
525  if (swapPermutations.count(toNode.typeId) > 0)
526  for (const auto &permutation : swapPermutations.at(toNode.typeId)) {
527  std::map<std::string, std::string> thisMapToPorts = mapToPorts;
528  applyPermutation(thisMapToPorts, permutation);
529  if (compare(other, mapFromPorts, thisMapToPorts))
530  return true;
531  }
532  return compare(other, mapFromPorts, mapToPorts);
533  }
534 
535  bool compare(const DiEdge &other, const std::map<std::string, std::set<std::set<std::string>>> &swapPorts,
536  const std::map<std::string, std::set<std::map<std::string, std::string>>> &swapPermutations) const
537  {
538  // brute force method for port swapping: try all variations
539 
540  std::vector<std::vector<std::string>> swapFromPorts;
541  std::vector<std::vector<std::string>> swapToPorts;
542 
543  // only use groups that are relevant for this edge
544 
545  if (swapPorts.count(fromNode.typeId) > 0)
546  for (const auto &ports : swapPorts.at(fromNode.typeId)) {
547  for (const auto &bit : bits)
548  if (ports.count(bit.fromPort))
549  goto foundFromPortMatch;
550  if (0) {
551  foundFromPortMatch:
552  std::vector<std::string> portsVector;
553  for (const auto &port : ports)
554  portsVector.push_back(port);
555  swapFromPorts.push_back(portsVector);
556  }
557  }
558 
559  if (swapPorts.count(toNode.typeId) > 0)
560  for (const auto &ports : swapPorts.at(toNode.typeId)) {
561  for (const auto &bit : bits)
562  if (ports.count(bit.toPort))
563  goto foundToPortMatch;
564  if (0) {
565  foundToPortMatch:
566  std::vector<std::string> portsVector;
567  for (const auto &port : ports)
568  portsVector.push_back(port);
569  swapToPorts.push_back(portsVector);
570  }
571  }
572 
573  // try all permutations
574 
575  std::map<std::string, std::string> mapFromPorts, mapToPorts;
576  int fromPortsPermutations = numberOfPermutationsArray(swapFromPorts);
577  int toPortsPermutations = numberOfPermutationsArray(swapToPorts);
578 
579  for (int i = 0; i < fromPortsPermutations; i++)
580  {
581  permutateVectorToMapArray(mapFromPorts, swapFromPorts, i);
582 
583  for (int j = 0; j < toPortsPermutations; j++) {
584  permutateVectorToMapArray(mapToPorts, swapToPorts, j);
585  if (compareWithFromAndToPermutations(other, mapFromPorts, mapToPorts, swapPermutations))
586  return true;
587  }
588  }
589 
590  return false;
591  }
592 
593  bool compare(const DiEdge &other, const std::map<std::string, std::string> &mapFromPorts, const std::map<std::string, std::set<std::set<std::string>>> &swapPorts,
594  const std::map<std::string, std::set<std::map<std::string, std::string>>> &swapPermutations) const
595  {
596  // strip-down version of the last function: only try permutations for mapToPorts, mapFromPorts is already provided by the caller
597 
598  std::vector<std::vector<std::string>> swapToPorts;
599 
600  if (swapPorts.count(toNode.typeId) > 0)
601  for (const auto &ports : swapPorts.at(toNode.typeId)) {
602  for (const auto &bit : bits)
603  if (ports.count(bit.toPort))
604  goto foundToPortMatch;
605  if (0) {
606  foundToPortMatch:
607  std::vector<std::string> portsVector;
608  for (const auto &port : ports)
609  portsVector.push_back(port);
610  swapToPorts.push_back(portsVector);
611  }
612  }
613 
614  std::map<std::string, std::string> mapToPorts;
615  int toPortsPermutations = numberOfPermutationsArray(swapToPorts);
616 
617  for (int j = 0; j < toPortsPermutations; j++) {
618  permutateVectorToMapArray(mapToPorts, swapToPorts, j);
619  if (compareWithToPermutations(other, mapFromPorts, mapToPorts, swapPermutations))
620  return true;
621  }
622 
623  return false;
624  }
625 
626  std::string toString() const
627  {
628  std::string buffer = fromNode.toString() + " " + toNode.toString();
629  for (const auto &bit : bits)
630  buffer += " " + bit.toString();
631  if (!userAnnotation.empty())
632  buffer += " " + userAnnotation;
633  return buffer;
634  }
635 
636  static void findEdgesInGraph(const Graph &graph, std::map<std::pair<int, int>, DiEdge> &edges)
637  {
638  edges.clear();
639  for (const auto &edge : graph.edges) {
640  if (edge.constValue != 0)
641  continue;
642  for (const auto &fromBit : edge.portBits)
643  for (const auto &toBit : edge.portBits)
644  if (&fromBit != &toBit) {
645  DiEdge &de = edges[std::pair<int, int>(fromBit.nodeIdx, toBit.nodeIdx)];
646  de.fromNode = DiNode(graph, fromBit.nodeIdx);
647  de.toNode = DiNode(graph, toBit.nodeIdx);
648  std::string fromPortId = graph.nodes[fromBit.nodeIdx].ports[fromBit.portIdx].portId;
649  std::string toPortId = graph.nodes[toBit.nodeIdx].ports[toBit.portIdx].portId;
650  de.bits.insert(DiBit(fromPortId, fromBit.bitIdx, toPortId, toBit.bitIdx));
651  }
652  }
653  }
654  };
655 
656  struct DiCache
657  {
658  std::map<DiEdge, int> edgeTypesMap;
659  std::vector<DiEdge> edgeTypes;
660  std::map<std::pair<int, int>, bool> compareCache;
661 
662  void add(const Graph &graph, adjMatrix_t &adjMatrix, const std::string &graphId, Solver *userSolver)
663  {
664  std::map<std::pair<int, int>, DiEdge> edges;
665  DiEdge::findEdgesInGraph(graph, edges);
666 
667  adjMatrix.clear();
668  adjMatrix.resize(graph.nodes.size());
669 
670  for (auto &it : edges) {
671  const Graph::Node &fromNode = graph.nodes[it.first.first];
672  const Graph::Node &toNode = graph.nodes[it.first.second];
673  it.second.userAnnotation = userSolver->userAnnotateEdge(graphId, fromNode.nodeId, fromNode.userData, toNode.nodeId, toNode.userData);
674  }
675 
676  for (const auto &it : edges) {
677  if (edgeTypesMap.count(it.second) == 0) {
678  edgeTypesMap[it.second] = edgeTypes.size();
679  edgeTypes.push_back(it.second);
680  }
681  adjMatrix[it.first.first][it.first.second] = edgeTypesMap[it.second];
682  }
683  }
684 
685  bool compare(int needleEdge, int haystackEdge, const std::map<std::string, std::set<std::set<std::string>>> &swapPorts,
686  const std::map<std::string, std::set<std::map<std::string, std::string>>> &swapPermutations)
687  {
688  std::pair<int, int> key(needleEdge, haystackEdge);
689  if (!compareCache.count(key))
690  compareCache[key] = edgeTypes.at(needleEdge).compare(edgeTypes.at(haystackEdge), swapPorts, swapPermutations);
691  return compareCache[key];
692  }
693 
694  bool compare(int needleEdge, int haystackEdge, const std::map<std::string, std::string> &mapFromPorts, const std::map<std::string, std::set<std::set<std::string>>> &swapPorts,
695  const std::map<std::string, std::set<std::map<std::string, std::string>>> &swapPermutations) const
696  {
697  return edgeTypes.at(needleEdge).compare(edgeTypes.at(haystackEdge), mapFromPorts, swapPorts, swapPermutations);
698  }
699 
700  bool compare(int needleEdge, int haystackEdge, const std::map<std::string, std::string> &mapFromPorts, const std::map<std::string, std::string> &mapToPorts) const
701  {
702  return edgeTypes.at(needleEdge).compare(edgeTypes.at(haystackEdge), mapFromPorts, mapToPorts);
703  }
704 
705  void printEdgeTypes() const
706  {
707  for (int i = 0; i < int(edgeTypes.size()); i++)
708  my_printf("%5d: %s\n", i, edgeTypes[i].toString().c_str());
709  }
710  };
711 
712  // solver state variables
713 
715  std::map<std::string, GraphData> graphData;
716  std::map<std::string, std::set<std::string>> compatibleTypes;
717  std::map<int, std::set<int>> compatibleConstants;
718  std::map<std::string, std::set<std::set<std::string>>> swapPorts;
719  std::map<std::string, std::set<std::map<std::string, std::string>>> swapPermutations;
721  bool verbose;
722 
723  // main solver functions
724 
725  bool matchNodePorts(const Graph &needle, int needleNodeIdx, const Graph &haystack, int haystackNodeIdx, const std::map<std::string, std::string> &swaps) const
726  {
727  const Graph::Node &nn = needle.nodes[needleNodeIdx];
728  const Graph::Node &hn = haystack.nodes[haystackNodeIdx];
729  assert(nn.ports.size() == hn.ports.size());
730 
731  for (int i = 0; i < int(nn.ports.size()); i++)
732  {
733  std::string hnPortId = nn.ports[i].portId;
734  if (swaps.count(hnPortId) > 0)
735  hnPortId = swaps.at(hnPortId);
736 
737  if (hn.portMap.count(hnPortId) == 0)
738  return false;
739 
740  const Graph::Port &np = nn.ports[i];
741  const Graph::Port &hp = hn.ports[hn.portMap.at(hnPortId)];
742 
743  if (int(hp.bits.size()) < np.minWidth || hp.bits.size() > np.bits.size())
744  return false;
745 
746  for (int j = 0; j < int(hp.bits.size()); j++)
747  {
748  const Graph::Edge &ne = needle.edges[np.bits[j].edgeIdx];
749  const Graph::Edge &he = haystack.edges[hp.bits[j].edgeIdx];
750 
751  if (ne.constValue || he.constValue) {
752  if (ne.constValue != he.constValue)
753  if (compatibleConstants.count(ne.constValue) == 0 || compatibleConstants.at(ne.constValue).count(he.constValue) == 0)
754  return false;
755  continue;
756  }
757 
758  if (ne.isExtern || needle.allExtern) {
759  if (he.portBits.size() < ne.portBits.size())
760  return false;
761  } else {
762  if (he.portBits.size() != ne.portBits.size())
763  return false;
764  if (he.isExtern || haystack.allExtern)
765  return false;
766  }
767  }
768  }
769 
770  return true;
771  }
772 
773  bool matchNodes(const GraphData &needle, int needleNodeIdx, const GraphData &haystack, int haystackNodeIdx) const
774  {
775  // Rules for matching nodes:
776  //
777  // 1. their typeId must be identical or compatible
778  // (this is checked before calling this function)
779  //
780  // 2. they must have the same ports and the haystack port
781  // widths must match the needle port width range
782  //
783  // 3. All edges from the needle must match the haystack:
784  // a) if the needle edge is extern:
785  // - the haystack edge must have at least as many components as the needle edge
786  // b) if the needle edge is not extern:
787  // - the haystack edge must have the same number of components as the needle edge
788  // - the haystack edge must not be extern
789 
790  const Graph::Node &nn = needle.graph.nodes[needleNodeIdx];
791  const Graph::Node &hn = haystack.graph.nodes[haystackNodeIdx];
792 
793  assert(nn.typeId == hn.typeId || (compatibleTypes.count(nn.typeId) > 0 && compatibleTypes.at(nn.typeId).count(hn.typeId) > 0));
794 
795  if (nn.ports.size() != hn.ports.size())
796  return false;
797 
798  std::map<std::string, std::string> currentCandidate;
799 
800  for (const auto &port : needle.graph.nodes[needleNodeIdx].ports)
801  currentCandidate[port.portId] = port.portId;
802 
803  if (swapPorts.count(needle.graph.nodes[needleNodeIdx].typeId) == 0)
804  {
805  if (matchNodePorts(needle.graph, needleNodeIdx, haystack.graph, haystackNodeIdx, currentCandidate) &&
806  userSolver->userCompareNodes(needle.graphId, nn.nodeId, nn.userData, haystack.graphId, hn.nodeId, hn.userData, currentCandidate))
807  return true;
808 
809  if (swapPermutations.count(needle.graph.nodes[needleNodeIdx].typeId) > 0)
810  for (const auto &permutation : swapPermutations.at(needle.graph.nodes[needleNodeIdx].typeId)) {
811  std::map<std::string, std::string> currentSubCandidate = currentCandidate;
812  applyPermutation(currentSubCandidate, permutation);
813  if (matchNodePorts(needle.graph, needleNodeIdx, haystack.graph, haystackNodeIdx, currentCandidate) &&
814  userSolver->userCompareNodes(needle.graphId, nn.nodeId, nn.userData, haystack.graphId, hn.nodeId, hn.userData, currentCandidate))
815  return true;
816  }
817  }
818  else
819  {
820  std::vector<std::vector<std::string>> thisSwapPorts;
821  for (const auto &ports : swapPorts.at(needle.graph.nodes[needleNodeIdx].typeId)) {
822  std::vector<std::string> portsVector;
823  for (const auto &port : ports)
824  portsVector.push_back(port);
825  thisSwapPorts.push_back(portsVector);
826  }
827 
828  int thisPermutations = numberOfPermutationsArray(thisSwapPorts);
829  for (int i = 0; i < thisPermutations; i++)
830  {
831  permutateVectorToMapArray(currentCandidate, thisSwapPorts, i);
832 
833  if (matchNodePorts(needle.graph, needleNodeIdx, haystack.graph, haystackNodeIdx, currentCandidate) &&
834  userSolver->userCompareNodes(needle.graphId, nn.nodeId, nn.userData, haystack.graphId, hn.nodeId, hn.userData, currentCandidate))
835  return true;
836 
837  if (swapPermutations.count(needle.graph.nodes[needleNodeIdx].typeId) > 0)
838  for (const auto &permutation : swapPermutations.at(needle.graph.nodes[needleNodeIdx].typeId)) {
839  std::map<std::string, std::string> currentSubCandidate = currentCandidate;
840  applyPermutation(currentSubCandidate, permutation);
841  if (matchNodePorts(needle.graph, needleNodeIdx, haystack.graph, haystackNodeIdx, currentCandidate) &&
842  userSolver->userCompareNodes(needle.graphId, nn.nodeId, nn.userData, haystack.graphId, hn.nodeId, hn.userData, currentCandidate))
843  return true;
844  }
845  }
846  }
847 
848  return false;
849  }
850 
851  void generateEnumerationMatrix(std::vector<std::set<int>> &enumerationMatrix, const GraphData &needle, const GraphData &haystack, const std::map<std::string, std::set<std::string>> &initialMappings) const
852  {
853  std::map<std::string, std::set<int>> haystackNodesByTypeId;
854  for (int i = 0; i < int(haystack.graph.nodes.size()); i++)
855  haystackNodesByTypeId[haystack.graph.nodes[i].typeId].insert(i);
856 
857  enumerationMatrix.clear();
858  enumerationMatrix.resize(needle.graph.nodes.size());
859  for (int i = 0; i < int(needle.graph.nodes.size()); i++)
860  {
861  const Graph::Node &nn = needle.graph.nodes[i];
862 
863  for (int j : haystackNodesByTypeId[nn.typeId]) {
864  const Graph::Node &hn = haystack.graph.nodes[j];
865  if (initialMappings.count(nn.nodeId) > 0 && initialMappings.at(nn.nodeId).count(hn.nodeId) == 0)
866  continue;
867  if (!matchNodes(needle, i, haystack, j))
868  continue;
869  enumerationMatrix[i].insert(j);
870  }
871 
872  if (compatibleTypes.count(nn.typeId) > 0)
873  for (const std::string &compatibleTypeId : compatibleTypes.at(nn.typeId))
874  for (int j : haystackNodesByTypeId[compatibleTypeId]) {
875  const Graph::Node &hn = haystack.graph.nodes[j];
876  if (initialMappings.count(nn.nodeId) > 0 && initialMappings.at(nn.nodeId).count(hn.nodeId) == 0)
877  continue;
878  if (!matchNodes(needle, i, haystack, j))
879  continue;
880  enumerationMatrix[i].insert(j);
881  }
882  }
883  }
884 
885  bool checkEnumerationMatrix(std::vector<std::set<int>> &enumerationMatrix, int i, int j, const GraphData &needle, const GraphData &haystack)
886  {
887  for (const auto &it_needle : needle.adjMatrix.at(i))
888  {
889  int needleNeighbour = it_needle.first;
890  int needleEdgeType = it_needle.second;
891 
892  for (int haystackNeighbour : enumerationMatrix[needleNeighbour])
893  if (haystack.adjMatrix.at(j).count(haystackNeighbour) > 0) {
894  int haystackEdgeType = haystack.adjMatrix.at(j).at(haystackNeighbour);
895  if (diCache.compare(needleEdgeType, haystackEdgeType, swapPorts, swapPermutations)) {
896  const Graph::Node &needleFromNode = needle.graph.nodes[i];
897  const Graph::Node &needleToNode = needle.graph.nodes[needleNeighbour];
898  const Graph::Node &haystackFromNode = haystack.graph.nodes[j];
899  const Graph::Node &haystackToNode = haystack.graph.nodes[haystackNeighbour];
900  if (userSolver->userCompareEdge(needle.graphId, needleFromNode.nodeId, needleFromNode.userData, needleToNode.nodeId, needleToNode.userData,
901  haystack.graphId, haystackFromNode.nodeId, haystackFromNode.userData, haystackToNode.nodeId, haystackToNode.userData))
902  goto found_match;
903  }
904  }
905 
906  return false;
907  found_match:;
908  }
909 
910  return true;
911  }
912 
913  bool pruneEnumerationMatrix(std::vector<std::set<int>> &enumerationMatrix, const GraphData &needle, const GraphData &haystack, int &nextRow, bool allowOverlap)
914  {
915  bool didSomething = true;
916  while (didSomething)
917  {
918  nextRow = -1;
919  didSomething = false;
920  for (int i = 0; i < int(enumerationMatrix.size()); i++) {
921  std::set<int> newRow;
922  for (int j : enumerationMatrix[i]) {
923  if (!checkEnumerationMatrix(enumerationMatrix, i, j, needle, haystack))
924  didSomething = true;
925  else if (!allowOverlap && haystack.usedNodes[j])
926  didSomething = true;
927  else
928  newRow.insert(j);
929  }
930  if (newRow.size() == 0)
931  return false;
932  if (newRow.size() >= 2 && (nextRow < 0 || needle.adjMatrix.at(nextRow).size() < needle.adjMatrix.at(i).size()))
933  nextRow = i;
934  enumerationMatrix[i].swap(newRow);
935  }
936  }
937  return true;
938  }
939 
940  void printEnumerationMatrix(const std::vector<std::set<int>> &enumerationMatrix, int maxHaystackNodeIdx = -1) const
941  {
942  if (maxHaystackNodeIdx < 0) {
943  for (const auto &it : enumerationMatrix)
944  for (int idx : it)
945  maxHaystackNodeIdx = std::max(maxHaystackNodeIdx, idx);
946  }
947 
948  my_printf(" ");
949  for (int j = 0; j < maxHaystackNodeIdx; j += 5)
950  my_printf("%-6d", j);
951  my_printf("\n");
952 
953  for (int i = 0; i < int(enumerationMatrix.size()); i++)
954  {
955  my_printf("%5d:", i);
956  for (int j = 0; j < maxHaystackNodeIdx; j++) {
957  if (j % 5 == 0)
958  my_printf(" ");
959  my_printf("%c", enumerationMatrix[i].count(j) > 0 ? '*' : '.');
960  }
961  my_printf("\n");
962  }
963  }
964 
965  bool checkPortmapCandidate(const std::vector<std::set<int>> &enumerationMatrix, const GraphData &needle, const GraphData &haystack, int idx, const std::map<std::string, std::string> &currentCandidate)
966  {
967  assert(enumerationMatrix[idx].size() == 1);
968  int idxHaystack = *enumerationMatrix[idx].begin();
969 
970  const Graph::Node &nn = needle.graph.nodes[idx];
971  const Graph::Node &hn = haystack.graph.nodes[idxHaystack];
972 
973  if (!matchNodePorts(needle.graph, idx, haystack.graph, idxHaystack, currentCandidate) ||
974  !userSolver->userCompareNodes(needle.graphId, nn.nodeId, nn.userData, haystack.graphId, hn.nodeId, hn.userData, currentCandidate))
975  return false;
976 
977  for (const auto &it_needle : needle.adjMatrix.at(idx))
978  {
979  int needleNeighbour = it_needle.first;
980  int needleEdgeType = it_needle.second;
981 
982  assert(enumerationMatrix[needleNeighbour].size() == 1);
983  int haystackNeighbour = *enumerationMatrix[needleNeighbour].begin();
984 
985  assert(haystack.adjMatrix.at(idxHaystack).count(haystackNeighbour) > 0);
986  int haystackEdgeType = haystack.adjMatrix.at(idxHaystack).at(haystackNeighbour);
987  if (!diCache.compare(needleEdgeType, haystackEdgeType, currentCandidate, swapPorts, swapPermutations))
988  return false;
989  }
990 
991  return true;
992  }
993 
994  void generatePortmapCandidates(std::set<std::map<std::string, std::string>> &portmapCandidates, const std::vector<std::set<int>> &enumerationMatrix,
995  const GraphData &needle, const GraphData &haystack, int idx)
996  {
997  std::map<std::string, std::string> currentCandidate;
998 
999  for (const auto &port : needle.graph.nodes[idx].ports)
1000  currentCandidate[port.portId] = port.portId;
1001 
1002  if (swapPorts.count(needle.graph.nodes[idx].typeId) == 0)
1003  {
1004  if (checkPortmapCandidate(enumerationMatrix, needle, haystack, idx, currentCandidate))
1005  portmapCandidates.insert(currentCandidate);
1006 
1007  if (swapPermutations.count(needle.graph.nodes[idx].typeId) > 0)
1008  for (const auto &permutation : swapPermutations.at(needle.graph.nodes[idx].typeId)) {
1009  std::map<std::string, std::string> currentSubCandidate = currentCandidate;
1010  applyPermutation(currentSubCandidate, permutation);
1011  if (checkPortmapCandidate(enumerationMatrix, needle, haystack, idx, currentSubCandidate))
1012  portmapCandidates.insert(currentSubCandidate);
1013  }
1014  }
1015  else
1016  {
1017  std::vector<std::vector<std::string>> thisSwapPorts;
1018  for (const auto &ports : swapPorts.at(needle.graph.nodes[idx].typeId)) {
1019  std::vector<std::string> portsVector;
1020  for (const auto &port : ports)
1021  portsVector.push_back(port);
1022  thisSwapPorts.push_back(portsVector);
1023  }
1024 
1025  int thisPermutations = numberOfPermutationsArray(thisSwapPorts);
1026  for (int i = 0; i < thisPermutations; i++)
1027  {
1028  permutateVectorToMapArray(currentCandidate, thisSwapPorts, i);
1029 
1030  if (checkPortmapCandidate(enumerationMatrix, needle, haystack, idx, currentCandidate))
1031  portmapCandidates.insert(currentCandidate);
1032 
1033  if (swapPermutations.count(needle.graph.nodes[idx].typeId) > 0)
1034  for (const auto &permutation : swapPermutations.at(needle.graph.nodes[idx].typeId)) {
1035  std::map<std::string, std::string> currentSubCandidate = currentCandidate;
1036  applyPermutation(currentSubCandidate, permutation);
1037  if (checkPortmapCandidate(enumerationMatrix, needle, haystack, idx, currentSubCandidate))
1038  portmapCandidates.insert(currentSubCandidate);
1039  }
1040  }
1041  }
1042  }
1043 
1044  bool prunePortmapCandidates(std::vector<std::set<std::map<std::string, std::string>>> &portmapCandidates, std::vector<std::set<int>> enumerationMatrix, const GraphData &needle, const GraphData &haystack)
1045  {
1046  bool didSomething = false;
1047 
1048  // strategy #1: prune impossible port mappings
1049 
1050  for (int i = 0; i < int(needle.graph.nodes.size()); i++)
1051  {
1052  assert(enumerationMatrix[i].size() == 1);
1053  int j = *enumerationMatrix[i].begin();
1054 
1055  std::set<std::map<std::string, std::string>> thisCandidates;
1056  portmapCandidates[i].swap(thisCandidates);
1057 
1058  for (const auto &testCandidate : thisCandidates)
1059  {
1060  for (const auto &it_needle : needle.adjMatrix.at(i))
1061  {
1062  int needleNeighbour = it_needle.first;
1063  int needleEdgeType = it_needle.second;
1064 
1065  assert(enumerationMatrix[needleNeighbour].size() == 1);
1066  int haystackNeighbour = *enumerationMatrix[needleNeighbour].begin();
1067 
1068  assert(haystack.adjMatrix.at(j).count(haystackNeighbour) > 0);
1069  int haystackEdgeType = haystack.adjMatrix.at(j).at(haystackNeighbour);
1070 
1071  std::set<std::map<std::string, std::string>> &candidates =
1072  i == needleNeighbour ? thisCandidates : portmapCandidates[needleNeighbour];
1073 
1074  for (const auto &otherCandidate : candidates) {
1075  if (diCache.compare(needleEdgeType, haystackEdgeType, testCandidate, otherCandidate))
1076  goto found_match;
1077  }
1078 
1079  didSomething = true;
1080  goto purgeCandidate;
1081  found_match:;
1082  }
1083 
1084  portmapCandidates[i].insert(testCandidate);
1085  purgeCandidate:;
1086  }
1087 
1088  if (portmapCandidates[i].size() == 0)
1089  return false;
1090  }
1091 
1092  if (didSomething)
1093  return true;
1094 
1095  // strategy #2: prune a single random port mapping
1096 
1097  for (int i = 0; i < int(needle.graph.nodes.size()); i++)
1098  if (portmapCandidates[i].size() > 1) {
1099  // remove last mapping. this keeps ports unswapped in don't-care situations
1100  portmapCandidates[i].erase(--portmapCandidates[i].end());
1101  return true;
1102  }
1103 
1104  return false;
1105  }
1106 
1107  void ullmannRecursion(std::vector<Solver::Result> &results, std::vector<std::set<int>> &enumerationMatrix, int iter, const GraphData &needle, GraphData &haystack, bool allowOverlap, int limitResults)
1108  {
1109  int i = -1;
1110  if (!pruneEnumerationMatrix(enumerationMatrix, needle, haystack, i, allowOverlap))
1111  return;
1112 
1113  if (i < 0)
1114  {
1115  Solver::Result result;
1116  result.needleGraphId = needle.graphId;
1117  result.haystackGraphId = haystack.graphId;
1118 
1119  std::vector<std::set<std::map<std::string, std::string>>> portmapCandidates;
1120  portmapCandidates.resize(enumerationMatrix.size());
1121 
1122  for (int j = 0; j < int(enumerationMatrix.size()); j++) {
1123  Solver::ResultNodeMapping mapping;
1124  mapping.needleNodeId = needle.graph.nodes[j].nodeId;
1125  mapping.needleUserData = needle.graph.nodes[j].userData;
1126  mapping.haystackNodeId = haystack.graph.nodes[*enumerationMatrix[j].begin()].nodeId;
1127  mapping.haystackUserData = haystack.graph.nodes[*enumerationMatrix[j].begin()].userData;
1128  generatePortmapCandidates(portmapCandidates[j], enumerationMatrix, needle, haystack, j);
1129  result.mappings[needle.graph.nodes[j].nodeId] = mapping;
1130  }
1131 
1132  while (prunePortmapCandidates(portmapCandidates, enumerationMatrix, needle, haystack)) { }
1133 
1134  if (verbose) {
1135  my_printf("\nPortmapper results:\n");
1136  for (int j = 0; j < int(enumerationMatrix.size()); j++) {
1137  my_printf("%5d: %s\n", j, needle.graph.nodes[j].nodeId.c_str());
1138  int variantCounter = 0;
1139  for (auto &i2 : portmapCandidates.at(j)) {
1140  my_printf("%*s variant %2d:", 6, "", variantCounter++);
1141  int mapCounter = 0;
1142  for (auto &i3 : i2)
1143  my_printf("%s %s -> %s", mapCounter++ ? "," : "", i3.first.c_str(), i3.second.c_str());
1144  my_printf("\n");
1145  }
1146  }
1147  }
1148 
1149  for (int j = 0; j < int(enumerationMatrix.size()); j++) {
1150  if (portmapCandidates[j].size() == 0) {
1151  if (verbose) {
1152  my_printf("\nSolution (rejected by portmapper):\n");
1153  printEnumerationMatrix(enumerationMatrix, haystack.graph.nodes.size());
1154  }
1155  return;
1156  }
1157  result.mappings[needle.graph.nodes[j].nodeId].portMapping = *portmapCandidates[j].begin();
1158  }
1159 
1160  if (!userSolver->userCheckSolution(result)) {
1161  if (verbose) {
1162  my_printf("\nSolution (rejected by userCheckSolution):\n");
1163  printEnumerationMatrix(enumerationMatrix, haystack.graph.nodes.size());
1164  }
1165  return;
1166  }
1167 
1168  for (int j = 0; j < int(enumerationMatrix.size()); j++)
1169  if (!haystack.graph.nodes[*enumerationMatrix[j].begin()].shared)
1170  haystack.usedNodes[*enumerationMatrix[j].begin()] = true;
1171 
1172  if (verbose) {
1173  my_printf("\nSolution:\n");
1174  printEnumerationMatrix(enumerationMatrix, haystack.graph.nodes.size());
1175  }
1176 
1177  results.push_back(result);
1178  return;
1179  }
1180 
1181  if (verbose) {
1182  my_printf("\n");
1183  my_printf("Enumeration Matrix at recursion level %d (%d):\n", iter, i);
1184  printEnumerationMatrix(enumerationMatrix, haystack.graph.nodes.size());
1185  }
1186 
1187  std::set<int> activeRow;
1188  enumerationMatrix[i].swap(activeRow);
1189 
1190  for (int j : activeRow)
1191  {
1192  // found enough?
1193  if (limitResults >= 0 && int(results.size()) >= limitResults)
1194  return;
1195 
1196  // already used by other solution -> try next
1197  if (!allowOverlap && haystack.usedNodes[j])
1198  continue;
1199 
1200  // create enumeration matrix for child in recursion tree
1201  std::vector<std::set<int>> nextEnumerationMatrix = enumerationMatrix;
1202  for (int k = 0; k < int(nextEnumerationMatrix.size()); k++)
1203  nextEnumerationMatrix[k].erase(j);
1204  nextEnumerationMatrix[i].insert(j);
1205 
1206  // recursion
1207  ullmannRecursion(results, nextEnumerationMatrix, iter+1, needle, haystack, allowOverlap, limitResults);
1208 
1209  // we just have found something -> unroll to top recursion level
1210  if (!allowOverlap && haystack.usedNodes[j] && iter > 0)
1211  return;
1212  }
1213  }
1214 
1215  // additional data structes and functions for mining
1216 
1217  struct NodeSet {
1218  std::string graphId;
1219  std::set<int> nodes;
1220  NodeSet(std::string graphId, int node1, int node2) {
1221  this->graphId = graphId;
1222  nodes.insert(node1);
1223  nodes.insert(node2);
1224  }
1225  NodeSet(std::string graphId, const std::vector<int> &nodes) {
1226  this->graphId = graphId;
1227  for (int node : nodes)
1228  this->nodes.insert(node);
1229  }
1230  void extend(const NodeSet &other) {
1231  assert(this->graphId == other.graphId);
1232  for (int node : other.nodes)
1233  nodes.insert(node);
1234  }
1235  int extendCandidate(const NodeSet &other) const {
1236  if (graphId != other.graphId)
1237  return 0;
1238  int newNodes = 0;
1239  bool intersect = false;
1240  for (int node : other.nodes)
1241  if (nodes.count(node) > 0)
1242  intersect = true;
1243  else
1244  newNodes++;
1245  return intersect ? newNodes : 0;
1246  }
1247  bool operator <(const NodeSet &other) const {
1248  if (graphId != other.graphId)
1249  return graphId < other.graphId;
1250  return nodes < other.nodes;
1251  }
1252  std::string to_string() const {
1253  std::string str = graphId + "(";
1254  bool first = true;
1255  for (int node : nodes) {
1256  str += my_stringf("%s%d", first ? "" : " ", node);
1257  first = false;
1258  }
1259  return str + ")";
1260  }
1261  };
1262 
1263  void solveForMining(std::vector<Solver::Result> &results, const GraphData &needle)
1264  {
1265  bool backupVerbose = verbose;
1266  verbose = false;
1267 
1268  for (auto &it : graphData)
1269  {
1270  GraphData &haystack = it.second;
1271 
1272  std::vector<std::set<int>> enumerationMatrix;
1273  std::map<std::string, std::set<std::string>> initialMappings;
1274  generateEnumerationMatrix(enumerationMatrix, needle, haystack, initialMappings);
1275 
1276  haystack.usedNodes.resize(haystack.graph.nodes.size());
1277  ullmannRecursion(results, enumerationMatrix, 0, needle, haystack, true, -1);
1278  }
1279 
1280  verbose = backupVerbose;
1281  }
1282 
1283  int testForMining(std::vector<Solver::MineResult> &results, std::set<NodeSet> &usedSets, std::set<NodeSet> &nextPool, NodeSet &testSet,
1284  const std::string &graphId, const Graph &graph, int minNodes, int minMatches, int limitMatchesPerGraph)
1285  {
1286  // my_printf("test: %s\n", testSet.to_string().c_str());
1287 
1288  GraphData needle;
1289  std::vector<std::string> needle_nodes;
1290  for (int nodeIdx : testSet.nodes)
1291  needle_nodes.push_back(graph.nodes[nodeIdx].nodeId);
1292  needle.graph = Graph(graph, needle_nodes);
1293  needle.graph.markAllExtern();
1294  diCache.add(needle.graph, needle.adjMatrix, graphId, userSolver);
1295 
1296  std::vector<Solver::Result> ullmannResults;
1297  solveForMining(ullmannResults, needle);
1298 
1299  int matches = 0;
1300  std::map<std::string, int> matchesPerGraph;
1301  std::set<NodeSet> thisNodeSetSet;
1302 
1303  for (auto &it : ullmannResults)
1304  {
1305  std::vector<int> resultNodes;
1306  for (auto &i2 : it.mappings)
1307  resultNodes.push_back(graphData[it.haystackGraphId].graph.nodeMap[i2.second.haystackNodeId]);
1308  NodeSet resultSet(it.haystackGraphId, resultNodes);
1309 
1310  // my_printf("match: %s%s\n", resultSet.to_string().c_str(), usedSets.count(resultSet) > 0 ? " (dup)" : "");
1311 
1312 #if 0
1313  if (usedSets.count(resultSet) > 0) {
1314  // Because of shorted pins isomorphisim is not always bidirectional!
1315  //
1316  // This means that the following assert is not true in all cases and subgraph A might
1317  // show up in the matches for subgraph B but not vice versa... This also means that the
1318  // order in which subgraphs are processed has an impact on the results set.
1319  //
1320  assert(thisNodeSetSet.count(resultSet) > 0);
1321  continue;
1322  }
1323 #else
1324  if (thisNodeSetSet.count(resultSet) > 0)
1325  continue;
1326 #endif
1327 
1328  usedSets.insert(resultSet);
1329  thisNodeSetSet.insert(resultSet);
1330 
1331  matchesPerGraph[it.haystackGraphId]++;
1332  if (limitMatchesPerGraph < 0 || matchesPerGraph[it.haystackGraphId] < limitMatchesPerGraph)
1333  matches++;
1334  }
1335 
1336  if (matches < minMatches)
1337  return matches;
1338 
1339  if (minNodes <= int(testSet.nodes.size()))
1340  {
1341  Solver::MineResult result;
1342  result.graphId = graphId;
1343  result.totalMatchesAfterLimits = matches;
1344  result.matchesPerGraph = matchesPerGraph;
1345  for (int nodeIdx : testSet.nodes) {
1346  Solver::MineResultNode resultNode;
1347  resultNode.nodeId = graph.nodes[nodeIdx].nodeId;
1348  resultNode.userData = graph.nodes[nodeIdx].userData;
1349  result.nodes.push_back(resultNode);
1350  }
1351  results.push_back(result);
1352  }
1353 
1354  nextPool.insert(thisNodeSetSet.begin(), thisNodeSetSet.end());
1355  return matches;
1356  }
1357 
1358  void findNodePairs(std::vector<Solver::MineResult> &results, std::set<NodeSet> &nodePairs, int minNodes, int minMatches, int limitMatchesPerGraph)
1359  {
1360  int groupCounter = 0;
1361  std::set<NodeSet> usedPairs;
1362  nodePairs.clear();
1363 
1364  if (verbose)
1365  my_printf("\nMining for frequent node pairs:\n");
1366 
1367  for (auto &graph_it : graphData)
1368  for (int node1 = 0; node1 < int(graph_it.second.graph.nodes.size()); node1++)
1369  for (auto &adj_it : graph_it.second.adjMatrix.at(node1))
1370  {
1371  const std::string &graphId = graph_it.first;
1372  const auto &graph = graph_it.second.graph;
1373  int node2 = adj_it.first;
1374 
1375  if (node1 == node2)
1376  continue;
1377 
1378  NodeSet pair(graphId, node1, node2);
1379 
1380  if (usedPairs.count(pair) > 0)
1381  continue;
1382 
1383  int matches = testForMining(results, usedPairs, nodePairs, pair, graphId, graph, minNodes, minMatches, limitMatchesPerGraph);
1384 
1385  if (verbose)
1386  my_printf("Pair %s[%s,%s] -> %d%s\n", graphId.c_str(), graph.nodes[node1].nodeId.c_str(),
1387  graph.nodes[node2].nodeId.c_str(), matches, matches < minMatches ? " *purge*" : "");
1388 
1389  if (minMatches <= matches)
1390  groupCounter++;
1391  }
1392 
1393  if (verbose)
1394  my_printf("Found a total of %d subgraphs in %d groups.\n", int(nodePairs.size()), groupCounter);
1395  }
1396 
1397  void findNextPool(std::vector<Solver::MineResult> &results, std::set<NodeSet> &pool,
1398  int oldSetSize, int increment, int minNodes, int minMatches, int limitMatchesPerGraph)
1399  {
1400  int groupCounter = 0;
1401  std::map<std::string, std::vector<const NodeSet*>> poolPerGraph;
1402  std::set<NodeSet> nextPool;
1403 
1404  for (auto &it : pool)
1405  poolPerGraph[it.graphId].push_back(&it);
1406 
1407  if (verbose)
1408  my_printf("\nMining for frequent subcircuits of size %d using increment %d:\n", oldSetSize+increment, increment);
1409 
1410  int count = 0;
1411  for (auto &it : poolPerGraph)
1412  {
1413  std::map<int, std::set<int>> node2sets;
1414  std::set<NodeSet> usedSets;
1415 
1416  for (int idx = 0; idx < int(it.second.size()); idx++) {
1417  for (int node : it.second[idx]->nodes)
1418  node2sets[node].insert(idx);
1419  }
1420 
1421  for (int idx1 = 0; idx1 < int(it.second.size()); idx1++, count++)
1422  {
1423  std::set<int> idx2set;
1424 
1425  for (int node : it.second[idx1]->nodes)
1426  for (int idx2 : node2sets[node])
1427  if (idx2 > idx1)
1428  idx2set.insert(idx2);
1429 
1430  for (int idx2 : idx2set)
1431  {
1432  if (it.second[idx1]->extendCandidate(*it.second[idx2]) != increment)
1433  continue;
1434 
1435  NodeSet mergedSet = *it.second[idx1];
1436  mergedSet.extend(*it.second[idx2]);
1437 
1438  if (usedSets.count(mergedSet) > 0)
1439  continue;
1440 
1441  const std::string &graphId = it.first;
1442  const auto &graph = graphData[it.first].graph;
1443 
1444  if (verbose) {
1445  my_printf("<%d%%/%d> Found %s[", int(100*count/pool.size()), oldSetSize+increment, graphId.c_str());
1446  bool first = true;
1447  for (int nodeIdx : mergedSet.nodes) {
1448  my_printf("%s%s", first ? "" : ",", graph.nodes[nodeIdx].nodeId.c_str());
1449  first = false;
1450  }
1451  my_printf("] ->");
1452  }
1453 
1454  int matches = testForMining(results, usedSets, nextPool, mergedSet, graphId, graph, minNodes, minMatches, limitMatchesPerGraph);
1455 
1456  if (verbose)
1457  my_printf(" %d%s\n", matches, matches < minMatches ? " *purge*" : "");
1458 
1459  if (minMatches <= matches)
1460  groupCounter++;
1461  }
1462  }
1463  }
1464 
1465  pool.swap(nextPool);
1466 
1467  if (verbose)
1468  my_printf("Found a total of %d subgraphs in %d groups.\n", int(pool.size()), groupCounter);
1469  }
1470 
1471  // interface to the public solver class
1472 
1473 protected:
1474  SolverWorker(Solver *userSolver) : userSolver(userSolver), verbose(false)
1475  {
1476  }
1477 
1478  void setVerbose()
1479  {
1480  verbose = true;
1481  }
1482 
1483  void addGraph(std::string graphId, const Graph &graph)
1484  {
1485  assert(graphData.count(graphId) == 0);
1486 
1487  GraphData &gd = graphData[graphId];
1488  gd.graphId = graphId;
1489  gd.graph = graph;
1490  diCache.add(gd.graph, gd.adjMatrix, graphId, userSolver);
1491  }
1492 
1493  void addCompatibleTypes(std::string needleTypeId, std::string haystackTypeId)
1494  {
1495  compatibleTypes[needleTypeId].insert(haystackTypeId);
1496  }
1497 
1498  void addCompatibleConstants(int needleConstant, int haystackConstant)
1499  {
1500  compatibleConstants[needleConstant].insert(haystackConstant);
1501  }
1502 
1503  void addSwappablePorts(std::string needleTypeId, const std::set<std::string> &ports)
1504  {
1505  swapPorts[needleTypeId].insert(ports);
1506  diCache.compareCache.clear();
1507  }
1508 
1509  void addSwappablePortsPermutation(std::string needleTypeId, const std::map<std::string, std::string> &portMapping)
1510  {
1511  swapPermutations[needleTypeId].insert(portMapping);
1512  diCache.compareCache.clear();
1513  }
1514 
1515  void solve(std::vector<Solver::Result> &results, std::string needleGraphId, std::string haystackGraphId,
1516  const std::map<std::string, std::set<std::string>> &initialMappings, bool allowOverlap, int maxSolutions)
1517  {
1518  assert(graphData.count(needleGraphId) > 0);
1519  assert(graphData.count(haystackGraphId) > 0);
1520 
1521  const GraphData &needle = graphData[needleGraphId];
1522  GraphData &haystack = graphData[haystackGraphId];
1523 
1524  std::vector<std::set<int>> enumerationMatrix;
1525  generateEnumerationMatrix(enumerationMatrix, needle, haystack, initialMappings);
1526 
1527  if (verbose)
1528  {
1529  my_printf("\n");
1530  my_printf("Needle nodes:\n");
1531  for (int i = 0; i < int(needle.graph.nodes.size()); i++)
1532  my_printf("%5d: %s (%s)\n", i, needle.graph.nodes[i].nodeId.c_str(), needle.graph.nodes[i].typeId.c_str());
1533 
1534  my_printf("\n");
1535  my_printf("Haystack nodes:\n");
1536  for (int i = 0; i < int(haystack.graph.nodes.size()); i++)
1537  my_printf("%5d: %s (%s)\n", i, haystack.graph.nodes[i].nodeId.c_str(), haystack.graph.nodes[i].typeId.c_str());
1538 
1539  my_printf("\n");
1540  my_printf("Needle Adjecency Matrix:\n");
1541  printAdjMatrix(needle.adjMatrix);
1542 
1543  my_printf("\n");
1544  my_printf("Haystack Adjecency Matrix:\n");
1545  printAdjMatrix(haystack.adjMatrix);
1546 
1547  my_printf("\n");
1548  my_printf("Edge Types:\n");
1550 
1551  my_printf("\n");
1552  my_printf("Enumeration Matrix (haystack nodes at column indices):\n");
1553  printEnumerationMatrix(enumerationMatrix, haystack.graph.nodes.size());
1554  }
1555 
1556  haystack.usedNodes.resize(haystack.graph.nodes.size());
1557  ullmannRecursion(results, enumerationMatrix, 0, needle, haystack, allowOverlap, maxSolutions > 0 ? results.size() + maxSolutions : -1);
1558  }
1559 
1560  void mine(std::vector<Solver::MineResult> &results, int minNodes, int maxNodes, int minMatches, int limitMatchesPerGraph)
1561  {
1562  int nodeSetSize = 2;
1563  std::set<NodeSet> pool;
1564  findNodePairs(results, pool, minNodes, minMatches, limitMatchesPerGraph);
1565 
1566  while ((maxNodes < 0 || nodeSetSize < maxNodes) && pool.size() > 0)
1567  {
1568  int increment = nodeSetSize - 1;
1569  if (nodeSetSize + increment >= minNodes)
1570  increment = minNodes - nodeSetSize;
1571  if (nodeSetSize >= minNodes)
1572  increment = 1;
1573 
1574  findNextPool(results, pool, nodeSetSize, increment, minNodes, minMatches, limitMatchesPerGraph);
1575  nodeSetSize += increment;
1576  }
1577  }
1578 
1580  {
1581  for (auto &it : graphData)
1582  it.second.usedNodes.clear();
1583  }
1584 
1586  {
1587  compatibleTypes.clear();
1588  compatibleConstants.clear();
1589  swapPorts.clear();
1590  swapPermutations.clear();
1591  diCache.compareCache.clear();
1592  }
1593 
1594  friend class Solver;
1595 };
1596 
1597 bool Solver::userCompareNodes(const std::string&, const std::string&, void*, const std::string&, const std::string&, void*, const std::map<std::string, std::string>&)
1598 {
1599  return true;
1600 }
1601 
1602 std::string Solver::userAnnotateEdge(const std::string&, const std::string&, void*, const std::string&, void*)
1603 {
1604  return std::string();
1605 }
1606 
1607 bool Solver::userCompareEdge(const std::string&, const std::string&, void*, const std::string&, void*, const std::string&, const std::string&, void*, const std::string&, void*)
1608 {
1609  return true;
1610 }
1611 
1613 {
1614  return true;
1615 }
1616 
1618 {
1619  worker = new SolverWorker(this);
1620 }
1621 
1623 {
1624  delete worker;
1625 }
1626 
1628 {
1629  worker->setVerbose();
1630 }
1631 
1632 void SubCircuit::Solver::addGraph(std::string graphId, const Graph &graph)
1633 {
1634  worker->addGraph(graphId, graph);
1635 }
1636 
1637 void SubCircuit::Solver::addCompatibleTypes(std::string needleTypeId, std::string haystackTypeId)
1638 {
1639  worker->addCompatibleTypes(needleTypeId, haystackTypeId);
1640 }
1641 
1642 void SubCircuit::Solver::addCompatibleConstants(int needleConstant, int haystackConstant)
1643 {
1644  worker->addCompatibleConstants(needleConstant, haystackConstant);
1645 }
1646 
1647 void SubCircuit::Solver::addSwappablePorts(std::string needleTypeId, std::string portId1, std::string portId2, std::string portId3, std::string portId4)
1648 {
1649  std::set<std::string> ports;
1650  ports.insert(portId1);
1651  ports.insert(portId2);
1652  ports.insert(portId3);
1653  ports.insert(portId4);
1654  ports.erase(std::string());
1655  addSwappablePorts(needleTypeId, ports);
1656 }
1657 
1658 void SubCircuit::Solver::addSwappablePorts(std::string needleTypeId, std::set<std::string> ports)
1659 {
1660  worker->addSwappablePorts(needleTypeId, ports);
1661 }
1662 
1663 void SubCircuit::Solver::addSwappablePortsPermutation(std::string needleTypeId, std::map<std::string, std::string> portMapping)
1664 {
1665  worker->addSwappablePortsPermutation(needleTypeId, portMapping);
1666 }
1667 
1668 void SubCircuit::Solver::solve(std::vector<Result> &results, std::string needleGraphId, std::string haystackGraphId, bool allowOverlap, int maxSolutions)
1669 {
1670  std::map<std::string, std::set<std::string>> emptyInitialMapping;
1671  worker->solve(results, needleGraphId, haystackGraphId, emptyInitialMapping, allowOverlap, maxSolutions);
1672 }
1673 
1674 void SubCircuit::Solver::solve(std::vector<Result> &results, std::string needleGraphId, std::string haystackGraphId,
1675  const std::map<std::string, std::set<std::string>> &initialMappings, bool allowOverlap, int maxSolutions)
1676 {
1677  worker->solve(results, needleGraphId, haystackGraphId, initialMappings, allowOverlap, maxSolutions);
1678 }
1679 
1680 void SubCircuit::Solver::mine(std::vector<MineResult> &results, int minNodes, int maxNodes, int minMatches, int limitMatchesPerGraph)
1681 {
1682  worker->mine(results, minNodes, maxNodes, minMatches, limitMatchesPerGraph);
1683 }
1684 
1686 {
1687  worker->clearOverlapHistory();
1688 }
1689 
1691 {
1692  worker->clearConfig();
1693 }
1694 
bool compare(int needleEdge, int haystackEdge, const std::map< std::string, std::string > &mapFromPorts, const std::map< std::string, std::string > &mapToPorts) const
Definition: subcircuit.cc:700
bool checkPortmapCandidate(const std::vector< std::set< int >> &enumerationMatrix, const GraphData &needle, const GraphData &haystack, int idx, const std::map< std::string, std::string > &currentCandidate)
Definition: subcircuit.cc:965
void ullmannRecursion(std::vector< Solver::Result > &results, std::vector< std::set< int >> &enumerationMatrix, int iter, const GraphData &needle, GraphData &haystack, bool allowOverlap, int limitResults)
Definition: subcircuit.cc:1107
static void printAdjMatrix(const adjMatrix_t &matrix)
Definition: subcircuit.cc:300
std::map< std::string, std::set< std::map< std::string, std::string > > > swapPermutations
Definition: subcircuit.cc:719
virtual bool userCompareNodes(const std::string &needleGraphId, const std::string &needleNodeId, void *needleUserData, const std::string &haystackGraphId, const std::string &haystackNodeId, void *haystackUserData, const std::map< std::string, std::string > &portMapping)
Definition: subcircuit.cc:1597
bool compare(int needleEdge, int haystackEdge, const std::map< std::string, std::string > &mapFromPorts, const std::map< std::string, std::set< std::set< std::string >>> &swapPorts, const std::map< std::string, std::set< std::map< std::string, std::string >>> &swapPermutations) const
Definition: subcircuit.cc:694
virtual std::string userAnnotateEdge(const std::string &graphId, const std::string &fromNodeId, void *fromUserData, const std::string &toNodeId, void *toUserData)
Definition: subcircuit.cc:1602
std::vector< Node > nodes
Definition: subcircuit.h:72
std::map< std::string, int > portMap
Definition: subcircuit.h:63
void add(const Graph &graph, adjMatrix_t &adjMatrix, const std::string &graphId, Solver *userSolver)
Definition: subcircuit.cc:662
void addGraph(std::string graphId, const Graph &graph)
Definition: subcircuit.cc:1483
void free(void *)
static void permutateVectorToMap(std::map< std::string, std::string > &map, const std::vector< std::string > &list, int idx)
Definition: subcircuit.cc:331
void printEnumerationMatrix(const std::vector< std::set< int >> &enumerationMatrix, int maxHaystackNodeIdx=-1) const
Definition: subcircuit.cc:940
SolverWorker(Solver *userSolver)
Definition: subcircuit.cc:1474
void mine(std::vector< Solver::MineResult > &results, int minNodes, int maxNodes, int minMatches, int limitMatchesPerGraph)
Definition: subcircuit.cc:1560
bool operator<(const NodeSet &other) const
Definition: subcircuit.cc:1247
void addCompatibleTypes(std::string needleTypeId, std::string haystackTypeId)
Definition: subcircuit.cc:1493
static void permutateVectorToMapArray(std::map< std::string, std::string > &map, const std::vector< std::vector< std::string >> &list, int idx)
Definition: subcircuit.cc:370
std::map< std::pair< int, int >, bool > compareCache
Definition: subcircuit.cc:660
static std::string idx(std::string str)
Definition: test_autotb.cc:57
bool compare(const DiEdge &other, const std::map< std::string, std::string > &mapFromPorts, const std::map< std::string, std::string > &mapToPorts) const
Definition: subcircuit.cc:472
int testForMining(std::vector< Solver::MineResult > &results, std::set< NodeSet > &usedSets, std::set< NodeSet > &nextPool, NodeSet &testSet, const std::string &graphId, const Graph &graph, int minNodes, int minMatches, int limitMatchesPerGraph)
Definition: subcircuit.cc:1283
void addSwappablePorts(std::string needleTypeId, std::string portId1, std::string portId2, std::string portId3=std::string(), std::string portId4=std::string())
Definition: subcircuit.cc:1647
void solve(std::vector< Solver::Result > &results, std::string needleGraphId, std::string haystackGraphId, const std::map< std::string, std::set< std::string >> &initialMappings, bool allowOverlap, int maxSolutions)
Definition: subcircuit.cc:1515
std::vector< DiEdge > edgeTypes
Definition: subcircuit.cc:659
bool pruneEnumerationMatrix(std::vector< std::set< int >> &enumerationMatrix, const GraphData &needle, const GraphData &haystack, int &nextRow, bool allowOverlap)
Definition: subcircuit.cc:913
NodeSet(std::string graphId, int node1, int node2)
Definition: subcircuit.cc:1220
bool operator<(const DiBit &other) const
Definition: subcircuit.cc:402
bool operator<(const DiNode &other) const
Definition: subcircuit.cc:436
void solveForMining(std::vector< Solver::Result > &results, const GraphData &needle)
Definition: subcircuit.cc:1263
void addCompatibleConstants(int needleConstant, int haystackConstant)
Definition: subcircuit.cc:1642
bool matchNodePorts(const Graph &needle, int needleNodeIdx, const Graph &haystack, int haystackNodeIdx, const std::map< std::string, std::string > &swaps) const
Definition: subcircuit.cc:725
std::map< std::string, int > portSizes
Definition: subcircuit.cc:422
std::string toString() const
Definition: subcircuit.cc:413
std::vector< Edge > edges
Definition: subcircuit.h:73
static void applyPermutation(std::map< std::string, std::string > &map, const std::map< std::string, std::string > &permutation)
Definition: subcircuit.cc:380
void createNode(std::string nodeId, std::string typeId, void *userData=NULL, bool shared=false)
Definition: subcircuit.cc:107
static int numberOfPermutationsArray(const std::vector< std::vector< std::string >> &list)
Definition: subcircuit.cc:359
void solve(std::vector< Result > &results, std::string needleGraphId, std::string haystackGraphId, bool allowOverlap=true, int maxSolutions=-1)
Definition: subcircuit.cc:1668
bool compare(const DiEdge &other, const std::map< std::string, std::set< std::set< std::string >>> &swapPorts, const std::map< std::string, std::set< std::map< std::string, std::string >>> &swapPermutations) const
Definition: subcircuit.cc:535
bool compare(int needleEdge, int haystackEdge, const std::map< std::string, std::set< std::set< std::string >>> &swapPorts, const std::map< std::string, std::set< std::map< std::string, std::string >>> &swapPermutations)
Definition: subcircuit.cc:685
static std::string my_stringf(const char *fmt,...)
Definition: subcircuit.cc:38
std::vector< MineResultNode > nodes
Definition: subcircuit.h:113
virtual bool userCompareEdge(const std::string &needleGraphId, const std::string &needleFromNodeId, void *needleFromUserData, const std::string &needleToNodeId, void *needleToUserData, const std::string &haystackGraphId, const std::string &haystackFromNodeId, void *haystackFromUserData, const std::string &haystackToNodeId, void *haystackToUserData)
Definition: subcircuit.cc:1607
virtual bool userCheckSolution(const Result &result)
Definition: subcircuit.cc:1612
static void findEdgesInGraph(const Graph &graph, std::map< std::pair< int, int >, DiEdge > &edges)
Definition: subcircuit.cc:636
bool prunePortmapCandidates(std::vector< std::set< std::map< std::string, std::string >>> &portmapCandidates, std::vector< std::set< int >> enumerationMatrix, const GraphData &needle, const GraphData &haystack)
Definition: subcircuit.cc:1044
void createConstant(std::string toNodeId, std::string toPortId, int toBit, int constValue)
Definition: subcircuit.cc:209
void addGraph(std::string graphId, const Graph &graph)
Definition: subcircuit.cc:1632
void addCompatibleConstants(int needleConstant, int haystackConstant)
Definition: subcircuit.cc:1498
std::vector< std::map< int, int > > adjMatrix_t
Definition: subcircuit.cc:291
bool compare(const DiEdge &other, const std::map< std::string, std::string > &mapFromPorts, const std::map< std::string, std::set< std::set< std::string >>> &swapPorts, const std::map< std::string, std::set< std::map< std::string, std::string >>> &swapPermutations) const
Definition: subcircuit.cc:593
void addSwappablePortsPermutation(std::string needleTypeId, const std::map< std::string, std::string > &portMapping)
Definition: subcircuit.cc:1509
void generatePortmapCandidates(std::set< std::map< std::string, std::string >> &portmapCandidates, const std::vector< std::set< int >> &enumerationMatrix, const GraphData &needle, const GraphData &haystack, int idx)
Definition: subcircuit.cc:994
void addSwappablePortsPermutation(std::string needleTypeId, std::map< std::string, std::string > portMapping)
Definition: subcircuit.cc:1663
void markExtern(std::string nodeId, std::string portId, int bit=-1)
Definition: subcircuit.cc:244
void generateEnumerationMatrix(std::vector< std::set< int >> &enumerationMatrix, const GraphData &needle, const GraphData &haystack, const std::map< std::string, std::set< std::string >> &initialMappings) const
Definition: subcircuit.cc:851
void mine(std::vector< MineResult > &results, int minNodes, int maxNodes, int minMatches, int limitMatchesPerGraph=-1)
Definition: subcircuit.cc:1680
void findNextPool(std::vector< Solver::MineResult > &results, std::set< NodeSet > &pool, int oldSetSize, int increment, int minNodes, int minMatches, int limitMatchesPerGraph)
Definition: subcircuit.cc:1397
static const int maxPermutationsLimit
Definition: subcircuit.cc:319
void extend(const NodeSet &other)
Definition: subcircuit.cc:1230
std::map< std::string, GraphData > graphData
Definition: subcircuit.cc:715
bool compareWithFromAndToPermutations(const DiEdge &other, const std::map< std::string, std::string > &mapFromPorts, const std::map< std::string, std::string > &mapToPorts, const std::map< std::string, std::set< std::map< std::string, std::string >>> &swapPermutations) const
Definition: subcircuit.cc:509
std::map< std::string, std::set< std::string > > compatibleTypes
Definition: subcircuit.cc:716
std::set< BitRef > portBits
Definition: subcircuit.h:43
void createConnection(std::string fromNodeId, std::string fromPortId, int fromBit, std::string toNodeId, std::string toPortId, int toBit, int width=1)
Definition: subcircuit.cc:144
void findNodePairs(std::vector< Solver::MineResult > &results, std::set< NodeSet > &nodePairs, int minNodes, int minMatches, int limitMatchesPerGraph)
Definition: subcircuit.cc:1358
std::map< int, std::set< int > > compatibleConstants
Definition: subcircuit.cc:717
void clearOverlapHistory()
Definition: subcircuit.cc:1685
int extendCandidate(const NodeSet &other) const
Definition: subcircuit.cc:1235
#define NULL
std::string toString() const
Definition: subcircuit.cc:443
std::map< std::string, int > nodeMap
Definition: subcircuit.h:71
DiBit(std::string fromPort, int fromBit, std::string toPort, int toBit)
Definition: subcircuit.cc:400
std::string to_string() const
Definition: subcircuit.cc:1252
std::vector< PortBit > bits
Definition: subcircuit.h:57
std::map< std::string, int > matchesPerGraph
Definition: subcircuit.h:112
void createPort(std::string nodeId, std::string portId, int width=1, int minWidth=-1)
Definition: subcircuit.cc:120
static int numberOfPermutations(const std::vector< std::string > &list)
Definition: subcircuit.cc:321
std::map< std::string, std::set< std::set< std::string > > > swapPorts
Definition: subcircuit.cc:718
bool compareWithToPermutations(const DiEdge &other, const std::map< std::string, std::string > &mapFromPorts, const std::map< std::string, std::string > &mapToPorts, const std::map< std::string, std::set< std::map< std::string, std::string >>> &swapPermutations) const
Definition: subcircuit.cc:522
std::map< DiEdge, int > edgeTypesMap
Definition: subcircuit.cc:658
std::string toString() const
Definition: subcircuit.cc:626
void addSwappablePorts(std::string needleTypeId, const std::set< std::string > &ports)
Definition: subcircuit.cc:1503
bool operator<(const DiEdge &other) const
Definition: subcircuit.cc:461
DiNode(const Graph &graph, int nodeIdx)
Definition: subcircuit.cc:428
NodeSet(std::string graphId, const std::vector< int > &nodes)
Definition: subcircuit.cc:1225
bool matchNodes(const GraphData &needle, int needleNodeIdx, const GraphData &haystack, int haystackNodeIdx) const
Definition: subcircuit.cc:773
std::vector< Port > ports
Definition: subcircuit.h:64
std::map< std::string, ResultNodeMapping > mappings
Definition: subcircuit.h:102
bool operator<(const BitRef &other) const
Definition: subcircuit.cc:98
bool checkEnumerationMatrix(std::vector< std::set< int >> &enumerationMatrix, int i, int j, const GraphData &needle, const GraphData &haystack)
Definition: subcircuit.cc:885
void addCompatibleTypes(std::string needleTypeId, std::string haystackTypeId)
Definition: subcircuit.cc:1637
#define my_printf
Definition: subcircuit.cc:32