Matrix.php 42 KB

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