JAL-1767 refactorings to enable faithful restore of PCA from project
[jalview.git] / src / jalview / analysis / PCA.java
index 3ec7995..b3268df 100755 (executable)
@@ -23,6 +23,7 @@ package jalview.analysis;
 import jalview.api.analysis.ScoreModelI;
 import jalview.api.analysis.SimilarityParamsI;
 import jalview.datamodel.AlignmentView;
+import jalview.datamodel.Point;
 import jalview.math.MatrixI;
 
 import java.io.PrintStream;
@@ -32,28 +33,39 @@ import java.io.PrintStream;
  */
 public class PCA implements Runnable
 {
-  MatrixI symm;
+  /*
+   * inputs
+   */
+  final private AlignmentView seqs;
+
+  final private ScoreModelI scoreModel;
 
-  double[] eigenvalue;
+  final private SimilarityParamsI similarityParams;
 
-  MatrixI eigenvector;
+  /*
+   * outputs
+   */
+  private MatrixI pairwiseScores;
 
-  StringBuilder details = new StringBuilder(1024);
+  private MatrixI afterTred;
 
-  final private AlignmentView seqs;
+  private MatrixI eigenvector;
 
-  private ScoreModelI scoreModel;
-  
-  private SimilarityParamsI similarityParams;
+  private String details;
 
-  public PCA(AlignmentView s, ScoreModelI sm, SimilarityParamsI options)
+  /**
+   * Constructor given the sequences to compute for, the similarity model to
+   * use, and a set of parameters for sequence comparison
+   * 
+   * @param sequences
+   * @param sm
+   * @param options
+   */
+  public PCA(AlignmentView sequences, ScoreModelI sm, SimilarityParamsI options)
   {
-    this.seqs = s;
-    this.similarityParams = options;
+    this.seqs = sequences;
     this.scoreModel = sm;
-    
-    details.append("PCA calculation using " + sm.getName()
-            + " sequence similarity matrix\n========\n\n");
+    this.similarityParams = options;
   }
 
   /**
@@ -83,15 +95,16 @@ public class PCA implements Runnable
    * 
    * @return DOCUMENT ME!
    */
-  public float[][] getComponents(int l, int n, int mm, float factor)
+  public Point[] getComponents(int l, int n, int mm, float factor)
   {
-    float[][] out = new float[getHeight()][3];
+    Point[] out = new Point[getHeight()];
 
     for (int i = 0; i < getHeight(); i++)
     {
-      out[i][0] = (float) component(i, l) * factor;
-      out[i][1] = (float) component(i, n) * factor;
-      out[i][2] = (float) component(i, mm) * factor;
+      float x = (float) component(i, l) * factor;
+      float y = (float) component(i, n) * factor;
+      float z = (float) component(i, mm) * factor;
+      out[i] = new Point(x, y, z);
     }
 
     return out;
@@ -132,58 +145,83 @@ public class PCA implements Runnable
   {
     double out = 0.0;
 
-    for (int i = 0; i < symm.width(); i++)
+    for (int i = 0; i < pairwiseScores.width(); i++)
     {
-      out += (symm.getValue(row, i) * eigenvector.getValue(i, n));
+      out += (pairwiseScores.getValue(row, i) * eigenvector.getValue(i, n));
     }
 
     return out / eigenvector.getD()[n];
   }
 
+  /**
+   * Answers a formatted text report of the PCA calculation results (matrices
+   * and eigenvalues) suitable for display
+   * 
+   * @return
+   */
   public String getDetails()
   {
-    return details.toString();
+    return details;
+    /*
+    StringBuilder sb = new StringBuilder(1024);
+    sb.append("PCA calculation using ").append(scoreModel.getName())
+            .append(" sequence similarity matrix\n========\n\n");
+    PrintStream ps = wrapOutputBuffer(sb);
+    
+    sb.append(" --- OrigT * Orig ---- \n");
+    pairwiseScores.print(ps, "%8.2f");
+    
+    sb.append(" ---Tridiag transform matrix ---\n");
+    sb.append(" --- D vector ---\n");
+    afterTred.printD(ps, "%15.4e");
+    ps.println();
+    sb.append("--- E vector ---\n");
+    afterTred.printE(ps, "%15.4e");
+    ps.println();
+    
+    sb.append(" --- New diagonalization matrix ---\n");
+    eigenvector.print(ps, "%8.2f");
+    sb.append(" --- Eigenvalues ---\n");
+    eigenvector.printD(ps, "%15.4e");
+    ps.println();
+    
+    return sb.toString();
+    */
   }
 
   /**
-   * DOCUMENT ME!
+   * Performs the PCA calculation
    */
   @Override
   public void run()
   {
-    PrintStream ps = new PrintStream(System.out)
-    {
-      @Override
-      public void print(String x)
-      {
-        details.append(x);
-      }
-
-      @Override
-      public void println()
-      {
-        details.append("\n");
-      }
-    };
+    /*
+     * print details to a string buffer as they are computed
+     */
+    StringBuilder sb = new StringBuilder(1024);
+    sb.append("PCA calculation using ").append(scoreModel.getName())
+            .append(" sequence similarity matrix\n========\n\n");
+    PrintStream ps = wrapOutputBuffer(sb);
 
-    // long now = System.currentTimeMillis();
     try
     {
       eigenvector = scoreModel.findSimilarities(seqs, similarityParams);
 
-      details.append(" --- OrigT * Orig ---- \n");
+      sb.append(" --- OrigT * Orig ---- \n");
       eigenvector.print(ps, "%8.2f");
 
-      symm = eigenvector.copy();
+      pairwiseScores = eigenvector.copy();
 
       eigenvector.tred();
 
-      details.append(" ---Tridiag transform matrix ---\n");
-      details.append(" --- D vector ---\n");
-      eigenvector.printD(ps, "%15.4e");
+      afterTred = eigenvector.copy();
+
+      sb.append(" ---Tridiag transform matrix ---\n");
+      sb.append(" --- D vector ---\n");
+      afterTred.printD(ps, "%15.4e");
       ps.println();
-      details.append("--- E vector ---\n");
-      eigenvector.printE(ps, "%15.4e");
+      sb.append("--- E vector ---\n");
+      afterTred.printE(ps, "%15.4e");
       ps.println();
 
       // Now produce the diagonalization matrix
@@ -191,24 +229,45 @@ public class PCA implements Runnable
     } catch (Exception q)
     {
       q.printStackTrace();
-      details.append("\n*** Unexpected exception when performing PCA ***\n"
+      sb.append("\n*** Unexpected exception when performing PCA ***\n"
               + q.getLocalizedMessage());
-      details.append("*** Matrices below may not be fully diagonalised. ***\n");
+      sb.append(
+              "*** Matrices below may not be fully diagonalised. ***\n");
     }
 
-    details.append(" --- New diagonalization matrix ---\n");
+    sb.append(" --- New diagonalization matrix ---\n");
     eigenvector.print(ps, "%8.2f");
-    details.append(" --- Eigenvalues ---\n");
+    sb.append(" --- Eigenvalues ---\n");
     eigenvector.printD(ps, "%15.4e");
     ps.println();
-    /*
-     * for (int seq=0;seq<symm.rows;seq++) { ps.print("\"Seq"+seq+"\""); for
-     * (int ev=0;ev<symm.rows; ev++) {
-     * 
-     * ps.print(","+component(seq, ev)); } ps.println(); }
-     */
-    // System.out.println(("PCA.run() took "
-    // + (System.currentTimeMillis() - now) + "ms"));
+
+    details = sb.toString();
+  }
+
+  /**
+   * Returns a PrintStream that wraps (appends its output to) the given
+   * StringBuilder
+   * 
+   * @param sb
+   * @return
+   */
+  protected PrintStream wrapOutputBuffer(StringBuilder sb)
+  {
+    PrintStream ps = new PrintStream(System.out)
+    {
+      @Override
+      public void print(String x)
+      {
+        sb.append(x);
+      }
+
+      @Override
+      public void println()
+      {
+        sb.append("\n");
+      }
+    };
+    return ps;
   }
 
   /**
@@ -220,6 +279,37 @@ public class PCA implements Runnable
   public int getHeight()
   {
     // TODO can any of seqs[] be null?
-    return seqs.getSequences().length;
+    return pairwiseScores.height();// seqs.getSequences().length;
+  }
+
+  /**
+   * Answers the sequence pairwise similarity scores which were the first step
+   * of the PCA calculation
+   * 
+   * @return
+   */
+  public MatrixI getPairwiseScores()
+  {
+    return pairwiseScores;
+  }
+
+  public void setPairwiseScores(MatrixI m)
+  {
+    pairwiseScores = m;
+  }
+
+  public MatrixI getEigenmatrix()
+  {
+    return eigenvector;
+  }
+
+  public void setEigenmatrix(MatrixI m)
+  {
+    eigenvector = m;
+  }
+
+  public void setDetails(String d)
+  {
+    details = d;
   }
 }