|
Posted on February 6, 2012 @ 11:49:32 AM by Paul Meagher
I re-implemented Matlab/Octave's sum function in PHP. The Matlab/Octave sum function is more flexible than PHP's array_sum function as it can handle scalar, vector, or matrix input. In the case of matrices, the sum function can also be directed to sum by column or row. The default is to sum a matrix by column which is handy for getting a bunch of column sums from a data matrix.
The way that the sum function works is similar to the way an ave or stdev function would work in Matlab/Octave. Eventually it would be nice to have all these data summarization functions available and working in a Matlab/Octave like way.
Without futher ado, here is the code that implements the sum function. Note that it reuses the get_type() function mentioned in previous blogs:
<?php /** * Partial implementation of matlab sum function. Does not * handle arrays with dimension greater than 2. * * @see http://www.mathworks.com/help/techdoc/ref/sum.html */
/** * Determines whether a variable is a scalar, vector, or matrix. * * @params mixed $var Scalar, vector, or matrix data. * @return string scalar, vector, matrix or false */ function get_type($var) { if (is_numeric($var)) { return "scalar"; } elseif (is_array($var)) { if (is_array($var[0])) return "matrix"; else return "vector"; } else return false; }
/** * Computes the row or column sums. The default is to compute * column sums and to store each column sum into a row vector. * * @param array $a A one to two dimensional array of numeric values. * @param integer $dim The dimension to sum (1=column sums, 2=row sums). * @return array/string $sum A row ($dim=1) or column ($dim=2) vector of sums. */ function sum($a, $dim=1) { $type = get_type($a); if ($type=="scalar") return array($a); elseif ($type=="vector") return array(array_sum($a)); else { // zero the sums array $sums = array(); // num rows $nrows = count($a); // num cols $ncols = count($a[0]); if ($dim == 1) { // compute sum of matrix columns for ($j=0; $j < $ncols; $j++) { $sums[$j] = 0.0; for($i=0; $i < $nrows; $i++) $sums[$j] += $a[$i][$j]; } return $sums; } else { // compute sum of matrix rows for ($i=0; $i < $nrows; $i++) $sums[$i][0] += array_sum($a[$i]); return $sums; } } }
$s = 5; $v = array(1,2,3); $m = array(array(1,2,3),array(1,2,3),array(1,2,3));
// scalar case $ans = sum($s); echo "<pre>"; print_r($ans); echo "</pre>"; echo "<br />";
// row vector case $ans = sum($v); echo "<pre>"; print_r($ans); echo "</pre>"; echo "<br />";
// matrix case - sum cols (default) $ans = sum($m); echo "<pre>"; print_r($ans); echo "</pre>"; echo "<br />";
// matrix case - sum rows $ans = sum($m, 2); echo "<pre>"; print_r($ans); echo "</pre>"; echo "<br />";
// compute sum of all elements $ans = sum(sum($m)); echo "<pre>"; print_r($ans); echo "</pre>"; echo "<br />";
?>
The output of this script looks like this:
Array
(
[0] => 5
)
Array
(
[0] => 6
)
Array
(
[0] => 3
[1] => 6
[2] => 9
)
Array
(
[0] => Array
(
[0] => 6
)
[1] => Array
(
[0] => 6
)
[2] => Array
(
[0] => 6
)
)
Array
(
[0] => 18
)
One important point to note is that when we sum a single scalar value like sum(5) the result is an array and not a scalar value. I suspect that it is of fundamental importance to matrix-oriented languages like Matlab/Octave that results be wrapped in an array structure so that we can string together matrix operations in a conistent manner.
|