1 /*
2  *  SubCircuit -- An implementation of the Ullmann Subgraph Isomorphism
3  *                algorithm for coarse grain logic networks
4  *
5  *  Copyright (C) 2013  Claire Xenia Wolf <claire@yosyshq.com>
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_
my_stringf(const char * fmt,...)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 
Graph(const Graph & other,const std::vector<std::string> & otherNodes)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 
operator <(const BitRef & other) const98 bool SubCircuit::Graph::BitRef::operator < (const BitRef &other) const
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 
createNode(std::string nodeId,std::string typeId,void * userData,bool shared)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 
createPort(std::string nodeId,std::string portId,int width,int minWidth)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 
createConnection(std::string fromNodeId,std::string fromPortId,int fromBit,std::string toNodeId,std::string toPortId,int toBit,int width)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 
createConnection(std::string fromNodeId,std::string fromPortId,std::string toNodeId,std::string toPortId)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 
createConstant(std::string toNodeId,std::string toPortId,int toBit,int constValue)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 
createConstant(std::string toNodeId,std::string toPortId,int constValue)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 
markExtern(std::string nodeId,std::string portId,int bit)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 
markAllExtern()261 void SubCircuit::Graph::markAllExtern()
262 {
263 	allExtern = true;
264 }
265 
print()266 void SubCircuit::Graph::print()
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 
287 class SubCircuit::SolverWorker
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;
295 		Graph graph;
296 		adjMatrix_t adjMatrix;
297 		std::vector<bool> usedNodes;
298 	};
299 
printAdjMatrix(const adjMatrix_t & matrix)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 constexpr int maxPermutationsLimit = 1000000;
320 
numberOfPermutations(const std::vector<std::string> & list)321 	static int numberOfPermutations(const std::vector<std::string> &list)
322 	{
323 		constexpr size_t mappedPermutationsSize = 10;
324 		constexpr int mappedPermutations[mappedPermutationsSize] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
325 		assert(list.size() < mappedPermutationsSize);
326 		return mappedPermutations[list.size()];
327 	}
328 
permutateVectorToMap(std::map<std::string,std::string> & map,const std::vector<std::string> & list,int idx)329 	static void permutateVectorToMap(std::map<std::string, std::string> &map, const std::vector<std::string> &list, int idx)
330 	{
331 		// convert idx to a list.size() digits factoradic number
332 
333 		std::vector<int> factoradicDigits;
334 		for (int i = 0; i < int(list.size()); i++) {
335 			factoradicDigits.push_back(idx % (i+1));
336 			idx = idx / (i+1);
337 		}
338 
339 		// construct permutation
340 
341 		std::vector<std::string> pool = list;
342 		std::vector<std::string> permutation;
343 
344 		while (!factoradicDigits.empty()) {
345 			int i = factoradicDigits.back();
346 			factoradicDigits.pop_back();
347 			permutation.push_back(pool[i]);
348 			pool.erase(pool.begin() + i);
349 		}
350 
351 		// update map
352 
353 		for (int i = 0; i < int(list.size()); i++)
354 			map[list[i]] = permutation[i];
355 	}
356 
numberOfPermutationsArray(const std::vector<std::vector<std::string>> & list)357 	static int numberOfPermutationsArray(const std::vector<std::vector<std::string>> &list)
358 	{
359 		int numPermutations = 1;
360 		for (const auto &it : list) {
361 			int thisPermutations = numberOfPermutations(it);
362 			assert(float(numPermutations) * float(thisPermutations) < maxPermutationsLimit);
363 			numPermutations *= thisPermutations;
364 		}
365 		return numPermutations;
366 	}
367 
permutateVectorToMapArray(std::map<std::string,std::string> & map,const std::vector<std::vector<std::string>> & list,int idx)368 	static void permutateVectorToMapArray(std::map<std::string, std::string> &map, const std::vector<std::vector<std::string>> &list, int idx)
369 	{
370 		for (const auto &it : list) {
371 			int thisPermutations = numberOfPermutations(it);
372 			int thisIdx = idx % thisPermutations;
373 			permutateVectorToMap(map, it, thisIdx);
374 			idx /= thisPermutations;
375 		}
376 	}
377 
applyPermutation(std::map<std::string,std::string> & map,const std::map<std::string,std::string> & permutation)378 	static void applyPermutation(std::map<std::string, std::string> &map, const std::map<std::string, std::string> &permutation)
379 	{
380 		std::vector<std::pair<std::string, std::string>> changeLog;
381 		for (const auto &it : permutation)
382 			if (map.count(it.second))
383 				changeLog.push_back(std::pair<std::string, std::string>(it.first, map.at(it.second)));
384 			else
385 				changeLog.push_back(std::pair<std::string, std::string>(it.first, it.second));
386 		for (const auto &it : changeLog)
387 			map[it.first] = it.second;
388 	}
389 
390 	// classes for internal digraph representation
391 
392 	struct DiBit
393 	{
394 		std::string fromPort, toPort;
395 		int fromBit, toBit;
396 
DiBitSubCircuit::SolverWorker::DiBit397 		DiBit() : fromPort(), toPort(), fromBit(-1), toBit(-1) { }
DiBitSubCircuit::SolverWorker::DiBit398 		DiBit(std::string fromPort, int fromBit, std::string toPort, int toBit) : fromPort(fromPort), toPort(toPort), fromBit(fromBit), toBit(toBit) { }
399 
operator <SubCircuit::SolverWorker::DiBit400 		bool operator < (const DiBit &other) const
401 		{
402 			if (fromPort != other.fromPort)
403 				return fromPort < other.fromPort;
404 			if (toPort != other.toPort)
405 				return toPort < other.toPort;
406 			if (fromBit != other.fromBit)
407 				return fromBit < other.fromBit;
408 			return toBit < other.toBit;
409 		}
410 
toStringSubCircuit::SolverWorker::DiBit411 		std::string toString() const
412 		{
413 			return my_stringf("%s[%d]:%s[%d]", fromPort.c_str(), fromBit, toPort.c_str(), toBit);
414 		}
415 	};
416 
417 	struct DiNode
418 	{
419 		std::string typeId;
420 		std::map<std::string, int> portSizes;
421 
DiNodeSubCircuit::SolverWorker::DiNode422 		DiNode()
423 		{
424 		}
425 
DiNodeSubCircuit::SolverWorker::DiNode426 		DiNode(const Graph &graph, int nodeIdx)
427 		{
428 			const Graph::Node &node = graph.nodes.at(nodeIdx);
429 			typeId = node.typeId;
430 			for (const auto &port : node.ports)
431 				portSizes[port.portId] = port.bits.size();
432 		}
433 
operator <SubCircuit::SolverWorker::DiNode434 		bool operator < (const DiNode &other) const
435 		{
436 			if (typeId != other.typeId)
437 				return typeId < other.typeId;
438 			return portSizes < other.portSizes;
439 		}
440 
toStringSubCircuit::SolverWorker::DiNode441 		std::string toString() const
442 		{
443 			std::string str;
444 			bool firstPort = true;
445 			for (const auto &it : portSizes) {
446 				str += my_stringf("%s%s[%d]", firstPort ? "" : ",", it.first.c_str(), it.second);
447 				firstPort = false;
448 			}
449 			return typeId + "(" + str + ")";
450 		}
451 	};
452 
453 	struct DiEdge
454 	{
455 		DiNode fromNode, toNode;
456 		std::set<DiBit> bits;
457 		std::string userAnnotation;
458 
operator <SubCircuit::SolverWorker::DiEdge459 		bool operator < (const DiEdge &other) const
460 		{
461 			if (fromNode < other.fromNode || other.fromNode < fromNode)
462 				return fromNode < other.fromNode;
463 			if (toNode < other.toNode || other.toNode < toNode)
464 				return toNode < other.toNode;
465 			if (bits < other.bits || other.bits < bits)
466 				return bits < other.bits;
467 			return userAnnotation < other.userAnnotation;
468 		}
469 
compareSubCircuit::SolverWorker::DiEdge470 		bool compare(const DiEdge &other, const std::map<std::string, std::string> &mapFromPorts, const std::map<std::string, std::string> &mapToPorts) const
471 		{
472 			// Rules for matching edges:
473 			//
474 			// For all bits in the needle edge:
475 			//   - ignore if needle ports don't exist in haystack edge
476 			//   - otherwise: matching bit in haystack edge must exist
477 			//
478 			// There is no need to check in the other direction, as checking
479 			// of the isExtern properties is already performed in node matching.
480 			//
481 			// Note: "this" is needle, "other" is haystack
482 
483 			for (auto bit : bits)
484 			{
485 				if (mapFromPorts.count(bit.fromPort) > 0)
486 					bit.fromPort = mapFromPorts.at(bit.fromPort);
487 				if (mapToPorts.count(bit.toPort) > 0)
488 					bit.toPort = mapToPorts.at(bit.toPort);
489 
490 				if (other.fromNode.portSizes.count(bit.fromPort) == 0)
491 					continue;
492 				if (other.toNode.portSizes.count(bit.toPort) == 0)
493 					continue;
494 
495 				if (bit.fromBit >= other.fromNode.portSizes.at(bit.fromPort))
496 					continue;
497 				if (bit.toBit >= other.toNode.portSizes.at(bit.toPort))
498 					continue;
499 
500 				if (other.bits.count(bit) == 0)
501 					return false;
502 			}
503 
504 			return true;
505 		}
506 
compareWithFromAndToPermutationsSubCircuit::SolverWorker::DiEdge507 		bool compareWithFromAndToPermutations(const DiEdge &other, const std::map<std::string, std::string> &mapFromPorts, const std::map<std::string, std::string> &mapToPorts,
508 				const std::map<std::string, std::set<std::map<std::string, std::string>>> &swapPermutations) const
509 		{
510 			if (swapPermutations.count(fromNode.typeId) > 0)
511 				for (const auto &permutation : swapPermutations.at(fromNode.typeId)) {
512 					std::map<std::string, std::string> thisMapFromPorts = mapFromPorts;
513 					applyPermutation(thisMapFromPorts, permutation);
514 					if (compareWithToPermutations(other, thisMapFromPorts, mapToPorts, swapPermutations))
515 						return true;
516 				}
517 			return compareWithToPermutations(other, mapFromPorts, mapToPorts, swapPermutations);
518 		}
519 
compareWithToPermutationsSubCircuit::SolverWorker::DiEdge520 		bool compareWithToPermutations(const DiEdge &other, const std::map<std::string, std::string> &mapFromPorts, const std::map<std::string, std::string> &mapToPorts,
521 				const std::map<std::string, std::set<std::map<std::string, std::string>>> &swapPermutations) const
522 		{
523 			if (swapPermutations.count(toNode.typeId) > 0)
524 				for (const auto &permutation : swapPermutations.at(toNode.typeId)) {
525 					std::map<std::string, std::string> thisMapToPorts = mapToPorts;
526 					applyPermutation(thisMapToPorts, permutation);
527 					if (compare(other, mapFromPorts, thisMapToPorts))
528 						return true;
529 				}
530 			return compare(other, mapFromPorts, mapToPorts);
531 		}
532 
compareSubCircuit::SolverWorker::DiEdge533 		bool compare(const DiEdge &other, const std::map<std::string, std::set<std::set<std::string>>> &swapPorts,
534 				const std::map<std::string, std::set<std::map<std::string, std::string>>> &swapPermutations) const
535 		{
536 			// brute force method for port swapping: try all variations
537 
538 			std::vector<std::vector<std::string>> swapFromPorts;
539 			std::vector<std::vector<std::string>> swapToPorts;
540 
541 			// only use groups that are relevant for this edge
542 
543 			if (swapPorts.count(fromNode.typeId) > 0)
544 				for (const auto &ports : swapPorts.at(fromNode.typeId)) {
545 					for (const auto &bit : bits)
546 						if (ports.count(bit.fromPort))
547 							goto foundFromPortMatch;
548 					if (0) {
549 				foundFromPortMatch:
550 						std::vector<std::string> portsVector;
551 						for (const auto &port : ports)
552 							portsVector.push_back(port);
553 						swapFromPorts.push_back(portsVector);
554 					}
555 				}
556 
557 			if (swapPorts.count(toNode.typeId) > 0)
558 				for (const auto &ports : swapPorts.at(toNode.typeId)) {
559 					for (const auto &bit : bits)
560 						if (ports.count(bit.toPort))
561 							goto foundToPortMatch;
562 					if (0) {
563 				foundToPortMatch:
564 						std::vector<std::string> portsVector;
565 						for (const auto &port : ports)
566 							portsVector.push_back(port);
567 						swapToPorts.push_back(portsVector);
568 					}
569 				}
570 
571 			// try all permutations
572 
573 			std::map<std::string, std::string> mapFromPorts, mapToPorts;
574 			int fromPortsPermutations = numberOfPermutationsArray(swapFromPorts);
575 			int toPortsPermutations = numberOfPermutationsArray(swapToPorts);
576 
577 			for (int i = 0; i < fromPortsPermutations; i++)
578 			{
579 				permutateVectorToMapArray(mapFromPorts, swapFromPorts, i);
580 
581 				for (int j = 0; j < toPortsPermutations; j++) {
582 					permutateVectorToMapArray(mapToPorts, swapToPorts, j);
583 					if (compareWithFromAndToPermutations(other, mapFromPorts, mapToPorts, swapPermutations))
584 						return true;
585 				}
586 			}
587 
588 			return false;
589 		}
590 
compareSubCircuit::SolverWorker::DiEdge591 		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,
592 				const std::map<std::string, std::set<std::map<std::string, std::string>>> &swapPermutations) const
593 		{
594 			// strip-down version of the last function: only try permutations for mapToPorts, mapFromPorts is already provided by the caller
595 
596 			std::vector<std::vector<std::string>> swapToPorts;
597 
598 			if (swapPorts.count(toNode.typeId) > 0)
599 				for (const auto &ports : swapPorts.at(toNode.typeId)) {
600 					for (const auto &bit : bits)
601 						if (ports.count(bit.toPort))
602 							goto foundToPortMatch;
603 					if (0) {
604 				foundToPortMatch:
605 						std::vector<std::string> portsVector;
606 						for (const auto &port : ports)
607 							portsVector.push_back(port);
608 						swapToPorts.push_back(portsVector);
609 					}
610 				}
611 
612 			std::map<std::string, std::string> mapToPorts;
613 			int toPortsPermutations = numberOfPermutationsArray(swapToPorts);
614 
615 			for (int j = 0; j < toPortsPermutations; j++) {
616 				permutateVectorToMapArray(mapToPorts, swapToPorts, j);
617 				if (compareWithToPermutations(other, mapFromPorts, mapToPorts, swapPermutations))
618 					return true;
619 			}
620 
621 			return false;
622 		}
623 
toStringSubCircuit::SolverWorker::DiEdge624 		std::string toString() const
625 		{
626 			std::string buffer = fromNode.toString() + " " + toNode.toString();
627 			for (const auto &bit : bits)
628 				buffer += " " + bit.toString();
629 			if (!userAnnotation.empty())
630 				buffer += " " + userAnnotation;
631 			return buffer;
632 		}
633 
findEdgesInGraphSubCircuit::SolverWorker::DiEdge634 		static void findEdgesInGraph(const Graph &graph, std::map<std::pair<int, int>, DiEdge> &edges)
635 		{
636 			edges.clear();
637 			for (const auto &edge : graph.edges) {
638 				if (edge.constValue != 0)
639 					continue;
640 				for (const auto &fromBit : edge.portBits)
641 				for (const auto &toBit : edge.portBits)
642 					if (&fromBit != &toBit) {
643 						DiEdge &de = edges[std::pair<int, int>(fromBit.nodeIdx, toBit.nodeIdx)];
644 						de.fromNode = DiNode(graph, fromBit.nodeIdx);
645 						de.toNode = DiNode(graph, toBit.nodeIdx);
646 						std::string fromPortId = graph.nodes[fromBit.nodeIdx].ports[fromBit.portIdx].portId;
647 						std::string toPortId = graph.nodes[toBit.nodeIdx].ports[toBit.portIdx].portId;
648 						de.bits.insert(DiBit(fromPortId, fromBit.bitIdx, toPortId, toBit.bitIdx));
649 					}
650 			}
651 		}
652 	};
653 
654 	struct DiCache
655 	{
656 		std::map<DiEdge, int> edgeTypesMap;
657 		std::vector<DiEdge> edgeTypes;
658 		std::map<std::pair<int, int>, bool> compareCache;
659 
addSubCircuit::SolverWorker::DiCache660 		void add(const Graph &graph, adjMatrix_t &adjMatrix, const std::string &graphId, Solver *userSolver)
661 		{
662 			std::map<std::pair<int, int>, DiEdge> edges;
663 			DiEdge::findEdgesInGraph(graph, edges);
664 
665 			adjMatrix.clear();
666 			adjMatrix.resize(graph.nodes.size());
667 
668 			for (auto &it : edges) {
669 				const Graph::Node &fromNode = graph.nodes[it.first.first];
670 				const Graph::Node &toNode = graph.nodes[it.first.second];
671 				it.second.userAnnotation = userSolver->userAnnotateEdge(graphId, fromNode.nodeId, fromNode.userData, toNode.nodeId, toNode.userData);
672 			}
673 
674 			for (const auto &it : edges) {
675 				if (edgeTypesMap.count(it.second) == 0) {
676 					edgeTypesMap[it.second] = edgeTypes.size();
677 					edgeTypes.push_back(it.second);
678 				}
679 				adjMatrix[it.first.first][it.first.second] = edgeTypesMap[it.second];
680 			}
681 		}
682 
compareSubCircuit::SolverWorker::DiCache683 		bool compare(int needleEdge, int haystackEdge, const std::map<std::string, std::set<std::set<std::string>>> &swapPorts,
684 				const std::map<std::string, std::set<std::map<std::string, std::string>>> &swapPermutations)
685 		{
686 			std::pair<int, int> key(needleEdge, haystackEdge);
687 			if (!compareCache.count(key))
688 				compareCache[key] = edgeTypes.at(needleEdge).compare(edgeTypes.at(haystackEdge), swapPorts, swapPermutations);
689 			return compareCache[key];
690 		}
691 
compareSubCircuit::SolverWorker::DiCache692 		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,
693 				const std::map<std::string, std::set<std::map<std::string, std::string>>> &swapPermutations) const
694 		{
695 			return edgeTypes.at(needleEdge).compare(edgeTypes.at(haystackEdge), mapFromPorts, swapPorts, swapPermutations);
696 		}
697 
compareSubCircuit::SolverWorker::DiCache698 		bool compare(int needleEdge, int haystackEdge, const std::map<std::string, std::string> &mapFromPorts, const std::map<std::string, std::string> &mapToPorts) const
699 		{
700 			return edgeTypes.at(needleEdge).compare(edgeTypes.at(haystackEdge), mapFromPorts, mapToPorts);
701 		}
702 
printEdgeTypesSubCircuit::SolverWorker::DiCache703 		void printEdgeTypes() const
704 		{
705 			for (int i = 0; i < int(edgeTypes.size()); i++)
706 				my_printf("%5d: %s\n", i, edgeTypes[i].toString().c_str());
707 		}
708 	};
709 
710 	// solver state variables
711 
712 	Solver *userSolver;
713 	std::map<std::string, GraphData> graphData;
714 	std::map<std::string, std::set<std::string>> compatibleTypes;
715 	std::map<int, std::set<int>> compatibleConstants;
716 	std::map<std::string, std::set<std::set<std::string>>> swapPorts;
717 	std::map<std::string, std::set<std::map<std::string, std::string>>> swapPermutations;
718 	DiCache diCache;
719 	bool verbose;
720 
721 	// main solver functions
722 
matchNodePorts(const Graph & needle,int needleNodeIdx,const Graph & haystack,int haystackNodeIdx,const std::map<std::string,std::string> & swaps) const723 	bool matchNodePorts(const Graph &needle, int needleNodeIdx, const Graph &haystack, int haystackNodeIdx, const std::map<std::string, std::string> &swaps) const
724 	{
725 		const Graph::Node &nn = needle.nodes[needleNodeIdx];
726 		const Graph::Node &hn = haystack.nodes[haystackNodeIdx];
727 		assert(nn.ports.size() == hn.ports.size());
728 
729 		for (int i = 0; i < int(nn.ports.size()); i++)
730 		{
731 			std::string hnPortId = nn.ports[i].portId;
732 			if (swaps.count(hnPortId) > 0)
733 				hnPortId = swaps.at(hnPortId);
734 
735 			if (hn.portMap.count(hnPortId) == 0)
736 				return false;
737 
738 			const Graph::Port &np = nn.ports[i];
739 			const Graph::Port &hp = hn.ports[hn.portMap.at(hnPortId)];
740 
741 			if (int(hp.bits.size()) < np.minWidth || hp.bits.size() > np.bits.size())
742 				return false;
743 
744 			for (int j = 0; j < int(hp.bits.size()); j++)
745 			{
746 				const Graph::Edge &ne = needle.edges[np.bits[j].edgeIdx];
747 				const Graph::Edge &he = haystack.edges[hp.bits[j].edgeIdx];
748 
749 				if (ne.constValue || he.constValue) {
750 					if (ne.constValue != he.constValue)
751 						if (compatibleConstants.count(ne.constValue) == 0 || compatibleConstants.at(ne.constValue).count(he.constValue) == 0)
752 							return false;
753 					continue;
754 				}
755 
756 				if (ne.isExtern || needle.allExtern) {
757 					if (he.portBits.size() < ne.portBits.size())
758 						return false;
759 				} else {
760 					if (he.portBits.size() != ne.portBits.size())
761 						return false;
762 					if (he.isExtern || haystack.allExtern)
763 						return false;
764 				}
765 			}
766 		}
767 
768 		return true;
769 	}
770 
matchNodes(const GraphData & needle,int needleNodeIdx,const GraphData & haystack,int haystackNodeIdx) const771 	bool matchNodes(const GraphData &needle, int needleNodeIdx, const GraphData &haystack, int haystackNodeIdx) const
772 	{
773 		// Rules for matching nodes:
774 		//
775 		// 1. their typeId must be identical or compatible
776 		//    (this is checked before calling this function)
777 		//
778 		// 2. they must have the same ports and the haystack port
779 		//    widths must match the needle port width range
780 		//
781 		// 3. All edges from the needle must match the haystack:
782 		//    a) if the needle edge is extern:
783 		//         - the haystack edge must have at least as many components as the needle edge
784 		//    b) if the needle edge is not extern:
785 		//         - the haystack edge must have the same number of components as the needle edge
786 		//         - the haystack edge must not be extern
787 
788 		const Graph::Node &nn = needle.graph.nodes[needleNodeIdx];
789 		const Graph::Node &hn = haystack.graph.nodes[haystackNodeIdx];
790 
791 		assert(nn.typeId == hn.typeId || (compatibleTypes.count(nn.typeId) > 0 && compatibleTypes.at(nn.typeId).count(hn.typeId) > 0));
792 
793 		if (nn.ports.size() != hn.ports.size())
794 			return false;
795 
796 		std::map<std::string, std::string> currentCandidate;
797 
798 		for (const auto &port : needle.graph.nodes[needleNodeIdx].ports)
799 			currentCandidate[port.portId] = port.portId;
800 
801 		if (swapPorts.count(needle.graph.nodes[needleNodeIdx].typeId) == 0)
802 		{
803 			if (matchNodePorts(needle.graph, needleNodeIdx, haystack.graph, haystackNodeIdx, currentCandidate) &&
804 					userSolver->userCompareNodes(needle.graphId, nn.nodeId, nn.userData, haystack.graphId, hn.nodeId, hn.userData, currentCandidate))
805 				return true;
806 
807 			if (swapPermutations.count(needle.graph.nodes[needleNodeIdx].typeId) > 0)
808 				for (const auto &permutation : swapPermutations.at(needle.graph.nodes[needleNodeIdx].typeId)) {
809 					std::map<std::string, std::string> currentSubCandidate = currentCandidate;
810 					applyPermutation(currentSubCandidate, permutation);
811 					if (matchNodePorts(needle.graph, needleNodeIdx, haystack.graph, haystackNodeIdx, currentCandidate) &&
812 							userSolver->userCompareNodes(needle.graphId, nn.nodeId, nn.userData, haystack.graphId, hn.nodeId, hn.userData, currentCandidate))
813 						return true;
814 				}
815 		}
816 		else
817 		{
818 			std::vector<std::vector<std::string>> thisSwapPorts;
819 			for (const auto &ports : swapPorts.at(needle.graph.nodes[needleNodeIdx].typeId)) {
820 				std::vector<std::string> portsVector;
821 				for (const auto &port : ports)
822 					portsVector.push_back(port);
823 				thisSwapPorts.push_back(portsVector);
824 			}
825 
826 			int thisPermutations = numberOfPermutationsArray(thisSwapPorts);
827 			for (int i = 0; i < thisPermutations; i++)
828 			{
829 				permutateVectorToMapArray(currentCandidate, thisSwapPorts, i);
830 
831 				if (matchNodePorts(needle.graph, needleNodeIdx, haystack.graph, haystackNodeIdx, currentCandidate) &&
832 						userSolver->userCompareNodes(needle.graphId, nn.nodeId, nn.userData, haystack.graphId, hn.nodeId, hn.userData, currentCandidate))
833 					return true;
834 
835 				if (swapPermutations.count(needle.graph.nodes[needleNodeIdx].typeId) > 0)
836 					for (const auto &permutation : swapPermutations.at(needle.graph.nodes[needleNodeIdx].typeId)) {
837 						std::map<std::string, std::string> currentSubCandidate = currentCandidate;
838 						applyPermutation(currentSubCandidate, permutation);
839 						if (matchNodePorts(needle.graph, needleNodeIdx, haystack.graph, haystackNodeIdx, currentCandidate) &&
840 								userSolver->userCompareNodes(needle.graphId, nn.nodeId, nn.userData, haystack.graphId, hn.nodeId, hn.userData, currentCandidate))
841 							return true;
842 					}
843 			}
844 		}
845 
846 		return false;
847 	}
848 
generateEnumerationMatrix(std::vector<std::set<int>> & enumerationMatrix,const GraphData & needle,const GraphData & haystack,const std::map<std::string,std::set<std::string>> & initialMappings) const849 	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
850 	{
851 		std::map<std::string, std::set<int>> haystackNodesByTypeId;
852 		for (int i = 0; i < int(haystack.graph.nodes.size()); i++)
853 			haystackNodesByTypeId[haystack.graph.nodes[i].typeId].insert(i);
854 
855 		enumerationMatrix.clear();
856 		enumerationMatrix.resize(needle.graph.nodes.size());
857 		for (int i = 0; i < int(needle.graph.nodes.size()); i++)
858 		{
859 			const Graph::Node &nn = needle.graph.nodes[i];
860 
861 			for (int j : haystackNodesByTypeId[nn.typeId]) {
862 				const Graph::Node &hn = haystack.graph.nodes[j];
863 				if (initialMappings.count(nn.nodeId) > 0 && initialMappings.at(nn.nodeId).count(hn.nodeId) == 0)
864 					continue;
865 				if (!matchNodes(needle, i, haystack, j))
866 					continue;
867 				enumerationMatrix[i].insert(j);
868 			}
869 
870 			if (compatibleTypes.count(nn.typeId) > 0)
871 				for (const std::string &compatibleTypeId : compatibleTypes.at(nn.typeId))
872 					for (int j : haystackNodesByTypeId[compatibleTypeId]) {
873 						const Graph::Node &hn = haystack.graph.nodes[j];
874 						if (initialMappings.count(nn.nodeId) > 0 && initialMappings.at(nn.nodeId).count(hn.nodeId) == 0)
875 							continue;
876 						if (!matchNodes(needle, i, haystack, j))
877 							continue;
878 						enumerationMatrix[i].insert(j);
879 					}
880 		}
881 	}
882 
checkEnumerationMatrix(std::vector<std::set<int>> & enumerationMatrix,int i,int j,const GraphData & needle,const GraphData & haystack)883 	bool checkEnumerationMatrix(std::vector<std::set<int>> &enumerationMatrix, int i, int j, const GraphData &needle, const GraphData &haystack)
884 	{
885 		for (const auto &it_needle : needle.adjMatrix.at(i))
886 		{
887 			int needleNeighbour = it_needle.first;
888 			int needleEdgeType = it_needle.second;
889 
890 			for (int haystackNeighbour : enumerationMatrix[needleNeighbour])
891 				if (haystack.adjMatrix.at(j).count(haystackNeighbour) > 0) {
892 					int haystackEdgeType = haystack.adjMatrix.at(j).at(haystackNeighbour);
893 					if (diCache.compare(needleEdgeType, haystackEdgeType, swapPorts, swapPermutations)) {
894 						const Graph::Node &needleFromNode = needle.graph.nodes[i];
895 						const Graph::Node &needleToNode = needle.graph.nodes[needleNeighbour];
896 						const Graph::Node &haystackFromNode = haystack.graph.nodes[j];
897 						const Graph::Node &haystackToNode = haystack.graph.nodes[haystackNeighbour];
898 						if (userSolver->userCompareEdge(needle.graphId, needleFromNode.nodeId,  needleFromNode.userData, needleToNode.nodeId,  needleToNode.userData,
899 								haystack.graphId, haystackFromNode.nodeId, haystackFromNode.userData, haystackToNode.nodeId, haystackToNode.userData))
900 							goto found_match;
901 					}
902 				}
903 
904 			return false;
905 		found_match:;
906 		}
907 
908 		return true;
909 	}
910 
pruneEnumerationMatrix(std::vector<std::set<int>> & enumerationMatrix,const GraphData & needle,const GraphData & haystack,int & nextRow,bool allowOverlap)911 	bool pruneEnumerationMatrix(std::vector<std::set<int>> &enumerationMatrix, const GraphData &needle, const GraphData &haystack, int &nextRow, bool allowOverlap)
912 	{
913 		bool didSomething = true;
914 		while (didSomething)
915 		{
916 			nextRow = -1;
917 			didSomething = false;
918 			for (int i = 0; i < int(enumerationMatrix.size()); i++) {
919 				std::set<int> newRow;
920 				for (int j : enumerationMatrix[i]) {
921 					if (!checkEnumerationMatrix(enumerationMatrix, i, j, needle, haystack))
922 						didSomething = true;
923 					else if (!allowOverlap && haystack.usedNodes[j])
924 						didSomething = true;
925 					else
926 						newRow.insert(j);
927 				}
928 				if (newRow.size() == 0)
929 					return false;
930 				if (newRow.size() >= 2 && (nextRow < 0 || needle.adjMatrix.at(nextRow).size() < needle.adjMatrix.at(i).size()))
931 					nextRow = i;
932 				enumerationMatrix[i].swap(newRow);
933 			}
934 		}
935 		return true;
936 	}
937 
printEnumerationMatrix(const std::vector<std::set<int>> & enumerationMatrix,int maxHaystackNodeIdx=-1) const938 	void printEnumerationMatrix(const std::vector<std::set<int>> &enumerationMatrix, int maxHaystackNodeIdx = -1) const
939 	{
940 		if (maxHaystackNodeIdx < 0) {
941 			for (const auto &it : enumerationMatrix)
942 				for (int idx : it)
943 					maxHaystackNodeIdx = std::max(maxHaystackNodeIdx, idx);
944 		}
945 
946 		my_printf("       ");
947 		for (int j = 0; j < maxHaystackNodeIdx; j += 5)
948 			my_printf("%-6d", j);
949 		my_printf("\n");
950 
951 		for (int i = 0; i < int(enumerationMatrix.size()); i++)
952 		{
953 			my_printf("%5d:", i);
954 			for (int j = 0; j < maxHaystackNodeIdx; j++) {
955 				if (j % 5 == 0)
956 					my_printf(" ");
957 				my_printf("%c", enumerationMatrix[i].count(j) > 0 ? '*' : '.');
958 			}
959 			my_printf("\n");
960 		}
961 	}
962 
checkPortmapCandidate(const std::vector<std::set<int>> & enumerationMatrix,const GraphData & needle,const GraphData & haystack,int idx,const std::map<std::string,std::string> & currentCandidate)963 	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)
964 	{
965 		assert(enumerationMatrix[idx].size() == 1);
966 		int idxHaystack = *enumerationMatrix[idx].begin();
967 
968 		const Graph::Node &nn = needle.graph.nodes[idx];
969 		const Graph::Node &hn = haystack.graph.nodes[idxHaystack];
970 
971 		if (!matchNodePorts(needle.graph, idx, haystack.graph, idxHaystack, currentCandidate) ||
972 				!userSolver->userCompareNodes(needle.graphId, nn.nodeId, nn.userData, haystack.graphId, hn.nodeId, hn.userData, currentCandidate))
973 			return false;
974 
975 		for (const auto &it_needle : needle.adjMatrix.at(idx))
976 		{
977 			int needleNeighbour = it_needle.first;
978 			int needleEdgeType = it_needle.second;
979 
980 			assert(enumerationMatrix[needleNeighbour].size() == 1);
981 			int haystackNeighbour = *enumerationMatrix[needleNeighbour].begin();
982 
983 			assert(haystack.adjMatrix.at(idxHaystack).count(haystackNeighbour) > 0);
984 			int haystackEdgeType = haystack.adjMatrix.at(idxHaystack).at(haystackNeighbour);
985 			if (!diCache.compare(needleEdgeType, haystackEdgeType, currentCandidate, swapPorts, swapPermutations))
986 				return false;
987 		}
988 
989 		return true;
990 	}
991 
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)992 	void generatePortmapCandidates(std::set<std::map<std::string, std::string>> &portmapCandidates, const std::vector<std::set<int>> &enumerationMatrix,
993 			const GraphData &needle, const GraphData &haystack, int idx)
994 	{
995 		std::map<std::string, std::string> currentCandidate;
996 
997 		for (const auto &port : needle.graph.nodes[idx].ports)
998 			currentCandidate[port.portId] = port.portId;
999 
1000 		if (swapPorts.count(needle.graph.nodes[idx].typeId) == 0)
1001 		{
1002 			if (checkPortmapCandidate(enumerationMatrix, needle, haystack, idx, currentCandidate))
1003 				portmapCandidates.insert(currentCandidate);
1004 
1005 			if (swapPermutations.count(needle.graph.nodes[idx].typeId) > 0)
1006 				for (const auto &permutation : swapPermutations.at(needle.graph.nodes[idx].typeId)) {
1007 					std::map<std::string, std::string> currentSubCandidate = currentCandidate;
1008 					applyPermutation(currentSubCandidate, permutation);
1009 					if (checkPortmapCandidate(enumerationMatrix, needle, haystack, idx, currentSubCandidate))
1010 						portmapCandidates.insert(currentSubCandidate);
1011 				}
1012 		}
1013 		else
1014 		{
1015 			std::vector<std::vector<std::string>> thisSwapPorts;
1016 			for (const auto &ports : swapPorts.at(needle.graph.nodes[idx].typeId)) {
1017 				std::vector<std::string> portsVector;
1018 				for (const auto &port : ports)
1019 					portsVector.push_back(port);
1020 				thisSwapPorts.push_back(portsVector);
1021 			}
1022 
1023 			int thisPermutations = numberOfPermutationsArray(thisSwapPorts);
1024 			for (int i = 0; i < thisPermutations; i++)
1025 			{
1026 				permutateVectorToMapArray(currentCandidate, thisSwapPorts, i);
1027 
1028 				if (checkPortmapCandidate(enumerationMatrix, needle, haystack, idx, currentCandidate))
1029 					portmapCandidates.insert(currentCandidate);
1030 
1031 				if (swapPermutations.count(needle.graph.nodes[idx].typeId) > 0)
1032 					for (const auto &permutation : swapPermutations.at(needle.graph.nodes[idx].typeId)) {
1033 						std::map<std::string, std::string> currentSubCandidate = currentCandidate;
1034 						applyPermutation(currentSubCandidate, permutation);
1035 						if (checkPortmapCandidate(enumerationMatrix, needle, haystack, idx, currentSubCandidate))
1036 							portmapCandidates.insert(currentSubCandidate);
1037 					}
1038 			}
1039 		}
1040 	}
1041 
prunePortmapCandidates(std::vector<std::set<std::map<std::string,std::string>>> & portmapCandidates,std::vector<std::set<int>> enumerationMatrix,const GraphData & needle,const GraphData & haystack)1042 	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)
1043 	{
1044 		bool didSomething = false;
1045 
1046 		// strategy #1: prune impossible port mappings
1047 
1048 		for (int i = 0; i < int(needle.graph.nodes.size()); i++)
1049 		{
1050 			assert(enumerationMatrix[i].size() == 1);
1051 			int j = *enumerationMatrix[i].begin();
1052 
1053 			std::set<std::map<std::string, std::string>> thisCandidates;
1054 			portmapCandidates[i].swap(thisCandidates);
1055 
1056 			for (const auto &testCandidate : thisCandidates)
1057 			{
1058 				for (const auto &it_needle : needle.adjMatrix.at(i))
1059 				{
1060 					int needleNeighbour = it_needle.first;
1061 					int needleEdgeType = it_needle.second;
1062 
1063 					assert(enumerationMatrix[needleNeighbour].size() == 1);
1064 					int haystackNeighbour = *enumerationMatrix[needleNeighbour].begin();
1065 
1066 					assert(haystack.adjMatrix.at(j).count(haystackNeighbour) > 0);
1067 					int haystackEdgeType = haystack.adjMatrix.at(j).at(haystackNeighbour);
1068 
1069 					std::set<std::map<std::string, std::string>> &candidates =
1070 							i == needleNeighbour ? thisCandidates : portmapCandidates[needleNeighbour];
1071 
1072 					for (const auto &otherCandidate : candidates) {
1073 						if (diCache.compare(needleEdgeType, haystackEdgeType, testCandidate, otherCandidate))
1074 							goto found_match;
1075 					}
1076 
1077 					didSomething = true;
1078 					goto purgeCandidate;
1079 				found_match:;
1080 				}
1081 
1082 				portmapCandidates[i].insert(testCandidate);
1083 			purgeCandidate:;
1084 			}
1085 
1086 			if (portmapCandidates[i].size() == 0)
1087 				return false;
1088 		}
1089 
1090 		if (didSomething)
1091 			return true;
1092 
1093 		// strategy #2: prune a single random port mapping
1094 
1095 		for (int i = 0; i < int(needle.graph.nodes.size()); i++)
1096 			if (portmapCandidates[i].size() > 1) {
1097 				// remove last mapping. this keeps ports unswapped in don't-care situations
1098 				portmapCandidates[i].erase(--portmapCandidates[i].end());
1099 				return true;
1100 			}
1101 
1102 		return false;
1103 	}
1104 
ullmannRecursion(std::vector<Solver::Result> & results,std::vector<std::set<int>> & enumerationMatrix,int iter,const GraphData & needle,GraphData & haystack,bool allowOverlap,int limitResults)1105 	void ullmannRecursion(std::vector<Solver::Result> &results, std::vector<std::set<int>> &enumerationMatrix, int iter, const GraphData &needle, GraphData &haystack, bool allowOverlap, int limitResults)
1106 	{
1107 		int i = -1;
1108 		if (!pruneEnumerationMatrix(enumerationMatrix, needle, haystack, i, allowOverlap))
1109 			return;
1110 
1111 		if (i < 0)
1112 		{
1113 			Solver::Result result;
1114 			result.needleGraphId = needle.graphId;
1115 			result.haystackGraphId = haystack.graphId;
1116 
1117 			std::vector<std::set<std::map<std::string, std::string>>> portmapCandidates;
1118 			portmapCandidates.resize(enumerationMatrix.size());
1119 
1120 			for (int j = 0; j < int(enumerationMatrix.size()); j++) {
1121 				Solver::ResultNodeMapping mapping;
1122 				mapping.needleNodeId = needle.graph.nodes[j].nodeId;
1123 				mapping.needleUserData = needle.graph.nodes[j].userData;
1124 				mapping.haystackNodeId = haystack.graph.nodes[*enumerationMatrix[j].begin()].nodeId;
1125 				mapping.haystackUserData = haystack.graph.nodes[*enumerationMatrix[j].begin()].userData;
1126 				generatePortmapCandidates(portmapCandidates[j], enumerationMatrix, needle, haystack, j);
1127 				result.mappings[needle.graph.nodes[j].nodeId] = mapping;
1128 			}
1129 
1130 			while (prunePortmapCandidates(portmapCandidates, enumerationMatrix, needle, haystack)) { }
1131 
1132 			if (verbose) {
1133 				my_printf("\nPortmapper results:\n");
1134 				for (int j = 0; j < int(enumerationMatrix.size()); j++) {
1135 					my_printf("%5d: %s\n", j, needle.graph.nodes[j].nodeId.c_str());
1136 					int variantCounter = 0;
1137 					for (auto &i2 : portmapCandidates.at(j)) {
1138 						my_printf("%*s variant %2d:", 6, "", variantCounter++);
1139 						int mapCounter = 0;
1140 						for (auto &i3 : i2)
1141 							my_printf("%s %s -> %s", mapCounter++ ? "," : "", i3.first.c_str(), i3.second.c_str());
1142 						my_printf("\n");
1143 					}
1144 				}
1145 			}
1146 
1147 			for (int j = 0; j < int(enumerationMatrix.size()); j++) {
1148 				if (portmapCandidates[j].size() == 0) {
1149 					if (verbose) {
1150 						my_printf("\nSolution (rejected by portmapper):\n");
1151 						printEnumerationMatrix(enumerationMatrix, haystack.graph.nodes.size());
1152 					}
1153 					return;
1154 				}
1155 				result.mappings[needle.graph.nodes[j].nodeId].portMapping = *portmapCandidates[j].begin();
1156 			}
1157 
1158 			if (!userSolver->userCheckSolution(result)) {
1159 				if (verbose) {
1160 					my_printf("\nSolution (rejected by userCheckSolution):\n");
1161 					printEnumerationMatrix(enumerationMatrix, haystack.graph.nodes.size());
1162 				}
1163 				return;
1164 			}
1165 
1166 			for (int j = 0; j < int(enumerationMatrix.size()); j++)
1167 				if (!haystack.graph.nodes[*enumerationMatrix[j].begin()].shared)
1168 					haystack.usedNodes[*enumerationMatrix[j].begin()] = true;
1169 
1170 			if (verbose) {
1171 				my_printf("\nSolution:\n");
1172 				printEnumerationMatrix(enumerationMatrix, haystack.graph.nodes.size());
1173 			}
1174 
1175 			results.push_back(result);
1176 			return;
1177 		}
1178 
1179 		if (verbose) {
1180 			my_printf("\n");
1181 			my_printf("Enumeration Matrix at recursion level %d (%d):\n", iter, i);
1182 			printEnumerationMatrix(enumerationMatrix, haystack.graph.nodes.size());
1183 		}
1184 
1185 		std::set<int> activeRow;
1186 		enumerationMatrix[i].swap(activeRow);
1187 
1188 		for (int j : activeRow)
1189 		{
1190 			// found enough?
1191 			if (limitResults >= 0 && int(results.size()) >= limitResults)
1192 				return;
1193 
1194 			// already used by other solution -> try next
1195 			if (!allowOverlap && haystack.usedNodes[j])
1196 				continue;
1197 
1198 			// create enumeration matrix for child in recursion tree
1199 			std::vector<std::set<int>> nextEnumerationMatrix = enumerationMatrix;
1200 			for (int k = 0; k < int(nextEnumerationMatrix.size()); k++)
1201 				nextEnumerationMatrix[k].erase(j);
1202 			nextEnumerationMatrix[i].insert(j);
1203 
1204 			// recursion
1205 			ullmannRecursion(results, nextEnumerationMatrix, iter+1, needle, haystack, allowOverlap, limitResults);
1206 
1207 			// we just have found something -> unroll to top recursion level
1208 			if (!allowOverlap && haystack.usedNodes[j] && iter > 0)
1209 				return;
1210 		}
1211 	}
1212 
1213 	// additional data structes and functions for mining
1214 
1215 	struct NodeSet {
1216 		std::string graphId;
1217 		std::set<int> nodes;
NodeSetSubCircuit::SolverWorker::NodeSet1218 		NodeSet(std::string graphId, int node1, int node2) {
1219 			this->graphId = graphId;
1220 			nodes.insert(node1);
1221 			nodes.insert(node2);
1222 		}
NodeSetSubCircuit::SolverWorker::NodeSet1223 		NodeSet(std::string graphId, const std::vector<int> &nodes) {
1224 			this->graphId = graphId;
1225 			for (int node : nodes)
1226 				this->nodes.insert(node);
1227 		}
extendSubCircuit::SolverWorker::NodeSet1228 		void extend(const NodeSet &other) {
1229 			assert(this->graphId == other.graphId);
1230 			for (int node : other.nodes)
1231 				nodes.insert(node);
1232 		}
extendCandidateSubCircuit::SolverWorker::NodeSet1233 		int extendCandidate(const NodeSet &other) const {
1234 			if (graphId != other.graphId)
1235 				return 0;
1236 			int newNodes = 0;
1237 			bool intersect = false;
1238 			for (int node : other.nodes)
1239 				if (nodes.count(node) > 0)
1240 					intersect = true;
1241 				else
1242 					newNodes++;
1243 			return intersect ? newNodes : 0;
1244 		}
operator <SubCircuit::SolverWorker::NodeSet1245 		bool operator <(const NodeSet &other) const {
1246 			if (graphId != other.graphId)
1247 				return graphId < other.graphId;
1248 			return nodes < other.nodes;
1249 		}
to_stringSubCircuit::SolverWorker::NodeSet1250 		std::string to_string() const {
1251 			std::string str = graphId + "(";
1252 			bool first = true;
1253 			for (int node : nodes) {
1254 				str += my_stringf("%s%d", first ? "" : " ", node);
1255 				first = false;
1256 			}
1257 			return str + ")";
1258 		}
1259 	};
1260 
solveForMining(std::vector<Solver::Result> & results,const GraphData & needle)1261 	void solveForMining(std::vector<Solver::Result> &results, const GraphData &needle)
1262 	{
1263 		bool backupVerbose = verbose;
1264 		verbose = false;
1265 
1266 		for (auto &it : graphData)
1267 		{
1268 			GraphData &haystack = it.second;
1269 
1270 			std::vector<std::set<int>> enumerationMatrix;
1271 			std::map<std::string, std::set<std::string>> initialMappings;
1272 			generateEnumerationMatrix(enumerationMatrix, needle, haystack, initialMappings);
1273 
1274 			haystack.usedNodes.resize(haystack.graph.nodes.size());
1275 			ullmannRecursion(results, enumerationMatrix, 0, needle, haystack, true, -1);
1276 		}
1277 
1278 		verbose = backupVerbose;
1279 	}
1280 
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)1281 	int testForMining(std::vector<Solver::MineResult> &results, std::set<NodeSet> &usedSets, std::set<NodeSet> &nextPool, NodeSet &testSet,
1282 			const std::string &graphId, const Graph &graph, int minNodes, int minMatches, int limitMatchesPerGraph)
1283 	{
1284 		// my_printf("test: %s\n", testSet.to_string().c_str());
1285 
1286 		GraphData needle;
1287 		std::vector<std::string> needle_nodes;
1288 		for (int nodeIdx : testSet.nodes)
1289 			needle_nodes.push_back(graph.nodes[nodeIdx].nodeId);
1290 		needle.graph = Graph(graph, needle_nodes);
1291 		needle.graph.markAllExtern();
1292 		diCache.add(needle.graph, needle.adjMatrix, graphId, userSolver);
1293 
1294 		std::vector<Solver::Result> ullmannResults;
1295 		solveForMining(ullmannResults, needle);
1296 
1297 		int matches = 0;
1298 		std::map<std::string, int> matchesPerGraph;
1299 		std::set<NodeSet> thisNodeSetSet;
1300 
1301 		for (auto &it : ullmannResults)
1302 		{
1303 			std::vector<int> resultNodes;
1304 			for (auto &i2 : it.mappings)
1305 				resultNodes.push_back(graphData[it.haystackGraphId].graph.nodeMap[i2.second.haystackNodeId]);
1306 			NodeSet resultSet(it.haystackGraphId, resultNodes);
1307 
1308 			// my_printf("match: %s%s\n", resultSet.to_string().c_str(), usedSets.count(resultSet) > 0 ? " (dup)" : "");
1309 
1310 #if 0
1311 			if (usedSets.count(resultSet) > 0) {
1312 				// Because of shorted pins isomorphisim is not always bidirectional!
1313 				//
1314 				// This means that the following assert is not true in all cases and subgraph A might
1315 				// show up in the matches for subgraph B but not vice versa... This also means that the
1316 				// order in which subgraphs are processed has an impact on the results set.
1317 				//
1318 				assert(thisNodeSetSet.count(resultSet) > 0);
1319 				continue;
1320 			}
1321 #else
1322 			if (thisNodeSetSet.count(resultSet) > 0)
1323 				continue;
1324 #endif
1325 
1326 			usedSets.insert(resultSet);
1327 			thisNodeSetSet.insert(resultSet);
1328 
1329 			matchesPerGraph[it.haystackGraphId]++;
1330 			if (limitMatchesPerGraph < 0 || matchesPerGraph[it.haystackGraphId] < limitMatchesPerGraph)
1331 				matches++;
1332 		}
1333 
1334 		if (matches < minMatches)
1335 			return matches;
1336 
1337 		if (minNodes <= int(testSet.nodes.size()))
1338 		{
1339 			Solver::MineResult result;
1340 			result.graphId = graphId;
1341 			result.totalMatchesAfterLimits = matches;
1342 			result.matchesPerGraph = matchesPerGraph;
1343 			for (int nodeIdx : testSet.nodes) {
1344 				Solver::MineResultNode resultNode;
1345 				resultNode.nodeId = graph.nodes[nodeIdx].nodeId;
1346 				resultNode.userData = graph.nodes[nodeIdx].userData;
1347 				result.nodes.push_back(resultNode);
1348 			}
1349 			results.push_back(result);
1350 		}
1351 
1352 		nextPool.insert(thisNodeSetSet.begin(), thisNodeSetSet.end());
1353 		return matches;
1354 	}
1355 
findNodePairs(std::vector<Solver::MineResult> & results,std::set<NodeSet> & nodePairs,int minNodes,int minMatches,int limitMatchesPerGraph)1356 	void findNodePairs(std::vector<Solver::MineResult> &results, std::set<NodeSet> &nodePairs, int minNodes, int minMatches, int limitMatchesPerGraph)
1357 	{
1358 		int groupCounter = 0;
1359 		std::set<NodeSet> usedPairs;
1360 		nodePairs.clear();
1361 
1362 		if (verbose)
1363 			my_printf("\nMining for frequent node pairs:\n");
1364 
1365 		for (auto &graph_it : graphData)
1366 		for (int node1 = 0; node1 < int(graph_it.second.graph.nodes.size()); node1++)
1367 		for (auto &adj_it : graph_it.second.adjMatrix.at(node1))
1368 		{
1369 			const std::string &graphId = graph_it.first;
1370 			const auto &graph = graph_it.second.graph;
1371 			int node2 = adj_it.first;
1372 
1373 			if (node1 == node2)
1374 				continue;
1375 
1376 			NodeSet pair(graphId, node1, node2);
1377 
1378 			if (usedPairs.count(pair) > 0)
1379 				continue;
1380 
1381 			int matches = testForMining(results, usedPairs, nodePairs, pair, graphId, graph, minNodes, minMatches, limitMatchesPerGraph);
1382 
1383 			if (verbose)
1384 				my_printf("Pair %s[%s,%s] -> %d%s\n", graphId.c_str(), graph.nodes[node1].nodeId.c_str(),
1385 						graph.nodes[node2].nodeId.c_str(), matches, matches < minMatches ? "  *purge*" : "");
1386 
1387 			if (minMatches <= matches)
1388 				groupCounter++;
1389 		}
1390 
1391 		if (verbose)
1392 			my_printf("Found a total of %d subgraphs in %d groups.\n", int(nodePairs.size()), groupCounter);
1393 	}
1394 
findNextPool(std::vector<Solver::MineResult> & results,std::set<NodeSet> & pool,int oldSetSize,int increment,int minNodes,int minMatches,int limitMatchesPerGraph)1395 	void findNextPool(std::vector<Solver::MineResult> &results, std::set<NodeSet> &pool,
1396 			int oldSetSize, int increment, int minNodes, int minMatches, int limitMatchesPerGraph)
1397 	{
1398 		int groupCounter = 0;
1399 		std::map<std::string, std::vector<const NodeSet*>> poolPerGraph;
1400 		std::set<NodeSet> nextPool;
1401 
1402 		for (auto &it : pool)
1403 			poolPerGraph[it.graphId].push_back(&it);
1404 
1405 		if (verbose)
1406 			my_printf("\nMining for frequent subcircuits of size %d using increment %d:\n", oldSetSize+increment, increment);
1407 
1408 		int count = 0;
1409 		for (auto &it : poolPerGraph)
1410 		{
1411 			std::map<int, std::set<int>> node2sets;
1412 			std::set<NodeSet> usedSets;
1413 
1414 			for (int idx = 0; idx < int(it.second.size()); idx++) {
1415 				for (int node : it.second[idx]->nodes)
1416 					node2sets[node].insert(idx);
1417 			}
1418 
1419 			for (int idx1 = 0; idx1 < int(it.second.size()); idx1++, count++)
1420 			{
1421 				std::set<int> idx2set;
1422 
1423 				for (int node : it.second[idx1]->nodes)
1424 					for (int idx2 : node2sets[node])
1425 						if (idx2 > idx1)
1426 							idx2set.insert(idx2);
1427 
1428 				for (int idx2 : idx2set)
1429 				{
1430 					if (it.second[idx1]->extendCandidate(*it.second[idx2]) != increment)
1431 						continue;
1432 
1433 					NodeSet mergedSet = *it.second[idx1];
1434 					mergedSet.extend(*it.second[idx2]);
1435 
1436 					if (usedSets.count(mergedSet) > 0)
1437 						continue;
1438 
1439 					const std::string &graphId = it.first;
1440 					const auto &graph = graphData[it.first].graph;
1441 
1442 					if (verbose) {
1443 						my_printf("<%d%%/%d> Found %s[", int(100*count/pool.size()), oldSetSize+increment, graphId.c_str());
1444 						bool first = true;
1445 						for (int nodeIdx : mergedSet.nodes) {
1446 							my_printf("%s%s", first ? "" : ",", graph.nodes[nodeIdx].nodeId.c_str());
1447 							first = false;
1448 						}
1449 						my_printf("] ->");
1450 					}
1451 
1452 					int matches = testForMining(results, usedSets, nextPool, mergedSet, graphId, graph, minNodes, minMatches, limitMatchesPerGraph);
1453 
1454 					if (verbose)
1455 						my_printf(" %d%s\n", matches, matches < minMatches ? "  *purge*" : "");
1456 
1457 					if (minMatches <= matches)
1458 						groupCounter++;
1459 				}
1460 			}
1461 		}
1462 
1463 		pool.swap(nextPool);
1464 
1465 		if (verbose)
1466 			my_printf("Found a total of %d subgraphs in %d groups.\n", int(pool.size()), groupCounter);
1467 	}
1468 
1469 	// interface to the public solver class
1470 
1471 protected:
SolverWorker(Solver * userSolver)1472 	SolverWorker(Solver *userSolver) : userSolver(userSolver), verbose(false)
1473 	{
1474 	}
1475 
setVerbose()1476 	void setVerbose()
1477 	{
1478 		verbose = true;
1479 	}
1480 
addGraph(std::string graphId,const Graph & graph)1481 	void addGraph(std::string graphId, const Graph &graph)
1482 	{
1483 		assert(graphData.count(graphId) == 0);
1484 
1485 		GraphData &gd = graphData[graphId];
1486 		gd.graphId = graphId;
1487 		gd.graph = graph;
1488 		diCache.add(gd.graph, gd.adjMatrix, graphId, userSolver);
1489 	}
1490 
addCompatibleTypes(std::string needleTypeId,std::string haystackTypeId)1491 	void addCompatibleTypes(std::string needleTypeId, std::string haystackTypeId)
1492 	{
1493 		compatibleTypes[needleTypeId].insert(haystackTypeId);
1494 	}
1495 
addCompatibleConstants(int needleConstant,int haystackConstant)1496 	void addCompatibleConstants(int needleConstant, int haystackConstant)
1497 	{
1498 		compatibleConstants[needleConstant].insert(haystackConstant);
1499 	}
1500 
addSwappablePorts(std::string needleTypeId,const std::set<std::string> & ports)1501 	void addSwappablePorts(std::string needleTypeId, const std::set<std::string> &ports)
1502 	{
1503 		swapPorts[needleTypeId].insert(ports);
1504 		diCache.compareCache.clear();
1505 	}
1506 
addSwappablePortsPermutation(std::string needleTypeId,const std::map<std::string,std::string> & portMapping)1507 	void addSwappablePortsPermutation(std::string needleTypeId, const std::map<std::string, std::string> &portMapping)
1508 	{
1509 		swapPermutations[needleTypeId].insert(portMapping);
1510 		diCache.compareCache.clear();
1511 	}
1512 
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)1513 	void solve(std::vector<Solver::Result> &results, std::string needleGraphId, std::string haystackGraphId,
1514 			const std::map<std::string, std::set<std::string>> &initialMappings, bool allowOverlap, int maxSolutions)
1515 	{
1516 		assert(graphData.count(needleGraphId) > 0);
1517 		assert(graphData.count(haystackGraphId) > 0);
1518 
1519 		const GraphData &needle = graphData[needleGraphId];
1520 		GraphData &haystack = graphData[haystackGraphId];
1521 
1522 		std::vector<std::set<int>> enumerationMatrix;
1523 		generateEnumerationMatrix(enumerationMatrix, needle, haystack, initialMappings);
1524 
1525 		if (verbose)
1526 		{
1527 			my_printf("\n");
1528 			my_printf("Needle nodes:\n");
1529 			for (int i = 0; i < int(needle.graph.nodes.size()); i++)
1530 				my_printf("%5d: %s (%s)\n", i, needle.graph.nodes[i].nodeId.c_str(), needle.graph.nodes[i].typeId.c_str());
1531 
1532 			my_printf("\n");
1533 			my_printf("Haystack nodes:\n");
1534 			for (int i = 0; i < int(haystack.graph.nodes.size()); i++)
1535 				my_printf("%5d: %s (%s)\n", i, haystack.graph.nodes[i].nodeId.c_str(), haystack.graph.nodes[i].typeId.c_str());
1536 
1537 			my_printf("\n");
1538 			my_printf("Needle Adjecency Matrix:\n");
1539 			printAdjMatrix(needle.adjMatrix);
1540 
1541 			my_printf("\n");
1542 			my_printf("Haystack Adjecency Matrix:\n");
1543 			printAdjMatrix(haystack.adjMatrix);
1544 
1545 			my_printf("\n");
1546 			my_printf("Edge Types:\n");
1547 			diCache.printEdgeTypes();
1548 
1549 			my_printf("\n");
1550 			my_printf("Enumeration Matrix (haystack nodes at column indices):\n");
1551 			printEnumerationMatrix(enumerationMatrix, haystack.graph.nodes.size());
1552 		}
1553 
1554 		haystack.usedNodes.resize(haystack.graph.nodes.size());
1555 		ullmannRecursion(results, enumerationMatrix, 0, needle, haystack, allowOverlap, maxSolutions > 0 ? results.size() + maxSolutions : -1);
1556 	}
1557 
mine(std::vector<Solver::MineResult> & results,int minNodes,int maxNodes,int minMatches,int limitMatchesPerGraph)1558 	void mine(std::vector<Solver::MineResult> &results, int minNodes, int maxNodes, int minMatches, int limitMatchesPerGraph)
1559 	{
1560 		int nodeSetSize = 2;
1561 		std::set<NodeSet> pool;
1562 		findNodePairs(results, pool, minNodes, minMatches, limitMatchesPerGraph);
1563 
1564 		while ((maxNodes < 0 || nodeSetSize < maxNodes) && pool.size() > 0)
1565 		{
1566 			int increment = nodeSetSize - 1;
1567 			if (nodeSetSize + increment >= minNodes)
1568 				increment = minNodes - nodeSetSize;
1569 			if (nodeSetSize >= minNodes)
1570 				increment = 1;
1571 
1572 			findNextPool(results, pool, nodeSetSize, increment, minNodes, minMatches, limitMatchesPerGraph);
1573 			nodeSetSize += increment;
1574 		}
1575 	}
1576 
clearOverlapHistory()1577 	void clearOverlapHistory()
1578 	{
1579 		for (auto &it : graphData)
1580 			it.second.usedNodes.clear();
1581 	}
1582 
clearConfig()1583 	void clearConfig()
1584 	{
1585 		compatibleTypes.clear();
1586 		compatibleConstants.clear();
1587 		swapPorts.clear();
1588 		swapPermutations.clear();
1589 		diCache.compareCache.clear();
1590 	}
1591 
1592 	friend class Solver;
1593 };
1594 
userCompareNodes(const std::string &,const std::string &,void *,const std::string &,const std::string &,void *,const std::map<std::string,std::string> &)1595 bool Solver::userCompareNodes(const std::string&, const std::string&, void*, const std::string&, const std::string&, void*, const std::map<std::string, std::string>&)
1596 {
1597 	return true;
1598 }
1599 
userAnnotateEdge(const std::string &,const std::string &,void *,const std::string &,void *)1600 std::string Solver::userAnnotateEdge(const std::string&, const std::string&, void*, const std::string&, void*)
1601 {
1602 	return std::string();
1603 }
1604 
userCompareEdge(const std::string &,const std::string &,void *,const std::string &,void *,const std::string &,const std::string &,void *,const std::string &,void *)1605 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*)
1606 {
1607 	return true;
1608 }
1609 
userCheckSolution(const Result &)1610 bool Solver::userCheckSolution(const Result&)
1611 {
1612 	return true;
1613 }
1614 
Solver()1615 SubCircuit::Solver::Solver()
1616 {
1617 	worker = new SolverWorker(this);
1618 }
1619 
~Solver()1620 SubCircuit::Solver::~Solver()
1621 {
1622 	delete worker;
1623 }
1624 
setVerbose()1625 void SubCircuit::Solver::setVerbose()
1626 {
1627 	worker->setVerbose();
1628 }
1629 
addGraph(std::string graphId,const Graph & graph)1630 void SubCircuit::Solver::addGraph(std::string graphId, const Graph &graph)
1631 {
1632 	worker->addGraph(graphId, graph);
1633 }
1634 
addCompatibleTypes(std::string needleTypeId,std::string haystackTypeId)1635 void SubCircuit::Solver::addCompatibleTypes(std::string needleTypeId, std::string haystackTypeId)
1636 {
1637 	worker->addCompatibleTypes(needleTypeId, haystackTypeId);
1638 }
1639 
addCompatibleConstants(int needleConstant,int haystackConstant)1640 void SubCircuit::Solver::addCompatibleConstants(int needleConstant, int haystackConstant)
1641 {
1642 	worker->addCompatibleConstants(needleConstant, haystackConstant);
1643 }
1644 
addSwappablePorts(std::string needleTypeId,std::string portId1,std::string portId2,std::string portId3,std::string portId4)1645 void SubCircuit::Solver::addSwappablePorts(std::string needleTypeId, std::string portId1, std::string portId2, std::string portId3, std::string portId4)
1646 {
1647 	std::set<std::string> ports;
1648 	ports.insert(portId1);
1649 	ports.insert(portId2);
1650 	ports.insert(portId3);
1651 	ports.insert(portId4);
1652 	ports.erase(std::string());
1653 	addSwappablePorts(needleTypeId, ports);
1654 }
1655 
addSwappablePorts(std::string needleTypeId,std::set<std::string> ports)1656 void SubCircuit::Solver::addSwappablePorts(std::string needleTypeId, std::set<std::string> ports)
1657 {
1658 	worker->addSwappablePorts(needleTypeId, ports);
1659 }
1660 
addSwappablePortsPermutation(std::string needleTypeId,std::map<std::string,std::string> portMapping)1661 void SubCircuit::Solver::addSwappablePortsPermutation(std::string needleTypeId, std::map<std::string, std::string> portMapping)
1662 {
1663 	worker->addSwappablePortsPermutation(needleTypeId, portMapping);
1664 }
1665 
solve(std::vector<Result> & results,std::string needleGraphId,std::string haystackGraphId,bool allowOverlap,int maxSolutions)1666 void SubCircuit::Solver::solve(std::vector<Result> &results, std::string needleGraphId, std::string haystackGraphId, bool allowOverlap, int maxSolutions)
1667 {
1668 	std::map<std::string, std::set<std::string>> emptyInitialMapping;
1669 	worker->solve(results, needleGraphId, haystackGraphId, emptyInitialMapping, allowOverlap, maxSolutions);
1670 }
1671 
solve(std::vector<Result> & results,std::string needleGraphId,std::string haystackGraphId,const std::map<std::string,std::set<std::string>> & initialMappings,bool allowOverlap,int maxSolutions)1672 void SubCircuit::Solver::solve(std::vector<Result> &results, std::string needleGraphId, std::string haystackGraphId,
1673 		const std::map<std::string, std::set<std::string>> &initialMappings, bool allowOverlap, int maxSolutions)
1674 {
1675 	worker->solve(results, needleGraphId, haystackGraphId, initialMappings, allowOverlap, maxSolutions);
1676 }
1677 
mine(std::vector<MineResult> & results,int minNodes,int maxNodes,int minMatches,int limitMatchesPerGraph)1678 void SubCircuit::Solver::mine(std::vector<MineResult> &results, int minNodes, int maxNodes, int minMatches, int limitMatchesPerGraph)
1679 {
1680 	worker->mine(results, minNodes, maxNodes, minMatches, limitMatchesPerGraph);
1681 }
1682 
clearOverlapHistory()1683 void SubCircuit::Solver::clearOverlapHistory()
1684 {
1685 	worker->clearOverlapHistory();
1686 }
1687 
clearConfig()1688 void SubCircuit::Solver::clearConfig()
1689 {
1690 	worker->clearConfig();
1691 }
1692