/* * Cluster.java The cluster-vertex class. * Copyright (c) 2005-2007 Andrew Krizhanovsky /aka at mail.iias.spb.su/ * Distributed under GNU Public License. * */ package wikipedia.clustering; import java.util.Arrays; import java.util.ArrayList; import java.util.List; /** * Class Description * */ abstract class Cluster { /** Edges tied this cluster with others */ //protected ArrayList<Edge> edges; protected Edge[] edges; /** Number of merged edges by clusters, i.e. * number of edges between vertices of the cluster. */ protected int edges_merged; /** The weight (size) of the cluster */ protected int weight; /** Creates a new instance of Cluster */ public Cluster() { } abstract String graphVizCluster(); public String toString() { String s = getClass().getName(); if(null != edges) { s += "; edges.len="+edges.length; } s += "; edges_merged="+edges_merged; s += "; weight=" + weight; return s; } /** Return the string like (for the graphviz .bat file): * :: clusters:11 */ public static String getStatistics (List<ClusterCategory> clusters) { return new String(":: clusters:" + clusters.size()); } public void addEdge(Edge e) { Edge[] n; if(null == edges) { n = new Edge[1]; } else { if(Arrays.asList(edges).contains(e)) return; n = new Edge[edges.length + 1]; for(int i=0; i<edges.length; i++) n[i] = edges[i]; } n[n.length-1] = e; edges = n; } /** Add cluster c to this cluster. * 1) Increase size of the cluster, * 2) Increase number of merged edges, * 3) Add all edges adjacent to c (with check: skip edge's repetition), update edges[].c1 and c2 * 4) Remove edge (this, c) * 5) Update or remove edges of merged (deleted) cluster. * @return list of removed edges (belong to the cluster c) */ public List<Edge> addCluster(Cluster c) { weight += c.weight; List<Edge> remove_edges = new ArrayList<Edge>(); List<Cluster> adjacent_clusters = getAdjacentVertices(); assert(!adjacent_clusters.contains(this)); adjacent_clusters.remove(c); // remove edge (this, c) Edge edge_merged = getEdgeToCluster(c); edges = Edge.RemoveEdge(edges, edge_merged); // remove edge (c, this) assert(edge_merged == c.getEdgeToCluster(this)); c.edges = Edge.RemoveEdge(c.edges, edge_merged); // update this.edges taking edges from merged cluster c { Edge[] c_edges = c.getAdjacentEdges(); if(null != c_edges && 0 < c_edges.length) { ArrayList<Edge> all = new ArrayList<Edge>(); if(null != edges) all.addAll(Arrays.asList(edges)); for(int i=0; i<c_edges.length; i++) { Edge e = c_edges[i]; if (e!=edge_merged) { // skip edge (c, this) if(!e.containsVertices(adjacent_clusters)) { all.add(e); } } } edges = (Edge[])all.toArray(Edge.NULL_EDGE_ARRAY); } } // update edges.v1 and .v2 for clusters adjacent to c List<Cluster> c_clusters = c.getAdjacentVertices(); if(null != c_clusters) { for(int i=0; i<c_clusters.size(); i++) { Edge r = c_clusters.get(i).updateEdgesOfMergedCluster(c, this); if (null != r) { remove_edges.add(r); } } } edges_merged += remove_edges.size(); return remove_edges; } /** Update or remove edges of merged (deleted) cluster. * Since adjacent cluster c_delete was added to cluster c (c_delete -> c), * then 1) if there are two edges (this, c_delete) and (this, c) then remove (this, c_delete). * 2) replace edges (this, c_delete) by (this, c); * @return list of removed edges or null */ public Edge updateEdgesOfMergedCluster(Cluster c_delete, Cluster c) { if(null == edges) return null; assert (c_delete != c); Edge this_to_c = null; Edge this_to_c_delete = null; // search edge to c, and edge to c_delete for(int i=0; i<edges.length; i++) { Edge e = edges[i]; if (e.containsVertex(c)) { this_to_c = e; } if (e.containsVertex(c_delete)) { this_to_c_delete = e; } } if (null != this_to_c && null != this_to_c_delete) {// 1) edges = Edge.RemoveEdge(edges, this_to_c_delete); return this_to_c_delete; } else { if (null != this_to_c_delete) { // 2) this_to_c_delete.replaceVertex(c_delete, c); } } return null; } /** Check whether the edge contains the sought cluster */ public boolean containsAdjacent(Cluster sought) { if (sought == this) return true; for(int i=0; i<edges.length; i++) { if(edges[i].containsVertex(sought)) return true; } return false; } /** Get list of adjacent clusters */ public List<Cluster> getAdjacentVertices() { List<Cluster> result = new ArrayList<Cluster>(); if(null != edges && 0 < edges.length) { for(int i=0; i<edges.length; i++) { Cluster c1 = edges[i].getVertex1(); Cluster c2 = edges[i].getVertex2(); result.add( ((c1 == this) ? c2 : c1) ) ; } } return result; } /** Get edge from adjacent edges with vertices (this, c) */ public Edge getEdgeToCluster(Cluster c) { if(null == edges) return null; for(int i=0; i<edges.length; i++) { Edge e = edges[i]; Cluster c1 = e.getVertex1(); Cluster c2 = e.getVertex2(); if (c1 == c || c2 == c) return e; } // unreachable code assert("Error in Cluster.getEdgeToCluster(): the non-adjacent cluster requested as adjacent" == ""); return null; } /** Update weight of all adjacent edges */ public void updateEdgesWeight() { if(null != edges) { for(int i=0; i<edges.length; i++) { edges[i].updateWeight(); } } } /** Get array of edges adjacent to the vertex (cluster) */ public Edge[] getAdjacentEdges() { return edges; } /** Get array of adjacent edges with the exception of the edge e */ /*public List<Edge> getAdjacentEdgesWithoutEdge(Edge e_exception) { List<Edge> result = new ArrayList<Edge>(); for(int i=0; i<edges.size(); i++) { Edge e = edges.get(i); if (e != e_exception) result.add(e); } return result; }*/ }