8d95203b1c6f4b532a8fb06309179a6bbe211b2d
[jalview.git] / src / jalview / math / Matrix.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.0b1)
3  * Copyright (C) 2014 The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  * The Jalview Authors are detailed in the 'AUTHORS' file.
18  */
19 package jalview.math;
20
21 import java.io.*;
22
23 import jalview.util.*;
24
25 /**
26  * DOCUMENT ME!
27  * 
28  * @author $author$
29  * @version $Revision$
30  */
31 public class Matrix
32 {
33   /**
34    * SMJSPUBLIC
35    */
36   public double[][] value;
37
38   /** DOCUMENT ME!! */
39   public int rows;
40
41   /** DOCUMENT ME!! */
42   public int cols;
43
44   /** DOCUMENT ME!! */
45   public double[] d; // Diagonal
46
47   /** DOCUMENT ME!! */
48   public double[] e; // off diagonal
49
50   /**
51    * maximum number of iterations for tqli 
52    * 
53    */
54   int maxIter = 45; // fudge - add 15 iterations, just in case
55
56   /**
57    * Creates a new Matrix object.
58    * 
59    * @param value
60    *          DOCUMENT ME!
61    * @param rows
62    *          DOCUMENT ME!
63    * @param cols
64    *          DOCUMENT ME!
65    */
66   public Matrix(double[][] value, int rows, int cols)
67   {
68     this.rows = rows;
69     this.cols = cols;
70     this.value = value;
71   }
72
73   /**
74    * DOCUMENT ME!
75    * 
76    * @return DOCUMENT ME!
77    */
78   public Matrix transpose()
79   {
80     double[][] out = new double[cols][rows];
81
82     for (int i = 0; i < cols; i++)
83     {
84       for (int j = 0; j < rows; j++)
85       {
86         out[i][j] = value[j][i];
87       }
88     }
89
90     return new Matrix(out, cols, rows);
91   }
92
93   /**
94    * DOCUMENT ME!
95    * 
96    * @param ps
97    *          DOCUMENT ME!
98    */
99   public void print(PrintStream ps)
100   {
101     for (int i = 0; i < rows; i++)
102     {
103       for (int j = 0; j < cols; j++)
104       {
105         Format.print(ps, "%8.2f", value[i][j]);
106       }
107
108       ps.println();
109     }
110   }
111
112   /**
113    * DOCUMENT ME!
114    * 
115    * @param in
116    *          DOCUMENT ME!
117    * 
118    * @return DOCUMENT ME!
119    */
120   public Matrix preMultiply(Matrix in)
121   {
122     double[][] tmp = new double[in.rows][this.cols];
123
124     for (int i = 0; i < in.rows; i++)
125     {
126       for (int j = 0; j < this.cols; j++)
127       {
128         tmp[i][j] = 0.0;
129
130         for (int k = 0; k < in.cols; k++)
131         {
132           tmp[i][j] += (in.value[i][k] * this.value[k][j]);
133         }
134       }
135     }
136
137     return new Matrix(tmp, in.rows, this.cols);
138   }
139
140   /**
141    * DOCUMENT ME!
142    * 
143    * @param in
144    *          DOCUMENT ME!
145    * 
146    * @return DOCUMENT ME!
147    */
148   public double[] vectorPostMultiply(double[] in)
149   {
150     double[] out = new double[in.length];
151
152     for (int i = 0; i < in.length; i++)
153     {
154       out[i] = 0.0;
155
156       for (int k = 0; k < in.length; k++)
157       {
158         out[i] += (value[i][k] * in[k]);
159       }
160     }
161
162     return out;
163   }
164
165   /**
166    * DOCUMENT ME!
167    * 
168    * @param in
169    *          DOCUMENT ME!
170    * 
171    * @return DOCUMENT ME!
172    */
173   public Matrix postMultiply(Matrix in)
174   {
175     double[][] out = new double[this.rows][in.cols];
176
177     for (int i = 0; i < this.rows; i++)
178     {
179       for (int j = 0; j < in.cols; j++)
180       {
181         out[i][j] = 0.0;
182
183         for (int k = 0; k < rows; k++)
184         {
185           out[i][j] = out[i][j] + (value[i][k] * in.value[k][j]);
186         }
187       }
188     }
189
190     return new Matrix(out, this.cols, in.rows);
191   }
192
193   /**
194    * DOCUMENT ME!
195    * 
196    * @return DOCUMENT ME!
197    */
198   public Matrix copy()
199   {
200     double[][] newmat = new double[rows][cols];
201
202     for (int i = 0; i < rows; i++)
203     {
204       for (int j = 0; j < cols; j++)
205       {
206         newmat[i][j] = value[i][j];
207       }
208     }
209
210     return new Matrix(newmat, rows, cols);
211   }
212
213   /**
214    * DOCUMENT ME!
215    */
216   public void tred()
217   {
218     int n = rows;
219     int l;
220     int k;
221     int j;
222     int i;
223
224     double scale;
225     double hh;
226     double h;
227     double g;
228     double f;
229
230     this.d = new double[rows];
231     this.e = new double[rows];
232
233     for (i = n; i >= 2; i--)
234     {
235       l = i - 1;
236       h = 0.0;
237       scale = 0.0;
238
239       if (l > 1)
240       {
241         for (k = 1; k <= l; k++)
242         {
243           scale += Math.abs(value[i - 1][k - 1]);
244         }
245
246         if (scale == 0.0)
247         {
248           e[i - 1] = value[i - 1][l - 1];
249         }
250         else
251         {
252           for (k = 1; k <= l; k++)
253           {
254             value[i - 1][k - 1] /= scale;
255             h += (value[i - 1][k - 1] * value[i - 1][k - 1]);
256           }
257
258           f = value[i - 1][l - 1];
259
260           if (f > 0)
261           {
262             g = -1.0 * Math.sqrt(h);
263           }
264           else
265           {
266             g = Math.sqrt(h);
267           }
268
269           e[i - 1] = scale * g;
270           h -= (f * g);
271           value[i - 1][l - 1] = f - g;
272           f = 0.0;
273
274           for (j = 1; j <= l; j++)
275           {
276             value[j - 1][i - 1] = value[i - 1][j - 1] / h;
277             g = 0.0;
278
279             for (k = 1; k <= j; k++)
280             {
281               g += (value[j - 1][k - 1] * value[i - 1][k - 1]);
282             }
283
284             for (k = j + 1; k <= l; k++)
285             {
286               g += (value[k - 1][j - 1] * value[i - 1][k - 1]);
287             }
288
289             e[j - 1] = g / h;
290             f += (e[j - 1] * value[i - 1][j - 1]);
291           }
292
293           hh = f / (h + h);
294
295           for (j = 1; j <= l; j++)
296           {
297             f = value[i - 1][j - 1];
298             g = e[j - 1] - (hh * f);
299             e[j - 1] = g;
300
301             for (k = 1; k <= j; k++)
302             {
303               value[j - 1][k - 1] -= ((f * e[k - 1]) + (g * value[i - 1][k - 1]));
304             }
305           }
306         }
307       }
308       else
309       {
310         e[i - 1] = value[i - 1][l - 1];
311       }
312
313       d[i - 1] = h;
314     }
315
316     d[0] = 0.0;
317     e[0] = 0.0;
318
319     for (i = 1; i <= n; i++)
320     {
321       l = i - 1;
322
323       if (d[i - 1] != 0.0)
324       {
325         for (j = 1; j <= l; j++)
326         {
327           g = 0.0;
328
329           for (k = 1; k <= l; k++)
330           {
331             g += (value[i - 1][k - 1] * value[k - 1][j - 1]);
332           }
333
334           for (k = 1; k <= l; k++)
335           {
336             value[k - 1][j - 1] -= (g * value[k - 1][i - 1]);
337           }
338         }
339       }
340
341       d[i - 1] = value[i - 1][i - 1];
342       value[i - 1][i - 1] = 1.0;
343
344       for (j = 1; j <= l; j++)
345       {
346         value[j - 1][i - 1] = 0.0;
347         value[i - 1][j - 1] = 0.0;
348       }
349     }
350   }
351   
352   /**
353    * DOCUMENT ME!
354    */
355   public void tqli() throws Exception
356   {
357     int n = rows;
358
359     int m;
360     int l;
361     int iter;
362     int i;
363     int k;
364     double s;
365     double r;
366     double p;
367     ;
368
369     double g;
370     double f;
371     double dd;
372     double c;
373     double b;
374
375     for (i = 2; i <= n; i++)
376     {
377       e[i - 2] = e[i - 1];
378     }
379
380     e[n - 1] = 0.0;
381
382     for (l = 1; l <= n; l++)
383     {
384       iter = 0;
385
386       do
387       {
388         for (m = l; m <= (n - 1); m++)
389         {
390           dd = Math.abs(d[m - 1]) + Math.abs(d[m]);
391
392           if ((Math.abs(e[m - 1]) + dd) == dd)
393           {
394             break;
395           }
396         }
397
398         if (m != l)
399         {
400           iter++;
401
402           if (iter == maxIter)
403           {
404             throw new Exception("Too many iterations in tqli ("+maxIter+")");
405           }
406           else
407           {
408             // System.out.println("Iteration " + iter);
409           }
410
411           g = (d[l] - d[l - 1]) / (2.0 * e[l - 1]);
412           r = Math.sqrt((g * g) + 1.0);
413           g = d[m - 1] - d[l - 1] + (e[l - 1] / (g + sign(r, g)));
414           c = 1.0;
415           s = c;
416           p = 0.0;
417
418           for (i = m - 1; i >= l; i--)
419           {
420             f = s * e[i - 1];
421             b = c * e[i - 1];
422
423             if (Math.abs(f) >= Math.abs(g))
424             {
425               c = g / f;
426               r = Math.sqrt((c * c) + 1.0);
427               e[i] = f * r;
428               s = 1.0 / r;
429               c *= s;
430             }
431             else
432             {
433               s = f / g;
434               r = Math.sqrt((s * s) + 1.0);
435               e[i] = g * r;
436               c = 1.0 / r;
437               s *= c;
438             }
439
440             g = d[i] - p;
441             r = ((d[i - 1] - g) * s) + (2.0 * c * b);
442             p = s * r;
443             d[i] = g + p;
444             g = (c * r) - b;
445
446             for (k = 1; k <= n; k++)
447             {
448               f = value[k - 1][i];
449               value[k - 1][i] = (s * value[k - 1][i - 1]) + (c * f);
450               value[k - 1][i - 1] = (c * value[k - 1][i - 1]) - (s * f);
451             }
452           }
453
454           d[l - 1] = d[l - 1] - p;
455           e[l - 1] = g;
456           e[m - 1] = 0.0;
457         }
458       } while (m != l);
459     }
460   }
461
462   /**
463    * DOCUMENT ME!
464    */
465   public void tred2()
466   {
467     int n = rows;
468     int l;
469     int k;
470     int j;
471     int i;
472
473     double scale;
474     double hh;
475     double h;
476     double g;
477     double f;
478
479     this.d = new double[rows];
480     this.e = new double[rows];
481
482     for (i = n - 1; i >= 1; i--)
483     {
484       l = i - 1;
485       h = 0.0;
486       scale = 0.0;
487
488       if (l > 0)
489       {
490         for (k = 0; k < l; k++)
491         {
492           scale += Math.abs(value[i][k]);
493         }
494
495         if (scale == 0.0)
496         {
497           e[i] = value[i][l];
498         }
499         else
500         {
501           for (k = 0; k < l; k++)
502           {
503             value[i][k] /= scale;
504             h += (value[i][k] * value[i][k]);
505           }
506
507           f = value[i][l];
508
509           if (f > 0)
510           {
511             g = -1.0 * Math.sqrt(h);
512           }
513           else
514           {
515             g = Math.sqrt(h);
516           }
517
518           e[i] = scale * g;
519           h -= (f * g);
520           value[i][l] = f - g;
521           f = 0.0;
522
523           for (j = 0; j < l; j++)
524           {
525             value[j][i] = value[i][j] / h;
526             g = 0.0;
527
528             for (k = 0; k < j; k++)
529             {
530               g += (value[j][k] * value[i][k]);
531             }
532
533             for (k = j; k < l; k++)
534             {
535               g += (value[k][j] * value[i][k]);
536             }
537
538             e[j] = g / h;
539             f += (e[j] * value[i][j]);
540           }
541
542           hh = f / (h + h);
543
544           for (j = 0; j < l; j++)
545           {
546             f = value[i][j];
547             g = e[j] - (hh * f);
548             e[j] = g;
549
550             for (k = 0; k < j; k++)
551             {
552               value[j][k] -= ((f * e[k]) + (g * value[i][k]));
553             }
554           }
555         }
556       }
557       else
558       {
559         e[i] = value[i][l];
560       }
561
562       d[i] = h;
563     }
564
565     d[0] = 0.0;
566     e[0] = 0.0;
567
568     for (i = 0; i < n; i++)
569     {
570       l = i - 1;
571
572       if (d[i] != 0.0)
573       {
574         for (j = 0; j < l; j++)
575         {
576           g = 0.0;
577
578           for (k = 0; k < l; k++)
579           {
580             g += (value[i][k] * value[k][j]);
581           }
582
583           for (k = 0; k < l; k++)
584           {
585             value[k][j] -= (g * value[k][i]);
586           }
587         }
588       }
589
590       d[i] = value[i][i];
591       value[i][i] = 1.0;
592
593       for (j = 0; j < l; j++)
594       {
595         value[j][i] = 0.0;
596         value[i][j] = 0.0;
597       }
598     }
599   }
600
601   /**
602    * DOCUMENT ME!
603    */
604   public void tqli2() throws Exception
605   {
606     int n = rows;
607
608     int m;
609     int l;
610     int iter;
611     int i;
612     int k;
613     double s;
614     double r;
615     double p;
616     ;
617
618     double g;
619     double f;
620     double dd;
621     double c;
622     double b;
623
624     for (i = 2; i <= n; i++)
625     {
626       e[i - 2] = e[i - 1];
627     }
628
629     e[n - 1] = 0.0;
630
631     for (l = 1; l <= n; l++)
632     {
633       iter = 0;
634
635       do
636       {
637         for (m = l; m <= (n - 1); m++)
638         {
639           dd = Math.abs(d[m - 1]) + Math.abs(d[m]);
640
641           if ((Math.abs(e[m - 1]) + dd) == dd)
642           {
643             break;
644           }
645         }
646
647         if (m != l)
648         {
649           iter++;
650
651           if (iter == maxIter)
652           {
653             throw new Exception ("Too many iterations in tqli2 (max is "+maxIter+")");
654           }
655           else
656           {
657             // System.out.println("Iteration " + iter);
658           }
659
660           g = (d[l] - d[l - 1]) / (2.0 * e[l - 1]);
661           r = Math.sqrt((g * g) + 1.0);
662           g = d[m - 1] - d[l - 1] + (e[l - 1] / (g + sign(r, g)));
663           c = 1.0;
664           s = c;
665           p = 0.0;
666
667           for (i = m - 1; i >= l; i--)
668           {
669             f = s * e[i - 1];
670             b = c * e[i - 1];
671
672             if (Math.abs(f) >= Math.abs(g))
673             {
674               c = g / f;
675               r = Math.sqrt((c * c) + 1.0);
676               e[i] = f * r;
677               s = 1.0 / r;
678               c *= s;
679             }
680             else
681             {
682               s = f / g;
683               r = Math.sqrt((s * s) + 1.0);
684               e[i] = g * r;
685               c = 1.0 / r;
686               s *= c;
687             }
688
689             g = d[i] - p;
690             r = ((d[i - 1] - g) * s) + (2.0 * c * b);
691             p = s * r;
692             d[i] = g + p;
693             g = (c * r) - b;
694
695             for (k = 1; k <= n; k++)
696             {
697               f = value[k - 1][i];
698               value[k - 1][i] = (s * value[k - 1][i - 1]) + (c * f);
699               value[k - 1][i - 1] = (c * value[k - 1][i - 1]) - (s * f);
700             }
701           }
702
703           d[l - 1] = d[l - 1] - p;
704           e[l - 1] = g;
705           e[m - 1] = 0.0;
706         }
707       } while (m != l);
708     }
709   }
710
711   /**
712    * DOCUMENT ME!
713    * 
714    * @param a
715    *          DOCUMENT ME!
716    * @param b
717    *          DOCUMENT ME!
718    * 
719    * @return DOCUMENT ME!
720    */
721   public double sign(double a, double b)
722   {
723     if (b < 0)
724     {
725       return -Math.abs(a);
726     }
727     else
728     {
729       return Math.abs(a);
730     }
731   }
732
733   /**
734    * DOCUMENT ME!
735    * 
736    * @param n
737    *          DOCUMENT ME!
738    * 
739    * @return DOCUMENT ME!
740    */
741   public double[] getColumn(int n)
742   {
743     double[] out = new double[rows];
744
745     for (int i = 0; i < rows; i++)
746     {
747       out[i] = value[i][n];
748     }
749
750     return out;
751   }
752
753   /**
754    * DOCUMENT ME!
755    * 
756    * @param ps
757    *          DOCUMENT ME!
758    */
759   public void printD(PrintStream ps)
760   {
761     for (int j = 0; j < rows; j++)
762     {
763       Format.print(ps, "%15.4e", d[j]);
764     }
765   }
766
767   /**
768    * DOCUMENT ME!
769    * 
770    * @param ps
771    *          DOCUMENT ME!
772    */
773   public void printE(PrintStream ps)
774   {
775     for (int j = 0; j < rows; j++)
776     {
777       Format.print(ps, "%15.4e", e[j]);
778     }
779   }
780
781   /**
782    * DOCUMENT ME!
783    * 
784    * @param args
785    *          DOCUMENT ME!
786    */
787   public static void main(String[] args) throws Exception
788   {
789     int n = Integer.parseInt(args[0]);
790     double[][] in = new double[n][n];
791
792     for (int i = 0; i < n; i++)
793     {
794       for (int j = 0; j < n; j++)
795       {
796         in[i][j] = (double) Math.random();
797       }
798     }
799
800     Matrix origmat = new Matrix(in, n, n);
801
802     // System.out.println(" --- Original matrix ---- ");
803     // / origmat.print(System.out);
804     // System.out.println();
805     // System.out.println(" --- transpose matrix ---- ");
806     Matrix trans = origmat.transpose();
807
808     // trans.print(System.out);
809     // System.out.println();
810     // System.out.println(" --- OrigT * Orig ---- ");
811     Matrix symm = trans.postMultiply(origmat);
812
813     // symm.print(System.out);
814     // System.out.println();
815     // Copy the symmetric matrix for later
816     // Matrix origsymm = symm.copy();
817
818     // This produces the tridiagonal transformation matrix
819     // long tstart = System.currentTimeMillis();
820     symm.tred();
821
822     // long tend = System.currentTimeMillis();
823
824     // System.out.println("Time take for tred = " + (tend-tstart) + "ms");
825     // System.out.println(" ---Tridiag transform matrix ---");
826     // symm.print(System.out);
827     // System.out.println();
828     // System.out.println(" --- D vector ---");
829     // symm.printD(System.out);
830     // System.out.println();
831     // System.out.println(" --- E vector ---");
832     // symm.printE(System.out);
833     // System.out.println();
834     // Now produce the diagonalization matrix
835     // tstart = System.currentTimeMillis();
836     symm.tqli();
837     // tend = System.currentTimeMillis();
838
839     // System.out.println("Time take for tqli = " + (tend-tstart) + " ms");
840     // System.out.println(" --- New diagonalization matrix ---");
841     // symm.print(System.out);
842     // System.out.println();
843     // System.out.println(" --- D vector ---");
844     // symm.printD(System.out);
845     // System.out.println();
846     // System.out.println(" --- E vector ---");
847     // symm.printE(System.out);
848     // System.out.println();
849     // System.out.println(" --- First eigenvector --- ");
850     // double[] eigenv = symm.getColumn(0);
851     // for (int i=0; i < eigenv.length;i++) {
852     // Format.print(System.out,"%15.4f",eigenv[i]);
853     // }
854     // System.out.println();
855     // double[] neigenv = origsymm.vectorPostMultiply(eigenv);
856     // for (int i=0; i < neigenv.length;i++) {
857     // Format.print(System.out,"%15.4f",neigenv[i]/symm.d[0]);
858     // }
859     // System.out.println();
860   }
861 }