PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.5.0
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.5.0
4.0.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 All 149 releases
visualizer / vendor / markbaker / matrix / classes / src / Decomposition / LU.php

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

261 lines 6.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Matrix\Decomposition;
4
5 use Matrix\Exception;
6 use Matrix\Matrix;
7
8 class LU
9 {
10 private $luMatrix;
11 private $rows;
12 private $columns;
13
14 private $pivot = [];
15
16 public function __construct(Matrix $matrix)
17 {
18 $this->luMatrix = $matrix->toArray();
19 $this->rows = $matrix->rows;
20 $this->columns = $matrix->columns;
21
22 $this->buildPivot();
23 }
24
25 /**
26 * Get lower triangular factor.
27 *
28 * @return Matrix Lower triangular factor
29 */
30 public function getL()
31 {
32 $lower = [];
33
34 $columns = min($this->rows, $this->columns);
35 for ($row = 0; $row < $this->rows; ++$row) {
36 for ($column = 0; $column < $columns; ++$column) {
37 if ($row > $column) {
38 $lower[$row][$column] = $this->luMatrix[$row][$column];
39 } elseif ($row === $column) {
40 $lower[$row][$column] = 1.0;
41 } else {
42 $lower[$row][$column] = 0.0;
43 }
44 }
45 }
46
47 return new Matrix($lower);
48 }
49
50 /**
51 * Get upper triangular factor.
52 *
53 * @return Matrix Upper triangular factor
54 */
55 public function getU()
56 {
57 $upper = [];
58
59 $rows = min($this->rows, $this->columns);
60 for ($row = 0; $row < $rows; ++$row) {
61 for ($column = 0; $column < $this->columns; ++$column) {
62 if ($row <= $column) {
63 $upper[$row][$column] = $this->luMatrix[$row][$column];
64 } else {
65 $upper[$row][$column] = 0.0;
66 }
67 }
68 }
69
70 return new Matrix($upper);
71 }
72
73 /**
74 * Return pivot permutation vector.
75 *
76 * @return Matrix Pivot matrix
77 */
78 public function getP()
79 {
80 $pMatrix = [];
81
82 $pivots = $this->pivot;
83 $pivotCount = count($pivots);
84 foreach ($pivots as $row => $pivot) {
85 $pMatrix[$row] = array_fill(0, $pivotCount, 0);
86 $pMatrix[$row][$pivot] = 1;
87 }
88
89 return new Matrix($pMatrix);
90 }
91
92 /**
93 * Return pivot permutation vector.
94 *
95 * @return array Pivot vector
96 */
97 public function getPivot()
98 {
99 return $this->pivot;
100 }
101
102 /**
103 * Is the matrix nonsingular?
104 *
105 * @return bool true if U, and hence A, is nonsingular
106 */
107 public function isNonsingular()
108 {
109 for ($diagonal = 0; $diagonal < $this->columns; ++$diagonal) {
110 if ($this->luMatrix[$diagonal][$diagonal] === 0.0) {
111 return false;
112 }
113 }
114
115 return true;
116 }
117
118 private function buildPivot()
119 {
120 for ($row = 0; $row < $this->rows; ++$row) {
121 $this->pivot[$row] = $row;
122 }
123
124 for ($column = 0; $column < $this->columns; ++$column) {
125 $luColumn = $this->localisedReferenceColumn($column);
126
127 $this->applyTransformations($column, $luColumn);
128
129 $pivot = $this->findPivot($column, $luColumn);
130 if ($pivot !== $column) {
131 $this->pivotExchange($pivot, $column);
132 }
133
134 $this->computeMultipliers($column);
135
136 unset($luColumn);
137 }
138 }
139
140 private function localisedReferenceColumn($column)
141 {
142 $luColumn = [];
143
144 for ($row = 0; $row < $this->rows; ++$row) {
145 $luColumn[$row] = &$this->luMatrix[$row][$column];
146 }
147
148 return $luColumn;
149 }
150
151 private function applyTransformations($column, array $luColumn)
152 {
153 for ($row = 0; $row < $this->rows; ++$row) {
154 $luRow = $this->luMatrix[$row];
155 // Most of the time is spent in the following dot product.
156 $kmax = min($row, $column);
157 $sValue = 0.0;
158 for ($kValue = 0; $kValue < $kmax; ++$kValue) {
159 $sValue += $luRow[$kValue] * $luColumn[$kValue];
160 }
161 $luRow[$column] = $luColumn[$row] -= $sValue;
162 }
163 }
164
165 private function findPivot($column, array $luColumn)
166 {
167 $pivot = $column;
168 for ($row = $column + 1; $row < $this->rows; ++$row) {
169 if (abs($luColumn[$row]) > abs($luColumn[$pivot])) {
170 $pivot = $row;
171 }
172 }
173
174 return $pivot;
175 }
176
177 private function pivotExchange($pivot, $column)
178 {
179 for ($kValue = 0; $kValue < $this->columns; ++$kValue) {
180 $tValue = $this->luMatrix[$pivot][$kValue];
181 $this->luMatrix[$pivot][$kValue] = $this->luMatrix[$column][$kValue];
182 $this->luMatrix[$column][$kValue] = $tValue;
183 }
184
185 $lValue = $this->pivot[$pivot];
186 $this->pivot[$pivot] = $this->pivot[$column];
187 $this->pivot[$column] = $lValue;
188 }
189
190 private function computeMultipliers($diagonal)
191 {
192 if (($diagonal < $this->rows) && ($this->luMatrix[$diagonal][$diagonal] != 0.0)) {
193 for ($row = $diagonal + 1; $row < $this->rows; ++$row) {
194 $this->luMatrix[$row][$diagonal] /= $this->luMatrix[$diagonal][$diagonal];
195 }
196 }
197 }
198
199 private function pivotB(Matrix $B)
200 {
201 $X = [];
202 foreach ($this->pivot as $rowId) {
203 $row = $B->getRows($rowId + 1)->toArray();
204 $X[] = array_pop($row);
205 }
206
207 return $X;
208 }
209
210 /**
211 * Solve A*X = B.
212 *
213 * @param Matrix $B a Matrix with as many rows as A and any number of columns
214 *
215 * @throws Exception
216 *
217 * @return Matrix X so that L*U*X = B(piv,:)
218 */
219 public function solve(Matrix $B)
220 {
221 if ($B->rows !== $this->rows) {
222 throw new Exception('Matrix row dimensions are not equal');
223 }
224
225 if ($this->rows !== $this->columns) {
226 throw new Exception('LU solve() only works on square matrices');
227 }
228
229 if (!$this->isNonsingular()) {
230 throw new Exception('Can only perform operation on singular matrix');
231 }
232
233 // Copy right hand side with pivoting
234 $nx = $B->columns;
235 $X = $this->pivotB($B);
236
237 // Solve L*Y = B(piv,:)
238 for ($k = 0; $k < $this->columns; ++$k) {
239 for ($i = $k + 1; $i < $this->columns; ++$i) {
240 for ($j = 0; $j < $nx; ++$j) {
241 $X[$i][$j] -= $X[$k][$j] * $this->luMatrix[$i][$k];
242 }
243 }
244 }
245
246 // Solve U*X = Y;
247 for ($k = $this->columns - 1; $k >= 0; --$k) {
248 for ($j = 0; $j < $nx; ++$j) {
249 $X[$k][$j] /= $this->luMatrix[$k][$k];
250 }
251 for ($i = 0; $i < $k; ++$i) {
252 for ($j = 0; $j < $nx; ++$j) {
253 $X[$i][$j] -= $X[$k][$j] * $this->luMatrix[$i][$k];
254 }
255 }
256 }
257
258 return new Matrix($X);
259 }
260 }
261