PageRenderTime 60ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/pma/libraries/PHPExcel/PHPExcel/Shared/JAMA/Matrix.php

https://bitbucket.org/kucing2k/ediassoc
PHP | 1445 lines | 901 code | 129 blank | 415 comment | 263 complexity | 662cbf2047ec1abad888b65ac33b5b36 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, BSD-2-Clause, GPL-2.0
  1. <?php
  2. /**
  3. * @package JAMA
  4. */
  5. define('RAND_MAX', mt_getrandmax());
  6. define('RAND_MIN', 0);
  7. /** PHPExcel root directory */
  8. if (!defined('PHPEXCEL_ROOT')) {
  9. /**
  10. * @ignore
  11. */
  12. define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../../');
  13. require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
  14. PHPExcel_Autoloader::Register();
  15. PHPExcel_Shared_ZipStreamWrapper::register();
  16. // check mbstring.func_overload
  17. if (ini_get('mbstring.func_overload') & 2) {
  18. throw new Exception('Multibyte function overloading in PHP must be disabled for string functions (2).');
  19. }
  20. }
  21. require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/JAMA/utils/Error.php';
  22. require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/JAMA/utils/Maths.php';
  23. require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/JAMA/CholeskyDecomposition.php';
  24. require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/JAMA/LUDecomposition.php';
  25. require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/JAMA/QRDecomposition.php';
  26. require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/JAMA/EigenvalueDecomposition.php';
  27. require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/JAMA/SingularValueDecomposition.php';
  28. require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/String.php';
  29. require_once PHPEXCEL_ROOT . 'PHPExcel/Calculation/Functions.php';
  30. /*
  31. * Matrix class
  32. *
  33. * @author Paul Meagher
  34. * @author Michael Bommarito
  35. * @author Lukasz Karapuda
  36. * @author Bartek Matosiuk
  37. * @version 1.8
  38. * @license PHP v3.0
  39. * @see http://math.nist.gov/javanumerics/jama/
  40. */
  41. class Matrix {
  42. /**
  43. * Matrix storage
  44. *
  45. * @var array
  46. * @access public
  47. */
  48. public $A = array();
  49. /**
  50. * Matrix row dimension
  51. *
  52. * @var int
  53. * @access private
  54. */
  55. private $m;
  56. /**
  57. * Matrix column dimension
  58. *
  59. * @var int
  60. * @access private
  61. */
  62. private $n;
  63. /**
  64. * Polymorphic constructor
  65. *
  66. * As PHP has no support for polymorphic constructors, we hack our own sort of polymorphism using func_num_args, func_get_arg, and gettype. In essence, we're just implementing a simple RTTI filter and calling the appropriate constructor.
  67. */
  68. public function __construct() {
  69. if (func_num_args() > 0) {
  70. $args = func_get_args();
  71. $match = implode(",", array_map('gettype', $args));
  72. switch($match) {
  73. //Square matrix - n x n
  74. case 'integer':
  75. $this->m = $args[0];
  76. $this->n = $args[0];
  77. $this->A = array_fill(0, $this->m, array_fill(0, $this->n, 0));
  78. break;
  79. //Rectangular matrix - m x n
  80. case 'integer,integer':
  81. $this->m = $args[0];
  82. $this->n = $args[1];
  83. $this->A = array_fill(0, $this->m, array_fill(0, $this->n, 0));
  84. break;
  85. //Rectangular matrix constant-filled - m x n filled with c
  86. case 'integer,integer,integer':
  87. $this->m = $args[0];
  88. $this->n = $args[1];
  89. $this->A = array_fill(0, $this->m, array_fill(0, $this->n, $args[2]));
  90. break;
  91. //Rectangular matrix constant-filled - m x n filled with c
  92. case 'integer,integer,double':
  93. $this->m = $args[0];
  94. $this->n = $args[1];
  95. $this->A = array_fill(0, $this->m, array_fill(0, $this->n, $args[2]));
  96. break;
  97. //Rectangular matrix - m x n initialized from 2D array
  98. case 'array':
  99. $this->m = count($args[0]);
  100. $this->n = count($args[0][0]);
  101. $this->A = $args[0];
  102. break;
  103. //Rectangular matrix - m x n initialized from 2D array
  104. case 'array,integer,integer':
  105. $this->m = $args[1];
  106. $this->n = $args[2];
  107. $this->A = $args[0];
  108. break;
  109. //Rectangular matrix - m x n initialized from packed array
  110. case 'array,integer':
  111. $this->m = $args[1];
  112. if ($this->m != 0) {
  113. $this->n = count($args[0]) / $this->m;
  114. } else {
  115. $this->n = 0;
  116. }
  117. if (($this->m * $this->n) == count($args[0])) {
  118. for($i = 0; $i < $this->m; ++$i) {
  119. for($j = 0; $j < $this->n; ++$j) {
  120. $this->A[$i][$j] = $args[0][$i + $j * $this->m];
  121. }
  122. }
  123. } else {
  124. throw new Exception(JAMAError(ArrayLengthException));
  125. }
  126. break;
  127. default:
  128. throw new Exception(JAMAError(PolymorphicArgumentException));
  129. break;
  130. }
  131. } else {
  132. throw new Exception(JAMAError(PolymorphicArgumentException));
  133. }
  134. } // function __construct()
  135. /**
  136. * getArray
  137. *
  138. * @return array Matrix array
  139. */
  140. public function getArray() {
  141. return $this->A;
  142. } // function getArray()
  143. /**
  144. * getArrayCopy
  145. *
  146. * @return array Matrix array copy
  147. */
  148. public function getArrayCopy() {
  149. return $this->A;
  150. } // function getArrayCopy()
  151. /**
  152. * constructWithCopy
  153. * Construct a matrix from a copy of a 2-D array.
  154. *
  155. * @param double A[][] Two-dimensional array of doubles.
  156. * @exception IllegalArgumentException All rows must have the same length
  157. */
  158. public function constructWithCopy($A) {
  159. $this->m = count($A);
  160. $this->n = count($A[0]);
  161. $newCopyMatrix = new Matrix($this->m, $this->n);
  162. for ($i = 0; $i < $this->m; ++$i) {
  163. if (count($A[$i]) != $this->n) {
  164. throw new Exception(JAMAError(RowLengthException));
  165. }
  166. for ($j = 0; $j < $this->n; ++$j) {
  167. $newCopyMatrix->A[$i][$j] = $A[$i][$j];
  168. }
  169. }
  170. return $newCopyMatrix;
  171. } // function constructWithCopy()
  172. /**
  173. * getColumnPackedCopy
  174. *
  175. * Get a column-packed array
  176. * @return array Column-packed matrix array
  177. */
  178. public function getColumnPackedCopy() {
  179. $P = array();
  180. for($i = 0; $i < $this->m; ++$i) {
  181. for($j = 0; $j < $this->n; ++$j) {
  182. array_push($P, $this->A[$j][$i]);
  183. }
  184. }
  185. return $P;
  186. } // function getColumnPackedCopy()
  187. /**
  188. * getRowPackedCopy
  189. *
  190. * Get a row-packed array
  191. * @return array Row-packed matrix array
  192. */
  193. public function getRowPackedCopy() {
  194. $P = array();
  195. for($i = 0; $i < $this->m; ++$i) {
  196. for($j = 0; $j < $this->n; ++$j) {
  197. array_push($P, $this->A[$i][$j]);
  198. }
  199. }
  200. return $P;
  201. } // function getRowPackedCopy()
  202. /**
  203. * getRowDimension
  204. *
  205. * @return int Row dimension
  206. */
  207. public function getRowDimension() {
  208. return $this->m;
  209. } // function getRowDimension()
  210. /**
  211. * getColumnDimension
  212. *
  213. * @return int Column dimension
  214. */
  215. public function getColumnDimension() {
  216. return $this->n;
  217. } // function getColumnDimension()
  218. /**
  219. * get
  220. *
  221. * Get the i,j-th element of the matrix.
  222. * @param int $i Row position
  223. * @param int $j Column position
  224. * @return mixed Element (int/float/double)
  225. */
  226. public function get($i = null, $j = null) {
  227. return $this->A[$i][$j];
  228. } // function get()
  229. /**
  230. * getMatrix
  231. *
  232. * Get a submatrix
  233. * @param int $i0 Initial row index
  234. * @param int $iF Final row index
  235. * @param int $j0 Initial column index
  236. * @param int $jF Final column index
  237. * @return Matrix Submatrix
  238. */
  239. public function getMatrix() {
  240. if (func_num_args() > 0) {
  241. $args = func_get_args();
  242. $match = implode(",", array_map('gettype', $args));
  243. switch($match) {
  244. //A($i0...; $j0...)
  245. case 'integer,integer':
  246. list($i0, $j0) = $args;
  247. if ($i0 >= 0) { $m = $this->m - $i0; } else { throw new Exception(JAMAError(ArgumentBoundsException)); }
  248. if ($j0 >= 0) { $n = $this->n - $j0; } else { throw new Exception(JAMAError(ArgumentBoundsException)); }
  249. $R = new Matrix($m, $n);
  250. for($i = $i0; $i < $this->m; ++$i) {
  251. for($j = $j0; $j < $this->n; ++$j) {
  252. $R->set($i, $j, $this->A[$i][$j]);
  253. }
  254. }
  255. return $R;
  256. break;
  257. //A($i0...$iF; $j0...$jF)
  258. case 'integer,integer,integer,integer':
  259. list($i0, $iF, $j0, $jF) = $args;
  260. if (($iF > $i0) && ($this->m >= $iF) && ($i0 >= 0)) { $m = $iF - $i0; } else { throw new Exception(JAMAError(ArgumentBoundsException)); }
  261. if (($jF > $j0) && ($this->n >= $jF) && ($j0 >= 0)) { $n = $jF - $j0; } else { throw new Exception(JAMAError(ArgumentBoundsException)); }
  262. $R = new Matrix($m+1, $n+1);
  263. for($i = $i0; $i <= $iF; ++$i) {
  264. for($j = $j0; $j <= $jF; ++$j) {
  265. $R->set($i - $i0, $j - $j0, $this->A[$i][$j]);
  266. }
  267. }
  268. return $R;
  269. break;
  270. //$R = array of row indices; $C = array of column indices
  271. case 'array,array':
  272. list($RL, $CL) = $args;
  273. if (count($RL) > 0) { $m = count($RL); } else { throw new Exception(JAMAError(ArgumentBoundsException)); }
  274. if (count($CL) > 0) { $n = count($CL); } else { throw new Exception(JAMAError(ArgumentBoundsException)); }
  275. $R = new Matrix($m, $n);
  276. for($i = 0; $i < $m; ++$i) {
  277. for($j = 0; $j < $n; ++$j) {
  278. $R->set($i - $i0, $j - $j0, $this->A[$RL[$i]][$CL[$j]]);
  279. }
  280. }
  281. return $R;
  282. break;
  283. //$RL = array of row indices; $CL = array of column indices
  284. case 'array,array':
  285. list($RL, $CL) = $args;
  286. if (count($RL) > 0) { $m = count($RL); } else { throw new Exception(JAMAError(ArgumentBoundsException)); }
  287. if (count($CL) > 0) { $n = count($CL); } else { throw new Exception(JAMAError(ArgumentBoundsException)); }
  288. $R = new Matrix($m, $n);
  289. for($i = 0; $i < $m; ++$i) {
  290. for($j = 0; $j < $n; ++$j) {
  291. $R->set($i, $j, $this->A[$RL[$i]][$CL[$j]]);
  292. }
  293. }
  294. return $R;
  295. break;
  296. //A($i0...$iF); $CL = array of column indices
  297. case 'integer,integer,array':
  298. list($i0, $iF, $CL) = $args;
  299. if (($iF > $i0) && ($this->m >= $iF) && ($i0 >= 0)) { $m = $iF - $i0; } else { throw new Exception(JAMAError(ArgumentBoundsException)); }
  300. if (count($CL) > 0) { $n = count($CL); } else { throw new Exception(JAMAError(ArgumentBoundsException)); }
  301. $R = new Matrix($m, $n);
  302. for($i = $i0; $i < $iF; ++$i) {
  303. for($j = 0; $j < $n; ++$j) {
  304. $R->set($i - $i0, $j, $this->A[$RL[$i]][$j]);
  305. }
  306. }
  307. return $R;
  308. break;
  309. //$RL = array of row indices
  310. case 'array,integer,integer':
  311. list($RL, $j0, $jF) = $args;
  312. if (count($RL) > 0) { $m = count($RL); } else { throw new Exception(JAMAError(ArgumentBoundsException)); }
  313. if (($jF >= $j0) && ($this->n >= $jF) && ($j0 >= 0)) { $n = $jF - $j0; } else { throw new Exception(JAMAError(ArgumentBoundsException)); }
  314. $R = new Matrix($m, $n+1);
  315. for($i = 0; $i < $m; ++$i) {
  316. for($j = $j0; $j <= $jF; ++$j) {
  317. $R->set($i, $j - $j0, $this->A[$RL[$i]][$j]);
  318. }
  319. }
  320. return $R;
  321. break;
  322. default:
  323. throw new Exception(JAMAError(PolymorphicArgumentException));
  324. break;
  325. }
  326. } else {
  327. throw new Exception(JAMAError(PolymorphicArgumentException));
  328. }
  329. } // function getMatrix()
  330. /**
  331. * setMatrix
  332. *
  333. * Set a submatrix
  334. * @param int $i0 Initial row index
  335. * @param int $j0 Initial column index
  336. * @param mixed $S Matrix/Array submatrix
  337. * ($i0, $j0, $S) $S = Matrix
  338. * ($i0, $j0, $S) $S = Array
  339. */
  340. public function setMatrix() {
  341. if (func_num_args() > 0) {
  342. $args = func_get_args();
  343. $match = implode(",", array_map('gettype', $args));
  344. switch($match) {
  345. case 'integer,integer,object':
  346. if ($args[2] instanceof Matrix) { $M = $args[2]; } else { throw new Exception(JAMAError(ArgumentTypeException)); }
  347. if (($args[0] + $M->m) <= $this->m) { $i0 = $args[0]; } else { throw new Exception(JAMAError(ArgumentBoundsException)); }
  348. if (($args[1] + $M->n) <= $this->n) { $j0 = $args[1]; } else { throw new Exception(JAMAError(ArgumentBoundsException)); }
  349. for($i = $i0; $i < $i0 + $M->m; ++$i) {
  350. for($j = $j0; $j < $j0 + $M->n; ++$j) {
  351. $this->A[$i][$j] = $M->get($i - $i0, $j - $j0);
  352. }
  353. }
  354. break;
  355. case 'integer,integer,array':
  356. $M = new Matrix($args[2]);
  357. if (($args[0] + $M->m) <= $this->m) { $i0 = $args[0]; } else { throw new Exception(JAMAError(ArgumentBoundsException)); }
  358. if (($args[1] + $M->n) <= $this->n) { $j0 = $args[1]; } else { throw new Exception(JAMAError(ArgumentBoundsException)); }
  359. for($i = $i0; $i < $i0 + $M->m; ++$i) {
  360. for($j = $j0; $j < $j0 + $M->n; ++$j) {
  361. $this->A[$i][$j] = $M->get($i - $i0, $j - $j0);
  362. }
  363. }
  364. break;
  365. default:
  366. throw new Exception(JAMAError(PolymorphicArgumentException));
  367. break;
  368. }
  369. } else {
  370. throw new Exception(JAMAError(PolymorphicArgumentException));
  371. }
  372. } // function setMatrix()
  373. /**
  374. * checkMatrixDimensions
  375. *
  376. * Is matrix B the same size?
  377. * @param Matrix $B Matrix B
  378. * @return boolean
  379. */
  380. public function checkMatrixDimensions($B = null) {
  381. if ($B instanceof Matrix) {
  382. if (($this->m == $B->getRowDimension()) && ($this->n == $B->getColumnDimension())) {
  383. return true;
  384. } else {
  385. throw new Exception(JAMAError(MatrixDimensionException));
  386. }
  387. } else {
  388. throw new Exception(JAMAError(ArgumentTypeException));
  389. }
  390. } // function checkMatrixDimensions()
  391. /**
  392. * set
  393. *
  394. * Set the i,j-th element of the matrix.
  395. * @param int $i Row position
  396. * @param int $j Column position
  397. * @param mixed $c Int/float/double value
  398. * @return mixed Element (int/float/double)
  399. */
  400. public function set($i = null, $j = null, $c = null) {
  401. // Optimized set version just has this
  402. $this->A[$i][$j] = $c;
  403. /*
  404. if (is_int($i) && is_int($j) && is_numeric($c)) {
  405. if (($i < $this->m) && ($j < $this->n)) {
  406. $this->A[$i][$j] = $c;
  407. } else {
  408. echo "A[$i][$j] = $c<br />";
  409. throw new Exception(JAMAError(ArgumentBoundsException));
  410. }
  411. } else {
  412. throw new Exception(JAMAError(ArgumentTypeException));
  413. }
  414. */
  415. } // function set()
  416. /**
  417. * identity
  418. *
  419. * Generate an identity matrix.
  420. * @param int $m Row dimension
  421. * @param int $n Column dimension
  422. * @return Matrix Identity matrix
  423. */
  424. public function identity($m = null, $n = null) {
  425. return $this->diagonal($m, $n, 1);
  426. } // function identity()
  427. /**
  428. * diagonal
  429. *
  430. * Generate a diagonal matrix
  431. * @param int $m Row dimension
  432. * @param int $n Column dimension
  433. * @param mixed $c Diagonal value
  434. * @return Matrix Diagonal matrix
  435. */
  436. public function diagonal($m = null, $n = null, $c = 1) {
  437. $R = new Matrix($m, $n);
  438. for($i = 0; $i < $m; ++$i) {
  439. $R->set($i, $i, $c);
  440. }
  441. return $R;
  442. } // function diagonal()
  443. /**
  444. * filled
  445. *
  446. * Generate a filled matrix
  447. * @param int $m Row dimension
  448. * @param int $n Column dimension
  449. * @param int $c Fill constant
  450. * @return Matrix Filled matrix
  451. */
  452. public function filled($m = null, $n = null, $c = 0) {
  453. if (is_int($m) && is_int($n) && is_numeric($c)) {
  454. $R = new Matrix($m, $n, $c);
  455. return $R;
  456. } else {
  457. throw new Exception(JAMAError(ArgumentTypeException));
  458. }
  459. } // function filled()
  460. /**
  461. * random
  462. *
  463. * Generate a random matrix
  464. * @param int $m Row dimension
  465. * @param int $n Column dimension
  466. * @return Matrix Random matrix
  467. */
  468. public function random($m = null, $n = null, $a = RAND_MIN, $b = RAND_MAX) {
  469. if (is_int($m) && is_int($n) && is_numeric($a) && is_numeric($b)) {
  470. $R = new Matrix($m, $n);
  471. for($i = 0; $i < $m; ++$i) {
  472. for($j = 0; $j < $n; ++$j) {
  473. $R->set($i, $j, mt_rand($a, $b));
  474. }
  475. }
  476. return $R;
  477. } else {
  478. throw new Exception(JAMAError(ArgumentTypeException));
  479. }
  480. } // function random()
  481. /**
  482. * packed
  483. *
  484. * Alias for getRowPacked
  485. * @return array Packed array
  486. */
  487. public function packed() {
  488. return $this->getRowPacked();
  489. } // function packed()
  490. /**
  491. * getMatrixByRow
  492. *
  493. * Get a submatrix by row index/range
  494. * @param int $i0 Initial row index
  495. * @param int $iF Final row index
  496. * @return Matrix Submatrix
  497. */
  498. public function getMatrixByRow($i0 = null, $iF = null) {
  499. if (is_int($i0)) {
  500. if (is_int($iF)) {
  501. return $this->getMatrix($i0, 0, $iF + 1, $this->n);
  502. } else {
  503. return $this->getMatrix($i0, 0, $i0 + 1, $this->n);
  504. }
  505. } else {
  506. throw new Exception(JAMAError(ArgumentTypeException));
  507. }
  508. } // function getMatrixByRow()
  509. /**
  510. * getMatrixByCol
  511. *
  512. * Get a submatrix by column index/range
  513. * @param int $i0 Initial column index
  514. * @param int $iF Final column index
  515. * @return Matrix Submatrix
  516. */
  517. public function getMatrixByCol($j0 = null, $jF = null) {
  518. if (is_int($j0)) {
  519. if (is_int($jF)) {
  520. return $this->getMatrix(0, $j0, $this->m, $jF + 1);
  521. } else {
  522. return $this->getMatrix(0, $j0, $this->m, $j0 + 1);
  523. }
  524. } else {
  525. throw new Exception(JAMAError(ArgumentTypeException));
  526. }
  527. } // function getMatrixByCol()
  528. /**
  529. * transpose
  530. *
  531. * Tranpose matrix
  532. * @return Matrix Transposed matrix
  533. */
  534. public function transpose() {
  535. $R = new Matrix($this->n, $this->m);
  536. for($i = 0; $i < $this->m; ++$i) {
  537. for($j = 0; $j < $this->n; ++$j) {
  538. $R->set($j, $i, $this->A[$i][$j]);
  539. }
  540. }
  541. return $R;
  542. } // function transpose()
  543. /**
  544. * norm1
  545. *
  546. * One norm
  547. * @return float Maximum column sum
  548. */
  549. public function norm1() {
  550. $r = 0;
  551. for($j = 0; $j < $this->n; ++$j) {
  552. $s = 0;
  553. for($i = 0; $i < $this->m; ++$i) {
  554. $s += abs($this->A[$i][$j]);
  555. }
  556. $r = ($r > $s) ? $r : $s;
  557. }
  558. return $r;
  559. } // function norm1()
  560. /**
  561. * norm2
  562. *
  563. * Maximum singular value
  564. * @return float Maximum singular value
  565. */
  566. public function norm2() {
  567. } // function norm2()
  568. /**
  569. * normInf
  570. *
  571. * Infinite norm
  572. * @return float Maximum row sum
  573. */
  574. public function normInf() {
  575. $r = 0;
  576. for($i = 0; $i < $this->m; ++$i) {
  577. $s = 0;
  578. for($j = 0; $j < $this->n; ++$j) {
  579. $s += abs($this->A[$i][$j]);
  580. }
  581. $r = ($r > $s) ? $r : $s;
  582. }
  583. return $r;
  584. } // function normInf()
  585. /**
  586. * normF
  587. *
  588. * Frobenius norm
  589. * @return float Square root of the sum of all elements squared
  590. */
  591. public function normF() {
  592. $f = 0;
  593. for ($i = 0; $i < $this->m; ++$i) {
  594. for ($j = 0; $j < $this->n; ++$j) {
  595. $f = hypo($f,$this->A[$i][$j]);
  596. }
  597. }
  598. return $f;
  599. } // function normF()
  600. /**
  601. * Matrix rank
  602. *
  603. * @return effective numerical rank, obtained from SVD.
  604. */
  605. public function rank () {
  606. $svd = new SingularValueDecomposition($this);
  607. return $svd->rank();
  608. } // function rank ()
  609. /**
  610. * Matrix condition (2 norm)
  611. *
  612. * @return ratio of largest to smallest singular value.
  613. */
  614. public function cond () {
  615. $svd = new SingularValueDecomposition($this);
  616. return $svd->cond();
  617. } // function cond ()
  618. /**
  619. * trace
  620. *
  621. * Sum of diagonal elements
  622. * @return float Sum of diagonal elements
  623. */
  624. public function trace() {
  625. $s = 0;
  626. $n = min($this->m, $this->n);
  627. for($i = 0; $i < $n; ++$i) {
  628. $s += $this->A[$i][$i];
  629. }
  630. return $s;
  631. } // function trace()
  632. /**
  633. * uminus
  634. *
  635. * Unary minus matrix -A
  636. * @return Matrix Unary minus matrix
  637. */
  638. public function uminus() {
  639. } // function uminus()
  640. /**
  641. * plus
  642. *
  643. * A + B
  644. * @param mixed $B Matrix/Array
  645. * @return Matrix Sum
  646. */
  647. public function plus() {
  648. if (func_num_args() > 0) {
  649. $args = func_get_args();
  650. $match = implode(",", array_map('gettype', $args));
  651. switch($match) {
  652. case 'object':
  653. if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); }
  654. break;
  655. case 'array':
  656. $M = new Matrix($args[0]);
  657. break;
  658. default:
  659. throw new Exception(JAMAError(PolymorphicArgumentException));
  660. break;
  661. }
  662. $this->checkMatrixDimensions($M);
  663. for($i = 0; $i < $this->m; ++$i) {
  664. for($j = 0; $j < $this->n; ++$j) {
  665. $M->set($i, $j, $M->get($i, $j) + $this->A[$i][$j]);
  666. }
  667. }
  668. return $M;
  669. } else {
  670. throw new Exception(JAMAError(PolymorphicArgumentException));
  671. }
  672. } // function plus()
  673. /**
  674. * plusEquals
  675. *
  676. * A = A + B
  677. * @param mixed $B Matrix/Array
  678. * @return Matrix Sum
  679. */
  680. public function plusEquals() {
  681. if (func_num_args() > 0) {
  682. $args = func_get_args();
  683. $match = implode(",", array_map('gettype', $args));
  684. switch($match) {
  685. case 'object':
  686. if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); }
  687. break;
  688. case 'array':
  689. $M = new Matrix($args[0]);
  690. break;
  691. default:
  692. throw new Exception(JAMAError(PolymorphicArgumentException));
  693. break;
  694. }
  695. $this->checkMatrixDimensions($M);
  696. for($i = 0; $i < $this->m; ++$i) {
  697. for($j = 0; $j < $this->n; ++$j) {
  698. $validValues = True;
  699. $value = $M->get($i, $j);
  700. if ((is_string($this->A[$i][$j])) && (strlen($this->A[$i][$j]) > 0) && (!is_numeric($this->A[$i][$j]))) {
  701. $this->A[$i][$j] = trim($this->A[$i][$j],'"');
  702. $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($this->A[$i][$j]);
  703. }
  704. if ((is_string($value)) && (strlen($value) > 0) && (!is_numeric($value))) {
  705. $value = trim($value,'"');
  706. $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($value);
  707. }
  708. if ($validValues) {
  709. $this->A[$i][$j] += $value;
  710. } else {
  711. $this->A[$i][$j] = PHPExcel_Calculation_Functions::NaN();
  712. }
  713. }
  714. }
  715. return $this;
  716. } else {
  717. throw new Exception(JAMAError(PolymorphicArgumentException));
  718. }
  719. } // function plusEquals()
  720. /**
  721. * minus
  722. *
  723. * A - B
  724. * @param mixed $B Matrix/Array
  725. * @return Matrix Sum
  726. */
  727. public function minus() {
  728. if (func_num_args() > 0) {
  729. $args = func_get_args();
  730. $match = implode(",", array_map('gettype', $args));
  731. switch($match) {
  732. case 'object':
  733. if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); }
  734. break;
  735. case 'array':
  736. $M = new Matrix($args[0]);
  737. break;
  738. default:
  739. throw new Exception(JAMAError(PolymorphicArgumentException));
  740. break;
  741. }
  742. $this->checkMatrixDimensions($M);
  743. for($i = 0; $i < $this->m; ++$i) {
  744. for($j = 0; $j < $this->n; ++$j) {
  745. $M->set($i, $j, $M->get($i, $j) - $this->A[$i][$j]);
  746. }
  747. }
  748. return $M;
  749. } else {
  750. throw new Exception(JAMAError(PolymorphicArgumentException));
  751. }
  752. } // function minus()
  753. /**
  754. * minusEquals
  755. *
  756. * A = A - B
  757. * @param mixed $B Matrix/Array
  758. * @return Matrix Sum
  759. */
  760. public function minusEquals() {
  761. if (func_num_args() > 0) {
  762. $args = func_get_args();
  763. $match = implode(",", array_map('gettype', $args));
  764. switch($match) {
  765. case 'object':
  766. if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); }
  767. break;
  768. case 'array':
  769. $M = new Matrix($args[0]);
  770. break;
  771. default:
  772. throw new Exception(JAMAError(PolymorphicArgumentException));
  773. break;
  774. }
  775. $this->checkMatrixDimensions($M);
  776. for($i = 0; $i < $this->m; ++$i) {
  777. for($j = 0; $j < $this->n; ++$j) {
  778. $validValues = True;
  779. $value = $M->get($i, $j);
  780. if ((is_string($this->A[$i][$j])) && (strlen($this->A[$i][$j]) > 0) && (!is_numeric($this->A[$i][$j]))) {
  781. $this->A[$i][$j] = trim($this->A[$i][$j],'"');
  782. $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($this->A[$i][$j]);
  783. }
  784. if ((is_string($value)) && (strlen($value) > 0) && (!is_numeric($value))) {
  785. $value = trim($value,'"');
  786. $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($value);
  787. }
  788. if ($validValues) {
  789. $this->A[$i][$j] -= $value;
  790. } else {
  791. $this->A[$i][$j] = PHPExcel_Calculation_Functions::NaN();
  792. }
  793. }
  794. }
  795. return $this;
  796. } else {
  797. throw new Exception(JAMAError(PolymorphicArgumentException));
  798. }
  799. } // function minusEquals()
  800. /**
  801. * arrayTimes
  802. *
  803. * Element-by-element multiplication
  804. * Cij = Aij * Bij
  805. * @param mixed $B Matrix/Array
  806. * @return Matrix Matrix Cij
  807. */
  808. public function arrayTimes() {
  809. if (func_num_args() > 0) {
  810. $args = func_get_args();
  811. $match = implode(",", array_map('gettype', $args));
  812. switch($match) {
  813. case 'object':
  814. if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); }
  815. break;
  816. case 'array':
  817. $M = new Matrix($args[0]);
  818. break;
  819. default:
  820. throw new Exception(JAMAError(PolymorphicArgumentException));
  821. break;
  822. }
  823. $this->checkMatrixDimensions($M);
  824. for($i = 0; $i < $this->m; ++$i) {
  825. for($j = 0; $j < $this->n; ++$j) {
  826. $M->set($i, $j, $M->get($i, $j) * $this->A[$i][$j]);
  827. }
  828. }
  829. return $M;
  830. } else {
  831. throw new Exception(JAMAError(PolymorphicArgumentException));
  832. }
  833. } // function arrayTimes()
  834. /**
  835. * arrayTimesEquals
  836. *
  837. * Element-by-element multiplication
  838. * Aij = Aij * Bij
  839. * @param mixed $B Matrix/Array
  840. * @return Matrix Matrix Aij
  841. */
  842. public function arrayTimesEquals() {
  843. if (func_num_args() > 0) {
  844. $args = func_get_args();
  845. $match = implode(",", array_map('gettype', $args));
  846. switch($match) {
  847. case 'object':
  848. if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); }
  849. break;
  850. case 'array':
  851. $M = new Matrix($args[0]);
  852. break;
  853. default:
  854. throw new Exception(JAMAError(PolymorphicArgumentException));
  855. break;
  856. }
  857. $this->checkMatrixDimensions($M);
  858. for($i = 0; $i < $this->m; ++$i) {
  859. for($j = 0; $j < $this->n; ++$j) {
  860. $validValues = True;
  861. $value = $M->get($i, $j);
  862. if ((is_string($this->A[$i][$j])) && (strlen($this->A[$i][$j]) > 0) && (!is_numeric($this->A[$i][$j]))) {
  863. $this->A[$i][$j] = trim($this->A[$i][$j],'"');
  864. $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($this->A[$i][$j]);
  865. }
  866. if ((is_string($value)) && (strlen($value) > 0) && (!is_numeric($value))) {
  867. $value = trim($value,'"');
  868. $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($value);
  869. }
  870. if ($validValues) {
  871. $this->A[$i][$j] *= $value;
  872. } else {
  873. $this->A[$i][$j] = PHPExcel_Calculation_Functions::NaN();
  874. }
  875. }
  876. }
  877. return $this;
  878. } else {
  879. throw new Exception(JAMAError(PolymorphicArgumentException));
  880. }
  881. } // function arrayTimesEquals()
  882. /**
  883. * arrayRightDivide
  884. *
  885. * Element-by-element right division
  886. * A / B
  887. * @param Matrix $B Matrix B
  888. * @return Matrix Division result
  889. */
  890. public function arrayRightDivide() {
  891. if (func_num_args() > 0) {
  892. $args = func_get_args();
  893. $match = implode(",", array_map('gettype', $args));
  894. switch($match) {
  895. case 'object':
  896. if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); }
  897. break;
  898. case 'array':
  899. $M = new Matrix($args[0]);
  900. break;
  901. default:
  902. throw new Exception(JAMAError(PolymorphicArgumentException));
  903. break;
  904. }
  905. $this->checkMatrixDimensions($M);
  906. for($i = 0; $i < $this->m; ++$i) {
  907. for($j = 0; $j < $this->n; ++$j) {
  908. $validValues = True;
  909. $value = $M->get($i, $j);
  910. if ((is_string($this->A[$i][$j])) && (strlen($this->A[$i][$j]) > 0) && (!is_numeric($this->A[$i][$j]))) {
  911. $this->A[$i][$j] = trim($this->A[$i][$j],'"');
  912. $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($this->A[$i][$j]);
  913. }
  914. if ((is_string($value)) && (strlen($value) > 0) && (!is_numeric($value))) {
  915. $value = trim($value,'"');
  916. $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($value);
  917. }
  918. if ($validValues) {
  919. if ($value == 0) {
  920. // Trap for Divide by Zero error
  921. $M->set($i, $j, '#DIV/0!');
  922. } else {
  923. $M->set($i, $j, $this->A[$i][$j] / $value);
  924. }
  925. } else {
  926. $this->A[$i][$j] = PHPExcel_Calculation_Functions::NaN();
  927. }
  928. }
  929. }
  930. return $M;
  931. } else {
  932. throw new Exception(JAMAError(PolymorphicArgumentException));
  933. }
  934. } // function arrayRightDivide()
  935. /**
  936. * arrayRightDivideEquals
  937. *
  938. * Element-by-element right division
  939. * Aij = Aij / Bij
  940. * @param mixed $B Matrix/Array
  941. * @return Matrix Matrix Aij
  942. */
  943. public function arrayRightDivideEquals() {
  944. if (func_num_args() > 0) {
  945. $args = func_get_args();
  946. $match = implode(",", array_map('gettype', $args));
  947. switch($match) {
  948. case 'object':
  949. if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); }
  950. break;
  951. case 'array':
  952. $M = new Matrix($args[0]);
  953. break;
  954. default:
  955. throw new Exception(JAMAError(PolymorphicArgumentException));
  956. break;
  957. }
  958. $this->checkMatrixDimensions($M);
  959. for($i = 0; $i < $this->m; ++$i) {
  960. for($j = 0; $j < $this->n; ++$j) {
  961. $this->A[$i][$j] = $this->A[$i][$j] / $M->get($i, $j);
  962. }
  963. }
  964. return $M;
  965. } else {
  966. throw new Exception(JAMAError(PolymorphicArgumentException));
  967. }
  968. } // function arrayRightDivideEquals()
  969. /**
  970. * arrayLeftDivide
  971. *
  972. * Element-by-element Left division
  973. * A / B
  974. * @param Matrix $B Matrix B
  975. * @return Matrix Division result
  976. */
  977. public function arrayLeftDivide() {
  978. if (func_num_args() > 0) {
  979. $args = func_get_args();
  980. $match = implode(",", array_map('gettype', $args));
  981. switch($match) {
  982. case 'object':
  983. if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); }
  984. break;
  985. case 'array':
  986. $M = new Matrix($args[0]);
  987. break;
  988. default:
  989. throw new Exception(JAMAError(PolymorphicArgumentException));
  990. break;
  991. }
  992. $this->checkMatrixDimensions($M);
  993. for($i = 0; $i < $this->m; ++$i) {
  994. for($j = 0; $j < $this->n; ++$j) {
  995. $M->set($i, $j, $M->get($i, $j) / $this->A[$i][$j]);
  996. }
  997. }
  998. return $M;
  999. } else {
  1000. throw new Exception(JAMAError(PolymorphicArgumentException));
  1001. }
  1002. } // function arrayLeftDivide()
  1003. /**
  1004. * arrayLeftDivideEquals
  1005. *
  1006. * Element-by-element Left division
  1007. * Aij = Aij / Bij
  1008. * @param mixed $B Matrix/Array
  1009. * @return Matrix Matrix Aij
  1010. */
  1011. public function arrayLeftDivideEquals() {
  1012. if (func_num_args() > 0) {
  1013. $args = func_get_args();
  1014. $match = implode(",", array_map('gettype', $args));
  1015. switch($match) {
  1016. case 'object':
  1017. if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); }
  1018. break;
  1019. case 'array':
  1020. $M = new Matrix($args[0]);
  1021. break;
  1022. default:
  1023. throw new Exception(JAMAError(PolymorphicArgumentException));
  1024. break;
  1025. }
  1026. $this->checkMatrixDimensions($M);
  1027. for($i = 0; $i < $this->m; ++$i) {
  1028. for($j = 0; $j < $this->n; ++$j) {
  1029. $this->A[$i][$j] = $M->get($i, $j) / $this->A[$i][$j];
  1030. }
  1031. }
  1032. return $M;
  1033. } else {
  1034. throw new Exception(JAMAError(PolymorphicArgumentException));
  1035. }
  1036. } // function arrayLeftDivideEquals()
  1037. /**
  1038. * times
  1039. *
  1040. * Matrix multiplication
  1041. * @param mixed $n Matrix/Array/Scalar
  1042. * @return Matrix Product
  1043. */
  1044. public function times() {
  1045. if (func_num_args() > 0) {
  1046. $args = func_get_args();
  1047. $match = implode(",", array_map('gettype', $args));
  1048. switch($match) {
  1049. case 'object':
  1050. if ($args[0] instanceof Matrix) { $B = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); }
  1051. if ($this->n == $B->m) {
  1052. $C = new Matrix($this->m, $B->n);
  1053. for($j = 0; $j < $B->n; ++$j) {
  1054. for ($k = 0; $k < $this->n; ++$k) {
  1055. $Bcolj[$k] = $B->A[$k][$j];
  1056. }
  1057. for($i = 0; $i < $this->m; ++$i) {
  1058. $Arowi = $this->A[$i];
  1059. $s = 0;
  1060. for($k = 0; $k < $this->n; ++$k) {
  1061. $s += $Arowi[$k] * $Bcolj[$k];
  1062. }
  1063. $C->A[$i][$j] = $s;
  1064. }
  1065. }
  1066. return $C;
  1067. } else {
  1068. throw new Exception(JAMAError(MatrixDimensionMismatch));
  1069. }
  1070. break;
  1071. case 'array':
  1072. $B = new Matrix($args[0]);
  1073. if ($this->n == $B->m) {
  1074. $C = new Matrix($this->m, $B->n);
  1075. for($i = 0; $i < $C->m; ++$i) {
  1076. for($j = 0; $j < $C->n; ++$j) {
  1077. $s = "0";
  1078. for($k = 0; $k < $C->n; ++$k) {
  1079. $s += $this->A[$i][$k] * $B->A[$k][$j];
  1080. }
  1081. $C->A[$i][$j] = $s;
  1082. }
  1083. }
  1084. return $C;
  1085. } else {
  1086. throw new Exception(JAMAError(MatrixDimensionMismatch));
  1087. }
  1088. return $M;
  1089. break;
  1090. case 'integer':
  1091. $C = new Matrix($this->A);
  1092. for($i = 0; $i < $C->m; ++$i) {
  1093. for($j = 0; $j < $C->n; ++$j) {
  1094. $C->A[$i][$j] *= $args[0];
  1095. }
  1096. }
  1097. return $C;
  1098. break;
  1099. case 'double':
  1100. $C = new Matrix($this->m, $this->n);
  1101. for($i = 0; $i < $C->m; ++$i) {
  1102. for($j = 0; $j < $C->n; ++$j) {
  1103. $C->A[$i][$j] = $args[0] * $this->A[$i][$j];
  1104. }
  1105. }
  1106. return $C;
  1107. break;
  1108. case 'float':
  1109. $C = new Matrix($this->A);
  1110. for($i = 0; $i < $C->m; ++$i) {
  1111. for($j = 0; $j < $C->n; ++$j) {
  1112. $C->A[$i][$j] *= $args[0];
  1113. }
  1114. }
  1115. return $C;
  1116. break;
  1117. default:
  1118. throw new Exception(JAMAError(PolymorphicArgumentException));
  1119. break;
  1120. }
  1121. } else {
  1122. throw new Exception(PolymorphicArgumentException);
  1123. }
  1124. } // function times()
  1125. /**
  1126. * power
  1127. *
  1128. * A = A ^ B
  1129. * @param mixed $B Matrix/Array
  1130. * @return Matrix Sum
  1131. */
  1132. public function power() {
  1133. if (func_num_args() > 0) {
  1134. $args = func_get_args();
  1135. $match = implode(",", array_map('gettype', $args));
  1136. switch($match) {
  1137. case 'object':
  1138. if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); }
  1139. break;
  1140. case 'array':
  1141. $M = new Matrix($args[0]);
  1142. break;
  1143. default:
  1144. throw new Exception(JAMAError(PolymorphicArgumentException));
  1145. break;
  1146. }
  1147. $this->checkMatrixDimensions($M);
  1148. for($i = 0; $i < $this->m; ++$i) {
  1149. for($j = 0; $j < $this->n; ++$j) {
  1150. $validValues = True;
  1151. $value = $M->get($i, $j);
  1152. if ((is_string($this->A[$i][$j])) && (strlen($this->A[$i][$j]) > 0) && (!is_numeric($this->A[$i][$j]))) {
  1153. $this->A[$i][$j] = trim($this->A[$i][$j],'"');
  1154. $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($this->A[$i][$j]);
  1155. }
  1156. if ((is_string($value)) && (strlen($value) > 0) && (!is_numeric($value))) {
  1157. $value = trim($value,'"');
  1158. $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($value);
  1159. }
  1160. if ($validValues) {
  1161. $this->A[$i][$j] = pow($this->A[$i][$j],$value);
  1162. } else {
  1163. $this->A[$i][$j] = PHPExcel_Calculation_Functions::NaN();
  1164. }
  1165. }
  1166. }
  1167. return $this;
  1168. } else {
  1169. throw new Exception(JAMAError(PolymorphicArgumentException));
  1170. }
  1171. } // function power()
  1172. /**
  1173. * concat
  1174. *
  1175. * A = A & B
  1176. * @param mixed $B Matrix/Array
  1177. * @return Matrix Sum
  1178. */
  1179. public function concat() {
  1180. if (func_num_args() > 0) {
  1181. $args = func_get_args();
  1182. $match = implode(",", array_map('gettype', $args));
  1183. switch($match) {
  1184. case 'object':
  1185. if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); }
  1186. case 'array':
  1187. $M = new Matrix($args[0]);
  1188. break;
  1189. default:
  1190. throw new Exception(JAMAError(PolymorphicArgumentException));
  1191. break;
  1192. }
  1193. $this->checkMatrixDimensions($M);
  1194. for($i = 0; $i < $this->m; ++$i) {
  1195. for($j = 0; $j < $this->n; ++$j) {
  1196. // $this->A[$i][$j] = '"'.trim($this->A[$i][$j],'"').trim($M->get($i, $j),'"').'"';
  1197. $this->A[$i][$j] = trim($this->A[$i][$j],'"').trim($M->get($i, $j),'"');
  1198. }
  1199. }
  1200. return $this;
  1201. } else {
  1202. throw new Exception(JAMAError(PolymorphicArgumentException));
  1203. }
  1204. } // function concat()
  1205. /**
  1206. * chol
  1207. *
  1208. * Cholesky decomposition
  1209. * @return Matrix Cholesky decomposition
  1210. */
  1211. public function chol() {
  1212. return new CholeskyDecomposition($this);
  1213. } // function chol()
  1214. /**
  1215. * lu
  1216. *
  1217. * LU decomposition
  1218. * @return Matrix LU decomposition
  1219. */
  1220. public function lu() {
  1221. return new LUDecomposition($this);
  1222. } // function lu()
  1223. /**
  1224. * qr
  1225. *
  1226. * QR decomposition
  1227. * @return Matrix QR decomposition
  1228. */
  1229. public function qr() {
  1230. return new QRDecomposition($this);
  1231. } // function qr()
  1232. /**
  1233. * eig
  1234. *
  1235. * Eigenvalue decomposition
  1236. * @return Matrix Eigenvalue decomposition
  1237. */
  1238. public function eig() {
  1239. return new EigenvalueDecomposition($this);
  1240. } // function eig()
  1241. /**
  1242. * svd
  1243. *
  1244. * Singular value decomposition
  1245. * @return Singular value decomposition
  1246. */
  1247. public function svd() {
  1248. return new SingularValueDecomposition($this);
  1249. } // function svd()
  1250. /**
  1251. * Solve A*X = B.
  1252. *
  1253. * @param Matrix $B Right hand side
  1254. * @return Matrix ... Solution if A is square, least squares solution otherwise
  1255. */
  1256. public function solve($B) {
  1257. if ($this->m == $this->n) {
  1258. $LU = new LUDecomposition($this);
  1259. return $LU->solve($B);
  1260. } else {
  1261. $QR = new QRDecomposition($this);
  1262. return $QR->solve($B);
  1263. }
  1264. } // function solve()
  1265. /**
  1266. * Matrix inverse or pseudoinverse.
  1267. *
  1268. * @return Matrix ... Inverse(A) if A is square, pseudoinverse otherwise.
  1269. */
  1270. public function inverse() {
  1271. return $this->solve($this->identity($this->m, $this->m));
  1272. } // function inverse()
  1273. /**
  1274. * det
  1275. *
  1276. * Calculate determinant
  1277. * @return float Determinant
  1278. */
  1279. public function det() {
  1280. $L = new LUDecomposition($this);
  1281. return $L->det();
  1282. } // function det()
  1283. /**
  1284. * Older debugging utility for backwards compatability.
  1285. *
  1286. * @return html version of matrix
  1287. */
  1288. public function mprint($A, $format="%01.2f", $width=2) {
  1289. $m = count($A);
  1290. $n = count($A[0]);
  1291. $spacing = str_repeat('&nbsp;',$width);
  1292. for ($i = 0; $i < $m; ++$i) {
  1293. for ($j = 0; $j < $n; ++$j) {
  1294. $formatted = sprintf($format, $A[$i][$j]);
  1295. echo $formatted.$spacing;
  1296. }
  1297. echo "<br />";
  1298. }
  1299. } // function mprint()
  1300. /**
  1301. * Debugging utility.
  1302. *
  1303. * @return Output HTML representation of matrix
  1304. */
  1305. public function toHTML($width=2) {
  1306. print('<table style="background-color:#eee;">');
  1307. for($i = 0; $i < $this->m; ++$i) {
  1308. print('<tr>');
  1309. for($j = 0; $j < $this->n; ++$j) {
  1310. print('<td style="background-color:#fff;border:1px solid #000;padding:2px;text-align:center;vertical-align:middle;">' . $this->A[$i][$j] . '</td>');
  1311. }
  1312. print('</tr>');
  1313. }
  1314. print('</table>');
  1315. } // function toHTML()
  1316. } // class Matrix