Passed
Push — develop ( aa265d...8b49d6 )
by Alec
14:04
created

MeasurementsResults::createResult()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 1
eloc 12
nc 1
nop 2
dl 0
loc 15
ccs 0
cts 10
cp 0
crap 2
rs 9.8666
c 3
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace AlecRabbit\Tools;
4
5
use MathPHP\Exception\BadDataException;
6
use MathPHP\Exception\OutOfBoundsException;
7
use MathPHP\Statistics\Average;
8
use MathPHP\Statistics\RandomVariable;
9
10
class MeasurementsResults
11
{
12
    protected const REJECTION_THRESHOLD = 100;
13
14
    /**
15
     * @param array $measurements
16
     * @param BenchmarkResult|null $previous
17
     * @return BenchmarkResult
18
     * @throws BadDataException
19
     * @throws OutOfBoundsException
20
     */
21
    public static function createResult(array $measurements, ?BenchmarkResult $previous = null): BenchmarkResult
22
    {
23
        $measurements = self::convertDataType($measurements);
24
        $numberOfRejections = self::refine($measurements, $previous);
25
        $numberOfMeasurements = count($measurements);
26
        $mean = Average::mean($measurements);
27
        $standardErrorOfTheMean = RandomVariable::standardErrorOfTheMean($measurements);
28
        $tValue = TDistribution::tValue($numberOfMeasurements);
29
30
        return
31
            new BenchmarkResult(
32
                $mean,
33
                $standardErrorOfTheMean * $tValue,
34
                $numberOfMeasurements,
35
                $numberOfRejections
36
            );
37
    }
38
39
    protected static function convertDataType(array $measurements): array
40
    {
41
        if ($measurements[0] instanceof BenchmarkResult) {
42
            $m = [];
43
            /** @var BenchmarkResult $r */
44
            foreach ($measurements as $r) {
45
                $m[] = $r->getMean();
46
            }
47
            $measurements = $m;
48
        }
49
        return $measurements;
50
    }
51
52
    protected static function refine(array &$measurements, ?BenchmarkResult $previous = null): int
53
    {
54
        self::removeMax($measurements);
55
        $rejections = 0;
56
        if ($previous instanceof BenchmarkResult) {
57
            $meanThreshold = $previous->getMean() * self::rejectionCoefficient();
58
        } else {
59
            $meanThreshold = Average::mean($measurements) * self::rejectionCoefficient();
60
        }
61
62
        foreach ($measurements as $key => $value) {
63
            if ($value > $meanThreshold) {
64
                unset($measurements[$key]);
65
                $rejections++;
66
            }
67
        }
68
        return $rejections;
69
    }
70
71
    protected static function removeMax(array &$measurements): void
72
    {
73
        $max = max($measurements);
74
        unset($measurements[array_search($max, $measurements, true)]);
75
    }
76
77
    /**
78
     * @return float|int
79
     */
80
    protected static function rejectionCoefficient()
81
    {
82
        return 1 + self::REJECTION_THRESHOLD / 100;
83
    }
84
}
85