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

Source for file QRDecomposition.php

Documentation is available at QRDecomposition.php

  1. <?php
  2. /**  
  3. @package JAMA
  4. *
  5. *  For an m-by-n matrix A with m >= n, the QR decomposition is an m-by-n
  6. *  orthogonal matrix Q and an n-by-n upper triangular matrix R so that
  7. *  A = Q*R.
  8. *   
  9. *  The QR decompostion always exists, even if the matrix does not have
  10. *  full rank, so the constructor will never fail.  The primary use of the
  11. *  QR decomposition is in the least squares solution of nonsquare systems
  12. *  of simultaneous linear equations.  This will fail if isFullRank()
  13. *  returns false.
  14. *  
  15. @author  Paul Meagher
  16. @license PHP v3.0
  17. @version 1.1
  18. */
  19. class QRDecomposition {
  20.   /**
  21.   * Array for internal storage of decomposition.
  22.   * @var array 
  23.   */     
  24.   var $QR = array();
  25.  
  26.   /**
  27.   * Row dimension.
  28.   * @var integer 
  29.   */    
  30.   var $m;
  31.  
  32.   /**
  33.   * Column dimension.
  34.   * @var integer 
  35.   */
  36.   var $n;
  37.  
  38.   /**
  39.   * Array for internal storage of diagonal of R.
  40.   * @var  array 
  41.   */
  42.   var $Rdiag = array();
  43.  
  44.   /**
  45.   * QR Decomposition computed by Householder reflections.
  46.   * @param matrix $A Rectangular matrix
  47.   * @return Structure to access R and the Householder vectors and compute Q.
  48.   */
  49.   function QRDecomposition($A{
  50.     ifis_a($A'Matrix') ) {
  51.       // Initialize.
  52.       $this->QR = $A->getArrayCopy();
  53.       $this->m  = $A->getRowDimension();
  54.       $this->n  = $A->getColumnDimension();
  55.       // Main loop.
  56.       for ($k 0$k $this->n$k++{
  57.         // Compute 2-norm of k-th column without under/overflow.
  58.         $nrm 0.0;
  59.         for ($i $k$i $this->m$i++)
  60.           $nrm hypo($nrm$this->QR[$i][$k]);
  61.         if ($nrm != 0.0{
  62.           // Form k-th Householder vector.
  63.           if ($this->QR[$k][$k0)
  64.             $nrm = -$nrm;
  65.           for ($i $k$i $this->m$i++)
  66.             $this->QR[$i][$k/= $nrm;
  67.           $this->QR[$k][$k+= 1.0;
  68.           // Apply transformation to remaining columns.
  69.           for ($j $k+1$j $this->n$j++{
  70.             $s 0.0;
  71.             for ($i $k$i $this->m$i++)
  72.               $s += $this->QR[$i][$k$this->QR[$i][$j];
  73.             $s = -$s/$this->QR[$k][$k];
  74.             for ($i $k$i $this->m$i++)
  75.               $this->QR[$i][$j+= $s $this->QR[$i][$k];
  76.           }
  77.         }
  78.             $this->Rdiag[$k= -$nrm;
  79.       }    
  80.       else 
  81.           trigger_error(ArgumentTypeExceptionERROR);
  82.   }
  83.  
  84.   /**
  85.   * Is the matrix full rank?
  86.   * @return boolean true if R, and hence A, has full rank, else false.
  87.   */
  88.   function isFullRank({
  89.     for ($j 0$j $this->n$j++)
  90.       if ($this->Rdiag[$j== 0)
  91.         return false;
  92.     return true;
  93.   }
  94.  
  95.   /**
  96.   * Return the Householder vectors
  97.   * @return Matrix Lower trapezoidal matrix whose columns define the reflections
  98.   */
  99.   function getH({
  100.     for ($i 0$i $this->m$i++{
  101.       for ($j 0$j $this->n$j++{
  102.         if ($i >= $j)
  103.           $H[$i][$j$this->QR[$i][$j];
  104.         else
  105.           $H[$i][$j0.0;
  106.       }
  107.     }
  108.     return new Matrix($H);
  109.   }
  110.  
  111.   /**
  112.   * Return the upper triangular factor
  113.   * @return Matrix upper triangular factor
  114.   */
  115.   function getR({
  116.     for ($i 0$i $this->n$i++{
  117.       for ($j 0$j $this->n$j++{
  118.         if ($i $j)
  119.           $R[$i][$j$this->QR[$i][$j];
  120.         else if ($i == $j)
  121.           $R[$i][$j$this->Rdiag[$i];
  122.         else
  123.           $R[$i][$j0.0;
  124.       }
  125.     }
  126.     return new Matrix($R);
  127.   }
  128.  
  129.   /**
  130.   * Generate and return the (economy-sized) orthogonal factor
  131.   * @return Matrix orthogonal factor
  132.   */
  133.   function getQ({
  134.     for ($k $this->n-1$k >= 0$k--{
  135.       for ($i 0$i $this->m$i++)
  136.         $Q[$i][$k0.0;
  137.       $Q[$k][$k1.0;
  138.       for ($j $k$j $this->n$j++{
  139.         if ($this->QR[$k][$k!= 0{
  140.           $s 0.0;
  141.           for ($i $k$i $this->m$i++)
  142.             $s += $this->QR[$i][$k$Q[$i][$j];
  143.           $s = -$s/$this->QR[$k][$k];
  144.           for ($i $k$i $this->m$i++)
  145.             $Q[$i][$j+= $s $this->QR[$i][$k];
  146.         }
  147.       }
  148.     }   
  149.     /* 
  150.       for( $i = 0; $i < count($Q); $i++ ) 
  151.           for( $j = 0; $j < count($Q); $j++ ) 
  152.               if(! isset($Q[$i][$j]) )
  153.                   $Q[$i][$j] = 0;
  154.       */
  155.       return new Matrix($Q);
  156.   }
  157.                     
  158.   /**
  159.   * Least squares solution of A*X = B
  160.   * @param Matrix $B A Matrix with as many rows as A and any number of columns.
  161.   * @return Matrix Matrix that minimizes the two norm of Q*R*X-B.
  162.   */
  163.   function solve($B{
  164.     if ($B->getRowDimension(== $this->m{
  165.       if ($this->isFullRank()) {
  166.         // Copy right hand side
  167.         $nx $B->getColumnDimension();                   
  168.         $X  $B->getArrayCopy();
  169.         // Compute Y = transpose(Q)*B
  170.         for ($k 0$k $this->n$k++{
  171.           for ($j 0$j $nx$j++{
  172.             $s 0.0;
  173.             for ($i $k$i $this->m$i++)
  174.               $s += $this->QR[$i][$k$X[$i][$j];
  175.             $s = -$s/$this->QR[$k][$k];
  176.             for ($i $k$i $this->m$i++)
  177.               $X[$i][$j+= $s $this->QR[$i][$k];
  178.           }
  179.         }    
  180.         // Solve R*X = Y;
  181.         for ($k $this->n-1$k >= 0$k--{
  182.           for ($j 0$j $nx$j++)
  183.             $X[$k][$j/= $this->Rdiag[$k];
  184.           for ($i 0$i $k$i++)
  185.             for ($j 0$j $nx$j++)
  186.               $X[$i][$j-= $X[$k][$j]$this->QR[$i][$k];
  187.         }
  188.         $X new Matrix($X);
  189.         return ($X->getMatrix(0$this->n-10$nx));
  190.       else 
  191.     else 
  192.   }
  193. }

Documentation generated on Mon, 05 Jan 2009 20:38:24 +0100 by phpDocumentor 1.4.1