org.carrot2.matrix.factorization.NonnegativeMatrixFactorizationED Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of carrot2-mini Show documentation
Show all versions of carrot2-mini Show documentation
Carrot2 search results clustering framework. Minimal functional subset
(core algorithms and infrastructure, no document sources).
/*
* 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();
}
}