For God so loved the world, that He gave His only begotten Son, that all who believe in Him should not perish but have everlasting life
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1159 lines
40 KiB

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