Author: scooter
Date: 2010-11-18 17:48:12 -0800 (Thu, 18 Nov 2010)
New Revision: 22920
Added:
csplugins/trunk/ucsf/scooter/clusterMaker/src/clusterMaker/algorithms/SCPS/
csplugins/trunk/ucsf/scooter/clusterMaker/src/clusterMaker/algorithms/SCPS/KCluster.java
csplugins/trunk/ucsf/scooter/clusterMaker/src/clusterMaker/algorithms/SCPS/RunSCPS.java
csplugins/trunk/ucsf/scooter/clusterMaker/src/clusterMaker/algorithms/SCPS/SCPSCluster.java
Modified:
csplugins/trunk/ucsf/scooter/clusterMaker/src/clusterMaker/ClusterMaker.java
Log:
Add first pass at SCPS clustering
Modified:
csplugins/trunk/ucsf/scooter/clusterMaker/src/clusterMaker/ClusterMaker.java
===================================================================
---
csplugins/trunk/ucsf/scooter/clusterMaker/src/clusterMaker/ClusterMaker.java
2010-11-19 01:24:27 UTC (rev 22919)
+++
csplugins/trunk/ucsf/scooter/clusterMaker/src/clusterMaker/ClusterMaker.java
2010-11-19 01:48:12 UTC (rev 22920)
@@ -66,6 +66,7 @@
import clusterMaker.algorithms.MCODE.MCODECluster;
import clusterMaker.algorithms.glay.GLayCluster;
import clusterMaker.algorithms.ConnectedComponents.ConnectedComponentsCluster;
+import clusterMaker.algorithms.SCPS.SCPSCluster;
// import clusterMaker.algorithms.QT.QTCluster;
// import clusterMaker.algorithms.Spectral.SpectralCluster;
// import clusterMaker.algorithms.CP.CPCluster;
@@ -109,15 +110,17 @@
addClusterAlgorithm(menu, new HierarchicalCluster());
addClusterAlgorithm(menu, new KMeansCluster());
// addClusterAlgorithm(menu, new QTCluster());
+ menu.addSeparator();
+ addClusterAlgorithm(menu, new APCluster());
+ addClusterAlgorithm(menu, new ConnectedComponentsCluster());
+ addClusterAlgorithm(menu, new GLayCluster());
addClusterAlgorithm(menu, new MCODECluster());
addClusterAlgorithm(menu, new MCLCluster());
// addClusterAlgorithm(menu, new SpectralCluster());
// addClusterAlgorithm(menu, new CPCluster());
- addClusterAlgorithm(menu, new APCluster());
- addClusterAlgorithm(menu, new GLayCluster());
// addClusterAlgorithm(menu, new FORCECluster());
+ addClusterAlgorithm(menu, new SCPSCluster());
addClusterAlgorithm(menu, new TransClustCluster());
- addClusterAlgorithm(menu, new ConnectedComponentsCluster());
// addClusterAlgorithm(new HOPACHCluster());
menu.addSeparator();
Added:
csplugins/trunk/ucsf/scooter/clusterMaker/src/clusterMaker/algorithms/SCPS/KCluster.java
===================================================================
---
csplugins/trunk/ucsf/scooter/clusterMaker/src/clusterMaker/algorithms/SCPS/KCluster.java
(rev 0)
+++
csplugins/trunk/ucsf/scooter/clusterMaker/src/clusterMaker/algorithms/SCPS/KCluster.java
2010-11-19 01:48:12 UTC (rev 22920)
@@ -0,0 +1,526 @@
+/* vim: set ts=2: */
+/**
+ * Copyright (c) 2008 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions, and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. Redistributions must acknowledge that this software was
+ * originally developed by the UCSF Computer Graphics Laboratory
+ * under support by the NIH National Center for Research Resources,
+ * grant P41-RR01081.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+package clusterMaker.algorithms.SCPS;
+
+import java.awt.GridLayout;
+import java.lang.Math;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Random;
+import javax.swing.JPanel;
+
+
+
+// clusterMaker imports
+import cern.colt.matrix.doublealgo.Statistic;
+
+import cern.colt.matrix.DoubleFactory2D;
+import cern.colt.matrix.DoubleMatrix1D;
+import cern.colt.matrix.DoubleMatrix2D;
+import cern.colt.matrix.impl.SparseDoubleMatrix2D;
+
+import cern.colt.list.IntArrayList;
+import cern.colt.list.DoubleArrayList;
+
+
+public class KCluster {
+
+
+
+
+ // Random seeds for uniform()
+ static int seed1 = 0;
+ static int seed2 = 0;
+ static boolean debug = false;
+
+
+
+
+ //perform Kmeans clustering on columns of matrix, the size of whose
row is K
+ public static int kmeans(int nClusters, int nIterations, DoubleMatrix2D
matrix,
+ int[] clusterID) {
+
+ int nelements = matrix.columns();
+ int ifound = 1;
+
+ int[] tclusterid = new int[nelements];
+
+ int[] saved = new int[nelements];
+
+ int[] mapping = new int[nClusters];
+ int[] counts = new int[nClusters];
+
+ double error = Double.MAX_VALUE;
+
+ // This matrix will store the centroid data. KxK matrix
+ SparseDoubleMatrix2D cData = new
SparseDoubleMatrix2D(nClusters, nClusters);
+
+ // Outer initialization
+ if (nIterations <= 1) {
+ for (int i=0; i < clusterID.length; i++) {
+ tclusterid[i] = clusterID[i];
+ }
+ nIterations = 1;
+ } else {
+ for (int i = 0; i < nelements; i++)
+ clusterID[i] = 0;
+ }
+
+ int iteration = 0;
+ do {
+ double total = Double.MAX_VALUE;
+ int counter = 0;
+ int period = 10;
+
+ // Randomly assign elements to clusters
+ if (nIterations != 0) randomAssign(nClusters,
nelements, tclusterid);
+
+
+ // Initialize
+ for (int i = 0; i < nClusters; i++) counts[i] = 0;
+ for (int i = 0; i < nelements; i++)
counts[tclusterid[i]]++;
+
+ while (true) {
+ double previous = total;
+ total = 0.0;
+ if (counter % period == 0) // Save the current
cluster assignments
+ {
+ for (int i = 0; i < nelements; i++)
+ saved[i] = tclusterid[i];
+ if (period < Integer.MAX_VALUE / 2)
+ period *= 2;
+ }
+ counter++;
+
+ //assign centroids as to maximize orthogonality
on first iteration of kmeans
+ if(iteration == 0)
+ selectCentroidsOrthogonally(nClusters,
matrix, cData);
+
+ // Find the centeroids based on cluster means
on all other iterations
+ else
+ getClusterMeans(nClusters, matrix, cData,
tclusterid);
+
+
+ for (int i = 0; i < nelements; i++) {
+ // Calculate the distances
+ double distance;
+ int k = tclusterid[i];
+ if (counts[k]==1) continue;
+
+ // Get the distance
+
+ distance =
getDistance(i,k,matrix,cData);
+
+ for (int j = 0; j < nClusters; j++) {
+ double tdistance;
+ if (j==k) continue;
+
+ tdistance =
getDistance(i,k,matrix,cData);
+ if (tdistance < distance)
+ {
+ distance = tdistance;
+ counts[tclusterid[i]]--;
+ tclusterid[i] = j;
+ counts[j]++;
+ }
+ }
+ total += distance;
+ }
+
+ if (total>=previous) break;
+ /* total>=previous is FALSE on some machines even if total and previous
+ * are bitwise identical. */
+ int i;
+ for (i = 0; i < nelements; i++)
+ if (saved[i]!=tclusterid[i]) break;
+ if (i==nelements)
+ break; /* Identical solution found; break out of this loop */
+ }
+
+ if (nIterations<=1)
+ { error = total;
+ break;
+ }
+
+ for (int i = 0; i < nClusters; i++) mapping[i] = -1;
+
+ int element = 0;
+ for (element = 0; element < nelements; element++)
+ {
+ int j = tclusterid[element];
+ int k = clusterID[element];
+ if (mapping[k] == -1)
+ mapping[k] = j;
+ else if (mapping[k] != j)
+ {
+ if (total < error)
+ {
+ ifound = 1;
+ error = total;
+ // System.out.println("Mapping
tclusterid to clusterid");
+ for (int i = 0; i < nelements; i++) clusterID[i] =
tclusterid[i];
+ }
+ break;
+ }
+ }
+ if (element==nelements) ifound++; /* break statement not encountered */
+ } while (++iteration < nIterations);
+
+
+ return ifound;
+ }
+
+
+
+ //Assign centroids to rows with maximal orthogonality
+ private static void selectCentroidsOrthogonally(int nClusters,
DoubleMatrix2D data, DoubleMatrix2D cdata){
+
+ //number of centroids allready set
+ int centroid_count = 0;
+
+ //centroid assigned element == 1 if centroid assigned, zero
otherwise
+ int[] centroid_assigned = new int[nClusters];
+ for (int i = 0; i < nClusters; i++){centroid_assigned[i] = 0;}
+
+ //randomly select first centroid
+ int centroid_id = binomial(nClusters-1,1.0/(double)(nClusters-1));
+
+ for(int i = 0; i < nClusters; i++){
+
+ //update centroid assinged array
+ centroid_assigned[centroid_id] = 1;
+
+ DoubleMatrix1D centroid = data.viewRow(centroid_id);
+
+ //copy newly selected centroid from data matrix
+ for(int j = 0; j < centroid.size(); j++)
+ cdata.set(centroid_count,j,centroid.get(j));
+
+ centroid_count++;
+
+ if(centroid_count == nClusters)
+ break;
+
+ int min_cosine = 10000;
+ int new_centroid_id = -1;
+
+ //loop through rows of data matrix, seach for next centroid,
which will minimize the cosine angle (dot product) with current centroid
+ for(int j = 0; j < data.rows(); i++){
+
+ //ignore centroids that allready have been set
+ if(centroid_assigned[j] == 1)
+ continue;
+
+ double cosine = centroid.zDotProduct(data.viewRow(j));
+
+ //if new cosine value < min cosine value, update min_cosine
and new_centroid_id to reflect taht
+ if(min_cosine > cosine){
+
+ cosine = min_cosine;
+ new_centroid_id = j;
+ }
+ }
+
+
+ centroid_id = new_centroid_id;
+
+ }
+ }
+
+
+
+
+ private static void getClusterMeans(int nClusters, DoubleMatrix2D data,
DoubleMatrix2D cdata, int[] clusterid) {
+
+ double[][]cmask = new double[nClusters][nClusters];
+
+ for (int i = 0; i < nClusters; i++) {
+ for (int j = 0; j < data.columns(); j++) {
+ //cdata.setValue(i, j, null);
+ cmask[i][j] = 0.0;
+ }
+ }
+
+ for (int k = 0; k < data.rows(); k++) {
+
+ //cetroid id
+ int i = clusterid[k];
+
+
+
+
+
+ for (int j = 0; j < data.columns(); j++) {
+
+
+ if (data.get(k,j) != 0) {
+ double cValue = 0.0;
+ double dataValue = data.get(k,j);
+ if (cdata.get(i,j) != 0) {
+ cValue = cdata.get(i,j);
+ }
+ cdata.set(i,j, cValue+dataValue);
+ cmask[i][j] = cmask[i][j] + 1.0;
+ }
+ }
+ }
+ for (int i = 0; i < nClusters; i++) {
+ for (int j = 0; j < data.columns(); j++) {
+ if (cmask[i][j] > 0.0) {
+ double cData = cdata.get(i,j) / cmask[i][j];
+ cdata.set(i,j,cData);
+ }
+ }
+ }
+ }
+
+
+ //get Euclidian Distance between two rows of matrix. Use colt Euclidian
Distance function
+ private static double getDistance(int row1_id, int row2_id, DoubleMatrix2D
matrix, DoubleMatrix2D cdata){
+
+
+ DoubleMatrix1D row1 = matrix.viewRow(row1_id);
+ DoubleMatrix1D row2 = cdata.viewRow(row2_id);
+
+ return Statistic.EUCLID.apply(row1,row2);
+ }
+
+
+ private static void randomAssign (int nClusters, int nElements, int[]
clusterID) {
+ int n = nElements - nClusters;
+ int k = 0;
+ int i = 0;
+ for (i = 0; i < nClusters-1; i++) {
+ double p = 1.0/(nClusters-1);
+ int j = binomial(n, p);
+ n -= j;
+ j += k+1; // Assign at least one element to cluster i
+ for (;k<j; k++) clusterID[k] = i;
+ }
+ // Assign the remaining elements to the last cluster
+ for (; k < nElements; k++) clusterID[k] = i;
+
+ // Create a random permutation of the cluster assignments
+ for (i = 0; i < nElements; i++) {
+ int j = (int) (i + (nElements-i)*uniform());
+ k = clusterID[j];
+ clusterID[j] = clusterID[i];
+ clusterID[i] = k;
+ }
+ }
+
+ // Debug version of "randomAssign" that isn't random
+ private static void debugAssign (int nClusters, int nElements, int[]
clusterID) {
+ for (int element = 0; element < nElements; element++) {
+ clusterID[element] = element%nClusters;
+ }
+ }
+
+ /**
+ * This routine generates a random number between 0 and n inclusive,
following
+ * the binomial distribution with probability p and n trials. The
routine is
+ * based on the BTPE algorithm, described in:
+ *
+ * Voratas Kachitvichyanukul and Bruce W. Schmeiser:
+ * Binomial Random Variate Generation
+ * Communications of the ACM, Volume 31, Number 2, February 1988, pages
216-222.
+ *
+ * @param p The probability of a single event. This should be less
than or equal to 0.5.
+ * @param n The number of trials
+ * @return An integer drawn from a binomial distribution with
parameters (p, n).
+ */
+
+ private static int binomial (int n, double p) {
+ double q = 1 - p;
+ if (n*p < 30.0) /* Algorithm BINV */
+ {
+ double s = p/q;
+ double a = (n+1)*s;
+ double r = Math.exp(n*Math.log(q)); /* pow() causes a
crash on AIX */
+ int x = 0;
+ double u = uniform();
+ while(true)
+ {
+ if (u < r) return x;
+ u-=r;
+ x++;
+ r *= (a/x)-s;
+ }
+ }
+ else /* Algorithm BTPE */
+ { /* Step 0 */
+ double fm = n*p + p;
+ int m = (int) fm;
+ double p1 = Math.floor(2.195*Math.sqrt(n*p*q) -4.6*q) +
0.5;
+ double xm = m + 0.5;
+ double xl = xm - p1;
+ double xr = xm + p1;
+ double c = 0.134 + 20.5/(15.3+m);
+ double a = (fm-xl)/(fm-xl*p);
+ double b = (xr-fm)/(xr*q);
+ double lambdal = a*(1.0+0.5*a);
+ double lambdar = b*(1.0+0.5*b);
+ double p2 = p1*(1+2*c);
+ double p3 = p2 + c/lambdal;
+ double p4 = p3 + c/lambdar;
+ while (true)
+ { /* Step 1 */
+ int y;
+ int k;
+ double u = uniform();
+ double v = uniform();
+ u *= p4;
+ if (u <= p1) return (int)(xm-p1*v+u);
+ /* Step 2 */
+ if (u > p2)
+ { /* Step 3 */
+ if (u > p3)
+ { /* Step 4 */
+ y =
(int)(xr-Math.log(v)/lambdar);
+ if (y > n) continue;
+ /* Go to step 5 */
+ v = v*(u-p3)*lambdar;
+ }
+ else
+ {
+ y =
(int)(xl+Math.log(v)/lambdal);
+ if (y < 0) continue;
+ /* Go to step 5 */
+ v = v*(u-p2)*lambdal;
+ }
+ }
+ else
+ {
+ double x = xl + (u-p1)/c;
+ v = v*c + 1.0 - Math.abs(m-x+0.5)/p1;
+ if (v > 1) continue;
+ /* Go to step 5 */
+ y = (int)x;
+ }
+ /* Step 5 */
+ /* Step 5.0 */
+ k = Math.abs(y-m);
+ if (k > 20 && k < 0.5*n*p*q-1.0)
+ { /* Step 5.2 */
+ double rho = (k/(n*p*q))*((k*(k/3.0 +
0.625) + 0.1666666666666)/(n*p*q)+0.5);
+ double t = -k*k/(2*n*p*q);
+ double A = Math.log(v);
+ if (A < t-rho) return y;
+ else if (A > t+rho) continue;
+ else
+ { /* Step 5.3 */
+ double x1 = y+1;
+ double f1 = m+1;
+ double z = n+1-m;
+ double w = n-y+1;
+ double x2 = x1*x1;
+ double f2 = f1*f1;
+ double z2 = z*z;
+ double w2 = w*w;
+ if (A > xm * Math.log(f1/x1) +
(n-m+0.5)*Math.log(z/w)
+ +
(y-m)*Math.log(w*p/(x1*q))
+ +
(13860.-(462.-(132.-(99.-140./f2)/f2)/f2)/f2)/f1/166320.
+ +
(13860.-(462.-(132.-(99.-140./z2)/z2)/z2)/z2)/z/166320.
+ +
(13860.-(462.-(132.-(99.-140./x2)/x2)/x2)/x2)/x1/166320.
+ +
(13860.-(462.-(132.-(99.-140./w2)/w2)/w2)/w2)/w/166320.)
+ continue;
+ return y;
+ }
+ }
+ else
+ { /* Step 5.1 */
+ int i;
+ double s = p/q;
+ double aa = s*(n+1);
+ double f = 1.0;
+ for (i = m; i < y; f *= (aa/(++i)-s));
+ for (i = y; i < m; f /= (aa/(++i)-s));
+ if (v > f) continue;
+ return y;
+ }
+ }
+ }
+ }
+
+ /**
+ * This routine returns a uniform random number between 0.0 and 1.0.
Both 0.0
+ * and 1.0 are excluded. This random number generator is described in:
+ *
+ * Pierre l'Ecuyer
+ * Efficient and Portable Combined Random Number Generators
+ * Communications of the ACM, Volume 31, Number 6, June 1988, pages
742-749,774.
+ *
+ * The first time this routine is called, it initializes the random
number
+ * generator using the current time. First, the current epoch time in
seconds is
+ * used as a seed for the random number generator in the C library. The
first two
+ * random numbers generated by this generator are used to initialize
the random
+ * number generator implemented in this routine.
+ *
+ * NOTE: how different is this from Java's Math.random() or
Random.nextDouble()?
+ *
+ * @return A double-precison number between 0.0 and 1.0.
+ */
+ private static double uniform() {
+ int z;
+ int m1 = 2147483563;
+ int m2 = 2147483399;
+ double scale = 1.0/m1;
+
+ if (seed1==0 || seed2==0) /* initialize */
+ {
+ Date date = new Date();
+ int initseed = (int) date.getTime();
+ Random r = new Random(initseed);
+ seed1 = r.nextInt();
+ seed2 = r.nextInt();
+ }
+
+ do
+ {
+ int k;
+ k = seed1/53668;
+ seed1 = 40014*(seed1-k*53668)-k*12211;
+ if (seed1 < 0) seed1+=m1;
+ k = seed2/52774;
+ seed2 = 40692*(seed2-k*52774)-k*3791;
+ if(seed2 < 0) seed2+=m2;
+ z = seed1-seed2;
+ if(z < 1) z+=(m1-1);
+ } while (z==m1); /* To avoid returning 1.0 */
+
+ return z*scale;
+ }
+}
Added:
csplugins/trunk/ucsf/scooter/clusterMaker/src/clusterMaker/algorithms/SCPS/RunSCPS.java
===================================================================
---
csplugins/trunk/ucsf/scooter/clusterMaker/src/clusterMaker/algorithms/SCPS/RunSCPS.java
(rev 0)
+++
csplugins/trunk/ucsf/scooter/clusterMaker/src/clusterMaker/algorithms/SCPS/RunSCPS.java
2010-11-19 01:48:12 UTC (rev 22920)
@@ -0,0 +1,418 @@
+/**
+ * Copyright (c) 2010 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions, and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. Redistributions must acknowledge that this software was
+ * originally developed by the UCSF Computer Graphics Laboratory
+ * under support by the NIH National Center for Research Resources,
+ * grant P41-RR01081.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+package clusterMaker.algorithms.SCPS;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.lang.Math;
+
+import cytoscape.Cytoscape;
+import cytoscape.CyNetwork;
+import cytoscape.CyEdge;
+import cytoscape.CyNode;
+import cytoscape.data.CyAttributes;
+import cytoscape.groups.CyGroup;
+import cytoscape.groups.CyGroupManager;
+import cytoscape.logger.CyLogger;
+import cytoscape.task.TaskMonitor;
+
+import clusterMaker.algorithms.NodeCluster;
+import clusterMaker.algorithms.DistanceMatrix;
+import clusterMaker.algorithms.ClusterResults;
+
+import cern.colt.function.IntIntDoubleFunction;
+import cern.colt.matrix.DoubleFactory2D;
+import cern.colt.matrix.DoubleMatrix1D;
+import cern.colt.matrix.DoubleMatrix2D;
+import cern.colt.matrix.impl.SparseDoubleMatrix2D;
+import cern.colt.matrix.linalg.EigenvalueDecomposition;
+import cern.colt.matrix.linalg.SingularValueDecomposition;
+
+
+
+import cern.colt.matrix.linalg.Algebra;
+import cern.colt.list.IntArrayList;
+import cern.colt.list.DoubleArrayList;
+
+import clusterMaker.algorithms.SCPS.KCluster;
+
+public class RunSCPS {
+
+
+
+ private List<CyNode> nodes;
+ private List<CyEdge> edges;
+ private boolean canceled = false;
+ private CyLogger logger;
+ public final static String GROUP_ATTRIBUTE = "__SCPSGroups";
+ protected int clusterCount = 0;
+ private boolean createMetaNodes = false;
+ private DistanceMatrix distanceMatrix = null;
+ private DoubleMatrix2D matrix = null;
+ private boolean debug = false;
+
+ private double epsilon;
+ private int kvalue;
+ private int rnumber;
+ private DoubleMatrix2D LMat;
+
+
+ private HashMap<Integer, NodeCluster> clusterMap;
+
+ private HashMap<Integer,Integer> index2indexMap;
+
+
+
+ public RunSCPS(DistanceMatrix dMat, double epsilon, int kvalue, int
rnumber, CyLogger logger )
+ {
+ this.distanceMatrix = dMat;
+ this.epsilon = epsilon;
+ this.kvalue = kvalue;
+ this.rnumber = rnumber;
+
+ this.logger = logger;
+ this.clusterMap = new HashMap();
+ this.clusterCount = 0;
+ nodes = distanceMatrix.getNodes();
+ edges = distanceMatrix.getEdges();
+ this.matrix = distanceMatrix.getDistanceMatrix();
+
+
+ //index2index maps indices of filtered nodes in new uMatrix to
the the original in the complete, unfiltered matrix
+ this.index2indexMap = new HashMap();
+ }
+
+
+ public void halt () { canceled = true; }
+
+ public List<NodeCluster> run(TaskMonitor monitor)
+ {
+
+ monitor.setStatus("Formatting Matrix Data");
+ DoubleMatrix2D sMat = getSMat(this.distanceMatrix);
+ DoubleMatrix2D LMat = getLMat(sMat);
+ monitor.setStatus("Calculating Eigenvalues");
+ DoubleMatrix2D uMat = getUMat(LMat);
+ monitor.setStatus("Running kmeans clustering");
+ doKMeansClustering(uMat);
+
+ //clusterMap calculated in getSMat and doKMeansClustering steps.
Simply return the results
+ return new ArrayList(this.clusterMap.values());
+
+
+ }
+
+ //map index2index key-value pair
+ public void setMap(int old_index, int new_index){
+
+ this.index2indexMap.put(new Integer(new_index), new
Integer(old_index));
+ }
+
+ //return value of old_index in index2index map
+ public int getMap(int new_index){
+
+ return ((Integer)this.index2indexMap.get(new
Integer(new_index))).intValue();
+ }
+
+ //Get Connected Components, cluster all components <= |5|, and connect
the remaining components with random lowscoring edges
+ public DoubleMatrix2D getSMat(DistanceMatrix distanceMatrix){
+
+ //Matrix prior to filtration modification
+ DoubleMatrix2D unfiltered_mat = distanceMatrix.getDistanceMatrix();
+
+ //Size of newly created Umat after filtering of small components
+ int sMat_rows = 0;
+
+ HashMap<Integer, List<CyNode>> filtered_cmap = new HashMap();
+
+ //Connected Componets
+ Map<Integer, List<CyNode>> cMap =
distanceMatrix.findConnectedComponents();
+
+ IntArrayList rowList = null;
+ IntArrayList columnList = null;
+ DoubleArrayList valueList = null;
+
+ //Iterate through connected components
+ Iterator it = cMap.entrySet().iterator();
+
+ while(it.hasNext()){
+
+ Map.Entry entry = (Map.Entry)it.next();
+ List<CyNode> component = (List<CyNode>)entry.getValue();
+
+ //Size <= 5. Automatically create cluster and increment
clusterCount. Delete component from Map.
+ if(component.size() <= 5){
+
+ NodeCluster iCluster = new NodeCluster();
+ iCluster.add(component,this.clusterCount);
+ this.clusterMap.put(new Integer(clusterCount),iCluster);
+ this.clusterCount++;
+
+
+
+ }
+
+ //iterate through components and assign them index mappings in
new uMatrix
+ else{
+
+ for(int i = 0; i < component.size(); i++){
+
+ CyNode n = component.get(i);
+
+ //set mapping of new matrix index to old index
+ setMap(this.nodes.indexOf(n), sMat_rows);
+ sMat_rows++;
+ }
+
+ }
+
+ }
+
+ SparseDoubleMatrix2D sMat = new SparseDoubleMatrix2D(sMat_rows,
sMat_rows);
+
+ //set diagnols of sMat to one
+ for(int i = 0; i < sMat_rows; i++)
+ sMat.set(i,i,1);
+
+
+ //iterate through nonzero edges. If both nodes in new index map,
transfer the edge to new matrix
+ unfiltered_mat.getNonZeros(rowList,columnList,valueList);
+
+ for(int i = 0; i<rowList.size(); i++){
+
+ int row_id = rowList.get(i);
+ int column_id = columnList.get(i);
+
+ int new_row_id = getMap(row_id);
+ int new_column_id = getMap(column_id);
+ double value = valueList.get(i);
+
+ //Set symmetrically the values in new matrix
+ if(new_row_id > -1 && new_column_id > -1)
+ {
+ sMat.set(new_row_id,new_column_id,value);
+ sMat.set(new_column_id,new_row_id,value);
+ }
+
+ }
+
+ //Normalize sMat
+ sMat.forEachNonZero(new Normalize(Double.MIN_VALUE,Double.MAX_VALUE,
1));
+
+ return sMat;
+
+ }
+
+ //Calculate negative square root of matrix using singular value
decomposition
+ //http://en.wikipedia.org/wiki/Square_root_of_a_matrix
+ public DoubleMatrix2D getNegSqrRoot(DoubleMatrix2D A){
+
+ //A = USV, where S is Diagnol Matrix
+ SingularValueDecomposition decomp = new
SingularValueDecomposition(A);
+ DoubleMatrix2D U = decomp.getU();
+ DoubleMatrix2D S = decomp.getS();
+ DoubleMatrix2D V = decomp.getV();
+
+ //S^1/2 = Square root of every value in diangol matrix
+ for(int i = 0; i < S.rows(); i++)
+ S.set(i,i,Math.pow(S.get(i,i),.5));
+
+ //A^1/2 = VS^1/2U
+ Algebra alg = new Algebra();
+ DoubleMatrix2D sqrtA = alg.mult(alg.mult(V,S),U);
+
+ //return A^-1/2
+ return alg.inverse(sqrtA);
+
+
+ }
+
+
+ // L = D^-1/2 * S * D^-1/2
+ public DoubleMatrix2D getLMat(DoubleMatrix2D sMat){
+
+ Algebra alg = new Algebra();
+ DoubleMatrix2D transDMat = getNegSqrRoot(sMat);
+
+ return alg.mult(transDMat,alg.mult(sMat,transDMat));
+ }
+
+ //D is Diagnol Matrix formed of vertex degree Dii = Sum Columns j over
row Si
+
+ public DoubleMatrix2D getDMat(DoubleMatrix2D sMat){
+
+
+ DoubleMatrix2D dMat = sMat.like();
+
+ for(int i = 0; i < sMat.rows(); i++){
+
+ //set the Diagnal (i,i) to sum of columns over row i
+ dMat.set(i,i, sMat.viewRow(i).zSum());
+ }
+
+
+ return dMat;
+
+ }
+
+ //U constructed from top K Eigenvectors of L. After construction, each
row of U is normalized to unit length.
+
+ public DoubleMatrix2D getUMat(DoubleMatrix2D LMat){
+
+ int k;
+ DoubleMatrix2D uMat;
+ double prevLamb;
+ double nextLamb;
+
+ IntArrayList indexList = null;
+ DoubleArrayList valueList = null;
+
+ EigenvalueDecomposition decomp = new
EigenvalueDecomposition(LMat);
+
+ //eigenvectors
+ DoubleMatrix2D eigenVect = decomp.getV();
+
+ //eigenvalues
+ DoubleMatrix1D eigenVal = decomp.getRealEigenvalues();
+
+ //set K. Use Epsilon to calculate K is this.kvalue not set
+ if(this.kvalue > -1)
+ k = this.kvalue;
+
+ //set K to smallest integer such that LambdaK+1/LambdaK >
epsilon
+ else{
+
+ prevLamb = eigenVal.get(0);
+
+ for(k = 1; k < eigenVal.size(); k++){
+
+ nextLamb = eigenVal.get(k);
+
+ if(nextLamb/prevLamb > this.epsilon)
+ break;
+
+ prevLamb = nextLamb;
+ }
+ }
+
+
+ //construct matrix U from first K eigenvectors
+ uMat = eigenVect.viewPart(0,0,eigenVect.rows()-1,k);
+
+ //Normalize each row of matrix U
+ for(int i = 0; i < uMat.columns(); i++){
+
+ DoubleMatrix1D row = uMat.viewRow(i);
+ double sum = row.zSum();
+ row.getNonZeros(indexList,valueList);
+
+ //normalize each Nozero value in row
+
+ for(int j = 0; j < indexList.size(); j ++){
+
+ int index = indexList.get(j);
+ double value = valueList.get(j)/sum;
+
+ uMat.set(i,index,value);
+ }
+
+ }
+
+
+ return uMat;
+ }
+
+ public void doKMeansClustering(DoubleMatrix2D uMat){
+
+ int k = uMat.rows();
+
+ int[] clusters = new int[uMat.columns()];
+
+ //do kmeans clustering
+ KCluster.kmeans(k,rnumber,uMat,clusters);
+
+ //Loop through clustering results, getting the clusters by order
+
+ for(int cluster_id = 0; cluster_id < k; cluster_id++){
+
+ NodeCluster iCluster = new NodeCluster();
+ List<CyNode> node_list = new ArrayList();
+
+ for(int j = 0; j < clusters.length; j++){
+
+ //node j in uMatrix belongs to cluster k
+ if(clusters[j] == k)
+ node_list.add(this.nodes.get(getMap(j)));
+ }
+
+ iCluster.add(node_list,this.clusterCount);
+ this.clusterMap.put(new Integer(clusterCount),iCluster);
+ this.clusterCount++;
+ }
+
+
+
+ }
+
+
+ /**
+ * Normalize normalizes a cell in the matrix
+ */
+ private class Normalize implements IntIntDoubleFunction {
+ private double maxValue;
+ private double minValue;
+ private double span;
+ private double factor;
+ private double minWeight = Double.MAX_VALUE;
+
+ public Normalize(double minValue, double maxValue, double
factor) {
+ this.maxValue = maxValue;
+ this.minValue = minValue;
+ this.factor = factor;
+ span = maxValue - minValue;
+ }
+
+ public double apply(int row, int column, double value) {
+ return ((value-minWeight)/span)*factor;
+ }
+ }
+
+
+}
+
Added:
csplugins/trunk/ucsf/scooter/clusterMaker/src/clusterMaker/algorithms/SCPS/SCPSCluster.java
===================================================================
---
csplugins/trunk/ucsf/scooter/clusterMaker/src/clusterMaker/algorithms/SCPS/SCPSCluster.java
(rev 0)
+++
csplugins/trunk/ucsf/scooter/clusterMaker/src/clusterMaker/algorithms/SCPS/SCPSCluster.java
2010-11-19 01:48:12 UTC (rev 22920)
@@ -0,0 +1,203 @@
+/* vim: set ts=2: */
+/**
+ * Copyright (c) 2008 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions, and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. Redistributions must acknowledge that this software was
+ * originally developed by the UCSF Computer Graphics Laboratory
+ * under support by the NIH National Center for Research Resources,
+ * grant P41-RR01081.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+package clusterMaker.algorithms.SCPS;
+
+import java.awt.Dimension;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import javax.swing.JPanel;
+
+// Cytoscape imports
+import cytoscape.CyEdge;
+import cytoscape.CyNetwork;
+import cytoscape.CyNode;
+import cytoscape.Cytoscape;
+import cytoscape.data.CyAttributes;
+import cytoscape.layout.Tunable;
+import cytoscape.layout.TunableListener;
+import cytoscape.logger.CyLogger;
+import cytoscape.task.TaskMonitor;
+
+import clusterMaker.ClusterMaker;
+import clusterMaker.algorithms.AbstractNetworkClusterer;
+import clusterMaker.algorithms.NodeCluster;
+import clusterMaker.algorithms.ClusterAlgorithm;
+import clusterMaker.algorithms.ClusterResults;
+import clusterMaker.algorithms.DistanceMatrix;
+import clusterMaker.algorithms.EdgeAttributeHandler;
+import clusterMaker.ui.ClusterViz;
+import clusterMaker.ui.NewNetworkView;
+
+// clusterMaker imports
+
+public class SCPSCluster extends AbstractNetworkClusterer {
+
+ double epsilon = 1.0;
+ int rNumber = 8;
+ int knumber = -1;
+
+ EdgeAttributeHandler edgeAttributeHandler = null;
+
+ TaskMonitor monitor = null;
+ CyLogger logger = null;
+ RunSCPS runSCPS = null;
+
+ public SCPSCluster() {
+ super();
+ clusterAttributeName =
Cytoscape.getCurrentNetwork().getIdentifier()+"_SCPS_cluster";
+ logger = CyLogger.getLogger(SCPSCluster.class);
+ initializeProperties();
+ }
+
+ public String getShortName() {return "SCPS";};
+ public String getName() {return "SCPS cluster";};
+
+ public JPanel getSettingsPanel() {
+ // Everytime we ask for the panel, we want to update our
attributes
+ edgeAttributeHandler.updateAttributeList();
+
+ return clusterProperties.getTunablePanel();
+ }
+
+ public ClusterViz getVisualizer() {
+ return new NewNetworkView(true);
+ }
+
+ public void initializeProperties() {
+ super.initializeProperties();
+
+ /**
+ * Tuning values
+ */
+ clusterProperties.add(new Tunable("tunables_panel",
+ "SCPS Tuning",
+ Tunable.GROUP, new
Integer(3)));
+
+ // Lambda Parameter
+ clusterProperties.add(new Tunable("epsilon",
+ "epsilon Parameter",
+ Tunable.DOUBLE, new
Double(1.0),
+ (Object)null, (Object)null,
0));
+
+
+ // Number of iterations
+ clusterProperties.add(new Tunable("rNumber",
+ "Number of iterations",
+ Tunable.INTEGER, new
Integer(10),
+ (Object)null, (Object)null,
0));
+
+
+ // K. Trumps epsilon if set to greater then zero
+ clusterProperties.add(new Tunable("knumber",
+ "Number of clusters",
+ Tunable.INTEGER, new
Integer(-1),
+ (Object)null, (Object)null,
0));
+
+
+ // Use the standard edge attribute handling stuff....
+ edgeAttributeHandler = new
EdgeAttributeHandler(clusterProperties, true);
+
+ super.advancedProperties();
+
+ clusterProperties.initializeProperties();
+ updateSettings(true);
+ }
+
+ public void updateSettings() {
+ updateSettings(false);
+ }
+
+ public void updateSettings(boolean force) {
+ clusterProperties.updateValues();
+ super.updateSettings(force);
+
+ Tunable t = clusterProperties.get("epsilon");
+ if ((t != null) && (t.valueChanged() || force))
+ epsilon = ((Double) t.getValue()).doubleValue();
+
+ t = clusterProperties.get("knumber");
+ if ((t != null) && (t.valueChanged() || force))
+ knumber = ((Integer) t.getValue()).intValue();
+
+
+ t = clusterProperties.get("rNumber");
+ if ((t != null) && (t.valueChanged() || force))
+ rNumber = ((Integer) t.getValue()).intValue();
+
+ edgeAttributeHandler.updateSettings(force);
+ }
+
+ public void doCluster(TaskMonitor monitor) {
+ this.monitor = monitor;
+ CyNetwork network = Cytoscape.getCurrentNetwork();
+ String networkID = network.getIdentifier();
+
+ CyAttributes netAttributes = Cytoscape.getNetworkAttributes();
+ CyAttributes nodeAttributes = Cytoscape.getNodeAttributes();
+
+ DistanceMatrix matrix = edgeAttributeHandler.getMatrix();
+
+ //Cluster the nodes
+ runSCPS = new RunSCPS(matrix, epsilon, knumber, rNumber,
logger);
+
+ List<NodeCluster> clusters = runSCPS.run(monitor);
+
+ logger.info("Removing groups");
+
+ // Remove any leftover groups from previous runs
+ removeGroups(netAttributes, networkID);
+
+ logger.info("Creating groups");
+ monitor.setStatus("Creating groups");
+
+ List<List<CyNode>> nodeClusters =
+ createGroups(netAttributes, networkID, nodeAttributes,
clusters);
+
+ ClusterResults results = new ClusterResults(network,
nodeClusters);
+ monitor.setStatus("Done. SCPS results:\n"+results);
+
+
+ // Tell any listeners that we're done
+ pcs.firePropertyChange(ClusterAlgorithm.CLUSTER_COMPUTED, null,
this);
+ }
+
+ public void halt() {
+ runSCPS.halt();
+ }
+
+}
--
You received this message because you are subscribed to the Google Groups
"cytoscape-cvs" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/cytoscape-cvs?hl=en.