Matrix.php 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160
  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. }