示例#1
0
 /**
  *	QR Decomposition computed by Householder reflections.
  *
  *	@param matrix $A Rectangular matrix
  *	@return Structure to access R and the Householder vectors and compute Q.
  */
 public function __construct($A)
 {
     if ($A instanceof PHPExcel_Shared_JAMA_Matrix) {
         // Initialize.
         $this->QR = $A->getArrayCopy();
         $this->m = $A->getRowDimension();
         $this->n = $A->getColumnDimension();
         // Main loop.
         for ($k = 0; $k < $this->n; ++$k) {
             // Compute 2-norm of k-th column without under/overflow.
             $nrm = 0.0;
             for ($i = $k; $i < $this->m; ++$i) {
                 $nrm = hypo($nrm, $this->QR[$i][$k]);
             }
             if ($nrm != 0.0) {
                 // Form k-th Householder vector.
                 if ($this->QR[$k][$k] < 0) {
                     $nrm = -$nrm;
                 }
                 for ($i = $k; $i < $this->m; ++$i) {
                     $this->QR[$i][$k] /= $nrm;
                 }
                 $this->QR[$k][$k] += 1.0;
                 // Apply transformation to remaining columns.
                 for ($j = $k + 1; $j < $this->n; ++$j) {
                     $s = 0.0;
                     for ($i = $k; $i < $this->m; ++$i) {
                         $s += $this->QR[$i][$k] * $this->QR[$i][$j];
                     }
                     $s = -$s / $this->QR[$k][$k];
                     for ($i = $k; $i < $this->m; ++$i) {
                         $this->QR[$i][$j] += $s * $this->QR[$i][$k];
                     }
                 }
             }
             $this->Rdiag[$k] = -$nrm;
         }
     } else {
         throw new Exception(PHPExcel_Shared_JAMA_Matrix::ArgumentTypeException);
     }
 }
示例#2
0
 /**
  * QR Decomposition computed by Householder reflections.
  * @param matrix $A Rectangular matrix
  * @return Structure to access R and the Householder vectors and compute Q.
  */
 function QRDecomposition($A)
 {
     if (is_a($A, 'Matrix')) {
         // Initialize.
         $this->QR = $A->getArrayCopy();
         $this->m = $A->getRowDimension();
         $this->n = $A->getColumnDimension();
         // Main loop.
         for ($k = 0; $k < $this->n; $k++) {
             // Compute 2-norm of k-th column without under/overflow.
             $nrm = 0.0;
             for ($i = $k; $i < $this->m; $i++) {
                 $nrm = hypo($nrm, $this->QR[$i][$k]);
             }
             if ($nrm != 0.0) {
                 // Form k-th Householder vector.
                 if ($this->QR[$k][$k] < 0) {
                     $nrm = -$nrm;
                 }
                 for ($i = $k; $i < $this->m; $i++) {
                     $this->QR[$i][$k] /= $nrm;
                 }
                 $this->QR[$k][$k] += 1.0;
                 // Apply transformation to remaining columns.
                 for ($j = $k + 1; $j < $this->n; $j++) {
                     $s = 0.0;
                     for ($i = $k; $i < $this->m; $i++) {
                         $s += $this->QR[$i][$k] * $this->QR[$i][$j];
                     }
                     $s = -$s / $this->QR[$k][$k];
                     for ($i = $k; $i < $this->m; $i++) {
                         $this->QR[$i][$j] += $s * $this->QR[$i][$k];
                     }
                 }
             }
             $this->Rdiag[$k] = -$nrm;
         }
     } else {
         trigger_error(ArgumentTypeException, ERROR);
     }
 }
示例#3
0
 /**
  * normF
  * Frobenius norm
  * @return float Square root of the sum of all elements squared
  */
 function normF()
 {
     $f = 0;
     for ($i = 0; $i < $this->m; $i++) {
         for ($j = 0; $j < $this->n; $j++) {
             $f = hypo($f, $this->A[$i][$j]);
         }
     }
     return $f;
 }
示例#4
0
 /**
  *	normF
  *
  *	Frobenius norm
  *	@return float Square root of the sum of all elements squared
  */
 public function normF()
 {
     $f = 0;
     for ($i = 0; $i < $this->m; ++$i) {
         for ($j = 0; $j < $this->n; ++$j) {
             $f = hypo($f, $this->A[$i][$j]);
         }
     }
     return $f;
 }
 /**
  *    Symmetric tridiagonal QL algorithm.
  *
  *    This is derived from the Algol procedures tql2, by
  *    Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
  *    Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
  *    Fortran subroutine in EISPACK.
  *
  *    @access private
  */
 private function tql2()
 {
     for ($i = 1; $i < $this->n; ++$i) {
         $this->e[$i - 1] = $this->e[$i];
     }
     $this->e[$this->n - 1] = 0.0;
     $f = 0.0;
     $tst1 = 0.0;
     $eps = pow(2.0, -52.0);
     for ($l = 0; $l < $this->n; ++$l) {
         // Find small subdiagonal element
         $tst1 = max($tst1, abs($this->d[$l]) + abs($this->e[$l]));
         $m = $l;
         while ($m < $this->n) {
             if (abs($this->e[$m]) <= $eps * $tst1) {
                 break;
             }
             ++$m;
         }
         // If m == l, $this->d[l] is an eigenvalue,
         // otherwise, iterate.
         if ($m > $l) {
             $iter = 0;
             do {
                 // Could check iteration count here.
                 $iter += 1;
                 // Compute implicit shift
                 $g = $this->d[$l];
                 $p = ($this->d[$l + 1] - $g) / (2.0 * $this->e[$l]);
                 $r = hypo($p, 1.0);
                 if ($p < 0) {
                     $r *= -1;
                 }
                 $this->d[$l] = $this->e[$l] / ($p + $r);
                 $this->d[$l + 1] = $this->e[$l] * ($p + $r);
                 $dl1 = $this->d[$l + 1];
                 $h = $g - $this->d[$l];
                 for ($i = $l + 2; $i < $this->n; ++$i) {
                     $this->d[$i] -= $h;
                 }
                 $f += $h;
                 // Implicit QL transformation.
                 $p = $this->d[$m];
                 $c = 1.0;
                 $c2 = $c3 = $c;
                 $el1 = $this->e[$l + 1];
                 $s = $s2 = 0.0;
                 for ($i = $m - 1; $i >= $l; --$i) {
                     $c3 = $c2;
                     $c2 = $c;
                     $s2 = $s;
                     $g = $c * $this->e[$i];
                     $h = $c * $p;
                     $r = hypo($p, $this->e[$i]);
                     $this->e[$i + 1] = $s * $r;
                     $s = $this->e[$i] / $r;
                     $c = $p / $r;
                     $p = $c * $this->d[$i] - $s * $g;
                     $this->d[$i + 1] = $h + $s * ($c * $g + $s * $this->d[$i]);
                     // Accumulate transformation.
                     for ($k = 0; $k < $this->n; ++$k) {
                         $h = $this->V[$k][$i + 1];
                         $this->V[$k][$i + 1] = $s * $this->V[$k][$i] + $c * $h;
                         $this->V[$k][$i] = $c * $this->V[$k][$i] - $s * $h;
                     }
                 }
                 $p = -$s * $s2 * $c3 * $el1 * $this->e[$l] / $dl1;
                 $this->e[$l] = $s * $p;
                 $this->d[$l] = $c * $p;
                 // Check for convergence.
             } while (abs($this->e[$l]) > $eps * $tst1);
         }
         $this->d[$l] = $this->d[$l] + $f;
         $this->e[$l] = 0.0;
     }
     // Sort eigenvalues and corresponding vectors.
     for ($i = 0; $i < $this->n - 1; ++$i) {
         $k = $i;
         $p = $this->d[$i];
         for ($j = $i + 1; $j < $this->n; ++$j) {
             if ($this->d[$j] < $p) {
                 $k = $j;
                 $p = $this->d[$j];
             }
         }
         if ($k != $i) {
             $this->d[$k] = $this->d[$i];
             $this->d[$i] = $p;
             for ($j = 0; $j < $this->n; ++$j) {
                 $p = $this->V[$j][$i];
                 $this->V[$j][$i] = $this->V[$j][$k];
                 $this->V[$j][$k] = $p;
             }
         }
     }
 }
 /**
  *	Construct the singular value decomposition
  *
  *	Derived from LINPACK code.
  *
  *	@param $A Rectangular matrix
  *	@return Structure to access U, S and V.
  */
 public function __construct($Arg)
 {
     // Initialize.
     $A = $Arg->getArrayCopy();
     $this->m = $Arg->getRowDimension();
     $this->n = $Arg->getColumnDimension();
     $nu = min($this->m, $this->n);
     $e = array();
     $work = array();
     $wantu = true;
     $wantv = true;
     $nct = min($this->m - 1, $this->n);
     $nrt = max(0, min($this->n - 2, $this->m));
     // Reduce A to bidiagonal form, storing the diagonal elements
     // in s and the super-diagonal elements in e.
     for ($k = 0; $k < max($nct, $nrt); ++$k) {
         if ($k < $nct) {
             // Compute the transformation for the k-th column and
             // place the k-th diagonal in s[$k].
             // Compute 2-norm of k-th column without under/overflow.
             $this->s[$k] = 0;
             for ($i = $k; $i < $this->m; ++$i) {
                 $this->s[$k] = hypo($this->s[$k], $A[$i][$k]);
             }
             if ($this->s[$k] != 0.0) {
                 if ($A[$k][$k] < 0.0) {
                     $this->s[$k] = -$this->s[$k];
                 }
                 for ($i = $k; $i < $this->m; ++$i) {
                     $A[$i][$k] /= $this->s[$k];
                 }
                 $A[$k][$k] += 1.0;
             }
             $this->s[$k] = -$this->s[$k];
         }
         for ($j = $k + 1; $j < $this->n; ++$j) {
             if ($k < $nct & $this->s[$k] != 0.0) {
                 // Apply the transformation.
                 $t = 0;
                 for ($i = $k; $i < $this->m; ++$i) {
                     $t += $A[$i][$k] * $A[$i][$j];
                 }
                 $t = -$t / $A[$k][$k];
                 for ($i = $k; $i < $this->m; ++$i) {
                     $A[$i][$j] += $t * $A[$i][$k];
                 }
                 // Place the k-th row of A into e for the
                 // subsequent calculation of the row transformation.
                 $e[$j] = $A[$k][$j];
             }
         }
         if ($wantu and $k < $nct) {
             // Place the transformation in U for subsequent back
             // multiplication.
             for ($i = $k; $i < $this->m; ++$i) {
                 $this->U[$i][$k] = $A[$i][$k];
             }
         }
         if ($k < $nrt) {
             // Compute the k-th row transformation and place the
             // k-th super-diagonal in e[$k].
             // Compute 2-norm without under/overflow.
             $e[$k] = 0;
             for ($i = $k + 1; $i < $this->n; ++$i) {
                 $e[$k] = hypo($e[$k], $e[$i]);
             }
             if ($e[$k] != 0.0) {
                 if ($e[$k + 1] < 0.0) {
                     $e[$k] = -$e[$k];
                 }
                 for ($i = $k + 1; $i < $this->n; ++$i) {
                     $e[$i] /= $e[$k];
                 }
                 $e[$k + 1] += 1.0;
             }
             $e[$k] = -$e[$k];
             if ($k + 1 < $this->m and $e[$k] != 0.0) {
                 // Apply the transformation.
                 for ($i = $k + 1; $i < $this->m; ++$i) {
                     $work[$i] = 0.0;
                 }
                 for ($j = $k + 1; $j < $this->n; ++$j) {
                     for ($i = $k + 1; $i < $this->m; ++$i) {
                         $work[$i] += $e[$j] * $A[$i][$j];
                     }
                 }
                 for ($j = $k + 1; $j < $this->n; ++$j) {
                     $t = -$e[$j] / $e[$k + 1];
                     for ($i = $k + 1; $i < $this->m; ++$i) {
                         $A[$i][$j] += $t * $work[$i];
                     }
                 }
             }
             if ($wantv) {
                 // Place the transformation in V for subsequent
                 // back multiplication.
                 for ($i = $k + 1; $i < $this->n; ++$i) {
                     $this->V[$i][$k] = $e[$i];
                 }
             }
         }
     }
     // Set up the final bidiagonal matrix or order p.
     $p = min($this->n, $this->m + 1);
     if ($nct < $this->n) {
         $this->s[$nct] = $A[$nct][$nct];
     }
     if ($this->m < $p) {
         $this->s[$p - 1] = 0.0;
     }
     if ($nrt + 1 < $p) {
         $e[$nrt] = $A[$nrt][$p - 1];
     }
     $e[$p - 1] = 0.0;
     // If required, generate U.
     if ($wantu) {
         for ($j = $nct; $j < $nu; ++$j) {
             for ($i = 0; $i < $this->m; ++$i) {
                 $this->U[$i][$j] = 0.0;
             }
             $this->U[$j][$j] = 1.0;
         }
         for ($k = $nct - 1; $k >= 0; --$k) {
             if ($this->s[$k] != 0.0) {
                 for ($j = $k + 1; $j < $nu; ++$j) {
                     $t = 0;
                     for ($i = $k; $i < $this->m; ++$i) {
                         $t += $this->U[$i][$k] * $this->U[$i][$j];
                     }
                     $t = -$t / $this->U[$k][$k];
                     for ($i = $k; $i < $this->m; ++$i) {
                         $this->U[$i][$j] += $t * $this->U[$i][$k];
                     }
                 }
                 for ($i = $k; $i < $this->m; ++$i) {
                     $this->U[$i][$k] = -$this->U[$i][$k];
                 }
                 $this->U[$k][$k] = 1.0 + $this->U[$k][$k];
                 for ($i = 0; $i < $k - 1; ++$i) {
                     $this->U[$i][$k] = 0.0;
                 }
             } else {
                 for ($i = 0; $i < $this->m; ++$i) {
                     $this->U[$i][$k] = 0.0;
                 }
                 $this->U[$k][$k] = 1.0;
             }
         }
     }
     // If required, generate V.
     if ($wantv) {
         for ($k = $this->n - 1; $k >= 0; --$k) {
             if ($k < $nrt and $e[$k] != 0.0) {
                 for ($j = $k + 1; $j < $nu; ++$j) {
                     $t = 0;
                     for ($i = $k + 1; $i < $this->n; ++$i) {
                         $t += $this->V[$i][$k] * $this->V[$i][$j];
                     }
                     $t = -$t / $this->V[$k + 1][$k];
                     for ($i = $k + 1; $i < $this->n; ++$i) {
                         $this->V[$i][$j] += $t * $this->V[$i][$k];
                     }
                 }
             }
             for ($i = 0; $i < $this->n; ++$i) {
                 $this->V[$i][$k] = 0.0;
             }
             $this->V[$k][$k] = 1.0;
         }
     }
     // Main iteration loop for the singular values.
     $pp = $p - 1;
     $iter = 0;
     $eps = pow(2.0, -52.0);
     while ($p > 0) {
         // Here is where a test for too many iterations would go.
         // This section of the program inspects for negligible
         // elements in the s and e arrays.  On completion the
         // variables kase and k are set as follows:
         // kase = 1  if s(p) and e[k-1] are negligible and k<p
         // kase = 2  if s(k) is negligible and k<p
         // kase = 3  if e[k-1] is negligible, k<p, and
         //           s(k), ..., s(p) are not negligible (qr step).
         // kase = 4  if e(p-1) is negligible (convergence).
         for ($k = $p - 2; $k >= -1; --$k) {
             if ($k == -1) {
                 break;
             }
             if (abs($e[$k]) <= $eps * (abs($this->s[$k]) + abs($this->s[$k + 1]))) {
                 $e[$k] = 0.0;
                 break;
             }
         }
         if ($k == $p - 2) {
             $kase = 4;
         } else {
             for ($ks = $p - 1; $ks >= $k; --$ks) {
                 if ($ks == $k) {
                     break;
                 }
                 $t = ($ks != $p ? abs($e[$ks]) : 0.0) + ($ks != $k + 1 ? abs($e[$ks - 1]) : 0.0);
                 if (abs($this->s[$ks]) <= $eps * $t) {
                     $this->s[$ks] = 0.0;
                     break;
                 }
             }
             if ($ks == $k) {
                 $kase = 3;
             } else {
                 if ($ks == $p - 1) {
                     $kase = 1;
                 } else {
                     $kase = 2;
                     $k = $ks;
                 }
             }
         }
         ++$k;
         // Perform the task indicated by kase.
         switch ($kase) {
             // Deflate negligible s(p).
             case 1:
                 $f = $e[$p - 2];
                 $e[$p - 2] = 0.0;
                 for ($j = $p - 2; $j >= $k; --$j) {
                     $t = hypo($this->s[$j], $f);
                     $cs = $this->s[$j] / $t;
                     $sn = $f / $t;
                     $this->s[$j] = $t;
                     if ($j != $k) {
                         $f = -$sn * $e[$j - 1];
                         $e[$j - 1] = $cs * $e[$j - 1];
                     }
                     if ($wantv) {
                         for ($i = 0; $i < $this->n; ++$i) {
                             $t = $cs * $this->V[$i][$j] + $sn * $this->V[$i][$p - 1];
                             $this->V[$i][$p - 1] = -$sn * $this->V[$i][$j] + $cs * $this->V[$i][$p - 1];
                             $this->V[$i][$j] = $t;
                         }
                     }
                 }
                 break;
                 // Split at negligible s(k).
             // Split at negligible s(k).
             case 2:
                 $f = $e[$k - 1];
                 $e[$k - 1] = 0.0;
                 for ($j = $k; $j < $p; ++$j) {
                     $t = hypo($this->s[$j], $f);
                     $cs = $this->s[$j] / $t;
                     $sn = $f / $t;
                     $this->s[$j] = $t;
                     $f = -$sn * $e[$j];
                     $e[$j] = $cs * $e[$j];
                     if ($wantu) {
                         for ($i = 0; $i < $this->m; ++$i) {
                             $t = $cs * $this->U[$i][$j] + $sn * $this->U[$i][$k - 1];
                             $this->U[$i][$k - 1] = -$sn * $this->U[$i][$j] + $cs * $this->U[$i][$k - 1];
                             $this->U[$i][$j] = $t;
                         }
                     }
                 }
                 break;
                 // Perform one qr step.
             // Perform one qr step.
             case 3:
                 // Calculate the shift.
                 $scale = max(max(max(max(abs($this->s[$p - 1]), abs($this->s[$p - 2])), abs($e[$p - 2])), abs($this->s[$k])), abs($e[$k]));
                 $sp = $this->s[$p - 1] / $scale;
                 $spm1 = $this->s[$p - 2] / $scale;
                 $epm1 = $e[$p - 2] / $scale;
                 $sk = $this->s[$k] / $scale;
                 $ek = $e[$k] / $scale;
                 $b = (($spm1 + $sp) * ($spm1 - $sp) + $epm1 * $epm1) / 2.0;
                 $c = $sp * $epm1 * ($sp * $epm1);
                 $shift = 0.0;
                 if ($b != 0.0 || $c != 0.0) {
                     $shift = sqrt($b * $b + $c);
                     if ($b < 0.0) {
                         $shift = -$shift;
                     }
                     $shift = $c / ($b + $shift);
                 }
                 $f = ($sk + $sp) * ($sk - $sp) + $shift;
                 $g = $sk * $ek;
                 // Chase zeros.
                 for ($j = $k; $j < $p - 1; ++$j) {
                     $t = hypo($f, $g);
                     $cs = $f / $t;
                     $sn = $g / $t;
                     if ($j != $k) {
                         $e[$j - 1] = $t;
                     }
                     $f = $cs * $this->s[$j] + $sn * $e[$j];
                     $e[$j] = $cs * $e[$j] - $sn * $this->s[$j];
                     $g = $sn * $this->s[$j + 1];
                     $this->s[$j + 1] = $cs * $this->s[$j + 1];
                     if ($wantv) {
                         for ($i = 0; $i < $this->n; ++$i) {
                             $t = $cs * $this->V[$i][$j] + $sn * $this->V[$i][$j + 1];
                             $this->V[$i][$j + 1] = -$sn * $this->V[$i][$j] + $cs * $this->V[$i][$j + 1];
                             $this->V[$i][$j] = $t;
                         }
                     }
                     $t = hypo($f, $g);
                     $cs = $f / $t;
                     $sn = $g / $t;
                     $this->s[$j] = $t;
                     $f = $cs * $e[$j] + $sn * $this->s[$j + 1];
                     $this->s[$j + 1] = -$sn * $e[$j] + $cs * $this->s[$j + 1];
                     $g = $sn * $e[$j + 1];
                     $e[$j + 1] = $cs * $e[$j + 1];
                     if ($wantu && $j < $this->m - 1) {
                         for ($i = 0; $i < $this->m; ++$i) {
                             $t = $cs * $this->U[$i][$j] + $sn * $this->U[$i][$j + 1];
                             $this->U[$i][$j + 1] = -$sn * $this->U[$i][$j] + $cs * $this->U[$i][$j + 1];
                             $this->U[$i][$j] = $t;
                         }
                     }
                 }
                 $e[$p - 2] = $f;
                 $iter = $iter + 1;
                 break;
                 // Convergence.
             // Convergence.
             case 4:
                 // Make the singular values positive.
                 if ($this->s[$k] <= 0.0) {
                     $this->s[$k] = $this->s[$k] < 0.0 ? -$this->s[$k] : 0.0;
                     if ($wantv) {
                         for ($i = 0; $i <= $pp; ++$i) {
                             $this->V[$i][$k] = -$this->V[$i][$k];
                         }
                     }
                 }
                 // Order the singular values.
                 while ($k < $pp) {
                     if ($this->s[$k] >= $this->s[$k + 1]) {
                         break;
                     }
                     $t = $this->s[$k];
                     $this->s[$k] = $this->s[$k + 1];
                     $this->s[$k + 1] = $t;
                     if ($wantv and $k < $this->n - 1) {
                         for ($i = 0; $i < $this->n; ++$i) {
                             $t = $this->V[$i][$k + 1];
                             $this->V[$i][$k + 1] = $this->V[$i][$k];
                             $this->V[$i][$k] = $t;
                         }
                     }
                     if ($wantu and $k < $this->m - 1) {
                         for ($i = 0; $i < $this->m; ++$i) {
                             $t = $this->U[$i][$k + 1];
                             $this->U[$i][$k + 1] = $this->U[$i][$k];
                             $this->U[$i][$k] = $t;
                         }
                     }
                     ++$k;
                 }
                 $iter = 0;
                 --$p;
                 break;
         }
         // end switch
     }
     // end while
 }