ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
Matrix.php
Go to the documentation of this file.
1 <?php
2 
11 namespace Matrix;
12 
13 use Generator;
16 
42 class Matrix
43 {
44  protected $rows;
45  protected $columns;
46  protected $grid = [];
47 
48  /*
49  * Create a new Matrix object from an array of values
50  *
51  * @param array $grid
52  */
53  final public function __construct(array $grid)
54  {
55  $this->buildFromArray(array_values($grid));
56  }
57 
58  /*
59  * Create a new Matrix object from an array of values
60  *
61  * @param array $grid
62  */
63  protected function buildFromArray(array $grid): void
64  {
65  $this->rows = count($grid);
66  $columns = array_reduce(
67  $grid,
68  function ($carry, $value) {
69  return max($carry, is_array($value) ? count($value) : 1);
70  }
71  );
72  $this->columns = $columns;
73 
74  array_walk(
75  $grid,
76  function (&$value) use ($columns) {
77  if (!is_array($value)) {
78  $value = [$value];
79  }
80  $value = array_pad(array_values($value), $columns, null);
81  }
82  );
83 
84  $this->grid = $grid;
85  }
86 
94  public static function validateRow(int $row): int
95  {
96  if ((!is_numeric($row)) || (intval($row) < 1)) {
97  throw new Exception('Invalid Row');
98  }
99 
100  return (int)$row;
101  }
102 
110  public static function validateColumn(int $column): int
111  {
112  if ((!is_numeric($column)) || (intval($column) < 1)) {
113  throw new Exception('Invalid Column');
114  }
115 
116  return (int)$column;
117  }
118 
126  protected function validateRowInRange(int $row): int
127  {
128  $row = static::validateRow($row);
129  if ($row > $this->rows) {
130  throw new Exception('Requested Row exceeds matrix size');
131  }
132 
133  return $row;
134  }
135 
143  protected function validateColumnInRange(int $column): int
144  {
145  $column = static::validateColumn($column);
146  if ($column > $this->columns) {
147  throw new Exception('Requested Column exceeds matrix size');
148  }
149 
150  return $column;
151  }
152 
165  public function getRows(int $row, int $rowCount = 1): Matrix
166  {
167  $row = $this->validateRowInRange($row);
168  if ($rowCount === 0) {
169  $rowCount = $this->rows - $row + 1;
170  }
171 
172  return new static(array_slice($this->grid, $row - 1, (int)$rowCount));
173  }
174 
187  public function getColumns(int $column, int $columnCount = 1): Matrix
188  {
189  $column = $this->validateColumnInRange($column);
190  if ($columnCount < 1) {
191  $columnCount = $this->columns + $columnCount - $column + 1;
192  }
193 
194  $grid = [];
195  for ($i = $column - 1; $i < $column + $columnCount - 1; ++$i) {
196  $grid[] = array_column($this->grid, $i);
197  }
198 
199  return (new static($grid))->transpose();
200  }
201 
215  public function dropRows(int $row, int $rowCount = 1): Matrix
216  {
217  $this->validateRowInRange($row);
218  if ($rowCount === 0) {
219  $rowCount = $this->rows - $row + 1;
220  }
221 
222  $grid = $this->grid;
223  array_splice($grid, $row - 1, (int)$rowCount);
224 
225  return new static($grid);
226  }
227 
241  public function dropColumns(int $column, int $columnCount = 1): Matrix
242  {
243  $this->validateColumnInRange($column);
244  if ($columnCount < 1) {
245  $columnCount = $this->columns + $columnCount - $column + 1;
246  }
247 
248  $grid = $this->grid;
249  array_walk(
250  $grid,
251  function (&$row) use ($column, $columnCount) {
252  array_splice($row, $column - 1, (int)$columnCount);
253  }
254  );
255 
256  return new static($grid);
257  }
258 
268  public function getValue(int $row, int $column)
269  {
270  $row = $this->validateRowInRange($row);
271  $column = $this->validateColumnInRange($column);
272 
273  return $this->grid[$row - 1][$column - 1];
274  }
275 
282  public function rows(): Generator
283  {
284  foreach ($this->grid as $i => $row) {
285  yield $i + 1 => ($this->columns == 1)
286  ? $row[0]
287  : new static([$row]);
288  }
289  }
290 
297  public function columns(): Generator
298  {
299  for ($i = 0; $i < $this->columns; ++$i) {
300  yield $i + 1 => ($this->rows == 1)
301  ? $this->grid[0][$i]
302  : new static(array_column($this->grid, $i));
303  }
304  }
305 
312  public function isSquare(): bool
313  {
314  return $this->rows === $this->columns;
315  }
316 
323  public function isVector(): bool
324  {
325  return $this->rows === 1 || $this->columns === 1;
326  }
327 
333  public function toArray(): array
334  {
335  return $this->grid;
336  }
337 
347  public function solve(Matrix $B): Matrix
348  {
349  if ($this->columns === $this->rows) {
350  return (new LU($this))->solve($B);
351  }
352 
353  return (new QR($this))->solve($B);
354  }
355 
356  protected static $getters = [
357  'rows',
358  'columns',
359  ];
360 
368  public function __get(string $propertyName)
369  {
370  $propertyName = strtolower($propertyName);
371 
372  // Test for function calls
373  if (in_array($propertyName, self::$getters)) {
374  return $this->$propertyName;
375  }
376 
377  throw new Exception('Property does not exist');
378  }
379 
380  protected static $functions = [
381  'adjoint',
382  'antidiagonal',
383  'cofactors',
384  'determinant',
385  'diagonal',
386  'identity',
387  'inverse',
388  'minors',
389  'trace',
390  'transpose',
391  ];
392 
393  protected static $operations = [
394  'add',
395  'subtract',
396  'multiply',
397  'divideby',
398  'divideinto',
399  'directsum',
400  ];
401 
410  public function __call(string $functionName, $arguments)
411  {
412  $functionName = strtolower(str_replace('_', '', $functionName));
413 
414  if (in_array($functionName, self::$functions, true) || in_array($functionName, self::$operations, true)) {
415  $functionName = "\\" . __NAMESPACE__ . "\\{$functionName}";
416  if (is_callable($functionName)) {
417  $arguments = array_values(array_merge([$this], $arguments));
418  return call_user_func_array($functionName, $arguments);
419  }
420  }
421  throw new Exception('Function or Operation does not exist');
422  }
423 }
$grid
Definition: test.php:8
if(! $row) $columnCount
isVector()
Identify if this matrix is a vector i.e.
Definition: Matrix.php:323
rows()
Returns a Generator that will yield each row of the matrix in turn as a vector matrix or the value of...
Definition: Matrix.php:282
getValue(int $row, int $column)
Return a value from this matrix, from the "cell" identified by the row and column numbers Note that r...
Definition: Matrix.php:268
__get(string $propertyName)
Access specific properties as read-only (no setters)
Definition: Matrix.php:368
static validateRow(int $row)
Validate that a row number is a positive integer.
Definition: Matrix.php:94
buildFromArray(array $grid)
Definition: Matrix.php:63
dropRows(int $row, int $rowCount=1)
Return a new matrix as a subset of rows from this matrix, dropping rows starting at row number $row...
Definition: Matrix.php:215
columns()
Returns a Generator that will yield each column of the matrix in turn as a vector matrix or the value...
Definition: Matrix.php:297
toArray()
Return the matrix as a 2-dimensional array.
Definition: Matrix.php:333
__call(string $functionName, $arguments)
Returns the result of the function call or operation.
Definition: Matrix.php:410
solve(Matrix $B)
Solve A*X = B.
Definition: Matrix.php:347
dropColumns(int $column, int $columnCount=1)
Return a new matrix as a subset of columns from this matrix, dropping columns starting at column numb...
Definition: Matrix.php:241
$row
validateColumnInRange(int $column)
Validate that a column number falls within the set of columns for this matrix.
Definition: Matrix.php:143
$i
Definition: disco.tpl.php:19
validateRowInRange(int $row)
Validate that a row number falls within the set of rows for this matrix.
Definition: Matrix.php:126
Class for the creating "special" Matrices.
Definition: Builder.php:11
static validateColumn(int $column)
Validate that a column number is a positive integer.
Definition: Matrix.php:110
if(! $in) $columns
Definition: Utf8Test.php:45
getColumns(int $column, int $columnCount=1)
Return a new matrix as a subset of columns from this matrix, starting at column number $column...
Definition: Matrix.php:187
isSquare()
Identify if the row and column dimensions of this matrix are equal, i.e.
Definition: Matrix.php:312
getRows(int $row, int $rowCount=1)
Return a new matrix as a subset of rows from this matrix, starting at row number $row, and $rowCount rows A $rowCount value of 0 will return all rows of the matrix from $row A negative $rowCount value will return rows until that many rows from the end of the matrix.
Definition: Matrix.php:165
__construct(array $grid)
Definition: Matrix.php:53