/*
* Carrot2 project.
*
* Copyright (C) 2002-2016, 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.carrot2.mahout.math.matrix.DoubleMatrix2D;
import org.carrot2.mahout.math.matrix.impl.DenseDoubleMatrix2D;
import org.carrot2.matrix.MatrixAssertions;
import org.carrot2.matrix.factorization.seeding.ISeedingStrategy;
import org.carrot2.matrix.factorization.seeding.ISeedingStrategyFactory;
import org.carrot2.util.tests.CarrotTestCase;
import org.junit.Test;
/**
* Test cases for matrix factorizations.
*/
public class MatrixFactorizationTest extends CarrotTestCase
{
/** Factorization parameters */
private static final int K = 2;
private static final int MAX_ITERATIONS = 50;
private static final double STOP_THRESHOLD = 0.0;
/** The maximum allowed difference between matrix elements */
private double DELTA = 1e-4;
/** The test input matrix */
private DoubleMatrix2D A = new DenseDoubleMatrix2D(new double [] []
{
{
0.00, 0.00, 0.56, 0.56, 0.00, 0.00, 1.00
},
{
0.49, 0.71, 0.00, 0.00, 0.00, 0.71, 0.00
},
{
0.49, 0.71, 0.00, 0.00, 0.00, 0.71, 0.00
},
{
0.72, 0.00, 0.00, 0.00, 1.00, 0.00, 0.00
},
{
0.00, 0.00, 0.83, 0.83, 0.00, 0.00, 0.00
}
});
@Test
public void testSVD()
{
PartialSingularValueDecompositionFactory factory = new PartialSingularValueDecompositionFactory();
factory.setK(2);
PartialSingularValueDecomposition factorization = (PartialSingularValueDecomposition) factory
.factorize(A);
DoubleMatrix2D expectedU = new DenseDoubleMatrix2D(new double [] []
{
{
0, 0.752646
},
{
-0.651927, 0
},
{
-0.651927, 0
},
{
-0.387277, 0
},
{
0, 0.658425
}
});
DoubleMatrix2D expectedV = new DenseDoubleMatrix2D(new double [] []
{
{
-0.557873, 0
},
{
-0.562741, 0
},
{
-2.775558E-017, 0.619628
},
{
8.326673E-017, 0.619628
},
{
-0.23542, 0
},
{
-0.562741, 0
},
{
2.220446E-016, 0.48179
}
});
double [] expectedS = new double []
{
1.6450472, 1.5621864
};
check(expectedU, expectedV, factorization);
org.junit.Assert.assertArrayEquals(expectedS, factorization.getSingularValues(), DELTA);
}
@Test
public void testUnorderedNMFED()
{
DoubleMatrix2D expectedU = new DenseDoubleMatrix2D(new double [] []
{
{
6.1201e-011, 0.99592
},
{
1.3886, 6.9024e-070
},
{
1.3886, 8.2856e-070
},
{
0.82488, 7.4263e-066
},
{
5.8999e-011, 0.87124
}
});
DoubleMatrix2D expectedV = new DenseDoubleMatrix2D(new double [] []
{
{
0.43087, 1.0265e-069
},
{
0.43463, 8.1702e-070
},
{
9.7187e-012, 0.73153
},
{
9.7187e-012, 0.73153
},
{
0.18182, 3.9668e-063
},
{
0.43463, 7.7853e-070
},
{
8.5895e-012, 0.5688
}
});
final NonnegativeMatrixFactorizationEDFactory factory = new NonnegativeMatrixFactorizationEDFactory();
factory.setOrdered(false);
checkIterative(expectedU, expectedV, factory);
}
@Test
public void testKMeans()
{
DoubleMatrix2D expectedU = new DenseDoubleMatrix2D(new double [] []
{
{
0.7380, 0
},
{
0, 0.6832
},
{
0, 0.6832
},
{
0.3481, 0.2575
},
{
0.5779, 0
}
});
DoubleMatrix2D expectedV = new DenseDoubleMatrix2D(new double [] []
{
{
0, 1
},
{
0, 1
},
{
1, 0
},
{
1, 0
},
{
1, 0
},
{
0, 1
},
{
1, 0
}
});
checkIterative(expectedU, expectedV, new KMeansMatrixFactorizationFactory());
}
@Test
public void testOrderedNMFED()
{
DoubleMatrix2D expectedU = new DenseDoubleMatrix2D(new double [] []
{
{
0.99592, 6.1201e-011
},
{
6.9024e-070, 1.3886
},
{
8.2856e-070, 1.3886
},
{
7.4263e-066, 0.82488
},
{
0.87124, 5.8999e-011
}
});
DoubleMatrix2D expectedV = new DenseDoubleMatrix2D(new double [] []
{
{
1.0265e-069, 0.43087
},
{
8.1702e-070, 0.43463
},
{
0.73153, 9.7187e-012
},
{
0.73153, 9.7187e-012
},
{
3.9668e-063, 0.18182
},
{
7.7853e-070, 0.43463
},
{
0.5688, 8.5895e-012
}
});
NonnegativeMatrixFactorizationEDFactory factory = new NonnegativeMatrixFactorizationEDFactory();
factory.setOrdered(true);
checkIterative(expectedU, expectedV, factory);
}
@Test
public void testNMFKL()
{
DoubleMatrix2D expectedU = new DenseDoubleMatrix2D(new double [] []
{
{
1.31E-11, 0.56085
},
{
0.34477, 1.34E-12
},
{
0.34477, 1.67E-12
},
{
0.31047, 2.89E-12
},
{
1.35E-11, 0.43915
}
});
DoubleMatrix2D expectedV = new DenseDoubleMatrix2D(new double [] []
{
{
1.7, 3.18E-12
},
{
1.42, 4.66E-12
},
{
5.76E-11, 1.39
},
{
5.76E-11, 1.39
},
{
1.0, 1.08E-11
},
{
1.42, 4.42E-12
},
{
5.97E-11, 1.0
}
});
checkIterative(expectedU, expectedV,
new NonnegativeMatrixFactorizationKLFactory());
}
@Test
public void testLNMF()
{
DoubleMatrix2D expectedU = new DenseDoubleMatrix2D(new double [] []
{
{
1.06E-193, 0.56085
},
{
0.34477, 5.97E-184
},
{
0.34477, 8.61E-184
},
{
0.31047, 3.73E-179
},
{
2.68E-192, 0.43915
}
});
DoubleMatrix2D expectedV = new DenseDoubleMatrix2D(new double [] []
{
{
1.3038, 4.47E-05
},
{
1.1916, 4.47E-05
},
{
5.48E-05, 1.179
},
{
5.48E-05, 1.179
},
{
1.0, 4.47E-05
},
{
1.1916, 4.47E-05
},
{
5.48E-05, 1.0
},
});
checkIterative(expectedU, expectedV,
new LocalNonnegativeMatrixFactorizationFactory());
}
private IMatrixFactorization checkIterative(DoubleMatrix2D expectedU,
DoubleMatrix2D expectedV, IterativeMatrixFactorizationFactory factory)
{
factory.setK(K);
factory.setMaxIterations(MAX_ITERATIONS);
factory.setStopThreshold(STOP_THRESHOLD);
factory.setSeedingFactory(ConstantSeedingStrategyFactory.INSTANCE);
IMatrixFactorization factorization = factory.factorize(A);
check(expectedU, expectedV, factorization);
return factorization;
}
private void check(DoubleMatrix2D expectedU, DoubleMatrix2D expectedV,
IMatrixFactorization factorization)
{
final DoubleMatrix2D u = factorization.getU();
MatrixAssertions.assertThat(u).as("U").isEquivalentTo(expectedU, DELTA);
MatrixAssertions.assertThat(factorization.getV()).as("V").isEquivalentTo(expectedV, DELTA);
}
/** Returns constant matrices of fixed size */
static class ConstantSeedingStrategyFactory implements ISeedingStrategyFactory
{
static ConstantSeedingStrategyFactory INSTANCE = new ConstantSeedingStrategyFactory();
private final double [][] constantU = new double [] []
{
{
0.84319, 0.6119
},
{
0.8062, 0.10298
},
{
0.85779, 0.15832
},
{
0.60975, 0.41365
},
{
0.56573, 0.56041
}
};
private final double [][] constantV = new double [] []
{
{
0.26868, 0.087422
},
{
0.78425, 0.93323
},
{
0.38787, 0.25938
},
{
0.030984, 0.20417
},
{
0.5855, 0.049208
},
{
0.55856, 0.60616
},
{
0.2007, 0.54635
}
};
public ISeedingStrategy createSeedingStrategy()
{
return new ISeedingStrategy()
{
public void seed(DoubleMatrix2D A, DoubleMatrix2D U, DoubleMatrix2D V)
{
U.assign(constantU);
V.assign(constantV);
}
};
}
}
}