Skip to content

Commit cb5f40c

Browse files
committed
improved jsd, canberra and aitchison, optimised cpp complilation
1 parent 2000733 commit cb5f40c

3 files changed

Lines changed: 39 additions & 42 deletions

File tree

src/Makevars

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1+
CXX_STD = CXX11
2+
PKG_CXXFLAGS = -O3 -march=native -mtune=native -fPIC
13
PKG_LIBS = `${R_HOME}/bin/Rscript -e "RcppParallel::RcppParallelLibs()"` $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)

src/Makevars.win

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
PKG_CXXFLAGS += -DRCPP_PARALLEL_USE_TBB=1
2-
1+
CXX_STD = CXX11
2+
PKG_CXXFLAGS = -O3 -Wall -DRCPP_PARALLEL_USE_TBB=1
33
PKG_LIBS += $(shell "${R_HOME}/bin${R_ARCH_BIN}/Rscript.exe" \
44
-e "RcppParallel::RcppParallelLibs()") $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)

src/distances.cpp

Lines changed: 35 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -52,22 +52,14 @@ double Cosine::operator()(const arma::sp_mat& A, const arma::sp_mat& B) const {
5252
-----------------------------*/
5353

5454
double 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

7870
double 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

104102
double 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

Comments
 (0)