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.     /**
  22.      *    Array for internal storage of decomposition.
  23.      *    @var array 
  24.      */
  25.     private $QR array();
  26.  
  27.     /**
  28.      *    Row dimension.
  29.      *    @var integer 
  30.      */
  31.     private $m;
  32.  
  33.     /**
  34.     *    Column dimension.
  35.     *    @var integer 
  36.     */
  37.     private $n;
  38.  
  39.     /**
  40.      *    Array for internal storage of diagonal of R.
  41.      *    @var  array 
  42.      */
  43.     private $Rdiag array();
  44.  
  45.  
  46.     /**
  47.      *    QR Decomposition computed by Householder reflections.
  48.      *
  49.      *    @param matrix $A Rectangular matrix
  50.      *    @return Structure to access R and the Householder vectors and compute Q.
  51.      */
  52.     public function __construct($A{
  53.         if($A instanceof Matrix{
  54.             // Initialize.
  55.             $this->QR $A->getArrayCopy();
  56.             $this->m  $A->getRowDimension();
  57.             $this->n  $A->getColumnDimension();
  58.             // Main loop.
  59.             for ($k 0$k $this->n++$k{
  60.                 // Compute 2-norm of k-th column without under/overflow.
  61.                 $nrm 0.0;
  62.                 for ($i $k$i $this->m++$i{
  63.                     $nrm hypo($nrm$this->QR[$i][$k]);
  64.                 }
  65.                 if ($nrm != 0.0{
  66.                     // Form k-th Householder vector.
  67.                     if ($this->QR[$k][$k0{
  68.                         $nrm = -$nrm;
  69.                     }
  70.                     for ($i $k$i $this->m++$i{
  71.                         $this->QR[$i][$k/= $nrm;
  72.                     }
  73.                     $this->QR[$k][$k+= 1.0;
  74.                     // Apply transformation to remaining columns.
  75.                     for ($j $k+1$j $this->n++$j{
  76.                         $s 0.0;
  77.                         for ($i $k$i $this->m++$i{
  78.                             $s += $this->QR[$i][$k$this->QR[$i][$j];
  79.                         }
  80.                         $s = -$s/$this->QR[$k][$k];
  81.                         for ($i $k$i $this->m++$i{
  82.                             $this->QR[$i][$j+= $s $this->QR[$i][$k];
  83.                         }
  84.                     }
  85.                 }
  86.                 $this->Rdiag[$k= -$nrm;
  87.             }
  88.         else {
  89.             throw new Exception(JAMAError(ArgumentTypeException));
  90.         }
  91.     }    //    function __construct()
  92.  
  93.  
  94.     /**
  95.      *    Is the matrix full rank?
  96.      *
  97.      *    @return boolean true if R, and hence A, has full rank, else false.
  98.      */
  99.     public function isFullRank({
  100.         for ($j 0$j $this->n++$j{
  101.             if ($this->Rdiag[$j== 0{
  102.                 return false;
  103.             }
  104.         }
  105.         return true;
  106.     }    //    function isFullRank()
  107.  
  108.  
  109.     /**
  110.      *    Return the Householder vectors
  111.      *
  112.      *    @return Matrix Lower trapezoidal matrix whose columns define the reflections
  113.      */
  114.     public function getH({
  115.         for ($i 0$i $this->m++$i{
  116.             for ($j 0$j $this->n++$j{
  117.                 if ($i >= $j{
  118.                     $H[$i][$j$this->QR[$i][$j];
  119.                 else {
  120.                     $H[$i][$j0.0;
  121.                 }
  122.             }
  123.         }
  124.         return new Matrix($H);
  125.     }    //    function getH()
  126.  
  127.  
  128.     /**
  129.      *    Return the upper triangular factor
  130.      *
  131.      *    @return Matrix upper triangular factor
  132.      */
  133.     public function getR({
  134.         for ($i 0$i $this->n++$i{
  135.             for ($j 0$j $this->n++$j{
  136.                 if ($i $j{
  137.                     $R[$i][$j$this->QR[$i][$j];
  138.                 elseif ($i == $j{
  139.                     $R[$i][$j$this->Rdiag[$i];
  140.                 else {
  141.                     $R[$i][$j0.0;
  142.                 }
  143.             }
  144.         }
  145.         return new Matrix($R);
  146.     }    //    function getR()
  147.  
  148.  
  149.     /**
  150.      *    Generate and return the (economy-sized) orthogonal factor
  151.      *
  152.      *    @return Matrix orthogonal factor
  153.      */
  154.     public function getQ({
  155.         for ($k $this->n-1$k >= 0--$k{
  156.             for ($i 0$i $this->m++$i{
  157.                 $Q[$i][$k0.0;
  158.             }
  159.             $Q[$k][$k1.0;
  160.             for ($j $k$j $this->n++$j{
  161.                 if ($this->QR[$k][$k!= 0{
  162.                     $s 0.0;
  163.                     for ($i $k$i $this->m++$i{
  164.                         $s += $this->QR[$i][$k$Q[$i][$j];
  165.                     }
  166.                     $s = -$s/$this->QR[$k][$k];
  167.                     for ($i $k$i $this->m++$i{
  168.                         $Q[$i][$j+= $s $this->QR[$i][$k];
  169.                     }
  170.                 }
  171.             }
  172.         }
  173.         /*
  174.         for($i = 0; $i < count($Q); ++$i) {
  175.             for($j = 0; $j < count($Q); ++$j) {
  176.                 if(! isset($Q[$i][$j]) ) {
  177.                     $Q[$i][$j] = 0;
  178.                 }
  179.             }
  180.         }
  181.         */
  182.         return new Matrix($Q);
  183.     }    //    function getQ()
  184.  
  185.  
  186.     /**
  187.      *    Least squares solution of A*X = B
  188.      *
  189.      *    @param Matrix $B A Matrix with as many rows as A and any number of columns.
  190.      *    @return Matrix Matrix that minimizes the two norm of Q*R*X-B.
  191.      */
  192.     public function solve($B{
  193.         if ($B->getRowDimension(== $this->m{
  194.             if ($this->isFullRank()) {
  195.                 // Copy right hand side
  196.                 $nx $B->getColumnDimension();
  197.                 $X  $B->getArrayCopy();
  198.                 // Compute Y = transpose(Q)*B
  199.                 for ($k 0$k $this->n++$k{
  200.                     for ($j 0$j $nx++$j{
  201.                         $s 0.0;
  202.                         for ($i $k$i $this->m++$i{
  203.                             $s += $this->QR[$i][$k$X[$i][$j];
  204.                         }
  205.                         $s = -$s/$this->QR[$k][$k];
  206.                         for ($i $k$i $this->m++$i{
  207.                             $X[$i][$j+= $s $this->QR[$i][$k];
  208.                         }
  209.                     }
  210.                 }
  211.                 // Solve R*X = Y;
  212.                 for ($k $this->n-1$k >= 0--$k{
  213.                     for ($j 0$j $nx++$j{
  214.                         $X[$k][$j/= $this->Rdiag[$k];
  215.                     }
  216.                     for ($i 0$i $k++$i{
  217.                         for ($j 0$j $nx++$j{
  218.                             $X[$i][$j-= $X[$k][$j]$this->QR[$i][$k];
  219.                         }
  220.                     }
  221.                 }
  222.                 $X new Matrix($X);
  223.                 return ($X->getMatrix(0$this->n-10$nx));
  224.             else {
  225.                 throw new Exception(JAMAError(MatrixRankException));
  226.             }
  227.         else {
  228.             throw new Exception(JAMAError(MatrixDimensionException));
  229.         }
  230.     }    //    function solve()
  231.  
  232. }    //    class QRDecomposition

Documentation generated on Tue, 01 Jun 2010 17:05:48 +0200 by phpDocumentor 1.4.3