Index: src/main/java/weka/clusterers/MetisMQIClusterer.java
===================================================================
--- src/main/java/weka/clusterers/MetisMQIClusterer.java	(revision 14)
+++ src/main/java/weka/clusterers/MetisMQIClusterer.java	(revision 14)
@@ -0,0 +1,201 @@
+package weka.clusterers;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+
+import weka.clusterers.forMetisMQI.GraphAlgorithms;
+import weka.clusterers.forMetisMQI.graph.Node;
+import weka.clusterers.forMetisMQI.graph.UndirectedGraph;
+import weka.core.Attribute;
+import weka.core.Capabilities;
+import weka.core.Instance;
+import weka.core.Instances;
+import weka.core.Option;
+import weka.core.OptionHandler;
+import weka.core.Utils;
+import weka.core.Capabilities.Capability;
+
+public class MetisMQIClusterer extends AbstractClusterer implements
+		OptionHandler {
+
+	private int numberOfClusters = 2;
+
+	private int sizeFinerGraph = 10;
+
+	/**
+	 * It maps each cluster with an integer id.
+	 */
+	private Map<Set<Node>, Integer> clustersMap = null;
+
+	/**
+	 * Holds the cluster membership for each node.
+	 */
+	private Map<Node, Integer> nodeMap = null;
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+
+	@Override
+	public void buildClusterer(Instances data) throws Exception {
+		getCapabilities().testWithFail(data);
+		UndirectedGraph g = new UndirectedGraph();
+		g.loadFromInstance(data);
+		Set<Set<Node>> clusters = GraphAlgorithms.metisMqi(g, numberOfClusters,
+				sizeFinerGraph);
+		setNumClusters(clusters.size());
+		int i = 0;
+		Iterator<Set<Node>> clusterIterator = clusters.iterator();
+		clustersMap = new HashMap<Set<Node>, Integer>();
+		nodeMap = new HashMap<Node, Integer>();
+		while (clusterIterator.hasNext()) {
+			Set<Node> cluster = clusterIterator.next();
+			clustersMap.put(cluster, i);
+			Iterator<Node> nodeIterator = cluster.iterator();
+			while (nodeIterator.hasNext()) {
+				Node n = nodeIterator.next();
+				if (nodeMap.get(n) == null) {
+					nodeMap.put(n, i);
+				}
+			}
+			i++;
+		}
+	}
+
+	@Override
+	public int clusterInstance(Instance instance) throws Exception {
+		Attribute from = instance.dataset().attribute("from");
+		Attribute to = instance.dataset().attribute("to");
+		Instance edge = instance;
+		Node node1 = new Node(Integer.toString(((int) Math.round(edge
+				.value(from)))));
+		Node node2 = new Node(Integer.toString(((int) Math
+				.round(edge.value(to)))));
+		if (nodeMap.get(node1) == nodeMap.get(node2))
+			return nodeMap.get(node1);
+		else
+			throw new Exception();
+	}
+
+	/**
+	 * Parses a given list of options.
+	 * <p/>
+	 * 
+	 * <!-- options-start --> Valid options are:
+	 * <p/>
+	 * 
+	 * <pre>
+	 * -N &lt;num&gt;
+	 *  number of clusters.
+	 *  (default 2).
+	 * </pre>
+	 * 
+	 * <pre>
+	 * -S
+	 *  Maximum size of the finer graph during the coarsening phase.
+	 * </pre>
+	 * 
+	 * <!-- options-end -->
+	 * 
+	 * @param options
+	 *            the list of options as an array of strings
+	 * @throws Exception
+	 *             if an option is not supported
+	 */
+	@Override
+	public void setOptions(String[] options) throws Exception {
+		String optionString = Utils.getOption('N', options);
+		if (optionString.length() != 0) {
+			setNumClusters(Integer.parseInt(optionString));
+		}
+		optionString = Utils.getOption('S', options);
+		if (optionString.length() != 0) {
+			setSizeFinerGraph(Integer.parseInt(optionString));
+		}
+	}
+
+	/**
+	 * Gets the current settings of MetisMQIClusterer
+	 * 
+	 * @return an array of strings suitable for passing to setOptions()
+	 */
+	@SuppressWarnings("unchecked")
+	@Override
+	public String[] getOptions() {
+		Vector result;
+		result = new Vector();
+		result.add("-N");
+		result.add("" + getNumClusters());
+		result.add("-S");
+		result.add("" + getSizeFinerGraph());
+		return (String[]) result.toArray(new String[result.size()]);
+	}
+
+	private int getSizeFinerGraph() {
+		return sizeFinerGraph;
+	}
+
+	private int getNumClusters() {
+		return numberOfClusters;
+	}
+
+	/**
+	 * Returns an enumeration describing the available options.
+	 * 
+	 * @return an enumeration of all the available options.
+	 */
+	@SuppressWarnings("unchecked")
+	@Override
+	public Enumeration listOptions() {
+		Vector result = new Vector();
+		result.addElement(new Option("\tnumber of clusters.\n"
+				+ "\t(default 2).", "N", 1, "-N <num>"));
+		result.addElement(new Option("\tsize of finer graph.\n"
+				+ "\t(default 10).", "S", 1, "-S <num>"));
+		return result.elements();
+	}
+
+	private void setSizeFinerGraph(int size) {
+		this.sizeFinerGraph = size;
+	}
+
+	private void setNumClusters(int n) {
+		this.numberOfClusters = n;
+	}
+
+	@Override
+	public double[] distributionForInstance(Instance instance) throws Exception {
+		double[] d = new double[numberOfClusters()];
+		d[clusterInstance(instance)] = 1.0;
+		return d;
+	}
+
+	@Override
+	public Capabilities getCapabilities() {
+		Capabilities result = super.getCapabilities();
+		result.enable(Capability.NUMERIC_ATTRIBUTES);
+		result.enable(Capability.NO_CLASS);
+		return result;
+	}
+
+	@Override
+	public int numberOfClusters() throws Exception {
+		return numberOfClusters;
+	}
+
+	/**
+	 * Main method for executing this clusterer.
+	 * 
+	 * @param args
+	 *            the options, use "-h" to display options
+	 */
+	public static void main(String[] args) {
+		AbstractClusterer.runClusterer(new MetisMQIClusterer(), args);
+	}
+
+}
Index: src/main/java/weka/clusterers/SimpleClusterer.java
===================================================================
--- src/main/java/weka/clusterers/SimpleClusterer.java	(revision 13)
+++ 	(revision )
@@ -1,67 +1,0 @@
-package weka.clusterers;
-
-
-import weka.clusterers.forMetisMQI.GraphAlgorithms;
-import weka.clusterers.forMetisMQI.graph.UndirectedGraph;
-import weka.core.Capabilities;
-import weka.core.Instance;
-import weka.core.Instances;
-import weka.core.Capabilities.Capability;
-
-public class SimpleClusterer extends AbstractClusterer {
-
-	private int numberOfClusters = 0;
-
-	/**
-	 * 
-	 */
-	private static final long serialVersionUID = 1L;
-
-	@Override
-	public void buildClusterer(Instances data) throws Exception {
-		getCapabilities().testWithFail(data);
-		
-		UndirectedGraph g = new UndirectedGraph();
-		g.loadFromInstance(data);
-		GraphAlgorithms ga = new GraphAlgorithms();
-		ga.METIS(g);
-		numberOfClusters = 1;
-	}
-
-	@Override
-	public int clusterInstance(Instance instance) throws Exception {
-		return 0;
-	}
-
-	@Override
-	public double[] distributionForInstance(Instance instance) 
-	throws Exception {
-		double[] d = new double[numberOfClusters()];
-		d[clusterInstance(instance)] = 1.0;
-		return d;
-	}
-
-	@Override
-	public Capabilities getCapabilities() {
-		Capabilities result = super.getCapabilities();
-		result.enable(Capability.NUMERIC_ATTRIBUTES);
-		result.enable(Capability.NO_CLASS);
-		return result;
-	}
-
-	@Override
-	public int numberOfClusters() throws Exception {
-		return numberOfClusters;
-	}
-
-	/**
-	 * Main method for executing this clusterer.
-	 * 
-	 * @param args
-	 *            the options, use "-h" to display options
-	 */
-	public static void main(String[] args) {
-		AbstractClusterer.runClusterer(new SimpleClusterer(), args);
-	}
-
-}
Index: src/main/java/weka/clusterers/forMetisMQI/Coarse.java
===================================================================
--- src/main/java/weka/clusterers/forMetisMQI/Coarse.java	(revision 14)
+++ src/main/java/weka/clusterers/forMetisMQI/Coarse.java	(revision 14)
@@ -0,0 +1,197 @@
+package weka.clusterers.forMetisMQI;
+
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+
+import weka.clusterers.forMetisMQI.graph.Edge;
+import weka.clusterers.forMetisMQI.graph.Node;
+import weka.clusterers.forMetisMQI.graph.UndirectedGraph;
+import weka.clusterers.forMetisMQI.util.CoarserGraphElement;
+
+import edu.uci.ics.jung.graph.util.Pair;
+
+public class Coarse {
+	
+	private static boolean debug = false;
+	private static PrintStream debugStream = System.err;
+	private static int finerSize = 5;
+
+	/**
+	 * Return true if the vertex v is matched
+	 * 
+	 * @param g graph
+	 * @param v
+	 *            the index of the vertex
+	 * @return true if the vertex v is matched, false o.w.
+	 */
+	private static boolean isMatched(Map<Node,Node> match, Node v) {
+		if(match.containsKey(v))
+			return !match.get(v).equals(v);
+		else
+			return false;
+	}
+
+	private static void RMMatch(UndirectedGraph g, Map<Node,Node> match, Map<Node,Node> map) {
+		int labelCounter = 0;
+		Iterator<Node> nodeIterator = g.vtxsPermutation().iterator();
+		while (nodeIterator.hasNext()) {
+			Node u = nodeIterator.next();
+			if (debug)
+				debugStream.println("Visiting node " + u + " Matched = " + isMatched(match,u));
+			if (!isMatched(match,u)) {
+				boolean foundMatch = false;
+				Node matchedNode = null;
+				Iterator<Node> iterator = g.getNeighborsPermutation(u).iterator();
+				while(iterator.hasNext() && !foundMatch){
+					Node v = iterator.next();
+					if (!isMatched(match,v)) {
+						matchedNode = v;
+						foundMatch = true;
+						if (debug)
+							debugStream.println("Found a match with node "
+									+ matchedNode);
+					}
+				}
+				if (debug && !foundMatch)
+					debugStream.println("There aren't unmatched neighbors.");
+				Node newNode = new Node(Integer.toString(labelCounter));
+				if(foundMatch) {
+					match.put(u, matchedNode);
+					match.put(matchedNode, u);
+					map.put(u, newNode);
+					map.put(matchedNode, newNode);
+					if(debug) debugStream.println("Contracting node " + u + " with " + matchedNode + ". Node id: " + getMappedNode(map, u));
+				} else {
+					match.put(u, u);
+					map.put(u, newNode);
+					if(debug) debugStream.println("Node " + u + " with " + " new node id: " + getMappedNode(map, u));
+				}
+				labelCounter++;
+			}
+		}
+	}
+	
+	private static Node getMatchedNode(Map<Node,Node> match, Node u) {
+		return match.get(u);
+	}
+	
+	private static Node getMappedNode(Map<Node,Node> map, Node u) {
+		return map.get(u);
+	}
+	
+	/**
+	 * Return a new contracted graph.
+	 */
+	private static UndirectedGraph contract(UndirectedGraph g, Map<Node,Node> match, Map<Node,Node> map) {
+		UndirectedGraph output = new UndirectedGraph();
+		Iterator<Node> iterator = g.getVertices().iterator();
+		int i = 0;
+		while(iterator.hasNext()) {
+			Node u = iterator.next();
+			output.addVertex(getMappedNode(map,u));
+			
+			Set<Node> neighbors = new HashSet<Node>();
+			Iterator<Node> it = g.getNeighbors(u).iterator();
+			while(it.hasNext())
+				neighbors.add(getMappedNode(map, it.next()));
+			it = g.getNeighbors(getMatchedNode(match, u)).iterator();
+			while(it.hasNext())
+				neighbors.add(getMappedNode(map, it.next()));
+			neighbors.remove(getMappedNode(map,u));
+			it = neighbors.iterator();
+			while(it.hasNext()) {
+				Node v = it.next();
+				output.addVertex(v);
+				output.addEdge(new Edge(Integer.toString(i),0,0),getMappedNode(map,u), v);
+				i++;
+			}
+		}
+		
+		//calcolo dei pesi del nuovo grafo: per ogni arco (u,v) && u < v.
+		//w(map(u),map(v)) += w(u,v).
+		
+		Iterator<Edge> edgeIterator = g.getEdges().iterator();
+		while(edgeIterator.hasNext()) {
+			Edge oldEdge = edgeIterator.next();
+			Pair<Node> srcDst = g.getEndpoints(oldEdge);
+			Node src = srcDst.getFirst();
+			Node dst = srcDst.getSecond();
+			Node srcMapped = getMappedNode(map, src);
+			Node dstMapped = getMappedNode(map, dst);
+			if(!srcMapped.equals(dstMapped) && output.containsEdge(srcMapped, dstMapped)) {
+				Edge newEdge = output.findEdge(srcMapped, dstMapped);
+				newEdge.setWeight(newEdge.getWeight() + oldEdge.getWeight());
+			}
+		}
+		iterator = g.getVertices().iterator();
+		Set<Node> nodesComplete = new HashSet<Node>();
+		while(iterator.hasNext()) {
+			Node u = iterator.next();
+			if(isMatched(match,u)) {
+				Node v = getMatchedNode(match,u);
+				if(!nodesComplete.contains(u)) {
+					getMappedNode(map,u).setVwgt(u.getVwgt() + v.getVwgt());
+					getMappedNode(map,u).setCewgt(u.getCewgt() + v.getCewgt() + g.findEdge(u, v).getWeight());
+					nodesComplete.add(u);
+					nodesComplete.add(v);
+				}
+			} else {
+				getMappedNode(map,u).setVwgt(u.getVwgt());
+				getMappedNode(map,u).setCewgt(u.getCewgt());
+			}
+		}
+		return output;
+	}
+
+	/**
+	 * Performs the first stage of the METIS algorithm, using RM.
+	 */
+	private static CoarserGraphElement coarseOneStep(UndirectedGraph g) {
+		UndirectedGraph projected = g;
+		UndirectedGraph contracted = null;
+		Map<Node,Node> match = new HashMap<Node,Node>();
+		Map<Node,Node> map = new HashMap<Node,Node>();
+		RMMatch(g,match,map);
+		contracted = contract(g,match,map);
+		return new CoarserGraphElement(contracted, projected, match, map);
+	}
+
+	
+	/**
+	 * Performs at least one contraction of the given the graph, and goes on until the graph
+	 * is under the desidered size (see setFinerSize()).
+	 * @param g
+	 * @return the stack of contracted graphs
+	 */
+	public static Stack<CoarserGraphElement> coarse(UndirectedGraph g) {
+		Stack<CoarserGraphElement> stack = new Stack<CoarserGraphElement>();
+		CoarserGraphElement e = null;
+		UndirectedGraph curr = g;
+		int i = 0;
+		
+	    do {
+	    	if(debug)
+	    		debugStream.println("--------CONTRACTION-nr" + i +"------------------------------");
+	    	e = coarseOneStep(curr);
+	    	stack.push(e);
+	    	curr = e.getContracted();
+	    	if(debug) {
+	    		debugStream.println("-----------EXPANDED----------------------------------");
+	    		debugStream.println(e.getProjected().toString());
+	    		debugStream.println("-----------CONTRACTED--------------------------------");
+	    		debugStream.println(e.getContracted().toString());
+	    	}
+	    	i++;
+	    } while(e.getProjected().getVertexCount() > e.getContracted().getVertexCount() && e.getContracted().getVertexCount() > finerSize);
+	    return stack;
+	}
+
+	public static void setFinerSize(int i) {
+		finerSize = i;
+	}
+}
Index: src/main/java/weka/clusterers/forMetisMQI/GraphAlgorithms.java
===================================================================
--- src/main/java/weka/clusterers/forMetisMQI/GraphAlgorithms.java	(revision 13)
+++ src/main/java/weka/clusterers/forMetisMQI/GraphAlgorithms.java	(revision 14)
@@ -5,13 +5,20 @@
 import java.util.Stack;
 
-import weka.clusterers.forMetisMQI.coarse.Coarse;
-import weka.clusterers.forMetisMQI.coarse.CoarserGraphElement;
 import weka.clusterers.forMetisMQI.graph.Bisection;
 import weka.clusterers.forMetisMQI.graph.Node;
 import weka.clusterers.forMetisMQI.graph.UndirectedGraph;
+import weka.clusterers.forMetisMQI.util.CoarserGraphElement;
+import weka.clusterers.forMetisMQI.util.Util;
 
 public class GraphAlgorithms {
 
-	public Bisection KL(UndirectedGraph g) {
+	
+	/**
+	 * Given an undirected graph, performs the Kernighan-Li algorithm to find a bisection and
+	 * then returns it.
+	 * @param g
+	 * @return
+	 */
+	static public Bisection KL(UndirectedGraph g) {
 		Bisection partition = new Bisection(g);
 		Bisection result = partition;
@@ -28,25 +35,32 @@
 		return result;
 	}
+	
+	static public Bisection metis(UndirectedGraph g, int sizeFinerGraph) {
+		Coarse.setFinerSize(sizeFinerGraph);
+		Stack<CoarserGraphElement> stack = Coarse.coarse(g);
+		Bisection partition = null;
+		if (stack.size() > 0) {
+			partition = KL(stack.peek().getContracted());
+			partition = Uncoarse.uncoarse(stack, partition);
+		}
+		return partition;
+	}
 
-	public void METIS(UndirectedGraph g) {
-//		MQI.viewGraph(g);
+	/**
+	 * Given an UndirectedGraph, runs metis+mqi for <code>numberOfCluster</code> times and
+	 * returns a set of clusters. With the third parameter you can control the maximum size of the finer
+	 * graph during the coarsening phase.  
+	 * @param g
+	 * @param numberOfCluster
+	 * @param sizeFinerGraph
+	 */
+	static public Set<Set<Node>> metisMqi(UndirectedGraph g, int numberOfCluster, int sizeFinerGraph) {
 		Set<Set<Node>> clusters = new HashSet<Set<Node>>();
-		for (int i = 0; i < 8; i++) {
-			Coarse.setFinerSize(8);
-			Stack<CoarserGraphElement> stack = Coarse.coarse(g);
-			Bisection partition = null;
-			if (stack.size() > 0) {
-				partition = KL(stack.peek().getContracted());
-//				System.out.println(partition.toString());
-				partition = new Uncoarse().uncoarse(stack, partition);
-//				System.out.println(partition.toString());
-				Set<Node> cluster = MQI.mqi(partition);
-				clusters.add(cluster);
-//				Set<Set<Node>> foundCluster = new HashSet<Set<Node>>();
-//				foundCluster.add(cluster);
-//				MQI.viewClusters(g, foundCluster);
-			}
+		for (int i = 0; i < numberOfCluster; i++) {
+			Bisection partition = metis(g,sizeFinerGraph);
+			Set<Node> cluster = MQI.mqi(partition);
+			clusters.add(cluster);
 		}
-		MQI.viewClusters(g, clusters);
+		return clusters;
 	}
 
Index: src/main/java/weka/clusterers/forMetisMQI/MQI.java
===================================================================
--- src/main/java/weka/clusterers/forMetisMQI/MQI.java	(revision 13)
+++ src/main/java/weka/clusterers/forMetisMQI/MQI.java	(revision 14)
@@ -23,4 +23,5 @@
 import weka.clusterers.forMetisMQI.graph.UndirectedGraph;
 import edu.uci.ics.jung.algorithms.flows.EdmondsKarpMaxFlow;
+import edu.uci.ics.jung.algorithms.layout.FRLayout;
 import edu.uci.ics.jung.algorithms.layout.KKLayout;
 import edu.uci.ics.jung.algorithms.layout.Layout;
@@ -35,79 +36,4 @@
 	static int i = -1;
 	
-	public static void viewClusters(Graph<Node, Edge> g, Set<Set<Node>> clusters) {
-		Layout<Node, Edge> layout = new KKLayout<Node, Edge>(g);
-		layout.setSize(new Dimension(800, 600)); // sets the initial size of the space
-		// The BasicVisualizationServer<V,E> is parameterized by the edge types
-		BasicVisualizationServer<Node, Edge> vv = new BasicVisualizationServer<Node, Edge>(
-				layout);
-
-		class VertexPaintTransformer implements Transformer<Node, Paint> {
-			Set<Set<Node>> clusters = null;
-			Map<Set<Node>, Color> clustersColor = null;
-
-			public Set<Node> getCluster(Node node) {
-				Iterator<Set<Node>> clusterIterator = clusters.iterator();
-				while (clusterIterator.hasNext()) {
-					Set<Node> cluster = clusterIterator.next();
-					if (cluster.contains(node))
-						return cluster;
-				}
-				return null;
-			}
-
-			public VertexPaintTransformer(Set<Set<Node>> clusters) {
-				this.clusters = clusters;
-				clustersColor = new HashMap<Set<Node>, Color>(clusters.size());
-				Iterator<Set<Node>> clusterIterator = clusters.iterator();
-				while (clusterIterator.hasNext()) {
-					Set<Node> cluster = clusterIterator.next();
-					clustersColor.put(cluster, new Color(Random.instance()
-							.nextInt(256), Random.instance().nextInt(256),
-							Random.instance().nextInt(256)));
-				}
-			}
-
-			public Paint transform(Node i) {
-				Set<Node> cluster = getCluster(i);
-				if (cluster == null)
-					return Color.RED;
-				else
-					return clustersColor.get(getCluster(i));
-			}
-		}
-
-		Transformer<Node, Paint> vertexPaint = new VertexPaintTransformer(
-				clusters);
-		vv.setPreferredSize(new Dimension(800, 600)); // Sets the viewing area
-														// size
-		vv.getRenderContext().setVertexLabelTransformer(
-				new ToStringLabeller<Node>());
-		vv.getRenderContext().setEdgeLabelTransformer(
-				new ToStringLabeller<Edge>());
-		vv.getRenderContext().setVertexFillPaintTransformer(vertexPaint);
-		JFrame frame = new JFrame("Graph View");
-		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-		frame.getContentPane().add(vv);
-		frame.pack();
-		frame.setVisible(true);
-	}
-	
-	public static void viewGraph(Graph<Node, Edge> g){
-		Layout<Node, Edge> layout = new KKLayout<Node, Edge>(g);
-		layout.setSize(new Dimension(800,600)); // sets the initial size of the space
-		// The BasicVisualizationServer<V,E> is parameterized by the edge types
-		BasicVisualizationServer<Node,Edge> vv =
-		new BasicVisualizationServer<Node,Edge>(layout);
-		vv.setPreferredSize(new Dimension(800,600)); //Sets the viewing area size
-		vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller<Node>());
-		vv.getRenderContext().setEdgeLabelTransformer(new ToStringLabeller<Edge>());
-
-		JFrame frame = new JFrame("Simple Graph View");
-		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-		frame.getContentPane().add(vv);
-		frame.pack();
-		frame.setVisible(true);
-	}
-
 	static private Set<Node> BFSReversed(Node sink, DirectedGraph<Node, Edge> g, Map<Edge, Number> edgeFlowMap) {
 		Set<Node> result = new HashSet<Node>();
Index: src/main/java/weka/clusterers/forMetisMQI/Uncoarse.java
===================================================================
--- src/main/java/weka/clusterers/forMetisMQI/Uncoarse.java	(revision 13)
+++ src/main/java/weka/clusterers/forMetisMQI/Uncoarse.java	(revision 14)
@@ -4,13 +4,13 @@
 import java.util.Stack;
 
-import weka.clusterers.forMetisMQI.coarse.CoarserGraphElement;
 import weka.clusterers.forMetisMQI.graph.Bisection;
 import weka.clusterers.forMetisMQI.graph.Node;
 import weka.clusterers.forMetisMQI.graph.Subgraph;
 import weka.clusterers.forMetisMQI.graph.UndirectedGraph;
+import weka.clusterers.forMetisMQI.util.CoarserGraphElement;
 
 public class Uncoarse {
 	
-	private boolean projectedBelongs(Node u, Bisection partition, CoarserGraphElement cge) {
+	private static boolean projectedBelongs(Node u, Bisection partition, CoarserGraphElement cge) {
 		Subgraph s = partition.getSubgraph();
 		Node mappedNode = cge.getMap().get(u);
@@ -24,5 +24,5 @@
 	 * @param cge
 	 */
-	public Bisection uncoarseOneStep(Bisection partition, CoarserGraphElement cge) {
+	private static Bisection uncoarseOneStep(Bisection partition, CoarserGraphElement cge) {
 		UndirectedGraph projected = cge.getProjected();
 		Subgraph part = new Subgraph(projected);
@@ -36,5 +36,12 @@
 	}
 	
-	public Bisection uncoarse(Stack<CoarserGraphElement> stack, Bisection partition) {
+	/**
+	 * Given a bisection of the finer graph and the stack of graphs which yielded the finer graph,
+	 * it returns the bisection projected into the coarser graph. 
+	 * @param stack
+	 * @param partition
+	 * @return
+	 */
+	public static Bisection uncoarse(Stack<CoarserGraphElement> stack, Bisection partition) {
 		while(stack.size() > 0) {
 			CoarserGraphElement element = stack.pop();
@@ -43,7 +50,3 @@
 		return partition;
 	}
-	
-	public Uncoarse() {
-	}
-
 }
Index: src/main/java/weka/clusterers/forMetisMQI/graph/UndirectedGraph.java
===================================================================
--- src/main/java/weka/clusterers/forMetisMQI/graph/UndirectedGraph.java	(revision 13)
+++ src/main/java/weka/clusterers/forMetisMQI/graph/UndirectedGraph.java	(revision 14)
@@ -122,4 +122,3 @@
         return sb.toString();
 	}
-
 }
Index: src/main/java/weka/clusterers/forMetisMQI/util/CoarserGraphElement.java
===================================================================
--- src/main/java/weka/clusterers/forMetisMQI/util/CoarserGraphElement.java	(revision 14)
+++ src/main/java/weka/clusterers/forMetisMQI/util/CoarserGraphElement.java	(revision 14)
@@ -0,0 +1,38 @@
+package weka.clusterers.forMetisMQI.util;
+
+import java.util.Map;
+
+import weka.clusterers.forMetisMQI.graph.Node;
+import weka.clusterers.forMetisMQI.graph.UndirectedGraph;
+
+public class CoarserGraphElement {
+	
+	private UndirectedGraph contracted;
+	private UndirectedGraph projected;
+	private Map<Node,Node> match;
+	private Map<Node,Node> map;
+	
+	public CoarserGraphElement(UndirectedGraph contracted, UndirectedGraph projected, Map<Node,Node> match, Map<Node,Node> map) {
+		this.contracted = contracted;
+		this.projected = projected;
+		this.match = match;
+		this.map = map;
+	}
+	
+	public Map<Node,Node> getMatch() {
+		return match;
+	}
+	
+	public Map<Node,Node> getMap() {
+		return map;
+	}
+	
+	public UndirectedGraph getContracted() {
+		return contracted;
+	}
+	
+	public UndirectedGraph getProjected() {
+		return projected;
+	}
+
+}
Index: src/main/java/weka/clusterers/forMetisMQI/util/Util.java
===================================================================
--- src/main/java/weka/clusterers/forMetisMQI/util/Util.java	(revision 14)
+++ src/main/java/weka/clusterers/forMetisMQI/util/Util.java	(revision 14)
@@ -0,0 +1,131 @@
+package weka.clusterers.forMetisMQI.util;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Paint;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.swing.JFrame;
+
+import org.apache.commons.collections15.Transformer;
+
+import weka.clusterers.forMetisMQI.Random;
+import weka.clusterers.forMetisMQI.graph.Edge;
+import weka.clusterers.forMetisMQI.graph.Node;
+import weka.clusterers.forMetisMQI.graph.UndirectedGraph;
+import edu.uci.ics.jung.algorithms.layout.FRLayout;
+import edu.uci.ics.jung.algorithms.layout.Layout;
+import edu.uci.ics.jung.graph.Graph;
+import edu.uci.ics.jung.visualization.BasicVisualizationServer;
+import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
+
+public class Util {
+	public static void viewClusters(Graph<Node, Edge> g, Set<Set<Node>> clusters) {
+		Layout<Node, Edge> layout = new FRLayout<Node, Edge>(g);
+		layout.setSize(new Dimension(800, 600)); // sets the initial size of the space
+		// The BasicVisualizationServer<V,E> is parameterized by the edge types
+		BasicVisualizationServer<Node, Edge> vv = new BasicVisualizationServer<Node, Edge>(
+				layout);
+
+		class VertexPaintTransformer implements Transformer<Node, Paint> {
+			Set<Set<Node>> clusters = null;
+			Map<Set<Node>, Color> clustersColor = null;
+
+			public Set<Node> getCluster(Node node) {
+				Iterator<Set<Node>> clusterIterator = clusters.iterator();
+				while (clusterIterator.hasNext()) {
+					Set<Node> cluster = clusterIterator.next();
+					if (cluster.contains(node))
+						return cluster;
+				}
+				return null;
+			}
+
+			public VertexPaintTransformer(Set<Set<Node>> clusters) {
+				this.clusters = clusters;
+				clustersColor = new HashMap<Set<Node>, Color>(clusters.size());
+				Iterator<Set<Node>> clusterIterator = clusters.iterator();
+				while (clusterIterator.hasNext()) {
+					Set<Node> cluster = clusterIterator.next();
+					clustersColor.put(cluster, new Color(Random.instance()
+							.nextInt(256), Random.instance().nextInt(256),
+							Random.instance().nextInt(256)));
+				}
+			}
+
+			public Paint transform(Node i) {
+				Set<Node> cluster = getCluster(i);
+				if (cluster == null)
+					return Color.RED;
+				else
+					return clustersColor.get(getCluster(i));
+			}
+		}
+
+		Transformer<Node, Paint> vertexPaint = new VertexPaintTransformer(
+				clusters);
+		vv.setPreferredSize(new Dimension(800, 600)); // Sets the viewing area
+														// size
+		vv.getRenderContext().setVertexLabelTransformer(
+				new ToStringLabeller<Node>());
+		vv.getRenderContext().setEdgeLabelTransformer(
+				new ToStringLabeller<Edge>());
+		vv.getRenderContext().setVertexFillPaintTransformer(vertexPaint);
+		JFrame frame = new JFrame("Graph View");
+		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+		frame.getContentPane().add(vv);
+		frame.pack();
+		frame.setVisible(true);
+	}
+	
+	public static void viewGraph(Graph<Node, Edge> g){
+		Layout<Node, Edge> layout = new FRLayout<Node, Edge>(g);
+		layout.setSize(new Dimension(800,600)); // sets the initial size of the space
+		// The BasicVisualizationServer<V,E> is parameterized by the edge types
+		BasicVisualizationServer<Node,Edge> vv =
+		new BasicVisualizationServer<Node,Edge>(layout);
+		vv.setPreferredSize(new Dimension(800,600)); //Sets the viewing area size
+		vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller<Node>());
+		vv.getRenderContext().setEdgeLabelTransformer(new ToStringLabeller<Edge>());
+
+		JFrame frame = new JFrame("Simple Graph View");
+		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+		frame.getContentPane().add(vv);
+		frame.pack();
+		frame.setVisible(true);
+	}
+	
+	/**
+	 * Generates a small graph with 100 nodes and two big components.
+	 * For testing purpose.
+	 * @return the generated graph
+	 */
+	public UndirectedGraph generateGraph(){
+		UndirectedGraph g = new UndirectedGraph();
+		for (int i = 0; i < 50; i++) {
+			g.addVertex(new Node(Integer.toString(i)));
+		}
+		for (int j = 0; j < 120; j++) {
+			g.addEdge(new Edge(Integer.toString(j), 1, 1), new Node(Integer
+					.toString(Random.instance().nextInt(50))), new Node(Integer
+					.toString(Random.instance().nextInt(50))));
+		}
+		for (int i = 50; i < 100; i++) {
+			g.addVertex(new Node(Integer.toString(i)));
+		}
+		for (int j = 120; j < 240; j++) {
+			g.addEdge(new Edge(Integer.toString(j), 1, 1), new Node(Integer
+					.toString(50 + Random.instance().nextInt(50))), new Node(
+					Integer.toString(50 + Random.instance().nextInt(50))));
+		}
+		for (int j = 240; j < 250; j++) {
+			g.addEdge(new Edge(Integer.toString(j), 1, 1), new Node(Integer
+					.toString(50 + Random.instance().nextInt(50))), new Node(
+					Integer.toString(Random.instance().nextInt(50))));
+		}
+		return g;
+	}
+}
