Biorithm  1.1
 All Classes Functions Variables Typedefs Friends
treewidth.h
00001 /**************************************************************************
00002  * Copyright (c) 2002-2011 T. M. Murali                                   *
00003  * Copyright (c) 2007-2011 Naveed Massjouni                               *
00004  *                                                                        *
00005  * This file is part of Biorithm.                                         *
00006  *                                                                        *
00007  * Biorithm is free software: you can redistribute it and/or modify       *
00008  * it under the terms of the GNU General Public License as published by   *
00009  * the Free Software Foundation, either version 3 of the License, or      *
00010  * (at your option) any later version.                                    *
00011  *                                                                        *
00012  * Biorithm is distributed in the hope that it will be useful,            *
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of         *
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
00015  * GNU General Public License for more details.                           *
00016  *                                                                        *
00017  * You should have received a copy of the GNU General Public License      *
00018  * along with Biorithm.  If not, see <http://www.gnu.org/licenses/>.      *
00019  *                                                                        *
00020  **************************************************************************/
00021 
00028 /*
00029   Treewidth is a class that reduces a graph by a series of "safe" rules.
00030   It also generates a minimum value for the treewidth of the graph.
00031   The rules that have been implemented so far are:
00032   * Islet Rule
00033   * Twig Rule
00034   * Series Rule
00035   * Triangle Rule
00036   * Simplicial Rule
00037   * Almost Simplicial Rule
00038 
00039   Example usage:
00040     Treewidth treewidth("graph.in");
00041     TODO: fill this in
00042     cout << "low = " << treewidth.getLow() << endl;
00043 */
00044 
00045 #ifndef TREEWIDTH_H
00046 #define TREEWIDTH_H
00047 
00048 #include <iostream>
00049 #include <map>
00050 #include <set>
00051 #include <stack>
00052 #include <string>
00053 #include <vector>
00054 #include "graph.h"
00055 using namespace  std;
00056 
00057 typedef MyNode Node;
00058 typedef MyEdge Edge;
00059 typedef MyNode::EdgeIterator EdgeIterator;
00060 typedef MyGraph Graph;
00061 typedef MyGraph::NodeIterator NodeIterator;
00062 typedef string NodeId;
00063 
00064 class Treewidth {
00065 
00066   private:
00067 
00068   int low;
00069   Graph graph;
00070 
00071   public:
00072 
00073   enum RuleType {ISLET_RULE = 1, TWIG_RULE = 2, SERIES_RULE = 4,
00074     TRIANGLE_RULE = 8, SIMPLICIAL_RULE = 16, ALMOST_SIMPLICIAL_RULE = 32,
00075     ALL_RULES_MASK = 0xffff};
00076 
00077   // Constructors
00078   Treewidth(string graphFile) : graph(graphFile, "asdf"), low(0) {}
00079   Treewidth(Graph graphIn) : graph(graphIn), low(0) {}
00080 
00081   void getGraph(Graph &g) const {
00082     g = graph;
00083   }
00084 
00085   // Returns a copy of the graph
00086   Graph getGraphCopy() {
00087     Graph g = graph;
00088     return g;
00089   }
00090 
00091   vector<NodeId> getNodes() {
00092     vector<NodeId> nodes;
00093     NodeIterator nodesItr = graph.nodes();
00094     while (nodesItr.hasNext()) {
00095       Node node = nodesItr.next();
00096       nodes.push_back(node.getId());
00097     }
00098     return nodes;
00099   }
00100 
00101   int getDegree(NodeId nodeId) {
00102     return graph.degree(nodeId);
00103   }
00104 
00105   int getLow() {
00106     return low;
00107   }
00108 
00109   int numNodes() {
00110     return graph.numNodes();
00111   }
00112 
00113   int numEdges() {
00114     return graph.numEdges();
00115   }
00116 
00117   void printEdges(ostream& ostr) {
00118     graph.printEdges(ostr);
00119   }
00120 
00121   void runRule(RuleType rule) {
00122     stack<string> nodesToProcess;
00123     set<string> deletedNodes;
00124     NodeIterator nodesItr = graph.nodes();
00125     while (nodesItr.hasNext()) {
00126       Node node = nodesItr.next();
00127       nodesToProcess.push(node.getId());
00128     }
00129     while (!nodesToProcess.empty()) {
00130       NodeId nodeId = nodesToProcess.top();
00131       nodesToProcess.pop();
00132       // Skip this node if we have already deleted it.
00133       if (deletedNodes.find(nodeId) != deletedNodes.end())
00134         continue;
00135       //cout << "looking at node: " << nodeId << endl;
00136       int degree = graph.degree(nodeId);
00137       switch(rule) {
00138         case ISLET_RULE:
00139           if (degree == 0) {
00140             //cout << "deleting it by islet rule" << endl;
00141             graph.deleteNode(nodeId);
00142             deletedNodes.insert(nodeId);
00143           }
00144           break;
00145         case TWIG_RULE:
00146           if (degree == 1) {
00147             pushNeighbors(nodesToProcess, nodeId);
00148             //cout << "deleting it by twig rule" << endl;
00149             graph.deleteNode(nodeId);
00150             deletedNodes.insert(nodeId);
00151             updateLow(degree);
00152           }
00153           break;
00154         case SERIES_RULE:
00155           if (degree == 2) {
00156             pushNeighbors(nodesToProcess, nodeId);
00157             connectNeighbors(nodeId);
00158             //cout << "deleting it by series rule" << endl;
00159             graph.deleteNode(nodeId);
00160             deletedNodes.insert(nodeId);
00161             updateLow(degree);
00162           }
00163           break;
00164         case TRIANGLE_RULE:
00165           if (degree == 3) {
00166             vector<NodeId> neighbors = getNeighbors(nodeId);
00167             if (graph.isEdge(neighbors[0], neighbors[1])
00168                 || graph.isEdge(neighbors[1], neighbors[2])
00169                 || graph.isEdge(neighbors[0], neighbors[2])) {
00170               pushNeighbors(nodesToProcess, nodeId);
00171               connectNeighbors(nodeId);
00172               //cout << "\tdeleting it by triangle rule" << endl;
00173               graph.deleteNode(nodeId);
00174               deletedNodes.insert(nodeId);
00175               updateLow(degree);
00176             }
00177           }
00178           break;
00179         case SIMPLICIAL_RULE:
00180           if (isSimplicial(nodeId)) {
00181             pushNeighbors(nodesToProcess, nodeId);
00182             //cout << "deleting it by simplicial rule" << endl;
00183             graph.deleteNode(nodeId);
00184             deletedNodes.insert(nodeId);
00185             updateLow(degree);
00186           }
00187           break;
00188         case ALMOST_SIMPLICIAL_RULE:
00189           if (isAlmostSimplicial(nodeId)) {
00190             pushNeighbors(nodesToProcess, nodeId);
00191             connectNeighbors(nodeId);
00192             //cout << "deleting it by almost simp. rule" << endl;
00193             graph.deleteNode(nodeId);
00194             deletedNodes.insert(nodeId);
00195             updateLow(degree);
00196           }
00197           break;
00198       }
00199     }
00200   }
00201 
00202   // Connect the neighbors of a node to each other.
00203   void connectNeighbors(NodeId nodeId) {
00204     vector<NodeId> neighbors = getNeighbors(nodeId);
00205     for (int i = 0; i < neighbors.size(); i++) {
00206       for (int j = i+1; j < neighbors.size(); j++) {
00207         graph.addEdge(neighbors[i], neighbors[j]);
00208       }
00209     }
00210   }
00211 
00212   // Push the neighbors of a node onto the given stack.
00213   void pushNeighbors(stack<NodeId>& s, NodeId nodeId) {
00214     vector<NodeId> neighbors = getNeighbors(nodeId);
00215     for (int i = 0; i < neighbors.size(); i++) {
00216       s.push(neighbors[i]);
00217     }
00218   }
00219 
00220   void updateLow(int degree) {
00221     low = degree > low ? degree : low;
00222   }
00223 
00224   // A node is simplicial if its neighbors induce a clique.
00225   bool isSimplicial(NodeId nodeId) {
00226     if (graph.degree(nodeId) <= 1)
00227       return true;
00228     vector<NodeId> neighbors = getNeighbors(nodeId);
00229     int size = neighbors.size();
00230     for (int i = 0; i < size; i++) {
00231       for (int j = i+1; j < size; j++) {
00232         if (!graph.isEdge(neighbors[i], neighbors[j])) {
00233           return false;
00234         }
00235       }
00236     }
00237     return true;
00238   }
00239 
00240   // A node v almost simplicial if there is a neighbor w (lonely node) of v
00241   // such that all other neighbors of v form a clique.
00242   bool isAlmostSimplicial(NodeId nodeId) {
00243     if (graph.degree(nodeId) <= 2)
00244       return true;
00245     map< NodeId, set<NodeId> > neigborsMap;
00246     vector<NodeId> neighbors = getNeighbors(nodeId);
00247     int numNeighbors = neighbors.size();
00248     // Map a list of the neighbors' neighbors to each neighbor.
00249     // Only consider neighbors of the original nodeId that was passed in.
00250     for (int i = 0; i < numNeighbors ; i++) {
00251       set<NodeId> neighborsNeighbors;
00252       neighborsNeighbors.insert(neighbors[i]);
00253       for (int j = 0; j < numNeighbors; j++) {
00254         if (i == j) continue;
00255         if (graph.isEdge(neighbors[i], neighbors[j])) {
00256           neighborsNeighbors.insert(neighbors[j]);
00257         }
00258       }
00259       neigborsMap[neighbors[i]] = neighborsNeighbors;
00260     }
00261     bool foundLonely = false;
00262     NodeId lonelyNodeId = "";
00263     for (int i = 0; i < numNeighbors ; i++) {
00264       if (neigborsMap[neighbors[i]].size() < numNeighbors-1) {
00265         if (foundLonely && neighbors[i] != lonelyNodeId) {
00266           return false; // can have only 1 lonely node
00267         } else {
00268           foundLonely = true;
00269           lonelyNodeId = neighbors[i];
00270         }
00271       } else if (neigborsMap[neighbors[i]].size() == numNeighbors-1) {
00272         for (int j = 0; j < numNeighbors; j++) {
00273           // If node is missing from list of neighbors
00274           if (neigborsMap[neighbors[i]].find(neighbors[j]) ==
00275               neigborsMap[neighbors[i]].end()) {
00276             if (foundLonely && neighbors[j] != lonelyNodeId) {
00277               return false; // can have only 1 lonely node
00278             } else {
00279               foundLonely = true;
00280               lonelyNodeId = neighbors[j];
00281             }
00282           }
00283         }
00284       }
00285     }
00286     return true;
00287   }
00288 
00289   vector<NodeId> getNeighbors(NodeId nodeId) {
00290     vector<NodeId> neighbors;
00291     EdgeIterator edgeItr = graph.incidentEdges(nodeId);
00292     while (edgeItr.hasNext()) {
00293       Edge edge = *edgeItr.next();
00294       Node* nodePtr = edge.opposite(nodeId);
00295       neighbors.push_back(nodePtr->getId());
00296     }
00297     return neighbors;
00298   }
00299 
00300   void core(unsigned int k) {
00301     graph.core(k, graph, false, &cout);
00302   }
00303 
00304   // Returns a clique containing nodeId or an empty vector
00305   vector<NodeId> getClique(NodeId nodeId) {
00306     vector<NodeId> nodes;
00307     if (isSimplicial(nodeId)) {
00308       nodes = getNeighbors(nodeId);
00309       nodes.push_back(nodeId);
00310       return nodes;
00311     }
00312     //cout << "Did not find clique for " << nodeId << endl;
00313     return nodes;
00314   }
00315 
00316   void reduce() {
00317     unsigned int prevSize = 0;
00318     while (numNodes() != prevSize) {
00319       prevSize = numNodes();
00320 
00321       cout << "running islet rule...          ";
00322       runRule(ISLET_RULE);
00323       cout << " num nodes: " << numNodes()
00324            << "\tlow: " << getLow() << endl;
00325 
00326       cout << "running twig rule...           ";
00327       runRule(TWIG_RULE);
00328       cout << " num nodes: " << numNodes()
00329            << "\tlow: " << getLow() << endl;
00330       if (numNodes() != prevSize) continue;
00331 
00332       cout << "running series rule...         ";
00333       runRule(SERIES_RULE);
00334       cout << " num nodes: " << numNodes()
00335            << "\tlow: " << getLow() << endl;
00336       if (numNodes() != prevSize) continue;
00337 
00338       cout << "running triangleRule...        ";
00339       runRule(TRIANGLE_RULE);
00340       cout << " num nodes: " << numNodes()
00341            << "\tlow: " << getLow() << endl;
00342       if (numNodes() != prevSize) continue;
00343 
00344       cout << "running simplicialRule...      ";
00345       runRule(SIMPLICIAL_RULE);
00346       cout << " num nodes: " << numNodes()
00347            << "\tlow: " << getLow() << endl;
00348       if (numNodes() != prevSize) continue;
00349 
00350       cout << "running almostSimplicialRule...";
00351       runRule(ALMOST_SIMPLICIAL_RULE);
00352       cout << " num nodes: " << numNodes()
00353            << "\tlow: " << getLow() << endl;
00354 
00355     }
00356   }
00357 
00358   int lowerBound() {
00359     reduce();
00360     return low;
00361   }
00362 
00363 };
00364 
00365 #endif
 All Classes Functions Variables Typedefs Friends