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.clusterers.forMetisMQI.util.Configuration; 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 { /** * It maps each cluster with an integer id. */ private Map, Integer> clustersMap = null; /** * Holds the cluster membership for each node. */ private Map 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> clusters = GraphAlgorithms.metisMqi(g); setNumClusters(clusters.size()); int i = 0; Iterator> clusterIterator = clusters.iterator(); clustersMap = new HashMap, Integer>(); nodeMap = new HashMap(); while (clusterIterator.hasNext()) { Set cluster = clusterIterator.next(); clustersMap.put(cluster, i); Iterator 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. *

* * Valid options are: *

* *

	 * -N <num>
	 *  number of clusters.
	 *  (default 2).
	 * 
* *
	 * -S
	 *  Maximum size of the finer graph during the coarsening phase.
	 * 
* * * * @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)); } optionString = Utils.getOption('R', options); setRandomBisection(Boolean.parseBoolean(optionString)); optionString = Utils.getOption('V', options); if (optionString.length() != 0) { setVerboseLevel(Integer.parseInt(optionString)); } optionString = Utils.getOption('o', options); if (optionString.length() != 0) { setOutputFile(optionString); } } private void setOutputFile(String outputFile) { Configuration.instance().setOutputFile(outputFile); } private String getOutputFile() { return Configuration.instance().getOutputFile(); } private void setVerboseLevel(int verboseLevel) { Configuration.instance().setVerboseLevel(verboseLevel); } private void setRandomBisection(boolean b) { Configuration.instance().setRandomBisection(b); } /** * 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()); result.add("-R"); result.add("" + getRandomBisection()); result.add("-V"); result.add("" + getVerboseLevel()); result.add("-o"); result.add("" + getOutputFile()); return (String[]) result.toArray(new String[result.size()]); } private boolean getRandomBisection() { return Configuration.instance().isRandomBisection(); } private int getVerboseLevel() { return Configuration.instance().getVerboseLevel(); } private int getSizeFinerGraph() { return Configuration.instance().getSizeFinerGraph(); } private int getNumClusters() { return Configuration.instance().getNumberOfClusters(); } /** * 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 ")); result.addElement(new Option("\tsize of finer graph.\n" + "\t(default 10).", "S", 1, "-S ")); result.addElement(new Option("\trandom bisection.\n" + "\t(default false).", "R", 1, "-V ")); result.addElement(new Option("\tverbosity of graphical output.\n" + "\t(default 1).", "V", 1, "-V ")); result.addElement(new Option("\tpath of the output file.\n" , "o", 1, "-o ")); return result.elements(); } private void setSizeFinerGraph(int size) { Configuration.instance().setSizeFinerGraph(size); } private void setNumClusters(int n) { Configuration.instance().setNumberOfClusters(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 Configuration.instance().getNumberOfClusters(); } /** * 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); } }