| File: | src/ten/qglox.c |
| Location: | line 498, column 3 |
| Description: | Value stored to 'dsum' is never read |
| 1 | /* |
| 2 | Teem: Tools to process and visualize scientific data and images . |
| 3 | Copyright (C) 2013, 2012, 2011, 2010, 2009 University of Chicago |
| 4 | Copyright (C) 2008, 2007, 2006, 2005 Gordon Kindlmann |
| 5 | Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998 University of Utah |
| 6 | |
| 7 | This library is free software; you can redistribute it and/or |
| 8 | modify it under the terms of the GNU Lesser General Public License |
| 9 | (LGPL) as published by the Free Software Foundation; either |
| 10 | version 2.1 of the License, or (at your option) any later version. |
| 11 | The terms of redistributing and/or modifying this software also |
| 12 | include exceptions to the LGPL that facilitate static linking. |
| 13 | |
| 14 | This library is distributed in the hope that it will be useful, |
| 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 17 | Lesser General Public License for more details. |
| 18 | |
| 19 | You should have received a copy of the GNU Lesser General Public License |
| 20 | along with this library; if not, write to Free Software Foundation, Inc., |
| 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| 22 | */ |
| 23 | |
| 24 | |
| 25 | #include "ten.h" |
| 26 | #include "privateTen.h" |
| 27 | |
| 28 | /* |
| 29 | ** computes (r1 - r0)/(log(r1) - log(r0)) |
| 30 | */ |
| 31 | double |
| 32 | _tenQGL_blah(double rr0, double rr1) { |
| 33 | double bb, ret; |
| 34 | |
| 35 | if (rr1 > rr0) { |
| 36 | /* the bb calculation below could blow up, so we recurse |
| 37 | with flipped order */ |
| 38 | ret = _tenQGL_blah(rr1, rr0); |
| 39 | } else { |
| 40 | /* rr1 <= rr0 --> rr1/rr0 <= 1 --> rr1/rr0 - 1 <= 0 --> bb <= 0 */ |
| 41 | /* and rr1 >= 0 --> rr1/rr0 >= 0 --> rr1/rr0 - 1 >= -1 --> bb >= -1 */ |
| 42 | bb = rr0 ? (rr1/rr0 - 1) : 0; |
| 43 | if (bb > -0.0001) { |
| 44 | ret = rr0*(1 + bb*(0.5001249976477329 |
| 45 | - bb*(7.0/6 + bb*(1.0/6 - bb/720.0)))); |
| 46 | } else { |
| 47 | /* had trouble finding a high-quality approximation for b near -1 */ |
| 48 | bb = AIR_MAX(bb, -1 + 100*FLT_EPSILON)((bb) > (-1 + 100*1.19209290e-7F) ? (bb) : (-1 + 100*1.19209290e-7F )); |
| 49 | ret = rr0*bb/log(bb + 1); |
| 50 | } |
| 51 | } |
| 52 | return ret; |
| 53 | } |
| 54 | |
| 55 | #define rr0 (RThZA[0]) |
| 56 | #define rr1 (RThZB[0]) |
| 57 | #define rr (oRThZ[0]) |
| 58 | #define th0 (RThZA[1]) |
| 59 | #define th1 (RThZB[1]) |
| 60 | #define th (oRThZ[1]) |
| 61 | #define zz0 (RThZA[2]) |
| 62 | #define zz1 (RThZB[2]) |
| 63 | #define zz (oRThZ[2]) |
| 64 | |
| 65 | void |
| 66 | tenQGLInterpTwoEvalK(double oeval[3], |
| 67 | const double evalA[3], const double evalB[3], |
| 68 | const double tt) { |
| 69 | double RThZA[3], RThZB[3], oRThZ[3], bb; |
| 70 | |
| 71 | tenTripleConvertSingle_d(RThZA, tenTripleTypeRThetaZ, |
| 72 | evalA, tenTripleTypeEigenvalue); |
| 73 | tenTripleConvertSingle_d(RThZB, tenTripleTypeRThetaZ, |
| 74 | evalB, tenTripleTypeEigenvalue); |
| 75 | if (rr1 > rr0) { |
| 76 | /* the bb calculation below could blow up, so we recurse |
| 77 | with flipped order */ |
| 78 | tenQGLInterpTwoEvalK(oeval, evalB, evalA, 1-tt); |
| 79 | } else { |
| 80 | rr = AIR_LERP(tt, rr0, rr1)((tt)*((rr1) - (rr0)) + (rr0)); |
| 81 | zz = AIR_LERP(tt, zz0, zz1)((tt)*((zz1) - (zz0)) + (zz0)); |
| 82 | bb = rr0 ? (rr1/rr0 - 1) : 0; |
| 83 | /* bb can't be positive, because rr1 <= rr0 enforced above, so below |
| 84 | is really test for -0.001 < bb <= 0 */ |
| 85 | if (bb > -0.0001) { |
| 86 | double dth; |
| 87 | dth = th1 - th0; |
| 88 | /* rr0 and rr1 are similar, use stable approximation */ |
| 89 | th = th0 + tt*(dth |
| 90 | + (0.5 - tt/2)*dth*bb |
| 91 | + (-1.0/12 - tt/4 + tt*tt/3)*dth*bb*bb |
| 92 | + (1.0/24 + tt/24 + tt*tt/6 - tt*tt*tt/4)*dth*bb*bb*bb); |
| 93 | } else { |
| 94 | /* use original formula */ |
| 95 | /* have to clamp value of b so that log() values don't explode */ |
| 96 | bb = AIR_MAX(bb, -1 + 100*FLT_EPSILON)((bb) > (-1 + 100*1.19209290e-7F) ? (bb) : (-1 + 100*1.19209290e-7F )); |
| 97 | th = th0 + (th1 - th0)*log(1 + bb*tt)/log(1 + bb); |
| 98 | } |
| 99 | tenTripleConvertSingle_d(oeval, tenTripleTypeEigenvalue, |
| 100 | oRThZ, tenTripleTypeRThetaZ); |
| 101 | /* |
| 102 | fprintf(stderr, "%s: (b = %g) %g %g %g <-- %g %g %g\n", "blah", bb, |
| 103 | oeval[0], oeval[1], oeval[2], |
| 104 | oRThZ[0], oRThZ[1], oRThZ[2]); |
| 105 | */ |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | double |
| 110 | _tenQGL_Kdist(const double RThZA[3], const double RThZB[3]) { |
| 111 | double dr, dth, dz, bl, dist; |
| 112 | |
| 113 | dr = rr1 - rr0; |
| 114 | bl = _tenQGL_blah(rr0, rr1); |
| 115 | dth = th1 - th0; |
| 116 | dz = zz1 - zz0; |
| 117 | dist = sqrt(dr*dr + bl*bl*dth*dth + dz*dz); |
| 118 | return dist; |
| 119 | } |
| 120 | |
| 121 | void |
| 122 | _tenQGL_Klog(double klog[3], |
| 123 | const double RThZA[3], const double RThZB[3]) { |
| 124 | double dr, bl, dth, dz; |
| 125 | |
| 126 | dr = rr1 - rr0; |
| 127 | bl = _tenQGL_blah(rr0, rr1); |
| 128 | dth = th1 - th0; |
| 129 | dz = zz1 - zz0; |
| 130 | ELL_3V_SET(klog, dr, bl*dth, dz)((klog)[0] = (dr), (klog)[1] = (bl*dth), (klog)[2] = (dz)); |
| 131 | return; |
| 132 | } |
| 133 | |
| 134 | void |
| 135 | _tenQGL_Kexp(double RThZB[3], |
| 136 | const double RThZA[3], const double klog[3]) { |
| 137 | double bl; |
| 138 | |
| 139 | rr1 = rr0 + klog[0]; |
| 140 | bl = _tenQGL_blah(rr0, rr1); |
| 141 | th1 = th0 + (bl ? klog[1]/bl : 0); |
| 142 | zz1 = zz0 + klog[2]; |
| 143 | return; |
| 144 | } |
| 145 | |
| 146 | #undef rr0 |
| 147 | #undef rr1 |
| 148 | #undef rr |
| 149 | #undef th0 |
| 150 | #undef th1 |
| 151 | #undef th |
| 152 | #undef zz0 |
| 153 | #undef zz1 |
| 154 | #undef zz |
| 155 | |
| 156 | /* |
| 157 | ** stable computation of (ph1 - ph0)/(log(tan(ph1/2)) - log(tan(ph0/2))) |
| 158 | */ |
| 159 | double |
| 160 | _tenQGL_fooo(double ph1, double ph0) { |
| 161 | double ret; |
| 162 | |
| 163 | if (ph0 > ph1) { |
| 164 | ret = _tenQGL_fooo(ph0, ph1); |
| 165 | } else if (0 == ph0/2) { |
| 166 | ret = 0; |
| 167 | } else { |
| 168 | /* ph1 >= ph0 > 0 */ |
| 169 | if (ph1 - ph0 < 0.0001) { |
| 170 | double dph, ss, cc; |
| 171 | dph = ph1 - ph0; |
| 172 | ss = sin(ph1); |
| 173 | cc = cos(ph1); |
| 174 | ret = (ss |
| 175 | + cc*dph/2 |
| 176 | + ((cos(2*ph1) - 3)/ss)*dph*dph/24 |
| 177 | + (cc/(ss*ss))*dph*dph*dph/24); |
| 178 | } else { |
| 179 | ret = (ph1 - ph0)/(log(tan(ph1/2)) - log(tan(ph0/2))); |
| 180 | } |
| 181 | } |
| 182 | return ret; |
| 183 | } |
| 184 | |
| 185 | #define rr0 (RThPhA[0]) |
| 186 | #define rr1 (RThPhB[0]) |
| 187 | #define rr (oRThPh[0]) |
| 188 | #define th0 (RThPhA[1]) |
| 189 | #define th1 (RThPhB[1]) |
| 190 | #define th (oRThPh[1]) |
| 191 | #define ph0 (RThPhA[2]) |
| 192 | #define ph1 (RThPhB[2]) |
| 193 | #define ph (oRThPh[2]) |
| 194 | |
| 195 | void |
| 196 | _tenQGL_Rlog(double rlog[3], |
| 197 | const double RThPhA[3], const double RThPhB[3]) { |
| 198 | double dr, dth, dph, bl, fo; |
| 199 | |
| 200 | dr = rr1 - rr0; |
| 201 | dth = th1 - th0; |
| 202 | dph = ph1 - ph0; |
| 203 | bl = _tenQGL_blah(rr0, rr1); |
| 204 | fo = _tenQGL_fooo(ph0, ph1); |
| 205 | /* rlog[0] rlog[1] rlog[2] */ |
| 206 | ELL_3V_SET(rlog, dr, bl*dth*fo, dph*bl)((rlog)[0] = (dr), (rlog)[1] = (bl*dth*fo), (rlog)[2] = (dph* bl)); |
| 207 | } |
| 208 | |
| 209 | void |
| 210 | _tenQGL_Rexp(double RThPhB[3], |
| 211 | const double RThPhA[3], const double rlog[3]) { |
| 212 | double bl, fo; |
| 213 | |
| 214 | rr1 = rr0 + rlog[0]; |
| 215 | bl = _tenQGL_blah(rr0, rr1); |
| 216 | ph1 = ph0 + (bl ? rlog[2]/bl : 0); |
| 217 | fo = _tenQGL_fooo(ph0, ph1); |
| 218 | th1 = th0 + (bl*fo ? rlog[1]/(bl*fo) : 0); |
| 219 | return; |
| 220 | } |
| 221 | |
| 222 | /* unlike with the K stuff, with the R stuff I seemed to have more luck |
| 223 | implementing pair-wise interpolation in terms of log and exp |
| 224 | */ |
| 225 | void |
| 226 | tenQGLInterpTwoEvalR(double oeval[3], |
| 227 | const double evalA[3], const double evalB[3], |
| 228 | const double tt) { |
| 229 | double RThPhA[3], RThPhB[3], rlog[3], oRThPh[3]; |
| 230 | |
| 231 | tenTripleConvertSingle_d(RThPhA, tenTripleTypeRThetaPhi, |
| 232 | evalA, tenTripleTypeEigenvalue); |
| 233 | tenTripleConvertSingle_d(RThPhB, tenTripleTypeRThetaPhi, |
| 234 | evalB, tenTripleTypeEigenvalue); |
| 235 | _tenQGL_Rlog(rlog, RThPhA, RThPhB); |
| 236 | ELL_3V_SCALE(rlog, tt, rlog)((rlog)[0] = (tt)*(rlog)[0], (rlog)[1] = (tt)*(rlog)[1], (rlog )[2] = (tt)*(rlog)[2]); |
| 237 | _tenQGL_Rexp(oRThPh, RThPhA, rlog); |
| 238 | tenTripleConvertSingle_d(oeval, tenTripleTypeEigenvalue, |
| 239 | oRThPh, tenTripleTypeRThetaPhi); |
| 240 | return; |
| 241 | } |
| 242 | |
| 243 | double |
| 244 | _tenQGL_Rdist(const double RThPhA[3], const double RThPhB[3]) { |
| 245 | double dr, dth, dph, bl, fo; |
| 246 | |
| 247 | dr = rr1 - rr0; |
| 248 | dth = th1 - th0; |
| 249 | dph = ph1 - ph0; |
| 250 | bl = _tenQGL_blah(rr0, rr1); |
| 251 | fo = _tenQGL_fooo(ph0, ph1); |
| 252 | return sqrt(dr*dr + bl*bl*(dth*dth*fo*fo + dph*dph)); |
| 253 | } |
| 254 | |
| 255 | #undef rr0 |
| 256 | #undef rr1 |
| 257 | #undef rr |
| 258 | #undef th0 |
| 259 | #undef th1 |
| 260 | #undef th |
| 261 | #undef ph0 |
| 262 | #undef ph1 |
| 263 | #undef ph |
| 264 | |
| 265 | /* returns the index into unitq[] of the quaternion that led to the |
| 266 | right alignment. If it was already aligned, this will be 0, |
| 267 | because unitq[0] is the identity quaternion */ |
| 268 | int |
| 269 | _tenQGL_q_align(double qOut[4], const double qRef[4], const double qIn[4]) { |
| 270 | unsigned int ii, maxDotIdx; |
| 271 | double unitq[8][4] = {{+1, 0, 0, 0}, |
| 272 | {-1, 0, 0, 0}, |
| 273 | {0, +1, 0, 0}, |
| 274 | {0, -1, 0, 0}, |
| 275 | {0, 0, +1, 0}, |
| 276 | {0, 0, -1, 0}, |
| 277 | {0, 0, 0, +1}, |
| 278 | {0, 0, 0, -1}}; |
| 279 | double dot[8], qInMul[8][4], maxDot; |
| 280 | |
| 281 | for (ii=0; ii<8; ii++) { |
| 282 | ell_q_mul_d(qInMul[ii], qIn, unitq[ii]); |
| 283 | dot[ii] = ELL_4V_DOT(qRef, qInMul[ii])((qRef)[0]*(qInMul[ii])[0] + (qRef)[1]*(qInMul[ii])[1] + (qRef )[2]*(qInMul[ii])[2] + (qRef)[3]*(qInMul[ii])[3]); |
| 284 | } |
| 285 | maxDotIdx = 0; |
| 286 | maxDot = dot[maxDotIdx]; |
| 287 | for (ii=1; ii<8; ii++) { |
| 288 | if (dot[ii] > maxDot) { |
| 289 | maxDotIdx = ii; |
| 290 | maxDot = dot[maxDotIdx]; |
| 291 | } |
| 292 | } |
| 293 | ELL_4V_COPY(qOut, qInMul[maxDotIdx])((qOut)[0] = (qInMul[maxDotIdx])[0], (qOut)[1] = (qInMul[maxDotIdx ])[1], (qOut)[2] = (qInMul[maxDotIdx])[2], (qOut)[3] = (qInMul [maxDotIdx])[3]); |
| 294 | return maxDotIdx; |
| 295 | } |
| 296 | |
| 297 | void |
| 298 | tenQGLInterpTwoEvec(double oevec[9], |
| 299 | const double evecA[9], const double evecB[9], |
| 300 | double tt) { |
| 301 | double rotA[9], rotB[9], orot[9], |
| 302 | oq[4], qA[4], qB[4], _qB[4], qdiv[4], angle, axis[3], qq[4]; |
| 303 | |
| 304 | ELL_3M_TRANSPOSE(rotA, evecA)((rotA)[0] = (evecA)[0], (rotA)[1] = (evecA)[3], (rotA)[2] = ( evecA)[6], (rotA)[3] = (evecA)[1], (rotA)[4] = (evecA)[4], (rotA )[5] = (evecA)[7], (rotA)[6] = (evecA)[2], (rotA)[7] = (evecA )[5], (rotA)[8] = (evecA)[8]); |
| 305 | ELL_3M_TRANSPOSE(rotB, evecB)((rotB)[0] = (evecB)[0], (rotB)[1] = (evecB)[3], (rotB)[2] = ( evecB)[6], (rotB)[3] = (evecB)[1], (rotB)[4] = (evecB)[4], (rotB )[5] = (evecB)[7], (rotB)[6] = (evecB)[2], (rotB)[7] = (evecB )[5], (rotB)[8] = (evecB)[8]); |
| 306 | ell_3m_to_q_d(qA, rotA); |
| 307 | ell_3m_to_q_d(_qB, rotB); |
| 308 | _tenQGL_q_align(qB, qA, _qB); |
| 309 | /* there's probably a faster way to do this slerp qA --> qB */ |
| 310 | ell_q_div_d(qdiv, qA, qB); /* div = A^-1 * B */ |
| 311 | angle = ell_q_to_aa_d(axis, qdiv); |
| 312 | ell_aa_to_q_d(qq, angle*tt, axis); |
| 313 | ell_q_mul_d(oq, qA, qq); |
| 314 | ell_q_to_3m_d(orot, oq); |
| 315 | ELL_3M_TRANSPOSE(oevec, orot)((oevec)[0] = (orot)[0], (oevec)[1] = (orot)[3], (oevec)[2] = (orot)[6], (oevec)[3] = (orot)[1], (oevec)[4] = (orot)[4], ( oevec)[5] = (orot)[7], (oevec)[6] = (orot)[2], (oevec)[7] = ( orot)[5], (oevec)[8] = (orot)[8]); |
| 316 | } |
| 317 | |
| 318 | void |
| 319 | tenQGLInterpTwo(double oten[7], |
| 320 | const double tenA[7], const double tenB[7], |
| 321 | int ptype, double tt, tenInterpParm *tip) { |
| 322 | double oeval[3], evalA[3], evalB[3], oevec[9], evecA[9], evecB[9], cc; |
| 323 | |
| 324 | AIR_UNUSED(tip)(void)(tip); |
| 325 | tenEigensolve_d(evalA, evecA, tenA); |
| 326 | tenEigensolve_d(evalB, evecB, tenB); |
| 327 | cc = AIR_LERP(tt, tenA[0], tenB[0])((tt)*((tenB[0]) - (tenA[0])) + (tenA[0])); |
| 328 | |
| 329 | if (tenInterpTypeQuatGeoLoxK == ptype) { |
| 330 | tenQGLInterpTwoEvalK(oeval, evalA, evalB, tt); |
| 331 | } else { |
| 332 | tenQGLInterpTwoEvalR(oeval, evalA, evalB, tt); |
| 333 | } |
| 334 | tenQGLInterpTwoEvec(oevec, evecA, evecB, tt); |
| 335 | tenMakeSingle_d(oten, cc, oeval, oevec); |
| 336 | |
| 337 | return; |
| 338 | } |
| 339 | |
| 340 | /* |
| 341 | ** This does (non-optionally) use biff, to report convergence failures |
| 342 | ** |
| 343 | ** we do in fact require non-NULL tip, because it holds the buffers we need |
| 344 | */ |
| 345 | int |
| 346 | _tenQGLInterpNEval(double evalOut[3], |
| 347 | const double *evalIn, /* size 3 -by- NN */ |
| 348 | const double *wght, /* size NN */ |
| 349 | unsigned int NN, |
| 350 | int ptype, tenInterpParm *tip) { |
| 351 | static const char me[]="_tenQGLInterpNEval"; |
| 352 | double RTh_Out[3], elen; |
| 353 | unsigned int ii, iter; |
| 354 | int rttype; |
| 355 | void (*llog)(double lg[3], const double RTh_A[3], const double RTh_B[3]); |
| 356 | void (*lexp)(double RTh_B[3], const double RTh_A[3], const double lg[3]); |
| 357 | |
| 358 | if (!(evalOut && evalIn && tip)) { |
| 359 | biffAddf(TENtenBiffKey, "%s: got NULL pointer", me); |
| 360 | return 1; |
| 361 | } |
| 362 | /* convert to (R,Th,_) and initialize RTh_Out */ |
| 363 | if (tenInterpTypeQuatGeoLoxK == ptype) { |
| 364 | rttype = tenTripleTypeRThetaZ; |
| 365 | llog = _tenQGL_Klog; |
| 366 | lexp = _tenQGL_Kexp; |
| 367 | } else { |
| 368 | rttype = tenTripleTypeRThetaPhi; |
| 369 | llog = _tenQGL_Rlog; |
| 370 | lexp = _tenQGL_Rexp; |
| 371 | } |
| 372 | ELL_3V_SET(RTh_Out, 0, 0, 0)((RTh_Out)[0] = (0), (RTh_Out)[1] = (0), (RTh_Out)[2] = (0)); |
| 373 | for (ii=0; ii<NN; ii++) { |
| 374 | double ww; |
| 375 | tenTripleConvertSingle_d(tip->rtIn + 3*ii, rttype, |
| 376 | evalIn + 3*ii, tenTripleTypeEigenvalue); |
| 377 | ww = wght ? wght[ii] : 1.0/NN; |
| 378 | ELL_3V_SCALE_INCR(RTh_Out, ww, tip->rtIn + 3*ii)((RTh_Out)[0] += (ww)*(tip->rtIn + 3*ii)[0], (RTh_Out)[1] += (ww)*(tip->rtIn + 3*ii)[1], (RTh_Out)[2] += (ww)*(tip-> rtIn + 3*ii)[2]); |
| 379 | } |
| 380 | |
| 381 | /* compute iterated weighted mean, stored in RTh_Out */ |
| 382 | iter = 0; |
| 383 | do { |
| 384 | double logavg[3]; |
| 385 | /* take log of everyone */ |
| 386 | for (ii=0; ii<NN; ii++) { |
| 387 | llog(tip->rtLog + 3*ii, RTh_Out, tip->rtIn + 3*ii); |
| 388 | } |
| 389 | /* average, and find length */ |
| 390 | ELL_3V_SET(logavg, 0, 0, 0)((logavg)[0] = (0), (logavg)[1] = (0), (logavg)[2] = (0)); |
| 391 | for (ii=0; ii<NN; ii++) { |
| 392 | double ww; |
| 393 | ww = wght ? wght[ii] : 1.0/NN; |
| 394 | ELL_3V_SCALE_INCR(logavg, ww, tip->rtLog + 3*ii)((logavg)[0] += (ww)*(tip->rtLog + 3*ii)[0], (logavg)[1] += (ww)*(tip->rtLog + 3*ii)[1], (logavg)[2] += (ww)*(tip-> rtLog + 3*ii)[2]); |
| 395 | } |
| 396 | elen = ELL_3V_LEN(logavg)(sqrt((((logavg))[0]*((logavg))[0] + ((logavg))[1]*((logavg)) [1] + ((logavg))[2]*((logavg))[2]))); |
| 397 | lexp(RTh_Out, RTh_Out, logavg); |
| 398 | iter++; |
| 399 | } while ((!tip->maxIter || iter < tip->maxIter) && elen > tip->convEps); |
| 400 | |
| 401 | if (elen > tip->convEps) { |
| 402 | ELL_3V_SET(evalOut, AIR_NAN, AIR_NAN, AIR_NAN)((evalOut)[0] = ((airFloatQNaN.f)), (evalOut)[1] = ((airFloatQNaN .f)), (evalOut)[2] = ((airFloatQNaN.f))); |
| 403 | biffAddf(TENtenBiffKey, "%s: still have error %g (> eps %g) after max %d iters", me, |
| 404 | elen, tip->convEps, tip->maxIter); |
| 405 | return 1; |
| 406 | } |
| 407 | |
| 408 | /* finish, convert to eval */ |
| 409 | tenTripleConvertSingle_d(evalOut, tenTripleTypeEigenvalue, |
| 410 | RTh_Out, rttype); |
| 411 | |
| 412 | return 0; |
| 413 | } |
| 414 | |
| 415 | double |
| 416 | _tenQGL_q_interdot(unsigned int *centerIdxP, |
| 417 | double *qq, double *inter, unsigned int NN) { |
| 418 | unsigned int ii, jj; |
| 419 | double sum, dot, max; |
| 420 | |
| 421 | for (jj=0; jj<NN; jj++) { |
| 422 | for (ii=0; ii<NN; ii++) { |
| 423 | inter[ii + NN*jj] = 0; |
| 424 | } |
| 425 | } |
| 426 | sum = 0; |
| 427 | for (jj=0; jj<NN; jj++) { |
| 428 | inter[jj + NN*jj] = 1.0; |
| 429 | for (ii=jj+1; ii<NN; ii++) { |
| 430 | dot = ELL_4V_DOT(qq + 4*ii, qq + 4*jj)((qq + 4*ii)[0]*(qq + 4*jj)[0] + (qq + 4*ii)[1]*(qq + 4*jj)[1 ] + (qq + 4*ii)[2]*(qq + 4*jj)[2] + (qq + 4*ii)[3]*(qq + 4*jj )[3]); |
| 431 | inter[ii + NN*jj] = dot; |
| 432 | inter[jj + NN*ii] = dot; |
| 433 | sum += dot; |
| 434 | } |
| 435 | } |
| 436 | for (jj=0; jj<NN; jj++) { |
| 437 | for (ii=1; ii<NN; ii++) { |
| 438 | inter[0 + NN*jj] += inter[ii + NN*jj]; |
| 439 | } |
| 440 | } |
| 441 | *centerIdxP = 0; |
| 442 | max = inter[0 + NN*(*centerIdxP)]; |
| 443 | for (jj=1; jj<NN; jj++) { |
| 444 | if (inter[0 + NN*jj] > max) { |
| 445 | *centerIdxP = jj; |
| 446 | max = inter[0 + NN*(*centerIdxP)]; |
| 447 | } |
| 448 | } |
| 449 | return sum; |
| 450 | } |
| 451 | |
| 452 | /* |
| 453 | ** This does (non-optionally) use biff, to report convergence failures |
| 454 | ** |
| 455 | ** we do in fact require non-NULL tip, because it holds the buffers we need |
| 456 | */ |
| 457 | int |
| 458 | _tenQGLInterpNEvec(double evecOut[9], |
| 459 | const double *evecIn, /* size 9 -by- NN */ |
| 460 | const double *wght, /* size NN */ |
| 461 | unsigned int NN, |
| 462 | tenInterpParm *tip) { |
| 463 | static const char me[]="_tenQGLInterpNEvec"; |
| 464 | double qOut[4], maxWght, len, /* odsum, */ dsum, rot[9]; |
| 465 | unsigned int ii, centerIdx=0, fix, qiter; |
| 466 | |
| 467 | if (!( evecOut && evecIn && tip )) { |
| 468 | biffAddf(TENtenBiffKey, "%s: got NULL pointer", me); |
| 469 | return 1; |
| 470 | } |
| 471 | /* convert to quaternions */ |
| 472 | for (ii=0; ii<NN; ii++) { |
| 473 | ELL_3M_TRANSPOSE(rot, evecIn + 9*ii)((rot)[0] = (evecIn + 9*ii)[0], (rot)[1] = (evecIn + 9*ii)[3] , (rot)[2] = (evecIn + 9*ii)[6], (rot)[3] = (evecIn + 9*ii)[1 ], (rot)[4] = (evecIn + 9*ii)[4], (rot)[5] = (evecIn + 9*ii)[ 7], (rot)[6] = (evecIn + 9*ii)[2], (rot)[7] = (evecIn + 9*ii) [5], (rot)[8] = (evecIn + 9*ii)[8]); |
| 474 | ell_3m_to_q_d(tip->qIn + 4*ii, rot); |
| 475 | } |
| 476 | /* HEY: what should this be used for? variable odsum set but not used */ |
| 477 | /* odsum = _tenQGL_q_interdot(¢erIdx, tip->qIn, tip->qInter, NN); */ |
| 478 | |
| 479 | /* find quaternion with maximal weight, use it as is (decree that |
| 480 | its the right representative), and then align rest with that. |
| 481 | This is actually principled; symmetry allows it */ |
| 482 | centerIdx = 0; |
| 483 | if (wght) { |
| 484 | maxWght = wght[centerIdx]; |
| 485 | for (ii=1; ii<NN; ii++) { |
| 486 | if (wght[ii] > maxWght) { |
| 487 | centerIdx = ii; |
| 488 | maxWght = wght[centerIdx]; |
| 489 | } |
| 490 | } |
| 491 | } |
| 492 | for (ii=0; ii<NN; ii++) { |
| 493 | if (ii == centerIdx) { |
| 494 | continue; |
| 495 | } |
| 496 | _tenQGL_q_align(tip->qIn + 4*ii, tip->qIn + 4*centerIdx, tip->qIn + 4*ii); |
| 497 | } |
| 498 | dsum = _tenQGL_q_interdot(¢erIdx, tip->qIn, tip->qInter, NN); |
Value stored to 'dsum' is never read | |
| 499 | |
| 500 | /* try to settle on tightest set of representatives */ |
| 501 | qiter = 0; |
| 502 | do { |
| 503 | fix = 0; |
| 504 | for (ii=0; ii<NN; ii++) { |
| 505 | unsigned int ff; |
| 506 | if (ii == centerIdx) { |
| 507 | continue; |
| 508 | } |
| 509 | ff = _tenQGL_q_align(tip->qIn + 4*ii, tip->qIn + 4*centerIdx, |
| 510 | tip->qIn + 4*ii); |
| 511 | fix = AIR_MAX(fix, ff)((fix) > (ff) ? (fix) : (ff)); |
| 512 | } |
| 513 | dsum = _tenQGL_q_interdot(¢erIdx, tip->qIn, tip->qInter, NN); |
| 514 | if (tip->maxIter && qiter > tip->maxIter) { |
| 515 | biffAddf(TENtenBiffKey, "%s: q tightening unconverged after %u iters; " |
| 516 | "interdot = %g -> maxfix = %u; center = %u\n", |
| 517 | me, tip->maxIter, dsum, fix, centerIdx); |
| 518 | return 1; |
| 519 | } |
| 520 | qiter++; |
| 521 | } while (fix); |
| 522 | /* |
| 523 | fprintf(stderr, "!%s: dsum %g --%u--> %g\n", me, odsum, qiter, dsum); |
| 524 | */ |
| 525 | /* make sure they're normalized */ |
| 526 | for (ii=0; ii<NN; ii++) { |
| 527 | ELL_4V_NORM(tip->qIn + 4*ii, tip->qIn + 4*ii, len)(len = (sqrt((((tip->qIn + 4*ii))[0]*((tip->qIn + 4*ii) )[0] + ((tip->qIn + 4*ii))[1]*((tip->qIn + 4*ii))[1] + ( (tip->qIn + 4*ii))[2]*((tip->qIn + 4*ii))[2] + ((tip-> qIn + 4*ii))[3]*((tip->qIn + 4*ii))[3]))), ((tip->qIn + 4*ii)[0] = (tip->qIn + 4*ii)[0]*1.0/len, (tip->qIn + 4 *ii)[1] = (tip->qIn + 4*ii)[1]*1.0/len, (tip->qIn + 4*ii )[2] = (tip->qIn + 4*ii)[2]*1.0/len, (tip->qIn + 4*ii)[ 3] = (tip->qIn + 4*ii)[3]*1.0/len)); |
| 528 | } |
| 529 | |
| 530 | /* compute iterated weighted mean, stored in qOut */ |
| 531 | if (ell_q_avgN_d(qOut, &qiter, tip->qIn, tip->qBuff, wght, |
| 532 | NN, tip->convEps, tip->maxIter)) { |
| 533 | biffMovef(TENtenBiffKey, ELLell_biff_key, "%s: problem doing quaternion mean", me); |
| 534 | return 1; |
| 535 | } |
| 536 | /* |
| 537 | fprintf(stderr, "!%s: q avg converged in %u\n", me, qiter); |
| 538 | */ |
| 539 | |
| 540 | /* finish, convert back to evec */ |
| 541 | ell_q_to_3m_d(rot, qOut); |
| 542 | ELL_3M_TRANSPOSE(evecOut, rot)((evecOut)[0] = (rot)[0], (evecOut)[1] = (rot)[3], (evecOut)[ 2] = (rot)[6], (evecOut)[3] = (rot)[1], (evecOut)[4] = (rot)[ 4], (evecOut)[5] = (rot)[7], (evecOut)[6] = (rot)[2], (evecOut )[7] = (rot)[5], (evecOut)[8] = (rot)[8]); |
| 543 | |
| 544 | return 0; |
| 545 | } |
| 546 |