private void compute(int maxiter)
{
// chose W and H randomly, W with unit norm
W = Accord.Math.Matrix.Random(m, r);
H = Accord.Math.Matrix.Random(r, n);
var Z = new double[r, r];
// a small epsilon is added to the
// denominator to avoid overflow.
double eps = 10e-9;
for (int t = 0; t < maxiter; t++)
{
var newW = new double[m, r];
var newH = new double[r, n];
// Update H using the multiplicative
// H = H .* (W'*A) ./ (W'*W*H + eps)
for (int i = 0; i < r; i++)
{
for (int j = i; j < r; j++)
{
double s = 0.0;
for (int l = 0; l < m; l++)
s += W[l, i] * W[l, j];
Z[i, j] = Z[j, i] = s;
}
for (int j = 0; j < n; j++)
{
double d = 0.0;
for (int l = 0; l < r; l++)
d += Z[i, l] * H[l, j];
double s = 0.0;
for (int l = 0; l < m; l++)
s += W[l, i] * X[j, l];
newH[i, j] = H[i, j] * s / (d + eps);
}
}
// Update W using the multiplicative
// W = W .* (A*H') ./ (W*H*H' + eps)
for (int j = 0; j < r; j++)
{
for (int i = j; i < r; i++)
{
double s = 0.0;
for (int l = 0; l < m; l++)
s += newH[i, l] * newH[j, l];
Z[i, j] = Z[j, i] = s;
}
for (int i = 0; i < m; i++)
{
double d = 0.0;
for (int l = 0; l < r; l++)
d += W[i, l] * Z[j, l];
double s = 0.0;
for (int l = 0; l < n; l++)
s += X[l, i] * newH[j, l];
newW[i, j] = W[i, j] * s / (d + eps);
}
}
W = newW;
H = newH;
}
}
}