JAMA
[ class tree: JAMA ] [ index: JAMA ] [ all elements ]

Source for file SingularValueDecomposition.php

Documentation is available at SingularValueDecomposition.php

  1. <?php
  2. /**
  3.  *    @package JAMA
  4.  *
  5.  *     For an m-by-n matrix A with m >= n, the singular value decomposition is
  6.  *     an m-by-n orthogonal matrix U, an n-by-n diagonal matrix S, and
  7.  *     an n-by-n orthogonal matrix V so that A = U*S*V'.
  8.  *
  9.  *     The singular values, sigma[$k] = S[$k][$k], are ordered so that
  10.  *     sigma[0] >= sigma[1] >= ... >= sigma[n-1].
  11.  *
  12.  *     The singular value decompostion always exists, so the constructor will
  13.  *     never fail.  The matrix condition number and the effective numerical
  14.  *     rank can be computed from this decomposition.
  15.  *
  16.  *    @author  Paul Meagher
  17.  *    @license PHP v3.0
  18.  *    @version 1.1
  19.  */
  20.  
  21.     /**
  22.      *    Internal storage of U.
  23.      *    @var array 
  24.      */
  25.     private $U array();
  26.  
  27.     /**
  28.      *    Internal storage of V.
  29.      *    @var array 
  30.      */
  31.     private $V array();
  32.  
  33.     /**
  34.      *    Internal storage of singular values.
  35.      *    @var array 
  36.      */
  37.     private $s array();
  38.  
  39.     /**
  40.      *    Row dimension.
  41.      *    @var int 
  42.      */
  43.     private $m;
  44.  
  45.     /**
  46.      *    Column dimension.
  47.      *    @var int 
  48.      */
  49.     private $n;
  50.  
  51.  
  52.     /**
  53.      *    Construct the singular value decomposition
  54.      *
  55.      *    Derived from LINPACK code.
  56.      *
  57.      *    @param $A Rectangular matrix
  58.      *    @return Structure to access U, S and V.
  59.      */
  60.     public function __construct($Arg{
  61.  
  62.         // Initialize.
  63.         $A $Arg->getArrayCopy();
  64.         $this->$Arg->getRowDimension();
  65.         $this->$Arg->getColumnDimension();
  66.         $nu      min($this->m$this->n);
  67.         $e       array();
  68.         $work    array();
  69.         $wantu   true;
  70.         $wantv   true;
  71.         $nct min($this->1$this->n);
  72.         $nrt max(0min($this->2$this->m));
  73.  
  74.         // Reduce A to bidiagonal form, storing the diagonal elements
  75.         // in s and the super-diagonal elements in e.
  76.         for ($k 0$k max($nct,$nrt)++$k{
  77.  
  78.             if ($k $nct{
  79.                 // Compute the transformation for the k-th column and
  80.                 // place the k-th diagonal in s[$k].
  81.                 // Compute 2-norm of k-th column without under/overflow.
  82.                 $this->s[$k0;
  83.                 for ($i $k$i $this->m++$i{
  84.                     $this->s[$khypo($this->s[$k]$A[$i][$k]);
  85.                 }
  86.                 if ($this->s[$k!= 0.0{
  87.                     if ($A[$k][$k0.0{
  88.                         $this->s[$k= -$this->s[$k];
  89.                     }
  90.                     for ($i $k$i $this->m++$i{
  91.                         $A[$i][$k/= $this->s[$k];
  92.                     }
  93.                     $A[$k][$k+= 1.0;
  94.                 }
  95.                 $this->s[$k= -$this->s[$k];
  96.             }
  97.  
  98.             for ($j $k 1$j $this->n++$j{
  99.                 if (($k $nct($this->s[$k!= 0.0)) {
  100.                     // Apply the transformation.
  101.                     $t 0;
  102.                     for ($i $k$i $this->m++$i{
  103.                         $t += $A[$i][$k$A[$i][$j];
  104.                     }
  105.                     $t = -$t $A[$k][$k];
  106.                     for ($i $k$i $this->m++$i{
  107.                         $A[$i][$j+= $t $A[$i][$k];
  108.                     }
  109.                     // Place the k-th row of A into e for the
  110.                     // subsequent calculation of the row transformation.
  111.                     $e[$j$A[$k][$j];
  112.                 }
  113.             }
  114.  
  115.             if ($wantu AND ($k $nct)) {
  116.                 // Place the transformation in U for subsequent back
  117.                 // multiplication.
  118.                 for ($i $k$i $this->m++$i{
  119.                     $this->U[$i][$k$A[$i][$k];
  120.                 }
  121.             }
  122.  
  123.             if ($k $nrt{
  124.                 // Compute the k-th row transformation and place the
  125.                 // k-th super-diagonal in e[$k].
  126.                 // Compute 2-norm without under/overflow.
  127.                 $e[$k0;
  128.                 for ($i $k 1$i $this->n++$i{
  129.                     $e[$khypo($e[$k]$e[$i]);
  130.                 }
  131.                 if ($e[$k!= 0.0{
  132.                     if ($e[$k+10.0{
  133.                         $e[$k= -$e[$k];
  134.                     }
  135.                     for ($i $k 1$i $this->n++$i{
  136.                         $e[$i/= $e[$k];
  137.                     }
  138.                     $e[$k+1+= 1.0;
  139.                 }
  140.                 $e[$k= -$e[$k];
  141.                 if (($k+$this->mAND ($e[$k!= 0.0)) {
  142.                     // Apply the transformation.
  143.                     for ($i $k+1$i $this->m++$i{
  144.                         $work[$i0.0;
  145.                     }
  146.                     for ($j $k+1$j $this->n++$j{
  147.                         for ($i $k+1$i $this->m++$i{
  148.                             $work[$i+= $e[$j$A[$i][$j];
  149.                         }
  150.                     }
  151.                     for ($j $k 1$j $this->n++$j{
  152.                         $t = -$e[$j$e[$k+1];
  153.                         for ($i $k 1$i $this->m++$i{
  154.                             $A[$i][$j+= $t $work[$i];
  155.                         }
  156.                     }
  157.                 }
  158.                 if ($wantv{
  159.                     // Place the transformation in V for subsequent
  160.                     // back multiplication.
  161.                     for ($i $k 1$i $this->n++$i{
  162.                         $this->V[$i][$k$e[$i];
  163.                     }
  164.                 }
  165.             }
  166.         }
  167.  
  168.         // Set up the final bidiagonal matrix or order p.
  169.         $p min($this->n$this->1);
  170.         if ($nct $this->n{
  171.             $this->s[$nct$A[$nct][$nct];
  172.         }
  173.         if ($this->$p{
  174.             $this->s[$p-10.0;
  175.         }
  176.         if ($nrt $p{
  177.             $e[$nrt$A[$nrt][$p-1];
  178.         }
  179.         $e[$p-10.0;
  180.         // If required, generate U.
  181.         if ($wantu{
  182.             for ($j $nct$j $nu++$j{
  183.                 for ($i 0$i $this->m++$i{
  184.                     $this->U[$i][$j0.0;
  185.                 }
  186.                 $this->U[$j][$j1.0;
  187.             }
  188.             for ($k $nct 1$k >= 0--$k{
  189.                 if ($this->s[$k!= 0.0{
  190.                     for ($j $k 1$j $nu++$j{
  191.                         $t 0;
  192.                         for ($i $k$i $this->m++$i{
  193.                             $t += $this->U[$i][$k$this->U[$i][$j];
  194.                         }
  195.                         $t = -$t $this->U[$k][$k];
  196.                         for ($i $k$i $this->m++$i{
  197.                             $this->U[$i][$j+= $t $this->U[$i][$k];
  198.                         }
  199.                     }
  200.                     for ($i $k$i $this->m++$i {
  201.                         $this->U[$i][$k= -$this->U[$i][$k];
  202.                     }
  203.                     $this->U[$k][$k1.0 $this->U[$k][$k];
  204.                     for ($i 0$i $k 1++$i{
  205.                         $this->U[$i][$k0.0;
  206.                     }
  207.                 else {
  208.                     for ($i 0$i $this->m++$i{
  209.                         $this->U[$i][$k0.0;
  210.                     }
  211.                     $this->U[$k][$k1.0;
  212.                 }
  213.             }
  214.         }
  215.  
  216.         // If required, generate V.
  217.         if ($wantv{
  218.             for ($k $this->1$k >= 0--$k{
  219.                 if (($k $nrtAND ($e[$k!= 0.0)) {
  220.                     for ($j $k 1$j $nu++$j{
  221.                         $t 0;
  222.                         for ($i $k 1$i $this->n++$i{
  223.                             $t += $this->V[$i][$k]$this->V[$i][$j];
  224.                         }
  225.                         $t = -$t $this->V[$k+1][$k];
  226.                         for ($i $k 1$i $this->n++$i{
  227.                             $this->V[$i][$j+= $t $this->V[$i][$k];
  228.                         }
  229.                     }
  230.                 }
  231.                 for ($i 0$i $this->n++$i{
  232.                     $this->V[$i][$k0.0;
  233.                 }
  234.                 $this->V[$k][$k1.0;
  235.             }
  236.         }
  237.  
  238.         // Main iteration loop for the singular values.
  239.         $pp   $p 1;
  240.         $iter 0;
  241.         $eps  pow(2.0-52.0);
  242.  
  243.         while ($p 0{
  244.             // Here is where a test for too many iterations would go.
  245.             // This section of the program inspects for negligible
  246.             // elements in the s and e arrays.  On completion the
  247.             // variables kase and k are set as follows:
  248.             // kase = 1  if s(p) and e[k-1] are negligible and k<p
  249.             // kase = 2  if s(k) is negligible and k<p
  250.             // kase = 3  if e[k-1] is negligible, k<p, and
  251.             //           s(k), ..., s(p) are not negligible (qr step).
  252.             // kase = 4  if e(p-1) is negligible (convergence).
  253.             for ($k $p 2$k >= -1--$k{
  254.                 if ($k == -1{
  255.                     break;
  256.                 }
  257.                 if (abs($e[$k]<= $eps (abs($this->s[$k]abs($this->s[$k+1]))) {
  258.                     $e[$k0.0;
  259.                     break;
  260.                 }
  261.             }
  262.             if ($k == $p 2{
  263.                 $kase 4;
  264.             else {
  265.                 for ($ks $p 1$ks >= $k--$ks{
  266.                     if ($ks == $k{
  267.                         break;
  268.                     }
  269.                     $t ($ks != $p abs($e[$ks]0.($ks != $k abs($e[$ks-1]0.);
  270.                     if (abs($this->s[$ks]<= $eps $t)  {
  271.                         $this->s[$ks0.0;
  272.                         break;
  273.                     }
  274.                 }
  275.                 if ($ks == $k{
  276.                     $kase 3;
  277.                 else if ($ks == $p-1{
  278.                     $kase 1;
  279.                 else {
  280.                     $kase 2;
  281.                     $k $ks;
  282.                 }
  283.             }
  284.             ++$k;
  285.  
  286.             // Perform the task indicated by kase.
  287.             switch ($kase{
  288.                 // Deflate negligible s(p).
  289.                 case 1:
  290.                         $f $e[$p-2];
  291.                         $e[$p-20.0;
  292.                         for ($j $p 2$j >= $k--$j{
  293.                             $t  hypo($this->s[$j],$f);
  294.                             $cs $this->s[$j$t;
  295.                             $sn $f $t;
  296.                             $this->s[$j$t;
  297.                             if ($j != $k{
  298.                                 $f = -$sn $e[$j-1];
  299.                                 $e[$j-1$cs $e[$j-1];
  300.                             }
  301.                             if ($wantv{
  302.                                 for ($i 0$i $this->n++$i{
  303.                                     $t $cs $this->V[$i][$j$sn $this->V[$i][$p-1];
  304.                                     $this->V[$i][$p-1= -$sn $this->V[$i][$j$cs $this->V[$i][$p-1];
  305.                                     $this->V[$i][$j$t;
  306.                                 }
  307.                             }
  308.                         }
  309.                         break;
  310.                 // Split at negligible s(k).
  311.                 case 2:
  312.                         $f $e[$k-1];
  313.                         $e[$k-10.0;
  314.                         for ($j $k$j $p++$j{
  315.                             $t hypo($this->s[$j]$f);
  316.                             $cs $this->s[$j$t;
  317.                             $sn $f $t;
  318.                             $this->s[$j$t;
  319.                             $f = -$sn $e[$j];
  320.                             $e[$j$cs $e[$j];
  321.                             if ($wantu{
  322.                                 for ($i 0$i $this->m++$i{
  323.                                     $t $cs $this->U[$i][$j$sn $this->U[$i][$k-1];
  324.                                     $this->U[$i][$k-1= -$sn $this->U[$i][$j$cs $this->U[$i][$k-1];
  325.                                     $this->U[$i][$j$t;
  326.                                 }
  327.                             }
  328.                         }
  329.                         break;
  330.                 // Perform one qr step.
  331.                 case 3:
  332.                         // Calculate the shift.
  333.                         $scale max(max(max(max(
  334.                                     abs($this->s[$p-1]),abs($this->s[$p-2])),abs($e[$p-2])),
  335.                                     abs($this->s[$k]))abs($e[$k]));
  336.                         $sp   $this->s[$p-1$scale;
  337.                         $spm1 $this->s[$p-2$scale;
  338.                         $epm1 $e[$p-2$scale;
  339.                         $sk   $this->s[$k$scale;
  340.                         $ek   $e[$k$scale;
  341.                         $b    (($spm1 $sp($spm1 $sp$epm1 $epm12.0;
  342.                         $c    ($sp $epm1($sp $epm1);
  343.                         $shift 0.0;
  344.                         if (($b != 0.0|| ($c != 0.0)) {
  345.                             $shift sqrt($b $b $c);
  346.                             if ($b 0.0{
  347.                                 $shift = -$shift;
  348.                             }
  349.                             $shift $c ($b $shift);
  350.                         }
  351.                         $f ($sk $sp($sk $sp$shift;
  352.                         $g $sk $ek;
  353.                         // Chase zeros.
  354.                         for ($j $k$j $p-1++$j{
  355.                             $t  hypo($f,$g);
  356.                             $cs $f/$t;
  357.                             $sn $g/$t;
  358.                             if ($j != $k{
  359.                                 $e[$j-1$t;
  360.                             }
  361.                             $f $cs $this->s[$j$sn $e[$j];
  362.                             $e[$j$cs $e[$j$sn $this->s[$j];
  363.                             $g $sn $this->s[$j+1];
  364.                             $this->s[$j+1$cs $this->s[$j+1];
  365.                             if ($wantv{
  366.                                 for ($i 0$i $this->n++$i{
  367.                                     $t $cs $this->V[$i][$j$sn $this->V[$i][$j+1];
  368.                                     $this->V[$i][$j+1= -$sn $this->V[$i][$j$cs $this->V[$i][$j+1];
  369.                                     $this->V[$i][$j$t;
  370.                                 }
  371.                             }
  372.                             $t hypo($f,$g);
  373.                             $cs $f/$t;
  374.                             $sn $g/$t;
  375.                             $this->s[$j$t;
  376.                             $f $cs $e[$j$sn $this->s[$j+1];
  377.                             $this->s[$j+1= -$sn $e[$j$cs $this->s[$j+1];
  378.                             $g $sn $e[$j+1];
  379.                             $e[$j+1$cs $e[$j+1];
  380.                             if ($wantu && ($j $this->1)) {
  381.                                 for ($i 0$i $this->m++$i{
  382.                                     $t $cs $this->U[$i][$j$sn $this->U[$i][$j+1];
  383.                                     $this->U[$i][$j+1= -$sn $this->U[$i][$j$cs $this->U[$i][$j+1];
  384.                                     $this->U[$i][$j$t;
  385.                                 }
  386.                             }
  387.                         }
  388.                         $e[$p-2$f;
  389.                         $iter $iter 1;
  390.                         break;
  391.                 // Convergence.
  392.                 case 4:
  393.                         // Make the singular values positive.
  394.                         if ($this->s[$k<= 0.0{
  395.                             $this->s[$k($this->s[$k0.0 ? -$this->s[$k0.0);
  396.                             if ($wantv{
  397.                                 for ($i 0$i <= $pp++$i{
  398.                                     $this->V[$i][$k= -$this->V[$i][$k];
  399.                                 }
  400.                             }
  401.                         }
  402.                         // Order the singular values.
  403.                         while ($k $pp{
  404.                             if ($this->s[$k>= $this->s[$k+1]{
  405.                                 break;
  406.                             }
  407.                             $t $this->s[$k];
  408.                             $this->s[$k$this->s[$k+1];
  409.                             $this->s[$k+1$t;
  410.                             if ($wantv AND ($k $this->1)) {
  411.                                 for ($i 0$i $this->n++$i{
  412.                                     $t $this->V[$i][$k+1];
  413.                                     $this->V[$i][$k+1$this->V[$i][$k];
  414.                                     $this->V[$i][$k$t;
  415.                                 }
  416.                             }
  417.                             if ($wantu AND ($k $this->m-1)) {
  418.                                 for ($i 0$i $this->m++$i{
  419.                                     $t $this->U[$i][$k+1];
  420.                                     $this->U[$i][$k+1$this->U[$i][$k];
  421.                                     $this->U[$i][$k$t;
  422.                                 }
  423.                             }
  424.                             ++$k;
  425.                         }
  426.                         $iter 0;
  427.                         --$p;
  428.                         break;
  429.             // end switch
  430.         // end while
  431.  
  432.     // end constructor
  433.  
  434.  
  435.     /**
  436.      *    Return the left singular vectors
  437.      *
  438.      *    @access public
  439.      *    @return 
  440.      */
  441.     public function getU({
  442.         return new Matrix($this->U$this->mmin($this->1$this->n));
  443.     }
  444.  
  445.  
  446.     /**
  447.      *    Return the right singular vectors
  448.      *
  449.      *    @access public
  450.      *    @return 
  451.      */
  452.     public function getV({
  453.         return new Matrix($this->V);
  454.     }
  455.  
  456.  
  457.     /**
  458.      *    Return the one-dimensional array of singular values
  459.      *
  460.      *    @access public
  461.      *    @return diagonal of S.
  462.      */
  463.     public function getSingularValues({
  464.         return $this->s;
  465.     }
  466.  
  467.  
  468.     /**
  469.      *    Return the diagonal matrix of singular values
  470.      *
  471.      *    @access public
  472.      *    @return 
  473.      */
  474.     public function getS({
  475.         for ($i 0$i $this->n++$i{
  476.             for ($j 0$j $this->n++$j{
  477.                 $S[$i][$j0.0;
  478.             }
  479.             $S[$i][$i$this->s[$i];
  480.         }
  481.         return new Matrix($S);
  482.     }
  483.  
  484.  
  485.     /**
  486.      *    Two norm
  487.      *
  488.      *    @access public
  489.      *    @return max(S) 
  490.      */
  491.     public function norm2({
  492.         return $this->s[0];
  493.     }
  494.  
  495.  
  496.     /**
  497.      *    Two norm condition number
  498.      *
  499.      *    @access public
  500.      *    @return max(S)/min(S) 
  501.      */
  502.     public function cond({
  503.         return $this->s[0$this->s[min($this->m$this->n1];
  504.     }
  505.  
  506.  
  507.     /**
  508.      *    Effective numerical matrix rank
  509.      *
  510.      *    @access public
  511.      *    @return Number of nonnegligible singular values.
  512.      */
  513.     public function rank({
  514.         $eps pow(2.0-52.0);
  515.         $tol max($this->m$this->n$this->s[0$eps;
  516.         $r 0;
  517.         for ($i 0$i count($this->s)++$i{
  518.             if ($this->s[$i$tol{
  519.                 ++$r;
  520.             }
  521.         }
  522.         return $r;
  523.     }
  524.  
  525. }    //    class SingularValueDecomposition

Documentation generated on Sun, 27 Feb 2011 16:33:54 -0800 by phpDocumentor 1.4.3