1+ /*
2+ For more information, please see: http://software.sci.utah.edu
3+
4+ The MIT License
5+
6+ Copyright (c) 2015 Scientific Computing and Imaging Institute,
7+ University of Utah.
8+
9+ License for the specific language governing rights and limitations under
10+ Permission is hereby granted, free of charge, to any person obtaining a
11+ copy of this software and associated documentation files (the "Software"),
12+ to deal in the Software without restriction, including without limitation
13+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
14+ and/or sell copies of the Software, and to permit persons to whom the
15+ Software is furnished to do so, subject to the following conditions:
16+
17+ The above copyright notice and this permission notice shall be included
18+ in all copies or substantial portions of the Software.
19+
20+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26+ DEALINGS IN THE SOFTWARE.
27+ */
28+
29+ // ComputeSVD algorithm test.
30+ #include < gtest/gtest.h>
31+ #include < Core/Datatypes/DenseMatrix.h>
32+ #include < Core/Datatypes/MatrixComparison.h>
33+ #include < Testing/Utils/MatrixTestUtilities.h>
34+ #include < Core/Algorithms/Math/ComputeSVD.h>
35+ #include < Eigen/SVD>
36+
37+ using namespace SCIRun ::Core::Datatypes;
38+ using namespace SCIRun ::Core::Algorithms::Math;
39+ using namespace SCIRun ::TestUtils;
40+
41+ namespace
42+ {
43+ // Matrix for input.
44+ DenseMatrixHandle inputMatrix ()
45+ {
46+ // Hard coded for testing.
47+ int column1 [12 ] = {5 ,4 ,7 ,8 ,10 ,10 ,4 ,6 ,8 ,7 ,9 ,6 };
48+ int column2 [12 ] = {7 ,6 ,9 ,8 ,5 ,7 ,9 ,3 ,4 ,5 ,5 ,9 };
49+
50+ // Puts the columns into a matrix.
51+ DenseMatrixHandle inputM (boost::make_shared<DenseMatrix>(12 ,2 ));
52+ for (int i = 0 ; i < inputM->rows (); i++){
53+ (*inputM)(i,0 ) = column1[i];
54+ (*inputM)(i,1 ) = column2[i];
55+ }
56+ return inputM;
57+ }
58+ }
59+
60+ // Checks if the outputs are correct.
61+ // U,S,V: U: Left singular matrix, S: Singular values, V: Right singular matrix.
62+ TEST (ComputeSVDtest, checkOutputs)
63+ {
64+ ComputeSVDAlgo algo;
65+
66+ DenseMatrixHandle m1 (inputMatrix ());
67+ DenseMatrixHandle LeftSingularMatrix_U;
68+ DenseMatrixHandle SingularValues_S;
69+ DenseMatrixHandle RightSingularMatrix_V;
70+
71+ // Runs algorithm.
72+ algo.run (m1,LeftSingularMatrix_U,SingularValues_S,RightSingularMatrix_V);
73+
74+ // Testing if the results are null.
75+ ASSERT_NE (nullptr ,LeftSingularMatrix_U);
76+ ASSERT_NE (nullptr ,SingularValues_S);
77+ ASSERT_NE (nullptr ,RightSingularMatrix_V);
78+
79+ // Check the dimensions of the matrices that were created for output.
80+
81+ // Rows
82+ ASSERT_EQ (12 ,LeftSingularMatrix_U->rows ());
83+ ASSERT_EQ (2 ,SingularValues_S->rows ());
84+ ASSERT_EQ (2 ,RightSingularMatrix_V->rows ());
85+
86+ // Columns
87+ ASSERT_EQ (12 ,LeftSingularMatrix_U->cols ());
88+ ASSERT_EQ (1 ,SingularValues_S->cols ());
89+ ASSERT_EQ (2 ,RightSingularMatrix_V->cols ());
90+
91+ // Eigen does not create a diagonal matrix when it computes SVD, it just has a column with the singular values, so we must put it into a diagonal matrix to be able to do some matrix multiplication later.
92+ DenseMatrix sDiag = Eigen::MatrixXd::Constant (12 ,2 ,0 );
93+ sDiag .diagonal () = SingularValues_S->col (0 );
94+
95+ // Multiplying back together and comparing to the centered matrix. They should be equal to each other with some tolerance.
96+ DenseMatrix product = (*LeftSingularMatrix_U) * sDiag * (*RightSingularMatrix_V).transpose ();
97+
98+ auto expected = *inputMatrix ();
99+
100+ // Comparing each element in the matrices.
101+ for (int i = 0 ; i < product.rows (); ++i) {
102+ for (int j = 0 ; j < product.cols (); ++j)
103+ ASSERT_NEAR (expected (i,j), product (i,j), 1e-5 );
104+ }
105+
106+ }
107+
108+ // Tests for input with a dimension of zero.
109+ TEST (ComputeSVDtest, ThrowsForZeroDimensionInput)
110+ {
111+ ComputeSVDAlgo algo;
112+
113+ DenseMatrixHandle m1 (new DenseMatrix (5 , 0 ));
114+ DenseMatrixHandle m2 (new DenseMatrix (0 , 5 ));
115+ DenseMatrixHandle m3 (new DenseMatrix (0 , 0 ));
116+
117+ DenseMatrixHandle LeftSingularMatrix_U;
118+ DenseMatrixHandle SingularValues_S;
119+ DenseMatrixHandle RightSingularMatrix_V;
120+
121+ // Runs algorithm and expects an error.
122+ EXPECT_ANY_THROW (algo.run (m1,LeftSingularMatrix_U,SingularValues_S,RightSingularMatrix_V));
123+ EXPECT_ANY_THROW (algo.run (m2,LeftSingularMatrix_U,SingularValues_S,RightSingularMatrix_V));
124+ EXPECT_ANY_THROW (algo.run (m3,LeftSingularMatrix_U,SingularValues_S,RightSingularMatrix_V));
125+
126+ }
0 commit comments