upgrade to PHPExcel 1.7.0

This commit is contained in:
Dieter Adriaenssens
2010-05-02 20:20:06 +02:00
parent 435a470445
commit cd30b51904
15 changed files with 3398 additions and 3219 deletions

View File

@@ -22,7 +22,7 @@
* @package PHPExcel_Shared_Escher * @package PHPExcel_Shared_Escher
* @copyright Copyright (c) 2006 - 2009 PHPExcel (http://www.codeplex.com/PHPExcel) * @copyright Copyright (c) 2006 - 2009 PHPExcel (http://www.codeplex.com/PHPExcel)
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
* @version 1.6.7, 2009-04-22 * @version 1.7.0, 2009-08-10
*/ */
/** /**

View File

@@ -22,7 +22,7 @@
* @package PHPExcel_Shared_Escher * @package PHPExcel_Shared_Escher
* @copyright Copyright (c) 2006 - 2009 PHPExcel (http://www.codeplex.com/PHPExcel) * @copyright Copyright (c) 2006 - 2009 PHPExcel (http://www.codeplex.com/PHPExcel)
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
* @version 1.6.7, 2009-04-22 * @version 1.7.0, 2009-08-10
*/ */
/** /**

View File

@@ -22,7 +22,7 @@
* @package PHPExcel_Shared_Escher * @package PHPExcel_Shared_Escher
* @copyright Copyright (c) 2006 - 2009 PHPExcel (http://www.codeplex.com/PHPExcel) * @copyright Copyright (c) 2006 - 2009 PHPExcel (http://www.codeplex.com/PHPExcel)
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
* @version 1.6.7, 2009-04-22 * @version 1.7.0, 2009-08-10
*/ */
/** /**

View File

@@ -22,7 +22,7 @@
* @package PHPExcel_Shared_Escher * @package PHPExcel_Shared_Escher
* @copyright Copyright (c) 2006 - 2009 PHPExcel (http://www.codeplex.com/PHPExcel) * @copyright Copyright (c) 2006 - 2009 PHPExcel (http://www.codeplex.com/PHPExcel)
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
* @version 1.6.7, 2009-04-22 * @version 1.7.0, 2009-08-10
*/ */
/** /**

View File

@@ -22,7 +22,7 @@
* @package PHPExcel_Shared_Escher * @package PHPExcel_Shared_Escher
* @copyright Copyright (c) 2006 - 2009 PHPExcel (http://www.codeplex.com/PHPExcel) * @copyright Copyright (c) 2006 - 2009 PHPExcel (http://www.codeplex.com/PHPExcel)
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
* @version 1.6.7, 2009-04-22 * @version 1.7.0, 2009-08-10
*/ */
/** /**

View File

@@ -22,7 +22,7 @@
* @package PHPExcel_Shared_Escher * @package PHPExcel_Shared_Escher
* @copyright Copyright (c) 2006 - 2009 PHPExcel (http://www.codeplex.com/PHPExcel) * @copyright Copyright (c) 2006 - 2009 PHPExcel (http://www.codeplex.com/PHPExcel)
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
* @version 1.6.7, 2009-04-22 * @version 1.7.0, 2009-08-10
*/ */
/** /**

View File

@@ -22,7 +22,7 @@
* @package PHPExcel_Shared_Escher * @package PHPExcel_Shared_Escher
* @copyright Copyright (c) 2006 - 2009 PHPExcel (http://www.codeplex.com/PHPExcel) * @copyright Copyright (c) 2006 - 2009 PHPExcel (http://www.codeplex.com/PHPExcel)
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
* @version 1.6.7, 2009-04-22 * @version 1.7.0, 2009-08-10
*/ */
/** /**

View File

@@ -16,42 +16,45 @@
* @version 1.2 * @version 1.2
*/ */
class CholeskyDecomposition { class CholeskyDecomposition {
/** /**
* Decomposition storage * Decomposition storage
* @var array * @var array
* @access private * @access private
*/ */
var $L = array(); private $L = array();
/** /**
* Matrix row and column dimension * Matrix row and column dimension
* @var int * @var int
* @access private * @access private
*/ */
var $m; private $m;
/** /**
* Symmetric positive definite flag * Symmetric positive definite flag
* @var boolean * @var boolean
* @access private * @access private
*/ */
var $isspd = true; private $isspd = true;
/** /**
* CholeskyDecomposition * CholeskyDecomposition
*
* Class constructor - decomposes symmetric positive definite matrix * Class constructor - decomposes symmetric positive definite matrix
* @param mixed Matrix square symmetric positive definite matrix * @param mixed Matrix square symmetric positive definite matrix
*/ */
function CholeskyDecomposition( $A = null ) { public function __construct($A = null) {
if( is_a($A, 'Matrix') ) { if ($A instanceof Matrix) {
$this->L = $A->getArray(); $this->L = $A->getArray();
$this->m = $A->getRowDimension(); $this->m = $A->getRowDimension();
for( $i = 0; $i < $this->m; $i++ ) { for($i = 0; $i < $this->m; ++$i) {
for( $j = $i; $j < $this->m; $j++ ) { for($j = $i; $j < $this->m; ++$j) {
for( $sum = $this->L[$i][$j], $k = $i - 1; $k >= 0; $k-- ) for($sum = $this->L[$i][$j], $k = $i - 1; $k >= 0; --$k) {
$sum -= $this->L[$i][$k] * $this->L[$j][$k]; $sum -= $this->L[$i][$k] * $this->L[$j][$k];
}
if ($i == $j) { if ($i == $j) {
if ($sum >= 0) { if ($sum >= 0) {
$this->L[$i][$i] = sqrt($sum); $this->L[$i][$i] = sqrt($sum);
@@ -59,75 +62,88 @@ class CholeskyDecomposition {
$this->isspd = false; $this->isspd = false;
} }
} else { } else {
if( $this->L[$i][$i] != 0 ) if ($this->L[$i][$i] != 0) {
$this->L[$j][$i] = $sum / $this->L[$i][$i]; $this->L[$j][$i] = $sum / $this->L[$i][$i];
} }
} }
}
for ($k = $i+1; $k < $this->m; $k++) for ($k = $i+1; $k < $this->m; ++$k) {
$this->L[$i][$k] = 0.0; $this->L[$i][$k] = 0.0;
} }
}
} else { } else {
trigger_error(ArgumentTypeException, ERROR); throw new Exception(JAMAError(ArgumentTypeException));
}
} }
} // function __construct()
/** /**
* Is the matrix symmetric and positive definite? * Is the matrix symmetric and positive definite?
*
* @return boolean * @return boolean
*/ */
function isSPD () { public function isSPD() {
return $this->isspd; return $this->isspd;
} } // function isSPD()
/** /**
* getL * getL
*
* Return triangular factor. * Return triangular factor.
* @return Matrix Lower triangular matrix * @return Matrix Lower triangular matrix
*/ */
function getL () { public function getL() {
return new Matrix($this->L); return new Matrix($this->L);
} } // function getL()
/** /**
* Solve A*X = B * Solve A*X = B
*
* @param $B Row-equal matrix * @param $B Row-equal matrix
* @return Matrix L * L' * X = B * @return Matrix L * L' * X = B
*/ */
function solve ( $B = null ) { public function solve($B = null) {
if( is_a($B, 'Matrix') ) { if ($B instanceof Matrix) {
if ($B->getRowDimension() == $this->m) { if ($B->getRowDimension() == $this->m) {
if ($this->isspd) { if ($this->isspd) {
$X = $B->getArrayCopy(); $X = $B->getArrayCopy();
$nx = $B->getColumnDimension(); $nx = $B->getColumnDimension();
for ($k = 0; $k < $this->m; $k++) { for ($k = 0; $k < $this->m; ++$k) {
for ($i = $k + 1; $i < $this->m; $i++) for ($i = $k + 1; $i < $this->m; ++$i) {
for ($j = 0; $j < $nx; $j++) for ($j = 0; $j < $nx; ++$j) {
$X[$i][$j] -= $X[$k][$j] * $this->L[$i][$k]; $X[$i][$j] -= $X[$k][$j] * $this->L[$i][$k];
}
for ($j = 0; $j < $nx; $j++) }
for ($j = 0; $j < $nx; ++$j) {
$X[$k][$j] /= $this->L[$k][$k]; $X[$k][$j] /= $this->L[$k][$k];
} }
}
for ($k = $this->m - 1; $k >= 0; $k--) { for ($k = $this->m - 1; $k >= 0; --$k) {
for ($j = 0; $j < $nx; $j++) for ($j = 0; $j < $nx; ++$j) {
$X[$k][$j] /= $this->L[$k][$k]; $X[$k][$j] /= $this->L[$k][$k];
}
for ($i = 0; $i < $k; $i++) for ($i = 0; $i < $k; ++$i) {
for ($j = 0; $j < $nx; $j++) for ($j = 0; $j < $nx; ++$j) {
$X[$i][$j] -= $X[$k][$j] * $this->L[$k][$i]; $X[$i][$j] -= $X[$k][$j] * $this->L[$k][$i];
} }
}
}
return new Matrix($X, $this->m, $nx); return new Matrix($X, $this->m, $nx);
} else { } else {
trigger_error(MatrixSPDException, ERROR); throw new Exception(JAMAError(MatrixSPDException));
} }
} else { } else {
trigger_error(MatrixDimensionException, ERROR); throw new Exception(JAMAError(MatrixDimensionException));
} }
} else { } else {
trigger_error(ArgumentTypeException, ERROR); throw new Exception(JAMAError(ArgumentTypeException));
}
}
} }
} // function solve()
} // class CholeskyDecomposition

View File

@@ -27,59 +27,60 @@ class EigenvalueDecomposition {
* Row and column dimension (square matrix). * Row and column dimension (square matrix).
* @var int * @var int
*/ */
var $n; private $n;
/** /**
* Internal symmetry flag. * Internal symmetry flag.
* @var int * @var int
*/ */
var $issymmetric; private $issymmetric;
/** /**
* Arrays for internal storage of eigenvalues. * Arrays for internal storage of eigenvalues.
* @var array * @var array
*/ */
var $d = array(); private $d = array();
var $e = array(); private $e = array();
/** /**
* Array for internal storage of eigenvectors. * Array for internal storage of eigenvectors.
* @var array * @var array
*/ */
var $V = array(); private $V = array();
/** /**
* Array for internal storage of nonsymmetric Hessenberg form. * Array for internal storage of nonsymmetric Hessenberg form.
* @var array * @var array
*/ */
var $H = array(); private $H = array();
/** /**
* Working storage for nonsymmetric algorithm. * Working storage for nonsymmetric algorithm.
* @var array * @var array
*/ */
var $ort; private $ort;
/** /**
* Used for complex scalar division. * Used for complex scalar division.
* @var float * @var float
*/ */
var $cdivr; private $cdivr;
var $cdivi; private $cdivi;
/** /**
* Symmetric Householder reduction to tridiagonal form. * Symmetric Householder reduction to tridiagonal form.
*
* @access private * @access private
*/ */
function tred2 () { private function tred2 () {
// This is derived from the Algol procedures tred2 by // This is derived from the Algol procedures tred2 by
// Bowdler, Martin, Reinsch, and Wilkinson, Handbook for // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
// Fortran subroutine in EISPACK. // Fortran subroutine in EISPACK.
$this->d = $this->V[$this->n-1]; $this->d = $this->V[$this->n-1];
// Householder reduction to tridiagonal form. // Householder reduction to tridiagonal form.
for ($i = $this->n-1; $i > 0; $i--) { for ($i = $this->n-1; $i > 0; --$i) {
$i_ = $i -1; $i_ = $i -1;
// Scale to avoid under/overflow. // Scale to avoid under/overflow.
$h = $scale = 0.0; $h = $scale = 0.0;
@@ -87,73 +88,82 @@ class EigenvalueDecomposition {
if ($scale == 0.0) { if ($scale == 0.0) {
$this->e[$i] = $this->d[$i_]; $this->e[$i] = $this->d[$i_];
$this->d = array_slice($this->V[$i_], 0, $i_); $this->d = array_slice($this->V[$i_], 0, $i_);
for ($j = 0; $j < $i; $j++) { for ($j = 0; $j < $i; ++$j) {
$this->V[$j][$i] = $this->V[$i][$j] = 0.0; $this->V[$j][$i] = $this->V[$i][$j] = 0.0;
} }
} else { } else {
// Generate Householder vector. // Generate Householder vector.
for ($k = 0; $k < $i; $k++) { for ($k = 0; $k < $i; ++$k) {
$this->d[$k] /= $scale; $this->d[$k] /= $scale;
$h += pow($this->d[$k], 2); $h += pow($this->d[$k], 2);
} }
$f = $this->d[$i_]; $f = $this->d[$i_];
$g = sqrt($h); $g = sqrt($h);
if ($f > 0) if ($f > 0) {
$g = -$g; $g = -$g;
}
$this->e[$i] = $scale * $g; $this->e[$i] = $scale * $g;
$h = $h - $f * $g; $h = $h - $f * $g;
$this->d[$i_] = $f - $g; $this->d[$i_] = $f - $g;
for ($j = 0; $j < $i; $j++) for ($j = 0; $j < $i; ++$j) {
$this->e[$j] = 0.0; $this->e[$j] = 0.0;
}
// Apply similarity transformation to remaining columns. // Apply similarity transformation to remaining columns.
for ($j = 0; $j < $i; $j++) { for ($j = 0; $j < $i; ++$j) {
$f = $this->d[$j]; $f = $this->d[$j];
$this->V[$j][$i] = $f; $this->V[$j][$i] = $f;
$g = $this->e[$j] + $this->V[$j][$j] * $f; $g = $this->e[$j] + $this->V[$j][$j] * $f;
for ($k = $j+1; $k <= $i_; $k++) { for ($k = $j+1; $k <= $i_; ++$k) {
$g += $this->V[$k][$j] * $this->d[$k]; $g += $this->V[$k][$j] * $this->d[$k];
$this->e[$k] += $this->V[$k][$j] * $f; $this->e[$k] += $this->V[$k][$j] * $f;
} }
$this->e[$j] = $g; $this->e[$j] = $g;
} }
$f = 0.0; $f = 0.0;
for ($j = 0; $j < $i; $j++) { for ($j = 0; $j < $i; ++$j) {
$this->e[$j] /= $h; $this->e[$j] /= $h;
$f += $this->e[$j] * $this->d[$j]; $f += $this->e[$j] * $this->d[$j];
} }
$hh = $f / (2 * $h); $hh = $f / (2 * $h);
for ($j=0; $j < $i; $j++) for ($j=0; $j < $i; ++$j) {
$this->e[$j] -= $hh * $this->d[$j]; $this->e[$j] -= $hh * $this->d[$j];
for ($j = 0; $j < $i; $j++) { }
for ($j = 0; $j < $i; ++$j) {
$f = $this->d[$j]; $f = $this->d[$j];
$g = $this->e[$j]; $g = $this->e[$j];
for ($k = $j; $k <= $i_; $k++) for ($k = $j; $k <= $i_; ++$k) {
$this->V[$k][$j] -= ($f * $this->e[$k] + $g * $this->d[$k]); $this->V[$k][$j] -= ($f * $this->e[$k] + $g * $this->d[$k]);
}
$this->d[$j] = $this->V[$i-1][$j]; $this->d[$j] = $this->V[$i-1][$j];
$this->V[$i][$j] = 0.0; $this->V[$i][$j] = 0.0;
} }
} }
$this->d[$i] = $h; $this->d[$i] = $h;
} }
// Accumulate transformations. // Accumulate transformations.
for ($i = 0; $i < $this->n-1; $i++) { for ($i = 0; $i < $this->n-1; ++$i) {
$this->V[$this->n-1][$i] = $this->V[$i][$i]; $this->V[$this->n-1][$i] = $this->V[$i][$i];
$this->V[$i][$i] = 1.0; $this->V[$i][$i] = 1.0;
$h = $this->d[$i+1]; $h = $this->d[$i+1];
if ($h != 0.0) { if ($h != 0.0) {
for ($k = 0; $k <= $i; $k++) for ($k = 0; $k <= $i; ++$k) {
$this->d[$k] = $this->V[$k][$i+1] / $h; $this->d[$k] = $this->V[$k][$i+1] / $h;
for ($j = 0; $j <= $i; $j++) { }
for ($j = 0; $j <= $i; ++$j) {
$g = 0.0; $g = 0.0;
for ($k = 0; $k <= $i; $k++) for ($k = 0; $k <= $i; ++$k) {
$g += $this->V[$k][$i+1] * $this->V[$k][$j]; $g += $this->V[$k][$i+1] * $this->V[$k][$j];
for ($k = 0; $k <= $i; $k++) }
for ($k = 0; $k <= $i; ++$k) {
$this->V[$k][$j] -= $g * $this->d[$k]; $this->V[$k][$j] -= $g * $this->d[$k];
} }
} }
for ($k = 0; $k <= $i; $k++) }
for ($k = 0; $k <= $i; ++$k) {
$this->V[$k][$i+1] = 0.0; $this->V[$k][$i+1] = 0.0;
} }
}
$this->d = $this->V[$this->n-1]; $this->d = $this->V[$this->n-1];
$this->V[$this->n-1] = array_fill(0, $j, 0.0); $this->V[$this->n-1] = array_fill(0, $j, 0.0);
@@ -161,6 +171,7 @@ class EigenvalueDecomposition {
$this->e[0] = 0.0; $this->e[0] = 0.0;
} }
/** /**
* Symmetric tridiagonal QL algorithm. * Symmetric tridiagonal QL algorithm.
* *
@@ -171,21 +182,23 @@ class EigenvalueDecomposition {
* *
* @access private * @access private
*/ */
function tql2 () { private function tql2() {
for ($i = 1; $i < $this->n; $i++) for ($i = 1; $i < $this->n; ++$i) {
$this->e[$i-1] = $this->e[$i]; $this->e[$i-1] = $this->e[$i];
}
$this->e[$this->n-1] = 0.0; $this->e[$this->n-1] = 0.0;
$f = 0.0; $f = 0.0;
$tst1 = 0.0; $tst1 = 0.0;
$eps = pow(2.0,-52.0); $eps = pow(2.0,-52.0);
for ($l = 0; $l < $this->n; $l++) {
for ($l = 0; $l < $this->n; ++$l) {
// Find small subdiagonal element // Find small subdiagonal element
$tst1 = max($tst1, abs($this->d[$l]) + abs($this->e[$l])); $tst1 = max($tst1, abs($this->d[$l]) + abs($this->e[$l]));
$m = $l; $m = $l;
while ($m < $this->n) { while ($m < $this->n) {
if (abs($this->e[$m]) <= $eps * $tst1) if (abs($this->e[$m]) <= $eps * $tst1)
break; break;
$m++; ++$m;
} }
// If m == l, $this->d[l] is an eigenvalue, // If m == l, $this->d[l] is an eigenvalue,
// otherwise, iterate. // otherwise, iterate.
@@ -204,7 +217,7 @@ class EigenvalueDecomposition {
$this->d[$l+1] = $this->e[$l] * ($p + $r); $this->d[$l+1] = $this->e[$l] * ($p + $r);
$dl1 = $this->d[$l+1]; $dl1 = $this->d[$l+1];
$h = $g - $this->d[$l]; $h = $g - $this->d[$l];
for ($i = $l + 2; $i < $this->n; $i++) for ($i = $l + 2; $i < $this->n; ++$i)
$this->d[$i] -= $h; $this->d[$i] -= $h;
$f += $h; $f += $h;
// Implicit QL transformation. // Implicit QL transformation.
@@ -213,7 +226,7 @@ class EigenvalueDecomposition {
$c2 = $c3 = $c; $c2 = $c3 = $c;
$el1 = $this->e[$l + 1]; $el1 = $this->e[$l + 1];
$s = $s2 = 0.0; $s = $s2 = 0.0;
for ($i = $m-1; $i >= $l; $i--) { for ($i = $m-1; $i >= $l; --$i) {
$c3 = $c2; $c3 = $c2;
$c2 = $c; $c2 = $c;
$s2 = $s; $s2 = $s;
@@ -226,7 +239,7 @@ class EigenvalueDecomposition {
$p = $c * $this->d[$i] - $s * $g; $p = $c * $this->d[$i] - $s * $g;
$this->d[$i+1] = $h + $s * ($c * $g + $s * $this->d[$i]); $this->d[$i+1] = $h + $s * ($c * $g + $s * $this->d[$i]);
// Accumulate transformation. // Accumulate transformation.
for ($k = 0; $k < $this->n; $k++) { for ($k = 0; $k < $this->n; ++$k) {
$h = $this->V[$k][$i+1]; $h = $this->V[$k][$i+1];
$this->V[$k][$i+1] = $s * $this->V[$k][$i] + $c * $h; $this->V[$k][$i+1] = $s * $this->V[$k][$i] + $c * $h;
$this->V[$k][$i] = $c * $this->V[$k][$i] - $s * $h; $this->V[$k][$i] = $c * $this->V[$k][$i] - $s * $h;
@@ -241,11 +254,12 @@ class EigenvalueDecomposition {
$this->d[$l] = $this->d[$l] + $f; $this->d[$l] = $this->d[$l] + $f;
$this->e[$l] = 0.0; $this->e[$l] = 0.0;
} }
// Sort eigenvalues and corresponding vectors. // Sort eigenvalues and corresponding vectors.
for ($i = 0; $i < $this->n - 1; $i++) { for ($i = 0; $i < $this->n - 1; ++$i) {
$k = $i; $k = $i;
$p = $this->d[$i]; $p = $this->d[$i];
for ($j = $i+1; $j < $this->n; $j++) { for ($j = $i+1; $j < $this->n; ++$j) {
if ($this->d[$j] < $p) { if ($this->d[$j] < $p) {
$k = $j; $k = $j;
$p = $this->d[$j]; $p = $this->d[$j];
@@ -254,7 +268,7 @@ class EigenvalueDecomposition {
if ($k != $i) { if ($k != $i) {
$this->d[$k] = $this->d[$i]; $this->d[$k] = $this->d[$i];
$this->d[$i] = $p; $this->d[$i] = $p;
for ($j = 0; $j < $this->n; $j++) { for ($j = 0; $j < $this->n; ++$j) {
$p = $this->V[$j][$i]; $p = $this->V[$j][$i];
$this->V[$j][$i] = $this->V[$j][$k]; $this->V[$j][$i] = $this->V[$j][$k];
$this->V[$j][$k] = $p; $this->V[$j][$k] = $p;
@@ -263,6 +277,7 @@ class EigenvalueDecomposition {
} }
} }
/** /**
* Nonsymmetric reduction to Hessenberg form. * Nonsymmetric reduction to Hessenberg form.
* *
@@ -273,74 +288,89 @@ class EigenvalueDecomposition {
* *
* @access private * @access private
*/ */
function orthes () { private function orthes () {
$low = 0; $low = 0;
$high = $this->n-1; $high = $this->n-1;
for ($m = $low+1; $m <= $high-1; $m++) {
for ($m = $low+1; $m <= $high-1; ++$m) {
// Scale column. // Scale column.
$scale = 0.0; $scale = 0.0;
for ($i = $m; $i <= $high; $i++) for ($i = $m; $i <= $high; ++$i) {
$scale = $scale + abs($this->H[$i][$m-1]); $scale = $scale + abs($this->H[$i][$m-1]);
}
if ($scale != 0.0) { if ($scale != 0.0) {
// Compute Householder transformation. // Compute Householder transformation.
$h = 0.0; $h = 0.0;
for ($i = $high; $i >= $m; $i--) { for ($i = $high; $i >= $m; --$i) {
$this->ort[$i] = $this->H[$i][$m-1] / $scale; $this->ort[$i] = $this->H[$i][$m-1] / $scale;
$h += $this->ort[$i] * $this->ort[$i]; $h += $this->ort[$i] * $this->ort[$i];
} }
$g = sqrt($h); $g = sqrt($h);
if ($this->ort[$m] > 0) if ($this->ort[$m] > 0) {
$g *= -1; $g *= -1;
}
$h -= $this->ort[$m] * $g; $h -= $this->ort[$m] * $g;
$this->ort[$m] -= $g; $this->ort[$m] -= $g;
// Apply Householder similarity transformation // Apply Householder similarity transformation
// H = (I -u * u' / h) * H * (I -u * u') / h) // H = (I -u * u' / h) * H * (I -u * u') / h)
for ($j = $m; $j < $this->n; $j++) { for ($j = $m; $j < $this->n; ++$j) {
$f = 0.0; $f = 0.0;
for ($i = $high; $i >= $m; $i--) for ($i = $high; $i >= $m; --$i) {
$f += $this->ort[$i] * $this->H[$i][$j]; $f += $this->ort[$i] * $this->H[$i][$j];
}
$f /= $h; $f /= $h;
for ($i = $m; $i <= $high; $i++) for ($i = $m; $i <= $high; ++$i) {
$this->H[$i][$j] -= $f * $this->ort[$i]; $this->H[$i][$j] -= $f * $this->ort[$i];
} }
for ($i = 0; $i <= $high; $i++) { }
for ($i = 0; $i <= $high; ++$i) {
$f = 0.0; $f = 0.0;
for ($j = $high; $j >= $m; $j--) for ($j = $high; $j >= $m; --$j) {
$f += $this->ort[$j] * $this->H[$i][$j]; $f += $this->ort[$j] * $this->H[$i][$j];
}
$f = $f / $h; $f = $f / $h;
for ($j = $m; $j <= $high; $j++) for ($j = $m; $j <= $high; ++$j) {
$this->H[$i][$j] -= $f * $this->ort[$j]; $this->H[$i][$j] -= $f * $this->ort[$j];
} }
}
$this->ort[$m] = $scale * $this->ort[$m]; $this->ort[$m] = $scale * $this->ort[$m];
$this->H[$m][$m-1] = $scale * $g; $this->H[$m][$m-1] = $scale * $g;
} }
} }
// Accumulate transformations (Algol's ortran). // Accumulate transformations (Algol's ortran).
for ($i = 0; $i < $this->n; $i++) for ($i = 0; $i < $this->n; ++$i) {
for ($j = 0; $j < $this->n; $j++) for ($j = 0; $j < $this->n; ++$j) {
$this->V[$i][$j] = ($i == $j ? 1.0 : 0.0); $this->V[$i][$j] = ($i == $j ? 1.0 : 0.0);
for ($m = $high-1; $m >= $low+1; $m--) { }
}
for ($m = $high-1; $m >= $low+1; --$m) {
if ($this->H[$m][$m-1] != 0.0) { if ($this->H[$m][$m-1] != 0.0) {
for ($i = $m+1; $i <= $high; $i++) for ($i = $m+1; $i <= $high; ++$i) {
$this->ort[$i] = $this->H[$i][$m-1]; $this->ort[$i] = $this->H[$i][$m-1];
for ($j = $m; $j <= $high; $j++) { }
for ($j = $m; $j <= $high; ++$j) {
$g = 0.0; $g = 0.0;
for ($i = $m; $i <= $high; $i++) for ($i = $m; $i <= $high; ++$i) {
$g += $this->ort[$i] * $this->V[$i][$j]; $g += $this->ort[$i] * $this->V[$i][$j];
}
// Double division avoids possible underflow // Double division avoids possible underflow
$g = ($g / $this->ort[$m]) / $this->H[$m][$m-1]; $g = ($g / $this->ort[$m]) / $this->H[$m][$m-1];
for ($i = $m; $i <= $high; $i++) for ($i = $m; $i <= $high; ++$i) {
$this->V[$i][$j] += $g * $this->ort[$i]; $this->V[$i][$j] += $g * $this->ort[$i];
} }
} }
} }
} }
}
/** /**
* Performs complex division. * Performs complex division.
*
* @access private * @access private
*/ */
function cdiv($xr, $xi, $yr, $yi) { private function cdiv($xr, $xi, $yr, $yi) {
if (abs($yr) > abs($yi)) { if (abs($yr) > abs($yi)) {
$r = $yi / $yr; $r = $yi / $yr;
$d = $yr + $r * $yi; $d = $yr + $r * $yi;
@@ -354,6 +384,7 @@ class EigenvalueDecomposition {
} }
} }
/** /**
* Nonsymmetric reduction from Hessenberg to real Schur form. * Nonsymmetric reduction from Hessenberg to real Schur form.
* *
@@ -364,7 +395,7 @@ class EigenvalueDecomposition {
* *
* @access private * @access private
*/ */
function hqr2 () { private function hqr2 () {
// Initialize // Initialize
$nn = $this->n; $nn = $this->n;
$n = $nn - 1; $n = $nn - 1;
@@ -375,14 +406,17 @@ class EigenvalueDecomposition {
$p = $q = $r = $s = $z = 0; $p = $q = $r = $s = $z = 0;
// Store roots isolated by balanc and compute matrix norm // Store roots isolated by balanc and compute matrix norm
$norm = 0.0; $norm = 0.0;
for ($i = 0; $i < $nn; $i++) {
for ($i = 0; $i < $nn; ++$i) {
if (($i < $low) OR ($i > $high)) { if (($i < $low) OR ($i > $high)) {
$this->d[$i] = $this->H[$i][$i]; $this->d[$i] = $this->H[$i][$i];
$this->e[$i] = 0.0; $this->e[$i] = 0.0;
} }
for ($j = max($i-1, 0); $j < $nn; $j++) for ($j = max($i-1, 0); $j < $nn; ++$j) {
$norm = $norm + abs($this->H[$i][$j]); $norm = $norm + abs($this->H[$i][$j]);
} }
}
// Outer loop over eigenvalue index // Outer loop over eigenvalue index
$iter = 0; $iter = 0;
while ($n >= $low) { while ($n >= $low) {
@@ -390,11 +424,13 @@ class EigenvalueDecomposition {
$l = $n; $l = $n;
while ($l > $low) { while ($l > $low) {
$s = abs($this->H[$l-1][$l-1]) + abs($this->H[$l][$l]); $s = abs($this->H[$l-1][$l-1]) + abs($this->H[$l][$l]);
if ($s == 0.0) if ($s == 0.0) {
$s = $norm; $s = $norm;
if (abs($this->H[$l][$l-1]) < $eps * $s) }
if (abs($this->H[$l][$l-1]) < $eps * $s) {
break; break;
$l--; }
--$l;
} }
// Check for convergence // Check for convergence
// One root found // One root found
@@ -402,7 +438,7 @@ class EigenvalueDecomposition {
$this->H[$n][$n] = $this->H[$n][$n] + $exshift; $this->H[$n][$n] = $this->H[$n][$n] + $exshift;
$this->d[$n] = $this->H[$n][$n]; $this->d[$n] = $this->H[$n][$n];
$this->e[$n] = 0.0; $this->e[$n] = 0.0;
$n--; --$n;
$iter = 0; $iter = 0;
// Two roots found // Two roots found
} else if ($l == $n-1) { } else if ($l == $n-1) {
@@ -415,14 +451,16 @@ class EigenvalueDecomposition {
$x = $this->H[$n][$n]; $x = $this->H[$n][$n];
// Real pair // Real pair
if ($q >= 0) { if ($q >= 0) {
if ($p >= 0) if ($p >= 0) {
$z = $p + $z; $z = $p + $z;
else } else {
$z = $p - $z; $z = $p - $z;
}
$this->d[$n-1] = $x + $z; $this->d[$n-1] = $x + $z;
$this->d[$n] = $this->d[$n-1]; $this->d[$n] = $this->d[$n-1];
if ($z != 0.0) if ($z != 0.0) {
$this->d[$n] = $x - $w / $z; $this->d[$n] = $x - $w / $z;
}
$this->e[$n-1] = 0.0; $this->e[$n-1] = 0.0;
$this->e[$n] = 0.0; $this->e[$n] = 0.0;
$x = $this->H[$n][$n-1]; $x = $this->H[$n][$n-1];
@@ -433,19 +471,19 @@ class EigenvalueDecomposition {
$p = $p / $r; $p = $p / $r;
$q = $q / $r; $q = $q / $r;
// Row modification // Row modification
for ($j = $n-1; $j < $nn; $j++) { for ($j = $n-1; $j < $nn; ++$j) {
$z = $this->H[$n-1][$j]; $z = $this->H[$n-1][$j];
$this->H[$n-1][$j] = $q * $z + $p * $this->H[$n][$j]; $this->H[$n-1][$j] = $q * $z + $p * $this->H[$n][$j];
$this->H[$n][$j] = $q * $this->H[$n][$j] - $p * $z; $this->H[$n][$j] = $q * $this->H[$n][$j] - $p * $z;
} }
// Column modification // Column modification
for ($i = 0; $i <= n; $i++) { for ($i = 0; $i <= n; ++$i) {
$z = $this->H[$i][$n-1]; $z = $this->H[$i][$n-1];
$this->H[$i][$n-1] = $q * $z + $p * $this->H[$i][$n]; $this->H[$i][$n-1] = $q * $z + $p * $this->H[$i][$n];
$this->H[$i][$n] = $q * $this->H[$i][$n] - $p * $z; $this->H[$i][$n] = $q * $this->H[$i][$n] - $p * $z;
} }
// Accumulate transformations // Accumulate transformations
for ($i = $low; $i <= $high; $i++) { for ($i = $low; $i <= $high; ++$i) {
$z = $this->V[$i][$n-1]; $z = $this->V[$i][$n-1];
$this->V[$i][$n-1] = $q * $z + $p * $this->V[$i][$n]; $this->V[$i][$n-1] = $q * $z + $p * $this->V[$i][$n];
$this->V[$i][$n] = $q * $this->V[$i][$n] - $p * $z; $this->V[$i][$n] = $q * $this->V[$i][$n] - $p * $z;
@@ -472,8 +510,9 @@ class EigenvalueDecomposition {
// Wilkinson's original ad hoc shift // Wilkinson's original ad hoc shift
if ($iter == 10) { if ($iter == 10) {
$exshift += $x; $exshift += $x;
for ($i = $low; $i <= $n; $i++) for ($i = $low; $i <= $n; ++$i) {
$this->H[$i][$i] -= $x; $this->H[$i][$i] -= $x;
}
$s = abs($this->H[$n][$n-1]) + abs($this->H[$n-1][$n-2]); $s = abs($this->H[$n][$n-1]) + abs($this->H[$n-1][$n-2]);
$x = $y = 0.75 * $s; $x = $y = 0.75 * $s;
$w = -0.4375 * $s * $s; $w = -0.4375 * $s * $s;
@@ -484,11 +523,13 @@ class EigenvalueDecomposition {
$s = $s * $s + $w; $s = $s * $s + $w;
if ($s > 0) { if ($s > 0) {
$s = sqrt($s); $s = sqrt($s);
if ($y < $x) if ($y < $x) {
$s = -$s; $s = -$s;
}
$s = $x - $w / (($y - $x) / 2.0 + $s); $s = $x - $w / (($y - $x) / 2.0 + $s);
for ($i = $low; $i <= $n; $i++) for ($i = $low; $i <= $n; ++$i) {
$this->H[$i][$i] -= $s; $this->H[$i][$i] -= $s;
}
$exshift += $s; $exshift += $s;
$x = $y = $w = 0.964; $x = $y = $w = 0.964;
} }
@@ -508,19 +549,23 @@ class EigenvalueDecomposition {
$p = $p / $s; $p = $p / $s;
$q = $q / $s; $q = $q / $s;
$r = $r / $s; $r = $r / $s;
if ($m == $l) if ($m == $l) {
break; break;
if (abs($this->H[$m][$m-1]) * (abs($q) + abs($r)) < $eps * (abs($p) * (abs($this->H[$m-1][$m-1]) + abs($z) + abs($this->H[$m+1][$m+1]))))
break;
$m--;
} }
for ($i = $m + 2; $i <= $n; $i++) { if (abs($this->H[$m][$m-1]) * (abs($q) + abs($r)) <
$eps * (abs($p) * (abs($this->H[$m-1][$m-1]) + abs($z) + abs($this->H[$m+1][$m+1])))) {
break;
}
--$m;
}
for ($i = $m + 2; $i <= $n; ++$i) {
$this->H[$i][$i-2] = 0.0; $this->H[$i][$i-2] = 0.0;
if ($i > $m+2) if ($i > $m+2) {
$this->H[$i][$i-3] = 0.0; $this->H[$i][$i-3] = 0.0;
} }
}
// Double QR step involving rows l:n and columns m:n // Double QR step involving rows l:n and columns m:n
for ($k = $m; $k <= $n-1; $k++) { for ($k = $m; $k <= $n-1; ++$k) {
$notlast = ($k != $n-1); $notlast = ($k != $n-1);
if ($k != $m) { if ($k != $m) {
$p = $this->H[$k][$k-1]; $p = $this->H[$k][$k-1];
@@ -533,16 +578,19 @@ class EigenvalueDecomposition {
$r = $r / $x; $r = $r / $x;
} }
} }
if ($x == 0.0) if ($x == 0.0) {
break; break;
}
$s = sqrt($p * $p + $q * $q + $r * $r); $s = sqrt($p * $p + $q * $q + $r * $r);
if ($p < 0) if ($p < 0) {
$s = -$s; $s = -$s;
}
if ($s != 0) { if ($s != 0) {
if ($k != $m) if ($k != $m) {
$this->H[$k][$k-1] = -$s * $x; $this->H[$k][$k-1] = -$s * $x;
else if ($l != $m) } elseif ($l != $m) {
$this->H[$k][$k-1] = -$this->H[$k][$k-1]; $this->H[$k][$k-1] = -$this->H[$k][$k-1];
}
$p = $p + $s; $p = $p + $s;
$x = $p / $s; $x = $p / $s;
$y = $q / $s; $y = $q / $s;
@@ -550,7 +598,7 @@ class EigenvalueDecomposition {
$q = $q / $p; $q = $q / $p;
$r = $r / $p; $r = $r / $p;
// Row modification // Row modification
for ($j = $k; $j < $nn; $j++) { for ($j = $k; $j < $nn; ++$j) {
$p = $this->H[$k][$j] + $q * $this->H[$k+1][$j]; $p = $this->H[$k][$j] + $q * $this->H[$k+1][$j];
if ($notlast) { if ($notlast) {
$p = $p + $r * $this->H[$k+2][$j]; $p = $p + $r * $this->H[$k+2][$j];
@@ -560,7 +608,7 @@ class EigenvalueDecomposition {
$this->H[$k+1][$j] = $this->H[$k+1][$j] - $p * $y; $this->H[$k+1][$j] = $this->H[$k+1][$j] - $p * $y;
} }
// Column modification // Column modification
for ($i = 0; $i <= min($n, $k+3); $i++) { for ($i = 0; $i <= min($n, $k+3); ++$i) {
$p = $x * $this->H[$i][$k] + $y * $this->H[$i][$k+1]; $p = $x * $this->H[$i][$k] + $y * $this->H[$i][$k+1];
if ($notlast) { if ($notlast) {
$p = $p + $z * $this->H[$i][$k+2]; $p = $p + $z * $this->H[$i][$k+2];
@@ -570,7 +618,7 @@ class EigenvalueDecomposition {
$this->H[$i][$k+1] = $this->H[$i][$k+1] - $p * $q; $this->H[$i][$k+1] = $this->H[$i][$k+1] - $p * $q;
} }
// Accumulate transformations // Accumulate transformations
for ($i = $low; $i <= $high; $i++) { for ($i = $low; $i <= $high; ++$i) {
$p = $x * $this->V[$i][$k] + $y * $this->V[$i][$k+1]; $p = $x * $this->V[$i][$k] + $y * $this->V[$i][$k+1];
if ($notlast) { if ($notlast) {
$p = $p + $z * $this->V[$i][$k+2]; $p = $p + $z * $this->V[$i][$k+2];
@@ -583,31 +631,36 @@ class EigenvalueDecomposition {
} // k loop } // k loop
} // check convergence } // check convergence
} // while ($n >= $low) } // while ($n >= $low)
// Backsubstitute to find vectors of upper triangular form // Backsubstitute to find vectors of upper triangular form
if ($norm == 0.0) if ($norm == 0.0) {
return; return;
for ($n = $nn-1; $n >= 0; $n--) { }
for ($n = $nn-1; $n >= 0; --$n) {
$p = $this->d[$n]; $p = $this->d[$n];
$q = $this->e[$n]; $q = $this->e[$n];
// Real vector // Real vector
if ($q == 0) { if ($q == 0) {
$l = $n; $l = $n;
$this->H[$n][$n] = 1.0; $this->H[$n][$n] = 1.0;
for ($i = $n-1; $i >= 0; $i--) { for ($i = $n-1; $i >= 0; --$i) {
$w = $this->H[$i][$i] - $p; $w = $this->H[$i][$i] - $p;
$r = 0.0; $r = 0.0;
for ($j = $l; $j <= $n; $j++) for ($j = $l; $j <= $n; ++$j) {
$r = $r + $this->H[$i][$j] * $this->H[$j][$n]; $r = $r + $this->H[$i][$j] * $this->H[$j][$n];
}
if ($this->e[$i] < 0.0) { if ($this->e[$i] < 0.0) {
$z = $w; $z = $w;
$s = $r; $s = $r;
} else { } else {
$l = $i; $l = $i;
if ($this->e[$i] == 0.0) { if ($this->e[$i] == 0.0) {
if ($w != 0.0) if ($w != 0.0) {
$this->H[$i][$n] = -$r / $w; $this->H[$i][$n] = -$r / $w;
else } else {
$this->H[$i][$n] = -$r / ($eps * $norm); $this->H[$i][$n] = -$r / ($eps * $norm);
}
// Solve real equations // Solve real equations
} else { } else {
$x = $this->H[$i][$i+1]; $x = $this->H[$i][$i+1];
@@ -615,19 +668,21 @@ class EigenvalueDecomposition {
$q = ($this->d[$i] - $p) * ($this->d[$i] - $p) + $this->e[$i] * $this->e[$i]; $q = ($this->d[$i] - $p) * ($this->d[$i] - $p) + $this->e[$i] * $this->e[$i];
$t = ($x * $s - $z * $r) / $q; $t = ($x * $s - $z * $r) / $q;
$this->H[$i][$n] = $t; $this->H[$i][$n] = $t;
if (abs($x) > abs($z)) if (abs($x) > abs($z)) {
$this->H[$i+1][$n] = (-$r - $w * $t) / $x; $this->H[$i+1][$n] = (-$r - $w * $t) / $x;
else } else {
$this->H[$i+1][$n] = (-$s - $y * $t) / $z; $this->H[$i+1][$n] = (-$s - $y * $t) / $z;
} }
}
// Overflow control // Overflow control
$t = abs($this->H[$i][$n]); $t = abs($this->H[$i][$n]);
if (($eps * $t) * $t > 1) { if (($eps * $t) * $t > 1) {
for ($j = $i; $j <= $n; $j++) for ($j = $i; $j <= $n; ++$j) {
$this->H[$j][$n] = $this->H[$j][$n] / $t; $this->H[$j][$n] = $this->H[$j][$n] / $t;
} }
} }
} }
}
// Complex vector // Complex vector
} else if ($q < 0) { } else if ($q < 0) {
$l = $n-1; $l = $n-1;
@@ -642,11 +697,11 @@ class EigenvalueDecomposition {
} }
$this->H[$n][$n-1] = 0.0; $this->H[$n][$n-1] = 0.0;
$this->H[$n][$n] = 1.0; $this->H[$n][$n] = 1.0;
for ($i = $n-2; $i >= 0; $i--) { for ($i = $n-2; $i >= 0; --$i) {
// double ra,sa,vr,vi; // double ra,sa,vr,vi;
$ra = 0.0; $ra = 0.0;
$sa = 0.0; $sa = 0.0;
for ($j = $l; $j <= $n; $j++) { for ($j = $l; $j <= $n; ++$j) {
$ra = $ra + $this->H[$i][$j] * $this->H[$j][$n-1]; $ra = $ra + $this->H[$i][$j] * $this->H[$j][$n-1];
$sa = $sa + $this->H[$i][$j] * $this->H[$j][$n]; $sa = $sa + $this->H[$i][$j] * $this->H[$j][$n];
} }
@@ -667,8 +722,9 @@ class EigenvalueDecomposition {
$y = $this->H[$i+1][$i]; $y = $this->H[$i+1][$i];
$vr = ($this->d[$i] - $p) * ($this->d[$i] - $p) + $this->e[$i] * $this->e[$i] - $q * $q; $vr = ($this->d[$i] - $p) * ($this->d[$i] - $p) + $this->e[$i] * $this->e[$i] - $q * $q;
$vi = ($this->d[$i] - $p) * 2.0 * $q; $vi = ($this->d[$i] - $p) * 2.0 * $q;
if ($vr == 0.0 & $vi == 0.0) if ($vr == 0.0 & $vi == 0.0) {
$vr = $eps * $norm * (abs($w) + abs($q) + abs($x) + abs($y) + abs($z)); $vr = $eps * $norm * (abs($w) + abs($q) + abs($x) + abs($y) + abs($z));
}
$this->cdiv($x * $r - $z * $ra + $q * $sa, $x * $s - $z * $sa - $q * $ra, $vr, $vi); $this->cdiv($x * $r - $z * $ra + $q * $sa, $x * $s - $z * $sa - $q * $ra, $vr, $vi);
$this->H[$i][$n-1] = $this->cdivr; $this->H[$i][$n-1] = $this->cdivr;
$this->H[$i][$n] = $this->cdivi; $this->H[$i][$n] = $this->cdivi;
@@ -684,7 +740,7 @@ class EigenvalueDecomposition {
// Overflow control // Overflow control
$t = max(abs($this->H[$i][$n-1]),abs($this->H[$i][$n])); $t = max(abs($this->H[$i][$n-1]),abs($this->H[$i][$n]));
if (($eps * $t) * $t > 1) { if (($eps * $t) * $t > 1) {
for ($j = $i; $j <= $n; $j++) { for ($j = $i; $j <= $n; ++$j) {
$this->H[$j][$n-1] = $this->H[$j][$n-1] / $t; $this->H[$j][$n-1] = $this->H[$j][$n-1] / $t;
$this->H[$j][$n] = $this->H[$j][$n] / $t; $this->H[$j][$n] = $this->H[$j][$n] / $t;
} }
@@ -693,40 +749,47 @@ class EigenvalueDecomposition {
} // end for } // end for
} // end else for complex case } // end else for complex case
} // end for } // end for
// Vectors of isolated roots // Vectors of isolated roots
for ($i = 0; $i < $nn; $i++) { for ($i = 0; $i < $nn; ++$i) {
if ($i < $low | $i > $high) { if ($i < $low | $i > $high) {
for ($j = $i; $j < $nn; $j++) for ($j = $i; $j < $nn; ++$j) {
$this->V[$i][$j] = $this->H[$i][$j]; $this->V[$i][$j] = $this->H[$i][$j];
} }
} }
}
// Back transformation to get eigenvectors of original matrix // Back transformation to get eigenvectors of original matrix
for ($j = $nn-1; $j >= $low; $j--) { for ($j = $nn-1; $j >= $low; --$j) {
for ($i = $low; $i <= $high; $i++) { for ($i = $low; $i <= $high; ++$i) {
$z = 0.0; $z = 0.0;
for ($k = $low; $k <= min($j,$high); $k++) for ($k = $low; $k <= min($j,$high); ++$k) {
$z = $z + $this->V[$i][$k] * $this->H[$k][$j]; $z = $z + $this->V[$i][$k] * $this->H[$k][$j];
}
$this->V[$i][$j] = $z; $this->V[$i][$j] = $z;
} }
} }
} // end hqr2 } // end hqr2
/** /**
* Constructor: Check for symmetry, then construct the eigenvalue decomposition * Constructor: Check for symmetry, then construct the eigenvalue decomposition
*
* @access public * @access public
* @param A Square matrix * @param A Square matrix
* @return Structure to access D and V. * @return Structure to access D and V.
*/ */
function EigenvalueDecomposition($Arg) { public function __construct($Arg) {
$this->A = $Arg->getArray(); $this->A = $Arg->getArray();
$this->n = $Arg->getColumnDimension(); $this->n = $Arg->getColumnDimension();
$this->V = array();
$this->d = array();
$this->e = array();
$issymmetric = true; $issymmetric = true;
for ($j = 0; ($j < $this->n) & $issymmetric; $j++) for ($j = 0; ($j < $this->n) & $issymmetric; ++$j) {
for ($i = 0; ($i < $this->n) & $issymmetric; $i++) for ($i = 0; ($i < $this->n) & $issymmetric; ++$i) {
$issymmetric = ($this->A[$i][$j] == $this->A[$j][$i]); $issymmetric = ($this->A[$i][$j] == $this->A[$j][$i]);
}
}
if ($issymmetric) { if ($issymmetric) {
$this->V = $this->A; $this->V = $this->A;
// Tridiagonalize. // Tridiagonalize.
@@ -743,47 +806,57 @@ class EigenvalueDecomposition {
} }
} }
/** /**
* Return the eigenvector matrix * Return the eigenvector matrix
*
* @access public * @access public
* @return V * @return V
*/ */
function getV() { public function getV() {
return new Matrix($this->V, $this->n, $this->n); return new Matrix($this->V, $this->n, $this->n);
} }
/** /**
* Return the real parts of the eigenvalues * Return the real parts of the eigenvalues
*
* @access public * @access public
* @return real(diag(D)) * @return real(diag(D))
*/ */
function getRealEigenvalues() { public function getRealEigenvalues() {
return $this->d; return $this->d;
} }
/** /**
* Return the imaginary parts of the eigenvalues * Return the imaginary parts of the eigenvalues
*
* @access public * @access public
* @return imag(diag(D)) * @return imag(diag(D))
*/ */
function getImagEigenvalues() { public function getImagEigenvalues() {
return $this->e; return $this->e;
} }
/** /**
* Return the block diagonal eigenvalue matrix * Return the block diagonal eigenvalue matrix
*
* @access public * @access public
* @return D * @return D
*/ */
function getD() { public function getD() {
for ($i = 0; $i < $this->n; $i++) { for ($i = 0; $i < $this->n; ++$i) {
$D[$i] = array_fill(0, $this->n, 0.0); $D[$i] = array_fill(0, $this->n, 0.0);
$D[$i][$i] = $this->d[$i]; $D[$i][$i] = $this->d[$i];
if ($this->e[$i] == 0) if ($this->e[$i] == 0) {
continue; continue;
}
$o = ($this->e[$i] > 0) ? $i + 1 : $i - 1; $o = ($this->e[$i] > 0) ? $i + 1 : $i - 1;
$D[$i][$o] = $this->e[$i]; $D[$i][$o] = $this->e[$i];
} }
return new Matrix($D); return new Matrix($D);
} }
}
} // class EigenvalueDecomposition

View File

@@ -19,75 +19,82 @@
* @license PHP v3.0 * @license PHP v3.0
*/ */
class LUDecomposition { class LUDecomposition {
/** /**
* Decomposition storage * Decomposition storage
* @var array * @var array
*/ */
var $LU = array(); private $LU = array();
/** /**
* Row dimension. * Row dimension.
* @var int * @var int
*/ */
var $m; private $m;
/** /**
* Column dimension. * Column dimension.
* @var int * @var int
*/ */
var $n; private $n;
/** /**
* Pivot sign. * Pivot sign.
* @var int * @var int
*/ */
var $pivsign; private $pivsign;
/** /**
* Internal storage of pivot vector. * Internal storage of pivot vector.
* @var array * @var array
*/ */
var $piv = array(); private $piv = array();
/** /**
* LU Decomposition constructor. * LU Decomposition constructor.
*
* @param $A Rectangular matrix * @param $A Rectangular matrix
* @return Structure to access L, U and piv. * @return Structure to access L, U and piv.
*/ */
function LUDecomposition ($A) { public function __construct($A) {
if( is_a($A, 'Matrix') ) { if ($A instanceof Matrix) {
// Use a "left-looking", dot-product, Crout/Doolittle algorithm. // Use a "left-looking", dot-product, Crout/Doolittle algorithm.
$this->LU = $A->getArrayCopy(); $this->LU = $A->getArrayCopy();
$this->m = $A->getRowDimension(); $this->m = $A->getRowDimension();
$this->n = $A->getColumnDimension(); $this->n = $A->getColumnDimension();
for ($i = 0; $i < $this->m; $i++) for ($i = 0; $i < $this->m; ++$i) {
$this->piv[$i] = $i; $this->piv[$i] = $i;
}
$this->pivsign = 1; $this->pivsign = 1;
$LUrowi = array(); $LUrowi = $LUcolj = array();
$LUcolj = array();
// Outer loop. // Outer loop.
for ($j = 0; $j < $this->n; $j++) { for ($j = 0; $j < $this->n; ++$j) {
// Make a copy of the j-th column to localize references. // Make a copy of the j-th column to localize references.
for ($i = 0; $i < $this->m; $i++) for ($i = 0; $i < $this->m; ++$i) {
$LUcolj[$i] = &$this->LU[$i][$j]; $LUcolj[$i] = &$this->LU[$i][$j];
}
// Apply previous transformations. // Apply previous transformations.
for ($i = 0; $i < $this->m; $i++) { for ($i = 0; $i < $this->m; ++$i) {
$LUrowi = $this->LU[$i]; $LUrowi = $this->LU[$i];
// Most of the time is spent in the following dot product. // Most of the time is spent in the following dot product.
$kmax = min($i,$j); $kmax = min($i,$j);
$s = 0.0; $s = 0.0;
for ($k = 0; $k < $kmax; $k++) for ($k = 0; $k < $kmax; ++$k) {
$s += $LUrowi[$k] * $LUcolj[$k]; $s += $LUrowi[$k] * $LUcolj[$k];
}
$LUrowi[$j] = $LUcolj[$i] -= $s; $LUrowi[$j] = $LUcolj[$i] -= $s;
} }
// Find pivot and exchange if necessary. // Find pivot and exchange if necessary.
$p = $j; $p = $j;
for ($i = $j+1; $i < $this->m; $i++) { for ($i = $j+1; $i < $this->m; ++$i) {
if (abs($LUcolj[$i]) > abs($LUcolj[$p])) if (abs($LUcolj[$i]) > abs($LUcolj[$p])) {
$p = $i; $p = $i;
} }
}
if ($p != $j) { if ($p != $j) {
for ($k = 0; $k < $this->n; $k++) { for ($k = 0; $k < $this->n; ++$k) {
$t = $this->LU[$p][$k]; $t = $this->LU[$p][$k];
$this->LU[$p][$k] = $this->LU[$j][$k]; $this->LU[$p][$k] = $this->LU[$j][$k];
$this->LU[$j][$k] = $t; $this->LU[$j][$k] = $t;
@@ -98,125 +105,151 @@ class LUDecomposition {
$this->pivsign = $this->pivsign * -1; $this->pivsign = $this->pivsign * -1;
} }
// Compute multipliers. // Compute multipliers.
if ( ($j < $this->m) AND ($this->LU[$j][$j] != 0.0) ) { if (($j < $this->m) && ($this->LU[$j][$j] != 0.0)) {
for ($i = $j+1; $i < $this->m; $i++) for ($i = $j+1; $i < $this->m; ++$i) {
$this->LU[$i][$j] /= $this->LU[$j][$j]; $this->LU[$i][$j] /= $this->LU[$j][$j];
} }
} }
}
} else { } else {
trigger_error(ArgumentTypeException, ERROR); throw new Exception(JAMAError(ArgumentTypeException));
}
} }
} // function __construct()
/** /**
* Get lower triangular factor. * Get lower triangular factor.
*
* @return array Lower triangular factor * @return array Lower triangular factor
*/ */
function getL () { public function getL() {
for ($i = 0; $i < $this->m; $i++) { for ($i = 0; $i < $this->m; ++$i) {
for ($j = 0; $j < $this->n; $j++) { for ($j = 0; $j < $this->n; ++$j) {
if ($i > $j) if ($i > $j) {
$L[$i][$j] = $this->LU[$i][$j]; $L[$i][$j] = $this->LU[$i][$j];
else if($i == $j) } elseif ($i == $j) {
$L[$i][$j] = 1.0; $L[$i][$j] = 1.0;
else } else {
$L[$i][$j] = 0.0; $L[$i][$j] = 0.0;
} }
} }
return new Matrix($L);
} }
return new Matrix($L);
} // function getL()
/** /**
* Get upper triangular factor. * Get upper triangular factor.
*
* @return array Upper triangular factor * @return array Upper triangular factor
*/ */
function getU () { public function getU() {
for ($i = 0; $i < $this->n; $i++) { for ($i = 0; $i < $this->n; ++$i) {
for ($j = 0; $j < $this->n; $j++) { for ($j = 0; $j < $this->n; ++$j) {
if ($i <= $j) if ($i <= $j) {
$U[$i][$j] = $this->LU[$i][$j]; $U[$i][$j] = $this->LU[$i][$j];
else } else {
$U[$i][$j] = 0.0; $U[$i][$j] = 0.0;
} }
} }
return new Matrix($U);
} }
return new Matrix($U);
} // function getU()
/** /**
* Return pivot permutation vector. * Return pivot permutation vector.
*
* @return array Pivot vector * @return array Pivot vector
*/ */
function getPivot () { public function getPivot() {
return $this->piv; return $this->piv;
} } // function getPivot()
/** /**
* Alias for getPivot * Alias for getPivot
*
* @see getPivot * @see getPivot
*/ */
function getDoublePivot () { public function getDoublePivot() {
return $this->getPivot(); return $this->getPivot();
} } // function getDoublePivot()
/** /**
* Is the matrix nonsingular? * Is the matrix nonsingular?
*
* @return true if U, and hence A, is nonsingular. * @return true if U, and hence A, is nonsingular.
*/ */
function isNonsingular () { public function isNonsingular() {
for ($j = 0; $j < $this->n; $j++) { for ($j = 0; $j < $this->n; ++$j) {
if ($this->LU[$j][$j] == 0) if ($this->LU[$j][$j] == 0) {
return false; return false;
} }
return true;
} }
return true;
} // function isNonsingular()
/** /**
* Count determinants * Count determinants
*
* @return array d matrix deterninat * @return array d matrix deterninat
*/ */
function det() { public function det() {
if ($this->m == $this->n) { if ($this->m == $this->n) {
$d = $this->pivsign; $d = $this->pivsign;
for ($j = 0; $j < $this->n; $j++) for ($j = 0; $j < $this->n; ++$j) {
$d *= $this->LU[$j][$j]; $d *= $this->LU[$j][$j];
}
return $d; return $d;
} else { } else {
trigger_error(MatrixDimensionException, ERROR); throw new Exception(JAMAError(MatrixDimensionException));
}
} }
} // function det()
/** /**
* Solve A*X = B * Solve A*X = B
*
* @param $B A Matrix with as many rows as A and any number of columns. * @param $B A Matrix with as many rows as A and any number of columns.
* @return X so that L*U*X = B(piv,:) * @return X so that L*U*X = B(piv,:)
* @exception IllegalArgumentException Matrix row dimensions must agree. * @exception IllegalArgumentException Matrix row dimensions must agree.
* @exception RuntimeException Matrix is singular. * @exception RuntimeException Matrix is singular.
*/ */
function solve($B) { public function solve($B) {
if ($B->getRowDimension() == $this->m) { if ($B->getRowDimension() == $this->m) {
if ($this->isNonsingular()) { if ($this->isNonsingular()) {
// Copy right hand side with pivoting // Copy right hand side with pivoting
$nx = $B->getColumnDimension(); $nx = $B->getColumnDimension();
$X = $B->getMatrix($this->piv, 0, $nx-1); $X = $B->getMatrix($this->piv, 0, $nx-1);
// Solve L*Y = B(piv,:) // Solve L*Y = B(piv,:)
for ($k = 0; $k < $this->n; $k++) for ($k = 0; $k < $this->n; ++$k) {
for ($i = $k+1; $i < $this->n; $i++) for ($i = $k+1; $i < $this->n; ++$i) {
for ($j = 0; $j < $nx; $j++) for ($j = 0; $j < $nx; ++$j) {
$X->A[$i][$j] -= $X->A[$k][$j] * $this->LU[$i][$k]; $X->A[$i][$j] -= $X->A[$k][$j] * $this->LU[$i][$k];
}
}
}
// Solve U*X = Y; // Solve U*X = Y;
for ($k = $this->n-1; $k >= 0; $k--) { for ($k = $this->n-1; $k >= 0; --$k) {
for ($j = 0; $j < $nx; $j++) for ($j = 0; $j < $nx; ++$j) {
$X->A[$k][$j] /= $this->LU[$k][$k]; $X->A[$k][$j] /= $this->LU[$k][$k];
for ($i = 0; $i < $k; $i++) }
for ($j = 0; $j < $nx; $j++) for ($i = 0; $i < $k; ++$i) {
for ($j = 0; $j < $nx; ++$j) {
$X->A[$i][$j] -= $X->A[$k][$j] * $this->LU[$i][$k]; $X->A[$i][$j] -= $X->A[$k][$j] * $this->LU[$i][$k];
} }
}
}
return $X; return $X;
} else { } else {
trigger_error(MatrixSingularException, ERROR); throw new Exception(JAMAError(MatrixSingularException));
} }
} else { } else {
trigger_error(MatrixSquareException, ERROR); throw new Exception(JAMAError(MatrixSquareException));
}
}
} }
} // function solve()
} // class LUDecomposition

File diff suppressed because it is too large Load Diff

View File

@@ -17,179 +17,216 @@
* @version 1.1 * @version 1.1
*/ */
class QRDecomposition { class QRDecomposition {
/** /**
* Array for internal storage of decomposition. * Array for internal storage of decomposition.
* @var array * @var array
*/ */
var $QR = array(); private $QR = array();
/** /**
* Row dimension. * Row dimension.
* @var integer * @var integer
*/ */
var $m; private $m;
/** /**
* Column dimension. * Column dimension.
* @var integer * @var integer
*/ */
var $n; private $n;
/** /**
* Array for internal storage of diagonal of R. * Array for internal storage of diagonal of R.
* @var array * @var array
*/ */
var $Rdiag = array(); private $Rdiag = array();
/** /**
* QR Decomposition computed by Householder reflections. * QR Decomposition computed by Householder reflections.
*
* @param matrix $A Rectangular matrix * @param matrix $A Rectangular matrix
* @return Structure to access R and the Householder vectors and compute Q. * @return Structure to access R and the Householder vectors and compute Q.
*/ */
function QRDecomposition($A) { public function __construct($A) {
if( is_a($A, 'Matrix') ) { if($A instanceof Matrix) {
// Initialize. // Initialize.
$this->QR = $A->getArrayCopy(); $this->QR = $A->getArrayCopy();
$this->m = $A->getRowDimension(); $this->m = $A->getRowDimension();
$this->n = $A->getColumnDimension(); $this->n = $A->getColumnDimension();
// Main loop. // Main loop.
for ($k = 0; $k < $this->n; $k++) { for ($k = 0; $k < $this->n; ++$k) {
// Compute 2-norm of k-th column without under/overflow. // Compute 2-norm of k-th column without under/overflow.
$nrm = 0.0; $nrm = 0.0;
for ($i = $k; $i < $this->m; $i++) for ($i = $k; $i < $this->m; ++$i) {
$nrm = hypo($nrm, $this->QR[$i][$k]); $nrm = hypo($nrm, $this->QR[$i][$k]);
}
if ($nrm != 0.0) { if ($nrm != 0.0) {
// Form k-th Householder vector. // Form k-th Householder vector.
if ($this->QR[$k][$k] < 0) if ($this->QR[$k][$k] < 0) {
$nrm = -$nrm; $nrm = -$nrm;
for ($i = $k; $i < $this->m; $i++) }
for ($i = $k; $i < $this->m; ++$i) {
$this->QR[$i][$k] /= $nrm; $this->QR[$i][$k] /= $nrm;
}
$this->QR[$k][$k] += 1.0; $this->QR[$k][$k] += 1.0;
// Apply transformation to remaining columns. // Apply transformation to remaining columns.
for ($j = $k+1; $j < $this->n; $j++) { for ($j = $k+1; $j < $this->n; ++$j) {
$s = 0.0; $s = 0.0;
for ($i = $k; $i < $this->m; $i++) for ($i = $k; $i < $this->m; ++$i) {
$s += $this->QR[$i][$k] * $this->QR[$i][$j]; $s += $this->QR[$i][$k] * $this->QR[$i][$j];
}
$s = -$s/$this->QR[$k][$k]; $s = -$s/$this->QR[$k][$k];
for ($i = $k; $i < $this->m; $i++) for ($i = $k; $i < $this->m; ++$i) {
$this->QR[$i][$j] += $s * $this->QR[$i][$k]; $this->QR[$i][$j] += $s * $this->QR[$i][$k];
} }
} }
}
$this->Rdiag[$k] = -$nrm; $this->Rdiag[$k] = -$nrm;
} }
} else } else {
trigger_error(ArgumentTypeException, ERROR); throw new Exception(JAMAError(ArgumentTypeException));
} }
} // function __construct()
/** /**
* Is the matrix full rank? * Is the matrix full rank?
*
* @return boolean true if R, and hence A, has full rank, else false. * @return boolean true if R, and hence A, has full rank, else false.
*/ */
function isFullRank() { public function isFullRank() {
for ($j = 0; $j < $this->n; $j++) for ($j = 0; $j < $this->n; ++$j) {
if ($this->Rdiag[$j] == 0) if ($this->Rdiag[$j] == 0) {
return false; return false;
return true;
} }
}
return true;
} // function isFullRank()
/** /**
* Return the Householder vectors * Return the Householder vectors
*
* @return Matrix Lower trapezoidal matrix whose columns define the reflections * @return Matrix Lower trapezoidal matrix whose columns define the reflections
*/ */
function getH() { public function getH() {
for ($i = 0; $i < $this->m; $i++) { for ($i = 0; $i < $this->m; ++$i) {
for ($j = 0; $j < $this->n; $j++) { for ($j = 0; $j < $this->n; ++$j) {
if ($i >= $j) if ($i >= $j) {
$H[$i][$j] = $this->QR[$i][$j]; $H[$i][$j] = $this->QR[$i][$j];
else } else {
$H[$i][$j] = 0.0; $H[$i][$j] = 0.0;
} }
} }
return new Matrix($H);
} }
return new Matrix($H);
} // function getH()
/** /**
* Return the upper triangular factor * Return the upper triangular factor
*
* @return Matrix upper triangular factor * @return Matrix upper triangular factor
*/ */
function getR() { public function getR() {
for ($i = 0; $i < $this->n; $i++) { for ($i = 0; $i < $this->n; ++$i) {
for ($j = 0; $j < $this->n; $j++) { for ($j = 0; $j < $this->n; ++$j) {
if ($i < $j) if ($i < $j) {
$R[$i][$j] = $this->QR[$i][$j]; $R[$i][$j] = $this->QR[$i][$j];
else if ($i == $j) } elseif ($i == $j) {
$R[$i][$j] = $this->Rdiag[$i]; $R[$i][$j] = $this->Rdiag[$i];
else } else {
$R[$i][$j] = 0.0; $R[$i][$j] = 0.0;
} }
} }
return new Matrix($R);
} }
return new Matrix($R);
} // function getR()
/** /**
* Generate and return the (economy-sized) orthogonal factor * Generate and return the (economy-sized) orthogonal factor
*
* @return Matrix orthogonal factor * @return Matrix orthogonal factor
*/ */
function getQ() { public function getQ() {
for ($k = $this->n-1; $k >= 0; $k--) { for ($k = $this->n-1; $k >= 0; --$k) {
for ($i = 0; $i < $this->m; $i++) for ($i = 0; $i < $this->m; ++$i) {
$Q[$i][$k] = 0.0; $Q[$i][$k] = 0.0;
}
$Q[$k][$k] = 1.0; $Q[$k][$k] = 1.0;
for ($j = $k; $j < $this->n; $j++) { for ($j = $k; $j < $this->n; ++$j) {
if ($this->QR[$k][$k] != 0) { if ($this->QR[$k][$k] != 0) {
$s = 0.0; $s = 0.0;
for ($i = $k; $i < $this->m; $i++) for ($i = $k; $i < $this->m; ++$i) {
$s += $this->QR[$i][$k] * $Q[$i][$j]; $s += $this->QR[$i][$k] * $Q[$i][$j];
}
$s = -$s/$this->QR[$k][$k]; $s = -$s/$this->QR[$k][$k];
for ($i = $k; $i < $this->m; $i++) for ($i = $k; $i < $this->m; ++$i) {
$Q[$i][$j] += $s * $this->QR[$i][$k]; $Q[$i][$j] += $s * $this->QR[$i][$k];
} }
} }
} }
}
/* /*
for( $i = 0; $i < count($Q); $i++ ) for($i = 0; $i < count($Q); ++$i) {
for( $j = 0; $j < count($Q); $j++ ) for($j = 0; $j < count($Q); ++$j) {
if(! isset($Q[$i][$j]) ) if(! isset($Q[$i][$j]) ) {
$Q[$i][$j] = 0; $Q[$i][$j] = 0;
}
}
}
*/ */
return new Matrix($Q); return new Matrix($Q);
} } // function getQ()
/** /**
* Least squares solution of A*X = B * Least squares solution of A*X = B
*
* @param Matrix $B A Matrix with as many rows as A and any number of columns. * @param Matrix $B A Matrix with as many rows as A and any number of columns.
* @return Matrix Matrix that minimizes the two norm of Q*R*X-B. * @return Matrix Matrix that minimizes the two norm of Q*R*X-B.
*/ */
function solve($B) { public function solve($B) {
if ($B->getRowDimension() == $this->m) { if ($B->getRowDimension() == $this->m) {
if ($this->isFullRank()) { if ($this->isFullRank()) {
// Copy right hand side // Copy right hand side
$nx = $B->getColumnDimension(); $nx = $B->getColumnDimension();
$X = $B->getArrayCopy(); $X = $B->getArrayCopy();
// Compute Y = transpose(Q)*B // Compute Y = transpose(Q)*B
for ($k = 0; $k < $this->n; $k++) { for ($k = 0; $k < $this->n; ++$k) {
for ($j = 0; $j < $nx; $j++) { for ($j = 0; $j < $nx; ++$j) {
$s = 0.0; $s = 0.0;
for ($i = $k; $i < $this->m; $i++) for ($i = $k; $i < $this->m; ++$i) {
$s += $this->QR[$i][$k] * $X[$i][$j]; $s += $this->QR[$i][$k] * $X[$i][$j];
}
$s = -$s/$this->QR[$k][$k]; $s = -$s/$this->QR[$k][$k];
for ($i = $k; $i < $this->m; $i++) for ($i = $k; $i < $this->m; ++$i) {
$X[$i][$j] += $s * $this->QR[$i][$k]; $X[$i][$j] += $s * $this->QR[$i][$k];
} }
} }
}
// Solve R*X = Y; // Solve R*X = Y;
for ($k = $this->n-1; $k >= 0; $k--) { for ($k = $this->n-1; $k >= 0; --$k) {
for ($j = 0; $j < $nx; $j++) for ($j = 0; $j < $nx; ++$j) {
$X[$k][$j] /= $this->Rdiag[$k]; $X[$k][$j] /= $this->Rdiag[$k];
for ($i = 0; $i < $k; $i++) }
for ($j = 0; $j < $nx; $j++) for ($i = 0; $i < $k; ++$i) {
for ($j = 0; $j < $nx; ++$j) {
$X[$i][$j] -= $X[$k][$j]* $this->QR[$i][$k]; $X[$i][$j] -= $X[$k][$j]* $this->QR[$i][$k];
} }
}
}
$X = new Matrix($X); $X = new Matrix($X);
return ($X->getMatrix(0, $this->n-1, 0, $nx)); return ($X->getMatrix(0, $this->n-1, 0, $nx));
} else } else {
trigger_error(MatrixRankException, ERROR); throw new Exception(JAMAError(MatrixRankException));
} else
trigger_error(MatrixDimensionException, ERROR);
} }
} else {
throw new Exception(JAMAError(MatrixDimensionException));
} }
} // function solve()
} // class QRDecomposition

View File

@@ -23,31 +23,32 @@ class SingularValueDecomposition {
* Internal storage of U. * Internal storage of U.
* @var array * @var array
*/ */
var $U = array(); private $U = array();
/** /**
* Internal storage of V. * Internal storage of V.
* @var array * @var array
*/ */
var $V = array(); private $V = array();
/** /**
* Internal storage of singular values. * Internal storage of singular values.
* @var array * @var array
*/ */
var $s = array(); private $s = array();
/** /**
* Row dimension. * Row dimension.
* @var int * @var int
*/ */
var $m; private $m;
/** /**
* Column dimension. * Column dimension.
* @var int * @var int
*/ */
var $n; private $n;
/** /**
* Construct the singular value decomposition * Construct the singular value decomposition
@@ -57,10 +58,9 @@ class SingularValueDecomposition {
* @param $A Rectangular matrix * @param $A Rectangular matrix
* @return Structure to access U, S and V. * @return Structure to access U, S and V.
*/ */
function SingularValueDecomposition ($Arg) { public function __construct($Arg) {
// Initialize. // Initialize.
$A = $Arg->getArrayCopy(); $A = $Arg->getArrayCopy();
$this->m = $Arg->getRowDimension(); $this->m = $Arg->getRowDimension();
$this->n = $Arg->getColumnDimension(); $this->n = $Arg->getColumnDimension();
@@ -74,35 +74,39 @@ class SingularValueDecomposition {
// Reduce A to bidiagonal form, storing the diagonal elements // Reduce A to bidiagonal form, storing the diagonal elements
// in s and the super-diagonal elements in e. // in s and the super-diagonal elements in e.
for ($k = 0; $k < max($nct,$nrt); ++$k) {
for ($k = 0; $k < max($nct,$nrt); $k++) {
if ($k < $nct) { if ($k < $nct) {
// Compute the transformation for the k-th column and // Compute the transformation for the k-th column and
// place the k-th diagonal in s[$k]. // place the k-th diagonal in s[$k].
// Compute 2-norm of k-th column without under/overflow. // Compute 2-norm of k-th column without under/overflow.
$this->s[$k] = 0; $this->s[$k] = 0;
for ($i = $k; $i < $this->m; $i++) for ($i = $k; $i < $this->m; ++$i) {
$this->s[$k] = hypo($this->s[$k], $A[$i][$k]); $this->s[$k] = hypo($this->s[$k], $A[$i][$k]);
}
if ($this->s[$k] != 0.0) { if ($this->s[$k] != 0.0) {
if ($A[$k][$k] < 0.0) if ($A[$k][$k] < 0.0) {
$this->s[$k] = -$this->s[$k]; $this->s[$k] = -$this->s[$k];
for ($i = $k; $i < $this->m; $i++) }
for ($i = $k; $i < $this->m; ++$i) {
$A[$i][$k] /= $this->s[$k]; $A[$i][$k] /= $this->s[$k];
}
$A[$k][$k] += 1.0; $A[$k][$k] += 1.0;
} }
$this->s[$k] = -$this->s[$k]; $this->s[$k] = -$this->s[$k];
} }
for ($j = $k + 1; $j < $this->n; $j++) { for ($j = $k + 1; $j < $this->n; ++$j) {
if (($k < $nct) & ($this->s[$k] != 0.0)) { if (($k < $nct) & ($this->s[$k] != 0.0)) {
// Apply the transformation. // Apply the transformation.
$t = 0; $t = 0;
for ($i = $k; $i < $this->m; $i++) for ($i = $k; $i < $this->m; ++$i) {
$t += $A[$i][$k] * $A[$i][$j]; $t += $A[$i][$k] * $A[$i][$j];
}
$t = -$t / $A[$k][$k]; $t = -$t / $A[$k][$k];
for ($i = $k; $i < $this->m; $i++) for ($i = $k; $i < $this->m; ++$i) {
$A[$i][$j] += $t * $A[$i][$k]; $A[$i][$j] += $t * $A[$i][$k];
}
// Place the k-th row of A into e for the // Place the k-th row of A into e for the
// subsequent calculation of the row transformation. // subsequent calculation of the row transformation.
$e[$j] = $A[$k][$j]; $e[$j] = $A[$k][$j];
@@ -112,81 +116,99 @@ class SingularValueDecomposition {
if ($wantu AND ($k < $nct)) { if ($wantu AND ($k < $nct)) {
// Place the transformation in U for subsequent back // Place the transformation in U for subsequent back
// multiplication. // multiplication.
for ($i = $k; $i < $this->m; $i++) for ($i = $k; $i < $this->m; ++$i) {
$this->U[$i][$k] = $A[$i][$k]; $this->U[$i][$k] = $A[$i][$k];
} }
}
if ($k < $nrt) { if ($k < $nrt) {
// Compute the k-th row transformation and place the // Compute the k-th row transformation and place the
// k-th super-diagonal in e[$k]. // k-th super-diagonal in e[$k].
// Compute 2-norm without under/overflow. // Compute 2-norm without under/overflow.
$e[$k] = 0; $e[$k] = 0;
for ($i = $k + 1; $i < $this->n; $i++) for ($i = $k + 1; $i < $this->n; ++$i) {
$e[$k] = hypo($e[$k], $e[$i]); $e[$k] = hypo($e[$k], $e[$i]);
}
if ($e[$k] != 0.0) { if ($e[$k] != 0.0) {
if ($e[$k+1] < 0.0) if ($e[$k+1] < 0.0) {
$e[$k] = -$e[$k]; $e[$k] = -$e[$k];
for ($i = $k + 1; $i < $this->n; $i++) }
for ($i = $k + 1; $i < $this->n; ++$i) {
$e[$i] /= $e[$k]; $e[$i] /= $e[$k];
}
$e[$k+1] += 1.0; $e[$k+1] += 1.0;
} }
$e[$k] = -$e[$k]; $e[$k] = -$e[$k];
if (($k+1 < $this->m) AND ($e[$k] != 0.0)) { if (($k+1 < $this->m) AND ($e[$k] != 0.0)) {
// Apply the transformation. // Apply the transformation.
for ($i = $k+1; $i < $this->m; $i++) for ($i = $k+1; $i < $this->m; ++$i) {
$work[$i] = 0.0; $work[$i] = 0.0;
for ($j = $k+1; $j < $this->n; $j++) }
for ($i = $k+1; $i < $this->m; $i++) for ($j = $k+1; $j < $this->n; ++$j) {
for ($i = $k+1; $i < $this->m; ++$i) {
$work[$i] += $e[$j] * $A[$i][$j]; $work[$i] += $e[$j] * $A[$i][$j];
for ($j = $k + 1; $j < $this->n; $j++) { }
}
for ($j = $k + 1; $j < $this->n; ++$j) {
$t = -$e[$j] / $e[$k+1]; $t = -$e[$j] / $e[$k+1];
for ($i = $k + 1; $i < $this->m; $i++) for ($i = $k + 1; $i < $this->m; ++$i) {
$A[$i][$j] += $t * $work[$i]; $A[$i][$j] += $t * $work[$i];
} }
} }
}
if ($wantv) { if ($wantv) {
// Place the transformation in V for subsequent // Place the transformation in V for subsequent
// back multiplication. // back multiplication.
for ($i = $k + 1; $i < $this->n; $i++) for ($i = $k + 1; $i < $this->n; ++$i) {
$this->V[$i][$k] = $e[$i]; $this->V[$i][$k] = $e[$i];
} }
} }
} }
}
// Set up the final bidiagonal matrix or order p. // Set up the final bidiagonal matrix or order p.
$p = min($this->n, $this->m + 1); $p = min($this->n, $this->m + 1);
if ($nct < $this->n) if ($nct < $this->n) {
$this->s[$nct] = $A[$nct][$nct]; $this->s[$nct] = $A[$nct][$nct];
if ($this->m < $p) }
if ($this->m < $p) {
$this->s[$p-1] = 0.0; $this->s[$p-1] = 0.0;
if ($nrt + 1 < $p) }
if ($nrt + 1 < $p) {
$e[$nrt] = $A[$nrt][$p-1]; $e[$nrt] = $A[$nrt][$p-1];
}
$e[$p-1] = 0.0; $e[$p-1] = 0.0;
// If required, generate U. // If required, generate U.
if ($wantu) { if ($wantu) {
for ($j = $nct; $j < $nu; $j++) { for ($j = $nct; $j < $nu; ++$j) {
for ($i = 0; $i < $this->m; $i++) for ($i = 0; $i < $this->m; ++$i) {
$this->U[$i][$j] = 0.0; $this->U[$i][$j] = 0.0;
}
$this->U[$j][$j] = 1.0; $this->U[$j][$j] = 1.0;
} }
for ($k = $nct - 1; $k >= 0; $k--) { for ($k = $nct - 1; $k >= 0; --$k) {
if ($this->s[$k] != 0.0) { if ($this->s[$k] != 0.0) {
for ($j = $k + 1; $j < $nu; $j++) { for ($j = $k + 1; $j < $nu; ++$j) {
$t = 0; $t = 0;
for ($i = $k; $i < $this->m; $i++) for ($i = $k; $i < $this->m; ++$i) {
$t += $this->U[$i][$k] * $this->U[$i][$j]; $t += $this->U[$i][$k] * $this->U[$i][$j];
}
$t = -$t / $this->U[$k][$k]; $t = -$t / $this->U[$k][$k];
for ($i = $k; $i < $this->m; $i++) for ($i = $k; $i < $this->m; ++$i) {
$this->U[$i][$j] += $t * $this->U[$i][$k]; $this->U[$i][$j] += $t * $this->U[$i][$k];
} }
for ($i = $k; $i < $this->m; $i++ ) }
for ($i = $k; $i < $this->m; ++$i ) {
$this->U[$i][$k] = -$this->U[$i][$k]; $this->U[$i][$k] = -$this->U[$i][$k];
}
$this->U[$k][$k] = 1.0 + $this->U[$k][$k]; $this->U[$k][$k] = 1.0 + $this->U[$k][$k];
for ($i = 0; $i < $k - 1; $i++) for ($i = 0; $i < $k - 1; ++$i) {
$this->U[$i][$k] = 0.0; $this->U[$i][$k] = 0.0;
}
} else { } else {
for ($i = 0; $i < $this->m; $i++) for ($i = 0; $i < $this->m; ++$i) {
$this->U[$i][$k] = 0.0; $this->U[$i][$k] = 0.0;
}
$this->U[$k][$k] = 1.0; $this->U[$k][$k] = 1.0;
} }
} }
@@ -194,19 +216,22 @@ class SingularValueDecomposition {
// If required, generate V. // If required, generate V.
if ($wantv) { if ($wantv) {
for ($k = $this->n - 1; $k >= 0; $k--) { for ($k = $this->n - 1; $k >= 0; --$k) {
if (($k < $nrt) AND ($e[$k] != 0.0)) { if (($k < $nrt) AND ($e[$k] != 0.0)) {
for ($j = $k + 1; $j < $nu; $j++) { for ($j = $k + 1; $j < $nu; ++$j) {
$t = 0; $t = 0;
for ($i = $k + 1; $i < $this->n; $i++) for ($i = $k + 1; $i < $this->n; ++$i) {
$t += $this->V[$i][$k]* $this->V[$i][$j]; $t += $this->V[$i][$k]* $this->V[$i][$j];
}
$t = -$t / $this->V[$k+1][$k]; $t = -$t / $this->V[$k+1][$k];
for ($i = $k + 1; $i < $this->n; $i++) for ($i = $k + 1; $i < $this->n; ++$i) {
$this->V[$i][$j] += $t * $this->V[$i][$k]; $this->V[$i][$j] += $t * $this->V[$i][$k];
} }
} }
for ($i = 0; $i < $this->n; $i++) }
for ($i = 0; $i < $this->n; ++$i) {
$this->V[$i][$k] = 0.0; $this->V[$i][$k] = 0.0;
}
$this->V[$k][$k] = 1.0; $this->V[$k][$k] = 1.0;
} }
} }
@@ -215,8 +240,8 @@ class SingularValueDecomposition {
$pp = $p - 1; $pp = $p - 1;
$iter = 0; $iter = 0;
$eps = pow(2.0, -52.0); $eps = pow(2.0, -52.0);
while ($p > 0) {
while ($p > 0) {
// Here is where a test for too many iterations would go. // Here is where a test for too many iterations would go.
// This section of the program inspects for negligible // This section of the program inspects for negligible
// elements in the s and e arrays. On completion the // elements in the s and e arrays. On completion the
@@ -226,37 +251,38 @@ class SingularValueDecomposition {
// kase = 3 if e[k-1] is negligible, k<p, and // kase = 3 if e[k-1] is negligible, k<p, and
// s(k), ..., s(p) are not negligible (qr step). // s(k), ..., s(p) are not negligible (qr step).
// kase = 4 if e(p-1) is negligible (convergence). // kase = 4 if e(p-1) is negligible (convergence).
for ($k = $p - 2; $k >= -1; --$k) {
for ($k = $p - 2; $k >= -1; $k--) { if ($k == -1) {
if ($k == -1)
break; break;
}
if (abs($e[$k]) <= $eps * (abs($this->s[$k]) + abs($this->s[$k+1]))) { if (abs($e[$k]) <= $eps * (abs($this->s[$k]) + abs($this->s[$k+1]))) {
$e[$k] = 0.0; $e[$k] = 0.0;
break; break;
} }
} }
if ($k == $p - 2) if ($k == $p - 2) {
$kase = 4; $kase = 4;
else { } else {
for ($ks = $p - 1; $ks >= $k; $ks--) { for ($ks = $p - 1; $ks >= $k; --$ks) {
if ($ks == $k) if ($ks == $k) {
break; break;
}
$t = ($ks != $p ? abs($e[$ks]) : 0.) + ($ks != $k + 1 ? abs($e[$ks-1]) : 0.); $t = ($ks != $p ? abs($e[$ks]) : 0.) + ($ks != $k + 1 ? abs($e[$ks-1]) : 0.);
if (abs($this->s[$ks]) <= $eps * $t) { if (abs($this->s[$ks]) <= $eps * $t) {
$this->s[$ks] = 0.0; $this->s[$ks] = 0.0;
break; break;
} }
} }
if ($ks == $k) if ($ks == $k) {
$kase = 3; $kase = 3;
else if ($ks == $p-1) } else if ($ks == $p-1) {
$kase = 1; $kase = 1;
else { } else {
$kase = 2; $kase = 2;
$k = $ks; $k = $ks;
} }
} }
$k++; ++$k;
// Perform the task indicated by kase. // Perform the task indicated by kase.
switch ($kase) { switch ($kase) {
@@ -264,7 +290,7 @@ class SingularValueDecomposition {
case 1: case 1:
$f = $e[$p-2]; $f = $e[$p-2];
$e[$p-2] = 0.0; $e[$p-2] = 0.0;
for ($j = $p - 2; $j >= $k; $j--) { for ($j = $p - 2; $j >= $k; --$j) {
$t = hypo($this->s[$j],$f); $t = hypo($this->s[$j],$f);
$cs = $this->s[$j] / $t; $cs = $this->s[$j] / $t;
$sn = $f / $t; $sn = $f / $t;
@@ -274,7 +300,7 @@ class SingularValueDecomposition {
$e[$j-1] = $cs * $e[$j-1]; $e[$j-1] = $cs * $e[$j-1];
} }
if ($wantv) { if ($wantv) {
for ($i = 0; $i < $this->n; $i++) { for ($i = 0; $i < $this->n; ++$i) {
$t = $cs * $this->V[$i][$j] + $sn * $this->V[$i][$p-1]; $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][$p-1] = -$sn * $this->V[$i][$j] + $cs * $this->V[$i][$p-1];
$this->V[$i][$j] = $t; $this->V[$i][$j] = $t;
@@ -286,7 +312,7 @@ class SingularValueDecomposition {
case 2: case 2:
$f = $e[$k-1]; $f = $e[$k-1];
$e[$k-1] = 0.0; $e[$k-1] = 0.0;
for ($j = $k; $j < $p; $j++) { for ($j = $k; $j < $p; ++$j) {
$t = hypo($this->s[$j], $f); $t = hypo($this->s[$j], $f);
$cs = $this->s[$j] / $t; $cs = $this->s[$j] / $t;
$sn = $f / $t; $sn = $f / $t;
@@ -294,7 +320,7 @@ class SingularValueDecomposition {
$f = -$sn * $e[$j]; $f = -$sn * $e[$j];
$e[$j] = $cs * $e[$j]; $e[$j] = $cs * $e[$j];
if ($wantu) { if ($wantu) {
for ($i = 0; $i < $this->m; $i++) { for ($i = 0; $i < $this->m; ++$i) {
$t = $cs * $this->U[$i][$j] + $sn * $this->U[$i][$k-1]; $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][$k-1] = -$sn * $this->U[$i][$j] + $cs * $this->U[$i][$k-1];
$this->U[$i][$j] = $t; $this->U[$i][$j] = $t;
@@ -318,25 +344,27 @@ class SingularValueDecomposition {
$shift = 0.0; $shift = 0.0;
if (($b != 0.0) || ($c != 0.0)) { if (($b != 0.0) || ($c != 0.0)) {
$shift = sqrt($b * $b + $c); $shift = sqrt($b * $b + $c);
if ($b < 0.0) if ($b < 0.0) {
$shift = -$shift; $shift = -$shift;
}
$shift = $c / ($b + $shift); $shift = $c / ($b + $shift);
} }
$f = ($sk + $sp) * ($sk - $sp) + $shift; $f = ($sk + $sp) * ($sk - $sp) + $shift;
$g = $sk * $ek; $g = $sk * $ek;
// Chase zeros. // Chase zeros.
for ($j = $k; $j < $p-1; $j++) { for ($j = $k; $j < $p-1; ++$j) {
$t = hypo($f,$g); $t = hypo($f,$g);
$cs = $f/$t; $cs = $f/$t;
$sn = $g/$t; $sn = $g/$t;
if ($j != $k) if ($j != $k) {
$e[$j-1] = $t; $e[$j-1] = $t;
}
$f = $cs * $this->s[$j] + $sn * $e[$j]; $f = $cs * $this->s[$j] + $sn * $e[$j];
$e[$j] = $cs * $e[$j] - $sn * $this->s[$j]; $e[$j] = $cs * $e[$j] - $sn * $this->s[$j];
$g = $sn * $this->s[$j+1]; $g = $sn * $this->s[$j+1];
$this->s[$j+1] = $cs * $this->s[$j+1]; $this->s[$j+1] = $cs * $this->s[$j+1];
if ($wantv) { if ($wantv) {
for ($i = 0; $i < $this->n; $i++) { for ($i = 0; $i < $this->n; ++$i) {
$t = $cs * $this->V[$i][$j] + $sn * $this->V[$i][$j+1]; $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+1] = -$sn * $this->V[$i][$j] + $cs * $this->V[$i][$j+1];
$this->V[$i][$j] = $t; $this->V[$i][$j] = $t;
@@ -351,7 +379,7 @@ class SingularValueDecomposition {
$g = $sn * $e[$j+1]; $g = $sn * $e[$j+1];
$e[$j+1] = $cs * $e[$j+1]; $e[$j+1] = $cs * $e[$j+1];
if ($wantu && ($j < $this->m - 1)) { if ($wantu && ($j < $this->m - 1)) {
for ($i = 0; $i < $this->m; $i++) { for ($i = 0; $i < $this->m; ++$i) {
$t = $cs * $this->U[$i][$j] + $sn * $this->U[$i][$j+1]; $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+1] = -$sn * $this->U[$i][$j] + $cs * $this->U[$i][$j+1];
$this->U[$i][$j] = $t; $this->U[$i][$j] = $t;
@@ -367,135 +395,132 @@ class SingularValueDecomposition {
if ($this->s[$k] <= 0.0) { if ($this->s[$k] <= 0.0) {
$this->s[$k] = ($this->s[$k] < 0.0 ? -$this->s[$k] : 0.0); $this->s[$k] = ($this->s[$k] < 0.0 ? -$this->s[$k] : 0.0);
if ($wantv) { if ($wantv) {
for ($i = 0; $i <= $pp; $i++) for ($i = 0; $i <= $pp; ++$i) {
$this->V[$i][$k] = -$this->V[$i][$k]; $this->V[$i][$k] = -$this->V[$i][$k];
} }
} }
}
// Order the singular values. // Order the singular values.
while ($k < $pp) { while ($k < $pp) {
if ($this->s[$k] >= $this->s[$k+1]) if ($this->s[$k] >= $this->s[$k+1]) {
break; break;
}
$t = $this->s[$k]; $t = $this->s[$k];
$this->s[$k] = $this->s[$k+1]; $this->s[$k] = $this->s[$k+1];
$this->s[$k+1] = $t; $this->s[$k+1] = $t;
if ($wantv AND ($k < $this->n - 1)) { if ($wantv AND ($k < $this->n - 1)) {
for ($i = 0; $i < $this->n; $i++) { for ($i = 0; $i < $this->n; ++$i) {
$t = $this->V[$i][$k+1]; $t = $this->V[$i][$k+1];
$this->V[$i][$k+1] = $this->V[$i][$k]; $this->V[$i][$k+1] = $this->V[$i][$k];
$this->V[$i][$k] = $t; $this->V[$i][$k] = $t;
} }
} }
if ($wantu AND ($k < $this->m-1)) { if ($wantu AND ($k < $this->m-1)) {
for ($i = 0; $i < $this->m; $i++) { for ($i = 0; $i < $this->m; ++$i) {
$t = $this->U[$i][$k+1]; $t = $this->U[$i][$k+1];
$this->U[$i][$k+1] = $this->U[$i][$k]; $this->U[$i][$k+1] = $this->U[$i][$k];
$this->U[$i][$k] = $t; $this->U[$i][$k] = $t;
} }
} }
$k++; ++$k;
} }
$iter = 0; $iter = 0;
$p--; --$p;
break; break;
} // end switch } // end switch
} // end while } // end while
/*
echo "<p>Output A</p>";
$A = new Matrix($A);
$A->toHTML();
echo "<p>Matrix U</p>";
echo "<pre>";
print_r($this->U);
echo "</pre>";
echo "<p>Matrix V</p>";
echo "<pre>";
print_r($this->V);
echo "</pre>";
echo "<p>Vector S</p>";
echo "<pre>";
print_r($this->s);
echo "</pre>";
exit;
*/
} // end constructor } // end constructor
/** /**
* Return the left singular vectors * Return the left singular vectors
*
* @access public * @access public
* @return U * @return U
*/ */
function getU() { public function getU() {
return new Matrix($this->U, $this->m, min($this->m + 1, $this->n)); return new Matrix($this->U, $this->m, min($this->m + 1, $this->n));
} }
/** /**
* Return the right singular vectors * Return the right singular vectors
*
* @access public * @access public
* @return V * @return V
*/ */
function getV() { public function getV() {
return new Matrix($this->V); return new Matrix($this->V);
} }
/** /**
* Return the one-dimensional array of singular values * Return the one-dimensional array of singular values
*
* @access public * @access public
* @return diagonal of S. * @return diagonal of S.
*/ */
function getSingularValues() { public function getSingularValues() {
return $this->s; return $this->s;
} }
/** /**
* Return the diagonal matrix of singular values * Return the diagonal matrix of singular values
*
* @access public * @access public
* @return S * @return S
*/ */
function getS() { public function getS() {
for ($i = 0; $i < $this->n; $i++) { for ($i = 0; $i < $this->n; ++$i) {
for ($j = 0; $j < $this->n; $j++) for ($j = 0; $j < $this->n; ++$j) {
$S[$i][$j] = 0.0; $S[$i][$j] = 0.0;
}
$S[$i][$i] = $this->s[$i]; $S[$i][$i] = $this->s[$i];
} }
return new Matrix($S); return new Matrix($S);
} }
/** /**
* Two norm * Two norm
*
* @access public * @access public
* @return max(S) * @return max(S)
*/ */
function norm2() { public function norm2() {
return $this->s[0]; return $this->s[0];
} }
/** /**
* Two norm condition number * Two norm condition number
*
* @access public * @access public
* @return max(S)/min(S) * @return max(S)/min(S)
*/ */
function cond() { public function cond() {
return $this->s[0] / $this->s[min($this->m, $this->n) - 1]; return $this->s[0] / $this->s[min($this->m, $this->n) - 1];
} }
/** /**
* Effective numerical matrix rank * Effective numerical matrix rank
*
* @access public * @access public
* @return Number of nonnegligible singular values. * @return Number of nonnegligible singular values.
*/ */
function rank() { public function rank() {
$eps = pow(2.0, -52.0); $eps = pow(2.0, -52.0);
$tol = max($this->m, $this->n) * $this->s[0] * $eps; $tol = max($this->m, $this->n) * $this->s[0] * $eps;
$r = 0; $r = 0;
for ($i = 0; $i < count($this->s); $i++) { for ($i = 0; $i < count($this->s); ++$i) {
if ($this->s[$i] > $tol) if ($this->s[$i] > $tol) {
$r++; ++$r;
}
} }
return $r; return $r;
} }
}
} // class SingularValueDecomposition

View File

@@ -8,113 +8,75 @@
*/ */
//Language constant //Language constant
define('LANG', 'EN'); define('JAMALANG', 'EN');
//Error type constants
define('ERROR', E_USER_ERROR);
define('WARNING', E_USER_WARNING);
define('NOTICE', E_USER_NOTICE);
//All errors may be defined by the following format: //All errors may be defined by the following format:
//define('ExceptionName', N); //define('ExceptionName', N);
//$error['lang'][N] = 'Error message'; //$error['lang'][ExceptionName] = 'Error message';
$error = array(); $error = array();
/* /*
I've used Babelfish and a little poor knowledge of Romance/Germanic languages for the translations I've used Babelfish and a little poor knowledge of Romance/Germanic languages for the translations here.
here. Feel free to correct anything that looks amiss to you. Feel free to correct anything that looks amiss to you.
*/ */
define('PolymorphicArgumentException', -1); define('PolymorphicArgumentException', -1);
$error['EN'][-1] = "Invalid argument pattern for polymorphic function."; $error['EN'][PolymorphicArgumentException] = "Invalid argument pattern for polymorphic function.";
$error['FR'][-1] = "Modèle inadmissible d'argument pour la fonction polymorphe.". $error['FR'][PolymorphicArgumentException] = "Modèle inadmissible d'argument pour la fonction polymorphe.".
$error['DE'][-1] = "Unzulässiges Argumentmuster für polymorphe Funktion."; $error['DE'][PolymorphicArgumentException] = "Unzulässiges Argumentmuster für polymorphe Funktion.";
define('ArgumentTypeException', -2); define('ArgumentTypeException', -2);
$error['EN'][-2] = "Invalid argument type."; $error['EN'][ArgumentTypeException] = "Invalid argument type.";
$error['FR'][-2] = "Type inadmissible d'argument."; $error['FR'][ArgumentTypeException] = "Type inadmissible d'argument.";
$error['DE'][-2] = "Unzulässige Argumentart."; $error['DE'][ArgumentTypeException] = "Unzulässige Argumentart.";
define('ArgumentBoundsException', -3); define('ArgumentBoundsException', -3);
$error['EN'][-3] = "Invalid argument range."; $error['EN'][ArgumentBoundsException] = "Invalid argument range.";
$error['FR'][-3] = "Gamme inadmissible d'argument."; $error['FR'][ArgumentBoundsException] = "Gamme inadmissible d'argument.";
$error['DE'][-3] = "Unzulässige Argumentstrecke."; $error['DE'][ArgumentBoundsException] = "Unzulässige Argumentstrecke.";
define('MatrixDimensionException', -4); define('MatrixDimensionException', -4);
$error['EN'][-4] = "Matrix dimensions are not equal."; $error['EN'][MatrixDimensionException] = "Matrix dimensions are not equal.";
$error['FR'][-4] = "Les dimensions de Matrix ne sont pas égales."; $error['FR'][MatrixDimensionException] = "Les dimensions de Matrix ne sont pas égales.";
$error['DE'][-4] = "Matrixmaße sind nicht gleich."; $error['DE'][MatrixDimensionException] = "Matrixmaße sind nicht gleich.";
define('PrecisionLossException', -5); define('PrecisionLossException', -5);
$error['EN'][-5] = "Significant precision loss detected."; $error['EN'][PrecisionLossException] = "Significant precision loss detected.";
$error['FR'][-5] = "Perte significative de précision détectée."; $error['FR'][PrecisionLossException] = "Perte significative de précision détectée.";
$error['DE'][-5] = "Bedeutender Präzision Verlust ermittelte."; $error['DE'][PrecisionLossException] = "Bedeutender Präzision Verlust ermittelte.";
define('MatrixSPDException', -6); define('MatrixSPDException', -6);
$error['EN'][-6] = "Can only perform operation on symmetric positive definite matrix."; $error['EN'][MatrixSPDException] = "Can only perform operation on symmetric positive definite matrix.";
$error['FR'][-6] = "Perte significative de précision détectée."; $error['FR'][MatrixSPDException] = "Perte significative de précision détectée.";
$error['DE'][-6] = "Bedeutender Präzision Verlust ermittelte."; $error['DE'][MatrixSPDException] = "Bedeutender Präzision Verlust ermittelte.";
define('MatrixSingularException', -7); define('MatrixSingularException', -7);
$error['EN'][-7] = "Can only perform operation on singular matrix."; $error['EN'][MatrixSingularException] = "Can only perform operation on singular matrix.";
define('MatrixRankException', -8); define('MatrixRankException', -8);
$error['EN'][-8] = "Can only perform operation on full-rank matrix."; $error['EN'][MatrixRankException] = "Can only perform operation on full-rank matrix.";
define('ArrayLengthException', -9); define('ArrayLengthException', -9);
$error['EN'][-9] = "Array length must be a multiple of m."; $error['EN'][ArrayLengthException] = "Array length must be a multiple of m.";
define('RowLengthException', -10); define('RowLengthException', -10);
$error['EN'][-10] = "All rows must have the same length."; $error['EN'][RowLengthException] = "All rows must have the same length.";
/** /**
* Custom error handler * Custom error handler
* @param int $type Error type: {ERROR, WARNING, NOTICE}
* @param int $num Error number * @param int $num Error number
* @param string $file File in which the error occured
* @param int $line Line on which the error occured
*/ */
function JAMAError( $type = null, $num = null, $file = null, $line = null, $context = null ) { function JAMAError($errorNumber = null) {
global $error; global $error;
$lang = LANG; if (isset($errorNumber)) {
if( isset($type) && isset($num) && isset($file) && isset($line) ) { if (isset($error[JAMALANG][$errorNumber])) {
switch( $type ) { return $error[JAMALANG][$errorNumber];
case ERROR: } else {
echo '<div class="errror"><b>Error:</b> ' . $error[$lang][$num] . '<br />' . $file . ' @ L' . $line . '</div>'; return $error['EN'][$errorNumber];
die();
break;
case WARNING:
echo '<div class="warning"><b>Warning:</b> ' . $error[$lang][$num] . '<br />' . $file . ' @ L' . $line . '</div>';
break;
case NOTICE:
//echo '<div class="notice"><b>Notice:</b> ' . $error[$lang][$num] . '<br />' . $file . ' @ L' . $line . '</div>';
break;
case E_NOTICE:
//echo '<div class="errror"><b>Notice:</b> ' . $error[$lang][$num] . '<br />' . $file . ' @ L' . $line . '</div>';
break;
case E_STRICT:
break;
case E_WARNING:
break;
default:
echo "<div class=\"error\"><b>Unknown Error Type:</b> $type - $file @ L{$line}</div>";
die();
break;
} }
} else { } else {
die( "Invalid arguments to JAMAError()" ); return ("Invalid argument to JAMAError()");
} }
} }
// TODO MarkBaker
//set_error_handler('JAMAError');
//error_reporting(ERROR | WARNING);

View File

@@ -18,10 +18,12 @@ function hypo($a, $b) {
} elseif ($b != 0) { } elseif ($b != 0) {
$r = $a / $b; $r = $a / $b;
$r = abs($b) * sqrt(1 + $r * $r); $r = abs($b) * sqrt(1 + $r * $r);
} else } else {
$r = 0.0; $r = 0.0;
return $r;
} }
return $r;
} // function hypo()
/** /**
* Mike Bommarito's version. * Mike Bommarito's version.
@@ -30,10 +32,11 @@ function hypo($a, $b) {
function hypot() { function hypot() {
$s = 0; $s = 0;
foreach (func_get_args() as $d) { foreach (func_get_args() as $d) {
if (is_numeric($d)) if (is_numeric($d)) {
$s += pow($d, 2); $s += pow($d, 2);
else } else {
trigger_error(ArgumentTypeException, ERROR); throw new Exception(JAMAError(ArgumentTypeException));
}
} }
return sqrt($s); return sqrt($s);
} }