// TODO: confirm this is a "Thin SVD"
// as per Wikipedia
int n = Math.min(rc, cc); // this should always be cc??
Matrix u = Matrix.create(rc, n);
Vector s = Vector.createLength(cc);
Matrix v = Matrix.create(cc, cc);
Vector e = Vector.createLength(cc);
Vector work = Vector.createLength(rc);
int nct = Math.min(rc - 1, cc);
int nrt = Math.max(0, Math.min(cc - 2, rc));
for (int k = 0; k < Math.max(nct, nrt); k++) {
if (k < nct) {
for (int i = k; i < rc; i++) {
s.set(k, Math.hypot(s.get(k), a.get(i, k)));
}
if (Math.abs(s.get(k)) > Constants.EPS) {
if (a.get(k, k) < 0.0) {
s.set(k, -s.get(k));
}
for (int i = k; i < rc; i++) {
a.set(i, k, a.get(i, k) / (s.get(k)));
}
a.addAt(k, k, 1.0);
}
s.set(k, -s.get(k));
}
for (int j = k + 1; j < cc; j++) {
if ((k < nct) && (Math.abs(s.get(k)) > Constants.EPS)) {
double t = 0;
for (int i = k; i < rc; i++) {
t += a.get(i, k) * a.get(i, j);
}
t = -t / a.get(k, k);
for (int i = k; i < rc; i++) {
a.addAt(i, j, (t * a.get(i, k)));
}
}
e.set(j, a.get(k, j));
}
if (k < nct) {
for (int i = k; i < rc; i++) {
u.set(i, k, a.get(i, k));
}
}
if (k < nrt) {
e.set(k, 0);
for (int i = k + 1; i < cc; i++) {
e.set(k, Math.hypot(e.get(k), e.get(i)));
}
if (Math.abs(e.get(k)) > Constants.EPS) {
if (e.get(k + 1) < 0.0) {
e.set(k, -e.get(k));
}
for (int i = k + 1; i < cc; i++) {
e.set(i, e.get(i) / (e.get(k)));
}
e.addAt(k + 1, 1.0);
}
e.set(k, -e.get(k));
if ((k + 1 < rc) && (Math.abs(e.get(k)) > Constants.EPS)) {
for (int j = k + 1; j < cc; j++) {
for (int i = k + 1; i < rc; i++) {
work.addAt(i, (e.get(j) * a.get(i, j)));
}
}
for (int j = k + 1; j < cc; j++) {
double t = -e.get(j) / e.get(k + 1);
for (int i = k + 1; i < rc; i++) {
a.addAt(i, j, (t * work.get(i)));
}
}
}
for (int i = k + 1; i < cc; i++) {