public function __construct(Matrix $_matrix) { $this->l_matrix = $_matrix; $m = $_matrix->u_size; $n = $_matrix->u_stride; /*if($m < $n) { return; }*/ $a = clone $this->l_matrix->u_data; /*$nu = min($m, $n);*/ $this->l_singular = new Vector($sl = min($m + 1, $n)); $s = $this->l_singular->u_data; $this->l_left = new Matrix($um = $m, $un = $m); $u = $this->l_left->u_data; $this->l_right = new Matrix($vm = $n, $vn = $n); $v = $this->l_right->u_data; $e = arrayFill($n, 0.0); $work = arrayFill($m, 0.0); $wantu = true; $wantv = true; /* Reduce A to bidiagonal form, storing the diagonal elements in s and the super-diagonal elements in e. */ $nct = min($m - 1, $n); $nrt = max(0, min($n - 2, $m)); $kmax = max($nct, $nrt); for ($k = 0; $k < $kmax; $k++) { if ($k < $nct) { /* Compute the transformation for the k-th column and place the k-th diagonal in s[k]. Compute 2-norm of k-th column without under/overflow. */ $s[$k] = 0.0; for ($i = $k; $i < $m; $i++) { $s[$k] = hypot($s[$k], $a[$i * $n + $k]); } if (compare($s[$k], 0)) { if ($a[$pos = $k * $n + $k] < 0) { $s[$k] = -$s[$k]; } for ($i = $k; $i < $m; $i++) { $a[$i * $n + $k] /= (double) $s[$k]; /* Division */ } $a[$pos] += 1.0; } $s[$k] = -$s[$k]; } for ($j = $k + 1; $j < $n; $j++) { if ($k < $nct && compare($s[$k], 0)) { /* Apply the transformation. */ $t = 0.0; for ($i = $k; $i < $m; $i++) { $t += $a[$i * $n + $k] * $a[$i * $n + $j]; } $t = -$t / (double) $a[$k * $n + $k]; /* Division */ for ($i = $k; $i < $m; $i++) { $a[$i * $n + $j] += $t * $a[$i * $n + $k]; } } /* Place the k-th row of A into e for the subsequent calculation of the row transformation. */ $e[$j] = $a[$k * $n + $j]; } if ($wantu && $k < $nct) { /* Place the transformation in U for subsequent back multiplication. */ for ($i = $k; $i < $m; $i++) { $u[$i * $un + $k] = $a[$i * $n + $k]; } } if ($k < $nrt) { /* Compute the k-th row transformation and place the k-th super-diagonal in e[k]. Compute 2-norm without under/overflow. */ $e[$k] = 0.0; for ($i = $k + 1; $i < $n; $i++) { $e[$k] = hypot($e[$k], $e[$i]); } if (compare($e[$k], 0)) { if ($e[$k + 1] < 0) { $e[$k] = -$e[$k]; } for ($i = $k + 1; $i < $n; $i++) { $e[$i] /= (double) $e[$k]; /* Division */ } $e[$k + 1] += 1.0; } $e[$k] = -$e[$k]; if ($k + 1 < $m && compare($e[$k], 0)) { /* Apply the transformation. */ for ($i = $k + 1; $i < $m; $i++) { $work[$i] = 0.0; } for ($j = $k + 1; $j < $n; $j++) { for ($i = $k + 1; $i < $m; $i++) { $work[$i] += $e[$j] * $a[$i * $n + $j]; } } for ($j = $k + 1; $j < $n; $j++) { $t = -$e[$j] / (double) $e[$k + 1]; /* Division */ for ($i = $k + 1; $i < $m; $i++) { $a[$i * $n + $j] += $t * $work[$i]; } } } if ($wantv) { /* Place the transformation in V for subsequent back multiplication. */ for ($i = $k + 1; $i < $n; $i++) { $v[$i * $vn + $k] = $e[$i]; } } } } /* Set up the final bidiagonal matrix or order p. */ $p = min($n, $m + 1); if ($nct < $n) { $s[$nct] = $a[$nct * $n + $nct]; } if ($m < $p) { $s[$p - 1] = 0.0; } if ($nrt + 1 < $p) { $e[$nrt] = $a[$nrt * $n + $p - 1]; } $e[$p - 1] = 0.0; /* If required, generate U. */ if ($wantu) { for ($j = $nct; $j < $m; $j++) { for ($i = 0; $i < $m; $i++) { $u[$i * $un + $j] = 0.0; } $u[$j * $un + $j] = 1.0; } for ($k = $nct - 1; $k >= 0; $k--) { if (compare($s[$k], 0)) { for ($j = $k + 1; $j < $m; $j++) { $t = 0.0; for ($i = $k; $i < $m; $i++) { $t += $u[$i * $un + $k] * $u[$i * $un + $j]; } $t = -$t / (double) $u[$k * $un + $k]; /* Division */ for ($i = $k; $i < $m; $i++) { $u[$i * $un + $j] += $t * $u[$i * $un + $k]; } } for ($i = $k; $i < $m; $i++) { $u[$pos = $i * $un + $k] = -$u[$pos]; } $u[$pos = $k * $un + $k] = 1.0 + $u[$pos]; for ($i = 0; $i < $k - 1; $i++) { $u[$i * $un + $k] = 0.0; } } else { for ($i = 0; $i < $m; $i++) { $u[$i * $un + $k] = 0.0; } $u[$k * $un + $k] = 1.0; } } } /* If required, generate V. */ if ($wantv) { for ($k = $n - 1; $k >= 0; $k--) { if ($k < $nrt && compare($e[$k], 0)) { for ($j = $k + 1; $j < $n; $j++) { $t = 0.0; for ($i = $k + 1; $i < $n; $i++) { $t += $v[$i * $vn + $k] * $v[$i * $vn + $j]; } $t = -$t / (double) $v[($k + 1) * $vn + $k]; /* Division */ for ($i = $k + 1; $i < $n; $i++) { $v[$i * $vn + $j] += $t * $v[$i * $vn + $k]; } } } for ($i = 0; $i < $n; $i++) { $v[$i * $vn + $k] = 0.0; } $v[$k * $vn + $k] = 1.0; } } /* Main iteration loop for the singular values. */ $pp = $p - 1; $iter = 0; $eps = pow(2, -52); $tiny = pow(2, -966); while ($p > 0) { $k = $kase = null; /* Here is where a test for too many iterations would go. This section of the program inspects for negligible elements in the s and e arrays. On completion the variables kase and k are set as follows. kase = 1 if s(p) and e[k - 1] are negligible and k < p kase = 2 if s(k) is negligible and k < p kase = 3 if e[k - 1] is negligible, k < p, and s(k), ..., s(p) are not negligible (qr step). kase = 4 if e(p - 1) is negligible (convergence). */ for ($k = $p - 2; $k >= -1; $k--) { if ($k == -1) { break; } if (compare(abs($e[$k]), $tiny + $eps * (abs($s[$k]) + abs($s[$k + 1]))) <= 0) { $e[$k] = 0.0; break; } } if ($k == $p - 2) { $kase = 4; } else { $ks = null; for ($ks = $p - 1; $ks >= $k; $ks--) { if ($ks == $k) { break; } $t = ($ks != $p ? abs($e[$ks]) : 0) + ($ks != $k + 1 ? abs($e[$ks - 1]) : 0); if (compare(abs($s[$ks]), $tiny + $eps * $t) <= 0) { $s[$ks] = 0.0; break; } } if ($ks == $k) { $kase = 3; } else { if ($ks == $p - 1) { $kase = 1; } else { $kase = 2; $k = $ks; } } } $k++; /* Perform the task indicated by kase. */ switch ($kase) { /* Deflate negligible s(p). */ case 1: $f = $e[$p - 2]; $e[$p - 2] = 0.0; for ($j = $p - 2; $j >= $k; $j--) { $t = (double) hypot($s[$j], $f); $cs = $s[$j] / $t; /* Division */ $sn = $f / $t; /* Division */ $s[$j] = $t; if ($j != $k) { $f = -$sn * $e[$j - 1]; $e[$j - 1] = $cs * $e[$j - 1]; } if ($wantv) { for ($i = 0; $i < $n; $i++) { $t = $cs * $v[$ijpos = $i * $vn + $j] + $sn * $v[$ippos = $i * $vn + $p - 1]; $v[$ippos] = -$sn * $v[$ijpos] + $cs * $v[$ippos]; $v[$ijpos] = $t; } } } break; /* Split at negligible s(k). */ /* Split at negligible s(k). */ case 2: $f = $e[$k - 1]; $e[$k - 1] = 0.0; for ($j = $k; $j < $p; $j++) { $t = (double) hypot($s[$j], $f); $cs = $s[$j] / $t; /* Division */ $sn = $f / $t; /* Division */ $s[$j] = $t; $f = -$sn * $e[$j]; $e[$j] = $cs * $e[$j]; if ($wantu) { for ($i = 0; $i < $m; $i++) { $t = $cs * $u[$ijpos = $i * $un + $j] + $sn * $u[$ikpos = $i * $un + $k - 1]; $u[$ikpos] = -$sn * $u[$ijpos] + $cs * $u[$ikpos]; $u[$ijpos] = $t; } } } break; /* Perform one qr step. */ /* Perform one qr step. */ case 3: /* Calculate the shift. */ $scale = (double) max(max(max(max(abs($s[$p - 1]), abs($s[$p - 2])), abs($e[$p - 2])), abs($s[$k])), abs($e[$k])); $sp = $s[$p - 1] / $scale; /* Division */ $spm1 = $s[$p - 2] / $scale; /* Division */ $epm1 = $e[$p - 2] / $scale; /* Division */ $sk = $s[$k] / $scale; /* Division */ $ek = $e[$k] / $scale; /* Division */ $b = (($spm1 + $sp) * ($spm1 - $sp) + $epm1 * $epm1) / 2.0; $c = $sp * $epm1 * ($sp * $epm1); $shift = 0.0; if (compare($b, 0) || compare($c, 0)) { $shift = sqrt($b * $b + $c); if ($b < 0) { $shift = -$shift; } $shift = $c / (double) ($b + $shift); /* Division */ } $f = ($sk + $sp) * ($sk - $sp) + $shift; $g = $sk * $ek; /* Chase zeros. */ for ($j = $k; $j < $p - 1; $j++) { $t = (double) hypot($f, $g); $cs = $f / $t; /* Division */ $sn = $g / $t; /* Division */ if ($j != $k) { $e[$j - 1] = $t; } $f = $cs * $s[$j] + $sn * $e[$j]; $e[$j] = $cs * $e[$j] - $sn * $s[$j]; $g = $sn * $s[$j + 1]; $s[$j + 1] = $cs * $s[$j + 1]; if ($wantv) { for ($i = 0; $i < $n; $i++) { $t = $cs * $v[$ijpos = $i * $vn + $j] + $sn * $v[$ij1pos = $i * $vn + $j + 1]; $v[$ij1pos] = -$sn * $v[$ijpos] + $cs * $v[$ij1pos]; $v[$ijpos] = $t; } } $t = (double) hypot($f, $g); $cs = $f / $t; /* Division */ $sn = $g / $t; /* Division */ $s[$j] = $t; $f = $cs * $e[$j] + $sn * $s[$j + 1]; $s[$j + 1] = -$sn * $e[$j] + $cs * $s[$j + 1]; $g = $sn * $e[$j + 1]; $e[$j + 1] = $cs * $e[$j + 1]; if ($wantu && $j < $m - 1) { for ($i = 0; $i < $m; $i++) { $t = $cs * $u[$ijpos = $i * $un + $j] + $sn * $u[$ij1pos = $i * $un + $j + 1]; $u[$ij1pos] = -$sn * $u[$ijpos] + $cs * $u[$ij1pos]; $u[$ijpos] = $t; } } } $e[$p - 2] = $f; $iter = $iter + 1; break; /* Convergence. */ /* Convergence. */ case 4: /* Make the singular values positive. */ if (compare($s[$k], 0) <= 0) { $s[$k] = $s[$k] < 0 ? -$s[$k] : 0.0; if ($wantv) { for ($i = 0; $i <= $pp; $i++) { $v[$pos = $i * $vn + $k] = -$v[$pos]; } } } /* Order the singular values. */ while ($k < $pp) { if (compare($s[$k], $s[$k + 1]) >= 0) { break; } $t = $s[$k]; $s[$k] = $s[$k + 1]; $s[$k + 1] = $t; if ($wantv && $k < $n - 1) { for ($i = 0; $i < $n; $i++) { $t = $v[$ik1pos = $i * $vn + $k + 1]; $v[$ik1pos] = $v[$ikpos = $i * $vn + $k]; $v[$ikpos] = $t; } } if ($wantu && $k < $m - 1) { for ($i = 0; $i < $m; $i++) { $t = $u[$ik1pos = $i * $un + $k + 1]; $u[$ik1pos] = $u[$ikpos = $i * $un + $k]; $u[$ikpos] = $t; } } $k++; } $iter = 0; $p--; break; } } if ($sl > $m) { $this->l_singular->u_stride = $m; $s->setSize($m); } }
public function __construct($_size, $_stride = 1, $_offset = 0, $_access = ACCESS_ROWS, \SplFixedArray $_data = null) { $this->l_position = 0; switch ($_access) { case ACCESS_ROWS: $this->l_count =& $this->u_size; break; case ACCESS_COLUMNS: $this->l_count =& $this->u_stride; break; default: $this->l_count = 0; } $this->u_size = max(0, (int) $_size); $this->u_stride = max(0, (int) $_stride); $this->u_offset = max(0, (int) $_offset); $this->u_data = $_data === null ? arrayFill($this->u_size * $this->u_stride, 0.0) : $_data; }
public function spearmanCorrelationColumns() { $result = new Matrix($this->u_stride, $this->u_stride); $combinations1 = $combinations2 = 0; $ranks1 = arrayFill($this->u_size, 0.0); $ranks2 = arrayFill($this->u_size, 0.0); for ($i = 0; $i < $result->u_size; $i++) { $offset = $i * $result->u_stride; $this->u_spearmanRanks($this->u_data, $this->u_size, $this->u_stride, $i, $ranks1, $combinations1); for ($j = $i; $j < $result->u_stride; $j++) { if ($i == $j) { $result->u_data[$offset + $j] = $result->u_data[$j * $result->u_stride + $i] = 1; } else { $this->u_spearmanRanks($this->u_data, $this->u_size, $this->u_stride, $j, $ranks2, $combinations2); $result->u_data[$offset + $j] = $result->u_data[$j * $result->u_stride + $i] = $this->u_spearmanCorrelation($ranks1, $combinations1, $ranks2, $combinations2, $this->u_size); } } } return $result; }
public function spearmanCorrelation(AbstractVector $_vector) { if ($_vector->u_stride !== $this->u_stride) { return null; } $combinations1 = $combinations2 = 0; $ranks1 = arrayFill($this->u_stride, 0.0); $ranks2 = arrayFill($this->u_stride, 0.0); $this->u_spearmanRanks($this->u_data, $this->u_stride, 1, $this->u_offset, $ranks1, $combinations1); $this->u_spearmanRanks($_vector->u_data, $_vector->u_stride, 1, $_vector->u_offset, $ranks2, $combinations2); return $this->u_spearmanCorrelation($ranks1, $combinations1, $ranks2, $combinations2, $this->u_stride); }