Matrix.php 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159
  1. <?php
  2. /**
  3. * @package JAMA
  4. */
  5. /** PHPExcel root directory */
  6. if (!defined('PHPEXCEL_ROOT')) {
  7. /**
  8. * @ignore
  9. */
  10. define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../../');
  11. require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
  12. }
  13. /*
  14. * Matrix class
  15. *
  16. * @author Paul Meagher
  17. * @author Michael Bommarito
  18. * @author Lukasz Karapuda
  19. * @author Bartek Matosiuk
  20. * @version 1.8
  21. * @license PHP v3.0
  22. * @see http://math.nist.gov/javanumerics/jama/
  23. */
  24. class PHPExcel_Shared_JAMA_Matrix
  25. {
  26. const POLYMORPHIC_ARGUMENT_EXCEPTION = "Invalid argument pattern for polymorphic function.";
  27. const ARGUMENT_TYPE_EXCEPTION = "Invalid argument type.";
  28. const ARGUMENT_BOUNDS_EXCEPTION = "Invalid argument range.";
  29. const MATRIX_DIMENSION_EXCEPTION = "Matrix dimensions are not equal.";
  30. const ARRAY_LENGTH_EXCEPTION = "Array length must be a multiple of m.";
  31. /**
  32. * Matrix storage
  33. *
  34. * @var array
  35. * @access public
  36. */
  37. public $A = array();
  38. /**
  39. * Matrix row dimension
  40. *
  41. * @var int
  42. * @access private
  43. */
  44. private $m;
  45. /**
  46. * Matrix column dimension
  47. *
  48. * @var int
  49. * @access private
  50. */
  51. private $n;
  52. /**
  53. * Polymorphic constructor
  54. *
  55. * 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.
  56. */
  57. public function __construct()
  58. {
  59. if (func_num_args() > 0) {
  60. $args = func_get_args();
  61. $match = implode(",", array_map('gettype', $args));
  62. switch ($match) {
  63. //Rectangular matrix - m x n initialized from 2D array
  64. case 'array':
  65. $this->m = count($args[0]);
  66. $this->n = count($args[0][0]);
  67. $this->A = $args[0];
  68. break;
  69. //Square matrix - n x n
  70. case 'integer':
  71. $this->m = $args[0];
  72. $this->n = $args[0];
  73. $this->A = array_fill(0, $this->m, array_fill(0, $this->n, 0));
  74. break;
  75. //Rectangular matrix - m x n
  76. case 'integer,integer':
  77. $this->m = $args[0];
  78. $this->n = $args[1];
  79. $this->A = array_fill(0, $this->m, array_fill(0, $this->n, 0));
  80. break;
  81. //Rectangular matrix - m x n initialized from packed array
  82. case 'array,integer':
  83. $this->m = $args[1];
  84. if ($this->m != 0) {
  85. $this->n = count($args[0]) / $this->m;
  86. } else {
  87. $this->n = 0;
  88. }
  89. if (($this->m * $this->n) == count($args[0])) {
  90. for ($i = 0; $i < $this->m; ++$i) {
  91. for ($j = 0; $j < $this->n; ++$j) {
  92. $this->A[$i][$j] = $args[0][$i + $j * $this->m];
  93. }
  94. }
  95. } else {
  96. throw new PHPExcel_Calculation_Exception(self::ARRAY_LENGTH_EXCEPTION);
  97. }
  98. break;
  99. default:
  100. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  101. break;
  102. }
  103. } else {
  104. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  105. }
  106. }
  107. /**
  108. * getArray
  109. *
  110. * @return array Matrix array
  111. */
  112. public function getArray()
  113. {
  114. return $this->A;
  115. }
  116. /**
  117. * getRowDimension
  118. *
  119. * @return int Row dimension
  120. */
  121. public function getRowDimension()
  122. {
  123. return $this->m;
  124. }
  125. /**
  126. * getColumnDimension
  127. *
  128. * @return int Column dimension
  129. */
  130. public function getColumnDimension()
  131. {
  132. return $this->n;
  133. }
  134. /**
  135. * get
  136. *
  137. * Get the i,j-th element of the matrix.
  138. * @param int $i Row position
  139. * @param int $j Column position
  140. * @return mixed Element (int/float/double)
  141. */
  142. public function get($i = null, $j = null)
  143. {
  144. return $this->A[$i][$j];
  145. }
  146. /**
  147. * getMatrix
  148. *
  149. * Get a submatrix
  150. * @param int $i0 Initial row index
  151. * @param int $iF Final row index
  152. * @param int $j0 Initial column index
  153. * @param int $jF Final column index
  154. * @return Matrix Submatrix
  155. */
  156. public function getMatrix()
  157. {
  158. if (func_num_args() > 0) {
  159. $args = func_get_args();
  160. $match = implode(",", array_map('gettype', $args));
  161. switch ($match) {
  162. //A($i0...; $j0...)
  163. case 'integer,integer':
  164. list($i0, $j0) = $args;
  165. if ($i0 >= 0) {
  166. $m = $this->m - $i0;
  167. } else {
  168. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
  169. }
  170. if ($j0 >= 0) {
  171. $n = $this->n - $j0;
  172. } else {
  173. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
  174. }
  175. $R = new PHPExcel_Shared_JAMA_Matrix($m, $n);
  176. for ($i = $i0; $i < $this->m; ++$i) {
  177. for ($j = $j0; $j < $this->n; ++$j) {
  178. $R->set($i, $j, $this->A[$i][$j]);
  179. }
  180. }
  181. return $R;
  182. break;
  183. //A($i0...$iF; $j0...$jF)
  184. case 'integer,integer,integer,integer':
  185. list($i0, $iF, $j0, $jF) = $args;
  186. if (($iF > $i0) && ($this->m >= $iF) && ($i0 >= 0)) {
  187. $m = $iF - $i0;
  188. } else {
  189. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
  190. }
  191. if (($jF > $j0) && ($this->n >= $jF) && ($j0 >= 0)) {
  192. $n = $jF - $j0;
  193. } else {
  194. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
  195. }
  196. $R = new PHPExcel_Shared_JAMA_Matrix($m+1, $n+1);
  197. for ($i = $i0; $i <= $iF; ++$i) {
  198. for ($j = $j0; $j <= $jF; ++$j) {
  199. $R->set($i - $i0, $j - $j0, $this->A[$i][$j]);
  200. }
  201. }
  202. return $R;
  203. break;
  204. //$R = array of row indices; $C = array of column indices
  205. case 'array,array':
  206. list($RL, $CL) = $args;
  207. if (count($RL) > 0) {
  208. $m = count($RL);
  209. } else {
  210. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
  211. }
  212. if (count($CL) > 0) {
  213. $n = count($CL);
  214. } else {
  215. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
  216. }
  217. $R = new PHPExcel_Shared_JAMA_Matrix($m, $n);
  218. for ($i = 0; $i < $m; ++$i) {
  219. for ($j = 0; $j < $n; ++$j) {
  220. $R->set($i - $i0, $j - $j0, $this->A[$RL[$i]][$CL[$j]]);
  221. }
  222. }
  223. return $R;
  224. break;
  225. //$RL = array of row indices; $CL = array of column indices
  226. case 'array,array':
  227. list($RL, $CL) = $args;
  228. if (count($RL) > 0) {
  229. $m = count($RL);
  230. } else {
  231. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
  232. }
  233. if (count($CL) > 0) {
  234. $n = count($CL);
  235. } else {
  236. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
  237. }
  238. $R = new PHPExcel_Shared_JAMA_Matrix($m, $n);
  239. for ($i = 0; $i < $m; ++$i) {
  240. for ($j = 0; $j < $n; ++$j) {
  241. $R->set($i, $j, $this->A[$RL[$i]][$CL[$j]]);
  242. }
  243. }
  244. return $R;
  245. break;
  246. //A($i0...$iF); $CL = array of column indices
  247. case 'integer,integer,array':
  248. list($i0, $iF, $CL) = $args;
  249. if (($iF > $i0) && ($this->m >= $iF) && ($i0 >= 0)) {
  250. $m = $iF - $i0;
  251. } else {
  252. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
  253. }
  254. if (count($CL) > 0) {
  255. $n = count($CL);
  256. } else {
  257. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
  258. }
  259. $R = new PHPExcel_Shared_JAMA_Matrix($m, $n);
  260. for ($i = $i0; $i < $iF; ++$i) {
  261. for ($j = 0; $j < $n; ++$j) {
  262. $R->set($i - $i0, $j, $this->A[$RL[$i]][$j]);
  263. }
  264. }
  265. return $R;
  266. break;
  267. //$RL = array of row indices
  268. case 'array,integer,integer':
  269. list($RL, $j0, $jF) = $args;
  270. if (count($RL) > 0) {
  271. $m = count($RL);
  272. } else {
  273. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
  274. }
  275. if (($jF >= $j0) && ($this->n >= $jF) && ($j0 >= 0)) {
  276. $n = $jF - $j0;
  277. } else {
  278. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
  279. }
  280. $R = new PHPExcel_Shared_JAMA_Matrix($m, $n+1);
  281. for ($i = 0; $i < $m; ++$i) {
  282. for ($j = $j0; $j <= $jF; ++$j) {
  283. $R->set($i, $j - $j0, $this->A[$RL[$i]][$j]);
  284. }
  285. }
  286. return $R;
  287. break;
  288. default:
  289. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  290. break;
  291. }
  292. } else {
  293. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  294. }
  295. }
  296. /**
  297. * checkMatrixDimensions
  298. *
  299. * Is matrix B the same size?
  300. * @param Matrix $B Matrix B
  301. * @return boolean
  302. */
  303. public function checkMatrixDimensions($B = null)
  304. {
  305. if ($B instanceof PHPExcel_Shared_JAMA_Matrix) {
  306. if (($this->m == $B->getRowDimension()) && ($this->n == $B->getColumnDimension())) {
  307. return true;
  308. } else {
  309. throw new PHPExcel_Calculation_Exception(self::MATRIX_DIMENSION_EXCEPTION);
  310. }
  311. } else {
  312. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
  313. }
  314. } // function checkMatrixDimensions()
  315. /**
  316. * set
  317. *
  318. * Set the i,j-th element of the matrix.
  319. * @param int $i Row position
  320. * @param int $j Column position
  321. * @param mixed $c Int/float/double value
  322. * @return mixed Element (int/float/double)
  323. */
  324. public function set($i = null, $j = null, $c = null)
  325. {
  326. // Optimized set version just has this
  327. $this->A[$i][$j] = $c;
  328. } // function set()
  329. /**
  330. * identity
  331. *
  332. * Generate an identity matrix.
  333. * @param int $m Row dimension
  334. * @param int $n Column dimension
  335. * @return Matrix Identity matrix
  336. */
  337. public function identity($m = null, $n = null)
  338. {
  339. return $this->diagonal($m, $n, 1);
  340. }
  341. /**
  342. * diagonal
  343. *
  344. * Generate a diagonal matrix
  345. * @param int $m Row dimension
  346. * @param int $n Column dimension
  347. * @param mixed $c Diagonal value
  348. * @return Matrix Diagonal matrix
  349. */
  350. public function diagonal($m = null, $n = null, $c = 1)
  351. {
  352. $R = new PHPExcel_Shared_JAMA_Matrix($m, $n);
  353. for ($i = 0; $i < $m; ++$i) {
  354. $R->set($i, $i, $c);
  355. }
  356. return $R;
  357. }
  358. /**
  359. * getMatrixByRow
  360. *
  361. * Get a submatrix by row index/range
  362. * @param int $i0 Initial row index
  363. * @param int $iF Final row index
  364. * @return Matrix Submatrix
  365. */
  366. public function getMatrixByRow($i0 = null, $iF = null)
  367. {
  368. if (is_int($i0)) {
  369. if (is_int($iF)) {
  370. return $this->getMatrix($i0, 0, $iF + 1, $this->n);
  371. } else {
  372. return $this->getMatrix($i0, 0, $i0 + 1, $this->n);
  373. }
  374. } else {
  375. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
  376. }
  377. }
  378. /**
  379. * getMatrixByCol
  380. *
  381. * Get a submatrix by column index/range
  382. * @param int $i0 Initial column index
  383. * @param int $iF Final column index
  384. * @return Matrix Submatrix
  385. */
  386. public function getMatrixByCol($j0 = null, $jF = null)
  387. {
  388. if (is_int($j0)) {
  389. if (is_int($jF)) {
  390. return $this->getMatrix(0, $j0, $this->m, $jF + 1);
  391. } else {
  392. return $this->getMatrix(0, $j0, $this->m, $j0 + 1);
  393. }
  394. } else {
  395. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
  396. }
  397. }
  398. /**
  399. * transpose
  400. *
  401. * Tranpose matrix
  402. * @return Matrix Transposed matrix
  403. */
  404. public function transpose()
  405. {
  406. $R = new PHPExcel_Shared_JAMA_Matrix($this->n, $this->m);
  407. for ($i = 0; $i < $this->m; ++$i) {
  408. for ($j = 0; $j < $this->n; ++$j) {
  409. $R->set($j, $i, $this->A[$i][$j]);
  410. }
  411. }
  412. return $R;
  413. } // function transpose()
  414. /**
  415. * trace
  416. *
  417. * Sum of diagonal elements
  418. * @return float Sum of diagonal elements
  419. */
  420. public function trace()
  421. {
  422. $s = 0;
  423. $n = min($this->m, $this->n);
  424. for ($i = 0; $i < $n; ++$i) {
  425. $s += $this->A[$i][$i];
  426. }
  427. return $s;
  428. }
  429. /**
  430. * uminus
  431. *
  432. * Unary minus matrix -A
  433. * @return Matrix Unary minus matrix
  434. */
  435. public function uminus()
  436. {
  437. }
  438. /**
  439. * plus
  440. *
  441. * A + B
  442. * @param mixed $B Matrix/Array
  443. * @return Matrix Sum
  444. */
  445. public function plus()
  446. {
  447. if (func_num_args() > 0) {
  448. $args = func_get_args();
  449. $match = implode(",", array_map('gettype', $args));
  450. switch ($match) {
  451. case 'object':
  452. if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
  453. $M = $args[0];
  454. } else {
  455. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
  456. }
  457. break;
  458. case 'array':
  459. $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
  460. break;
  461. default:
  462. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  463. break;
  464. }
  465. $this->checkMatrixDimensions($M);
  466. for ($i = 0; $i < $this->m; ++$i) {
  467. for ($j = 0; $j < $this->n; ++$j) {
  468. $M->set($i, $j, $M->get($i, $j) + $this->A[$i][$j]);
  469. }
  470. }
  471. return $M;
  472. } else {
  473. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  474. }
  475. }
  476. /**
  477. * plusEquals
  478. *
  479. * A = A + B
  480. * @param mixed $B Matrix/Array
  481. * @return Matrix Sum
  482. */
  483. public function plusEquals()
  484. {
  485. if (func_num_args() > 0) {
  486. $args = func_get_args();
  487. $match = implode(",", array_map('gettype', $args));
  488. switch ($match) {
  489. case 'object':
  490. if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
  491. $M = $args[0];
  492. } else {
  493. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
  494. }
  495. break;
  496. case 'array':
  497. $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
  498. break;
  499. default:
  500. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  501. break;
  502. }
  503. $this->checkMatrixDimensions($M);
  504. for ($i = 0; $i < $this->m; ++$i) {
  505. for ($j = 0; $j < $this->n; ++$j) {
  506. $validValues = true;
  507. $value = $M->get($i, $j);
  508. if ((is_string($this->A[$i][$j])) && (strlen($this->A[$i][$j]) > 0) && (!is_numeric($this->A[$i][$j]))) {
  509. $this->A[$i][$j] = trim($this->A[$i][$j], '"');
  510. $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($this->A[$i][$j]);
  511. }
  512. if ((is_string($value)) && (strlen($value) > 0) && (!is_numeric($value))) {
  513. $value = trim($value, '"');
  514. $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($value);
  515. }
  516. if ($validValues) {
  517. $this->A[$i][$j] += $value;
  518. } else {
  519. $this->A[$i][$j] = PHPExcel_Calculation_Functions::NaN();
  520. }
  521. }
  522. }
  523. return $this;
  524. } else {
  525. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  526. }
  527. }
  528. /**
  529. * minus
  530. *
  531. * A - B
  532. * @param mixed $B Matrix/Array
  533. * @return Matrix Sum
  534. */
  535. public function minus()
  536. {
  537. if (func_num_args() > 0) {
  538. $args = func_get_args();
  539. $match = implode(",", array_map('gettype', $args));
  540. switch ($match) {
  541. case 'object':
  542. if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
  543. $M = $args[0];
  544. } else {
  545. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
  546. }
  547. break;
  548. case 'array':
  549. $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
  550. break;
  551. default:
  552. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  553. break;
  554. }
  555. $this->checkMatrixDimensions($M);
  556. for ($i = 0; $i < $this->m; ++$i) {
  557. for ($j = 0; $j < $this->n; ++$j) {
  558. $M->set($i, $j, $M->get($i, $j) - $this->A[$i][$j]);
  559. }
  560. }
  561. return $M;
  562. } else {
  563. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  564. }
  565. }
  566. /**
  567. * minusEquals
  568. *
  569. * A = A - B
  570. * @param mixed $B Matrix/Array
  571. * @return Matrix Sum
  572. */
  573. public function minusEquals()
  574. {
  575. if (func_num_args() > 0) {
  576. $args = func_get_args();
  577. $match = implode(",", array_map('gettype', $args));
  578. switch ($match) {
  579. case 'object':
  580. if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
  581. $M = $args[0];
  582. } else {
  583. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
  584. }
  585. break;
  586. case 'array':
  587. $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
  588. break;
  589. default:
  590. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  591. break;
  592. }
  593. $this->checkMatrixDimensions($M);
  594. for ($i = 0; $i < $this->m; ++$i) {
  595. for ($j = 0; $j < $this->n; ++$j) {
  596. $validValues = true;
  597. $value = $M->get($i, $j);
  598. if ((is_string($this->A[$i][$j])) && (strlen($this->A[$i][$j]) > 0) && (!is_numeric($this->A[$i][$j]))) {
  599. $this->A[$i][$j] = trim($this->A[$i][$j], '"');
  600. $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($this->A[$i][$j]);
  601. }
  602. if ((is_string($value)) && (strlen($value) > 0) && (!is_numeric($value))) {
  603. $value = trim($value, '"');
  604. $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($value);
  605. }
  606. if ($validValues) {
  607. $this->A[$i][$j] -= $value;
  608. } else {
  609. $this->A[$i][$j] = PHPExcel_Calculation_Functions::NaN();
  610. }
  611. }
  612. }
  613. return $this;
  614. } else {
  615. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  616. }
  617. }
  618. /**
  619. * arrayTimes
  620. *
  621. * Element-by-element multiplication
  622. * Cij = Aij * Bij
  623. * @param mixed $B Matrix/Array
  624. * @return Matrix Matrix Cij
  625. */
  626. public function arrayTimes()
  627. {
  628. if (func_num_args() > 0) {
  629. $args = func_get_args();
  630. $match = implode(",", array_map('gettype', $args));
  631. switch ($match) {
  632. case 'object':
  633. if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
  634. $M = $args[0];
  635. } else {
  636. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
  637. }
  638. break;
  639. case 'array':
  640. $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
  641. break;
  642. default:
  643. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  644. break;
  645. }
  646. $this->checkMatrixDimensions($M);
  647. for ($i = 0; $i < $this->m; ++$i) {
  648. for ($j = 0; $j < $this->n; ++$j) {
  649. $M->set($i, $j, $M->get($i, $j) * $this->A[$i][$j]);
  650. }
  651. }
  652. return $M;
  653. } else {
  654. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  655. }
  656. }
  657. /**
  658. * arrayTimesEquals
  659. *
  660. * Element-by-element multiplication
  661. * Aij = Aij * Bij
  662. * @param mixed $B Matrix/Array
  663. * @return Matrix Matrix Aij
  664. */
  665. public function arrayTimesEquals()
  666. {
  667. if (func_num_args() > 0) {
  668. $args = func_get_args();
  669. $match = implode(",", array_map('gettype', $args));
  670. switch ($match) {
  671. case 'object':
  672. if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
  673. $M = $args[0];
  674. } else {
  675. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
  676. }
  677. break;
  678. case 'array':
  679. $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
  680. break;
  681. default:
  682. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  683. break;
  684. }
  685. $this->checkMatrixDimensions($M);
  686. for ($i = 0; $i < $this->m; ++$i) {
  687. for ($j = 0; $j < $this->n; ++$j) {
  688. $validValues = true;
  689. $value = $M->get($i, $j);
  690. if ((is_string($this->A[$i][$j])) && (strlen($this->A[$i][$j]) > 0) && (!is_numeric($this->A[$i][$j]))) {
  691. $this->A[$i][$j] = trim($this->A[$i][$j], '"');
  692. $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($this->A[$i][$j]);
  693. }
  694. if ((is_string($value)) && (strlen($value) > 0) && (!is_numeric($value))) {
  695. $value = trim($value, '"');
  696. $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($value);
  697. }
  698. if ($validValues) {
  699. $this->A[$i][$j] *= $value;
  700. } else {
  701. $this->A[$i][$j] = PHPExcel_Calculation_Functions::NaN();
  702. }
  703. }
  704. }
  705. return $this;
  706. } else {
  707. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  708. }
  709. }
  710. /**
  711. * arrayRightDivide
  712. *
  713. * Element-by-element right division
  714. * A / B
  715. * @param Matrix $B Matrix B
  716. * @return Matrix Division result
  717. */
  718. public function arrayRightDivide()
  719. {
  720. if (func_num_args() > 0) {
  721. $args = func_get_args();
  722. $match = implode(",", array_map('gettype', $args));
  723. switch ($match) {
  724. case 'object':
  725. if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
  726. $M = $args[0];
  727. } else {
  728. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
  729. }
  730. break;
  731. case 'array':
  732. $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
  733. break;
  734. default:
  735. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  736. break;
  737. }
  738. $this->checkMatrixDimensions($M);
  739. for ($i = 0; $i < $this->m; ++$i) {
  740. for ($j = 0; $j < $this->n; ++$j) {
  741. $validValues = true;
  742. $value = $M->get($i, $j);
  743. if ((is_string($this->A[$i][$j])) && (strlen($this->A[$i][$j]) > 0) && (!is_numeric($this->A[$i][$j]))) {
  744. $this->A[$i][$j] = trim($this->A[$i][$j], '"');
  745. $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($this->A[$i][$j]);
  746. }
  747. if ((is_string($value)) && (strlen($value) > 0) && (!is_numeric($value))) {
  748. $value = trim($value, '"');
  749. $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($value);
  750. }
  751. if ($validValues) {
  752. if ($value == 0) {
  753. // Trap for Divide by Zero error
  754. $M->set($i, $j, '#DIV/0!');
  755. } else {
  756. $M->set($i, $j, $this->A[$i][$j] / $value);
  757. }
  758. } else {
  759. $M->set($i, $j, PHPExcel_Calculation_Functions::NaN());
  760. }
  761. }
  762. }
  763. return $M;
  764. } else {
  765. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  766. }
  767. }
  768. /**
  769. * arrayRightDivideEquals
  770. *
  771. * Element-by-element right division
  772. * Aij = Aij / Bij
  773. * @param mixed $B Matrix/Array
  774. * @return Matrix Matrix Aij
  775. */
  776. public function arrayRightDivideEquals()
  777. {
  778. if (func_num_args() > 0) {
  779. $args = func_get_args();
  780. $match = implode(",", array_map('gettype', $args));
  781. switch ($match) {
  782. case 'object':
  783. if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
  784. $M = $args[0];
  785. } else {
  786. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
  787. }
  788. break;
  789. case 'array':
  790. $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
  791. break;
  792. default:
  793. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  794. break;
  795. }
  796. $this->checkMatrixDimensions($M);
  797. for ($i = 0; $i < $this->m; ++$i) {
  798. for ($j = 0; $j < $this->n; ++$j) {
  799. $this->A[$i][$j] = $this->A[$i][$j] / $M->get($i, $j);
  800. }
  801. }
  802. return $M;
  803. } else {
  804. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  805. }
  806. }
  807. /**
  808. * arrayLeftDivide
  809. *
  810. * Element-by-element Left division
  811. * A / B
  812. * @param Matrix $B Matrix B
  813. * @return Matrix Division result
  814. */
  815. public function arrayLeftDivide()
  816. {
  817. if (func_num_args() > 0) {
  818. $args = func_get_args();
  819. $match = implode(",", array_map('gettype', $args));
  820. switch ($match) {
  821. case 'object':
  822. if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
  823. $M = $args[0];
  824. } else {
  825. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
  826. }
  827. break;
  828. case 'array':
  829. $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
  830. break;
  831. default:
  832. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  833. break;
  834. }
  835. $this->checkMatrixDimensions($M);
  836. for ($i = 0; $i < $this->m; ++$i) {
  837. for ($j = 0; $j < $this->n; ++$j) {
  838. $M->set($i, $j, $M->get($i, $j) / $this->A[$i][$j]);
  839. }
  840. }
  841. return $M;
  842. } else {
  843. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  844. }
  845. }
  846. /**
  847. * arrayLeftDivideEquals
  848. *
  849. * Element-by-element Left division
  850. * Aij = Aij / Bij
  851. * @param mixed $B Matrix/Array
  852. * @return Matrix Matrix Aij
  853. */
  854. public function arrayLeftDivideEquals()
  855. {
  856. if (func_num_args() > 0) {
  857. $args = func_get_args();
  858. $match = implode(",", array_map('gettype', $args));
  859. switch ($match) {
  860. case 'object':
  861. if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
  862. $M = $args[0];
  863. } else {
  864. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
  865. }
  866. break;
  867. case 'array':
  868. $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
  869. break;
  870. default:
  871. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  872. break;
  873. }
  874. $this->checkMatrixDimensions($M);
  875. for ($i = 0; $i < $this->m; ++$i) {
  876. for ($j = 0; $j < $this->n; ++$j) {
  877. $this->A[$i][$j] = $M->get($i, $j) / $this->A[$i][$j];
  878. }
  879. }
  880. return $M;
  881. } else {
  882. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  883. }
  884. }
  885. /**
  886. * times
  887. *
  888. * Matrix multiplication
  889. * @param mixed $n Matrix/Array/Scalar
  890. * @return Matrix Product
  891. */
  892. public function times()
  893. {
  894. if (func_num_args() > 0) {
  895. $args = func_get_args();
  896. $match = implode(",", array_map('gettype', $args));
  897. switch ($match) {
  898. case 'object':
  899. if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
  900. $B = $args[0];
  901. } else {
  902. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
  903. }
  904. if ($this->n == $B->m) {
  905. $C = new PHPExcel_Shared_JAMA_Matrix($this->m, $B->n);
  906. for ($j = 0; $j < $B->n; ++$j) {
  907. for ($k = 0; $k < $this->n; ++$k) {
  908. $Bcolj[$k] = $B->A[$k][$j];
  909. }
  910. for ($i = 0; $i < $this->m; ++$i) {
  911. $Arowi = $this->A[$i];
  912. $s = 0;
  913. for ($k = 0; $k < $this->n; ++$k) {
  914. $s += $Arowi[$k] * $Bcolj[$k];
  915. }
  916. $C->A[$i][$j] = $s;
  917. }
  918. }
  919. return $C;
  920. } else {
  921. throw new PHPExcel_Calculation_Exception(JAMAError(MatrixDimensionMismatch));
  922. }
  923. break;
  924. case 'array':
  925. $B = new PHPExcel_Shared_JAMA_Matrix($args[0]);
  926. if ($this->n == $B->m) {
  927. $C = new PHPExcel_Shared_JAMA_Matrix($this->m, $B->n);
  928. for ($i = 0; $i < $C->m; ++$i) {
  929. for ($j = 0; $j < $C->n; ++$j) {
  930. $s = "0";
  931. for ($k = 0; $k < $C->n; ++$k) {
  932. $s += $this->A[$i][$k] * $B->A[$k][$j];
  933. }
  934. $C->A[$i][$j] = $s;
  935. }
  936. }
  937. return $C;
  938. } else {
  939. throw new PHPExcel_Calculation_Exception(JAMAError(MatrixDimensionMismatch));
  940. }
  941. return $M;
  942. break;
  943. case 'integer':
  944. $C = new PHPExcel_Shared_JAMA_Matrix($this->A);
  945. for ($i = 0; $i < $C->m; ++$i) {
  946. for ($j = 0; $j < $C->n; ++$j) {
  947. $C->A[$i][$j] *= $args[0];
  948. }
  949. }
  950. return $C;
  951. break;
  952. case 'double':
  953. $C = new PHPExcel_Shared_JAMA_Matrix($this->m, $this->n);
  954. for ($i = 0; $i < $C->m; ++$i) {
  955. for ($j = 0; $j < $C->n; ++$j) {
  956. $C->A[$i][$j] = $args[0] * $this->A[$i][$j];
  957. }
  958. }
  959. return $C;
  960. break;
  961. case 'float':
  962. $C = new PHPExcel_Shared_JAMA_Matrix($this->A);
  963. for ($i = 0; $i < $C->m; ++$i) {
  964. for ($j = 0; $j < $C->n; ++$j) {
  965. $C->A[$i][$j] *= $args[0];
  966. }
  967. }
  968. return $C;
  969. break;
  970. default:
  971. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  972. break;
  973. }
  974. } else {
  975. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  976. }
  977. }
  978. /**
  979. * power
  980. *
  981. * A = A ^ B
  982. * @param mixed $B Matrix/Array
  983. * @return Matrix Sum
  984. */
  985. public function power()
  986. {
  987. if (func_num_args() > 0) {
  988. $args = func_get_args();
  989. $match = implode(",", array_map('gettype', $args));
  990. switch ($match) {
  991. case 'object':
  992. if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
  993. $M = $args[0];
  994. } else {
  995. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
  996. }
  997. break;
  998. case 'array':
  999. $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
  1000. break;
  1001. default:
  1002. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  1003. break;
  1004. }
  1005. $this->checkMatrixDimensions($M);
  1006. for ($i = 0; $i < $this->m; ++$i) {
  1007. for ($j = 0; $j < $this->n; ++$j) {
  1008. $validValues = true;
  1009. $value = $M->get($i, $j);
  1010. if ((is_string($this->A[$i][$j])) && (strlen($this->A[$i][$j]) > 0) && (!is_numeric($this->A[$i][$j]))) {
  1011. $this->A[$i][$j] = trim($this->A[$i][$j], '"');
  1012. $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($this->A[$i][$j]);
  1013. }
  1014. if ((is_string($value)) && (strlen($value) > 0) && (!is_numeric($value))) {
  1015. $value = trim($value, '"');
  1016. $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($value);
  1017. }
  1018. if ($validValues) {
  1019. $this->A[$i][$j] = pow($this->A[$i][$j], $value);
  1020. } else {
  1021. $this->A[$i][$j] = PHPExcel_Calculation_Functions::NaN();
  1022. }
  1023. }
  1024. }
  1025. return $this;
  1026. } else {
  1027. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  1028. }
  1029. }
  1030. /**
  1031. * concat
  1032. *
  1033. * A = A & B
  1034. * @param mixed $B Matrix/Array
  1035. * @return Matrix Sum
  1036. */
  1037. public function concat()
  1038. {
  1039. if (func_num_args() > 0) {
  1040. $args = func_get_args();
  1041. $match = implode(",", array_map('gettype', $args));
  1042. switch ($match) {
  1043. case 'object':
  1044. if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
  1045. $M = $args[0];
  1046. } else {
  1047. throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
  1048. }
  1049. case 'array':
  1050. $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
  1051. break;
  1052. default:
  1053. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  1054. break;
  1055. }
  1056. $this->checkMatrixDimensions($M);
  1057. for ($i = 0; $i < $this->m; ++$i) {
  1058. for ($j = 0; $j < $this->n; ++$j) {
  1059. $this->A[$i][$j] = trim($this->A[$i][$j], '"').trim($M->get($i, $j), '"');
  1060. }
  1061. }
  1062. return $this;
  1063. } else {
  1064. throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
  1065. }
  1066. }
  1067. /**
  1068. * Solve A*X = B.
  1069. *
  1070. * @param Matrix $B Right hand side
  1071. * @return Matrix ... Solution if A is square, least squares solution otherwise
  1072. */
  1073. public function solve($B)
  1074. {
  1075. if ($this->m == $this->n) {
  1076. $LU = new PHPExcel_Shared_JAMA_LUDecomposition($this);
  1077. return $LU->solve($B);
  1078. } else {
  1079. $QR = new PHPExcel_Shared_JAMA_QRDecomposition($this);
  1080. return $QR->solve($B);
  1081. }
  1082. }
  1083. /**
  1084. * Matrix inverse or pseudoinverse.
  1085. *
  1086. * @return Matrix ... Inverse(A) if A is square, pseudoinverse otherwise.
  1087. */
  1088. public function inverse()
  1089. {
  1090. return $this->solve($this->identity($this->m, $this->m));
  1091. }
  1092. /**
  1093. * det
  1094. *
  1095. * Calculate determinant
  1096. * @return float Determinant
  1097. */
  1098. public function det()
  1099. {
  1100. $L = new PHPExcel_Shared_JAMA_LUDecomposition($this);
  1101. return $L->det();
  1102. }
  1103. }