11#include < Rcpp.h>
2+ #include < cmath>
3+ #include < algorithm>
4+
25using namespace Rcpp ;
36
4- // [[Rcpp::export]]
5- double stress (NumericMatrix x, NumericMatrix W, NumericMatrix D) {
6- double fct = 0 ;
7- int n = x.nrow ();
8- for (int i = 0 ; i < (n - 1 ); ++i) {
9- for (int j = (i + 1 ); j < n; ++j) {
10- double denom = sqrt ((x (i, 0 ) - x (j, 0 )) * (x (i, 0 ) - x (j, 0 )) +
11- (x (i, 1 ) - x (j, 1 )) * (x (i, 1 ) - x (j, 1 )));
12- fct += W (i, j) * (denom - D (i, j)) * (denom - D (i, j));
7+ namespace {
8+ inline double safe_inv_dist (double dx, double dy, double eps = 1e-10 ) {
9+ const double d2 = dx*dx + dy*dy;
10+ if (d2 <= eps) return 0.0 ;
11+ return 1.0 / std::sqrt (d2);
12+ }
13+
14+ inline double stress2d (const NumericMatrix& x,
15+ const NumericMatrix& W,
16+ const NumericMatrix& D) {
17+ double fct = 0.0 ;
18+ const int n = x.nrow ();
19+ for (int i = 0 ; i < n - 1 ; ++i) {
20+ const double xi0 = x (i, 0 ), xi1 = x (i, 1 );
21+ for (int j = i + 1 ; j < n; ++j) {
22+ const double dx = xi0 - x (j, 0 );
23+ const double dy = xi1 - x (j, 1 );
24+ const double dist = std::sqrt (dx*dx + dy*dy);
25+ const double r = dist - D (i, j);
26+ fct += W (i, j) * r * r;
27+ }
1328 }
29+ return fct;
1430 }
15- return fct;
31+ }
32+
33+ // [[Rcpp::export]]
34+ double stress (NumericMatrix x, NumericMatrix W, NumericMatrix D) {
35+ return stress2d (x, W, D);
1636}
1737
1838// [[Rcpp::export]]
1939NumericMatrix stress_major (NumericMatrix y, NumericMatrix W, NumericMatrix D,
2040 int iter, double tol) {
21- int n = y.nrow ();
22-
23- NumericMatrix x (clone (y));
41+ const int n = y.nrow ();
42+ NumericMatrix x = clone (y);
2443
2544 NumericVector wsum = rowSums (W);
2645
27- double stress_old = stress (x, W, D);
28- NumericMatrix xnew (n, 2 ); // out or in?
46+ double stress_old = stress2d (x, W, D);
47+ NumericMatrix xnew (n, 2 );
48+
2949 for (int k = 0 ; k < iter; ++k) {
30- std::fill (xnew.begin (), xnew.end (), 0 );
50+ std::fill (xnew.begin (), xnew.end (), 0.0 );
51+
3152 for (int i = 0 ; i < n; ++i) {
53+ const double xi0 = x (i, 0 ), xi1 = x (i, 1 );
54+ double acc0 = 0.0 , acc1 = 0.0 ;
55+
3256 for (int j = 0 ; j < n; ++j) {
33- if (i != j) {
34- double denom = sqrt ((x (i, 0 ) - x (j, 0 )) * (x (i, 0 ) - x (j, 0 )) +
35- (x (i, 1 ) - x (j, 1 )) * (x (i, 1 ) - x (j, 1 )));
36- if (denom > 0.00001 ) {
37- xnew (i, 0 ) +=
38- W (i, j) * (x (j, 0 ) + D (i, j) * (x (i, 0 ) - x (j, 0 )) / denom);
39- xnew (i, 1 ) +=
40- W (i, j) * (x (j, 1 ) + D (i, j) * (x (i, 1 ) - x (j, 1 )) / denom);
41- }
42- }
57+ if (i == j) continue ;
58+
59+ const double xj0 = x (j, 0 ), xj1 = x (j, 1 );
60+ const double dx = xi0 - xj0;
61+ const double dy = xi1 - xj1;
62+ const double invd = safe_inv_dist (dx, dy, 1e-10 );
63+ if (invd == 0.0 ) continue ;
64+
65+ const double wij = W (i, j);
66+ const double dij = D (i, j);
67+
68+ acc0 += wij * (xj0 + dij * dx * invd);
69+ acc1 += wij * (xj1 + dij * dy * invd);
4370 }
44- xnew (i, 0 ) = xnew (i, 0 ) / wsum[i];
45- xnew (i, 1 ) = xnew (i, 1 ) / wsum[i];
71+
72+ const double denom = wsum[i];
73+ xnew (i, 0 ) = acc0 / denom;
74+ xnew (i, 1 ) = acc1 / denom;
75+ }
76+
77+ const double stress_new = stress2d (xnew, W, D);
78+
79+
80+ if (stress_old <= 0.0 ) {
81+ x = clone (xnew);
82+ break ;
4683 }
47- double stress_new = stress (xnew, W, D);
48- double eps = (stress_old - stress_new) / stress_old;
4984
85+ const double eps = (stress_old - stress_new) / stress_old;
5086 if (eps <= tol) {
87+
88+ x = clone (xnew);
5189 break ;
5290 }
91+
5392 stress_old = stress_new;
5493 x = clone (xnew);
5594 }
95+
5696 return x;
5797}
5898
5999// [[Rcpp::export]]
60100NumericMatrix stress_radii (NumericMatrix y, NumericMatrix W, NumericMatrix D,
61101 NumericVector r, NumericVector tseq) {
62- int n = y.nrow ();
63- int m = tseq.length ();
102+ const int n = y.nrow ();
103+ const int m = tseq.size ();
64104
65- NumericMatrix x (n, 2 );
66- for (int i = 0 ; i < n; ++i) {
67- for (int d = 0 ; d < 2 ; ++d) {
68- x (i, d) = y (i, d);
69- }
70- }
105+ NumericMatrix x = clone (y);
71106
72107 NumericVector wsum (n);
73108 for (int i = 0 ; i < n; ++i) {
74- for ( int j = 0 ; j < n; ++j) {
75- wsum[i] += W (i, j);
76- }
109+ double s = 0.0 ;
110+ for ( int j = 0 ; j < n; ++j) s += W (i, j);
111+ wsum[i] = s;
77112 }
78113
79114 NumericVector rpow (n);
80115 for (int i = 0 ; i < n; ++i) {
81- rpow[i] = 1 / (r[i] * r[i]);
116+ const double ri = r[i];
117+ rpow[i] = 1.0 / (ri * ri);
82118 }
83119
120+ NumericMatrix xnew (n, 2 );
121+
84122 for (int s = 0 ; s < m; ++s) {
85- double t = tseq[s];
86- for (int k = 0 ; k < 1 ; ++k) {
87- NumericMatrix xnew (n, 2 ); // out or in?
88- for (int i = 0 ; i < n; ++i) {
89- for (int j = 0 ; j < n; ++j) {
90- if (i != j) {
91- double bij = sqrt ((x (i, 0 ) - x (j, 0 )) * (x (i, 0 ) - x (j, 0 )) +
92- (x (i, 1 ) - x (j, 1 )) * (x (i, 1 ) - x (j, 1 )));
93- double ai = sqrt (x (i, 0 ) * x (i, 0 ) + x (i, 1 ) * x (i, 1 ));
94- if (ai < 0.0001 ) {
95- ai = 0 ;
96- } else {
97- ai = 1 / ai;
98- }
99- if (bij < 0.0001 ) {
100- bij = 0 ;
101- } else {
102- bij = 1 / bij;
103- }
104- xnew (i, 0 ) += (1 - t) * W (i, j) *
105- (x (j, 0 ) + D (i, j) * (x (i, 0 ) - x (j, 0 )) * bij) +
106- t * rpow[i] * (r[i] * x (i, 0 ) * ai);
107- xnew (i, 1 ) += (1 - t) * W (i, j) *
108- (x (j, 1 ) + D (i, j) * (x (i, 1 ) - x (j, 1 )) * bij) +
109- t * rpow[i] * (r[i] * x (i, 1 ) * ai);
110- }
111- }
112- xnew (i, 0 ) = xnew (i, 0 ) / ((1 - t) * wsum[i] + t * rpow[i]);
113- xnew (i, 1 ) = xnew (i, 1 ) / ((1 - t) * wsum[i] + t * rpow[i]);
114- }
115- for (int i = 0 ; i < n; ++i) {
116- x (i, 0 ) = xnew (i, 0 );
117- x (i, 1 ) = xnew (i, 1 );
123+ const double t = tseq[s];
124+ std::fill (xnew.begin (), xnew.end (), 0.0 );
125+
126+ for (int i = 0 ; i < n; ++i) {
127+ const double xi0 = x (i, 0 ), xi1 = x (i, 1 );
128+
129+ const double inv_ai = safe_inv_dist (xi0, xi1, 1e-10 );
130+
131+ double acc0 = 0.0 , acc1 = 0.0 ;
132+
133+ for (int j = 0 ; j < n; ++j) {
134+ if (i == j) continue ;
135+
136+ const double xj0 = x (j, 0 ), xj1 = x (j, 1 );
137+ const double dx = xi0 - xj0;
138+ const double dy = xi1 - xj1;
139+ const double inv_bij = safe_inv_dist (dx, dy, 1e-10 );
140+
141+ const double wij = W (i, j);
142+ const double dij = D (i, j);
143+
144+ if (inv_bij != 0.0 ) {
145+ acc0 += (1.0 - t) * wij * (xj0 + dij * dx * inv_bij);
146+ acc1 += (1.0 - t) * wij * (xj1 + dij * dy * inv_bij);
147+ }
148+
149+ acc0 += t * rpow[i] * (r[i] * xi0 * inv_ai);
150+ acc1 += t * rpow[i] * (r[i] * xi1 * inv_ai);
118151 }
152+
153+ const double denom = (1.0 - t) * wsum[i] + t * rpow[i];
154+ xnew (i, 0 ) = acc0 / denom;
155+ xnew (i, 1 ) = acc1 / denom;
119156 }
157+
158+ x = clone (xnew);
120159 }
160+
121161 return x;
122162}
123163
124164// [[Rcpp::export]]
125165NumericMatrix stress_focus (NumericMatrix y, NumericMatrix W, NumericMatrix D,
126166 NumericMatrix Z, NumericVector tseq, int iter,
127167 double tol) {
128- int n = y.nrow ();
129- int m = tseq.length ();
168+ const int n = y.nrow ();
169+ const int m = tseq.size ();
130170
131- NumericMatrix x (n, 2 );
132- for (int i = 0 ; i < n; ++i) {
133- for (int d = 0 ; d < 2 ; ++d) {
134- x (i, d) = y (i, d);
135- }
136- }
171+ NumericMatrix x = clone (y);
137172
138- NumericVector wsum (n);
139- NumericVector zsum (n);
173+ NumericVector wsum (n), zsum (n);
140174 for (int i = 0 ; i < n; ++i) {
175+ double sw = 0.0 , sz = 0.0 ;
141176 for (int j = 0 ; j < n; ++j) {
142- wsum[i] += W (i, j);
143- zsum[i] += Z (i, j);
177+ sw += W (i, j);
178+ sz += Z (i, j);
144179 }
180+ wsum[i] = sw;
181+ zsum[i] = sz;
145182 }
146183
147- double stress_oldW = stress (x, W, D);
148- // double stress_oldZ = stress(x,Z,D );
149- double stress_old = stress_oldW;
184+ double stress_old = stress2d (x, W, D);
185+ NumericMatrix xnew (n, 2 );
186+
150187 for (int s = 0 ; s < m; ++s) {
151- double t = tseq[s];
188+ const double t = tseq[s];
152189
153190 for (int k = 0 ; k < iter; ++k) {
154- NumericMatrix xnew (n, 2 ); // out or in?
191+ std::fill (xnew.begin (), xnew.end (), 0.0 );
192+
155193 for (int i = 0 ; i < n; ++i) {
194+ const double xi0 = x (i, 0 ), xi1 = x (i, 1 );
195+ double acc0 = 0.0 , acc1 = 0.0 ;
196+
156197 for (int j = 0 ; j < n; ++j) {
157- if (i != j) {
158- double denom = sqrt (( x (i, 0 ) - x (j, 0 )) * ( x (i, 0 ) - x (j, 0 )) +
159- ( x (i, 1 ) - x ( j, 1 )) * ( x (i, 1 ) - x (j, 1 )) );
160- if (denom > 0.00001 ) {
161- denom = 1 / denom ;
162- } else {
163- denom = 0 ;
164- }
165- xnew (i, 0 ) += (( 1 - t) * W (i, j) + t * Z (i, j)) *
166- ( x (j, 0 ) + D (i, j) * ( x (i, 0 ) - x (j, 0 )) * denom);
167- xnew (i, 1 ) += (( 1 - t) * W ( i, j) + t * Z (i, j)) *
168- ( x (j, 1 ) + D (i, j) * ( x (i, 1 ) - x (j, 1 )) * denom );
169- }
198+ if (i == j) continue ;
199+
200+ const double xj0 = x ( j, 0 ), xj1 = x (j, 1 );
201+ const double dx = xi0 - xj0;
202+ const double dy = xi1 - xj1 ;
203+ const double invd = safe_inv_dist (dx, dy, 1e-10 );
204+
205+ const double wij = ( 1.0 - t) * W (i, j) + t * Z (i, j);
206+ if (invd == 0.0 ) continue ;
207+
208+ const double dij = D ( i, j);
209+ acc0 += wij * (xj0 + dij * dx * invd );
210+ acc1 += wij * (xj1 + dij * dy * invd);
170211 }
171- xnew (i, 0 ) = xnew (i, 0 ) / ((1 - t) * wsum[i] + t * zsum[i]);
172- xnew (i, 1 ) = xnew (i, 1 ) / ((1 - t) * wsum[i] + t * zsum[i]);
173- }
174- double stress_newW = stress (xnew, W, D);
175- double stress_newZ = stress (xnew, Z, D);
176- double stress_new = (1 - t) * stress_newW + t * stress_newZ;
177212
178- for (int i = 0 ; i < n; ++i) {
179- x (i, 0 ) = xnew (i, 0 );
180- x (i, 1 ) = xnew (i, 1 );
181- }
182- double eps = (stress_old - stress_new) / stress_old;
183- if (eps <= tol) {
184- break ;
213+ const double denom = (1.0 - t) * wsum[i] + t * zsum[i];
214+ xnew (i, 0 ) = acc0 / denom;
215+ xnew (i, 1 ) = acc1 / denom;
185216 }
217+
218+ const double stress_newW = stress2d (xnew, W, D);
219+ const double stress_newZ = stress2d (xnew, Z, D);
220+ const double stress_new = (1.0 - t) * stress_newW + t * stress_newZ;
221+
222+ x = clone (xnew);
223+
224+ if (stress_old <= 0.0 ) break ;
225+ const double eps = (stress_old - stress_new) / stress_old;
226+ if (eps <= tol) break ;
227+
186228 stress_old = stress_new;
187229 }
188230 }
231+
189232 return x;
190- }
233+ }
0 commit comments