Matrix.php 29 KB

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