This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /* |
||
4 | MatLabPHP |
||
5 | @author: Patricio Tarantino |
||
6 | @description: Using vectors and matrix syntaxis as MatLab to work in PHP. |
||
7 | @start-date: Sept 2012 |
||
8 | */ |
||
9 | |||
10 | use \Malenki\Math\Stats\Stats; |
||
11 | |||
12 | namespace MatLabPHP; |
||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||
13 | |||
14 | class MatLabPHP |
||
15 | { |
||
16 | |||
17 | public function __construct() |
||
18 | { |
||
19 | bcscale(10); |
||
20 | } |
||
21 | |||
22 | // To Return Error Msgs in methods |
||
23 | private function errorMsg($msg) |
||
24 | { |
||
25 | $errorMsg = array( |
||
26 | 'BadFormat' => 'Bad Format', |
||
27 | 'NotNum' => 'Value in vector is not Numeric', |
||
28 | 'NotSameColsRows' => 'The cols in each row should be the same', |
||
29 | 'ArgsNum' => 'Arguments must be numeric' |
||
30 | ); |
||
31 | |||
32 | return $errorMsg[$msg]; |
||
33 | } |
||
34 | |||
35 | /** |
||
36 | * String to Vector: |
||
37 | * @desc: Transform a vector in the format of [1 2 3] to an array(1,2,3); |
||
38 | * @param: Number, Vector or Matrix. Ex: 1 or [1 2 3] or [1 2 ; 3 4] |
||
39 | * @return: Array of Number, Vector or Matrix to operate in the class. |
||
40 | */ |
||
41 | public function stringToVector($vector) |
||
42 | { |
||
43 | if (is_array($vector)) { |
||
44 | return $vector; |
||
45 | } elseif (is_numeric($vector)) { |
||
46 | return array($vector); |
||
47 | } else { |
||
48 | $vector = trim($vector); |
||
49 | |||
50 | if (strpos($vector, ";")) { // If there are a few rows, then it is a matrix |
||
51 | $rows = explode(";", $vector); |
||
52 | foreach ($rows as $key => $row) { |
||
53 | if ($key == 0) { |
||
54 | $row = substr($row, 1); |
||
55 | } elseif ($key == count($rows)-1) { |
||
56 | $row = substr($row, 0, -1); |
||
57 | } |
||
58 | $returnVector[] = $this->stringToVector("[".$row."]"); |
||
59 | } |
||
60 | // Array of the Matrix finished. We should check if it is consistent. |
||
61 | $cols = count($returnVector[0]); |
||
62 | foreach ($returnVector as $row) { |
||
63 | if (count($row) != $cols) { |
||
64 | return $this->errorMsg('NotSameColsRows'); |
||
65 | end(); |
||
66 | } |
||
67 | } |
||
68 | return $returnVector; |
||
69 | } elseif ($vector[0] != "[" || $vector[strlen($vector)-1] != "]") { // Checking good format of [ numbers ] |
||
70 | return $this->errorMsg('BadFormat'); |
||
71 | end(); |
||
72 | } else { |
||
73 | $vector = trim(substr($vector, 1, -1)); |
||
74 | $values = explode(" ", $vector); |
||
75 | foreach ($values as $value) { |
||
76 | if ($value != "") { |
||
77 | if (is_numeric(trim($value))) { |
||
78 | $vectorArray[] = trim($value); |
||
79 | } else { |
||
80 | return $this->errorMsg('NotNum'); |
||
81 | end(); |
||
82 | } |
||
83 | } |
||
84 | } |
||
85 | return $vectorArray; |
||
86 | } |
||
87 | } |
||
88 | } |
||
89 | |||
90 | /** |
||
91 | * Eye: |
||
92 | * @desc: Create the identity matrix; |
||
93 | * @param: cols and rows. |
||
94 | * @return: Eye matrix |
||
95 | */ |
||
96 | public function eye($cols, $rows = 'eq') |
||
97 | { |
||
98 | $rows = ($rows == 'eq')? trim($cols) : trim($rows); |
||
99 | $cols = trim($cols); |
||
100 | |||
101 | if (!is_numeric($cols) || !is_numeric($rows)) { |
||
102 | return $this->errorMsg('ArgsNum'); |
||
103 | end(); |
||
104 | } |
||
105 | |||
106 | $matrix = array(); |
||
107 | for ($c = 1; $c <= $cols; $c++) { |
||
108 | for ($r=1; $r<=$rows; $r++) { |
||
109 | $matrix[$c][$r] = ($c == $r)? '1' : '0'; |
||
110 | } |
||
111 | } |
||
112 | return $matrix; |
||
113 | |||
114 | |||
115 | } |
||
116 | |||
117 | /** |
||
118 | * Zeros: |
||
119 | * @desc: Create the a matrix of zeros; |
||
120 | * @param: cols and rows. |
||
121 | * @return: Zero matrix |
||
122 | */ |
||
123 | public function zeros($cols, $rows = 'eq') |
||
124 | { |
||
125 | $rows = ($rows == 'eq')? trim($cols) : trim($rows); |
||
126 | $cols = trim($cols); |
||
127 | |||
128 | if (!is_numeric($cols) || !is_numeric($rows)) { |
||
129 | return $this->errorMsg('ArgsNum'); |
||
130 | end(); |
||
131 | } |
||
132 | |||
133 | $matrix = array(); |
||
134 | for ($c=1; $c<=$cols; $c++) { |
||
135 | for ($r=1; $r<=$rows; $r++) { |
||
136 | $matrix[$c][$r] = '0'; |
||
137 | } |
||
138 | } |
||
139 | return $matrix; |
||
140 | |||
141 | |||
142 | } |
||
143 | |||
144 | /** |
||
145 | * Length |
||
146 | * @desc: Gives back the max between cols and rows of a matrix |
||
147 | * @param: vector or matrix |
||
148 | * @return: int |
||
149 | */ |
||
150 | public function length($vector, $ret = 0) |
||
151 | { |
||
152 | $vector = $this->stringToVector($vector); |
||
153 | if ($ret == 0) { |
||
154 | return max(count($vector), count($vector[1])); |
||
155 | } else { |
||
156 | $rows = (isset($sumA[1])) ? count($sumA[1]) : 1; |
||
157 | return array(count($vector),$rows); |
||
158 | } |
||
159 | } |
||
160 | |||
161 | /** |
||
162 | * Sum |
||
163 | * @desc: Sumes two matrix or vectors or numbers |
||
164 | * @param: two vector or matrix or numbers |
||
165 | * @return: result |
||
166 | */ |
||
167 | public function sum($sumA, $sumB) |
||
168 | { |
||
169 | $sumA = $this->stringToVector($sumA); |
||
170 | $sumB = $this->stringToVector($sumB); |
||
171 | $lengthA = $this->length($sumA, 1); |
||
172 | $lengthB = $this->length($sumB, 1); |
||
173 | |||
174 | if ($lengthA[0] != $lengthB[0] || $lengthA[1] != $lengthB[1]) { |
||
175 | return $this->errorMsg('NotSameColsRows'); |
||
176 | end(); |
||
177 | } |
||
178 | |||
179 | $cols = count($sumA); |
||
180 | $rows = (isset($sumA[1])) ? count($sumA[1]) : 1; |
||
181 | $matrix = array(); |
||
182 | |||
183 | for ($c = 0; $c < $cols; $c++) { |
||
184 | for ($r = 0; $r < $rows; $r++) { |
||
185 | $matrix[$c][$r] = ($sumA[$c][$r] + $sumB[$c][$r]); |
||
186 | } |
||
187 | } |
||
188 | return $matrix; |
||
189 | } |
||
190 | |||
191 | /** |
||
192 | * price2ret |
||
193 | * @desc: Convert prices to returns -- http://www.mathworks.com/help/econ/price2ret.html |
||
194 | * @param: vector with series price |
||
195 | * @return: vector with returns |
||
196 | */ |
||
197 | public function price2ret($seriesPrice) |
||
198 | { |
||
199 | $arr = new \ArrayIterator(); |
||
200 | |||
201 | foreach ($seriesPrice as $key => $value) { |
||
202 | if ($key == 0) { |
||
203 | $arr->offsetSet($value, null); |
||
204 | continue; |
||
205 | } |
||
206 | |||
207 | $priceD0 = $seriesPrice[$key - 1]; |
||
208 | $return = log($value/$priceD0); |
||
209 | |||
210 | $arr->offsetSet($value, $return); |
||
211 | } |
||
212 | |||
213 | return $arr->getArrayCopy(); |
||
214 | } |
||
215 | |||
216 | /** |
||
217 | * @desc: Maximum value of timeseries dat |
||
218 | * @ref: http://www.mathworks.com/help/matlab/ref/timeseries.max.html |
||
219 | * @param: float[] A array or matrix |
||
220 | * @return: float |
||
221 | */ |
||
222 | public function max($vector) |
||
223 | { |
||
224 | return true; |
||
225 | } |
||
226 | |||
227 | /** |
||
228 | * @desc: Minimum value of timeseries data |
||
229 | * @ref: http://www.mathworks.com/help/matlab/ref/timeseries.min.html |
||
230 | * @param: float[] A array or matrix |
||
231 | * @return: float |
||
232 | */ |
||
233 | public function min($vector) |
||
234 | { |
||
235 | return true; |
||
236 | } |
||
237 | |||
238 | /** |
||
239 | * @desc: Convert prices to returns |
||
240 | * @ref: https://nf.nci.org.au/facilities/software/Matlab/techdoc/ref/mean.html |
||
241 | * @param: float[] A array or matrix |
||
242 | * @return: float |
||
243 | */ |
||
244 | public function meanOld($array) |
||
245 | { |
||
246 | $average = array_sum($array) / count($array); |
||
247 | |||
248 | return $average; |
||
249 | } |
||
250 | |||
251 | /** |
||
252 | * @desc: Standard deviation of timeseries data |
||
253 | * @ref: http://www.mathworks.com/help/matlab/ref/timeseries.std.html |
||
254 | * @param: float[] A array or matrix |
||
255 | * @return: float |
||
256 | */ |
||
257 | public function std($array, $isSample = false) |
||
258 | { |
||
259 | return $this->stddev($array, $isSample); |
||
260 | } |
||
261 | |||
262 | /** |
||
263 | * General mathematical functions. |
||
264 | */ |
||
265 | public function mathArraySum($array, &$count = null) |
||
266 | { |
||
267 | $sum = '0'; |
||
268 | $count = '0'; |
||
269 | foreach($array as $value) { |
||
270 | if (is_numeric($value)) { |
||
271 | $sum = bcadd($sum, (string) $value); |
||
272 | $count = bcadd($count, '1'); |
||
273 | } |
||
274 | } |
||
275 | return $sum; |
||
276 | } |
||
277 | |||
278 | public function mathCount($array) |
||
279 | { |
||
280 | $c = '0'; |
||
281 | foreach($array as $value) { |
||
282 | if (is_numeric($value)) { |
||
283 | $c = bcadd($c, '1'); |
||
284 | } |
||
285 | } |
||
286 | return $c; |
||
287 | } |
||
288 | |||
289 | /** |
||
290 | * Calculate mean (simple arithmetic average). |
||
291 | * |
||
292 | * @param array $values |
||
293 | * @return string Mean |
||
294 | */ |
||
295 | public function mean(array $values) |
||
296 | { |
||
297 | $sum = $this->mathArraySum($values, $n); |
||
298 | return bcdiv($sum, $n); |
||
299 | } |
||
300 | |||
301 | /** |
||
302 | * Calculate median. |
||
303 | * |
||
304 | * @param array $values |
||
305 | * @return string Median value |
||
306 | */ |
||
307 | public function median(array $values) |
||
308 | { |
||
309 | $values = array_values(array_map('strval', $values)); |
||
310 | sort($values, SORT_NUMERIC); |
||
311 | $n = count($values); |
||
312 | // exact median |
||
313 | if (isset($values[$n/2])) { |
||
314 | return $values[$n/2]; |
||
315 | } |
||
316 | // average of two middle values |
||
317 | $m1 = ($n-1)/2; |
||
318 | $m2 = ($n+1)/2; |
||
319 | if (isset($values[$m1]) && isset($values[$m2])) { |
||
320 | return bcdiv(bcadd($values[$m1], $values[$m2]), '2'); |
||
321 | } |
||
322 | // best guess |
||
323 | $mrnd = (int) round($n/2, 0); |
||
324 | if (isset($values[$mrnd])) { |
||
325 | return $values[$mrnd]; |
||
326 | } |
||
327 | return null; |
||
328 | } |
||
329 | |||
330 | /** |
||
331 | * Calculate the sum of products. |
||
332 | * |
||
333 | * @param array $x_values |
||
334 | * @param array $y_values |
||
335 | * @return string Sum of products. |
||
336 | */ |
||
337 | public function sumxy(array $x_values, array $y_values) |
||
338 | { |
||
339 | $sum = '0'; |
||
340 | foreach($x_values as $i => $x) { |
||
341 | if (isset($y_values[$i])) { |
||
342 | $sum = bcadd($sum, bcmul($x, $y_values[$i])); |
||
343 | #$sum += $x * $y_values[$i]; |
||
344 | } |
||
345 | } |
||
346 | return (string) $sum; |
||
347 | } |
||
348 | |||
349 | /** |
||
350 | * Compute the sum of squares. |
||
351 | * |
||
352 | * @param array $values An array of values. |
||
353 | * @param null|scalar|array $values2 If null is given, squares each array value. |
||
354 | * If given a scalar value, squares the difference between each array value and |
||
355 | * the one given in $values2 (good for explained/regression SS). |
||
356 | * If given an array, squares the difference between betweeen each array value |
||
357 | * and the value in $values2 with matching key (good for residual SS). |
||
358 | * @return string Sum of all da squares. |
||
359 | */ |
||
360 | public function sos(array $values, $values2 = null) |
||
361 | { |
||
362 | if (isset($values2) && ! is_array($values2)) { |
||
363 | $values2 = array_fill_keys(array_keys($values), $values2); |
||
364 | } |
||
365 | $sum = '0'; |
||
366 | foreach ($values as $i => $val) { |
||
367 | if (! isset($values2)) { |
||
368 | $sum = bcadd($sum, bcpow($val, '2')); |
||
369 | #$sum += pow($val, 2); |
||
370 | } else if (isset($values2[$i])) { |
||
371 | $sum = bcadd($sum, bcpow(bcsub($val, $values2[$i]), '2')); |
||
372 | #$sum += pow($val - $values2[$i], 2); |
||
373 | } |
||
374 | } |
||
375 | return (string) $sum; |
||
376 | } |
||
377 | |||
378 | |||
379 | /** |
||
380 | * @desc: Variance of timeseries data |
||
381 | * @ref: http://www.mathworks.com/help/matlab/ref/timeseries.var.html |
||
382 | * @param: float[] A array or matrix |
||
383 | * @return: float |
||
384 | */ |
||
385 | /** |
||
386 | * Calculate variance. |
||
387 | * |
||
388 | * @param array $values |
||
389 | * @param boolean $isSample Default false. |
||
390 | * @return string Variance of the values. |
||
391 | */ |
||
392 | public function variance(array $values, $isSample = false) |
||
393 | { |
||
394 | if ($isSample) { |
||
395 | // = SOS(r) / (COUNT(s) - 1) |
||
396 | return bcdiv($this->sos($values, $this->mean($values)), |
||
397 | bcsub($this->mathCount($values), '1') |
||
398 | ); |
||
399 | } |
||
400 | return $this->covariance($values, $values); |
||
401 | } |
||
402 | |||
403 | /** |
||
404 | * Compute standard deviation. |
||
405 | * |
||
406 | * @param array $a The array of data to find the standard deviation for. |
||
407 | * Note that all values of the array will be cast to float. |
||
408 | * @param bool $isSample [Optional] Indicates if $a represents a sample of the |
||
409 | * population (otherwise its the population); Defaults to false. |
||
410 | * @return string|bool The standard deviation or false on error. |
||
411 | */ |
||
412 | public function stddev(array $a, $isSample = false) |
||
413 | { |
||
414 | if ($this->mathCount($a) < 2) { |
||
415 | trigger_error("The array has too few elements", E_USER_NOTICE); |
||
416 | return false; |
||
417 | } |
||
418 | return bcsqrt($this->variance($a, $isSample)); |
||
419 | } |
||
420 | |||
421 | /** |
||
422 | * Calculate covariance. |
||
423 | * |
||
424 | * @param array $x_values Dependent variable values. |
||
425 | * @param array $y_values Independent variable values. |
||
426 | * @return string Covariance of x and y. |
||
427 | */ |
||
428 | public function covariance(array $x_values, array $y_values) |
||
429 | { |
||
430 | $l = bcdiv($this->sumxy($x_values, $y_values), $this->mathCount($x_values)); |
||
431 | $r = bcmul($this->mean($x_values), $this->mean($y_values)); |
||
432 | |||
433 | return bcsub($l, $r); |
||
434 | |||
435 | #return sumxy($x_values, $y_values)/mathCount($x_values) - mean($x_values)*mean($y_values); |
||
436 | } |
||
437 | |||
438 | /** |
||
439 | * Compute correlation. |
||
440 | * |
||
441 | * @param array $x_values |
||
442 | * @param array $y_values |
||
443 | * @param boolean $is |
||
444 | * @return string Correlation |
||
445 | */ |
||
446 | public function correlation(array $x_values, array $y_values, $isSample = false) |
||
447 | { |
||
448 | $stddevxy = bcmul($this->stddev($x_values, $isSample), $this->stddev($y_values, $isSample)); |
||
449 | |||
450 | return round(bcdiv($this->covariance($x_values, $y_values), $stddevxy), 8); |
||
451 | } |
||
452 | |||
453 | /** |
||
454 | * Returns the present value of a cashflow. |
||
455 | * |
||
456 | * @param int|float|string $cashflow Numeric quantity of currency. |
||
457 | * @param float|string $rate Discount rate |
||
458 | * @param int|float|string $period A number representing time period in which the |
||
459 | * cash flow occurs. e.g. for an annual cashflow, start a 0 and increase by 1 |
||
460 | * each year (e.g. [Year] 0, [Year] 1, ...) |
||
461 | * @return string Present value of the cash flow. |
||
462 | */ |
||
463 | public function pv($cashflow, $rate, $period = 0) |
||
464 | { |
||
465 | if ($period < 1) { |
||
466 | return (string) $cashflow; |
||
467 | } |
||
468 | |||
469 | return bcdiv($cashflow, bcpow(bcadd($rate, '1'), $period)); |
||
470 | |||
471 | #return $cashflow / pow(1 + $rate, $period); |
||
472 | } |
||
473 | |||
474 | /** |
||
475 | * Returns the Net Present Value of a series of cashflows. |
||
476 | * |
||
477 | * @param array $cashflows Indexed array of cash flows. |
||
478 | * @param number $rate Discount rate applied. |
||
479 | * @return string NPV of $cashflows discounted at $rate. |
||
480 | */ |
||
481 | public function npv(array $cashflows, $rate) |
||
482 | { |
||
483 | $npv = "0.0"; |
||
484 | foreach ($cashflows as $index => $cashflow) { |
||
485 | $npv += pv($cashflow, $rate, $index); |
||
486 | } |
||
487 | return (string) $npv; |
||
488 | } |
||
489 | |||
490 | /** |
||
491 | * Returns the weighted average of a series of values. |
||
492 | * |
||
493 | * @param array $values Indexed array of values. |
||
494 | * @param array $weights Indexed array of weights corresponding to each value. |
||
495 | * @return string Weighted average of values. |
||
496 | */ |
||
497 | public function weightedAvg(array $values, array $weights) |
||
498 | { |
||
499 | if (count($values) !== count($weights)) { |
||
500 | trigger_error("Must pass the same number of weights and values."); |
||
501 | return null; |
||
502 | } |
||
503 | $weighted_sum = "0.0"; |
||
504 | foreach ($values as $i => $val) { |
||
505 | $weighted_sum += $val * $weights[$i]; |
||
506 | } |
||
507 | return strval($weighted_sum/array_sum($weights)); |
||
508 | } |
||
509 | |||
510 | /** ======================================== |
||
511 | Percentages |
||
512 | ======================================== */ |
||
513 | |||
514 | /** |
||
515 | * Returns the % of an amount of the total. |
||
516 | * |
||
517 | * e.g. for operating margin, use operating income as 1st arg, revenue as 2nd. |
||
518 | * e.g. for capex as a % of sales, use capex as 1st arg, revenue as 2nd. |
||
519 | * |
||
520 | * @param number $portion An amount, a portion of the total. |
||
521 | * @param number $total The total amount. |
||
522 | * @return string % |
||
523 | */ |
||
524 | public function pct($portion, $total) |
||
525 | { |
||
526 | return strval($portion/$total); |
||
527 | } |
||
528 | |||
529 | /** |
||
530 | * Returns the % change between two values. |
||
531 | * |
||
532 | * @param number $current The current value. |
||
533 | * @param number $previous The previous value. |
||
534 | * @return string Percent change from previous to current. |
||
535 | */ |
||
536 | public function pctChange($current, $previous) |
||
537 | { |
||
538 | return strval(($current - $previous) / $previous); |
||
539 | } |
||
540 | |||
541 | /** |
||
542 | * Convert an array of values to % change. |
||
543 | * |
||
544 | * @param array $values Raw values ordered from oldest to newest. |
||
545 | * @return array Array of the % change between values. |
||
546 | */ |
||
547 | public function pctChangeArray(array $values) |
||
548 | { |
||
549 | $pcts = array(); |
||
550 | $keys = array_keys($values); |
||
551 | $vals = array_values($values); |
||
552 | foreach ($vals as $i => $value) { |
||
553 | if (0 !== $i) { |
||
554 | $prev = $vals[$i-1]; |
||
555 | if (0 == $prev) { |
||
556 | $pcts[$i] = '0'; |
||
557 | } else { |
||
558 | $pcts[$i] = strval(($value-$prev)/$prev); |
||
559 | } |
||
560 | } |
||
561 | } |
||
562 | array_shift($keys); |
||
563 | return array_combine($keys, $pcts); |
||
564 | } |
||
565 | |||
566 | /** ======================================== |
||
567 | Aliases |
||
568 | ======================================== */ |
||
569 | |||
570 | /** |
||
571 | * Arithmetic average. |
||
572 | */ |
||
573 | public function avg(array $values) |
||
574 | { |
||
575 | return strval(array_sum($values)/count($values)); |
||
576 | } |
||
577 | |||
578 | /** |
||
579 | * Covariance |
||
580 | */ |
||
581 | public function covar(array $xvals, array $yvals) |
||
582 | { |
||
583 | return $this->covariance($xvals, $yvals); |
||
584 | } |
||
585 | |||
586 | /** |
||
587 | * Standard deviation |
||
588 | */ |
||
589 | public function stdev(array $values, $isSample = false) |
||
590 | { |
||
591 | return $this->stddev($values, $isSample); |
||
592 | } |
||
593 | |||
594 | /** |
||
595 | * Correlation |
||
596 | */ |
||
597 | public function correl(array $x_values, array $y_values, $isSample = false) |
||
598 | { |
||
599 | return $this->correlation($x_values, $y_values, $isSample); |
||
600 | } |
||
601 | } |
||
602 |