All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.carrot2.matrix.factorization.NonnegativeMatrixFactorizationED Maven / Gradle / Ivy

Go to download

Carrot2 search results clustering framework. Minimal functional subset (core algorithms and infrastructure, no document sources).

There is a newer version: 3.16.3
Show newest version

/*
 * Carrot2 project.
 *
 * Copyright (C) 2002-2013, Dawid Weiss, Stanisław Osiński.
 * All rights reserved.
 *
 * Refer to the full license file "carrot2.LICENSE"
 * in the root folder of the repository checkout or at:
 * http://www.carrot2.org/carrot2.LICENSE
 */

package org.carrot2.matrix.factorization;

import org.apache.mahout.math.function.DoubleFunction;
import org.apache.mahout.math.function.Functions;
import org.apache.mahout.math.matrix.DoubleMatrix2D;
import org.apache.mahout.math.matrix.impl.DenseDoubleMatrix2D;

/**
 * Performs matrix factorization using the Non-negative Matrix Factorization algorithm
 * with minimization of Euclidean Distance between A and UV' and multiplicative updating.
 */
@SuppressWarnings("deprecation")
public class NonnegativeMatrixFactorizationED extends IterativeMatrixFactorizationBase
{
    /**
     * Creates the NNINonnegativeMatrixFactorizationED object for matrix A. Before
     * accessing results, perform computations by calling the {@link #compute()}method.
     * 
     * @param A matrix to be factorized
     */
    public NonnegativeMatrixFactorizationED(DoubleMatrix2D A)
    {
        super(A);
    }

    public void compute()
    {
        // Prototype Matlab code for the NMF-ED
        //        
        // function [U, V, C] = nmf-ed(A)
        // [m, n] = size(A);
        // k = 2; % the desired number of base vectors
        // maxiter = 50; % the number of iterations
        // eps = 1e-9; % machine epsilon
        //        
        // U = rand(m, k); % initialise U randomly
        // V = rand(n, k); % initialise V randomly
        //        
        // for iter = 1:maxiter
        // V = V.*((A'*U+eps)./(V*U'*U+eps)); % update V
        // U = U.*((A*V+eps)./(U*V'*V+eps)); % update U
        // C(1, iter) = norm((A-U*V'), 'fro'); % approximation quality
        // end

        double eps = 1e-9;

        // Seed U and V with initial values
        U = new DenseDoubleMatrix2D(A.rows(), k);
        V = new DenseDoubleMatrix2D(A.columns(), k);
        seedingStrategy.seed(A, U, V);

        // Temporary matrices
        DoubleMatrix2D T = new DenseDoubleMatrix2D(k, k);
        DoubleMatrix2D UT1 = new DenseDoubleMatrix2D(A.rows(), k);
        DoubleMatrix2D UT2 = new DenseDoubleMatrix2D(A.rows(), k);
        DoubleMatrix2D VT1 = new DenseDoubleMatrix2D(A.columns(), k);
        DoubleMatrix2D VT2 = new DenseDoubleMatrix2D(A.columns(), k);
        DoubleFunction plusEps = Functions.plus(eps);

        if (stopThreshold >= 0)
        {
            updateApproximationError();
        }

        for (int i = 0; i < maxIterations; i++)
        {
            // Update V
            U.zMult(U, T, 1, 0, true, false); // T <- U'U
            A.zMult(U, VT1, 1, 0, true, false); // VT1 <- A'U
            V.zMult(T, VT2, 1, 0, false, false); // VT2 <- VT
            VT1.assign(plusEps); // TODO: shift this to the dividing function?
            VT2.assign(plusEps);
            VT1.assign(VT2, Functions.DIV); // VT1 <- VT1 ./ VT2
            V.assign(VT1, Functions.MULT); // V <- V .* VT1

            // Update U
            V.zMult(V, T, 1, 0, true, false); // T <- V'V
            A.zMult(V, UT1, 1, 0, false, false); // UT1 <- AV
            U.zMult(T, UT2, 1, 0, false, false); // UT2 <- UT
            UT1.assign(plusEps);
            UT2.assign(plusEps);
            UT1.assign(UT2, Functions.DIV); // UT1 <- UT1 ./ UT2
            U.assign(UT1, Functions.MULT); // U <- U .* UT1

            iterationsCompleted++;
            if (stopThreshold >= 0)
            {
                if (updateApproximationError())
                {
                    break;
                }
            }
        }

        if (ordered)
        {
            order();
        }
    }

    public String toString()
    {
        return "NMF-ED-" + seedingStrategy.toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy