summaryrefslogtreecommitdiffstats
path: root/admin/survey/excel/PHPExcel/Shared/JAMA/examples
diff options
context:
space:
mode:
Diffstat (limited to 'admin/survey/excel/PHPExcel/Shared/JAMA/examples')
-rw-r--r--admin/survey/excel/PHPExcel/Shared/JAMA/examples/LMQuadTest.php116
-rw-r--r--admin/survey/excel/PHPExcel/Shared/JAMA/examples/LagrangeInterpolation.php59
-rw-r--r--admin/survey/excel/PHPExcel/Shared/JAMA/examples/LagrangeInterpolation2.php59
-rw-r--r--admin/survey/excel/PHPExcel/Shared/JAMA/examples/LevenbergMarquardt.php185
-rw-r--r--admin/survey/excel/PHPExcel/Shared/JAMA/examples/MagicSquareExample.php182
-rw-r--r--admin/survey/excel/PHPExcel/Shared/JAMA/examples/Stats.php1605
-rw-r--r--admin/survey/excel/PHPExcel/Shared/JAMA/examples/benchmark.php263
-rw-r--r--admin/survey/excel/PHPExcel/Shared/JAMA/examples/polyfit.php73
-rw-r--r--admin/survey/excel/PHPExcel/Shared/JAMA/examples/tile.php78
9 files changed, 2620 insertions, 0 deletions
diff --git a/admin/survey/excel/PHPExcel/Shared/JAMA/examples/LMQuadTest.php b/admin/survey/excel/PHPExcel/Shared/JAMA/examples/LMQuadTest.php
new file mode 100644
index 0000000..706d9e9
--- /dev/null
+++ b/admin/survey/excel/PHPExcel/Shared/JAMA/examples/LMQuadTest.php
@@ -0,0 +1,116 @@
+<?php
+/**
+ * quadratic (p-o)'S'S(p-o)
+ * solve for o, S
+ * S is a single scale factor
+ */
+class LMQuadTest {
+
+ /**
+ * @param array[] $x
+ * @param array[] $a
+ */
+ function val($x, $a) {
+ if (count($a) != 3) die ("Wrong number of elements in array a");
+ if (count($x) != 2) die ("Wrong number of elements in array x");
+
+ $ox = $a[0];
+ $oy = $a[1];
+ $s = $a[2];
+
+ $sdx = $s * ($x[0] - $ox);
+ $sdy = $s * ($x[1] - $oy);
+
+ return ($sdx * $sdx) + ($sdy * $sdy);
+ } // function val()
+
+
+ /**
+ * z = (p-o)'S'S(p-o)
+ * dz/dp = 2S'S(p-o)
+ *
+ * z = (s*(px-ox))^2 + (s*(py-oy))^2
+ * dz/dox = -2(s*(px-ox))*s
+ * dz/ds = 2*s*[(px-ox)^2 + (py-oy)^2]
+ *
+ * z = (s*dx)^2 + (s*dy)^2
+ * dz/ds = 2(s*dx)*dx + 2(s*dy)*dy
+ *
+ * @param array[] $x
+ * @param array[] $a
+ * @param int $a_k
+ * @param array[] $a
+ */
+ function grad($x, $a, $a_k) {
+ if (count($a) != 3) die ("Wrong number of elements in array a");
+ if (count($x) != 2) die ("Wrong number of elements in array x");
+ if ($a_k < 3) die ("a_k=".$a_k);
+
+ $ox = $a[0];
+ $oy = $a[1];
+ $s = $a[2];
+
+ $dx = ($x[0] - $ox);
+ $dy = ($x[1] - $oy);
+
+ if ($a_k == 0)
+ return -2.*$s*$s*$dx;
+ elseif ($a_k == 1)
+ return -2.*$s*$s*$dy;
+ else
+ return 2.*$s*($dx*$dx + $dy*$dy);
+ } // function grad()
+
+
+ /**
+ * @return array[] $a
+ */
+ function initial() {
+ $a[0] = 0.05;
+ $a[1] = 0.1;
+ $a[2] = 1.0;
+
+ return $a;
+ } // function initial()
+
+
+ /**
+ * @return Object[] $a
+ */
+ function testdata() {
+ $npts = 25;
+
+ $a[0] = 0.;
+ $a[1] = 0.;
+ $a[2] = 0.9;
+
+ $i = 0;
+
+ for ($r = -2; $r <= 2; ++$r) {
+ for ($c = -2; $c <= 2; ++$c) {
+ $x[$i][0] = $c;
+ $x[$i][1] = $r;
+ $y[$i] = $this->val($x[$i], $a);
+ print("Quad ".$c.",".$r." -> ".$y[$i]."<br />");
+ $s[$i] = 1.;
+ ++$i;
+ }
+ }
+ print("quad x= ");
+
+ $qx = new Matrix($x);
+ $qx->print(10, 2);
+
+ print("quad y= ");
+ $qy = new Matrix($y, $npts);
+ $qy->print(10, 2);
+
+ $o[0] = $x;
+ $o[1] = $a;
+ $o[2] = $y;
+ $o[3] = $s;
+
+ return $o;
+ } // function testdata()
+
+} // class LMQuadTest
diff --git a/admin/survey/excel/PHPExcel/Shared/JAMA/examples/LagrangeInterpolation.php b/admin/survey/excel/PHPExcel/Shared/JAMA/examples/LagrangeInterpolation.php
new file mode 100644
index 0000000..27c8937
--- /dev/null
+++ b/admin/survey/excel/PHPExcel/Shared/JAMA/examples/LagrangeInterpolation.php
@@ -0,0 +1,59 @@
+<?php
+
+require_once "../Matrix.php";
+
+/**
+ * Given n points (x0,y0)...(xn-1,yn-1), the following methid computes
+ * the polynomial factors of the n-1't degree polynomial passing through
+ * the n points.
+ *
+ * Example: Passing in three points (2,3) (1,4) and (3,7) will produce
+ * the results [2.5, -8.5, 10] which means that the points are on the
+ * curve y = 2.5x² - 8.5x + 10.
+ *
+ * @see http://geosoft.no/software/lagrange/LagrangeInterpolation.java.html
+ * @author Jacob Dreyer
+ * @author Paul Meagher (port to PHP and minor changes)
+ *
+ * @param x[] float
+ * @param y[] float
+ */
+class LagrangeInterpolation {
+
+ public function findPolynomialFactors($x, $y) {
+ $n = count($x);
+
+ $data = array(); // double[n][n];
+ $rhs = array(); // double[n];
+
+ for ($i = 0; $i < $n; ++$i) {
+ $v = 1;
+ for ($j = 0; $j < $n; ++$j) {
+ $data[$i][$n-$j-1] = $v;
+ $v *= $x[$i];
+ }
+ $rhs[$i] = $y[$i];
+ }
+
+ // Solve m * s = b
+ $m = new Matrix($data);
+ $b = new Matrix($rhs, $n);
+
+ $s = $m->solve($b);
+
+ return $s->getRowPackedCopy();
+ } // function findPolynomialFactors()
+
+} // class LagrangeInterpolation
+
+
+$x = array(2.0, 1.0, 3.0);
+$y = array(3.0, 4.0, 7.0);
+
+$li = new LagrangeInterpolation;
+$f = $li->findPolynomialFactors($x, $y);
+
+
+for ($i = 0; $i < 3; ++$i) {
+ echo $f[$i]."<br />";
+}
diff --git a/admin/survey/excel/PHPExcel/Shared/JAMA/examples/LagrangeInterpolation2.php b/admin/survey/excel/PHPExcel/Shared/JAMA/examples/LagrangeInterpolation2.php
new file mode 100644
index 0000000..cd9cb9a
--- /dev/null
+++ b/admin/survey/excel/PHPExcel/Shared/JAMA/examples/LagrangeInterpolation2.php
@@ -0,0 +1,59 @@
+<?php
+
+require_once "../Matrix.php";
+
+/**
+ * Given n points (x0,y0)...(xn-1,yn-1), the following method computes
+ * the polynomial factors of the n-1't degree polynomial passing through
+ * the n points.
+ *
+ * Example: Passing in three points (2,3) (1,4) and (3,7) will produce
+ * the results [2.5, -8.5, 10] which means that the points are on the
+ * curve y = 2.5x² - 8.5x + 10.
+ *
+ * @see http://geosoft.no/software/lagrange/LagrangeInterpolation.java.html
+ * @see http://source.freehep.org/jcvsweb/ilc/LCSIM/wdview/lcsim/src/org/lcsim/fit/polynomial/PolynomialFitter.java
+ * @author Jacob Dreyer
+ * @author Paul Meagher (port to PHP and minor changes)
+ *
+ * @param x[] float
+ * @param y[] float
+ */
+class LagrangeInterpolation {
+
+ public function findPolynomialFactors($x, $y) {
+ $n = count($x);
+
+ $data = array(); // double[n][n];
+ $rhs = array(); // double[n];
+
+ for ($i = 0; $i < $n; ++$i) {
+ $v = 1;
+ for ($j = 0; $j < $n; ++$j) {
+ $data[$i][$n-$j-1] = $v;
+ $v *= $x[$i];
+ }
+ $rhs[$i] = $y[$i];
+ }
+
+ // Solve m * s = b
+ $m = new Matrix($data);
+ $b = new Matrix($rhs, $n);
+
+ $s = $m->solve($b);
+
+ return $s->getRowPackedCopy();
+ } // function findPolynomialFactors()
+
+} // class LagrangeInterpolation
+
+
+$x = array(2.0, 1.0, 3.0);
+$y = array(3.0, 4.0, 7.0);
+
+$li = new LagrangeInterpolation;
+$f = $li->findPolynomialFactors($x, $y);
+
+for ($i = 0; $i < 3; ++$i) {
+ echo $f[$i]."<br />";
+}
diff --git a/admin/survey/excel/PHPExcel/Shared/JAMA/examples/LevenbergMarquardt.php b/admin/survey/excel/PHPExcel/Shared/JAMA/examples/LevenbergMarquardt.php
new file mode 100644
index 0000000..01c4acc
--- /dev/null
+++ b/admin/survey/excel/PHPExcel/Shared/JAMA/examples/LevenbergMarquardt.php
@@ -0,0 +1,185 @@
+<?php
+
+// Levenberg-Marquardt in PHP
+
+// http://www.idiom.com/~zilla/Computer/Javanumeric/LM.java
+
+class LevenbergMarquardt {
+
+ /**
+ * Calculate the current sum-squared-error
+ *
+ * Chi-squared is the distribution of squared Gaussian errors,
+ * thus the name.
+ *
+ * @param double[][] $x
+ * @param double[] $a
+ * @param double[] $y,
+ * @param double[] $s,
+ * @param object $f
+ */
+ function chiSquared($x, $a, $y, $s, $f) {
+ $npts = count($y);
+ $sum = 0.0;
+
+ for ($i = 0; $i < $npts; ++$i) {
+ $d = $y[$i] - $f->val($x[$i], $a);
+ $d = $d / $s[$i];
+ $sum = $sum + ($d*$d);
+ }
+
+ return $sum;
+ } // function chiSquared()
+
+
+ /**
+ * Minimize E = sum {(y[k] - f(x[k],a)) / s[k]}^2
+ * The individual errors are optionally scaled by s[k].
+ * Note that LMfunc implements the value and gradient of f(x,a),
+ * NOT the value and gradient of E with respect to a!
+ *
+ * @param x array of domain points, each may be multidimensional
+ * @param y corresponding array of values
+ * @param a the parameters/state of the model
+ * @param vary false to indicate the corresponding a[k] is to be held fixed
+ * @param s2 sigma^2 for point i
+ * @param lambda blend between steepest descent (lambda high) and
+ * jump to bottom of quadratic (lambda zero).
+ * Start with 0.001.
+ * @param termepsilon termination accuracy (0.01)
+ * @param maxiter stop and return after this many iterations if not done
+ * @param verbose set to zero (no prints), 1, 2
+ *
+ * @return the new lambda for future iterations.
+ * Can use this and maxiter to interleave the LM descent with some other
+ * task, setting maxiter to something small.
+ */
+ function solve($x, $a, $y, $s, $vary, $f, $lambda, $termepsilon, $maxiter, $verbose) {
+ $npts = count($y);
+ $nparm = count($a);
+
+ if ($verbose > 0) {
+ print("solve x[".count($x)."][".count($x[0])."]");
+ print(" a[".count($a)."]");
+ println(" y[".count(length)."]");
+ }
+
+ $e0 = $this->chiSquared($x, $a, $y, $s, $f);
+
+ //double lambda = 0.001;
+ $done = false;
+
+ // g = gradient, H = hessian, d = step to minimum
+ // H d = -g, solve for d
+ $H = array();
+ $g = array();
+
+ //double[] d = new double[nparm];
+
+ $oos2 = array();
+
+ for($i = 0; $i < $npts; ++$i) {
+ $oos2[$i] = 1./($s[$i]*$s[$i]);
+ }
+ $iter = 0;
+ $term = 0; // termination count test
+
+ do {
+ ++$iter;
+
+ // hessian approximation
+ for( $r = 0; $r < $nparm; ++$r) {
+ for( $c = 0; $c < $nparm; ++$c) {
+ for( $i = 0; $i < $npts; ++$i) {
+ if ($i == 0) $H[$r][$c] = 0.;
+ $xi = $x[$i];
+ $H[$r][$c] += ($oos2[$i] * $f->grad($xi, $a, $r) * $f->grad($xi, $a, $c));
+ } //npts
+ } //c
+ } //r
+
+ // boost diagonal towards gradient descent
+ for( $r = 0; $r < $nparm; ++$r)
+ $H[$r][$r] *= (1. + $lambda);
+
+ // gradient
+ for( $r = 0; $r < $nparm; ++$r) {
+ for( $i = 0; $i < $npts; ++$i) {
+ if ($i == 0) $g[$r] = 0.;
+ $xi = $x[$i];
+ $g[$r] += ($oos2[$i] * ($y[$i]-$f->val($xi,$a)) * $f->grad($xi, $a, $r));
+ }
+ } //npts
+
+ // scale (for consistency with NR, not necessary)
+ if ($false) {
+ for( $r = 0; $r < $nparm; ++$r) {
+ $g[$r] = -0.5 * $g[$r];
+ for( $c = 0; $c < $nparm; ++$c) {
+ $H[$r][$c] *= 0.5;
+ }
+ }
+ }
+
+ // solve H d = -g, evaluate error at new location
+ //double[] d = DoubleMatrix.solve(H, g);
+// double[] d = (new Matrix(H)).lu().solve(new Matrix(g, nparm)).getRowPackedCopy();
+ //double[] na = DoubleVector.add(a, d);
+// double[] na = (new Matrix(a, nparm)).plus(new Matrix(d, nparm)).getRowPackedCopy();
+// double e1 = chiSquared(x, na, y, s, f);
+
+// if (verbose > 0) {
+// System.out.println("\n\niteration "+iter+" lambda = "+lambda);
+// System.out.print("a = ");
+// (new Matrix(a, nparm)).print(10, 2);
+// if (verbose > 1) {
+// System.out.print("H = ");
+// (new Matrix(H)).print(10, 2);
+// System.out.print("g = ");
+// (new Matrix(g, nparm)).print(10, 2);
+// System.out.print("d = ");
+// (new Matrix(d, nparm)).print(10, 2);
+// }
+// System.out.print("e0 = " + e0 + ": ");
+// System.out.print("moved from ");
+// (new Matrix(a, nparm)).print(10, 2);
+// System.out.print("e1 = " + e1 + ": ");
+// if (e1 < e0) {
+// System.out.print("to ");
+// (new Matrix(na, nparm)).print(10, 2);
+// } else {
+// System.out.println("move rejected");
+// }
+// }
+
+ // termination test (slightly different than NR)
+// if (Math.abs(e1-e0) > termepsilon) {
+// term = 0;
+// } else {
+// term++;
+// if (term == 4) {
+// System.out.println("terminating after " + iter + " iterations");
+// done = true;
+// }
+// }
+// if (iter >= maxiter) done = true;
+
+ // in the C++ version, found that changing this to e1 >= e0
+ // was not a good idea. See comment there.
+ //
+// if (e1 > e0 || Double.isNaN(e1)) { // new location worse than before
+// lambda *= 10.;
+// } else { // new location better, accept new parameters
+// lambda *= 0.1;
+// e0 = e1;
+// // simply assigning a = na will not get results copied back to caller
+// for( int i = 0; i < nparm; i++ ) {
+// if (vary[i]) a[i] = na[i];
+// }
+// }
+ } while(!$done);
+
+ return $lambda;
+ } // function solve()
+
+} // class LevenbergMarquardt
diff --git a/admin/survey/excel/PHPExcel/Shared/JAMA/examples/MagicSquareExample.php b/admin/survey/excel/PHPExcel/Shared/JAMA/examples/MagicSquareExample.php
new file mode 100644
index 0000000..8a66903
--- /dev/null
+++ b/admin/survey/excel/PHPExcel/Shared/JAMA/examples/MagicSquareExample.php
@@ -0,0 +1,182 @@
+<?php
+/**
+* @package JAMA
+*/
+
+require_once "../Matrix.php";
+
+/**
+* Example of use of Matrix Class, featuring magic squares.
+*/
+class MagicSquareExample {
+
+ /**
+ * Generate magic square test matrix.
+ * @param int n dimension of matrix
+ */
+ function magic($n) {
+
+ // Odd order
+
+ if (($n % 2) == 1) {
+ $a = ($n+1)/2;
+ $b = ($n+1);
+ for ($j = 0; $j < $n; ++$j)
+ for ($i = 0; $i < $n; ++$i)
+ $M[$i][$j] = $n*(($i+$j+$a) % $n) + (($i+2*$j+$b) % $n) + 1;
+
+ // Doubly Even Order
+
+ } else if (($n % 4) == 0) {
+ for ($j = 0; $j < $n; ++$j) {
+ for ($i = 0; $i < $n; ++$i) {
+ if ((($i+1)/2)%2 == (($j+1)/2)%2)
+ $M[$i][$j] = $n*$n-$n*$i-$j;
+ else
+ $M[$i][$j] = $n*$i+$j+1;
+ }
+ }
+
+ // Singly Even Order
+
+ } else {
+
+ $p = $n/2;
+ $k = ($n-2)/4;
+ $A = $this->magic($p);
+ $M = array();
+ for ($j = 0; $j < $p; ++$j) {
+ for ($i = 0; $i < $p; ++$i) {
+ $aij = $A->get($i,$j);
+ $M[$i][$j] = $aij;
+ $M[$i][$j+$p] = $aij + 2*$p*$p;
+ $M[$i+$p][$j] = $aij + 3*$p*$p;
+ $M[$i+$p][$j+$p] = $aij + $p*$p;
+ }
+ }
+
+ for ($i = 0; $i < $p; ++$i) {
+ for ($j = 0; $j < $k; ++$j) {
+ $t = $M[$i][$j];
+ $M[$i][$j] = $M[$i+$p][$j];
+ $M[$i+$p][$j] = $t;
+ }
+ for ($j = $n-$k+1; $j < $n; ++$j) {
+ $t = $M[$i][$j];
+ $M[$i][$j] = $M[$i+$p][$j];
+ $M[$i+$p][$j] = $t;
+ }
+ }
+
+ $t = $M[$k][0]; $M[$k][0] = $M[$k+$p][0]; $M[$k+$p][0] = $t;
+ $t = $M[$k][$k]; $M[$k][$k] = $M[$k+$p][$k]; $M[$k+$p][$k] = $t;
+
+ }
+
+ return new Matrix($M);
+
+ }
+
+ /**
+ * Simple function to replicate PHP 5 behaviour
+ */
+ function microtime_float() {
+ list($usec, $sec) = explode(" ", microtime());
+ return ((float)$usec + (float)$sec);
+ }
+
+ /**
+ * Tests LU, QR, SVD and symmetric Eig decompositions.
+ *
+ * n = order of magic square.
+ * trace = diagonal sum, should be the magic sum, (n^3 + n)/2.
+ * max_eig = maximum eigenvalue of (A + A')/2, should equal trace.
+ * rank = linear algebraic rank, should equal n if n is odd,
+ * be less than n if n is even.
+ * cond = L_2 condition number, ratio of singular values.
+ * lu_res = test of LU factorization, norm1(L*U-A(p,:))/(n*eps).
+ * qr_res = test of QR factorization, norm1(Q*R-A)/(n*eps).
+ */
+ function main() {
+ ?>
+ <p>Test of Matrix Class, using magic squares.</p>
+ <p>See MagicSquareExample.main() for an explanation.</p>
+ <table border='1' cellspacing='0' cellpadding='4'>
+ <tr>
+ <th>n</th>
+ <th>trace</th>
+ <th>max_eig</th>
+ <th>rank</th>
+ <th>cond</th>
+ <th>lu_res</th>
+ <th>qr_res</th>
+ </tr>
+ <?php
+ $start_time = $this->microtime_float();
+ $eps = pow(2.0,-52.0);
+ for ($n = 3; $n <= 6; ++$n) {
+ echo "<tr>";
+
+ echo "<td align='right'>$n</td>";
+
+ $M = $this->magic($n);
+ $t = (int) $M->trace();
+
+ echo "<td align='right'>$t</td>";
+
+ $O = $M->plus($M->transpose());
+ $E = new EigenvalueDecomposition($O->times(0.5));
+ $d = $E->getRealEigenvalues();
+
+ echo "<td align='right'>".$d[$n-1]."</td>";
+
+ $r = $M->rank();
+
+ echo "<td align='right'>".$r."</td>";
+
+ $c = $M->cond();
+
+ if ($c < 1/$eps)
+ echo "<td align='right'>".sprintf("%.3f",$c)."</td>";
+ else
+ echo "<td align='right'>Inf</td>";
+
+ $LU = new LUDecomposition($M);
+ $L = $LU->getL();
+ $U = $LU->getU();
+ $p = $LU->getPivot();
+ // Java version: R = L.times(U).minus(M.getMatrix(p,0,n-1));
+ $S = $L->times($U);
+ $R = $S->minus($M->getMatrix($p,0,$n-1));
+ $res = $R->norm1()/($n*$eps);
+
+ echo "<td align='right'>".sprintf("%.3f",$res)."</td>";
+
+ $QR = new QRDecomposition($M);
+ $Q = $QR->getQ();
+ $R = $QR->getR();
+ $S = $Q->times($R);
+ $R = $S->minus($M);
+ $res = $R->norm1()/($n*$eps);
+
+ echo "<td align='right'>".sprintf("%.3f",$res)."</td>";
+
+ echo "</tr>";
+
+ }
+ echo "<table>";
+ echo "<br />";
+
+ $stop_time = $this->microtime_float();
+ $etime = $stop_time - $start_time;
+
+ echo "<p>Elapsed time is ". sprintf("%.4f",$etime) ." seconds.</p>";
+
+ }
+
+}
+
+$magic = new MagicSquareExample();
+$magic->main();
+
+?>
diff --git a/admin/survey/excel/PHPExcel/Shared/JAMA/examples/Stats.php b/admin/survey/excel/PHPExcel/Shared/JAMA/examples/Stats.php
new file mode 100644
index 0000000..7d1359b
--- /dev/null
+++ b/admin/survey/excel/PHPExcel/Shared/JAMA/examples/Stats.php
@@ -0,0 +1,1605 @@
+<?php
+//
+// +----------------------------------------------------------------------+
+// | PHP Version 4 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2003 The PHP Group |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 2.0 of the PHP license, |
+// | that is bundled with this package in the file LICENSE, and is |
+// | available at through the world-wide-web at |
+// | http://www.php.net/license/2_02.txt. |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to |
+// | license@php.net so we can mail you a copy immediately. |
+// +----------------------------------------------------------------------+
+// | Authors: Jesus M. Castagnetto <jmcastagnetto@php.net> |
+// +----------------------------------------------------------------------+
+//
+// $Id: Stats.php,v 1.15 2003/06/01 11:40:30 jmcastagnetto Exp $
+//
+
+include_once 'PEAR.php';
+
+/**
+* @package Math_Stats
+*/
+
+// Constants for defining the statistics to calculate /*{{{*/
+/**
+* STATS_BASIC to generate the basic descriptive statistics
+*/
+define('STATS_BASIC', 1);
+/**
+* STATS_FULL to generate also higher moments, mode, median, etc.
+*/
+define('STATS_FULL', 2);
+/*}}}*/
+
+// Constants describing the data set format /*{{{*/
+/**
+* STATS_DATA_SIMPLE for an array of numeric values. This is the default.
+* e.g. $data = array(2,3,4,5,1,1,6);
+*/
+define('STATS_DATA_SIMPLE', 0);
+/**
+* STATS_DATA_CUMMULATIVE for an associative array of frequency values,
+* where in each array entry, the index is the data point and the
+* value the count (frequency):
+* e.g. $data = array(3=>4, 2.3=>5, 1.25=>6, 0.5=>3)
+*/
+define('STATS_DATA_CUMMULATIVE', 1);
+/*}}}*/
+
+// Constants defining how to handle nulls /*{{{*/
+/**
+* STATS_REJECT_NULL, reject data sets with null values. This is the default.
+* Any non-numeric value is considered a null in this context.
+*/
+define('STATS_REJECT_NULL', -1);
+/**
+* STATS_IGNORE_NULL, ignore null values and prune them from the data.
+* Any non-numeric value is considered a null in this context.
+*/
+define('STATS_IGNORE_NULL', -2);
+/**
+* STATS_USE_NULL_AS_ZERO, assign the value of 0 (zero) to null values.
+* Any non-numeric value is considered a null in this context.
+*/
+define('STATS_USE_NULL_AS_ZERO', -3);
+/*}}}*/
+
+/**
+* A class to calculate descriptive statistics from a data set.
+* Data sets can be simple arrays of data, or a cummulative hash.
+* The second form is useful when passing large data set,
+* for example the data set:
+*
+* <pre>
+* $data1 = array (1,2,1,1,1,1,3,3,4.1,3,2,2,4.1,1,1,2,3,3,2,2,1,1,2,2);
+* </pre>
+*
+* can be epxressed more compactly as:
+*
+* <pre>
+* $data2 = array('1'=>9, '2'=>8, '3'=>5, '4.1'=>2);
+* </pre>
+*
+* Example of use:
+*
+* <pre>
+* include_once 'Math/Stats.php';
+* $s = new Math_Stats();
+* $s->setData($data1);
+* // or
+* // $s->setData($data2, STATS_DATA_CUMMULATIVE);
+* $stats = $s->calcBasic();
+* echo 'Mean: '.$stats['mean'].' StDev: '.$stats['stdev'].' <br />\n';
+*
+* // using data with nulls
+* // first ignoring them:
+* $data3 = array(1.2, 'foo', 2.4, 3.1, 4.2, 3.2, null, 5.1, 6.2);
+* $s->setNullOption(STATS_IGNORE_NULL);
+* $s->setData($data3);
+* $stats3 = $s->calcFull();
+*
+* // and then assuming nulls == 0
+* $s->setNullOption(STATS_USE_NULL_AS_ZERO);
+* $s->setData($data3);
+* $stats3 = $s->calcFull();
+* </pre>
+*
+* Originally this class was part of NumPHP (Numeric PHP package)
+*
+* @author Jesus M. Castagnetto <jmcastagnetto@php.net>
+* @version 0.8
+* @access public
+* @package Math_Stats
+*/
+class Base {/*{{{*/
+ // properties /*{{{*/
+
+ /**
+ * The simple or cummulative data set.
+ * Null by default.
+ *
+ * @access private
+ * @var array
+ */
+ public $_data = null;
+
+ /**
+ * Expanded data set. Only set when cummulative data
+ * is being used. Null by default.
+ *
+ * @access private
+ * @var array
+ */
+ public $_dataExpanded = null;
+
+ /**
+ * Flag for data type, one of STATS_DATA_SIMPLE or
+ * STATS_DATA_CUMMULATIVE. Null by default.
+ *
+ * @access private
+ * @var int
+ */
+ public $_dataOption = null;
+
+ /**
+ * Flag for null handling options. One of STATS_REJECT_NULL,
+ * STATS_IGNORE_NULL or STATS_USE_NULL_AS_ZERO
+ *
+ * @access private
+ * @var int
+ */
+ public $_nullOption;
+
+ /**
+ * Array for caching result values, should be reset
+ * when using setData()
+ *
+ * @access private
+ * @var array
+ */
+ public $_calculatedValues = array();
+
+ /*}}}*/
+
+ /**
+ * Constructor for the class
+ *
+ * @access public
+ * @param optional int $nullOption how to handle null values
+ * @return object Math_Stats
+ */
+ function Math_Stats($nullOption=STATS_REJECT_NULL) {/*{{{*/
+ $this->_nullOption = $nullOption;
+ }/*}}}*/
+
+ /**
+ * Sets and verifies the data, checking for nulls and using
+ * the current null handling option
+ *
+ * @access public
+ * @param array $arr the data set
+ * @param optional int $opt data format: STATS_DATA_CUMMULATIVE or STATS_DATA_SIMPLE (default)
+ * @return mixed true on success, a PEAR_Error object otherwise
+ */
+ function setData($arr, $opt=STATS_DATA_SIMPLE) {/*{{{*/
+ if (!is_array($arr)) {
+ return PEAR::raiseError('invalid data, an array of numeric data was expected');
+ }
+ $this->_data = null;
+ $this->_dataExpanded = null;
+ $this->_dataOption = null;
+ $this->_calculatedValues = array();
+ if ($opt == STATS_DATA_SIMPLE) {
+ $this->_dataOption = $opt;
+ $this->_data = array_values($arr);
+ } else if ($opt == STATS_DATA_CUMMULATIVE) {
+ $this->_dataOption = $opt;
+ $this->_data = $arr;
+ $this->_dataExpanded = array();
+ }
+ return $this->_validate();
+ }/*}}}*/
+
+ /**
+ * Returns the data which might have been modified
+ * according to the current null handling options.
+ *
+ * @access public
+ * @param boolean $expanded whether to return a expanded list, default is false
+ * @return mixed array of data on success, a PEAR_Error object otherwise
+ * @see _validate()
+ */
+ function getData($expanded=false) {/*{{{*/
+ if ($this->_data == null) {
+ return PEAR::raiseError('data has not been set');
+ }
+ if ($this->_dataOption == STATS_DATA_CUMMULATIVE && $expanded) {
+ return $this->_dataExpanded;
+ } else {
+ return $this->_data;
+ }
+ }/*}}}*/
+
+ /**
+ * Sets the null handling option.
+ * Must be called before assigning a new data set containing null values
+ *
+ * @access public
+ * @return mixed true on success, a PEAR_Error object otherwise
+ * @see _validate()
+ */
+ function setNullOption($nullOption) {/*{{{*/
+ if ($nullOption == STATS_REJECT_NULL
+ || $nullOption == STATS_IGNORE_NULL
+ || $nullOption == STATS_USE_NULL_AS_ZERO) {
+ $this->_nullOption = $nullOption;
+ return true;
+ } else {
+ return PEAR::raiseError('invalid null handling option expecting: '.
+ 'STATS_REJECT_NULL, STATS_IGNORE_NULL or STATS_USE_NULL_AS_ZERO');
+ }
+ }/*}}}*/
+
+ /**
+ * Transforms the data by substracting each entry from the mean and
+ * dividing by its standard deviation. This will reset all pre-calculated
+ * values to their original (unset) defaults.
+ *
+ * @access public
+ * @return mixed true on success, a PEAR_Error object otherwise
+ * @see mean()
+ * @see stDev()
+ * @see setData()
+ */
+ function studentize() {/*{{{*/
+ $mean = $this->mean();
+ if (PEAR::isError($mean)) {
+ return $mean;
+ }
+ $std = $this->stDev();
+ if (PEAR::isError($std)) {
+ return $std;
+ }
+ if ($std == 0) {
+ return PEAR::raiseError('cannot studentize data, standard deviation is zero.');
+ }
+ $arr = array();
+ if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
+ foreach ($this->_data as $val=>$freq) {
+ $newval = ($val - $mean) / $std;
+ $arr["$newval"] = $freq;
+ }
+ } else {
+ foreach ($this->_data as $val) {
+ $newval = ($val - $mean) / $std;
+ $arr[] = $newval;
+ }
+ }
+ return $this->setData($arr, $this->_dataOption);
+ }/*}}}*/
+
+ /**
+ * Transforms the data by substracting each entry from the mean.
+ * This will reset all pre-calculated values to their original (unset) defaults.
+ *
+ * @access public
+ * @return mixed true on success, a PEAR_Error object otherwise
+ * @see mean()
+ * @see setData()
+ */
+ function center() {/*{{{*/
+ $mean = $this->mean();
+ if (PEAR::isError($mean)) {
+ return $mean;
+ }
+ $arr = array();
+ if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
+ foreach ($this->_data as $val=>$freq) {
+ $newval = $val - $mean;
+ $arr["$newval"] = $freq;
+ }
+ } else {
+ foreach ($this->_data as $val) {
+ $newval = $val - $mean;
+ $arr[] = $newval;
+ }
+ }
+ return $this->setData($arr, $this->_dataOption);
+ }/*}}}*/
+
+ /**
+ * Calculates the basic or full statistics for the data set
+ *
+ * @access public
+ * @param int $mode one of STATS_BASIC or STATS_FULL
+ * @param boolean $returnErrorObject whether the raw PEAR_Error (when true, default),
+ * or only the error message will be returned (when false), if an error happens.
+ * @return mixed an associative array of statistics on success, a PEAR_Error object otherwise
+ * @see calcBasic()
+ * @see calcFull()
+ */
+ function calc($mode, $returnErrorObject=true) {/*{{{*/
+ if ($this->_data == null) {
+ return PEAR::raiseError('data has not been set');
+ }
+ if ($mode == STATS_BASIC) {
+ return $this->calcBasic($returnErrorObject);
+ } elseif ($mode == STATS_FULL) {
+ return $this->calcFull($returnErrorObject);
+ } else {
+ return PEAR::raiseError('incorrect mode, expected STATS_BASIC or STATS_FULL');
+ }
+ }/*}}}*/
+
+ /**
+ * Calculates a basic set of statistics
+ *
+ * @access public
+ * @param boolean $returnErrorObject whether the raw PEAR_Error (when true, default),
+ * or only the error message will be returned (when false), if an error happens.
+ * @return mixed an associative array of statistics on success, a PEAR_Error object otherwise
+ * @see calc()
+ * @see calcFull()
+ */
+ function calcBasic($returnErrorObject=true) {/*{{{*/
+ return array (
+ 'min' => $this->__format($this->min(), $returnErrorObject),
+ 'max' => $this->__format($this->max(), $returnErrorObject),
+ 'sum' => $this->__format($this->sum(), $returnErrorObject),
+ 'sum2' => $this->__format($this->sum2(), $returnErrorObject),
+ 'count' => $this->__format($this->count(), $returnErrorObject),
+ 'mean' => $this->__format($this->mean(), $returnErrorObject),
+ 'stdev' => $this->__format($this->stDev(), $returnErrorObject),
+ 'variance' => $this->__format($this->variance(), $returnErrorObject),
+ 'range' => $this->__format($this->range(), $returnErrorObject)
+ );
+ }/*}}}*/
+
+ /**
+ * Calculates a full set of statistics
+ *
+ * @access public
+ * @param boolean $returnErrorObject whether the raw PEAR_Error (when true, default),
+ * or only the error message will be returned (when false), if an error happens.
+ * @return mixed an associative array of statistics on success, a PEAR_Error object otherwise
+ * @see calc()
+ * @see calcBasic()
+ */
+ function calcFull($returnErrorObject=true) {/*{{{*/
+ return array (
+ 'min' => $this->__format($this->min(), $returnErrorObject),
+ 'max' => $this->__format($this->max(), $returnErrorObject),
+ 'sum' => $this->__format($this->sum(), $returnErrorObject),
+ 'sum2' => $this->__format($this->sum2(), $returnErrorObject),
+ 'count' => $this->__format($this->count(), $returnErrorObject),
+ 'mean' => $this->__format($this->mean(), $returnErrorObject),
+ 'median' => $this->__format($this->median(), $returnErrorObject),
+ 'mode' => $this->__format($this->mode(), $returnErrorObject),
+ 'midrange' => $this->__format($this->midrange(), $returnErrorObject),
+ 'geometric_mean' => $this->__format($this->geometricMean(), $returnErrorObject),
+ 'harmonic_mean' => $this->__format($this->harmonicMean(), $returnErrorObject),
+ 'stdev' => $this->__format($this->stDev(), $returnErrorObject),
+ 'absdev' => $this->__format($this->absDev(), $returnErrorObject),
+ 'variance' => $this->__format($this->variance(), $returnErrorObject),
+ 'range' => $this->__format($this->range(), $returnErrorObject),
+ 'std_error_of_mean' => $this->__format($this->stdErrorOfMean(), $returnErrorObject),
+ 'skewness' => $this->__format($this->skewness(), $returnErrorObject),
+ 'kurtosis' => $this->__format($this->kurtosis(), $returnErrorObject),
+ 'coeff_of_variation' => $this->__format($this->coeffOfVariation(), $returnErrorObject),
+ 'sample_central_moments' => array (
+ 1 => $this->__format($this->sampleCentralMoment(1), $returnErrorObject),
+ 2 => $this->__format($this->sampleCentralMoment(2), $returnErrorObject),
+ 3 => $this->__format($this->sampleCentralMoment(3), $returnErrorObject),
+ 4 => $this->__format($this->sampleCentralMoment(4), $returnErrorObject),
+ 5 => $this->__format($this->sampleCentralMoment(5), $returnErrorObject)
+ ),
+ 'sample_raw_moments' => array (
+ 1 => $this->__format($this->sampleRawMoment(1), $returnErrorObject),
+ 2 => $this->__format($this->sampleRawMoment(2), $returnErrorObject),
+ 3 => $this->__format($this->sampleRawMoment(3), $returnErrorObject),
+ 4 => $this->__format($this->sampleRawMoment(4), $returnErrorObject),
+ 5 => $this->__format($this->sampleRawMoment(5), $returnErrorObject)
+ ),
+ 'frequency' => $this->__format($this->frequency(), $returnErrorObject),
+ 'quartiles' => $this->__format($this->quartiles(), $returnErrorObject),
+ 'interquartile_range' => $this->__format($this->interquartileRange(), $returnErrorObject),
+ 'interquartile_mean' => $this->__format($this->interquartileMean(), $returnErrorObject),
+ 'quartile_deviation' => $this->__format($this->quartileDeviation(), $returnErrorObject),
+ 'quartile_variation_coefficient' => $this->__format($this->quartileVariationCoefficient(), $returnErrorObject),
+ 'quartile_skewness_coefficient' => $this->__format($this->quartileSkewnessCoefficient(), $returnErrorObject)
+ );
+ }/*}}}*/
+
+ /**
+ * Calculates the minimum of a data set.
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @return mixed the minimum value on success, a PEAR_Error object otherwise
+ * @see calc()
+ * @see max()
+ */
+ function min() {/*{{{*/
+ if ($this->_data == null) {
+ return PEAR::raiseError('data has not been set');
+ }
+ if (!array_key_exists('min', $this->_calculatedValues)) {
+ if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
+ $min = min(array_keys($this->_data));
+ } else {
+ $min = min($this->_data);
+ }
+ $this->_calculatedValues['min'] = $min;
+ }
+ return $this->_calculatedValues['min'];
+ }/*}}}*/
+
+ /**
+ * Calculates the maximum of a data set.
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @return mixed the maximum value on success, a PEAR_Error object otherwise
+ * @see calc()
+ * @see min()
+ */
+ function max() {/*{{{*/
+ if ($this->_data == null) {
+ return PEAR::raiseError('data has not been set');
+ }
+ if (!array_key_exists('max', $this->_calculatedValues)) {
+ if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
+ $max = max(array_keys($this->_data));
+ } else {
+ $max = max($this->_data);
+ }
+ $this->_calculatedValues['max'] = $max;
+ }
+ return $this->_calculatedValues['max'];
+ }/*}}}*/
+
+ /**
+ * Calculates SUM { xi }
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @return mixed the sum on success, a PEAR_Error object otherwise
+ * @see calc()
+ * @see sum2()
+ * @see sumN()
+ */
+ function sum() {/*{{{*/
+ if (!array_key_exists('sum', $this->_calculatedValues)) {
+ $sum = $this->sumN(1);
+ if (PEAR::isError($sum)) {
+ return $sum;
+ } else {
+ $this->_calculatedValues['sum'] = $sum;
+ }
+ }
+ return $this->_calculatedValues['sum'];
+ }/*}}}*/
+
+ /**
+ * Calculates SUM { (xi)^2 }
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @return mixed the sum on success, a PEAR_Error object otherwise
+ * @see calc()
+ * @see sum()
+ * @see sumN()
+ */
+ function sum2() {/*{{{*/
+ if (!array_key_exists('sum2', $this->_calculatedValues)) {
+ $sum2 = $this->sumN(2);
+ if (PEAR::isError($sum2)) {
+ return $sum2;
+ } else {
+ $this->_calculatedValues['sum2'] = $sum2;
+ }
+ }
+ return $this->_calculatedValues['sum2'];
+ }/*}}}*/
+
+ /**
+ * Calculates SUM { (xi)^n }
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @param numeric $n the exponent
+ * @return mixed the sum on success, a PEAR_Error object otherwise
+ * @see calc()
+ * @see sum()
+ * @see sum2()
+ */
+ function sumN($n) {/*{{{*/
+ if ($this->_data == null) {
+ return PEAR::raiseError('data has not been set');
+ }
+ $sumN = 0;
+ if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
+ foreach($this->_data as $val=>$freq) {
+ $sumN += $freq * pow((double)$val, (double)$n);
+ }
+ } else {
+ foreach($this->_data as $val) {
+ $sumN += pow((double)$val, (double)$n);
+ }
+ }
+ return $sumN;
+ }/*}}}*/
+
+ /**
+ * Calculates PROD { (xi) }, (the product of all observations)
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @return mixed the product on success, a PEAR_Error object otherwise
+ * @see productN()
+ */
+ function product() {/*{{{*/
+ if (!array_key_exists('product', $this->_calculatedValues)) {
+ $product = $this->productN(1);
+ if (PEAR::isError($product)) {
+ return $product;
+ } else {
+ $this->_calculatedValues['product'] = $product;
+ }
+ }
+ return $this->_calculatedValues['product'];
+ }/*}}}*/
+
+ /**
+ * Calculates PROD { (xi)^n }, which is the product of all observations
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @param numeric $n the exponent
+ * @return mixed the product on success, a PEAR_Error object otherwise
+ * @see product()
+ */
+ function productN($n) {/*{{{*/
+ if ($this->_data == null) {
+ return PEAR::raiseError('data has not been set');
+ }
+ $prodN = 1.0;
+ if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
+ foreach($this->_data as $val=>$freq) {
+ if ($val == 0) {
+ return 0.0;
+ }
+ $prodN *= $freq * pow((double)$val, (double)$n);
+ }
+ } else {
+ foreach($this->_data as $val) {
+ if ($val == 0) {
+ return 0.0;
+ }
+ $prodN *= pow((double)$val, (double)$n);
+ }
+ }
+ return $prodN;
+
+ }/*}}}*/
+
+ /**
+ * Calculates the number of data points in the set
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @return mixed the count on success, a PEAR_Error object otherwise
+ * @see calc()
+ */
+ function count() {/*{{{*/
+ if ($this->_data == null) {
+ return PEAR::raiseError('data has not been set');
+ }
+ if (!array_key_exists('count', $this->_calculatedValues)) {
+ if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
+ $count = count($this->_dataExpanded);
+ } else {
+ $count = count($this->_data);
+ }
+ $this->_calculatedValues['count'] = $count;
+ }
+ return $this->_calculatedValues['count'];
+ }/*}}}*/
+
+ /**
+ * Calculates the mean (average) of the data points in the set
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @return mixed the mean value on success, a PEAR_Error object otherwise
+ * @see calc()
+ * @see sum()
+ * @see count()
+ */
+ function mean() {/*{{{*/
+ if (!array_key_exists('mean', $this->_calculatedValues)) {
+ $sum = $this->sum();
+ if (PEAR::isError($sum)) {
+ return $sum;
+ }
+ $count = $this->count();
+ if (PEAR::isError($count)) {
+ return $count;
+ }
+ $this->_calculatedValues['mean'] = $sum / $count;
+ }
+ return $this->_calculatedValues['mean'];
+ }/*}}}*/
+
+ /**
+ * Calculates the range of the data set = max - min
+ *
+ * @access public
+ * @return mixed the value of the range on success, a PEAR_Error object otherwise.
+ */
+ function range() {/*{{{*/
+ if (!array_key_exists('range', $this->_calculatedValues)) {
+ $min = $this->min();
+ if (PEAR::isError($min)) {
+ return $min;
+ }
+ $max = $this->max();
+ if (PEAR::isError($max)) {
+ return $max;
+ }
+ $this->_calculatedValues['range'] = $max - $min;
+ }
+ return $this->_calculatedValues['range'];
+
+ }/*}}}*/
+
+ /**
+ * Calculates the variance (unbiased) of the data points in the set
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @return mixed the variance value on success, a PEAR_Error object otherwise
+ * @see calc()
+ * @see __sumdiff()
+ * @see count()
+ */
+ function variance() {/*{{{*/
+ if (!array_key_exists('variance', $this->_calculatedValues)) {
+ $variance = $this->__calcVariance();
+ if (PEAR::isError($variance)) {
+ return $variance;
+ }
+ $this->_calculatedValues['variance'] = $variance;
+ }
+ return $this->_calculatedValues['variance'];
+ }/*}}}*/
+
+ /**
+ * Calculates the standard deviation (unbiased) of the data points in the set
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @return mixed the standard deviation on success, a PEAR_Error object otherwise
+ * @see calc()
+ * @see variance()
+ */
+ function stDev() {/*{{{*/
+ if (!array_key_exists('stDev', $this->_calculatedValues)) {
+ $variance = $this->variance();
+ if (PEAR::isError($variance)) {
+ return $variance;
+ }
+ $this->_calculatedValues['stDev'] = sqrt($variance);
+ }
+ return $this->_calculatedValues['stDev'];
+ }/*}}}*/
+
+ /**
+ * Calculates the variance (unbiased) of the data points in the set
+ * given a fixed mean (average) value. Not used in calcBasic(), calcFull()
+ * or calc().
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @param numeric $mean the fixed mean value
+ * @return mixed the variance on success, a PEAR_Error object otherwise
+ * @see __sumdiff()
+ * @see count()
+ * @see variance()
+ */
+ function varianceWithMean($mean) {/*{{{*/
+ return $this->__calcVariance($mean);
+ }/*}}}*/
+
+ /**
+ * Calculates the standard deviation (unbiased) of the data points in the set
+ * given a fixed mean (average) value. Not used in calcBasic(), calcFull()
+ * or calc().
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @param numeric $mean the fixed mean value
+ * @return mixed the standard deviation on success, a PEAR_Error object otherwise
+ * @see varianceWithMean()
+ * @see stDev()
+ */
+ function stDevWithMean($mean) {/*{{{*/
+ $varianceWM = $this->varianceWithMean($mean);
+ if (PEAR::isError($varianceWM)) {
+ return $varianceWM;
+ }
+ return sqrt($varianceWM);
+ }/*}}}*/
+
+ /**
+ * Calculates the absolute deviation of the data points in the set
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @return mixed the absolute deviation on success, a PEAR_Error object otherwise
+ * @see calc()
+ * @see __sumabsdev()
+ * @see count()
+ * @see absDevWithMean()
+ */
+ function absDev() {/*{{{*/
+ if (!array_key_exists('absDev', $this->_calculatedValues)) {
+ $absDev = $this->__calcAbsoluteDeviation();
+ if (PEAR::isError($absdev)) {
+ return $absdev;
+ }
+ $this->_calculatedValues['absDev'] = $absDev;
+ }
+ return $this->_calculatedValues['absDev'];
+ }/*}}}*/
+
+ /**
+ * Calculates the absolute deviation of the data points in the set
+ * given a fixed mean (average) value. Not used in calcBasic(), calcFull()
+ * or calc().
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @param numeric $mean the fixed mean value
+ * @return mixed the absolute deviation on success, a PEAR_Error object otherwise
+ * @see __sumabsdev()
+ * @see absDev()
+ */
+ function absDevWithMean($mean) {/*{{{*/
+ return $this->__calcAbsoluteDeviation($mean);
+ }/*}}}*/
+
+ /**
+ * Calculates the skewness of the data distribution in the set
+ * The skewness measures the degree of asymmetry of a distribution,
+ * and is related to the third central moment of a distribution.
+ * A normal distribution has a skewness = 0
+ * A distribution with a tail off towards the high end of the scale
+ * (positive skew) has a skewness > 0
+ * A distribution with a tail off towards the low end of the scale
+ * (negative skew) has a skewness < 0
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @return mixed the skewness value on success, a PEAR_Error object otherwise
+ * @see __sumdiff()
+ * @see count()
+ * @see stDev()
+ * @see calc()
+ */
+ function skewness() {/*{{{*/
+ if (!array_key_exists('skewness', $this->_calculatedValues)) {
+ $count = $this->count();
+ if (PEAR::isError($count)) {
+ return $count;
+ }
+ $stDev = $this->stDev();
+ if (PEAR::isError($stDev)) {
+ return $stDev;
+ }
+ $sumdiff3 = $this->__sumdiff(3);
+ if (PEAR::isError($sumdiff3)) {
+ return $sumdiff3;
+ }
+ $this->_calculatedValues['skewness'] = ($sumdiff3 / ($count * pow($stDev, 3)));
+ }
+ return $this->_calculatedValues['skewness'];
+ }/*}}}*/
+
+ /**
+ * Calculates the kurtosis of the data distribution in the set
+ * The kurtosis measures the degrees of peakedness of a distribution.
+ * It is also called the "excess" or "excess coefficient", and is
+ * a normalized form of the fourth central moment of a distribution.
+ * A normal distributions has kurtosis = 0
+ * A narrow and peaked (leptokurtic) distribution has a
+ * kurtosis > 0
+ * A flat and wide (platykurtic) distribution has a kurtosis < 0
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @return mixed the kurtosis value on success, a PEAR_Error object otherwise
+ * @see __sumdiff()
+ * @see count()
+ * @see stDev()
+ * @see calc()
+ */
+ function kurtosis() {/*{{{*/
+ if (!array_key_exists('kurtosis', $this->_calculatedValues)) {
+ $count = $this->count();
+ if (PEAR::isError($count)) {
+ return $count;
+ }
+ $stDev = $this->stDev();
+ if (PEAR::isError($stDev)) {
+ return $stDev;
+ }
+ $sumdiff4 = $this->__sumdiff(4);
+ if (PEAR::isError($sumdiff4)) {
+ return $sumdiff4;
+ }
+ $this->_calculatedValues['kurtosis'] = ($sumdiff4 / ($count * pow($stDev, 4))) - 3;
+ }
+ return $this->_calculatedValues['kurtosis'];
+ }/*}}}*/
+
+ /**
+ * Calculates the median of a data set.
+ * The median is the value such that half of the points are below it
+ * in a sorted data set.
+ * If the number of values is odd, it is the middle item.
+ * If the number of values is even, is the average of the two middle items.
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @return mixed the median value on success, a PEAR_Error object otherwise
+ * @see count()
+ * @see calc()
+ */
+ function median() {/*{{{*/
+ if ($this->_data == null) {
+ return PEAR::raiseError('data has not been set');
+ }
+ if (!array_key_exists('median', $this->_calculatedValues)) {
+ if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
+ $arr =& $this->_dataExpanded;
+ } else {
+ $arr =& $this->_data;
+ }
+ $n = $this->count();
+ if (PEAR::isError($n)) {
+ return $n;
+ }
+ $h = intval($n / 2);
+ if ($n % 2 == 0) {
+ $median = ($arr[$h] + $arr[$h - 1]) / 2;
+ } else {
+ $median = $arr[$h + 1];
+ }
+ $this->_calculatedValues['median'] = $median;
+ }
+ return $this->_calculatedValues['median'];
+ }/*}}}*/
+
+ /**
+ * Calculates the mode of a data set.
+ * The mode is the value with the highest frequency in the data set.
+ * There can be more than one mode.
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @return mixed an array of mode value on success, a PEAR_Error object otherwise
+ * @see frequency()
+ * @see calc()
+ */
+ function mode() {/*{{{*/
+ if ($this->_data == null) {
+ return PEAR::raiseError('data has not been set');
+ }
+ if (!array_key_exists('mode', $this->_calculatedValues)) {
+ if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
+ $arr = $this->_data;
+ } else {
+ $arr = $this->frequency();
+ }
+ arsort($arr);
+ $mcount = 1;
+ foreach ($arr as $val=>$freq) {
+ if ($mcount == 1) {
+ $mode = array($val);
+ $mfreq = $freq;
+ ++$mcount;
+ continue;
+ }
+ if ($mfreq == $freq)
+ $mode[] = $val;
+ if ($mfreq > $freq)
+ break;
+ }
+ $this->_calculatedValues['mode'] = $mode;
+ }
+ return $this->_calculatedValues['mode'];
+ }/*}}}*/
+
+ /**
+ * Calculates the midrange of a data set.
+ * The midrange is the average of the minimum and maximum of the data set.
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @return mixed the midrange value on success, a PEAR_Error object otherwise
+ * @see min()
+ * @see max()
+ * @see calc()
+ */
+ function midrange() {/*{{{*/
+ if (!array_key_exists('midrange', $this->_calculatedValues)) {
+ $min = $this->min();
+ if (PEAR::isError($min)) {
+ return $min;
+ }
+ $max = $this->max();
+ if (PEAR::isError($max)) {
+ return $max;
+ }
+ $this->_calculatedValues['midrange'] = (($max + $min) / 2);
+ }
+ return $this->_calculatedValues['midrange'];
+ }/*}}}*/
+
+ /**
+ * Calculates the geometrical mean of the data points in the set
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @return mixed the geometrical mean value on success, a PEAR_Error object otherwise
+ * @see calc()
+ * @see product()
+ * @see count()
+ */
+ function geometricMean() {/*{{{*/
+ if (!array_key_exists('geometricMean', $this->_calculatedValues)) {
+ $count = $this->count();
+ if (PEAR::isError($count)) {
+ return $count;
+ }
+ $prod = $this->product();
+ if (PEAR::isError($prod)) {
+ return $prod;
+ }
+ if ($prod == 0.0) {
+ return 0.0;
+ }
+ if ($prod < 0) {
+ return PEAR::raiseError('The product of the data set is negative, geometric mean undefined.');
+ }
+ $this->_calculatedValues['geometricMean'] = pow($prod , 1 / $count);
+ }
+ return $this->_calculatedValues['geometricMean'];
+ }/*}}}*/
+
+ /**
+ * Calculates the harmonic mean of the data points in the set
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @return mixed the harmonic mean value on success, a PEAR_Error object otherwise
+ * @see calc()
+ * @see count()
+ */
+ function harmonicMean() {/*{{{*/
+ if ($this->_data == null) {
+ return PEAR::raiseError('data has not been set');
+ }
+ if (!array_key_exists('harmonicMean', $this->_calculatedValues)) {
+ $count = $this->count();
+ if (PEAR::isError($count)) {
+ return $count;
+ }
+ $invsum = 0.0;
+ if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
+ foreach($this->_data as $val=>$freq) {
+ if ($val == 0) {
+ return PEAR::raiseError('cannot calculate a '.
+ 'harmonic mean with data values of zero.');
+ }
+ $invsum += $freq / $val;
+ }
+ } else {
+ foreach($this->_data as $val) {
+ if ($val == 0) {
+ return PEAR::raiseError('cannot calculate a '.
+ 'harmonic mean with data values of zero.');
+ }
+ $invsum += 1 / $val;
+ }
+ }
+ $this->_calculatedValues['harmonicMean'] = $count / $invsum;
+ }
+ return $this->_calculatedValues['harmonicMean'];
+ }/*}}}*/
+
+ /**
+ * Calculates the nth central moment (m{n}) of a data set.
+ *
+ * The definition of a sample central moment is:
+ *
+ * m{n} = 1/N * SUM { (xi - avg)^n }
+ *
+ * where: N = sample size, avg = sample mean.
+ *
+ * @access public
+ * @param integer $n moment to calculate
+ * @return mixed the numeric value of the moment on success, PEAR_Error otherwise
+ */
+ function sampleCentralMoment($n) {/*{{{*/
+ if (!is_int($n) || $n < 1) {
+ return PEAR::isError('moment must be a positive integer >= 1.');
+ }
+
+ if ($n == 1) {
+ return 0;
+ }
+ $count = $this->count();
+ if (PEAR::isError($count)) {
+ return $count;
+ }
+ if ($count == 0) {
+ return PEAR::raiseError("Cannot calculate {$n}th sample moment, ".
+ 'there are zero data entries');
+ }
+ $sum = $this->__sumdiff($n);
+ if (PEAR::isError($sum)) {
+ return $sum;
+ }
+ return ($sum / $count);
+ }/*}}}*/
+
+ /**
+ * Calculates the nth raw moment (m{n}) of a data set.
+ *
+ * The definition of a sample central moment is:
+ *
+ * m{n} = 1/N * SUM { xi^n }
+ *
+ * where: N = sample size, avg = sample mean.
+ *
+ * @access public
+ * @param integer $n moment to calculate
+ * @return mixed the numeric value of the moment on success, PEAR_Error otherwise
+ */
+ function sampleRawMoment($n) {/*{{{*/
+ if (!is_int($n) || $n < 1) {
+ return PEAR::isError('moment must be a positive integer >= 1.');
+ }
+
+ $count = $this->count();
+ if (PEAR::isError($count)) {
+ return $count;
+ }
+ if ($count == 0) {
+ return PEAR::raiseError("Cannot calculate {$n}th raw moment, ".
+ 'there are zero data entries.');
+ }
+ $sum = $this->sumN($n);
+ if (PEAR::isError($sum)) {
+ return $sum;
+ }
+ return ($sum / $count);
+ }/*}}}*/
+
+
+ /**
+ * Calculates the coefficient of variation of a data set.
+ * The coefficient of variation measures the spread of a set of data
+ * as a proportion of its mean. It is often expressed as a percentage.
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @return mixed the coefficient of variation on success, a PEAR_Error object otherwise
+ * @see stDev()
+ * @see mean()
+ * @see calc()
+ */
+ function coeffOfVariation() {/*{{{*/
+ if (!array_key_exists('coeffOfVariation', $this->_calculatedValues)) {
+ $mean = $this->mean();
+ if (PEAR::isError($mean)) {
+ return $mean;
+ }
+ if ($mean == 0.0) {
+ return PEAR::raiseError('cannot calculate the coefficient '.
+ 'of variation, mean of sample is zero');
+ }
+ $stDev = $this->stDev();
+ if (PEAR::isError($stDev)) {
+ return $stDev;
+ }
+
+ $this->_calculatedValues['coeffOfVariation'] = $stDev / $mean;
+ }
+ return $this->_calculatedValues['coeffOfVariation'];
+ }/*}}}*/
+
+ /**
+ * Calculates the standard error of the mean.
+ * It is the standard deviation of the sampling distribution of
+ * the mean. The formula is:
+ *
+ * S.E. Mean = SD / (N)^(1/2)
+ *
+ * This formula does not assume a normal distribution, and shows
+ * that the size of the standard error of the mean is inversely
+ * proportional to the square root of the sample size.
+ *
+ * @access public
+ * @return mixed the standard error of the mean on success, a PEAR_Error object otherwise
+ * @see stDev()
+ * @see count()
+ * @see calc()
+ */
+ function stdErrorOfMean() {/*{{{*/
+ if (!array_key_exists('stdErrorOfMean', $this->_calculatedValues)) {
+ $count = $this->count();
+ if (PEAR::isError($count)) {
+ return $count;
+ }
+ $stDev = $this->stDev();
+ if (PEAR::isError($stDev)) {
+ return $stDev;
+ }
+ $this->_calculatedValues['stdErrorOfMean'] = $stDev / sqrt($count);
+ }
+ return $this->_calculatedValues['stdErrorOfMean'];
+ }/*}}}*/
+
+ /**
+ * Calculates the value frequency table of a data set.
+ * Handles cummulative data sets correctly
+ *
+ * @access public
+ * @return mixed an associative array of value=>frequency items on success, a PEAR_Error object otherwise
+ * @see min()
+ * @see max()
+ * @see calc()
+ */
+ function frequency() {/*{{{*/
+ if ($this->_data == null) {
+ return PEAR::raiseError('data has not been set');
+ }
+ if (!array_key_exists('frequency', $this->_calculatedValues)) {
+ if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
+ $freq = $this->_data;
+ } else {
+ $freq = array();
+ foreach ($this->_data as $val) {
+ $freq["$val"]++;
+ }
+ ksort($freq);
+ }
+ $this->_calculatedValues['frequency'] = $freq;
+ }
+ return $this->_calculatedValues['frequency'];
+ }/*}}}*/
+
+ /**
+ * The quartiles are defined as the values that divide a sorted
+ * data set into four equal-sized subsets, and correspond to the
+ * 25th, 50th, and 75th percentiles.
+ *
+ * @access public
+ * @return mixed an associative array of quartiles on success, a PEAR_Error otherwise
+ * @see percentile()
+ */
+ function quartiles() {/*{{{*/
+ if (!array_key_exists('quartiles', $this->_calculatedValues)) {
+ $q1 = $this->percentile(25);
+ if (PEAR::isError($q1)) {
+ return $q1;
+ }
+ $q2 = $this->percentile(50);
+ if (PEAR::isError($q2)) {
+ return $q2;
+ }
+ $q3 = $this->percentile(75);
+ if (PEAR::isError($q3)) {
+ return $q3;
+ }
+ $this->_calculatedValues['quartiles'] = array (
+ '25' => $q1,
+ '50' => $q2,
+ '75' => $q3
+ );
+ }
+ return $this->_calculatedValues['quartiles'];
+ }/*}}}*/
+
+ /**
+ * The interquartile mean is defined as the mean of the values left
+ * after discarding the lower 25% and top 25% ranked values, i.e.:
+ *
+ * interquart mean = mean(<P(25),P(75)>)
+ *
+ * where: P = percentile
+ *
+ * @todo need to double check the equation
+ * @access public
+ * @return mixed a numeric value on success, a PEAR_Error otherwise
+ * @see quartiles()
+ */
+ function interquartileMean() {/*{{{*/
+ if (!array_key_exists('interquartileMean', $this->_calculatedValues)) {
+ $quart = $this->quartiles();
+ if (PEAR::isError($quart)) {
+ return $quart;
+ }
+ $q3 = $quart['75'];
+ $q1 = $quart['25'];
+ $sum = 0;
+ $n = 0;
+ foreach ($this->getData(true) as $val) {
+ if ($val >= $q1 && $val <= $q3) {
+ $sum += $val;
+ ++$n;
+ }
+ }
+ if ($n == 0) {
+ return PEAR::raiseError('error calculating interquartile mean, '.
+ 'empty interquartile range of values.');
+ }
+ $this->_calculatedValues['interquartileMean'] = $sum / $n;
+ }
+ return $this->_calculatedValues['interquartileMean'];
+ }/*}}}*/
+
+ /**
+ * The interquartile range is the distance between the 75th and 25th
+ * percentiles. Basically the range of the middle 50% of the data set,
+ * and thus is not affected by outliers or extreme values.
+ *
+ * interquart range = P(75) - P(25)
+ *
+ * where: P = percentile
+ *
+ * @access public
+ * @return mixed a numeric value on success, a PEAR_Error otherwise
+ * @see quartiles()
+ */
+ function interquartileRange() {/*{{{*/
+ if (!array_key_exists('interquartileRange', $this->_calculatedValues)) {
+ $quart = $this->quartiles();
+ if (PEAR::isError($quart)) {
+ return $quart;
+ }
+ $q3 = $quart['75'];
+ $q1 = $quart['25'];
+ $this->_calculatedValues['interquartileRange'] = $q3 - $q1;
+ }
+ return $this->_calculatedValues['interquartileRange'];
+ }/*}}}*/
+
+ /**
+ * The quartile deviation is half of the interquartile range value
+ *
+ * quart dev = (P(75) - P(25)) / 2
+ *
+ * where: P = percentile
+ *
+ * @access public
+ * @return mixed a numeric value on success, a PEAR_Error otherwise
+ * @see quartiles()
+ * @see interquartileRange()
+ */
+ function quartileDeviation() {/*{{{*/
+ if (!array_key_exists('quartileDeviation', $this->_calculatedValues)) {
+ $iqr = $this->interquartileRange();
+ if (PEAR::isError($iqr)) {
+ return $iqr;
+ }
+ $this->_calculatedValues['quartileDeviation'] = $iqr / 2;
+ }
+ return $this->_calculatedValues['quartileDeviation'];
+ }/*}}}*/
+
+ /**
+ * The quartile variation coefficient is defines as follows:
+ *
+ * quart var coeff = 100 * (P(75) - P(25)) / (P(75) + P(25))
+ *
+ * where: P = percentile
+ *
+ * @todo need to double check the equation
+ * @access public
+ * @return mixed a numeric value on success, a PEAR_Error otherwise
+ * @see quartiles()
+ */
+ function quartileVariationCoefficient() {/*{{{*/
+ if (!array_key_exists('quartileVariationCoefficient', $this->_calculatedValues)) {
+ $quart = $this->quartiles();
+ if (PEAR::isError($quart)) {
+ return $quart;
+ }
+ $q3 = $quart['75'];
+ $q1 = $quart['25'];
+ $d = $q3 - $q1;
+ $s = $q3 + $q1;
+ $this->_calculatedValues['quartileVariationCoefficient'] = 100 * $d / $s;
+ }
+ return $this->_calculatedValues['quartileVariationCoefficient'];
+ }/*}}}*/
+
+ /**
+ * The quartile skewness coefficient (also known as Bowley Skewness),
+ * is defined as follows:
+ *
+ * quart skewness coeff = (P(25) - 2*P(50) + P(75)) / (P(75) - P(25))
+ *
+ * where: P = percentile
+ *
+ * @todo need to double check the equation
+ * @access public
+ * @return mixed a numeric value on success, a PEAR_Error otherwise
+ * @see quartiles()
+ */
+ function quartileSkewnessCoefficient() {/*{{{*/
+ if (!array_key_exists('quartileSkewnessCoefficient', $this->_calculatedValues)) {
+ $quart = $this->quartiles();
+ if (PEAR::isError($quart)) {
+ return $quart;
+ }
+ $q3 = $quart['75'];
+ $q2 = $quart['50'];
+ $q1 = $quart['25'];
+ $d = $q3 - 2*$q2 + $q1;
+ $s = $q3 - $q1;
+ $this->_calculatedValues['quartileSkewnessCoefficient'] = $d / $s;
+ }
+ return $this->_calculatedValues['quartileSkewnessCoefficient'];
+ }/*}}}*/
+
+ /**
+ * The pth percentile is the value such that p% of the a sorted data set
+ * is smaller than it, and (100 - p)% of the data is larger.
+ *
+ * A quick algorithm to pick the appropriate value from a sorted data
+ * set is as follows:
+ *
+ * - Count the number of values: n
+ * - Calculate the position of the value in the data list: i = p * (n + 1)
+ * - if i is an integer, return the data at that position
+ * - if i < 1, return the minimum of the data set
+ * - if i > n, return the maximum of the data set
+ * - otherwise, average the entries at adjacent positions to i
+ *
+ * The median is the 50th percentile value.
+ *
+ * @todo need to double check generality of the algorithm
+ *
+ * @access public
+ * @param numeric $p the percentile to estimate, e.g. 25 for 25th percentile
+ * @return mixed a numeric value on success, a PEAR_Error otherwise
+ * @see quartiles()
+ * @see median()
+ */
+ function percentile($p) {/*{{{*/
+ $count = $this->count();
+ if (PEAR::isError($count)) {
+ return $count;
+ }
+ if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
+ $data =& $this->_dataExpanded;
+ } else {
+ $data =& $this->_data;
+ }
+ $obsidx = $p * ($count + 1) / 100;
+ if (intval($obsidx) == $obsidx) {
+ return $data[($obsidx - 1)];
+ } elseif ($obsidx < 1) {
+ return $data[0];
+ } elseif ($obsidx > $count) {
+ return $data[($count - 1)];
+ } else {
+ $left = floor($obsidx - 1);
+ $right = ceil($obsidx - 1);
+ return ($data[$left] + $data[$right]) / 2;
+ }
+ }/*}}}*/
+
+ // private methods
+
+ /**
+ * Utility function to calculate: SUM { (xi - mean)^n }
+ *
+ * @access private
+ * @param numeric $power the exponent
+ * @param optional double $mean the data set mean value
+ * @return mixed the sum on success, a PEAR_Error object otherwise
+ *
+ * @see stDev()
+ * @see variaceWithMean();
+ * @see skewness();
+ * @see kurtosis();
+ */
+ function __sumdiff($power, $mean=null) {/*{{{*/
+ if ($this->_data == null) {
+ return PEAR::raiseError('data has not been set');
+ }
+ if (is_null($mean)) {
+ $mean = $this->mean();
+ if (PEAR::isError($mean)) {
+ return $mean;
+ }
+ }
+ $sdiff = 0;
+ if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
+ foreach ($this->_data as $val=>$freq) {
+ $sdiff += $freq * pow((double)($val - $mean), (double)$power);
+ }
+ } else {
+ foreach ($this->_data as $val)
+ $sdiff += pow((double)($val - $mean), (double)$power);
+ }
+ return $sdiff;
+ }/*}}}*/
+
+ /**
+ * Utility function to calculate the variance with or without
+ * a fixed mean
+ *
+ * @access private
+ * @param $mean the fixed mean to use, null as default
+ * @return mixed a numeric value on success, a PEAR_Error otherwise
+ * @see variance()
+ * @see varianceWithMean()
+ */
+ function __calcVariance($mean = null) {/*{{{*/
+ if ($this->_data == null) {
+ return PEAR::raiseError('data has not been set');
+ }
+ $sumdiff2 = $this->__sumdiff(2, $mean);
+ if (PEAR::isError($sumdiff2)) {
+ return $sumdiff2;
+ }
+ $count = $this->count();
+ if (PEAR::isError($count)) {
+ return $count;
+ }
+ if ($count == 1) {
+ return PEAR::raiseError('cannot calculate variance of a singe data point');
+ }
+ return ($sumdiff2 / ($count - 1));
+ }/*}}}*/
+
+ /**
+ * Utility function to calculate the absolute deviation with or without
+ * a fixed mean
+ *
+ * @access private
+ * @param $mean the fixed mean to use, null as default
+ * @return mixed a numeric value on success, a PEAR_Error otherwise
+ * @see absDev()
+ * @see absDevWithMean()
+ */
+ function __calcAbsoluteDeviation($mean = null) {/*{{{*/
+ if ($this->_data == null) {
+ return PEAR::raiseError('data has not been set');
+ }
+ $count = $this->count();
+ if (PEAR::isError($count)) {
+ return $count;
+ }
+ $sumabsdev = $this->__sumabsdev($mean);
+ if (PEAR::isError($sumabsdev)) {
+ return $sumabsdev;
+ }
+ return $sumabsdev / $count;
+ }/*}}}*/
+
+ /**
+ * Utility function to calculate: SUM { | xi - mean | }
+ *
+ * @access private
+ * @param optional double $mean the mean value for the set or population
+ * @return mixed the sum on success, a PEAR_Error object otherwise
+ *
+ * @see absDev()
+ * @see absDevWithMean()
+ */
+ function __sumabsdev($mean=null) {/*{{{*/
+ if ($this->_data == null) {
+ return PEAR::raiseError('data has not been set');
+ }
+ if (is_null($mean)) {
+ $mean = $this->mean();
+ }
+ $sdev = 0;
+ if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
+ foreach ($this->_data as $val=>$freq) {
+ $sdev += $freq * abs($val - $mean);
+ }
+ } else {
+ foreach ($this->_data as $val) {
+ $sdev += abs($val - $mean);
+ }
+ }
+ return $sdev;
+ }/*}}}*/
+
+ /**
+ * Utility function to format a PEAR_Error to be used by calc(),
+ * calcBasic() and calcFull()
+ *
+ * @access private
+ * @param mixed $v value to be formatted
+ * @param boolean $returnErrorObject whether the raw PEAR_Error (when true, default),
+ * or only the error message will be returned (when false)
+ * @return mixed if the value is a PEAR_Error object, and $useErrorObject
+ * is false, then a string with the error message will be returned,
+ * otherwise the value will not be modified and returned as passed.
+ */
+ function __format($v, $useErrorObject=true) {/*{{{*/
+ if (PEAR::isError($v) && $useErrorObject == false) {
+ return $v->getMessage();
+ } else {
+ return $v;
+ }
+ }/*}}}*/
+
+ /**
+ * Utility function to validate the data and modify it
+ * according to the current null handling option
+ *
+ * @access private
+ * @return mixed true on success, a PEAR_Error object otherwise
+ *
+ * @see setData()
+ */
+ function _validate() {/*{{{*/
+ $flag = ($this->_dataOption == STATS_DATA_CUMMULATIVE);
+ foreach ($this->_data as $key=>$value) {
+ $d = ($flag) ? $key : $value;
+ $v = ($flag) ? $value : $key;
+ if (!is_numeric($d)) {
+ switch ($this->_nullOption) {
+ case STATS_IGNORE_NULL :
+ unset($this->_data["$key"]);
+ break;
+ case STATS_USE_NULL_AS_ZERO:
+ if ($flag) {
+ unset($this->_data["$key"]);
+ $this->_data[0] += $v;
+ } else {
+ $this->_data[$key] = 0;
+ }
+ break;
+ case STATS_REJECT_NULL :
+ default:
+ return PEAR::raiseError('data rejected, contains NULL values');
+ break;
+ }
+ }
+ }
+ if ($flag) {
+ ksort($this->_data);
+ $this->_dataExpanded = array();
+ foreach ($this->_data as $val=>$freq) {
+ $this->_dataExpanded = array_pad($this->_dataExpanded, count($this->_dataExpanded) + $freq, $val);
+ }
+ sort($this->_dataExpanded);
+ } else {
+ sort($this->_data);
+ }
+ return true;
+ }/*}}}*/
+
+}/*}}}*/
+
+// vim: ts=4:sw=4:et:
+// vim6: fdl=1: fdm=marker:
+
+?>
diff --git a/admin/survey/excel/PHPExcel/Shared/JAMA/examples/benchmark.php b/admin/survey/excel/PHPExcel/Shared/JAMA/examples/benchmark.php
new file mode 100644
index 0000000..42a4884
--- /dev/null
+++ b/admin/survey/excel/PHPExcel/Shared/JAMA/examples/benchmark.php
@@ -0,0 +1,263 @@
+<?php
+
+error_reporting(E_ALL);
+
+/**
+ * @package JAMA
+ */
+
+require_once '../Matrix.php';
+require_once 'Stats.php';
+
+
+/**
+ * Example of use of Matrix Class, featuring magic squares.
+ */
+class Benchmark {
+ public $stat;
+
+
+ /**
+ * Simple function to replicate PHP 5 behaviour
+ */
+ function microtime_float() {
+ list($usec, $sec) = explode(" ", microtime());
+
+ return ((float)$usec + (float)$sec);
+ } // function microtime_float()
+
+
+ function displayStats($times = null) {
+ $this->stat->setData($times);
+ $stats = $this->stat->calcFull();
+
+ echo '<table style="margin-left:32px;">';
+ echo '<tr><td style="text-align:right;"><b>n:</b><td style="text-align:right;">' . $stats['count'] . ' </td></tr>';
+ echo '<tr><td style="text-align:right;"><b>Mean:</b><td style="text-align:right;">' . $stats['mean'] . ' </td></tr>';
+ echo '<tr><td style="text-align:right;"><b>Min.:</b><td style="text-align:right;">' . $stats['min'] . ' </td></tr>';
+ echo '<tr><td style="text-align:right;"><b>Max.:</b><td style="text-align:right;">' . $stats['max'] . ' </td></tr>';
+ echo '<tr><td style="text-align:right;"><b>&sigma;:</b><td style="text-align:right;">' . $stats['stdev'] . ' </td></tr>';
+ echo '<tr><td style="text-align:right;"><b>Variance:</b><td style="text-align:right;">' . $stats['variance'] . ' </td></tr>';
+ echo '<tr><td style="text-align:right;"><b>Range:</b><td style="text-align:right;">' . $stats['range'] . ' </td></tr>';
+ echo '</table>';
+
+ return $stats;
+ } // function displayStats()
+
+
+ function runEig($n = 4, $t = 100) {
+ $times = array();
+
+ for ($i = 0; $i < $t; ++$i) {
+ $M = Matrix::random($n, $n);
+ $start_time = $this->microtime_float();
+ $E = new EigenvalueDecomposition($M);
+ $stop_time = $this->microtime_float();
+ $times[] = $stop_time - $start_time;
+ }
+
+ return $times;
+ } // function runEig()
+
+
+ function runLU($n = 4, $t = 100) {
+ $times = array();
+
+ for ($i = 0; $i < $t; ++$i) {
+ $M = Matrix::random($n, $n);
+ $start_time = $this->microtime_float();
+ $E = new LUDecomposition($M);
+ $stop_time = $this->microtime_float();
+ $times[] = $stop_time - $start_time;
+ }
+
+ return $times;
+ } // function runLU()
+
+
+ function runQR($n = 4, $t = 100) {
+ $times = array();
+
+ for ($i = 0; $i < $t; ++$i) {
+ $M = Matrix::random($n, $n);
+ $start_time = $this->microtime_float();
+ $E = new QRDecomposition($M);
+ $stop_time = $this->microtime_float();
+ $times[] = $stop_time - $start_time;
+ }
+
+ return $times;
+ } // function runQR()
+
+
+ function runCholesky($n = 4, $t = 100) {
+ $times = array();
+
+ for ($i = 0; $i < $t; ++$i) {
+ $M = Matrix::random($n, $n);
+ $start_time = $this->microtime_float();
+ $E = new CholeskyDecomposition($M);
+ $stop_time = $this->microtime_float();
+ $times[] = $stop_time - $start_time;
+ }
+
+ return $times;
+ } // function runCholesky()
+
+
+ function runSVD($n = 4, $t = 100) {
+ $times = array();
+
+ for ($i = 0; $i < $t; ++$i) {
+ $M = Matrix::random($n, $n);
+ $start_time = $this->microtime_float();
+ $E = new SingularValueDecomposition($M);
+ $stop_time = $this->microtime_float();
+ $times[] = $stop_time - $start_time;
+ }
+
+ return $times;
+ } // function runSVD()
+
+
+ function run() {
+ $n = 8;
+ $t = 16;
+ $sum = 0;
+ echo "<b>Cholesky decomposition: $t random {$n}x{$n} matrices</b><br />";
+ $r = $this->displayStats($this->runCholesky($n, $t));
+ $sum += $r['mean'] * $n;
+
+ echo '<hr />';
+
+ echo "<b>Eigenvalue decomposition: $t random {$n}x{$n} matrices</b><br />";
+ $r = $this->displayStats($this->runEig($n, $t));
+ $sum += $r['mean'] * $n;
+
+ echo '<hr />';
+
+ echo "<b>LU decomposition: $t random {$n}x{$n} matrices</b><br />";
+ $r = $this->displayStats($this->runLU($n, $t));
+ $sum += $r['mean'] * $n;
+
+ echo '<hr />';
+
+ echo "<b>QR decomposition: $t random {$n}x{$n} matrices</b><br />";
+ $r = $this->displayStats($this->runQR($n, $t));
+ $sum += $r['mean'] * $n;
+
+ echo '<hr />';
+
+ echo "<b>Singular Value decomposition: $t random {$n}x{$n} matrices</b><br />";
+ $r = $this->displayStats($this->runSVD($n, $t));
+ $sum += $r['mean'] * $n;
+
+ return $sum;
+ } // function run()
+
+
+ public function __construct() {
+ $this->stat = new Base();
+ } // function Benchmark()
+
+} // class Benchmark (end MagicSquareExample)
+
+
+$benchmark = new Benchmark();
+
+switch($_REQUEST['decomposition']) {
+ case 'cholesky':
+ $m = array();
+ for ($i = 2; $i <= 8; $i *= 2) {
+ $t = 32 / $i;
+ echo "<b>Cholesky decomposition: $t random {$i}x{$i} matrices</b><br />";
+ $s = $benchmark->displayStats($benchmark->runCholesky($i, $t));
+ $m[$i] = $s['mean'];
+ echo "<br />";
+ }
+ echo '<pre>';
+ foreach($m as $x => $y) {
+ echo "$x\t" . 1000*$y . "\n";
+ }
+ echo '</pre>';
+ break;
+ case 'eigenvalue':
+ $m = array();
+ for ($i = 2; $i <= 8; $i *= 2) {
+ $t = 32 / $i;
+ echo "<b>Eigenvalue decomposition: $t random {$i}x{$i} matrices</b><br />";
+ $s = $benchmark->displayStats($benchmark->runEig($i, $t));
+ $m[$i] = $s['mean'];
+ echo "<br />";
+ }
+ echo '<pre>';
+ foreach($m as $x => $y) {
+ echo "$x\t" . 1000*$y . "\n";
+ }
+ echo '</pre>';
+ break;
+ case 'lu':
+ $m = array();
+ for ($i = 2; $i <= 8; $i *= 2) {
+ $t = 32 / $i;
+ echo "<b>LU decomposition: $t random {$i}x{$i} matrices</b><br />";
+ $s = $benchmark->displayStats($benchmark->runLU($i, $t));
+ $m[$i] = $s['mean'];
+ echo "<br />";
+ }
+ echo '<pre>';
+ foreach($m as $x => $y) {
+ echo "$x\t" . 1000*$y . "\n";
+ }
+ echo '</pre>';
+ break;
+ case 'qr':
+ $m = array();
+ for ($i = 2; $i <= 8; $i *= 2) {
+ $t = 32 / $i;
+ echo "<b>QR decomposition: $t random {$i}x{$i} matrices</b><br />";
+ $s = $benchmark->displayStats($benchmark->runQR($i, $t));
+ $m[$i] = $s['mean'];
+ echo "<br />";
+ }
+ echo '<pre>';
+ foreach($m as $x => $y) {
+ echo "$x\t" . 1000*$y . "\n";
+ }
+ echo '</pre>';
+ break;
+ case 'svd':
+ $m = array();
+ for($i = 2; $i <= 8; $i *= 2) {
+ $t = 32 / $i;
+ echo "<b>Singular value decomposition: $t random {$i}x{$i} matrices</b><br />";
+ $s = $benchmark->displayStats($benchmark->runSVD($i, $t));
+ $m[$i] = $s['mean'];
+ echo "<br />";
+ }
+ echo '<pre>';
+ foreach($m as $x => $y) {
+ echo "$x\t" . 1000*$y . "\n";
+ }
+ echo '</pre>';
+ break;
+ case 'all':
+ $s = $benchmark->run();
+ print("<br /><b>Total<b>: {$s}s<br />");
+ break;
+ default:
+ ?>
+ <ul>
+ <li><a href="benchmark.php?decomposition=all">Complete Benchmark</a>
+ <ul>
+ <li><a href="benchmark.php?decomposition=cholesky">Cholesky</a></li>
+ <li><a href="benchmark.php?decomposition=eigenvalue">Eigenvalue</a></li>
+ <li><a href="benchmark.php?decomposition=lu">LU</a></li>
+ <li><a href="benchmark.php?decomposition=qr">QR</a></li>
+ <li><a href="benchmark.php?decomposition=svd">Singular Value</a></li>
+ </ul>
+ </li>
+ </ul>
+ <?php
+ break;
+}
diff --git a/admin/survey/excel/PHPExcel/Shared/JAMA/examples/polyfit.php b/admin/survey/excel/PHPExcel/Shared/JAMA/examples/polyfit.php
new file mode 100644
index 0000000..fffc864
--- /dev/null
+++ b/admin/survey/excel/PHPExcel/Shared/JAMA/examples/polyfit.php
@@ -0,0 +1,73 @@
+<?php
+require_once "../Matrix.php";
+/*
+* @package JAMA
+* @author Michael Bommarito
+* @author Paul Meagher
+* @version 0.1
+*
+* Function to fit an order n polynomial function through
+* a series of x-y data points using least squares.
+*
+* @param $X array x values
+* @param $Y array y values
+* @param $n int order of polynomial to be used for fitting
+* @returns array $coeffs of polynomial coefficients
+* Pre-Conditions: the system is not underdetermined: sizeof($X) > $n+1
+*/
+function polyfit($X, $Y, $n) {
+ for ($i = 0; $i < sizeof($X); ++$i)
+ for ($j = 0; $j <= $n; ++$j)
+ $A[$i][$j] = pow($X[$i], $j);
+ for ($i=0; $i < sizeof($Y); ++$i)
+ $B[$i] = array($Y[$i]);
+ $matrixA = new Matrix($A);
+ $matrixB = new Matrix($B);
+ $C = $matrixA->solve($matrixB);
+ return $C->getMatrix(0, $n, 0, 1);
+}
+
+function printpoly( $C = null ) {
+ for($i = $C->m - 1; $i >= 0; --$i) {
+ $r = $C->get($i, 0);
+ if ( abs($r) <= pow(10, -9) )
+ $r = 0;
+ if ($i == $C->m - 1)
+ echo $r . "x<sup>$i</sup>";
+ else if ($i < $C->m - 1)
+ echo " + " . $r . "x<sup>$i</sup>";
+ else if ($i == 0)
+ echo " + " . $r;
+ }
+}
+
+$X = array(0,1,2,3,4,5);
+$Y = array(4,3,12,67,228, 579);
+$points = new Matrix(array($X, $Y));
+$points->toHTML();
+printpoly(polyfit($X, $Y, 4));
+
+echo '<hr />';
+
+$X = array(0,1,2,3,4,5);
+$Y = array(1,2,5,10,17, 26);
+$points = new Matrix(array($X, $Y));
+$points->toHTML();
+printpoly(polyfit($X, $Y, 2));
+
+echo '<hr />';
+
+$X = array(0,1,2,3,4,5,6);
+$Y = array(-90,-104,-178,-252,-26, 1160, 4446);
+$points = new Matrix(array($X, $Y));
+$points->toHTML();
+printpoly(polyfit($X, $Y, 5));
+
+echo '<hr />';
+
+$X = array(0,1,2,3,4);
+$Y = array(mt_rand(0, 10), mt_rand(40, 80), mt_rand(240, 400), mt_rand(1800, 2215), mt_rand(8000, 9000));
+$points = new Matrix(array($X, $Y));
+$points->toHTML();
+printpoly(polyfit($X, $Y, 3));
+?>
diff --git a/admin/survey/excel/PHPExcel/Shared/JAMA/examples/tile.php b/admin/survey/excel/PHPExcel/Shared/JAMA/examples/tile.php
new file mode 100644
index 0000000..b5c48e1
--- /dev/null
+++ b/admin/survey/excel/PHPExcel/Shared/JAMA/examples/tile.php
@@ -0,0 +1,78 @@
+<?php
+
+include "../Matrix.php";
+
+/**
+* Tiling of matrix X in [rowWise by colWise] dimension. Tiling
+* creates a larger matrix than the original data X. Example, if
+* X is to be tiled in a [3 x 4] manner, then:
+*
+* / \
+* | X X X X |
+* C = | X X X X |
+* | X X X X |
+* \ /
+*
+* @param X Matrix
+* @param rowWise int
+* @param colWise int
+* @return Matrix
+*/
+
+function tile(&$X, $rowWise, $colWise){
+
+ $xArray = $X->getArray();
+ print_r($xArray);
+
+ $countRow = 0;
+ $countColumn = 0;
+
+ $m = $X->getRowDimension();
+ $n = $X->getColumnDimension();
+
+ if( $rowWise<1 || $colWise<1 ){
+ die("tile : Array index is out-of-bound.");
+ }
+
+ $newRowDim = $m*$rowWise;
+ $newColDim = $n*$colWise;
+
+ $result = array();
+
+ for($i=0 ; $i<$newRowDim; ++$i) {
+
+ $holder = array();
+
+ for($j=0 ; $j<$newColDim ; ++$j) {
+
+ $holder[$j] = $xArray[$countRow][$countColumn++];
+
+ // reset the column-index to zero to avoid reference to out-of-bound index in xArray[][]
+
+ if($countColumn == $n) { $countColumn = 0; }
+
+ } // end for
+
+ ++$countRow;
+
+ // reset the row-index to zero to avoid reference to out-of-bound index in xArray[][]
+
+ if($countRow == $m) { $countRow = 0; }
+
+ $result[$i] = $holder;
+
+ } // end for
+
+ return new Matrix($result);
+
+}
+
+
+$X =array(1,2,3,4,5,6,7,8,9);
+$nRow = 3;
+$nCol = 3;
+$tiled_matrix = tile(new Matrix($X), $nRow, $nCol);
+echo "<pre>";
+print_r($tiled_matrix);
+echo "</pre>";
+?>