Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 1
<?php
2
 
3
namespace PhpOffice\PhpSpreadsheet\Calculation\Engine;
4
 
5
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
6
 
7
class ArrayArgumentProcessor
8
{
9
    private static ArrayArgumentHelper $arrayArgumentHelper;
10
 
11
    public static function processArguments(
12
        ArrayArgumentHelper $arrayArgumentHelper,
13
        callable $method,
14
        mixed ...$arguments
15
    ): array {
16
        self::$arrayArgumentHelper = $arrayArgumentHelper;
17
 
18
        if (self::$arrayArgumentHelper->hasArrayArgument() === false) {
19
            return [$method(...$arguments)];
20
        }
21
 
22
        if (self::$arrayArgumentHelper->arrayArguments() === 1) {
23
            $nthArgument = self::$arrayArgumentHelper->getFirstArrayArgumentNumber();
24
 
25
            return self::evaluateNthArgumentAsArray($method, $nthArgument, ...$arguments);
26
        }
27
 
28
        $singleRowVectorIndex = self::$arrayArgumentHelper->getSingleRowVector();
29
        $singleColumnVectorIndex = self::$arrayArgumentHelper->getSingleColumnVector();
30
 
31
        if ($singleRowVectorIndex !== null && $singleColumnVectorIndex !== null) {
32
            // Basic logic for a single row vector and a single column vector
33
            return self::evaluateVectorPair($method, $singleRowVectorIndex, $singleColumnVectorIndex, ...$arguments);
34
        }
35
 
36
        $matrixPair = self::$arrayArgumentHelper->getMatrixPair();
37
        if ($matrixPair !== []) {
38
            if (
39
                (self::$arrayArgumentHelper->isVector($matrixPair[0]) === true
40
                    && self::$arrayArgumentHelper->isVector($matrixPair[1]) === false)
41
                || (self::$arrayArgumentHelper->isVector($matrixPair[0]) === false
42
                    && self::$arrayArgumentHelper->isVector($matrixPair[1]) === true)
43
            ) {
44
                // Logic for a matrix and a vector (row or column)
45
                return self::evaluateVectorMatrixPair($method, $matrixPair, ...$arguments);
46
            }
47
 
48
            // Logic for matrix/matrix, column vector/column vector or row vector/row vector
49
            return self::evaluateMatrixPair($method, $matrixPair, ...$arguments);
50
        }
51
 
52
        // Still need to work out the logic for more than two array arguments,
53
        // For the moment, we're throwing an Exception when we initialise the ArrayArgumentHelper
54
        return ['#VALUE!'];
55
    }
56
 
57
    private static function evaluateVectorMatrixPair(callable $method, array $matrixIndexes, mixed ...$arguments): array
58
    {
59
        $matrix2 = array_pop($matrixIndexes);
60
        /** @var array $matrixValues2 */
61
        $matrixValues2 = $arguments[$matrix2];
62
        $matrix1 = array_pop($matrixIndexes);
63
        /** @var array $matrixValues1 */
64
        $matrixValues1 = $arguments[$matrix1];
65
 
66
        $rows = min(array_map([self::$arrayArgumentHelper, 'rowCount'], [$matrix1, $matrix2]));
67
        $columns = min(array_map([self::$arrayArgumentHelper, 'columnCount'], [$matrix1, $matrix2]));
68
 
69
        if ($rows === 1) {
70
            $rows = max(array_map([self::$arrayArgumentHelper, 'rowCount'], [$matrix1, $matrix2]));
71
        }
72
        if ($columns === 1) {
73
            $columns = max(array_map([self::$arrayArgumentHelper, 'columnCount'], [$matrix1, $matrix2]));
74
        }
75
 
76
        $result = [];
77
        for ($rowIndex = 0; $rowIndex < $rows; ++$rowIndex) {
78
            for ($columnIndex = 0; $columnIndex < $columns; ++$columnIndex) {
79
                $rowIndex1 = self::$arrayArgumentHelper->isRowVector($matrix1) ? 0 : $rowIndex;
80
                $columnIndex1 = self::$arrayArgumentHelper->isColumnVector($matrix1) ? 0 : $columnIndex;
81
                $value1 = $matrixValues1[$rowIndex1][$columnIndex1];
82
                $rowIndex2 = self::$arrayArgumentHelper->isRowVector($matrix2) ? 0 : $rowIndex;
83
                $columnIndex2 = self::$arrayArgumentHelper->isColumnVector($matrix2) ? 0 : $columnIndex;
84
                $value2 = $matrixValues2[$rowIndex2][$columnIndex2];
85
                $arguments[$matrix1] = $value1;
86
                $arguments[$matrix2] = $value2;
87
 
88
                $result[$rowIndex][$columnIndex] = $method(...$arguments);
89
            }
90
        }
91
 
92
        return $result;
93
    }
94
 
95
    private static function evaluateMatrixPair(callable $method, array $matrixIndexes, mixed ...$arguments): array
96
    {
97
        $matrix2 = array_pop($matrixIndexes);
98
        /** @var array $matrixValues2 */
99
        $matrixValues2 = $arguments[$matrix2];
100
        $matrix1 = array_pop($matrixIndexes);
101
        /** @var array $matrixValues1 */
102
        $matrixValues1 = $arguments[$matrix1];
103
 
104
        $result = [];
105
        foreach ($matrixValues1 as $rowIndex => $row) {
106
            foreach ($row as $columnIndex => $value1) {
107
                if (isset($matrixValues2[$rowIndex][$columnIndex]) === false) {
108
                    continue;
109
                }
110
 
111
                $value2 = $matrixValues2[$rowIndex][$columnIndex];
112
                $arguments[$matrix1] = $value1;
113
                $arguments[$matrix2] = $value2;
114
 
115
                $result[$rowIndex][$columnIndex] = $method(...$arguments);
116
            }
117
        }
118
 
119
        return $result;
120
    }
121
 
122
    private static function evaluateVectorPair(callable $method, int $rowIndex, int $columnIndex, mixed ...$arguments): array
123
    {
124
        $rowVector = Functions::flattenArray($arguments[$rowIndex]);
125
        $columnVector = Functions::flattenArray($arguments[$columnIndex]);
126
 
127
        $result = [];
128
        foreach ($columnVector as $column) {
129
            $rowResults = [];
130
            foreach ($rowVector as $row) {
131
                $arguments[$rowIndex] = $row;
132
                $arguments[$columnIndex] = $column;
133
 
134
                $rowResults[] = $method(...$arguments);
135
            }
136
            $result[] = $rowResults;
137
        }
138
 
139
        return $result;
140
    }
141
 
142
    /**
143
     * Note, offset is from 1 (for the first argument) rather than from 0.
144
     */
145
    private static function evaluateNthArgumentAsArray(callable $method, int $nthArgument, mixed ...$arguments): array
146
    {
147
        $values = array_slice($arguments, $nthArgument - 1, 1);
148
        /** @var array $values */
149
        $values = array_pop($values);
150
 
151
        $result = [];
152
        foreach ($values as $value) {
153
            $arguments[$nthArgument - 1] = $value;
154
            $result[] = $method(...$arguments);
155
        }
156
 
157
        return $result;
158
    }
159
}