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

Source for file EigenvalueDecomposition.php

Documentation is available at EigenvalueDecomposition.php

  1. <?php
  2. /**
  3. @package JAMA
  4. *
  5. *  Class to obtain eigenvalues and eigenvectors of a real matrix.
  6. *
  7. *  If A is symmetric, then A = V*D*V' where the eigenvalue matrix D
  8. *  is diagonal and the eigenvector matrix V is orthogonal (i.e.
  9. *  A = V.times(D.times(V.transpose())) and V.times(V.transpose())
  10. *  equals the identity matrix).
  11. *
  12. *  If A is not symmetric, then the eigenvalue matrix D is block diagonal
  13. *  with the real eigenvalues in 1-by-1 blocks and any complex eigenvalues,
  14. *  lambda + i*mu, in 2-by-2 blocks, [lambda, mu; -mu, lambda].  The
  15. *  columns of V represent the eigenvectors in the sense that A*V = V*D,
  16. *  i.e. A.times(V) equals V.times(D).  The matrix V may be badly
  17. *  conditioned, or even singular, so the validity of the equation
  18. *  A = V*D*inverse(V) depends upon V.cond().
  19. *
  20. @author  Paul Meagher
  21. @license PHP v3.0
  22. @version 1.1
  23. */
  24.  
  25.   /**
  26.   * Row and column dimension (square matrix).
  27.   * @var int 
  28.   */
  29.   var $n;
  30.  
  31.   /**
  32.   * Internal symmetry flag.
  33.  
  34.   * @var int 
  35.   */
  36.   var $issymmetric;
  37.  
  38.   /**
  39.   * Arrays for internal storage of eigenvalues.
  40.   * @var array 
  41.   */
  42.   var $d = array();
  43.   var $e = array();
  44.  
  45.   /**
  46.   * Array for internal storage of eigenvectors.
  47.   * @var array 
  48.   */
  49.   var $V = array();
  50.  
  51.   /**
  52.   * Array for internal storage of nonsymmetric Hessenberg form.
  53.   * @var array 
  54.   */
  55.   var $H = array();
  56.  
  57.   /**
  58.   * Working storage for nonsymmetric algorithm.
  59.   * @var array 
  60.   */
  61.   var $ort;
  62.  
  63.   /**
  64.   * Used for complex scalar division.
  65.   * @var float 
  66.   */
  67.   var $cdivr;
  68.   var $cdivi;
  69.  
  70.   /**
  71.   * Symmetric Householder reduction to tridiagonal form.
  72.   * @access private
  73.   */
  74.   function tred2 ({
  75.     //  This is derived from the Algol procedures tred2 by
  76.     //  Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
  77.     //  Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
  78.     //  Fortran subroutine in EISPACK.
  79.     $this->d = $this->V[$this->n-1];
  80.     // Householder reduction to tridiagonal form.   
  81.     for ($i $this->n-1$i 0$i--
  82.     $i_ $i -1;
  83.       // Scale to avoid under/overflow.  
  84.       $h $scale 0.0;
  85.       $scale += array_sum(array_map(abs$this->d));
  86.       if ($scale == 0.0{
  87.         $this->e[$i$this->d[$i_];
  88.         $this->d = array_slice($this->V[$i_]0$i_);
  89.     for ($j 0$j $i$j++{
  90.           $this->V[$j][$i$this->V[$i][$j0.0;
  91.         }
  92.       else {
  93.         // Generate Householder vector.
  94.         for ($k 0$k $i$k++{
  95.           $this->d[$k/= $scale;
  96.           $h += pow($this->d[$k]2);
  97.         }
  98.         $f $this->d[$i_];
  99.         $g sqrt($h);
  100.         if ($f 0)
  101.           $g = -$g;
  102.         $this->e[$i$scale $g;
  103.         $h $h $f $g;
  104.         $this->d[$i_$f $g;
  105.         for ($j 0$j $i$j++)
  106.           $this->e[$j0.0;
  107.          // Apply similarity transformation to remaining columns.
  108.          for ($j 0$j $i$j++{
  109.            $f $this->d[$j];
  110.            $this->V[$j][$i$f;
  111.            $g $this->e[$j$this->V[$j][$j$f;
  112.            for ($k $j+1$k <= $i_$k++{
  113.              $g += $this->V[$k][$j$this->d[$k];
  114.              $this->e[$k+= $this->V[$k][$j$f;
  115.            }
  116.            $this->e[$j$g;
  117.          }
  118.          $f 0.0;
  119.          for ($j 0$j $i$j++{
  120.            $this->e[$j/= $h;
  121.            $f += $this->e[$j$this->d[$j];
  122.          }
  123.          $hh $f ($h);
  124.          for ($j=0$j $i$j++)
  125.            $this->e[$j-= $hh $this->d[$j];
  126.          for ($j 0$j $i$j++{
  127.            $f $this->d[$j];
  128.            $g $this->e[$j];
  129.            for ($k $j$k <= $i_$k++)
  130.              $this->V[$k][$j-= ($f $this->e[$k$g $this->d[$k]);
  131.            $this->d[$j$this->V[$i-1][$j];
  132.            $this->V[$i][$j0.0;
  133.          }
  134.       }
  135.       $this->d[$i$h;
  136.     }   
  137.     // Accumulate transformations.
  138.     for ($i 0$i $this->n-1$i++{
  139.       $this->V[$this->n-1][$i$this->V[$i][$i];
  140.       $this->V[$i][$i1.0;
  141.       $h $this->d[$i+1];
  142.       if ($h != 0.0{
  143.         for ($k 0$k <= $i$k++)
  144.           $this->d[$k$this->V[$k][$i+1$h;
  145.         for ($j 0$j <= $i$j++{
  146.           $g 0.0;
  147.           for ($k 0$k <= $i$k++)
  148.             $g += $this->V[$k][$i+1$this->V[$k][$j];
  149.           for ($k 0$k <= $i$k++)
  150.             $this->V[$k][$j-= $g $this->d[$k];
  151.         }
  152.       }
  153.       for ($k 0$k <= $i$k++)
  154.         $this->V[$k][$i+10.0;
  155.     
  156.  
  157.   $this->d = $this->V[$this->n-1];
  158.   $this->V[$this->n-1array_fill(0$j0.0);    
  159.     $this->V[$this->n-1][$this->n-11.0;
  160.     $this->e[00.0;
  161.   }
  162.  
  163.   /**
  164.   * Symmetric tridiagonal QL algorithm.
  165.   *
  166.   * This is derived from the Algol procedures tql2, by
  167.   * Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
  168.   * Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
  169.   * Fortran subroutine in EISPACK.
  170.   *
  171.   * @access private
  172.   */
  173.   function tql2 ({
  174.     for ($i 1$i $this->n$i++)
  175.       $this->e[$i-1$this->e[$i];
  176.     $this->e[$this->n-10.0;   
  177.     $f 0.0;
  178.     $tst1 0.0;
  179.     $eps  pow(2.0,-52.0);
  180.     for ($l 0$l $this->n$l++{
  181.       // Find small subdiagonal element
  182.       $tst1 max($tst1abs($this->d[$l]abs($this->e[$l]));
  183.       $m $l;
  184.       while ($m $this->n{
  185.         if (abs($this->e[$m]<= $eps $tst1)
  186.           break;
  187.         $m++;
  188.       }   
  189.       // If m == l, $this->d[l] is an eigenvalue,
  190.       // otherwise, iterate.  
  191.       if ($m $l{
  192.         $iter 0;
  193.         do {
  194.           // Could check iteration count here.          
  195.           $iter += 1;  
  196.           // Compute implicit shift
  197.           $g $this->d[$l];
  198.           $p ($this->d[$l+1$g(2.0 $this->e[$l]);
  199.           $r hypo($p1.0);
  200.           if ($p 0)
  201.             $r *= -1;
  202.       $this->d[$l$this->e[$l($p $r);
  203.           $this->d[$l+1$this->e[$l($p $r);
  204.           $dl1 $this->d[$l+1];
  205.           $h $g $this->d[$l];
  206.           for ($i $l 2$i $this->n$i++)
  207.             $this->d[$i-= $h;
  208.           $f += $h;
  209.           // Implicit QL transformation.
  210.           $p $this->d[$m];
  211.           $c 1.0;
  212.           $c2 $c3 $c;
  213.           $el1 $this->e[$l 1];
  214.           $s $s2 0.0;
  215.           for ($i $m-1$i >= $l$i--{
  216.             $c3 $c2;
  217.             $c2 $c;
  218.             $s2 $s;
  219.             $g  $c $this->e[$i];
  220.             $h  $c $p;
  221.             $r  hypo($p$this->e[$i]);
  222.             $this->e[$i+1$s $r;
  223.             $s $this->e[$i$r;
  224.             $c $p $r;
  225.             $p $c $this->d[$i$s $g;
  226.             $this->d[$i+1$h $s ($c $g $s $this->d[$i]);
  227.             // Accumulate transformation.
  228.             for ($k 0$k $this->n$k++{
  229.               $h $this->V[$k][$i+1];
  230.               $this->V[$k][$i+1$s $this->V[$k][$i$c $h;
  231.               $this->V[$k][$i$c $this->V[$k][$i$s $h;
  232.             }
  233.           }
  234.           $p = -$s $s2 $c3 $el1 $this->e[$l$dl1;
  235.           $this->e[$l$s $p;
  236.           $this->d[$l$c $p;
  237.           // Check for convergence.
  238.         while (abs($this->e[$l]$eps $tst1);
  239.       }
  240.       $this->d[$l$this->d[$l$f;
  241.       $this->e[$l0.0;      
  242.     }      
  243.     // Sort eigenvalues and corresponding vectors.  
  244.     for ($i 0$i $this->n - 1$i++{
  245.       $k $i;
  246.       $p $this->d[$i];
  247.       for ($j $i+1$j $this->n$j++{
  248.         if ($this->d[$j$p{
  249.           $k $j;
  250.           $p $this->d[$j];
  251.         }
  252.       }
  253.       if ($k != $i{
  254.         $this->d[$k$this->d[$i];
  255.         $this->d[$i$p;
  256.         for ($j 0$j $this->n$j++{
  257.           $p $this->V[$j][$i];
  258.           $this->V[$j][$i$this->V[$j][$k];
  259.           $this->V[$j][$k$p;
  260.         }
  261.       }
  262.     }      
  263.   }
  264.  
  265.   /**
  266.   * Nonsymmetric reduction to Hessenberg form.
  267.   *
  268.   * This is derived from the Algol procedures orthes and ortran,
  269.   * by Martin and Wilkinson, Handbook for Auto. Comp.,
  270.   * Vol.ii-Linear Algebra, and the corresponding
  271.   * Fortran subroutines in EISPACK.
  272.   *  
  273.   * @access private
  274.   */
  275.   function orthes ({   
  276.     $low  0;
  277.     $high $this->n-1;   
  278.     for ($m $low+1$m <= $high-1$m++{  
  279.       // Scale column.
  280.       $scale 0.0;
  281.       for ($i $m$i <= $high$i++)
  282.         $scale $scale abs($this->H[$i][$m-1]);
  283.       if ($scale != 0.0{
  284.         // Compute Householder transformation.
  285.         $h 0.0;
  286.         for ($i $high$i >= $m$i--{
  287.           $this->ort[$i$this->H[$i][$m-1]/$scale;
  288.           $h += $this->ort[$i$this->ort[$i];
  289.         }
  290.         $g sqrt($h);
  291.         if ($this->ort[$m0)
  292.           $g *= -1;
  293.         $h -= $this->ort[$m$g;
  294.         $this->ort[$m-= $g;
  295.         // Apply Householder similarity transformation
  296.         // H = (I-u*u'/h)*H*(I-u*u')/h)
  297.         for ($j $m$j $this->n$j++{
  298.           $f 0.0;
  299.           for ($i $high$i >= $m$i--)
  300.             $f += $this->ort[$i$this->H[$i][$j];
  301.           $f /= $h;
  302.           for ($i $m$i <= $high$i++)
  303.             $this->H[$i][$j-= $f $this->ort[$i];
  304.         }
  305.         for ($i 0$i <= $high$i++{
  306.           $f 0.0;
  307.           for ($j $high$j >= $m$j--)
  308.             $f += $this->ort[$j$this->H[$i][$j];
  309.           $f $f/$h;
  310.           for ($j $m$j <= $high$j++)
  311.             $this->H[$i][$j-= $f $this->ort[$j];
  312.         }
  313.         $this->ort[$m$scale $this->ort[$m];
  314.         $this->H[$m][$m-1$scale $g;
  315.       }
  316.     }  
  317.     // Accumulate transformations (Algol's ortran).
  318.     for ($i 0$i $this->n$i++)
  319.       for ($j 0$j $this->n$j++)
  320.         $this->V[$i][$j($i == $j 1.0 0.0);
  321.     for ($m $high-1$m >= $low+1$m--{
  322.       if ($this->H[$m][$m-1!= 0.0{
  323.         for ($i $m+1$i <= $high$i++)
  324.           $this->ort[$i$this->H[$i][$m-1];
  325.         for ($j $m$j <= $high$j++{
  326.           $g 0.0;
  327.           for ($i $m$i <= $high$i++)
  328.             $g += $this->ort[$i$this->V[$i][$j];
  329.           // Double division avoids possible underflow
  330.           $g ($g $this->ort[$m]$this->H[$m][$m-1];
  331.           for ($i $m$i <= $high$i++)
  332.             $this->V[$i][$j+= $g $this->ort[$i];
  333.         }
  334.       }
  335.     }
  336.   }
  337.  
  338.   /**
  339.   * Performs complex division.
  340.   * @access private
  341.   */            
  342.   function cdiv($xr$xi$yr$yi{
  343.     if (abs($yrabs($yi)) {
  344.       $r $yi $yr;
  345.       $d $yr $r $yi;
  346.       $this->cdivr = ($xr $r $xi$d;
  347.       $this->cdivi = ($xi $r $xr$d;
  348.     else {
  349.       $r $yr $yi;
  350.       $d $yi $r $yr;
  351.       $this->cdivr = ($r $xr $xi$d;
  352.       $this->cdivi = ($r $xi $xr$d;
  353.     }
  354.   }
  355.   
  356.   /**
  357.   * Nonsymmetric reduction from Hessenberg to real Schur form.
  358.   *
  359.   * Code is derived from the Algol procedure hqr2,
  360.   * by Martin and Wilkinson, Handbook for Auto. Comp.,
  361.   * Vol.ii-Linear Algebra, and the corresponding
  362.   * Fortran subroutine in EISPACK.
  363.   *
  364.   * @access private
  365.   */
  366.   function hqr2 ({  
  367.     //  Initialize
  368.     $nn $this->n;
  369.     $n  $nn 1;
  370.     $low 0;
  371.     $high $nn 1;
  372.     $eps pow(2.0-52.0);
  373.     $exshift 0.0;
  374.     $p $q $r $s $z 0;
  375.     // Store roots isolated by balanc and compute matrix norm
  376.     $norm 0.0;
  377.     for ($i 0$i $nn$i++{
  378.       if (($i $lowOR ($i $high)) {
  379.         $this->d[$i$this->H[$i][$i];
  380.         $this->e[$i0.0;
  381.       }
  382.       for ($j max($i-10)$j $nn$j++)
  383.         $norm $norm abs($this->H[$i][$j]);
  384.     }
  385.     // Outer loop over eigenvalue index
  386.     $iter 0;
  387.     while ($n >= $low{         
  388.       // Look for single small sub-diagonal element
  389.       $l $n;
  390.       while ($l $low{
  391.         $s abs($this->H[$l-1][$l-1]abs($this->H[$l][$l]);
  392.         if ($s == 0.0)
  393.           $s $norm;
  394.         if (abs($this->H[$l][$l-1]$eps $s)
  395.           break;
  396.         $l--;
  397.       }       
  398.       // Check for convergence
  399.       // One root found
  400.       if ($l == $n{
  401.         $this->H[$n][$n$this->H[$n][$n$exshift;
  402.         $this->d[$n$this->H[$n][$n];
  403.         $this->e[$n0.0;
  404.         $n--;
  405.         $iter 0;
  406.        // Two roots found
  407.        else if ($l == $n-1{
  408.          $w $this->H[$n][$n-1$this->H[$n-1][$n];
  409.          $p ($this->H[$n-1][$n-1$this->H[$n][$n]2.0;
  410.          $q $p $p $w;
  411.          $z sqrt(abs($q));
  412.          $this->H[$n][$n$this->H[$n][$n$exshift;
  413.          $this->H[$n-1][$n-1$this->H[$n-1][$n-1$exshift;
  414.          $x $this->H[$n][$n];
  415.          // Real pair
  416.          if ($q >= 0{
  417.            if ($p >= 0)
  418.              $z $p $z;
  419.            else
  420.              $z $p $z;
  421.            $this->d[$n-1$x $z;
  422.            $this->d[$n$this->d[$n-1];
  423.            if ($z != 0.0)
  424.              $this->d[$n$x $w $z;
  425.            $this->e[$n-10.0;
  426.            $this->e[$n0.0;
  427.            $x $this->H[$n][$n-1];
  428.            $s abs($xabs($z);
  429.            $p $x $s;
  430.            $q $z $s;
  431.            $r sqrt($p $p $q $q);
  432.            $p $p $r;
  433.            $q $q $r;
  434.            // Row modification
  435.            for ($j $n-1$j $nn$j++{
  436.              $z $this->H[$n-1][$j];
  437.              $this->H[$n-1][$j$q $z $p $this->H[$n][$j];
  438.              $this->H[$n][$j$q $this->H[$n][$j$p $z;
  439.            }
  440.            // Column modification
  441.            for ($i 0$i <= n$i++{
  442.              $z $this->H[$i][$n-1];
  443.              $this->H[$i][$n-1$q $z $p $this->H[$i][$n];
  444.              $this->H[$i][$n$q $this->H[$i][$n$p $z;
  445.            }
  446.            // Accumulate transformations
  447.            for ($i $low$i <= $high$i++{
  448.              $z $this->V[$i][$n-1];
  449.              $this->V[$i][$n-1$q $z $p $this->V[$i][$n];
  450.              $this->V[$i][$n$q $this->V[$i][$n$p $z;
  451.            }
  452.          // Complex pair
  453.          else {
  454.            $this->d[$n-1$x $p;
  455.            $this->d[$n$x $p;
  456.            $this->e[$n-1$z;
  457.            $this->e[$n= -$z;
  458.          }
  459.          $n $n 2;
  460.          $iter 0;
  461.        // No convergence yet          
  462.        else {
  463.          // Form shift
  464.          $x $this->H[$n][$n];
  465.          $y 0.0;
  466.          $w 0.0;
  467.          if ($l $n{
  468.            $y $this->H[$n-1][$n-1];
  469.            $w $this->H[$n][$n-1$this->H[$n-1][$n];
  470.          }
  471.          // Wilkinson's original ad hoc shift
  472.          if ($iter == 10{
  473.            $exshift += $x;
  474.            for ($i $low$i <= $n$i++)
  475.              $this->H[$i][$i-= $x;
  476.            $s abs($this->H[$n][$n-1]abs($this->H[$n-1][$n-2]);
  477.            $x $y 0.75 $s;
  478.            $w = -0.4375 $s $s;
  479.          }
  480.          // MATLAB's new ad hoc shift
  481.          if ($iter == 30{
  482.            $s ($y $x2.0;
  483.            $s $s $s $w;
  484.            if ($s 0{
  485.              $s sqrt($s);
  486.              if ($y $x)
  487.                $s = -$s;
  488.              $s $x $w (($y $x2.0 $s);
  489.              for ($i $low$i <= $n$i++)
  490.                $this->H[$i][$i-= $s;
  491.              $exshift += $s;
  492.              $x $y $w 0.964;
  493.            }
  494.          }            
  495.          // Could check iteration count here.
  496.          $iter $iter 1;   
  497.          // Look for two consecutive small sub-diagonal elements
  498.          $m $n 2;
  499.          while ($m >= $l{
  500.            $z $this->H[$m][$m];
  501.            $r $x $z;
  502.            $s $y $z;
  503.            $p ($r $s $w$this->H[$m+1][$m$this->H[$m][$m+1];
  504.            $q $this->H[$m+1][$m+1$z $r $s;
  505.            $r $this->H[$m+2][$m+1];
  506.            $s abs($pabs($qabs($r);
  507.            $p $p $s;
  508.            $q $q $s;
  509.            $r $r $s;
  510.            if ($m == $l)
  511.              break;
  512.            if (abs($this->H[$m][$m-1](abs($qabs($r)) $eps (abs($p(abs($this->H[$m-1][$m-1]abs($zabs($this->H[$m+1][$m+1]))))
  513.              break;
  514.            $m--;
  515.          }
  516.          for ($i $m 2$i <= $n$i++{
  517.            $this->H[$i][$i-20.0;
  518.            if ($i $m+2)
  519.              $this->H[$i][$i-30.0;
  520.          }
  521.          // Double QR step involving rows l:n and columns m:n
  522.          for ($k $m$k <= $n-1$k++{
  523.            $notlast ($k != $n-1);
  524.            if ($k != $m{
  525.              $p $this->H[$k][$k-1];
  526.              $q $this->H[$k+1][$k-1];
  527.              $r ($notlast $this->H[$k+2][$k-10.0);
  528.              $x abs($pabs($qabs($r);
  529.              if ($x != 0.0{
  530.                $p $p $x;
  531.                $q $q $x;
  532.                $r $r $x;
  533.              }
  534.            }
  535.            if ($x == 0.0)
  536.              break;
  537.            $s sqrt($p $p $q $q $r $r);
  538.            if ($p 0)
  539.              $s = -$s;
  540.            if ($s != 0{
  541.              if ($k != $m)
  542.                $this->H[$k][$k-1= -$s $x;
  543.              else if ($l != $m)
  544.                $this->H[$k][$k-1= -$this->H[$k][$k-1];
  545.              $p $p $s;
  546.              $x $p $s;
  547.              $y $q $s;
  548.              $z $r $s;
  549.              $q $q $p;
  550.              $r $r $p;
  551.              // Row modification
  552.              for ($j $k$j $nn$j++{
  553.                $p $this->H[$k][$j$q $this->H[$k+1][$j];
  554.                if ($notlast{
  555.                  $p $p $r $this->H[$k+2][$j];
  556.                  $this->H[$k+2][$j$this->H[$k+2][$j$p $z;
  557.                }
  558.                $this->H[$k][$j$this->H[$k][$j$p $x;
  559.                $this->H[$k+1][$j$this->H[$k+1][$j$p $y;
  560.              }
  561.              // Column modification
  562.              for ($i 0$i <= min($n$k+3)$i++{
  563.                $p $x $this->H[$i][$k$y $this->H[$i][$k+1];
  564.                if ($notlast{
  565.                  $p $p $z $this->H[$i][$k+2];
  566.                  $this->H[$i][$k+2$this->H[$i][$k+2$p $r;
  567.                }
  568.                $this->H[$i][$k$this->H[$i][$k$p;
  569.                $this->H[$i][$k+1$this->H[$i][$k+1$p $q;
  570.              }
  571.              // Accumulate transformations
  572.              for ($i $low$i <= $high$i++{
  573.                $p $x $this->V[$i][$k$y $this->V[$i][$k+1];
  574.                if ($notlast{
  575.                  $p $p $z $this->V[$i][$k+2];
  576.                  $this->V[$i][$k+2$this->V[$i][$k+2$p $r;
  577.                }
  578.                $this->V[$i][$k$this->V[$i][$k$p;
  579.                $this->V[$i][$k+1$this->V[$i][$k+1$p $q;
  580.              }
  581.            }  // ($s != 0)
  582.          }  // k loop
  583.        }  // check convergence
  584.     }  // while ($n >= $low)                      
  585.     // Backsubstitute to find vectors of upper triangular form
  586.     if ($norm == 0.0)
  587.       return;
  588.     for ($n $nn-1$n >= 0$n--{
  589.       $p $this->d[$n];
  590.       $q $this->e[$n];
  591.       // Real vector
  592.       if ($q == 0{
  593.         $l $n;
  594.         $this->H[$n][$n1.0;
  595.         for ($i $n-1$i >= 0$i--{
  596.           $w $this->H[$i][$i$p;
  597.           $r 0.0;
  598.           for ($j $l$j <= $n$j++)
  599.             $r $r $this->H[$i][$j$this->H[$j][$n];
  600.           if ($this->e[$i0.0{
  601.             $z $w;
  602.             $s $r;
  603.           else {
  604.             $l $i;
  605.             if ($this->e[$i== 0.0{
  606.               if ($w != 0.0)
  607.                 $this->H[$i][$n= -$r $w;
  608.               else
  609.                 $this->H[$i][$n= -$r ($eps $norm);
  610.               // Solve real equations
  611.             else {
  612.               $x $this->H[$i][$i+1];
  613.               $y $this->H[$i+1][$i];
  614.               $q ($this->d[$i$p($this->d[$i$p$this->e[$i$this->e[$i];
  615.               $t ($x $s $z $r$q;
  616.               $this->H[$i][$n$t;
  617.               if (abs($xabs($z))
  618.                 $this->H[$i+1][$n(-$r $w $t$x;
  619.               else
  620.                 $this->H[$i+1][$n(-$s $y $t$z;
  621.             }
  622.             // Overflow control
  623.             $t abs($this->H[$i][$n]);
  624.             if (($eps $t$t 1{
  625.               for ($j $i$j <= $n$j++)
  626.                 $this->H[$j][$n$this->H[$j][$n$t;
  627.             }
  628.           }
  629.         }
  630.       // Complex vector
  631.       else if ($q 0{
  632.         $l $n-1;
  633.         // Last vector component imaginary so matrix is triangular
  634.         if (abs($this->H[$n][$n-1]abs($this->H[$n-1][$n])) {
  635.           $this->H[$n-1][$n-1$q $this->H[$n][$n-1];
  636.           $this->H[$n-1][$n= -($this->H[$n][$n$p$this->H[$n][$n-1];
  637.         else {
  638.           $this->cdiv(0.0-$this->H[$n-1][$n]$this->H[$n-1][$n-1$p$q);
  639.           $this->H[$n-1][$n-1$this->cdivr;
  640.           $this->H[$n-1][$n]   $this->cdivi;
  641.         }
  642.         $this->H[$n][$n-10.0;
  643.         $this->H[$n][$n1.0;
  644.         for ($i $n-2$i >= 0$i--{
  645.           // double ra,sa,vr,vi;
  646.           $ra 0.0;
  647.           $sa 0.0;
  648.           for ($j $l$j <= $n$j++{
  649.             $ra $ra $this->H[$i][$j$this->H[$j][$n-1];
  650.             $sa $sa $this->H[$i][$j$this->H[$j][$n];
  651.           }
  652.           $w $this->H[$i][$i$p;
  653.           if ($this->e[$i0.0{
  654.             $z $w;
  655.             $r $ra;
  656.             $s $sa;
  657.           else {
  658.             $l $i;
  659.             if ($this->e[$i== 0{
  660.               $this->cdiv(-$ra-$sa$w$q);
  661.               $this->H[$i][$n-1$this->cdivr;
  662.               $this->H[$i][$n]   $this->cdivi;
  663.             else {
  664.               // Solve complex equations
  665.               $x $this->H[$i][$i+1];
  666.               $y $this->H[$i+1][$i];
  667.               $vr ($this->d[$i$p($this->d[$i$p$this->e[$i$this->e[$i$q $q;
  668.               $vi ($this->d[$i$p2.0 $q;
  669.               if ($vr == 0.0 $vi == 0.0)
  670.                 $vr $eps $norm (abs($wabs($qabs($xabs($yabs($z));
  671.               $this->cdiv($x $r $z $ra $q $sa$x $s $z $sa $q $ra$vr$vi);
  672.               $this->H[$i][$n-1$this->cdivr;
  673.               $this->H[$i][$n]   $this->cdivi;
  674.               if (abs($x(abs($zabs($q))) {
  675.                 $this->H[$i+1][$n-1(-$ra $w $this->H[$i][$n-1$q $this->H[$i][$n]$x;
  676.                 $this->H[$i+1][$n(-$sa $w $this->H[$i][$n$q $this->H[$i][$n-1]$x;
  677.               else {
  678.                 $this->cdiv(-$r $y $this->H[$i][$n-1]-$s $y $this->H[$i][$n]$z$q);
  679.                 $this->H[$i+1][$n-1$this->cdivr;
  680.                 $this->H[$i+1][$n]   $this->cdivi;
  681.               }
  682.             }
  683.             // Overflow control
  684.             $t max(abs($this->H[$i][$n-1]),abs($this->H[$i][$n]));
  685.             if (($eps $t$t 1{
  686.               for ($j $i$j <= $n$j++{
  687.                 $this->H[$j][$n-1$this->H[$j][$n-1$t;
  688.                 $this->H[$j][$n]   $this->H[$j][$n$t;
  689.               }
  690.             }
  691.           // end else
  692.         // end for
  693.       // end else for complex case
  694.     // end for            
  695.     // Vectors of isolated roots
  696.     for ($i 0$i $nn$i++{
  697.       if ($i $low $i $high{
  698.         for ($j $i$j $nn$j++)
  699.           $this->V[$i][$j$this->H[$i][$j];
  700.       }
  701.     }
  702.     // Back transformation to get eigenvectors of original matrix
  703.     for ($j $nn-1$j >= $low$j--{
  704.       for ($i $low$i <= $high$i++{
  705.         $z 0.0;
  706.         for ($k $low$k <= min($j,$high)$k++)
  707.           $z $z $this->V[$i][$k$this->H[$k][$j];
  708.         $this->V[$i][$j$z;
  709.       }
  710.     }                                     
  711.   // end hqr2
  712.   
  713.   /**
  714.   * Constructor: Check for symmetry, then construct the eigenvalue decomposition
  715.   * @access public
  716.   * @param  Square matrix
  717.   * @return Structure to access D and V.
  718.   */
  719.   function EigenvalueDecomposition($Arg{
  720.     $this->$Arg->getArray();
  721.     $this->n = $Arg->getColumnDimension();
  722.     $this->V = array();
  723.     $this->d = array();
  724.     $this->e = array();    
  725.     $issymmetric true;
  726.     for ($j 0($j $this->n$issymmetric$j++)
  727.       for ($i 0($i $this->n$issymmetric$i++)
  728.         $issymmetric ($this->A[$i][$j== $this->A[$j][$i]);
  729.     if ($issymmetric{
  730.        $this->V = $this->A;
  731.        // Tridiagonalize.
  732.        $this->tred2();
  733.        // Diagonalize.
  734.        $this->tql2();
  735.      else {
  736.        $this->H = $this->A;
  737.        $this->ort = array();
  738.        // Reduce to Hessenberg form.
  739.        $this->orthes();  
  740.        // Reduce Hessenberg to real Schur form.
  741.        $this->hqr2();
  742.      }
  743.   }
  744.  
  745.   /**
  746.   * Return the eigenvector matrix
  747.   * @access public
  748.   * @return 
  749.   */
  750.   function getV({
  751.     return new Matrix($this->V$this->n$this->n);
  752.   }
  753.  
  754.   /**
  755.   * Return the real parts of the eigenvalues
  756.   * @access public
  757.   * @return real(diag(D)) 
  758.   */
  759.   function getRealEigenvalues({
  760.     return $this->d;
  761.   }
  762.  
  763.   /**
  764.   * Return the imaginary parts of the eigenvalues
  765.   * @access public
  766.   * @return imag(diag(D)) 
  767.   */
  768.   function getImagEigenvalues({
  769.     return $this->e;
  770.   }
  771.  
  772.   /**
  773.   * Return the block diagonal eigenvalue matrix
  774.   * @access public
  775.   * @return 
  776.   */
  777.   function getD({
  778.     for ($i 0$i $this->n$i++{
  779.       $D[$iarray_fill(0$this->n0.0);
  780.       $D[$i][$i$this->d[$i];
  781.       if ($this->e[$i== 0)
  782.       continue;
  783.     $o ($this->e[$i0$i $i 1;
  784.     $D[$i][$o$this->e[$i];
  785.     }
  786.     return new Matrix($D);
  787.   }         
  788. }

Documentation generated on Mon, 05 Jan 2009 20:36:52 +0100 by phpDocumentor 1.4.1