SingularValueDecomposition::__construct()   F
last analyzed

Complexity

Conditions 95
Paths > 20000

Size

Total Lines 373
Code Lines 241

Duplication

Lines 76
Ratio 20.38 %

Importance

Changes 0
Metric Value
cc 95
eloc 241
c 0
b 0
f 0
nc 32742304
nop 1
dl 76
loc 373
rs 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 *	@package JAMA
4
 *
5
 *	For an m-by-n matrix A with m >= n, the singular value decomposition is
6
 *	an m-by-n orthogonal matrix U, an n-by-n diagonal matrix S, and
7
 *	an n-by-n orthogonal matrix V so that A = U*S*V'.
8
 *
9
 *	The singular values, sigma[$k] = S[$k][$k], are ordered so that
10
 *	sigma[0] >= sigma[1] >= ... >= sigma[n-1].
11
 *
12
 *	The singular value decompostion always exists, so the constructor will
13
 *	never fail.  The matrix condition number and the effective numerical
14
 *	rank can be computed from this decomposition.
15
 *
16
 *	@author  Paul Meagher
17
 *	@license PHP v3.0
18
 *	@version 1.1
19
 */
20
class SingularValueDecomposition  {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after class name; 2 found
Loading history...
21
22
	/**
23
	 *	Internal storage of U.
24
	 *	@var array
25
	 */
26
	private $U = array();
27
28
	/**
29
	 *	Internal storage of V.
30
	 *	@var array
31
	 */
32
	private $V = array();
33
34
	/**
35
	 *	Internal storage of singular values.
36
	 *	@var array
37
	 */
38
	private $s = array();
39
40
	/**
41
	 *	Row dimension.
42
	 *	@var int
43
	 */
44
	private $m;
45
46
	/**
47
	 *	Column dimension.
48
	 *	@var int
49
	 */
50
	private $n;
51
52
53
	/**
54
	 *	Construct the singular value decomposition
55
	 *
56
	 *	Derived from LINPACK code.
57
	 *
58
	 *	@param $A Rectangular matrix
59
	 *	@return Structure to access U, S and V.
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
60
	 */
61
	public function __construct($Arg) {
62
63
		// Initialize.
64
		$A = $Arg->getArrayCopy();
65
		$this->m = $Arg->getRowDimension();
66
		$this->n = $Arg->getColumnDimension();
67
		$nu      = min($this->m, $this->n);
68
		$e       = array();
69
		$work    = array();
70
		$wantu   = true;
71
		$wantv   = true;
72
		$nct = min($this->m - 1, $this->n);
73
		$nrt = max(0, min($this->n - 2, $this->m));
74
75
		// Reduce A to bidiagonal form, storing the diagonal elements
76
		// in s and the super-diagonal elements in e.
77
		for ($k = 0; $k < max($nct,$nrt); ++$k) {
78
79
			if ($k < $nct) {
80
				// Compute the transformation for the k-th column and
81
				// place the k-th diagonal in s[$k].
82
				// Compute 2-norm of k-th column without under/overflow.
83
				$this->s[$k] = 0;
84
				for ($i = $k; $i < $this->m; ++$i) {
85
					$this->s[$k] = hypo($this->s[$k], $A[$i][$k]);
86
				}
87
				if ($this->s[$k] != 0.0) {
88
					if ($A[$k][$k] < 0.0) {
89
						$this->s[$k] = -$this->s[$k];
90
					}
91
					for ($i = $k; $i < $this->m; ++$i) {
92
						$A[$i][$k] /= $this->s[$k];
93
					}
94
					$A[$k][$k] += 1.0;
95
				}
96
				$this->s[$k] = -$this->s[$k];
97
			}
98
99
			for ($j = $k + 1; $j < $this->n; ++$j) {
100
				if (($k < $nct) & ($this->s[$k] != 0.0)) {
101
					// Apply the transformation.
102
					$t = 0;
103
					for ($i = $k; $i < $this->m; ++$i) {
104
						$t += $A[$i][$k] * $A[$i][$j];
105
					}
106
					$t = -$t / $A[$k][$k];
107
					for ($i = $k; $i < $this->m; ++$i) {
108
						$A[$i][$j] += $t * $A[$i][$k];
109
					}
110
					// Place the k-th row of A into e for the
111
					// subsequent calculation of the row transformation.
112
					$e[$j] = $A[$k][$j];
113
				}
114
			}
115
116
			if ($wantu AND ($k < $nct)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
117
				// Place the transformation in U for subsequent back
118
				// multiplication.
119
				for ($i = $k; $i < $this->m; ++$i) {
120
					$this->U[$i][$k] = $A[$i][$k];
121
				}
122
			}
123
124
			if ($k < $nrt) {
125
				// Compute the k-th row transformation and place the
126
				// k-th super-diagonal in e[$k].
127
				// Compute 2-norm without under/overflow.
128
				$e[$k] = 0;
129
				for ($i = $k + 1; $i < $this->n; ++$i) {
130
					$e[$k] = hypo($e[$k], $e[$i]);
131
				}
132
				if ($e[$k] != 0.0) {
133
					if ($e[$k+1] < 0.0) {
134
						$e[$k] = -$e[$k];
135
					}
136
					for ($i = $k + 1; $i < $this->n; ++$i) {
137
						$e[$i] /= $e[$k];
138
					}
139
					$e[$k+1] += 1.0;
140
				}
141
				$e[$k] = -$e[$k];
142
				if (($k+1 < $this->m) AND ($e[$k] != 0.0)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
143
					// Apply the transformation.
144 View Code Duplication
					for ($i = $k+1; $i < $this->m; ++$i) {
145
						$work[$i] = 0.0;
146
					}
147
					for ($j = $k+1; $j < $this->n; ++$j) {
148
						for ($i = $k+1; $i < $this->m; ++$i) {
149
							$work[$i] += $e[$j] * $A[$i][$j];
150
						}
151
					}
152
					for ($j = $k + 1; $j < $this->n; ++$j) {
153
						$t = -$e[$j] / $e[$k+1];
154
						for ($i = $k + 1; $i < $this->m; ++$i) {
155
							$A[$i][$j] += $t * $work[$i];
156
						}
157
					}
158
				}
159 View Code Duplication
				if ($wantv) {
160
					// Place the transformation in V for subsequent
161
					// back multiplication.
162
					for ($i = $k + 1; $i < $this->n; ++$i) {
163
						$this->V[$i][$k] = $e[$i];
164
					}
165
				}
166
			}
167
		}
168
169
		// Set up the final bidiagonal matrix or order p.
170
		$p = min($this->n, $this->m + 1);
171
		if ($nct < $this->n) {
172
			$this->s[$nct] = $A[$nct][$nct];
173
		}
174
		if ($this->m < $p) {
175
			$this->s[$p-1] = 0.0;
176
		}
177
		if ($nrt + 1 < $p) {
178
			$e[$nrt] = $A[$nrt][$p-1];
179
		}
180
		$e[$p-1] = 0.0;
181
		// If required, generate U.
182
		if ($wantu) {
183
			for ($j = $nct; $j < $nu; ++$j) {
184
				for ($i = 0; $i < $this->m; ++$i) {
185
					$this->U[$i][$j] = 0.0;
186
				}
187
				$this->U[$j][$j] = 1.0;
188
			}
189
			for ($k = $nct - 1; $k >= 0; --$k) {
190
				if ($this->s[$k] != 0.0) {
191 View Code Duplication
					for ($j = $k + 1; $j < $nu; ++$j) {
192
						$t = 0;
193
						for ($i = $k; $i < $this->m; ++$i) {
194
							$t += $this->U[$i][$k] * $this->U[$i][$j];
195
						}
196
						$t = -$t / $this->U[$k][$k];
197
						for ($i = $k; $i < $this->m; ++$i) {
198
							$this->U[$i][$j] += $t * $this->U[$i][$k];
199
						}
200
					}
201
					for ($i = $k; $i < $this->m; ++$i ) {
202
						$this->U[$i][$k] = -$this->U[$i][$k];
203
					}
204
					$this->U[$k][$k] = 1.0 + $this->U[$k][$k];
205 View Code Duplication
					for ($i = 0; $i < $k - 1; ++$i) {
206
						$this->U[$i][$k] = 0.0;
207
					}
208
				} else {
209 View Code Duplication
					for ($i = 0; $i < $this->m; ++$i) {
210
						$this->U[$i][$k] = 0.0;
211
					}
212
					$this->U[$k][$k] = 1.0;
213
				}
214
			}
215
		}
216
217
		// If required, generate V.
218
		if ($wantv) {
219
			for ($k = $this->n - 1; $k >= 0; --$k) {
220
				if (($k < $nrt) AND ($e[$k] != 0.0)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
221
					for ($j = $k + 1; $j < $nu; ++$j) {
222
						$t = 0;
223
						for ($i = $k + 1; $i < $this->n; ++$i) {
224
							$t += $this->V[$i][$k]* $this->V[$i][$j];
225
						}
226
						$t = -$t / $this->V[$k+1][$k];
227
						for ($i = $k + 1; $i < $this->n; ++$i) {
228
							$this->V[$i][$j] += $t * $this->V[$i][$k];
229
						}
230
					}
231
				}
232 View Code Duplication
				for ($i = 0; $i < $this->n; ++$i) {
233
					$this->V[$i][$k] = 0.0;
234
				}
235
				$this->V[$k][$k] = 1.0;
236
			}
237
		}
238
239
		// Main iteration loop for the singular values.
240
		$pp   = $p - 1;
241
		$iter = 0;
242
		$eps  = pow(2.0, -52.0);
243
244
		while ($p > 0) {
245
			// Here is where a test for too many iterations would go.
246
			// This section of the program inspects for negligible
247
			// elements in the s and e arrays.  On completion the
248
			// variables kase and k are set as follows:
249
			// kase = 1  if s(p) and e[k-1] are negligible and k<p
250
			// kase = 2  if s(k) is negligible and k<p
251
			// kase = 3  if e[k-1] is negligible, k<p, and
252
			//           s(k), ..., s(p) are not negligible (qr step).
253
			// kase = 4  if e(p-1) is negligible (convergence).
254
			for ($k = $p - 2; $k >= -1; --$k) {
255
				if ($k == -1) {
256
					break;
257
				}
258
				if (abs($e[$k]) <= $eps * (abs($this->s[$k]) + abs($this->s[$k+1]))) {
259
					$e[$k] = 0.0;
260
					break;
261
				}
262
			}
263
			if ($k == $p - 2) {
264
				$kase = 4;
265
			} else {
266
				for ($ks = $p - 1; $ks >= $k; --$ks) {
267
					if ($ks == $k) {
268
						break;
269
					}
270
					$t = ($ks != $p ? abs($e[$ks]) : 0.) + ($ks != $k + 1 ? abs($e[$ks-1]) : 0.);
271
					if (abs($this->s[$ks]) <= $eps * $t)  {
272
						$this->s[$ks] = 0.0;
273
						break;
274
					}
275
				}
276
				if ($ks == $k) {
277
					$kase = 3;
278
				} else if ($ks == $p-1) {
279
					$kase = 1;
280
				} else {
281
					$kase = 2;
282
					$k = $ks;
283
				}
284
			}
285
			++$k;
286
287
			// Perform the task indicated by kase.
288
			switch ($kase) {
289
				// Deflate negligible s(p).
290
				case 1:
291
						$f = $e[$p-2];
292
						$e[$p-2] = 0.0;
293
						for ($j = $p - 2; $j >= $k; --$j) {
294
							$t  = hypo($this->s[$j],$f);
295
							$cs = $this->s[$j] / $t;
296
							$sn = $f / $t;
297
							$this->s[$j] = $t;
298
							if ($j != $k) {
299
								$f = -$sn * $e[$j-1];
300
								$e[$j-1] = $cs * $e[$j-1];
301
							}
302 View Code Duplication
							if ($wantv) {
303
								for ($i = 0; $i < $this->n; ++$i) {
304
									$t = $cs * $this->V[$i][$j] + $sn * $this->V[$i][$p-1];
305
									$this->V[$i][$p-1] = -$sn * $this->V[$i][$j] + $cs * $this->V[$i][$p-1];
306
									$this->V[$i][$j] = $t;
307
								}
308
							}
309
						}
310
						break;
311
				// Split at negligible s(k).
312
				case 2:
313
						$f = $e[$k-1];
314
						$e[$k-1] = 0.0;
315
						for ($j = $k; $j < $p; ++$j) {
316
							$t = hypo($this->s[$j], $f);
317
							$cs = $this->s[$j] / $t;
318
							$sn = $f / $t;
319
							$this->s[$j] = $t;
320
							$f = -$sn * $e[$j];
321
							$e[$j] = $cs * $e[$j];
322 View Code Duplication
							if ($wantu) {
323
								for ($i = 0; $i < $this->m; ++$i) {
324
									$t = $cs * $this->U[$i][$j] + $sn * $this->U[$i][$k-1];
325
									$this->U[$i][$k-1] = -$sn * $this->U[$i][$j] + $cs * $this->U[$i][$k-1];
326
									$this->U[$i][$j] = $t;
327
								}
328
							}
329
						}
330
						break;
331
				// Perform one qr step.
332
				case 3:
333
						// Calculate the shift.
334
						$scale = max(max(max(max(
335
									abs($this->s[$p-1]),abs($this->s[$p-2])),abs($e[$p-2])),
336
									abs($this->s[$k])), abs($e[$k]));
337
						$sp   = $this->s[$p-1] / $scale;
338
						$spm1 = $this->s[$p-2] / $scale;
339
						$epm1 = $e[$p-2] / $scale;
340
						$sk   = $this->s[$k] / $scale;
341
						$ek   = $e[$k] / $scale;
342
						$b    = (($spm1 + $sp) * ($spm1 - $sp) + $epm1 * $epm1) / 2.0;
343
						$c    = ($sp * $epm1) * ($sp * $epm1);
344
						$shift = 0.0;
345
						if (($b != 0.0) || ($c != 0.0)) {
346
							$shift = sqrt($b * $b + $c);
347
							if ($b < 0.0) {
348
								$shift = -$shift;
349
							}
350
							$shift = $c / ($b + $shift);
351
						}
352
						$f = ($sk + $sp) * ($sk - $sp) + $shift;
353
						$g = $sk * $ek;
354
						// Chase zeros.
355
						for ($j = $k; $j < $p-1; ++$j) {
356
							$t  = hypo($f,$g);
357
							$cs = $f/$t;
358
							$sn = $g/$t;
359
							if ($j != $k) {
360
								$e[$j-1] = $t;
361
							}
362
							$f = $cs * $this->s[$j] + $sn * $e[$j];
363
							$e[$j] = $cs * $e[$j] - $sn * $this->s[$j];
364
							$g = $sn * $this->s[$j+1];
365
							$this->s[$j+1] = $cs * $this->s[$j+1];
366 View Code Duplication
							if ($wantv) {
367
								for ($i = 0; $i < $this->n; ++$i) {
368
									$t = $cs * $this->V[$i][$j] + $sn * $this->V[$i][$j+1];
369
									$this->V[$i][$j+1] = -$sn * $this->V[$i][$j] + $cs * $this->V[$i][$j+1];
370
									$this->V[$i][$j] = $t;
371
								}
372
							}
373
							$t = hypo($f,$g);
374
							$cs = $f/$t;
375
							$sn = $g/$t;
376
							$this->s[$j] = $t;
377
							$f = $cs * $e[$j] + $sn * $this->s[$j+1];
378
							$this->s[$j+1] = -$sn * $e[$j] + $cs * $this->s[$j+1];
379
							$g = $sn * $e[$j+1];
380
							$e[$j+1] = $cs * $e[$j+1];
381 View Code Duplication
							if ($wantu && ($j < $this->m - 1)) {
382
								for ($i = 0; $i < $this->m; ++$i) {
383
									$t = $cs * $this->U[$i][$j] + $sn * $this->U[$i][$j+1];
384
									$this->U[$i][$j+1] = -$sn * $this->U[$i][$j] + $cs * $this->U[$i][$j+1];
385
									$this->U[$i][$j] = $t;
386
								}
387
							}
388
						}
389
						$e[$p-2] = $f;
390
						$iter = $iter + 1;
391
						break;
392
				// Convergence.
393
				case 4:
394
						// Make the singular values positive.
395
						if ($this->s[$k] <= 0.0) {
396
							$this->s[$k] = ($this->s[$k] < 0.0 ? -$this->s[$k] : 0.0);
397 View Code Duplication
							if ($wantv) {
398
								for ($i = 0; $i <= $pp; ++$i) {
399
									$this->V[$i][$k] = -$this->V[$i][$k];
400
								}
401
							}
402
						}
403
						// Order the singular values.
404
						while ($k < $pp) {
405
							if ($this->s[$k] >= $this->s[$k+1]) {
406
								break;
407
							}
408
							$t = $this->s[$k];
409
							$this->s[$k] = $this->s[$k+1];
410
							$this->s[$k+1] = $t;
411 View Code Duplication
							if ($wantv AND ($k < $this->n - 1)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
412
								for ($i = 0; $i < $this->n; ++$i) {
413
									$t = $this->V[$i][$k+1];
414
									$this->V[$i][$k+1] = $this->V[$i][$k];
415
									$this->V[$i][$k] = $t;
416
								}
417
							}
418 View Code Duplication
							if ($wantu AND ($k < $this->m-1)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
419
								for ($i = 0; $i < $this->m; ++$i) {
420
									$t = $this->U[$i][$k+1];
421
									$this->U[$i][$k+1] = $this->U[$i][$k];
422
									$this->U[$i][$k] = $t;
423
								}
424
							}
425
							++$k;
426
						}
427
						$iter = 0;
428
						--$p;
429
						break;
430
			} // end switch
431
		} // end while
432
433
	} // end constructor
434
435
436
	/**
437
	 *	Return the left singular vectors
438
	 *
439
	 *	@access public
440
	 *	@return U
441
	 */
442
	public function getU() {
443
		return new Matrix($this->U, $this->m, min($this->m + 1, $this->n));
444
	}
445
446
447
	/**
448
	 *	Return the right singular vectors
449
	 *
450
	 *	@access public
451
	 *	@return V
452
	 */
453
	public function getV() {
454
		return new Matrix($this->V);
455
	}
456
457
458
	/**
459
	 *	Return the one-dimensional array of singular values
460
	 *
461
	 *	@access public
462
	 *	@return diagonal of S.
463
	 */
464
	public function getSingularValues() {
465
		return $this->s;
466
	}
467
468
469
	/**
470
	 *	Return the diagonal matrix of singular values
471
	 *
472
	 *	@access public
473
	 *	@return S
474
	 */
475
	public function getS() {
476
		for ($i = 0; $i < $this->n; ++$i) {
477
			for ($j = 0; $j < $this->n; ++$j) {
478
				$S[$i][$j] = 0.0;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$S was never initialized. Although not strictly required by PHP, it is generally a good practice to add $S = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
479
			}
480
			$S[$i][$i] = $this->s[$i];
0 ignored issues
show
Bug introduced by
The variable $S does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
481
		}
482
		return new Matrix($S);
483
	}
484
485
486
	/**
487
	 *	Two norm
488
	 *
489
	 *	@access public
490
	 *	@return max(S)
0 ignored issues
show
Documentation introduced by
The doc-type max(S) could not be parsed: Expected "|" or "end of type", but got "(" at position 3. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
491
	 */
492
	public function norm2() {
493
		return $this->s[0];
494
	}
495
496
497
	/**
498
	 *	Two norm condition number
499
	 *
500
	 *	@access public
501
	 *	@return max(S)/min(S)
0 ignored issues
show
Documentation introduced by
The doc-type max(S)/min(S) could not be parsed: Expected "|" or "end of type", but got "(" at position 3. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
502
	 */
503
	public function cond() {
504
		return $this->s[0] / $this->s[min($this->m, $this->n) - 1];
505
	}
506
507
508
	/**
509
	 *	Effective numerical matrix rank
510
	 *
511
	 *	@access public
512
	 *	@return Number of nonnegligible singular values.
513
	 */
514
	public function rank() {
515
		$eps = pow(2.0, -52.0);
516
		$tol = max($this->m, $this->n) * $this->s[0] * $eps;
517
		$r = 0;
518
		for ($i = 0; $i < count($this->s); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
519
			if ($this->s[$i] > $tol) {
520
				++$r;
521
			}
522
		}
523
		return $r;
524
	}
525
526
}	//	class SingularValueDecomposition
527