2727 */
2828
2929#include < gtest/gtest.h>
30-
3130#include < Core/Datatypes/DenseMatrix.h>
3231#include < Core/Datatypes/MatrixComparison.h>
3332#include < Testing/Utils/MatrixTestUtilities.h>
3433#include < Core/Algorithms/Math/ComputePCA.h>
34+ #include < Eigen/SVD>
3535
3636using namespace SCIRun ::Core::Datatypes;
3737using namespace SCIRun ::Core::Algorithms::Math;
3838using namespace SCIRun ::TestUtils;
3939
40-
4140namespace
4241{
43- // Matrix for input
42+ // Matrix for input.
4443 DenseMatrixHandle inputMatrix ()
4544 {
45+ // Hard coded for testing.
4646 int column1 [12 ] = {5 ,4 ,7 ,8 ,10 ,10 ,4 ,6 ,8 ,7 ,9 ,6 };
4747 int column2 [12 ] = {7 ,6 ,9 ,8 ,5 ,7 ,9 ,3 ,4 ,5 ,5 ,9 };
4848
49+ // Puts the columns into a matrix.
4950 DenseMatrixHandle inputM (boost::make_shared<DenseMatrix>(12 ,2 ));
5051 for (int i = 0 ; i < inputM->rows (); i++){
5152 (*inputM)(i,0 ) = column1[i];
@@ -54,34 +55,24 @@ namespace
5455 return inputM;
5556 }
5657
57- // A after it is centered
58+ // The input matrix after centering.
5859 DenseMatrixHandle centeredInputMatrix ()
5960 {
60-
61+ // Hard coded for testing.
6162 double centeredColumn1 [12 ] = {-2.0 ,-3.0 ,-0.0 ,1.0 ,3.0 ,3.0 ,-3.0 ,-1.0 ,1.0 ,-0.0 ,2.0 ,-1.0 };
6263 double centeredColumn2 [12 ] = {0.583333 ,-0.416667 ,2.583333 ,1.583333 ,-1.416667 ,0.583333 ,2.583333 ,-3.416667 ,-2.416667 ,-1.416667 ,-1.416667 ,2.583333 };
6364
65+ // Puts the columns into a matrix.
6466 DenseMatrixHandle centeredM (boost::make_shared<DenseMatrix>(12 ,2 ));
6567 for (int i = 0 ; i < centeredM->rows (); i++){
6668 (*centeredM)(i,0 ) = centeredColumn1[i];
6769 (*centeredM)(i,1 ) = centeredColumn2[i];
6870 }
6971 return centeredM;
70-
7172 }
72-
73- // Outputs: U,S,V
74- DenseMatrixHandle outputU ()
75- {}
76- DenseMatrixHandle outputS ()
77- {}
78- DenseMatrixHandle outputV ()
79- {}
80-
8173}
8274
83-
84-
75+ // Checks if the algorithm centers the data correctly.
8576TEST (ComputePCAtest, CenterData)
8677{
8778 ComputePCAAlgo algo;
@@ -92,33 +83,77 @@ TEST(ComputePCAtest, CenterData)
9283
9384 auto expected = *centeredInputMatrix ();
9485
86+ // Checking every element with a tolerance of 1e-5.
9587 for (int i = 0 ; i < centered.rows (); ++i) {
9688 for (int j = 0 ; j < centered.cols (); ++j)
97- EXPECT_NEAR (expected (i,j), centered (i,j), 1e-5 );
89+ ASSERT_NEAR (expected (i,j), centered (i,j), 1e-5 );
90+ }
91+ }
92+
93+ // Checks if the outputs are correct.
94+ // U,S,V: U: Left principal matrix, S: principal values, V: Right principal matrix.
95+ TEST (ComputePCAtest, checkOutputs)
96+ {
97+ ComputePCAAlgo algo;
98+
99+ DenseMatrixHandle m1 (inputMatrix ());
100+ DenseMatrixHandle LeftPrinMat_U;
101+ DenseMatrixHandle PrinVals_S;
102+ DenseMatrixHandle RightPrinMat_V;
103+
104+ // Runs algorithm.
105+ algo.run (m1,LeftPrinMat_U,PrinVals_S,RightPrinMat_V);
106+
107+ // Testing if the results are null.
108+ ASSERT_NE (nullptr ,LeftPrinMat_U);
109+ ASSERT_NE (nullptr ,PrinVals_S);
110+ ASSERT_NE (nullptr ,RightPrinMat_V);
111+
112+ // Check the dimensions of the matrices that were created for output.
113+
114+ // Rows
115+ ASSERT_EQ (12 ,LeftPrinMat_U->rows ());
116+ ASSERT_EQ (2 ,PrinVals_S->rows ());
117+ ASSERT_EQ (2 ,RightPrinMat_V->rows ());
118+
119+ // Columns
120+ ASSERT_EQ (12 ,LeftPrinMat_U->cols ());
121+ ASSERT_EQ (1 ,PrinVals_S->cols ());
122+ ASSERT_EQ (2 ,RightPrinMat_V->cols ());
123+
124+ // Eigen does not create a diagonal matrix when it computes SVD, it just has a column with the principal values, so we must put it into a diagonal matrix to be able to do some matrix multiplication later.
125+ DenseMatrix sDiag = Eigen::MatrixXd::Constant (12 ,2 ,0 );
126+ sDiag .diagonal () = PrinVals_S->col (0 );
127+
128+ // Multiplying back together and comparing to the centered matrix. They should be equal to each other with some tolerance.
129+ auto product = (*LeftPrinMat_U) * sDiag * (*RightPrinMat_V).transpose ();
130+
131+ auto expected = *centeredInputMatrix ();
132+
133+ // Comparing each element in the matrices.
134+ for (int i = 0 ; i < product.rows (); ++i) {
135+ for (int j = 0 ; j < product.cols (); ++j)
136+ ASSERT_NEAR (expected (i,j), product (i,j), 1e-5 );
98137 }
138+
99139}
100140
101- // TEST(ComputePCAtest, output1)
102- // {
103- // ComputePCAAlgorithm algo;
104- //
105- // DenseMatrixHandle m1(testMatrix());
106- // ComputePCAAlgorithm::Outputs result = algo.run(ComputePCAAlgorithm::Inputs(m1),ComputePCAAlgorithm);
107- //
108- // }
109- //
110- // TEST(ComputePCAtest, output2)
111- // {
112- // ComputePCAAlgorithm algo;
113- //
114- // DenseMatrixHandle m1(testMatrix());
115- //
116- // }
117- //
118- // TEST(ComputePCAtest, output3)
119- // {
120- // ComputePCAAlgorithm algo;
121- //
122- // DenseMatrixHandle m1(testMatrix());
123- //
124- // }
141+ // Tests for input with a dimension of zero.
142+ TEST (ComputePCAtest, ThrowsForZeroDimensionInput)
143+ {
144+ ComputePCAAlgo algo;
145+
146+ DenseMatrixHandle m1 (new DenseMatrix (5 , 0 ));
147+ DenseMatrixHandle m2 (new DenseMatrix (0 , 5 ));
148+ DenseMatrixHandle m3 (new DenseMatrix (0 , 0 ));
149+
150+ DenseMatrixHandle LeftPrinMat_U;
151+ DenseMatrixHandle PrinVals_S;
152+ DenseMatrixHandle RightPrinMat_V;
153+
154+ // Runs algorithm and expects an error.
155+ EXPECT_ANY_THROW (algo.run (m1,LeftPrinMat_U,PrinVals_S,RightPrinMat_V));
156+ EXPECT_ANY_THROW (algo.run (m2,LeftPrinMat_U,PrinVals_S,RightPrinMat_V));
157+ EXPECT_ANY_THROW (algo.run (m3,LeftPrinMat_U,PrinVals_S,RightPrinMat_V));
158+
159+ }
0 commit comments