PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.4.8
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.4.8
4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 3.10.4 All 148 releases
visualizer / vendor / markbaker / matrix / classes / src / Matrix.php

Matrix.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 3.4.8, at vendor/markbaker/matrix/classes/src/Matrix.php

401 lines 10.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 *
5 * Class for the management of Matrices
6 *
7 * @copyright Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
8 * @license https://opensource.org/licenses/MIT MIT
9 */
10
11 namespace Matrix;
12
13 /**
14 * Matrix object.
15 *
16 * @package Matrix
17 *
18 * @property-read int $rows The number of rows in the matrix
19 * @property-read int $columns The number of columns in the matrix
20 * @method Matrix antidiagonal()
21 * @method Matrix adjoint()
22 * @method Matrix cofactors()
23 * @method float determinant()
24 * @method Matrix diagonal()
25 * @method Matrix identity()
26 * @method Matrix inverse()
27 * @method Matrix pseudoInverse()
28 * @method Matrix minors()
29 * @method float trace()
30 * @method Matrix transpose()
31 * @method Matrix add(...$matrices)
32 * @method Matrix subtract(...$matrices)
33 * @method Matrix multiply(...$matrices)
34 * @method Matrix divideby(...$matrices)
35 * @method Matrix divideinto(...$matrices)
36 */
37 class Matrix
38 {
39 protected $rows;
40 protected $columns;
41 protected $grid = [];
42
43 /*
44 * Create a new Matrix object from an array of values
45 *
46 * @param array $grid
47 */
48 final public function __construct(array $grid)
49 {
50 $this->buildFromArray(array_values($grid));
51 }
52
53 /*
54 * Create a new Matrix object from an array of values
55 *
56 * @param array $grid
57 */
58 protected function buildFromArray(array $grid)
59 {
60 $this->rows = count($grid);
61 $columns = array_reduce(
62 $grid,
63 function ($carry, $value) {
64 return max($carry, is_array($value) ? count($value) : 1);
65 }
66 );
67 $this->columns = $columns;
68
69 array_walk(
70 $grid,
71 function (&$value) use ($columns) {
72 if (!is_array($value)) {
73 $value = [$value];
74 }
75 $value = array_pad(array_values($value), $columns, null);
76 }
77 );
78
79 $this->grid = $grid;
80 }
81
82 /**
83 * Validate that a row number is a positive integer
84 *
85 * @param int $row
86 * @return int
87 * @throws Exception
88 */
89 public static function validateRow($row)
90 {
91 if ((!is_numeric($row)) || (intval($row) < 1)) {
92 throw new Exception('Invalid Row');
93 }
94
95 return (int)$row;
96 }
97
98 /**
99 * Validate that a column number is a positive integer
100 *
101 * @param int $column
102 * @return int
103 * @throws Exception
104 */
105 public static function validateColumn($column)
106 {
107 if ((!is_numeric($column)) || (intval($column) < 1)) {
108 throw new Exception('Invalid Column');
109 }
110
111 return (int)$column;
112 }
113
114 /**
115 * Validate that a row number falls within the set of rows for this matrix
116 *
117 * @param int $row
118 * @return int
119 * @throws Exception
120 */
121 protected function validateRowInRange($row)
122 {
123 $row = static::validateRow($row);
124 if ($row > $this->rows) {
125 throw new Exception('Requested Row exceeds matrix size');
126 }
127
128 return $row;
129 }
130
131 /**
132 * Validate that a column number falls within the set of columns for this matrix
133 *
134 * @param int $column
135 * @return int
136 * @throws Exception
137 */
138 protected function validateColumnInRange($column)
139 {
140 $column = static::validateColumn($column);
141 if ($column > $this->columns) {
142 throw new Exception('Requested Column exceeds matrix size');
143 }
144
145 return $column;
146 }
147
148 /**
149 * Return a new matrix as a subset of rows from this matrix, starting at row number $row, and $rowCount rows
150 * A $rowCount value of 0 will return all rows of the matrix from $row
151 * A negative $rowCount value will return rows until that many rows from the end of the matrix
152 *
153 * Note that row numbers start from 1, not from 0
154 *
155 * @param int $row
156 * @param int $rowCount
157 * @return static
158 * @throws Exception
159 */
160 public function getRows($row, $rowCount = 1)
161 {
162 $row = $this->validateRowInRange($row);
163 if ($rowCount === 0) {
164 $rowCount = $this->rows - $row + 1;
165 }
166
167 return new static(array_slice($this->grid, $row - 1, (int)$rowCount));
168 }
169
170 /**
171 * Return a new matrix as a subset of columns from this matrix, starting at column number $column, and $columnCount columns
172 * A $columnCount value of 0 will return all columns of the matrix from $column
173 * A negative $columnCount value will return columns until that many columns from the end of the matrix
174 *
175 * Note that column numbers start from 1, not from 0
176 *
177 * @param int $column
178 * @param int $columnCount
179 * @return Matrix
180 * @throws Exception
181 */
182 public function getColumns($column, $columnCount = 1)
183 {
184 $column = $this->validateColumnInRange($column);
185 if ($columnCount < 1) {
186 $columnCount = $this->columns + $columnCount - $column + 1;
187 }
188
189 $grid = [];
190 for ($i = $column - 1; $i < $column + $columnCount - 1; ++$i) {
191 $grid[] = array_column($this->grid, $i);
192 }
193
194 return (new static($grid))->transpose();
195 }
196
197 /**
198 * Return a new matrix as a subset of rows from this matrix, dropping rows starting at row number $row,
199 * and $rowCount rows
200 * A negative $rowCount value will drop rows until that many rows from the end of the matrix
201 * A $rowCount value of 0 will remove all rows of the matrix from $row
202 *
203 * Note that row numbers start from 1, not from 0
204 *
205 * @param int $row
206 * @param int $rowCount
207 * @return static
208 * @throws Exception
209 */
210 public function dropRows($row, $rowCount = 1)
211 {
212 $this->validateRowInRange($row);
213 if ($rowCount === 0) {
214 $rowCount = $this->rows - $row + 1;
215 }
216
217 $grid = $this->grid;
218 array_splice($grid, $row - 1, (int)$rowCount);
219
220 return new static($grid);
221 }
222
223 /**
224 * Return a new matrix as a subset of columns from this matrix, dropping columns starting at column number $column,
225 * and $columnCount columns
226 * A negative $columnCount value will drop columns until that many columns from the end of the matrix
227 * A $columnCount value of 0 will remove all columns of the matrix from $column
228 *
229 * Note that column numbers start from 1, not from 0
230 *
231 * @param int $column
232 * @param int $columnCount
233 * @return static
234 * @throws Exception
235 */
236 public function dropColumns($column, $columnCount = 1)
237 {
238 $this->validateColumnInRange($column);
239 if ($columnCount < 1) {
240 $columnCount = $this->columns + $columnCount - $column + 1;
241 }
242
243 $grid = $this->grid;
244 array_walk(
245 $grid,
246 function (&$row) use ($column, $columnCount) {
247 array_splice($row, $column - 1, (int)$columnCount);
248 }
249 );
250
251 return new static($grid);
252 }
253
254 /**
255 * Return a value from this matrix, from the "cell" identified by the row and column numbers
256 * Note that row and column numbers start from 1, not from 0
257 *
258 * @param int $row
259 * @param int $column
260 * @return mixed
261 * @throws Exception
262 */
263 public function getValue($row, $column)
264 {
265 $row = $this->validateRowInRange($row);
266 $column = $this->validateColumnInRange($column);
267
268 return $this->grid[$row - 1][$column - 1];
269 }
270
271 /**
272 * Returns a Generator that will yield each row of the matrix in turn as a vector matrix
273 * or the value of each cell if the matrix is a vector
274 *
275 * @return \Generator|Matrix[]|mixed[]
276 */
277 public function rows()
278 {
279 foreach ($this->grid as $i => $row) {
280 yield $i + 1 => ($this->columns == 1)
281 ? $row[0]
282 : new static([$row]);
283 }
284 }
285
286 /**
287 * Returns a Generator that will yield each column of the matrix in turn as a vector matrix
288 * or the value of each cell if the matrix is a vector
289 *
290 * @return \Generator|Matrix[]|mixed[]
291 */
292 public function columns()
293 {
294 for ($i = 0; $i < $this->columns; ++$i) {
295 yield $i + 1 => ($this->rows == 1)
296 ? $this->grid[0][$i]
297 : new static(array_column($this->grid, $i));
298 }
299 }
300
301 /**
302 * Identify if the row and column dimensions of this matrix are equal,
303 * i.e. if it is a "square" matrix
304 *
305 * @return bool
306 */
307 public function isSquare()
308 {
309 return $this->rows == $this->columns;
310 }
311
312 /**
313 * Identify if this matrix is a vector
314 * i.e. if it comprises only a single row or a single column
315 *
316 * @return bool
317 */
318 public function isVector()
319 {
320 return $this->rows == 1 || $this->columns == 1;
321 }
322
323 /**
324 * Return the matrix as a 2-dimensional array
325 *
326 * @return array
327 */
328 public function toArray()
329 {
330 return $this->grid;
331 }
332
333 protected static $getters = [
334 'rows',
335 'columns',
336 ];
337
338 /**
339 * Access specific properties as read-only (no setters)
340 *
341 * @param string $propertyName
342 * @return mixed
343 * @throws Exception
344 */
345 public function __get($propertyName)
346 {
347 $propertyName = strtolower($propertyName);
348
349 // Test for function calls
350 if (in_array($propertyName, self::$getters)) {
351 return $this->$propertyName;
352 }
353
354 throw new Exception('Property does not exist');
355 }
356
357 protected static $functions = [
358 'antidiagonal',
359 'adjoint',
360 'cofactors',
361 'determinant',
362 'diagonal',
363 'identity',
364 'inverse',
365 'minors',
366 'trace',
367 'transpose',
368 ];
369
370 protected static $operations = [
371 'add',
372 'subtract',
373 'multiply',
374 'divideby',
375 'divideinto',
376 'directsum',
377 ];
378
379 /**
380 * Returns the result of the function call or operation
381 *
382 * @param string $functionName
383 * @param mixed[] $arguments
384 * @return Matrix|float
385 * @throws Exception
386 */
387 public function __call($functionName, $arguments)
388 {
389 $functionName = strtolower(str_replace('_', '', $functionName));
390
391 if (in_array($functionName, self::$functions, true) || in_array($functionName, self::$operations, true)) {
392 $functionName = "\\" . __NAMESPACE__ . "\\{$functionName}";
393 if (is_callable($functionName)) {
394 $arguments = array_values(array_merge([$this], $arguments));
395 return call_user_func_array($functionName, $arguments);
396 }
397 }
398 throw new Exception('Function or Operation does not exist');
399 }
400 }
401