MagicSquareExample.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. <?php
  2. /**
  3. * @package JAMA
  4. */
  5. require_once "../Matrix.php";
  6. /**
  7. * Example of use of Matrix Class, featuring magic squares.
  8. */
  9. class MagicSquareExample {
  10. /**
  11. * Generate magic square test matrix.
  12. * @param int n dimension of matrix
  13. */
  14. function magic($n) {
  15. // Odd order
  16. if (($n % 2) == 1) {
  17. $a = ($n+1)/2;
  18. $b = ($n+1);
  19. for ($j = 0; $j < $n; ++$j)
  20. for ($i = 0; $i < $n; ++$i)
  21. $M[$i][$j] = $n*(($i+$j+$a) % $n) + (($i+2*$j+$b) % $n) + 1;
  22. // Doubly Even Order
  23. } else if (($n % 4) == 0) {
  24. for ($j = 0; $j < $n; ++$j) {
  25. for ($i = 0; $i < $n; ++$i) {
  26. if ((($i+1)/2)%2 == (($j+1)/2)%2)
  27. $M[$i][$j] = $n*$n-$n*$i-$j;
  28. else
  29. $M[$i][$j] = $n*$i+$j+1;
  30. }
  31. }
  32. // Singly Even Order
  33. } else {
  34. $p = $n/2;
  35. $k = ($n-2)/4;
  36. $A = $this->magic($p);
  37. $M = array();
  38. for ($j = 0; $j < $p; ++$j) {
  39. for ($i = 0; $i < $p; ++$i) {
  40. $aij = $A->get($i,$j);
  41. $M[$i][$j] = $aij;
  42. $M[$i][$j+$p] = $aij + 2*$p*$p;
  43. $M[$i+$p][$j] = $aij + 3*$p*$p;
  44. $M[$i+$p][$j+$p] = $aij + $p*$p;
  45. }
  46. }
  47. for ($i = 0; $i < $p; ++$i) {
  48. for ($j = 0; $j < $k; ++$j) {
  49. $t = $M[$i][$j];
  50. $M[$i][$j] = $M[$i+$p][$j];
  51. $M[$i+$p][$j] = $t;
  52. }
  53. for ($j = $n-$k+1; $j < $n; ++$j) {
  54. $t = $M[$i][$j];
  55. $M[$i][$j] = $M[$i+$p][$j];
  56. $M[$i+$p][$j] = $t;
  57. }
  58. }
  59. $t = $M[$k][0]; $M[$k][0] = $M[$k+$p][0]; $M[$k+$p][0] = $t;
  60. $t = $M[$k][$k]; $M[$k][$k] = $M[$k+$p][$k]; $M[$k+$p][$k] = $t;
  61. }
  62. return new Matrix($M);
  63. }
  64. /**
  65. * Simple function to replicate PHP 5 behaviour
  66. */
  67. function microtime_float() {
  68. list($usec, $sec) = explode(" ", microtime());
  69. return ((float)$usec + (float)$sec);
  70. }
  71. /**
  72. * Tests LU, QR, SVD and symmetric Eig decompositions.
  73. *
  74. * n = order of magic square.
  75. * trace = diagonal sum, should be the magic sum, (n^3 + n)/2.
  76. * max_eig = maximum eigenvalue of (A + A')/2, should equal trace.
  77. * rank = linear algebraic rank, should equal n if n is odd,
  78. * be less than n if n is even.
  79. * cond = L_2 condition number, ratio of singular values.
  80. * lu_res = test of LU factorization, norm1(L*U-A(p,:))/(n*eps).
  81. * qr_res = test of QR factorization, norm1(Q*R-A)/(n*eps).
  82. */
  83. function main() {
  84. ?>
  85. <p>Test of Matrix Class, using magic squares.</p>
  86. <p>See MagicSquareExample.main() for an explanation.</p>
  87. <table border='1' cellspacing='0' cellpadding='4'>
  88. <tr>
  89. <th>n</th>
  90. <th>trace</th>
  91. <th>max_eig</th>
  92. <th>rank</th>
  93. <th>cond</th>
  94. <th>lu_res</th>
  95. <th>qr_res</th>
  96. </tr>
  97. <?php
  98. $start_time = $this->microtime_float();
  99. $eps = pow(2.0,-52.0);
  100. for ($n = 3; $n <= 6; ++$n) {
  101. echo "<tr>";
  102. echo "<td align='right'>$n</td>";
  103. $M = $this->magic($n);
  104. $t = (int) $M->trace();
  105. echo "<td align='right'>$t</td>";
  106. $O = $M->plus($M->transpose());
  107. $E = new EigenvalueDecomposition($O->times(0.5));
  108. $d = $E->getRealEigenvalues();
  109. echo "<td align='right'>".$d[$n-1]."</td>";
  110. $r = $M->rank();
  111. echo "<td align='right'>".$r."</td>";
  112. $c = $M->cond();
  113. if ($c < 1/$eps)
  114. echo "<td align='right'>".sprintf("%.3f",$c)."</td>";
  115. else
  116. echo "<td align='right'>Inf</td>";
  117. $LU = new LUDecomposition($M);
  118. $L = $LU->getL();
  119. $U = $LU->getU();
  120. $p = $LU->getPivot();
  121. // Java version: R = L.times(U).minus(M.getMatrix(p,0,n-1));
  122. $S = $L->times($U);
  123. $R = $S->minus($M->getMatrix($p,0,$n-1));
  124. $res = $R->norm1()/($n*$eps);
  125. echo "<td align='right'>".sprintf("%.3f",$res)."</td>";
  126. $QR = new QRDecomposition($M);
  127. $Q = $QR->getQ();
  128. $R = $QR->getR();
  129. $S = $Q->times($R);
  130. $R = $S->minus($M);
  131. $res = $R->norm1()/($n*$eps);
  132. echo "<td align='right'>".sprintf("%.3f",$res)."</td>";
  133. echo "</tr>";
  134. }
  135. echo "<table>";
  136. echo "<br />";
  137. $stop_time = $this->microtime_float();
  138. $etime = $stop_time - $start_time;
  139. echo "<p>Elapsed time is ". sprintf("%.4f",$etime) ." seconds.</p>";
  140. }
  141. }
  142. $magic = new MagicSquareExample();
  143. $magic->main();
  144. ?>