summaryrefslogtreecommitdiff
path: root/libs/subcircuit/README
diff options
context:
space:
mode:
Diffstat (limited to 'libs/subcircuit/README')
-rw-r--r--libs/subcircuit/README440
1 files changed, 440 insertions, 0 deletions
diff --git a/libs/subcircuit/README b/libs/subcircuit/README
new file mode 100644
index 00000000..5c8a8a9e
--- /dev/null
+++ b/libs/subcircuit/README
@@ -0,0 +1,440 @@
+
+ **************************************************************************
+ * *
+ * The SubCircuit C++11 library *
+ * *
+ * An implementation of a modified Ullmann Subgraph Isomorphism Algorithm *
+ * for coarse grain logic networks. by Clifford Wolf *
+ * *
+ **************************************************************************
+
+============
+Introduction
+============
+
+This is a library that implements a modified Ullmann Subgraph Isomorphism
+Algorithm with additional features aimed at working with coarse grain logic
+networks.
+
+A simple command line tool that exposes the features of the library is also
+included.
+
+
+Under-Construction Warning
+--------------------------
+
+This work is under constructions. It is likely that they are bugs in the
+library that need fixing. Feel free to contact me at clifford@clifford.at
+if you have found a bug.
+
+
+C++11 Warning
+-------------
+
+This project is written in C++11. Use appropriate compiler switches to compile
+it. Tested with clang version 3.0 and option -std=c++11. Also tested with gcc
+version 4.6.3 and option -std=c++0x.
+
+
+========
+Features
+========
+
+The input is two graphs (needle and haystack) that represent coarse grain
+logic networks. The algorithm identifies all subgraphs of haystack that are
+isomorphic to needle.
+
+The following additional features over the regular Ullmann Subgraph Isomorphism
+Algorithm are provided by the library.
+
+ * The graphs are attributed hypergraphs capable of representing netlists:
+
+ - Nodes represent the logic cells:
+ - Nodes have types and only match compatible types
+ - Nodes have ports with variable bit-width
+
+ - Hyperedges represent the signals:
+ - Each hyperedge connects one to many bits on ports on nodes
+
+ - Callback functions for advanced attributes and compatibility rules:
+ Any set of node-node compatibility rules and edge-edge
+ compatibility rules can be implemented by providing
+ the necessary callback functions.
+
+ * The algorithm is very efficient when all or many bits of one port are
+ connected to bits of the same other port. This is usually the case
+ in coarse grain logic networks. But the algorithm does not add any
+ restrictions in this area; it is just optimized for this scenario.
+
+ * The algorithm can be configured to allow larger ports in needle cells to
+ match smaller ports in haystack cells in certain situations. This way it
+ is possible to e.g. have a 32-bit adder cell in the needle match a
+ 16-bit adder cell in the haystack.
+
+ * The algorithm can be configured to perform port-swapping on certain
+ ports on certain cell types to match commutative operations properly.
+
+ This is, however, not implemented very efficiently when a larger number
+ of permutations is possible on a cell type. Therefore it is recommended
+ to only use swap groups with only a few members and a few such groups
+ on one cell type type.
+
+ Also note, that the algorithm can not resolve complex dependencies
+ between the port swappings of different cells. Therefore it is
+ recommended to only use port swapping on input pins of commutative
+ operations, where such complex dependencies can not emerge.
+
+ * The algorithm can be configured to distinguish between internal signals
+ of the needle and externally visible signals. The needle will only
+ match a subgraph of the haystack if that subgraph does not expose the
+ internal signal to nodes in the haystack outside the matching subgraph.
+
+ * The algorithm can recognize a subcircuit even if some or all of its
+ inputs and/or outputs are shorted together.
+
+ * Explicit fast support for constant signals without extra nodes for
+ constant drivers.
+
+ * Support for finding only non-overlapping matches.
+
+ * The public API of the library is using std::string identifiers for
+ nodes, node types and ports. Internally the costly part of the
+ algorithm is only using integer values, thus speeding up the
+ algorithm without exposing complex internal encodings to the caller.
+
+
+=================
+API Documentation
+=================
+
+This section gives a brief overview of the API. For a working example, have a
+look at the demo.cc example program in this directory.
+
+
+Setting up graphs
+-----------------
+
+Instanciate the SubCircuit::Graph class and use the methods of this class to
+set up the circuit.
+
+ SubCircuit::Graph myGraph;
+
+For each node in the circuit call the createNode() method. Specify the
+identifier for the node and also the type of function implemented by the node.
+Then call createPort() for each port of this node.
+
+E.g. the following code adds a node "myAdder" of type "add" with three 32 bit
+wide ports "A", "B" and "Y". Note that SubCircuit does not care which port is
+an input and which port is an output. The last (and optional) argument to
+createPort() specifies the minimum number of bits required for this port in the
+haystack (this field is only used in the needle graph). So in this example the
+node would e.g. also match any adder with a bit width smaller 32.
+
+ myGraph.createNode("myAdder", "add");
+ myGraph.createPort("myAdder", "A", 32, 1);
+ myGraph.createPort("myAdder", "B", 32, 1);
+ myGraph.createPort("myAdder", "Y", 32, 1);
+
+The createConnection() method can be used to connect the nodes. It internally
+creates a hypergraph. So the following code does not only connect cell1.Y with
+cell2.A and cell3.A but also implicitly cell2.A with cell3.A.
+
+ myGraph.createConnection("cell1", "Y", "cell2", "A");
+ myGraph.createConnection("cell1", "Y", "cell3", "A");
+
+Redundent calls to createConnection() are ignored. As long as the method is
+called after the relevant nodes and ports are created, the order in which the
+createConnection() calls are performed is irrelevant.
+
+The createConnection() method can also be used to connect single bit signals.
+In this case the start bit for both ports must be provided as well as an
+optional width (which defaults to 1). E.g. the following calls can be used to
+connect the 32 bit port cell4.Y to the 32 bit port cell5.A with a one bit left
+rotate shift,
+
+ myGraph.createConnection("cell4", "Y", 0, "cell5", "A", 1, 31);
+ myGraph.createConnection("cell4", "Y", 31, "cell5", "A", 0);
+
+The method createConstant() can be used to add a constant driver to a signal.
+The signal value is encoded as one char by bit, allowing for multi-valued
+logic matching. The follwoing command sets the lowest bit of cell6.A to a
+logic 1:
+
+ myGraph.createConnection("cell6", "A", 0, '1');
+
+It is also possible to set an entire port to a integer value, using the
+encodings '0' and '1' for the binary digits:
+
+ myGraph.createConnection("cell6", "A", 42);
+
+The method markExtern() can be used to mark a signal as externally visible. In
+a needle graph this means, this signal may match a signal in the haystack that
+is used outside the matching subgraph. In a haystack graph this means, this
+signal is used outside the haystack graph. I.e. an internal signal of the
+needle won't match an external signal of the haystack regardless where the
+signal is used in the haystack.
+
+In some application one may disable this extern/intern checks. This can easily
+be achieved by marking all signals in the needle as extern. This can be done
+using the Graph::markAllExtern() method.
+
+
+Setting up and running solvers
+------------------------------
+
+To actually run the subgraph isomorphism algorithm, an instance of
+SubCircuit::Solver must be created.
+
+ SubCircuit::Solver mySolver;
+
+The addGraph() method can be used to register graphs with the solver:
+
+ mySolver.addGraph("graph1", myGraph);
+ mySolver.addGraph("graph2", myOtherGraph);
+
+Usually nodes in the needle and the haystack must have the same type identifier
+to match each other. Additionally pairs of compatible needle and haystack node
+pairs can be registered using the addCompatibleTypes() method:
+
+ mySolver.addCompatibleTypes("alu", "add");
+ mySolver.addCompatibleTypes("alu", "sub");
+ mySolver.addCompatibleTypes("alu", "and");
+ mySolver.addCompatibleTypes("alu", "or");
+ mySolver.addCompatibleTypes("alu", "xor");
+
+Note that nodes in needle and haystack must also use the same naming convention
+for their ports in order to be considered compatible by the algorithm.
+
+Similarly the method addCompatibleConstants() can be used the specify which
+constant values in the needle should match which constant value in the haystack.
+Equal values always do match.
+
+ mySolver.addCompatibleConstants('x', '0');
+ mySolver.addCompatibleConstants('x', '1');
+
+Some cells implement commutative operations that don't care if their input
+operands are swapped. For this cell types it is possible to register groups
+of swappable ports. Let's consider a cell "macc23" that implements the
+function Y = (A * B) + (C * D * E):
+
+ mySolver.addSwappablePorts("macc23", "A", "B");
+ mySolver.addSwappablePorts("macc23", "C", "D", "E");
+
+Sometimes the rules for port swapping are a more complicated and the swapping
+of one port is related to the swapping of another port. Let's consider a cell
+"macc22" that implements the function Y = (A * B) + (C * D):
+
+ mySolver.addSwappablePorts("macc22", "A", "B");
+ mySolver.addSwappablePorts("macc22", "C", "D");
+
+ std::map<std::string, std::string> portMapping;
+ portMapping["A"] = "C";
+ portMapping["B"] = "D";
+ portMapping["C"] = "A";
+ portMapping["D"] = "B";
+ mySolver.addSwappablePortsPermutation("macc22", portMapping);
+
+I.e. the method mySolver.addSwappablePortsPermutation() can be used to register
+additional permutations for a node type of which one or none is applied on top
+of the permutations yielded by the permutations generated by the swap groups.
+
+Note that two solutions that differ only in the applied port swapping are not
+reported as separate solutions. Instead only one of them is selected (in most
+cases the one with less port swapping as it is usually identified first).
+
+Once everything has been set up, the solve() method can be used to actually
+search for isomorphic subgraphs. The first argument to solve() is an
+std::vector<SubCircuit::Solver::Result> objects to which all found solutions
+are appended. The second argument is the identifier under which the needle
+graph has been registered and the third argument is the identifier under which
+the haystack graph has been registered:
+
+ std::vector<SubCircuit::Solver::Result> results;
+ mySolver.solve(results, "graph1", "graph2");
+
+The SubCircuit::Solver::Result object is a simple data structure that contains
+the mappings between needle and haystack nodes, port mappings after the port
+swapping and some additional metadata. See "subcircuit.h" and "demo.cc" for
+details.
+
+The solve() method has a third optional boolean argument. If it is set to
+false, solve will not return any solutions that contain haystack nodes that
+have been part of a previously found solution. This way it is e.g. easy
+to implement a greedy macro cell matching algorithm:
+
+ std::vector<SubCircuit::Solver::Result> results;
+ mySolver.solve(results, "macroCell1", "circuit", false);
+ mySolver.solve(results, "macroCell2", "circuit", false);
+ mySolver.solve(results, "macroCell3", "circuit", false);
+
+After this code has been executed, the results vector contains all
+non-overlapping matches of the three macrocells. The method
+clearOverlapHistory() can be used to reset the internal state used
+for this feature. The default value for the third argument to solve()
+is true (allow overlapping).
+
+The solve() method also has a fourth optional integer argument. If it is set to
+a positive integer, this integer specifies the maximum number of solutions to
+be appended to the results vector, i.e. to terminate the algorithm early when
+the set number of matches is found. When this fourth argument is negative or
+omitted all matches are found and appended.
+
+An alternative version of the solve() method supports an additional argument
+after they haystack graph identifier that specifies initial mappings for
+the algorithm. In the following example only the haystack nodes cell_1 and
+cell_2 are considered as mappings for the needle node cell_A:
+
+ std::map<std::string, std::set<std::string>> initialMappings;
+ initialMappings["cell_A"].insert("cell_1");
+ initialMappings["cell_A"].insert("cell_2");
+
+ std::vector<SubCircuit::Solver::Result> results;
+ mySolver.solve(results, "graph1", "graph2", initialMappings);
+
+The clearConfig() method can be used to clear all data registered using
+addCompatibleTypes(), addCompatibleConstants(), addSwappablePorts() and
+addSwappablePortsPermutation() but retaining the graphs and the overlap state.
+
+
+Using user callback function
+----------------------------
+
+For more complex tasks it is possible to derive a class from SubCircuit::Solver
+that overloads one or more of the following virtual methods. The userData
+arguments to the following methods are void pointers that can be passed as
+third argument to Graph::createNode() and are simly passed thru to the user
+callback functions together with the node id whenever a node is referenced.
+
+bool userCompareNodes(needleGraphId, needleNodeId, needleUserData, haystackGraphId, haystackNodeId, haystackUserData):
+
+ Perform additional checks on a pair of nodes (one from the needle, one
+ from the haystack) to determine if the nodes are compatible. The default
+ implementation always returns true.
+
+
+bool userCompareEdge(needleGraphId, needleFromNodeId, needleFromUserData, needleToNodeId, needleToUserData,
+ haystackGraphId, haystackFromNodeId, haystackFromUserData, haystackToNodeId, haystackToUserData):
+
+ Perform additional checks on a pair of a pair of adjacent nodes (one
+ adjacent pair from the needle and one adjacent pair from the haystack)
+ to determine wheter this edge from the needle is compatible with
+ that edge from the haystack. The default implementation always
+ returns true.
+
+bool userCheckSolution(result):
+
+ Perform additional checks on a solution before appending it to the
+ results vector. When this function returns false, the solution is
+ ignored. The default implementation always returns true.
+
+
+Debugging
+---------
+
+For debugging purposes the SubCircuit::Solver class implements a setVerbose()
+method. When called once, all further calls to the solve() method cause the
+algorithm to dump out a lot of debug information to stdout.
+
+In conjunction with setVerbose() one can also overload the userAnnotateEdge()
+method in order to add additional information about the edges to the debug
+output.
+
+
+===================
+Shell Documentation
+===================
+
+This package also contains a small command-line tool called "scshell" that can
+be used for experimentation with the algorithm. This program reads a series of
+commands from stdin and reports its findings to stdout on exit.
+
+ $ ./scshell < test_macc22.txt
+
+ ...
+
+ Match #3: (macc22 in macc4x2)
+ add_1 -> add_2 A:B B:A Y:Y
+ mul_1 -> mul_4 A:A B:B Y:Y
+ mul_2 -> mul_3 A:A B:B Y:Y
+
+The following commands can be used in scshell to specify graphs:
+
+ graph <graph_name>
+ ...
+ endgraph
+
+ Used to specify a graph with the given name. Only the commands
+ "node", "connect" and "extern" may be used within the graph ...
+ endgraph block.
+
+ node <node_name> [<port_name> [<bits> [<min_bits>]]]+
+
+ Used to create a node and ports. This command is a direct frontend
+ to the Graph::createNode() and Graph::createPort() methods.
+
+ connect <from_node> <from_port> <to_node> <to_port>
+ connect <from_node> <from_port> <from_bit> <to_node> <to_port> <to_bit>
+ connect <from_node> <from_port> <from_bit> <to_node> <to_port> <to_bit> <width>
+
+ Used to connect the nodes in the graph via Graph::createConnection().
+
+ constant <node> <port> [<bit>] <value>
+
+ Call Graph::createConstant().
+
+ extern <node> [<port> [<bit>]]+
+
+ Mark signals as extern via Graph::markExtern().
+
+ allextern
+
+ Mark all signals as extern via Graph::markAllExtern().
+
+The following commands can be used in scshell outside a graph ... endgraph block:
+
+ compatible <needle_type> <haystack_type>
+
+ Call Solver::addCompatibleTypes().
+
+ constcompat <needle_value> <haystack_value>
+
+ Call Solver::addCompatibleConstants().
+
+ swapgroup <needle_type> <port>+
+
+ Call Solver::addSwappablePorts().
+
+ swapperm <needle_type> <ports>+ : <ports>+
+
+ Call Solver::addSwappablePortsPermutation(). Both port lists must
+ have the same length and the second one must be a permutation of the
+ first one.
+
+ initmap <needle_node> <haystack_node>+
+
+ Add an entry to the initial mappings for the next solve command.
+ This mappings are automatically reset after the solve command.
+
+ solve <needle_graph> <haystack_graph> [<allow_overlap> [<max_solutions>]]
+
+ Call Solver::solve(). The <allow_overlap> must be "1" or "true"
+ for true and "0" or "false" for false.
+
+ expect <number>
+
+ Print all results so far since the last call to expect. Expect
+ <number> results and exit with error code 1 if a different number
+ of results have been found.
+
+ clearoverlap
+
+ Call Solver::clearOverlapHistory().
+
+ clearconfig
+
+ Call Solver::clearConfig().
+
+ verbose
+
+ Call Solver::setVerbose().
+