Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403]

   1  <?php
   2  
   3  namespace PhpOffice\PhpSpreadsheet\Shared\Trend;
   4  
   5  class Trend
   6  {
   7      const TREND_LINEAR = 'Linear';
   8      const TREND_LOGARITHMIC = 'Logarithmic';
   9      const TREND_EXPONENTIAL = 'Exponential';
  10      const TREND_POWER = 'Power';
  11      const TREND_POLYNOMIAL_2 = 'Polynomial_2';
  12      const TREND_POLYNOMIAL_3 = 'Polynomial_3';
  13      const TREND_POLYNOMIAL_4 = 'Polynomial_4';
  14      const TREND_POLYNOMIAL_5 = 'Polynomial_5';
  15      const TREND_POLYNOMIAL_6 = 'Polynomial_6';
  16      const TREND_BEST_FIT = 'Bestfit';
  17      const TREND_BEST_FIT_NO_POLY = 'Bestfit_no_Polynomials';
  18  
  19      /**
  20       * Names of the best-fit Trend analysis methods.
  21       *
  22       * @var string[]
  23       */
  24      private static $trendTypes = [
  25          self::TREND_LINEAR,
  26          self::TREND_LOGARITHMIC,
  27          self::TREND_EXPONENTIAL,
  28          self::TREND_POWER,
  29      ];
  30  
  31      /**
  32       * Names of the best-fit Trend polynomial orders.
  33       *
  34       * @var string[]
  35       */
  36      private static $trendTypePolynomialOrders = [
  37          self::TREND_POLYNOMIAL_2,
  38          self::TREND_POLYNOMIAL_3,
  39          self::TREND_POLYNOMIAL_4,
  40          self::TREND_POLYNOMIAL_5,
  41          self::TREND_POLYNOMIAL_6,
  42      ];
  43  
  44      /**
  45       * Cached results for each method when trying to identify which provides the best fit.
  46       *
  47       * @var bestFit[]
  48       */
  49      private static $trendCache = [];
  50  
  51      public static function calculate($trendType = self::TREND_BEST_FIT, $yValues = [], $xValues = [], $const = true)
  52      {
  53          //    Calculate number of points in each dataset
  54          $nY = count($yValues);
  55          $nX = count($xValues);
  56  
  57          //    Define X Values if necessary
  58          if ($nX == 0) {
  59              $xValues = range(1, $nY);
  60              $nX = $nY;
  61          } elseif ($nY != $nX) {
  62              //    Ensure both arrays of points are the same size
  63              trigger_error('Trend(): Number of elements in coordinate arrays do not match.', E_USER_ERROR);
  64          }
  65  
  66          $key = md5($trendType . $const . serialize($yValues) . serialize($xValues));
  67          //    Determine which Trend method has been requested
  68          switch ($trendType) {
  69              //    Instantiate and return the class for the requested Trend method
  70              case self::TREND_LINEAR:
  71              case self::TREND_LOGARITHMIC:
  72              case self::TREND_EXPONENTIAL:
  73              case self::TREND_POWER:
  74                  if (!isset(self::$trendCache[$key])) {
  75                      $className = '\PhpOffice\PhpSpreadsheet\Shared\Trend\\' . $trendType . 'BestFit';
  76                      self::$trendCache[$key] = new $className($yValues, $xValues, $const);
  77                  }
  78  
  79                  return self::$trendCache[$key];
  80              case self::TREND_POLYNOMIAL_2:
  81              case self::TREND_POLYNOMIAL_3:
  82              case self::TREND_POLYNOMIAL_4:
  83              case self::TREND_POLYNOMIAL_5:
  84              case self::TREND_POLYNOMIAL_6:
  85                  if (!isset(self::$trendCache[$key])) {
  86                      $order = substr($trendType, -1);
  87                      self::$trendCache[$key] = new PolynomialBestFit($order, $yValues, $xValues, $const);
  88                  }
  89  
  90                  return self::$trendCache[$key];
  91              case self::TREND_BEST_FIT:
  92              case self::TREND_BEST_FIT_NO_POLY:
  93                  //    If the request is to determine the best fit regression, then we test each Trend line in turn
  94                  //    Start by generating an instance of each available Trend method
  95                  foreach (self::$trendTypes as $trendMethod) {
  96                      $className = '\PhpOffice\PhpSpreadsheet\Shared\Trend\\' . $trendType . 'BestFit';
  97                      $bestFit[$trendMethod] = new $className($yValues, $xValues, $const);
  98                      $bestFitValue[$trendMethod] = $bestFit[$trendMethod]->getGoodnessOfFit();
  99                  }
 100                  if ($trendType != self::TREND_BEST_FIT_NO_POLY) {
 101                      foreach (self::$trendTypePolynomialOrders as $trendMethod) {
 102                          $order = substr($trendMethod, -1);
 103                          $bestFit[$trendMethod] = new PolynomialBestFit($order, $yValues, $xValues, $const);
 104                          if ($bestFit[$trendMethod]->getError()) {
 105                              unset($bestFit[$trendMethod]);
 106                          } else {
 107                              $bestFitValue[$trendMethod] = $bestFit[$trendMethod]->getGoodnessOfFit();
 108                          }
 109                      }
 110                  }
 111                  //    Determine which of our Trend lines is the best fit, and then we return the instance of that Trend class
 112                  arsort($bestFitValue);
 113                  $bestFitType = key($bestFitValue);
 114  
 115                  return $bestFit[$bestFitType];
 116              default:
 117                  return false;
 118          }
 119      }
 120  }