Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
 
3
namespace Matrix;
4
 
5
class Functions
6
{
7
    /**
8
     * Validates an array of matrix, converting an array to a matrix if required.
9
     *
10
     * @param Matrix|array $matrix Matrix or an array to treat as a matrix.
11
     * @return Matrix The new matrix
12
     * @throws Exception If argument isn't a valid matrix or array.
13
     */
14
    private static function validateMatrix($matrix)
15
    {
16
        if (is_array($matrix)) {
17
            $matrix = new Matrix($matrix);
18
        }
19
        if (!$matrix instanceof Matrix) {
20
            throw new Exception('Must be Matrix or array');
21
        }
22
 
23
        return $matrix;
24
    }
25
 
26
    /**
27
     * Calculate the adjoint of the matrix
28
     *
29
     * @param Matrix $matrix The matrix whose adjoint we wish to calculate
30
     * @return Matrix
31
     *
32
     * @throws Exception
33
     */
34
    private static function getAdjoint(Matrix $matrix)
35
    {
36
        return self::transpose(
37
            self::getCofactors($matrix)
38
        );
39
    }
40
 
41
    /**
42
     * Return the adjoint of this matrix
43
     * The adjugate, classical adjoint, or adjunct of a square matrix is the transpose of its cofactor matrix.
44
     * The adjugate has sometimes been called the "adjoint", but today the "adjoint" of a matrix normally refers
45
     *     to its corresponding adjoint operator, which is its conjugate transpose.
46
     *
47
     * @param Matrix|array $matrix The matrix whose adjoint we wish to calculate
48
     * @return Matrix
49
     * @throws Exception
50
     **/
51
    public static function adjoint($matrix)
52
    {
53
        $matrix = self::validateMatrix($matrix);
54
 
55
        if (!$matrix->isSquare()) {
56
            throw new Exception('Adjoint can only be calculated for a square matrix');
57
        }
58
 
59
        return self::getAdjoint($matrix);
60
    }
61
 
62
    /**
63
     * Calculate the cofactors of the matrix
64
     *
65
     * @param Matrix $matrix The matrix whose cofactors we wish to calculate
66
     * @return Matrix
67
     *
68
     * @throws Exception
69
     */
70
    private static function getCofactors(Matrix $matrix)
71
    {
72
        $cofactors = self::getMinors($matrix);
73
        $dimensions = $matrix->rows;
74
 
75
        $cof = 1;
76
        for ($i = 0; $i < $dimensions; ++$i) {
77
            $cofs = $cof;
78
            for ($j = 0; $j < $dimensions; ++$j) {
79
                $cofactors[$i][$j] *= $cofs;
80
                $cofs = -$cofs;
81
            }
82
            $cof = -$cof;
83
        }
84
 
85
        return new Matrix($cofactors);
86
    }
87
 
88
    /**
89
     * Return the cofactors of this matrix
90
     *
91
     * @param Matrix|array $matrix The matrix whose cofactors we wish to calculate
92
     * @return Matrix
93
     *
94
     * @throws Exception
95
     */
96
    public static function cofactors($matrix)
97
    {
98
        $matrix = self::validateMatrix($matrix);
99
 
100
        if (!$matrix->isSquare()) {
101
            throw new Exception('Cofactors can only be calculated for a square matrix');
102
        }
103
 
104
        return self::getCofactors($matrix);
105
    }
106
 
107
    /**
108
     * @param Matrix $matrix
109
     * @param int $row
110
     * @param int $column
111
     * @return float
112
     * @throws Exception
113
     */
114
    private static function getDeterminantSegment(Matrix $matrix, $row, $column)
115
    {
116
        $tmpMatrix = $matrix->toArray();
117
        unset($tmpMatrix[$row]);
118
        array_walk(
119
            $tmpMatrix,
120
            function (&$row) use ($column) {
121
                unset($row[$column]);
122
            }
123
        );
124
 
125
        return self::getDeterminant(new Matrix($tmpMatrix));
126
    }
127
 
128
    /**
129
     * Calculate the determinant of the matrix
130
     *
131
     * @param Matrix $matrix The matrix whose determinant we wish to calculate
132
     * @return float
133
     *
134
     * @throws Exception
135
     */
136
    private static function getDeterminant(Matrix $matrix)
137
    {
138
        $dimensions = $matrix->rows;
139
        $determinant = 0;
140
 
141
        switch ($dimensions) {
142
            case 1:
143
                $determinant = $matrix->getValue(1, 1);
144
                break;
145
            case 2:
146
                $determinant = $matrix->getValue(1, 1) * $matrix->getValue(2, 2) -
147
                    $matrix->getValue(1, 2) * $matrix->getValue(2, 1);
148
                break;
149
            default:
150
                for ($i = 1; $i <= $dimensions; ++$i) {
151
                    $det = $matrix->getValue(1, $i) * self::getDeterminantSegment($matrix, 0, $i - 1);
152
                    if (($i % 2) == 0) {
153
                        $determinant -= $det;
154
                    } else {
155
                        $determinant += $det;
156
                    }
157
                }
158
                break;
159
        }
160
 
161
        return $determinant;
162
    }
163
 
164
    /**
165
     * Return the determinant of this matrix
166
     *
167
     * @param Matrix|array $matrix The matrix whose determinant we wish to calculate
168
     * @return float
169
     * @throws Exception
170
     **/
171
    public static function determinant($matrix)
172
    {
173
        $matrix = self::validateMatrix($matrix);
174
 
175
        if (!$matrix->isSquare()) {
176
            throw new Exception('Determinant can only be calculated for a square matrix');
177
        }
178
 
179
        return self::getDeterminant($matrix);
180
    }
181
 
182
    /**
183
     * Return the diagonal of this matrix
184
     *
185
     * @param Matrix|array $matrix The matrix whose diagonal we wish to calculate
186
     * @return Matrix
187
     * @throws Exception
188
     **/
189
    public static function diagonal($matrix)
190
    {
191
        $matrix = self::validateMatrix($matrix);
192
 
193
        if (!$matrix->isSquare()) {
194
            throw new Exception('Diagonal can only be extracted from a square matrix');
195
        }
196
 
197
        $dimensions = $matrix->rows;
198
        $grid = Builder::createFilledMatrix(0, $dimensions, $dimensions)
199
            ->toArray();
200
 
201
        for ($i = 0; $i < $dimensions; ++$i) {
202
            $grid[$i][$i] = $matrix->getValue($i + 1, $i + 1);
203
        }
204
 
205
        return new Matrix($grid);
206
    }
207
 
208
    /**
209
     * Return the antidiagonal of this matrix
210
     *
211
     * @param Matrix|array $matrix The matrix whose antidiagonal we wish to calculate
212
     * @return Matrix
213
     * @throws Exception
214
     **/
215
    public static function antidiagonal($matrix)
216
    {
217
        $matrix = self::validateMatrix($matrix);
218
 
219
        if (!$matrix->isSquare()) {
220
            throw new Exception('Anti-Diagonal can only be extracted from a square matrix');
221
        }
222
 
223
        $dimensions = $matrix->rows;
224
        $grid = Builder::createFilledMatrix(0, $dimensions, $dimensions)
225
            ->toArray();
226
 
227
        for ($i = 0; $i < $dimensions; ++$i) {
228
            $grid[$i][$dimensions - $i - 1] = $matrix->getValue($i + 1, $dimensions - $i);
229
        }
230
 
231
        return new Matrix($grid);
232
    }
233
 
234
    /**
235
     * Return the identity matrix
236
     * The identity matrix, or sometimes ambiguously called a unit matrix, of size n is the n × n square matrix
237
     *   with ones on the main diagonal and zeros elsewhere
238
     *
239
     * @param Matrix|array $matrix The matrix whose identity we wish to calculate
240
     * @return Matrix
241
     * @throws Exception
242
     **/
243
    public static function identity($matrix)
244
    {
245
        $matrix = self::validateMatrix($matrix);
246
 
247
        if (!$matrix->isSquare()) {
248
            throw new Exception('Identity can only be created for a square matrix');
249
        }
250
 
251
        $dimensions = $matrix->rows;
252
 
253
        return Builder::createIdentityMatrix($dimensions);
254
    }
255
 
256
    /**
257
     * Return the inverse of this matrix
258
     *
259
     * @param Matrix|array $matrix The matrix whose inverse we wish to calculate
260
     * @return Matrix
261
     * @throws Exception
262
     **/
263
    public static function inverse($matrix, string $type = 'inverse')
264
    {
265
        $matrix = self::validateMatrix($matrix);
266
 
267
        if (!$matrix->isSquare()) {
268
            throw new Exception(ucfirst($type) . ' can only be calculated for a square matrix');
269
        }
270
 
271
        $determinant = self::getDeterminant($matrix);
272
        if ($determinant == 0.0) {
273
            throw new Div0Exception(ucfirst($type) . ' can only be calculated for a matrix with a non-zero determinant');
274
        }
275
 
276
        if ($matrix->rows == 1) {
277
            return new Matrix([[1 / $matrix->getValue(1, 1)]]);
278
        }
279
 
280
        return self::getAdjoint($matrix)
281
            ->multiply(1 / $determinant);
282
    }
283
 
284
    /**
285
     * Calculate the minors of the matrix
286
     *
287
     * @param Matrix $matrix The matrix whose minors we wish to calculate
288
     * @return array[]
289
     *
290
     * @throws Exception
291
     */
292
    protected static function getMinors(Matrix $matrix)
293
    {
294
        $minors = $matrix->toArray();
295
        $dimensions = $matrix->rows;
296
        if ($dimensions == 1) {
297
            return $minors;
298
        }
299
 
300
        for ($i = 0; $i < $dimensions; ++$i) {
301
            for ($j = 0; $j < $dimensions; ++$j) {
302
                $minors[$i][$j] = self::getDeterminantSegment($matrix, $i, $j);
303
            }
304
        }
305
 
306
        return $minors;
307
    }
308
 
309
    /**
310
     * Return the minors of the matrix
311
     * The minor of a matrix A is the determinant of some smaller square matrix, cut down from A by removing one or
312
     *     more of its rows or columns.
313
     * Minors obtained by removing just one row and one column from square matrices (first minors) are required for
314
     *     calculating matrix cofactors, which in turn are useful for computing both the determinant and inverse of
315
     *     square matrices.
316
     *
317
     * @param Matrix|array $matrix The matrix whose minors we wish to calculate
318
     * @return Matrix
319
     * @throws Exception
320
     **/
321
    public static function minors($matrix)
322
    {
323
        $matrix = self::validateMatrix($matrix);
324
 
325
        if (!$matrix->isSquare()) {
326
            throw new Exception('Minors can only be calculated for a square matrix');
327
        }
328
 
329
        return new Matrix(self::getMinors($matrix));
330
    }
331
 
332
    /**
333
     * Return the trace of this matrix
334
     * The trace is defined as the sum of the elements on the main diagonal (the diagonal from the upper left to the lower right)
335
     *     of the matrix
336
     *
337
     * @param Matrix|array $matrix The matrix whose trace we wish to calculate
338
     * @return float
339
     * @throws Exception
340
     **/
341
    public static function trace($matrix)
342
    {
343
        $matrix = self::validateMatrix($matrix);
344
 
345
        if (!$matrix->isSquare()) {
346
            throw new Exception('Trace can only be extracted from a square matrix');
347
        }
348
 
349
        $dimensions = $matrix->rows;
350
        $result = 0;
351
        for ($i = 1; $i <= $dimensions; ++$i) {
352
            $result += $matrix->getValue($i, $i);
353
        }
354
 
355
        return $result;
356
    }
357
 
358
    /**
359
     * Return the transpose of this matrix
360
     *
361
     * @param Matrix|\a $matrix The matrix whose transpose we wish to calculate
362
     * @return Matrix
363
     **/
364
    public static function transpose($matrix)
365
    {
366
        $matrix = self::validateMatrix($matrix);
367
 
368
        $array = array_values(array_merge([null], $matrix->toArray()));
369
        $grid = call_user_func_array(
370
            'array_map',
371
            $array
372
        );
373
 
374
        return new Matrix($grid);
375
    }
376
}