183 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
		
		
			
		
	
	
			183 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
|   | <?php | ||
|  | /** | ||
|  | * @package JAMA | ||
|  | */ | ||
|  | 
 | ||
|  | require_once "../Matrix.php"; | ||
|  | 
 | ||
|  | /** | ||
|  | * Example of use of Matrix Class, featuring magic squares. | ||
|  | */ | ||
|  | class MagicSquareExample { | ||
|  | 
 | ||
|  |   /** | ||
|  |   * Generate magic square test matrix. | ||
|  |   * @param int n dimension of matrix | ||
|  |   */ | ||
|  |   function magic($n) { | ||
|  | 
 | ||
|  |     // Odd order
 | ||
|  | 
 | ||
|  |     if (($n % 2) == 1) { | ||
|  |       $a = ($n+1)/2; | ||
|  |       $b = ($n+1); | ||
|  |       for ($j = 0; $j < $n; ++$j) | ||
|  |         for ($i = 0; $i < $n; ++$i) | ||
|  |           $M[$i][$j] = $n*(($i+$j+$a) % $n) + (($i+2*$j+$b) % $n) + 1; | ||
|  | 
 | ||
|  |     // Doubly Even Order
 | ||
|  | 
 | ||
|  |     } else if (($n % 4) == 0) { | ||
|  |       for ($j = 0; $j < $n; ++$j) { | ||
|  |         for ($i = 0; $i < $n; ++$i) { | ||
|  |           if ((($i+1)/2)%2 == (($j+1)/2)%2) | ||
|  |             $M[$i][$j] = $n*$n-$n*$i-$j; | ||
|  |           else | ||
|  |             $M[$i][$j] = $n*$i+$j+1; | ||
|  |         } | ||
|  |       } | ||
|  | 
 | ||
|  |     // Singly Even Order
 | ||
|  | 
 | ||
|  |     } else { | ||
|  | 
 | ||
|  |       $p = $n/2; | ||
|  |       $k = ($n-2)/4; | ||
|  |       $A = $this->magic($p); | ||
|  |       $M = array(); | ||
|  |       for ($j = 0; $j < $p; ++$j) { | ||
|  |         for ($i = 0; $i < $p; ++$i) { | ||
|  |           $aij = $A->get($i,$j); | ||
|  |           $M[$i][$j]       = $aij; | ||
|  |           $M[$i][$j+$p]    = $aij + 2*$p*$p; | ||
|  |           $M[$i+$p][$j]    = $aij + 3*$p*$p; | ||
|  |           $M[$i+$p][$j+$p] = $aij + $p*$p; | ||
|  |         } | ||
|  |       } | ||
|  | 
 | ||
|  |       for ($i = 0; $i < $p; ++$i) { | ||
|  |         for ($j = 0; $j < $k; ++$j) { | ||
|  |           $t = $M[$i][$j]; | ||
|  |           $M[$i][$j] = $M[$i+$p][$j]; | ||
|  |           $M[$i+$p][$j] = $t; | ||
|  |         } | ||
|  |         for ($j = $n-$k+1; $j < $n; ++$j) { | ||
|  |           $t = $M[$i][$j]; | ||
|  |           $M[$i][$j] = $M[$i+$p][$j]; | ||
|  |           $M[$i+$p][$j] = $t; | ||
|  |         } | ||
|  |       } | ||
|  | 
 | ||
|  |       $t = $M[$k][0];  $M[$k][0]  = $M[$k+$p][0];  $M[$k+$p][0]  = $t; | ||
|  |       $t = $M[$k][$k]; $M[$k][$k] = $M[$k+$p][$k]; $M[$k+$p][$k] = $t; | ||
|  | 
 | ||
|  |     } | ||
|  | 
 | ||
|  |     return new Matrix($M); | ||
|  | 
 | ||
|  |   } | ||
|  | 
 | ||
|  |   /** | ||
|  |   * Simple function to replicate PHP 5 behaviour | ||
|  |   */ | ||
|  |   function microtime_float() { | ||
|  |     list($usec, $sec) = explode(" ", microtime()); | ||
|  |     return ((float)$usec + (float)$sec); | ||
|  |   } | ||
|  | 
 | ||
|  |   /** | ||
|  |   * Tests LU, QR, SVD and symmetric Eig decompositions. | ||
|  |   * | ||
|  |   *   n       = order of magic square. | ||
|  |   *   trace   = diagonal sum, should be the magic sum, (n^3 + n)/2. | ||
|  |   *   max_eig = maximum eigenvalue of (A + A')/2, should equal trace. | ||
|  |   *   rank    = linear algebraic rank, should equal n if n is odd, | ||
|  |   *             be less than n if n is even. | ||
|  |   *   cond    = L_2 condition number, ratio of singular values. | ||
|  |   *   lu_res  = test of LU factorization, norm1(L*U-A(p,:))/(n*eps). | ||
|  |   *   qr_res  = test of QR factorization, norm1(Q*R-A)/(n*eps). | ||
|  |   */ | ||
|  |   function main() { | ||
|  |     ?>
 | ||
|  |     <p>Test of Matrix Class, using magic squares.</p> | ||
|  |     <p>See MagicSquareExample.main() for an explanation.</p> | ||
|  |     <table border='1' cellspacing='0' cellpadding='4'> | ||
|  |       <tr> | ||
|  |         <th>n</th> | ||
|  |         <th>trace</th> | ||
|  |         <th>max_eig</th> | ||
|  |         <th>rank</th> | ||
|  |         <th>cond</th> | ||
|  |         <th>lu_res</th> | ||
|  |         <th>qr_res</th> | ||
|  |       </tr> | ||
|  |       <?php | ||
|  |       $start_time = $this->microtime_float(); | ||
|  |       $eps = pow(2.0,-52.0); | ||
|  |       for ($n = 3; $n <= 6; ++$n) { | ||
|  |         echo "<tr>"; | ||
|  | 
 | ||
|  |         echo "<td align='right'>$n</td>"; | ||
|  | 
 | ||
|  |         $M = $this->magic($n); | ||
|  |         $t = (int) $M->trace(); | ||
|  | 
 | ||
|  |         echo "<td align='right'>$t</td>"; | ||
|  | 
 | ||
|  |         $O = $M->plus($M->transpose()); | ||
|  |         $E = new EigenvalueDecomposition($O->times(0.5)); | ||
|  |         $d = $E->getRealEigenvalues(); | ||
|  | 
 | ||
|  |         echo "<td align='right'>".$d[$n-1]."</td>"; | ||
|  | 
 | ||
|  |         $r = $M->rank(); | ||
|  | 
 | ||
|  |         echo "<td align='right'>".$r."</td>"; | ||
|  | 
 | ||
|  |         $c = $M->cond(); | ||
|  | 
 | ||
|  |         if ($c < 1/$eps) | ||
|  |           echo "<td align='right'>".sprintf("%.3f",$c)."</td>"; | ||
|  |         else | ||
|  |           echo "<td align='right'>Inf</td>"; | ||
|  | 
 | ||
|  |         $LU = new LUDecomposition($M); | ||
|  |         $L = $LU->getL(); | ||
|  |         $U = $LU->getU(); | ||
|  |         $p = $LU->getPivot(); | ||
|  |         // Java version: R = L.times(U).minus(M.getMatrix(p,0,n-1));
 | ||
|  |         $S = $L->times($U); | ||
|  |         $R = $S->minus($M->getMatrix($p,0,$n-1)); | ||
|  |         $res = $R->norm1()/($n*$eps); | ||
|  | 
 | ||
|  |         echo "<td align='right'>".sprintf("%.3f",$res)."</td>"; | ||
|  | 
 | ||
|  |         $QR = new QRDecomposition($M); | ||
|  |         $Q = $QR->getQ(); | ||
|  |         $R = $QR->getR(); | ||
|  |         $S = $Q->times($R); | ||
|  |         $R = $S->minus($M); | ||
|  |         $res = $R->norm1()/($n*$eps); | ||
|  | 
 | ||
|  |         echo "<td align='right'>".sprintf("%.3f",$res)."</td>"; | ||
|  | 
 | ||
|  |         echo "</tr>"; | ||
|  | 
 | ||
|  |      } | ||
|  |      echo "<table>"; | ||
|  |      echo "<br />"; | ||
|  | 
 | ||
|  |      $stop_time = $this->microtime_float(); | ||
|  |      $etime = $stop_time - $start_time; | ||
|  | 
 | ||
|  |      echo "<p>Elapsed time is ". sprintf("%.4f",$etime) ." seconds.</p>"; | ||
|  | 
 | ||
|  |   } | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | $magic = new MagicSquareExample(); | ||
|  | $magic->main(); | ||
|  | 
 | ||
|  | ?>
 |