Accord.Math.Decompositions.NonnegativeFactorization.nnmf C# (CSharp) Method

nnmf() private method

Single non-negative matrix factorization.
private nnmf ( double value, double &w0, double &h0, NonnegativeFactorizationAlgorithm alg, int maxIterations, double normChangeThreshold, double maxFactorChangeThreshold ) : double
value double
w0 double
h0 double
alg NonnegativeFactorizationAlgorithm
maxIterations int
normChangeThreshold double
maxFactorChangeThreshold double
return double
        private double nnmf(double[,] value,
                            ref double[,] w0, ref double[,] h0, NonnegativeFactorizationAlgorithm alg,
                            int maxIterations, double normChangeThreshold, double maxFactorChangeThreshold)
        {
            double[,] v = value;
            double[,] h = h0;
            double[,] w = w0;
            double[,] z = null;

            double dnorm0 = 0.0; // previous iteration norm

            // Main loop
            for (int iteration = 0; iteration < maxIterations; iteration++)
            {
                // Check which algorithm should be used
                if (alg == NonnegativeFactorizationAlgorithm.MultiplicativeUpdate)
                {
                    // Multiplicative update formula
                    h = new double[k,m];
                    w = new double[n,k];

                    if (z == null) z = new double[k,k];

                    // Update H
                    for (int i = 0; i < k; i++)
                    {
                        for (int j = i; j < k; j++)
                        {
                            double s = 0.0;
                            for (int l = 0; l < n; l++)
                                s += w0[l, i]*w0[l, j];
                            z[i, j] = z[j, i] = s;
                        }

                        for (int j = 0; j < m; j++)
                        {
                            double d = 0.0;
                            for (int l = 0; l < k; l++)
                                d += z[i, l]*h0[l, j];

                            double s = 0.0;
                            for (int l = 0; l < n; l++)
                                s += w0[l, i]*v[l, j];

                            h[i, j] = h0[i, j]*s/(d + Special.Epslon(s));
                        }
                    }

                    // Update W
                    for (int j = 0; j < k; j++)
                    {
                        for (int i = j; i < k; i++)
                        {
                            double s = 0.0;
                            for (int l = 0; l < m; l++)
                                s += h[i, l]*h[j, l];
                            z[i, j] = z[j, i] = s;
                        }

                        for (int i = 0; i < n; i++)
                        {
                            double d = 0.0;
                            for (int l = 0; l < k; l++)
                                d += w0[i, l]*z[j, l];

                            double s = 0.0;
                            for (int l = 0; l < m; l++)
                                s += v[i, l]*h[j, l];

                            w[i, j] = w0[i, j]*s/(d + Special.Epslon(s));
                        }
                    }
                }
                else
                {
                    // Alternating least squares update
                    h = w0.Solve(v);
                    makepositive(h);
                    w = v.Divide(h);
                    makepositive(w);
                }


                // Reconstruct matrix A using W and H
                double[,] r = w.Multiply(h);

                // Get norm of difference
                double dnorm = normdiff(v, r);

                // Get maximum change in factors
                double dw = maxdiff(w0, w)/(sqrteps + maxabs(w0));
                double dh = maxdiff(h0, h)/(sqrteps + maxabs(h0));
                double delta = System.Math.Max(dw, dh);

                if (iteration > 0) // Check for convergence
                {
                    if (delta <= maxFactorChangeThreshold ||
                        dnorm <= normChangeThreshold*dnorm0)
                        break;
                }

                // Remember previous iteration results
                dnorm0 = dnorm;
                w0 = w;
                h0 = h;
            }

            return dnorm0;
        }