@@ -52,22 +52,14 @@ double Cosine::operator()(const arma::sp_mat& A, const arma::sp_mat& B) const {
5252-----------------------------*/
5353
5454double JSD::operator ()(const arma::sp_mat& A, const arma::sp_mat& B) const {
55- arma::mat a = arma::conv_to<arma::mat>::from (A.col (0 ));
56- arma::mat b = arma::conv_to<arma::mat>::from (B.col (0 ));
57- arma::mat m = 0.5 * (a + b );
55+ arma::mat denseA = arma::conv_to<arma::mat>::from (A.col (0 ) + eps );
56+ arma::mat denseB = arma::conv_to<arma::mat>::from (B.col (0 ) + eps );
57+ arma::mat M = 0.5 * (denseA + denseB );
5858
59- // Adding small epsilon for zero's
60- arma::mat ai = a + eps;
61- arma::mat bi = b + eps;
62- arma::mat mi = m + eps;
59+ double num = 0.5 * arma::accu (A % (arma::log (denseA / M)));
60+ double denum = 0.5 * arma::accu (B % (arma::log (denseB / M)));
6361
64- arma::vec num = 0.5 * (ai % arma::log (ai / mi));
65- arma::vec denum = 0.5 * (bi % arma::log (bi / mi));
66-
67- double jsd = arma::accu (num + denum);
68-
69- if (jsd == 0.0 ) return 0.0 ;
70- return jsd;
62+ return num + denum;
7163};
7264
7365
@@ -76,23 +68,29 @@ double JSD::operator()(const arma::sp_mat& A, const arma::sp_mat& B) const {
7668-----------------------------*/
7769
7870double Canberra::operator ()(const arma::sp_mat& A, const arma::sp_mat& B) const {
71+ arma::sp_mat num = arma::abs (A - B);
72+ arma::sp_mat denum = arma::abs (A + B);
73+
7974 double sum = 0.0 ;
8075 int count = 0 ;
81- arma::sp_mat C = A + B;
82-
83- for (auto it = C.begin (); it != C.end (); ++it) {
84- int i = it.row ();
85- int j = it.col ();
86- double a_val = A (i, j);
87- double b_val = B (i, j);
88- double num = std::abs (a_val - b_val);
89- double denum = std::abs (a_val) + std::abs (b_val);
90- if (denum > 0.0 ) {
91- sum += num / denum;
92- count++;
76+
77+ auto itNum = num.begin ();
78+ auto itDen = denum.begin ();
79+
80+ while (itDen != denum.end () && itNum != num.end ()) {
81+ if (itDen.row () == itNum.row ()) {
82+ if (*itDen > 0.0 ) {
83+ sum += (*itNum) / (*itDen);
84+ ++count;
85+ }
86+ ++itDen;
87+ ++itNum;
88+ } else if (itDen.row () < itNum.row ()) {
89+ ++itDen;
90+ } else {
91+ ++itNum;
9392 }
9493 }
95- if (count == 0 ) return std::numeric_limits<double >::quiet_NaN ();
9694 if (sum == 0.0 || count == 0 ) return 0.0 ;
9795 return sum / count;
9896};
@@ -102,20 +100,17 @@ double Canberra::operator()(const arma::sp_mat& A, const arma::sp_mat& B) const
102100-----------------------------*/
103101
104102double Aitchison::operator ()(const arma::sp_mat& A, const arma::sp_mat& B) const {
105- arma::mat a = arma::conv_to<arma::mat>::from (A.col (0 ));
106- arma::mat b = arma::conv_to<arma::mat>::from (B.col (0 ));
107-
108- // Adding small epsilon for zero's
109- arma::mat ai = a + eps;
110- arma::mat bi = b + eps;
111-
112- // Compute geometric means
113- double ga = std::exp (arma::as_scalar (arma::mean (arma::log (ai))));
114- double gb = std::exp (arma::as_scalar (arma::mean (arma::log (bi))));
115-
103+ // Convert to dense vector
104+ arma::mat denseA = arma::conv_to<arma::mat>::from (A.col (0 ) + eps);
105+ arma::mat denseB = arma::conv_to<arma::mat>::from (B.col (0 ) + eps);
106+
107+ // Geometric mean
108+ double ga = std::exp (arma::as_scalar (arma::mean (arma::log (denseA))));
109+ double gb = std::exp (arma::as_scalar (arma::mean (arma::log (denseB))));
110+
116111 // Compute clr transforms
117- arma::vec clr_a = arma::log (ai / ga);
118- arma::vec clr_b = arma::log (bi / gb);
112+ arma::mat clr_a = arma::log (denseA / ga);
113+ arma::mat clr_b = arma::log (denseB / gb);
119114
120115 return arma::norm (clr_a - clr_b, 2 );
121116};
0 commit comments