/PHPExcel/Shared/JAMA/tests/TestMatrix.php

https://bitbucket.org/nfredricks/wp-employee-time · PHP · 415 lines · 261 code · 53 blank · 101 comment · 56 complexity · 19723aca94cb1db21a8ee2346d65c4bd MD5 · raw file

  1. <?php
  2. require_once "../Matrix.php";
  3. class TestMatrix {
  4. function TestMatrix() {
  5. // define test variables
  6. $errorCount = 0;
  7. $warningCount = 0;
  8. $columnwise = array(1.,2.,3.,4.,5.,6.,7.,8.,9.,10.,11.,12.);
  9. $rowwise = array(1.,4.,7.,10.,2.,5.,8.,11.,3.,6.,9.,12.);
  10. $avals = array(array(1.,4.,7.,10.),array(2.,5.,8.,11.),array(3.,6.,9.,12.));
  11. $rankdef = $avals;
  12. $tvals = array(array(1.,2.,3.),array(4.,5.,6.),array(7.,8.,9.),array(10.,11.,12.));
  13. $subavals = array(array(5.,8.,11.),array(6.,9.,12.));
  14. $rvals = array(array(1.,4.,7.),array(2.,5.,8.,11.),array(3.,6.,9.,12.));
  15. $pvals = array(array(1.,1.,1.),array(1.,2.,3.),array(1.,3.,6.));
  16. $ivals = array(array(1.,0.,0.,0.),array(0.,1.,0.,0.),array(0.,0.,1.,0.));
  17. $evals = array(array(0.,1.,0.,0.),array(1.,0.,2.e-7,0.),array(0.,-2.e-7,0.,1.),array(0.,0.,1.,0.));
  18. $square = array(array(166.,188.,210.),array(188.,214.,240.),array(210.,240.,270.));
  19. $sqSolution = array(array(13.),array(15.));
  20. $condmat = array(array(1.,3.),array(7.,9.));
  21. $rows = 3;
  22. $cols = 4;
  23. $invalidID = 5; /* should trigger bad shape for construction with val */
  24. $raggedr = 0; /* (raggedr,raggedc) should be out of bounds in ragged array */
  25. $raggedc = 4;
  26. $validID = 3; /* leading dimension of intended test Matrices */
  27. $nonconformld = 4; /* leading dimension which is valid, but nonconforming */
  28. $ib = 1; /* index ranges for sub Matrix */
  29. $ie = 2;
  30. $jb = 1;
  31. $je = 3;
  32. $rowindexset = array(1,2);
  33. $badrowindexset = array(1,3);
  34. $columnindexset = array(1,2,3);
  35. $badcolumnindexset = array(1,2,4);
  36. $columnsummax = 33.;
  37. $rowsummax = 30.;
  38. $sumofdiagonals = 15;
  39. $sumofsquares = 650;
  40. /**
  41. * Test matrix methods
  42. */
  43. /**
  44. * Constructors and constructor-like methods:
  45. *
  46. * Matrix(double[], int)
  47. * Matrix(double[][])
  48. * Matrix(int, int)
  49. * Matrix(int, int, double)
  50. * Matrix(int, int, double[][])
  51. * constructWithCopy(double[][])
  52. * random(int,int)
  53. * identity(int)
  54. */
  55. echo "<p>Testing constructors and constructor-like methods...</p>";
  56. $A = new Matrix($columnwise, 3);
  57. if($A instanceof Matrix) {
  58. $this->try_success("Column-packed constructor...");
  59. } else
  60. $errorCount = $this->try_failure($errorCount, "Column-packed constructor...", "Unable to construct Matrix");
  61. $T = new Matrix($tvals);
  62. if($T instanceof Matrix)
  63. $this->try_success("2D array constructor...");
  64. else
  65. $errorCount = $this->try_failure($errorCount, "2D array constructor...", "Unable to construct Matrix");
  66. $A = new Matrix($columnwise, $validID);
  67. $B = new Matrix($avals);
  68. $tmp = $B->get(0,0);
  69. $avals[0][0] = 0.0;
  70. $C = $B->minus($A);
  71. $avals[0][0] = $tmp;
  72. $B = Matrix::constructWithCopy($avals);
  73. $tmp = $B->get(0,0);
  74. $avals[0][0] = 0.0;
  75. /** check that constructWithCopy behaves properly **/
  76. if ( ( $tmp - $B->get(0,0) ) != 0.0 )
  77. $errorCount = $this->try_failure($errorCount,"constructWithCopy... ","copy not effected... data visible outside");
  78. else
  79. $this->try_success("constructWithCopy... ","");
  80. $I = new Matrix($ivals);
  81. if ( $this->checkMatrices($I,Matrix::identity(3,4)) )
  82. $this->try_success("identity... ","");
  83. else
  84. $errorCount = $this->try_failure($errorCount,"identity... ","identity Matrix not successfully created");
  85. /**
  86. * Access Methods:
  87. *
  88. * getColumnDimension()
  89. * getRowDimension()
  90. * getArray()
  91. * getArrayCopy()
  92. * getColumnPackedCopy()
  93. * getRowPackedCopy()
  94. * get(int,int)
  95. * getMatrix(int,int,int,int)
  96. * getMatrix(int,int,int[])
  97. * getMatrix(int[],int,int)
  98. * getMatrix(int[],int[])
  99. * set(int,int,double)
  100. * setMatrix(int,int,int,int,Matrix)
  101. * setMatrix(int,int,int[],Matrix)
  102. * setMatrix(int[],int,int,Matrix)
  103. * setMatrix(int[],int[],Matrix)
  104. */
  105. print "<p>Testing access methods...</p>";
  106. $B = new Matrix($avals);
  107. if($B->getRowDimension() == $rows)
  108. $this->try_success("getRowDimension...");
  109. else
  110. $errorCount = $this->try_failure($errorCount, "getRowDimension...");
  111. if($B->getColumnDimension() == $cols)
  112. $this->try_success("getColumnDimension...");
  113. else
  114. $errorCount = $this->try_failure($errorCount, "getColumnDimension...");
  115. $barray = $B->getArray();
  116. if($this->checkArrays($barray, $avals))
  117. $this->try_success("getArray...");
  118. else
  119. $errorCount = $this->try_failure($errorCount, "getArray...");
  120. $bpacked = $B->getColumnPackedCopy();
  121. if($this->checkArrays($bpacked, $columnwise))
  122. $this->try_success("getColumnPackedCopy...");
  123. else
  124. $errorCount = $this->try_failure($errorCount, "getColumnPackedCopy...");
  125. $bpacked = $B->getRowPackedCopy();
  126. if($this->checkArrays($bpacked, $rowwise))
  127. $this->try_success("getRowPackedCopy...");
  128. else
  129. $errorCount = $this->try_failure($errorCount, "getRowPackedCopy...");
  130. /**
  131. * Array-like methods:
  132. * minus
  133. * minusEquals
  134. * plus
  135. * plusEquals
  136. * arrayLeftDivide
  137. * arrayLeftDivideEquals
  138. * arrayRightDivide
  139. * arrayRightDivideEquals
  140. * arrayTimes
  141. * arrayTimesEquals
  142. * uminus
  143. */
  144. print "<p>Testing array-like methods...</p>";
  145. /**
  146. * I/O methods:
  147. * read
  148. * print
  149. * serializable:
  150. * writeObject
  151. * readObject
  152. */
  153. print "<p>Testing I/O methods...</p>";
  154. /**
  155. * Test linear algebra methods
  156. */
  157. echo "<p>Testing linear algebra methods...<p>";
  158. $A = new Matrix($columnwise, 3);
  159. if( $this->checkMatrices($A->transpose(), $T) )
  160. $this->try_success("Transpose check...");
  161. else
  162. $errorCount = $this->try_failure($errorCount, "Transpose check...", "Matrices are not equal");
  163. if($this->checkScalars($A->norm1(), $columnsummax))
  164. $this->try_success("Maximum column sum...");
  165. else
  166. $errorCount = $this->try_failure($errorCount, "Maximum column sum...", "Incorrect: " . $A->norm1() . " != " . $columnsummax);
  167. if($this->checkScalars($A->normInf(), $rowsummax))
  168. $this->try_success("Maximum row sum...");
  169. else
  170. $errorCount = $this->try_failure($errorCount, "Maximum row sum...", "Incorrect: " . $A->normInf() . " != " . $rowsummax );
  171. if($this->checkScalars($A->normF(), sqrt($sumofsquares)))
  172. $this->try_success("Frobenius norm...");
  173. else
  174. $errorCount = $this->try_failure($errorCount, "Frobenius norm...", "Incorrect:" . $A->normF() . " != " . sqrt($sumofsquares));
  175. if($this->checkScalars($A->trace(), $sumofdiagonals))
  176. $this->try_success("Matrix trace...");
  177. else
  178. $errorCount = $this->try_failure($errorCount, "Matrix trace...", "Incorrect: " . $A->trace() . " != " . $sumofdiagonals);
  179. $B = $A->getMatrix(0, $A->getRowDimension(), 0, $A->getRowDimension());
  180. if( $B->det() == 0 )
  181. $this->try_success("Matrix determinant...");
  182. else
  183. $errorCount = $this->try_failure($errorCount, "Matrix determinant...", "Incorrect: " . $B->det() . " != " . 0);
  184. $A = new Matrix($columnwise,3);
  185. $SQ = new Matrix($square);
  186. if ($this->checkMatrices($SQ, $A->times($A->transpose())))
  187. $this->try_success("times(Matrix)...");
  188. else {
  189. $errorCount = $this->try_failure($errorCount, "times(Matrix)...", "Unable to multiply matrices");
  190. $SQ->toHTML();
  191. $AT->toHTML();
  192. }
  193. $A = new Matrix($columnwise, 4);
  194. $QR = $A->qr();
  195. $R = $QR->getR();
  196. $Q = $QR->getQ();
  197. if($this->checkMatrices($A, $Q->times($R)))
  198. $this->try_success("QRDecomposition...","");
  199. else
  200. $errorCount = $this->try_failure($errorCount,"QRDecomposition...","incorrect qr decomposition calculation");
  201. $A = new Matrix($columnwise, 4);
  202. $SVD = $A->svd();
  203. $U = $SVD->getU();
  204. $S = $SVD->getS();
  205. $V = $SVD->getV();
  206. if ($this->checkMatrices($A, $U->times($S->times($V->transpose()))))
  207. $this->try_success("SingularValueDecomposition...","");
  208. else
  209. $errorCount = $this->try_failure($errorCount,"SingularValueDecomposition...","incorrect singular value decomposition calculation");
  210. $n = $A->getColumnDimension();
  211. $A = $A->getMatrix(0,$n-1,0,$n-1);
  212. $A->set(0,0,0.);
  213. $LU = $A->lu();
  214. $L = $LU->getL();
  215. if ( $this->checkMatrices($A->getMatrix($LU->getPivot(),0,$n-1), $L->times($LU->getU())) )
  216. $this->try_success("LUDecomposition...","");
  217. else
  218. $errorCount = $this->try_failure($errorCount,"LUDecomposition...","incorrect LU decomposition calculation");
  219. $X = $A->inverse();
  220. if ( $this->checkMatrices($A->times($X),Matrix::identity(3,3)) )
  221. $this->try_success("inverse()...","");
  222. else
  223. $errorCount = $this->try_failure($errorCount, "inverse()...","incorrect inverse calculation");
  224. $DEF = new Matrix($rankdef);
  225. if($this->checkScalars($DEF->rank(), min($DEF->getRowDimension(), $DEF->getColumnDimension())-1))
  226. $this->try_success("Rank...");
  227. else
  228. $this->try_failure("Rank...", "incorrect rank calculation");
  229. $B = new Matrix($condmat);
  230. $SVD = $B->svd();
  231. $singularvalues = $SVD->getSingularValues();
  232. if($this->checkScalars($B->cond(), $singularvalues[0]/$singularvalues[min($B->getRowDimension(), $B->getColumnDimension())-1]))
  233. $this->try_success("Condition number...");
  234. else
  235. $this->try_failure("Condition number...", "incorrect condition number calculation");
  236. $SUB = new Matrix($subavals);
  237. $O = new Matrix($SUB->getRowDimension(),1,1.0);
  238. $SOL = new Matrix($sqSolution);
  239. $SQ = $SUB->getMatrix(0,$SUB->getRowDimension()-1,0,$SUB->getRowDimension()-1);
  240. if ( $this->checkMatrices($SQ->solve($SOL),$O) )
  241. $this->try_success("solve()...","");
  242. else
  243. $errorCount = $this->try_failure($errorCount,"solve()...","incorrect lu solve calculation");
  244. $A = new Matrix($pvals);
  245. $Chol = $A->chol();
  246. $L = $Chol->getL();
  247. if ( $this->checkMatrices($A, $L->times($L->transpose())) )
  248. $this->try_success("CholeskyDecomposition...","");
  249. else
  250. $errorCount = $this->try_failure($errorCount,"CholeskyDecomposition...","incorrect Cholesky decomposition calculation");
  251. $X = $Chol->solve(Matrix::identity(3,3));
  252. if ( $this->checkMatrices($A->times($X), Matrix::identity(3,3)) )
  253. $this->try_success("CholeskyDecomposition solve()...","");
  254. else
  255. $errorCount = $this->try_failure($errorCount,"CholeskyDecomposition solve()...","incorrect Choleskydecomposition solve calculation");
  256. $Eig = $A->eig();
  257. $D = $Eig->getD();
  258. $V = $Eig->getV();
  259. if( $this->checkMatrices($A->times($V),$V->times($D)) )
  260. $this->try_success("EigenvalueDecomposition (symmetric)...","");
  261. else
  262. $errorCount = $this->try_failure($errorCount,"EigenvalueDecomposition (symmetric)...","incorrect symmetric Eigenvalue decomposition calculation");
  263. $A = new Matrix($evals);
  264. $Eig = $A->eig();
  265. $D = $Eig->getD();
  266. $V = $Eig->getV();
  267. if ( $this->checkMatrices($A->times($V),$V->times($D)) )
  268. $this->try_success("EigenvalueDecomposition (nonsymmetric)...","");
  269. else
  270. $errorCount = $this->try_failure($errorCount,"EigenvalueDecomposition (nonsymmetric)...","incorrect nonsymmetric Eigenvalue decomposition calculation");
  271. print("<b>{$errorCount} total errors</b>.");
  272. }
  273. /**
  274. * Print appropriate messages for successful outcome try
  275. * @param string $s
  276. * @param string $e
  277. */
  278. function try_success($s, $e = "") {
  279. print "> ". $s ."success<br />";
  280. if ($e != "")
  281. print "> Message: ". $e ."<br />";
  282. }
  283. /**
  284. * Print appropriate messages for unsuccessful outcome try
  285. * @param int $count
  286. * @param string $s
  287. * @param string $e
  288. * @return int incremented counter
  289. */
  290. function try_failure($count, $s, $e="") {
  291. print "> ". $s ."*** failure ***<br />> Message: ". $e ."<br />";
  292. return ++$count;
  293. }
  294. /**
  295. * Print appropriate messages for unsuccessful outcome try
  296. * @param int $count
  297. * @param string $s
  298. * @param string $e
  299. * @return int incremented counter
  300. */
  301. function try_warning($count, $s, $e="") {
  302. print "> ". $s ."*** warning ***<br />> Message: ". $e ."<br />";
  303. return ++$count;
  304. }
  305. /**
  306. * Check magnitude of difference of "scalars".
  307. * @param float $x
  308. * @param float $y
  309. */
  310. function checkScalars($x, $y) {
  311. $eps = pow(2.0,-52.0);
  312. if ($x == 0 & abs($y) < 10*$eps) return;
  313. if ($y == 0 & abs($x) < 10*$eps) return;
  314. if (abs($x-$y) > 10 * $eps * max(abs($x),abs($y)))
  315. return false;
  316. else
  317. return true;
  318. }
  319. /**
  320. * Check norm of difference of "vectors".
  321. * @param float $x[]
  322. * @param float $y[]
  323. */
  324. function checkVectors($x, $y) {
  325. $nx = count($x);
  326. $ny = count($y);
  327. if ($nx == $ny)
  328. for($i=0; $i < $nx; ++$i)
  329. $this->checkScalars($x[$i],$y[$i]);
  330. else
  331. die("Attempt to compare vectors of different lengths");
  332. }
  333. /**
  334. * Check norm of difference of "arrays".
  335. * @param float $x[][]
  336. * @param float $y[][]
  337. */
  338. function checkArrays($x, $y) {
  339. $A = new Matrix($x);
  340. $B = new Matrix($y);
  341. return $this->checkMatrices($A,$B);
  342. }
  343. /**
  344. * Check norm of difference of "matrices".
  345. * @param matrix $X
  346. * @param matrix $Y
  347. */
  348. function checkMatrices($X = null, $Y = null) {
  349. if( $X == null || $Y == null )
  350. return false;
  351. $eps = pow(2.0,-52.0);
  352. if ($X->norm1() == 0. & $Y->norm1() < 10*$eps) return true;
  353. if ($Y->norm1() == 0. & $X->norm1() < 10*$eps) return true;
  354. $A = $X->minus($Y);
  355. if ($A->norm1() > 1000 * $eps * max($X->norm1(),$Y->norm1()))
  356. die("The norm of (X-Y) is too large: ".$A->norm1());
  357. else
  358. return true;
  359. }
  360. }
  361. $test = new TestMatrix;
  362. ?>