30 # define my_printf YOSYS_NAMESPACE_PREFIX log
32 # define my_printf printf
35 using namespace SubCircuit;
45 if (vasprintf(&str, fmt, ap) < 0)
57 # define my_stringf YOSYS_NAMESPACE_PREFIX stringf
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;
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;
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;
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);
101 return nodeIdx < other.
nodeIdx;
103 return portIdx < other.
portIdx;
104 return bitIdx < other.
bitIdx;
109 assert(nodeMap.count(nodeId) == 0);
110 nodeMap[nodeId] = nodes.size();
111 nodes.push_back(
Node());
113 Node &newNode = nodes.back();
122 assert(nodeMap.count(nodeId) != 0);
123 int nodeIdx = nodeMap[nodeId];
124 Node &node = nodes[nodeIdx];
126 assert(node.
portMap.count(portId) == 0);
128 int portIdx = node.
ports.size();
129 node.
portMap[portId] = portIdx;
134 port.
minWidth = minWidth < 0 ? width : minWidth;
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));
146 assert(nodeMap.count(fromNodeId) != 0);
147 assert(nodeMap.count(toNodeId) != 0);
149 int fromNodeIdx = nodeMap[fromNodeId];
150 Node &fromNode = nodes[fromNodeIdx];
152 int toNodeIdx = nodeMap[toNodeId];
153 Node &toNode = nodes[toNodeIdx];
155 assert(fromNode.
portMap.count(fromPortId) != 0);
156 assert(toNode.
portMap.count(toPortId) != 0);
158 int fromPortIdx = fromNode.
portMap[fromPortId];
159 Port &fromPort = fromNode.
ports[fromPortIdx];
161 int toPortIdx = toNode.
portMap[toPortId];
165 assert(fromBit == 0 && toBit == 0);
166 assert(fromPort.
bits.size() == toPort.
bits.size());
167 width = fromPort.
bits.size();
170 assert(fromBit >= 0 && toBit >= 0);
171 for (
int i = 0; i < width; i++)
173 assert(fromBit + i <
int(fromPort.
bits.size()));
174 assert(toBit + i <
int(toPort.
bits.size()));
176 int fromEdgeIdx = fromPort.
bits[fromBit + i].edgeIdx;
177 int toEdgeIdx = toPort.
bits[toBit + i].edgeIdx;
179 if (fromEdgeIdx == toEdgeIdx)
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;
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;
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;
206 createConnection(fromNodeId, fromPortId, 0, toNodeId, toPortId, 0, -1);
211 assert(nodeMap.count(toNodeId) != 0);
212 int toNodeIdx = nodeMap[toNodeId];
213 Node &toNode = nodes[toNodeIdx];
215 assert(toNode.
portMap.count(toPortId) != 0);
216 int toPortIdx = toNode.
portMap[toPortId];
219 assert(toBit >= 0 && toBit <
int(toPort.
bits.size()));
220 int toEdgeIdx = toPort.
bits[toBit].edgeIdx;
222 assert(edges[toEdgeIdx].constValue == 0);
223 edges[toEdgeIdx].constValue = constValue;
228 assert(nodeMap.count(toNodeId) != 0);
229 int toNodeIdx = nodeMap[toNodeId];
230 Node &toNode = nodes[toNodeIdx];
232 assert(toNode.
portMap.count(toPortId) != 0);
233 int toPortIdx = toNode.
portMap[toPortId];
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;
246 assert(nodeMap.count(nodeId) != 0);
247 Node &node = nodes[nodeMap[nodeId]];
249 assert(node.portMap.count(portId) != 0);
250 Port &port = node.ports[node.portMap[portId]];
253 for (
const auto portBit : port.bits)
254 edges[portBit.edgeIdx].isExtern =
true;
256 assert(bit <
int(port.bits.size()));
257 edges[port.bits[bit].edgeIdx].isExtern =
true;
268 for (
int i = 0; i < int(nodes.size()); i++) {
269 const Node &node = nodes[i];
271 for (
int j = 0; j < int(node.
ports.size()); j++) {
274 for (
int k = 0; k < int(port.
bits.size()); k++) {
275 int edgeIdx = port.
bits[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)
303 for (
int i = 0; i < int(matrix.size()); i++)
306 for (
int i = 0; i < int(matrix.size()); i++) {
308 for (
int j = 0; j < int(matrix.size()); j++)
309 if (matrix.at(i).count(j) == 0)
323 int numPermutations = 1;
324 for (
int i = 0; i < int(list.size()); i++) {
326 numPermutations *= i+1;
328 return numPermutations;
335 std::vector<int> factoradicDigits;
336 for (
int i = 0; i < int(list.size()); i++) {
337 factoradicDigits.push_back(idx % (i+1));
343 std::vector<std::string> pool = list;
344 std::vector<std::string> permutation;
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);
355 for (
int i = 0; i < int(list.size()); i++)
356 map[list[i]] = permutation[i];
361 int numPermutations = 1;
362 for (
const auto &it : list) {
365 numPermutations *= thisPermutations;
367 return numPermutations;
372 for (
const auto &it : list) {
374 int thisIdx = idx % thisPermutations;
376 idx /= thisPermutations;
380 static void applyPermutation(std::map<std::string, std::string> &map,
const std::map<std::string, std::string> &permutation)
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)));
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;
432 for (
const auto &port : node.
ports)
433 portSizes[port.portId] = port.bits.size();
446 bool firstPort =
true;
448 str +=
my_stringf(
"%s%s[%d]", firstPort ?
"" :
",", it.first.c_str(), it.second);
451 return typeId +
"(" + str +
")";
472 bool compare(
const DiEdge &other,
const std::map<std::string, std::string> &mapFromPorts,
const std::map<std::string, std::string> &mapToPorts)
const
485 for (
auto bit :
bits)
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);
502 if (other.
bits.count(bit) == 0)
510 const std::map<std::string, std::set<std::map<std::string, std::string>>> &
swapPermutations)
const
514 std::map<std::string, std::string> thisMapFromPorts = mapFromPorts;
523 const std::map<std::string, std::set<std::map<std::string, std::string>>> &
swapPermutations)
const
527 std::map<std::string, std::string> thisMapToPorts = mapToPorts;
529 if (
compare(other, mapFromPorts, thisMapToPorts))
532 return compare(other, mapFromPorts, mapToPorts);
536 const std::map<std::string, std::set<std::map<std::string, std::string>>> &
swapPermutations)
const
540 std::vector<std::vector<std::string>> swapFromPorts;
541 std::vector<std::vector<std::string>> swapToPorts;
547 for (
const auto &bit :
bits)
548 if (ports.count(bit.fromPort))
549 goto foundFromPortMatch;
552 std::vector<std::string> portsVector;
553 for (
const auto &port : ports)
554 portsVector.push_back(port);
555 swapFromPorts.push_back(portsVector);
561 for (
const auto &bit :
bits)
562 if (ports.count(bit.toPort))
563 goto foundToPortMatch;
566 std::vector<std::string> portsVector;
567 for (
const auto &port : ports)
568 portsVector.push_back(port);
569 swapToPorts.push_back(portsVector);
575 std::map<std::string, std::string> mapFromPorts, mapToPorts;
579 for (
int i = 0; i < fromPortsPermutations; i++)
583 for (
int j = 0; j < toPortsPermutations; j++) {
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
598 std::vector<std::vector<std::string>> swapToPorts;
602 for (
const auto &bit :
bits)
603 if (ports.count(bit.toPort))
604 goto foundToPortMatch;
607 std::vector<std::string> portsVector;
608 for (
const auto &port : ports)
609 portsVector.push_back(port);
610 swapToPorts.push_back(portsVector);
614 std::map<std::string, std::string> mapToPorts;
617 for (
int j = 0; j < toPortsPermutations; j++) {
629 for (
const auto &bit :
bits)
630 buffer +=
" " + bit.toString();
639 for (
const auto &edge : graph.
edges) {
640 if (edge.constValue != 0)
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)];
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));
664 std::map<std::pair<int, int>,
DiEdge> edges;
668 adjMatrix.resize(graph.
nodes.size());
670 for (
auto &it : edges) {
676 for (
const auto &it : edges) {
681 adjMatrix[it.first.first][it.first.second] =
edgeTypesMap[it.second];
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)
688 std::pair<int, int> key(needleEdge, haystackEdge);
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
700 bool compare(
int needleEdge,
int haystackEdge,
const std::map<std::string, std::string> &mapFromPorts,
const std::map<std::string, std::string> &mapToPorts)
const
702 return edgeTypes.at(needleEdge).compare(
edgeTypes.at(haystackEdge), mapFromPorts, mapToPorts);
707 for (
int i = 0; i < int(
edgeTypes.size()); i++)
718 std::map<std::string, std::set<std::set<std::string>>>
swapPorts;
725 bool matchNodePorts(
const Graph &needle,
int needleNodeIdx,
const Graph &haystack,
int haystackNodeIdx,
const std::map<std::string, std::string> &swaps)
const
731 for (
int i = 0; i < int(nn.
ports.size()); i++)
733 std::string hnPortId = nn.
ports[i].portId;
734 if (swaps.count(hnPortId) > 0)
735 hnPortId = swaps.at(hnPortId);
737 if (hn.
portMap.count(hnPortId) == 0)
746 for (
int j = 0; j < int(hp.
bits.size()); j++)
798 std::map<std::string, std::string> currentCandidate;
800 for (
const auto &port : needle.
graph.
nodes[needleNodeIdx].ports)
801 currentCandidate[port.portId] = port.portId;
811 std::map<std::string, std::string> currentSubCandidate = currentCandidate;
820 std::vector<std::vector<std::string>> thisSwapPorts;
822 std::vector<std::string> portsVector;
823 for (
const auto &port : ports)
824 portsVector.push_back(port);
825 thisSwapPorts.push_back(portsVector);
829 for (
int i = 0; i < thisPermutations; i++)
839 std::map<std::string, std::string> currentSubCandidate = currentCandidate;
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);
857 enumerationMatrix.clear();
858 enumerationMatrix.resize(needle.
graph.
nodes.size());
859 for (
int i = 0; i < int(needle.
graph.
nodes.size()); i++)
863 for (
int j : haystackNodesByTypeId[nn.
typeId]) {
865 if (initialMappings.count(nn.
nodeId) > 0 && initialMappings.at(nn.
nodeId).count(hn.
nodeId) == 0)
869 enumerationMatrix[i].insert(j);
874 for (
int j : haystackNodesByTypeId[compatibleTypeId]) {
876 if (initialMappings.count(nn.
nodeId) > 0 && initialMappings.at(nn.
nodeId).count(hn.
nodeId) == 0)
880 enumerationMatrix[i].insert(j);
887 for (
const auto &it_needle : needle.
adjMatrix.at(i))
889 int needleNeighbour = it_needle.first;
890 int needleEdgeType = it_needle.second;
892 for (
int haystackNeighbour : enumerationMatrix[needleNeighbour])
893 if (haystack.
adjMatrix.at(j).count(haystackNeighbour) > 0) {
894 int haystackEdgeType = haystack.
adjMatrix.at(j).at(haystackNeighbour);
915 bool didSomething =
true;
919 didSomething =
false;
920 for (
int i = 0; i < int(enumerationMatrix.size()); i++) {
921 std::set<int> newRow;
922 for (
int j : enumerationMatrix[i]) {
925 else if (!allowOverlap && haystack.
usedNodes[j])
930 if (newRow.size() == 0)
932 if (newRow.size() >= 2 && (nextRow < 0 || needle.
adjMatrix.at(nextRow).size() < needle.
adjMatrix.at(i).size()))
934 enumerationMatrix[i].swap(newRow);
942 if (maxHaystackNodeIdx < 0) {
943 for (
const auto &it : enumerationMatrix)
945 maxHaystackNodeIdx = std::max(maxHaystackNodeIdx,
idx);
949 for (
int j = 0; j < maxHaystackNodeIdx; j += 5)
953 for (
int i = 0; i < int(enumerationMatrix.size()); i++)
956 for (
int j = 0; j < maxHaystackNodeIdx; j++) {
959 my_printf(
"%c", enumerationMatrix[i].count(j) > 0 ?
'*' :
'.');
967 assert(enumerationMatrix[idx].size() == 1);
968 int idxHaystack = *enumerationMatrix[
idx].begin();
977 for (
const auto &it_needle : needle.
adjMatrix.at(idx))
979 int needleNeighbour = it_needle.first;
980 int needleEdgeType = it_needle.second;
982 assert(enumerationMatrix[needleNeighbour].size() == 1);
983 int haystackNeighbour = *enumerationMatrix[needleNeighbour].begin();
985 assert(haystack.
adjMatrix.at(idxHaystack).count(haystackNeighbour) > 0);
986 int haystackEdgeType = haystack.
adjMatrix.at(idxHaystack).at(haystackNeighbour);
994 void generatePortmapCandidates(std::set<std::map<std::string, std::string>> &portmapCandidates,
const std::vector<std::set<int>> &enumerationMatrix,
997 std::map<std::string, std::string> currentCandidate;
999 for (
const auto &port : needle.
graph.
nodes[idx].ports)
1000 currentCandidate[port.portId] = port.portId;
1005 portmapCandidates.insert(currentCandidate);
1009 std::map<std::string, std::string> currentSubCandidate = currentCandidate;
1012 portmapCandidates.insert(currentSubCandidate);
1017 std::vector<std::vector<std::string>> thisSwapPorts;
1019 std::vector<std::string> portsVector;
1020 for (
const auto &port : ports)
1021 portsVector.push_back(port);
1022 thisSwapPorts.push_back(portsVector);
1026 for (
int i = 0; i < thisPermutations; i++)
1031 portmapCandidates.insert(currentCandidate);
1035 std::map<std::string, std::string> currentSubCandidate = currentCandidate;
1038 portmapCandidates.insert(currentSubCandidate);
1046 bool didSomething =
false;
1050 for (
int i = 0; i < int(needle.
graph.
nodes.size()); i++)
1052 assert(enumerationMatrix[i].size() == 1);
1053 int j = *enumerationMatrix[i].begin();
1055 std::set<std::map<std::string, std::string>> thisCandidates;
1056 portmapCandidates[i].swap(thisCandidates);
1058 for (
const auto &testCandidate : thisCandidates)
1060 for (
const auto &it_needle : needle.
adjMatrix.at(i))
1062 int needleNeighbour = it_needle.first;
1063 int needleEdgeType = it_needle.second;
1065 assert(enumerationMatrix[needleNeighbour].size() == 1);
1066 int haystackNeighbour = *enumerationMatrix[needleNeighbour].begin();
1068 assert(haystack.
adjMatrix.at(j).count(haystackNeighbour) > 0);
1069 int haystackEdgeType = haystack.
adjMatrix.at(j).at(haystackNeighbour);
1071 std::set<std::map<std::string, std::string>> &candidates =
1072 i == needleNeighbour ? thisCandidates : portmapCandidates[needleNeighbour];
1074 for (
const auto &otherCandidate : candidates) {
1075 if (
diCache.
compare(needleEdgeType, haystackEdgeType, testCandidate, otherCandidate))
1079 didSomething =
true;
1080 goto purgeCandidate;
1084 portmapCandidates[i].insert(testCandidate);
1088 if (portmapCandidates[i].size() == 0)
1097 for (
int i = 0; i < int(needle.
graph.
nodes.size()); i++)
1098 if (portmapCandidates[i].size() > 1) {
1100 portmapCandidates[i].erase(--portmapCandidates[i].end());
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)
1119 std::vector<std::set<std::map<std::string, std::string>>> portmapCandidates;
1120 portmapCandidates.resize(enumerationMatrix.size());
1122 for (
int j = 0; j < int(enumerationMatrix.size()); j++) {
1136 for (
int j = 0; j < int(enumerationMatrix.size()); j++) {
1138 int variantCounter = 0;
1139 for (
auto &i2 : portmapCandidates.at(j)) {
1140 my_printf(
"%*s variant %2d:", 6,
"", variantCounter++);
1143 my_printf(
"%s %s -> %s", mapCounter++ ?
"," :
"", i3.first.c_str(), i3.second.c_str());
1149 for (
int j = 0; j < int(enumerationMatrix.size()); j++) {
1150 if (portmapCandidates[j].size() == 0) {
1152 my_printf(
"\nSolution (rejected by portmapper):\n");
1157 result.
mappings[needle.
graph.
nodes[j].nodeId].portMapping = *portmapCandidates[j].begin();
1162 my_printf(
"\nSolution (rejected by userCheckSolution):\n");
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;
1177 results.push_back(result);
1183 my_printf(
"Enumeration Matrix at recursion level %d (%d):\n", iter, i);
1187 std::set<int> activeRow;
1188 enumerationMatrix[i].swap(activeRow);
1190 for (
int j : activeRow)
1193 if (limitResults >= 0 &&
int(results.size()) >= limitResults)
1197 if (!allowOverlap && haystack.
usedNodes[j])
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);
1207 ullmannRecursion(results, nextEnumerationMatrix, iter+1, needle, haystack, allowOverlap, limitResults);
1210 if (!allowOverlap && haystack.
usedNodes[j] && iter > 0)
1222 nodes.insert(node1);
1223 nodes.insert(node2);
1227 for (
int node : nodes)
1228 this->nodes.insert(node);
1232 for (
int node : other.
nodes)
1239 bool intersect =
false;
1240 for (
int node : other.
nodes)
1241 if (
nodes.count(node) > 0)
1245 return intersect ? newNodes : 0;
1253 std::string str =
graphId +
"(";
1255 for (
int node :
nodes) {
1256 str +=
my_stringf(
"%s%d", first ?
"" :
" ", node);
1272 std::vector<std::set<int>> enumerationMatrix;
1273 std::map<std::string, std::set<std::string>> initialMappings;
1277 ullmannRecursion(results, enumerationMatrix, 0, needle, haystack,
true, -1);
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)
1289 std::vector<std::string> needle_nodes;
1290 for (
int nodeIdx : testSet.
nodes)
1291 needle_nodes.push_back(graph.
nodes[nodeIdx].nodeId);
1296 std::vector<Solver::Result> ullmannResults;
1300 std::map<std::string, int> matchesPerGraph;
1301 std::set<NodeSet> thisNodeSetSet;
1303 for (
auto &it : ullmannResults)
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);
1313 if (usedSets.count(resultSet) > 0) {
1320 assert(thisNodeSetSet.count(resultSet) > 0);
1324 if (thisNodeSetSet.count(resultSet) > 0)
1328 usedSets.insert(resultSet);
1329 thisNodeSetSet.insert(resultSet);
1331 matchesPerGraph[it.haystackGraphId]++;
1332 if (limitMatchesPerGraph < 0 || matchesPerGraph[it.haystackGraphId] < limitMatchesPerGraph)
1336 if (matches < minMatches)
1339 if (minNodes <=
int(testSet.
nodes.size()))
1345 for (
int nodeIdx : testSet.
nodes) {
1349 result.
nodes.push_back(resultNode);
1351 results.push_back(result);
1354 nextPool.insert(thisNodeSetSet.begin(), thisNodeSetSet.end());
1358 void findNodePairs(std::vector<Solver::MineResult> &results, std::set<NodeSet> &nodePairs,
int minNodes,
int minMatches,
int limitMatchesPerGraph)
1360 int groupCounter = 0;
1361 std::set<NodeSet> usedPairs;
1365 my_printf(
"\nMining for frequent node pairs:\n");
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))
1371 const std::string &graphId = graph_it.first;
1372 const auto &graph = graph_it.second.graph;
1373 int node2 = adj_it.first;
1378 NodeSet pair(graphId, node1, node2);
1380 if (usedPairs.count(pair) > 0)
1383 int matches =
testForMining(results, usedPairs, nodePairs, pair, graphId, graph, minNodes, minMatches, limitMatchesPerGraph);
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*" :
"");
1389 if (minMatches <= matches)
1394 my_printf(
"Found a total of %d subgraphs in %d groups.\n",
int(nodePairs.size()), groupCounter);
1397 void findNextPool(std::vector<Solver::MineResult> &results, std::set<NodeSet> &pool,
1398 int oldSetSize,
int increment,
int minNodes,
int minMatches,
int limitMatchesPerGraph)
1400 int groupCounter = 0;
1401 std::map<std::string, std::vector<const NodeSet*>> poolPerGraph;
1402 std::set<NodeSet> nextPool;
1404 for (
auto &it : pool)
1405 poolPerGraph[it.graphId].push_back(&it);
1408 my_printf(
"\nMining for frequent subcircuits of size %d using increment %d:\n", oldSetSize+increment, increment);
1411 for (
auto &it : poolPerGraph)
1413 std::map<int, std::set<int>> node2sets;
1414 std::set<NodeSet> usedSets;
1416 for (
int idx = 0;
idx < int(it.second.size());
idx++) {
1417 for (
int node : it.second[
idx]->nodes)
1418 node2sets[node].insert(idx);
1421 for (
int idx1 = 0; idx1 < int(it.second.size()); idx1++, count++)
1423 std::set<int> idx2set;
1425 for (
int node : it.second[idx1]->nodes)
1426 for (
int idx2 : node2sets[node])
1428 idx2set.insert(idx2);
1430 for (
int idx2 : idx2set)
1432 if (it.second[idx1]->extendCandidate(*it.second[idx2]) != increment)
1435 NodeSet mergedSet = *it.second[idx1];
1436 mergedSet.
extend(*it.second[idx2]);
1438 if (usedSets.count(mergedSet) > 0)
1441 const std::string &graphId = it.first;
1442 const auto &graph =
graphData[it.first].graph;
1445 my_printf(
"<%d%%/%d> Found %s[",
int(100*count/pool.size()), oldSetSize+increment, graphId.c_str());
1447 for (
int nodeIdx : mergedSet.
nodes) {
1448 my_printf(
"%s%s", first ?
"" :
",", graph.nodes[nodeIdx].nodeId.c_str());
1454 int matches =
testForMining(results, usedSets, nextPool, mergedSet, graphId, graph, minNodes, minMatches, limitMatchesPerGraph);
1457 my_printf(
" %d%s\n", matches, matches < minMatches ?
" *purge*" :
"");
1459 if (minMatches <= matches)
1465 pool.swap(nextPool);
1468 my_printf(
"Found a total of %d subgraphs in %d groups.\n",
int(pool.size()), groupCounter);
1488 gd.graphId = graphId;
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)
1518 assert(
graphData.count(needleGraphId) > 0);
1519 assert(
graphData.count(haystackGraphId) > 0);
1524 std::vector<std::set<int>> enumerationMatrix;
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());
1536 for (
int i = 0; i < int(haystack.
graph.
nodes.size()); i++)
1540 my_printf(
"Needle Adjecency Matrix:\n");
1544 my_printf(
"Haystack Adjecency Matrix:\n");
1552 my_printf(
"Enumeration Matrix (haystack nodes at column indices):\n");
1557 ullmannRecursion(results, enumerationMatrix, 0, needle, haystack, allowOverlap, maxSolutions > 0 ? results.size() + maxSolutions : -1);
1560 void mine(std::vector<Solver::MineResult> &results,
int minNodes,
int maxNodes,
int minMatches,
int limitMatchesPerGraph)
1562 int nodeSetSize = 2;
1563 std::set<NodeSet> pool;
1564 findNodePairs(results, pool, minNodes, minMatches, limitMatchesPerGraph);
1566 while ((maxNodes < 0 || nodeSetSize < maxNodes) && pool.size() > 0)
1568 int increment = nodeSetSize - 1;
1569 if (nodeSetSize + increment >= minNodes)
1570 increment = minNodes - nodeSetSize;
1571 if (nodeSetSize >= minNodes)
1574 findNextPool(results, pool, nodeSetSize, increment, minNodes, minMatches, limitMatchesPerGraph);
1575 nodeSetSize += increment;
1582 it.second.usedNodes.clear();
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>&)
1604 return std::string();
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*)
1629 worker->setVerbose();
1634 worker->addGraph(graphId, graph);
1639 worker->addCompatibleTypes(needleTypeId, haystackTypeId);
1644 worker->addCompatibleConstants(needleConstant, haystackConstant);
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);
1660 worker->addSwappablePorts(needleTypeId, ports);
1665 worker->addSwappablePortsPermutation(needleTypeId, portMapping);
1668 void SubCircuit::Solver::solve(std::vector<Result> &results, std::string needleGraphId, std::string haystackGraphId,
bool allowOverlap,
int maxSolutions)
1670 std::map<std::string, std::set<std::string>> emptyInitialMapping;
1671 worker->solve(results, needleGraphId, haystackGraphId, emptyInitialMapping, allowOverlap, maxSolutions);
1675 const std::map<std::string, std::set<std::string>> &initialMappings,
bool allowOverlap,
int maxSolutions)
1677 worker->solve(results, needleGraphId, haystackGraphId, initialMappings, allowOverlap, maxSolutions);
1682 worker->mine(results, minNodes, maxNodes, minMatches, limitMatchesPerGraph);
1687 worker->clearOverlapHistory();
1692 worker->clearConfig();
bool compare(int needleEdge, int haystackEdge, const std::map< std::string, std::string > &mapFromPorts, const std::map< std::string, std::string > &mapToPorts) const
bool checkPortmapCandidate(const std::vector< std::set< int >> &enumerationMatrix, const GraphData &needle, const GraphData &haystack, int idx, const std::map< std::string, std::string > ¤tCandidate)
void ullmannRecursion(std::vector< Solver::Result > &results, std::vector< std::set< int >> &enumerationMatrix, int iter, const GraphData &needle, GraphData &haystack, bool allowOverlap, int limitResults)
void clearOverlapHistory()
static void printAdjMatrix(const adjMatrix_t &matrix)
std::map< std::string, std::set< std::map< std::string, std::string > > > swapPermutations
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)
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
virtual std::string userAnnotateEdge(const std::string &graphId, const std::string &fromNodeId, void *fromUserData, const std::string &toNodeId, void *toUserData)
std::vector< Node > nodes
std::map< std::string, int > portMap
void add(const Graph &graph, adjMatrix_t &adjMatrix, const std::string &graphId, Solver *userSolver)
void addGraph(std::string graphId, const Graph &graph)
std::string needleGraphId
static void permutateVectorToMap(std::map< std::string, std::string > &map, const std::vector< std::string > &list, int idx)
void printEnumerationMatrix(const std::vector< std::set< int >> &enumerationMatrix, int maxHaystackNodeIdx=-1) const
SolverWorker(Solver *userSolver)
void mine(std::vector< Solver::MineResult > &results, int minNodes, int maxNodes, int minMatches, int limitMatchesPerGraph)
bool operator<(const NodeSet &other) const
void addCompatibleTypes(std::string needleTypeId, std::string haystackTypeId)
static void permutateVectorToMapArray(std::map< std::string, std::string > &map, const std::vector< std::vector< std::string >> &list, int idx)
std::map< std::pair< int, int >, bool > compareCache
static std::string idx(std::string str)
bool compare(const DiEdge &other, const std::map< std::string, std::string > &mapFromPorts, const std::map< std::string, std::string > &mapToPorts) const
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)
void addSwappablePorts(std::string needleTypeId, std::string portId1, std::string portId2, std::string portId3=std::string(), std::string portId4=std::string())
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)
std::vector< DiEdge > edgeTypes
bool pruneEnumerationMatrix(std::vector< std::set< int >> &enumerationMatrix, const GraphData &needle, const GraphData &haystack, int &nextRow, bool allowOverlap)
NodeSet(std::string graphId, int node1, int node2)
bool operator<(const DiBit &other) const
bool operator<(const DiNode &other) const
void solveForMining(std::vector< Solver::Result > &results, const GraphData &needle)
void addCompatibleConstants(int needleConstant, int haystackConstant)
bool matchNodePorts(const Graph &needle, int needleNodeIdx, const Graph &haystack, int haystackNodeIdx, const std::map< std::string, std::string > &swaps) const
std::map< std::string, int > portSizes
std::string toString() const
std::vector< Edge > edges
static void applyPermutation(std::map< std::string, std::string > &map, const std::map< std::string, std::string > &permutation)
void createNode(std::string nodeId, std::string typeId, void *userData=NULL, bool shared=false)
static int numberOfPermutationsArray(const std::vector< std::vector< std::string >> &list)
std::vector< bool > usedNodes
void solve(std::vector< Result > &results, std::string needleGraphId, std::string haystackGraphId, bool allowOverlap=true, int maxSolutions=-1)
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
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)
static std::string my_stringf(const char *fmt,...)
std::vector< MineResultNode > nodes
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)
virtual bool userCheckSolution(const Result &result)
static void findEdgesInGraph(const Graph &graph, std::map< std::pair< int, int >, DiEdge > &edges)
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)
void createConstant(std::string toNodeId, std::string toPortId, int toBit, int constValue)
void addGraph(std::string graphId, const Graph &graph)
void addCompatibleConstants(int needleConstant, int haystackConstant)
std::vector< std::map< int, int > > adjMatrix_t
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
void addSwappablePortsPermutation(std::string needleTypeId, const std::map< std::string, std::string > &portMapping)
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)
void addSwappablePortsPermutation(std::string needleTypeId, std::map< std::string, std::string > portMapping)
void markExtern(std::string nodeId, std::string portId, int bit=-1)
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
void mine(std::vector< MineResult > &results, int minNodes, int maxNodes, int minMatches, int limitMatchesPerGraph=-1)
void findNextPool(std::vector< Solver::MineResult > &results, std::set< NodeSet > &pool, int oldSetSize, int increment, int minNodes, int minMatches, int limitMatchesPerGraph)
static const int maxPermutationsLimit
std::string haystackNodeId
void extend(const NodeSet &other)
std::map< std::string, GraphData > graphData
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
std::map< std::string, std::set< std::string > > compatibleTypes
std::set< BitRef > portBits
void createConnection(std::string fromNodeId, std::string fromPortId, int fromBit, std::string toNodeId, std::string toPortId, int toBit, int width=1)
void findNodePairs(std::vector< Solver::MineResult > &results, std::set< NodeSet > &nodePairs, int minNodes, int minMatches, int limitMatchesPerGraph)
std::map< int, std::set< int > > compatibleConstants
void printEdgeTypes() const
std::string haystackGraphId
void clearOverlapHistory()
int extendCandidate(const NodeSet &other) const
std::string toString() const
std::map< std::string, int > nodeMap
DiBit(std::string fromPort, int fromBit, std::string toPort, int toBit)
std::string to_string() const
std::vector< PortBit > bits
std::map< std::string, int > matchesPerGraph
void createPort(std::string nodeId, std::string portId, int width=1, int minWidth=-1)
static int numberOfPermutations(const std::vector< std::string > &list)
std::map< std::string, std::set< std::set< std::string > > > swapPorts
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
std::map< DiEdge, int > edgeTypesMap
std::string toString() const
void addSwappablePorts(std::string needleTypeId, const std::set< std::string > &ports)
std::string userAnnotation
bool operator<(const DiEdge &other) const
DiNode(const Graph &graph, int nodeIdx)
NodeSet(std::string graphId, const std::vector< int > &nodes)
bool matchNodes(const GraphData &needle, int needleNodeIdx, const GraphData &haystack, int haystackNodeIdx) const
std::vector< Port > ports
std::map< std::string, ResultNodeMapping > mappings
int totalMatchesAfterLimits
bool operator<(const BitRef &other) const
bool checkEnumerationMatrix(std::vector< std::set< int >> &enumerationMatrix, int i, int j, const GraphData &needle, const GraphData &haystack)
void addCompatibleTypes(std::string needleTypeId, std::string haystackTypeId)