Add test, Disable TREND_BEST_FIT, POLYNOMIAL_BEST_FIT

This commit is contained in:
oleibman
2025-03-09 20:21:16 -07:00
parent e496d856c0
commit 263a397b84
3 changed files with 84 additions and 6 deletions
@@ -3,11 +3,14 @@
namespace PhpOffice\PhpSpreadsheet\Shared\Trend;
use Matrix\Matrix;
use PhpOffice\PhpSpreadsheet\Exception as SpreadsheetException;
// Phpstan and Scrutinizer seem to have legitimate complaints.
// $this->slope is specified where an array is expected in several places.
// But it seems that it should always be float.
// This code is probably not exercised at all in unit tests.
// Private bool property $implemented is set to indicate
// whether this implementation is correct.
class PolynomialBestFit extends BestFit
{
/**
@@ -21,6 +24,8 @@ class PolynomialBestFit extends BestFit
*/
protected int $order = 0;
private bool $implemented = false;
/**
* Return the order of this polynomial.
*/
@@ -187,6 +192,10 @@ class PolynomialBestFit extends BestFit
*/
public function __construct(int $order, array $yValues, array $xValues = [])
{
if (!$this->implemented) {
throw new SpreadsheetException('Polynomial Best Fit not yet implemented');
}
parent::__construct($yValues, $xValues);
if (!$this->error) {
+3 -6
View File
@@ -18,10 +18,8 @@ class Trend
/**
* Names of the best-fit Trend analysis methods.
*
* @var string[]
*/
private static array $trendTypes = [
private const TREND_TYPES = [
self::TREND_LINEAR,
self::TREND_LOGARITHMIC,
self::TREND_EXPONENTIAL,
@@ -93,13 +91,12 @@ class Trend
// Start by generating an instance of each available Trend method
$bestFit = [];
$bestFitValue = [];
foreach (self::$trendTypes as $trendMethod) {
foreach (self::TREND_TYPES as $trendMethod) {
$className = '\PhpOffice\PhpSpreadsheet\Shared\Trend\\' . $trendMethod . 'BestFit';
//* @phpstan-ignore-next-line
$bestFit[$trendMethod] = new $className($yValues, $xValues, $const);
$bestFitValue[$trendMethod] = $bestFit[$trendMethod]->getGoodnessOfFit();
}
if ($trendType != self::TREND_BEST_FIT_NO_POLY) {
if ($trendType !== self::TREND_BEST_FIT_NO_POLY) {
foreach (self::$trendTypePolynomialOrders as $trendMethod) {
$order = (int) substr($trendMethod, -1);
$bestFit[$trendMethod] = new PolynomialBestFit($order, $yValues, $xValues);
@@ -0,0 +1,72 @@
<?php
declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Shared\Trend;
use PhpOffice\PhpSpreadsheet\Exception as SpreadsheetException;
use PhpOffice\PhpSpreadsheet\Shared\Trend\Trend;
use PHPUnit\Framework\TestCase;
class BestFitTest extends TestCase
{
private const LBF_PRECISION = 1.0E-4;
public function testBestFit(): void
{
$xValues = [45, 55, 47, 75, 90, 100, 100, 95, 88, 50, 45, 58];
$yValues = [15, 25, 17, 30, 41, 47, 50, 46, 37, 22, 20, 26];
$maxGoodness = -1000.0;
$maxType = '';
$type = Trend::TREND_LINEAR;
$result = Trend::calculate($type, $yValues, $xValues);
$goodness = $result->getGoodnessOfFit();
if ($maxGoodness < $goodness) {
$maxGoodness = $goodness;
$maxType = $type;
}
self::assertEqualsWithDelta(0.9628, $goodness, self::LBF_PRECISION);
$type = Trend::TREND_EXPONENTIAL;
$result = Trend::calculate($type, $yValues, $xValues);
$goodness = $result->getGoodnessOfFit();
if ($maxGoodness < $goodness) {
$maxGoodness = $goodness;
$maxType = $type;
}
self::assertEqualsWithDelta(0.9952, $goodness, self::LBF_PRECISION);
$type = Trend::TREND_LOGARITHMIC;
$result = Trend::calculate($type, $yValues, $xValues);
$goodness = $result->getGoodnessOfFit();
if ($maxGoodness < $goodness) {
$maxGoodness = $goodness;
$maxType = $type;
}
self::assertEqualsWithDelta(-0.0724, $goodness, self::LBF_PRECISION);
$type = Trend::TREND_POWER;
$result = Trend::calculate($type, $yValues, $xValues);
$goodness = $result->getGoodnessOfFit();
if ($maxGoodness < $goodness) {
$maxGoodness = $goodness;
$maxType = $type;
}
self::assertEqualsWithDelta(0.9946, $goodness, self::LBF_PRECISION);
$type = Trend::TREND_BEST_FIT_NO_POLY;
$result = Trend::calculate($type, $yValues, $xValues);
$goodness = $result->getGoodnessOfFit();
self::assertSame($maxGoodness, $goodness);
self::assertSame(lcfirst($maxType), $result->getBestFitType());
try {
$type = Trend::TREND_BEST_FIT;
$result = Trend::calculate($type, $yValues, $xValues);
self::fail('should have failed - TREND_BEST_FIT includes polynomials which are not implemented yet');
} catch (SpreadsheetException $e) {
self::assertStringContainsString('not yet implemented', $e->getMessage());
}
}
}