1<?php 2/** 3 * PHPExcel 4 * 5 * Copyright (c) 2006 - 2014 PHPExcel 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 * 21 * @category PHPExcel 22 * @package PHPExcel_Shared_Trend 23 * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel) 24 * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL 25 * @version ##VERSION##, ##DATE## 26 */ 27 28 29require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/trend/bestFitClass.php'; 30require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/JAMA/Matrix.php'; 31 32 33/** 34 * PHPExcel_Polynomial_Best_Fit 35 * 36 * @category PHPExcel 37 * @package PHPExcel_Shared_Trend 38 * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel) 39 */ 40class PHPExcel_Polynomial_Best_Fit extends PHPExcel_Best_Fit 41{ 42 /** 43 * Algorithm type to use for best-fit 44 * (Name of this trend class) 45 * 46 * @var string 47 **/ 48 protected $_bestFitType = 'polynomial'; 49 50 /** 51 * Polynomial order 52 * 53 * @protected 54 * @var int 55 **/ 56 protected $_order = 0; 57 58 59 /** 60 * Return the order of this polynomial 61 * 62 * @return int 63 **/ 64 public function getOrder() { 65 return $this->_order; 66 } // function getOrder() 67 68 69 /** 70 * Return the Y-Value for a specified value of X 71 * 72 * @param float $xValue X-Value 73 * @return float Y-Value 74 **/ 75 public function getValueOfYForX($xValue) { 76 $retVal = $this->getIntersect(); 77 $slope = $this->getSlope(); 78 foreach($slope as $key => $value) { 79 if ($value != 0.0) { 80 $retVal += $value * pow($xValue, $key + 1); 81 } 82 } 83 return $retVal; 84 } // function getValueOfYForX() 85 86 87 /** 88 * Return the X-Value for a specified value of Y 89 * 90 * @param float $yValue Y-Value 91 * @return float X-Value 92 **/ 93 public function getValueOfXForY($yValue) { 94 return ($yValue - $this->getIntersect()) / $this->getSlope(); 95 } // function getValueOfXForY() 96 97 98 /** 99 * Return the Equation of the best-fit line 100 * 101 * @param int $dp Number of places of decimal precision to display 102 * @return string 103 **/ 104 public function getEquation($dp=0) { 105 $slope = $this->getSlope($dp); 106 $intersect = $this->getIntersect($dp); 107 108 $equation = 'Y = '.$intersect; 109 foreach($slope as $key => $value) { 110 if ($value != 0.0) { 111 $equation .= ' + '.$value.' * X'; 112 if ($key > 0) { 113 $equation .= '^'.($key + 1); 114 } 115 } 116 } 117 return $equation; 118 } // function getEquation() 119 120 121 /** 122 * Return the Slope of the line 123 * 124 * @param int $dp Number of places of decimal precision to display 125 * @return string 126 **/ 127 public function getSlope($dp=0) { 128 if ($dp != 0) { 129 $coefficients = array(); 130 foreach($this->_slope as $coefficient) { 131 $coefficients[] = round($coefficient,$dp); 132 } 133 return $coefficients; 134 } 135 return $this->_slope; 136 } // function getSlope() 137 138 139 public function getCoefficients($dp=0) { 140 return array_merge(array($this->getIntersect($dp)),$this->getSlope($dp)); 141 } // function getCoefficients() 142 143 144 /** 145 * Execute the regression and calculate the goodness of fit for a set of X and Y data values 146 * 147 * @param int $order Order of Polynomial for this regression 148 * @param float[] $yValues The set of Y-values for this regression 149 * @param float[] $xValues The set of X-values for this regression 150 * @param boolean $const 151 */ 152 private function _polynomial_regression($order, $yValues, $xValues, $const) { 153 // calculate sums 154 $x_sum = array_sum($xValues); 155 $y_sum = array_sum($yValues); 156 $xx_sum = $xy_sum = 0; 157 for($i = 0; $i < $this->_valueCount; ++$i) { 158 $xy_sum += $xValues[$i] * $yValues[$i]; 159 $xx_sum += $xValues[$i] * $xValues[$i]; 160 $yy_sum += $yValues[$i] * $yValues[$i]; 161 } 162 /* 163 * This routine uses logic from the PHP port of polyfit version 0.1 164 * written by Michael Bommarito and Paul Meagher 165 * 166 * The function fits a polynomial function of order $order through 167 * a series of x-y data points using least squares. 168 * 169 */ 170 for ($i = 0; $i < $this->_valueCount; ++$i) { 171 for ($j = 0; $j <= $order; ++$j) { 172 $A[$i][$j] = pow($xValues[$i], $j); 173 } 174 } 175 for ($i=0; $i < $this->_valueCount; ++$i) { 176 $B[$i] = array($yValues[$i]); 177 } 178 $matrixA = new Matrix($A); 179 $matrixB = new Matrix($B); 180 $C = $matrixA->solve($matrixB); 181 182 $coefficients = array(); 183 for($i = 0; $i < $C->m; ++$i) { 184 $r = $C->get($i, 0); 185 if (abs($r) <= pow(10, -9)) { 186 $r = 0; 187 } 188 $coefficients[] = $r; 189 } 190 191 $this->_intersect = array_shift($coefficients); 192 $this->_slope = $coefficients; 193 194 $this->_calculateGoodnessOfFit($x_sum,$y_sum,$xx_sum,$yy_sum,$xy_sum); 195 foreach($this->_xValues as $xKey => $xValue) { 196 $this->_yBestFitValues[$xKey] = $this->getValueOfYForX($xValue); 197 } 198 } // function _polynomial_regression() 199 200 201 /** 202 * Define the regression and calculate the goodness of fit for a set of X and Y data values 203 * 204 * @param int $order Order of Polynomial for this regression 205 * @param float[] $yValues The set of Y-values for this regression 206 * @param float[] $xValues The set of X-values for this regression 207 * @param boolean $const 208 */ 209 function __construct($order, $yValues, $xValues=array(), $const=True) { 210 if (parent::__construct($yValues, $xValues) !== False) { 211 if ($order < $this->_valueCount) { 212 $this->_bestFitType .= '_'.$order; 213 $this->_order = $order; 214 $this->_polynomial_regression($order, $yValues, $xValues, $const); 215 if (($this->getGoodnessOfFit() < 0.0) || ($this->getGoodnessOfFit() > 1.0)) { 216 $this->_error = True; 217 } 218 } else { 219 $this->_error = True; 220 } 221 } 222 } // function __construct() 223 224} // class polynomialBestFit