Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401] [Versions 401 and 402] [Versions 401 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          } elseif ($nY !== $nX) {
  61              //    Ensure both arrays of points are the same size
  62              trigger_error('Trend(): Number of elements in coordinate arrays do not match.', E_USER_ERROR);
  63          }
  64  
  65          $key = md5($trendType . $const . serialize($yValues) . serialize($xValues));
  66          //    Determine which Trend method has been requested
  67          switch ($trendType) {
  68              //    Instantiate and return the class for the requested Trend method
  69              case self::TREND_LINEAR:
  70              case self::TREND_LOGARITHMIC:
  71              case self::TREND_EXPONENTIAL:
  72              case self::TREND_POWER:
  73                  if (!isset(self::$trendCache[$key])) {
  74                      $className = '\PhpOffice\PhpSpreadsheet\Shared\Trend\\' . $trendType . 'BestFit';
  75                      // @phpstan-ignore-next-line
  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 = (int) substr($trendType, -1);
  87                      self::$trendCache[$key] = new PolynomialBestFit($order, $yValues, $xValues);
  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                  $bestFit = [];
  96                  $bestFitValue = [];
  97                  foreach (self::$trendTypes as $trendMethod) {
  98                      $className = '\PhpOffice\PhpSpreadsheet\Shared\Trend\\' . $trendType . 'BestFit';
  99                      $bestFit[$trendMethod] = new $className($yValues, $xValues, $const);
 100                      $bestFitValue[$trendMethod] = $bestFit[$trendMethod]->getGoodnessOfFit();
 101                  }
 102                  if ($trendType != self::TREND_BEST_FIT_NO_POLY) {
 103                      foreach (self::$trendTypePolynomialOrders as $trendMethod) {
 104                          $order = (int) substr($trendMethod, -1);
 105                          $bestFit[$trendMethod] = new PolynomialBestFit($order, $yValues, $xValues);
 106                          if ($bestFit[$trendMethod]->getError()) {
 107                              unset($bestFit[$trendMethod]);
 108                          } else {
 109                              $bestFitValue[$trendMethod] = $bestFit[$trendMethod]->getGoodnessOfFit();
 110                          }
 111                      }
 112                  }
 113                  //    Determine which of our Trend lines is the best fit, and then we return the instance of that Trend class
 114                  arsort($bestFitValue);
 115                  $bestFitType = key($bestFitValue);
 116  
 117                  return $bestFit[$bestFitType];
 118              default:
 119                  return false;
 120          }
 121      }
 122  }