File: | src/ten/grads.c |
Location: | line 411, column 3 |
Description: | Value stored to 'done' 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 | #include "ten.h" |
25 | #include "privateTen.h" |
26 | |
27 | tenGradientParm * |
28 | tenGradientParmNew(void) { |
29 | tenGradientParm *ret; |
30 | |
31 | ret = (tenGradientParm *)calloc(1, sizeof(tenGradientParm)); |
32 | if (ret) { |
33 | ret->initStep = 1.0; |
34 | ret->jitter = 0.2; |
35 | ret->minVelocity = 0.000000001; |
36 | ret->minPotentialChange = 0.000000001; |
37 | ret->minMean = 0.0001; |
38 | ret->minMeanImprovement = 0.00005; |
39 | ret->single = AIR_FALSE0; |
40 | ret->insertZeroVec = AIR_FALSE0; |
41 | ret->verbose = 1; |
42 | ret->snap = 0; |
43 | ret->report = 400; |
44 | ret->expo = 1; |
45 | ret->expo_d = 0; |
46 | ret->seed = 42; |
47 | ret->maxEdgeShrink = 20; |
48 | ret->minIteration = 0; |
49 | ret->maxIteration = 1000000; |
50 | ret->step = 0; |
51 | ret->nudge = 0; |
52 | ret->itersUsed = 0; |
53 | ret->potential = 0; |
54 | ret->potentialNorm = 0; |
55 | ret->angle = 0; |
56 | ret->edge = 0; |
57 | } |
58 | return ret; |
59 | } |
60 | |
61 | tenGradientParm * |
62 | tenGradientParmNix(tenGradientParm *tgparm) { |
63 | |
64 | airFree(tgparm); |
65 | return NULL((void*)0); |
66 | } |
67 | |
68 | int |
69 | tenGradientCheck(const Nrrd *ngrad, int type, unsigned int minnum) { |
70 | static const char me[]="tenGradientCheck"; |
71 | |
72 | if (nrrdCheck(ngrad)) { |
73 | biffMovef(TENtenBiffKey, NRRDnrrdBiffKey, "%s: basic validity check failed", me); |
74 | return 1; |
75 | } |
76 | if (!( 3 == ngrad->axis[0].size && 2 == ngrad->dim )) { |
77 | char stmp[AIR_STRLEN_SMALL(128+1)]; |
78 | biffAddf(TENtenBiffKey, "%s: need a 3xN 2-D array (not a %sx? %u-D array)", me, |
79 | airSprintSize_t(stmp, ngrad->axis[0].size), ngrad->dim); |
80 | return 1; |
81 | } |
82 | if (nrrdTypeDefault != type && type != ngrad->type) { |
83 | biffAddf(TENtenBiffKey, "%s: requested type %s but got type %s", me, |
84 | airEnumStr(nrrdType, type), airEnumStr(nrrdType, ngrad->type)); |
85 | return 1; |
86 | } |
87 | if (nrrdTypeBlock == ngrad->type) { |
88 | biffAddf(TENtenBiffKey, "%s: sorry, can't use %s type", me, |
89 | airEnumStr(nrrdType, nrrdTypeBlock)); |
90 | return 1; |
91 | } |
92 | if (!( minnum <= ngrad->axis[1].size )) { |
93 | char stmp[AIR_STRLEN_SMALL(128+1)]; |
94 | biffAddf(TENtenBiffKey, "%s: have only %s gradients, need at least %d", me, |
95 | airSprintSize_t(stmp, ngrad->axis[1].size), minnum); |
96 | return 1; |
97 | } |
98 | |
99 | return 0; |
100 | } |
101 | |
102 | /* |
103 | ******** tenGradientRandom |
104 | ** |
105 | ** generates num random unit vectors of type double |
106 | */ |
107 | int |
108 | tenGradientRandom(Nrrd *ngrad, unsigned int num, unsigned int seed) { |
109 | static const char me[]="tenGradientRandom"; |
110 | double *grad, len; |
111 | unsigned int gi; |
112 | |
113 | if (nrrdMaybeAlloc_va(ngrad, nrrdTypeDouble, 2, |
114 | AIR_CAST(size_t, 3)((size_t)(3)), AIR_CAST(size_t, num)((size_t)(num)))) { |
115 | biffMovef(TENtenBiffKey, NRRDnrrdBiffKey, "%s: couldn't allocate output", me); |
116 | return 1; |
117 | } |
118 | airSrandMT(seed); |
119 | grad = AIR_CAST(double*, ngrad->data)((double*)(ngrad->data)); |
120 | for (gi=0; gi<num; gi++) { |
121 | do { |
122 | grad[0] = AIR_AFFINE(0, airDrandMT(), 1, -1, 1)( ((double)(1)-(-1))*((double)(airDrandMT())-(0)) / ((double) (1)-(0)) + (-1)); |
123 | grad[1] = AIR_AFFINE(0, airDrandMT(), 1, -1, 1)( ((double)(1)-(-1))*((double)(airDrandMT())-(0)) / ((double) (1)-(0)) + (-1)); |
124 | grad[2] = AIR_AFFINE(0, airDrandMT(), 1, -1, 1)( ((double)(1)-(-1))*((double)(airDrandMT())-(0)) / ((double) (1)-(0)) + (-1)); |
125 | len = ELL_3V_LEN(grad)(sqrt((((grad))[0]*((grad))[0] + ((grad))[1]*((grad))[1] + (( grad))[2]*((grad))[2]))); |
126 | } while (len > 1 || !len); |
127 | ELL_3V_SCALE(grad, 1.0/len, grad)((grad)[0] = (1.0/len)*(grad)[0], (grad)[1] = (1.0/len)*(grad )[1], (grad)[2] = (1.0/len)*(grad)[2]); |
128 | grad += 3; |
129 | } |
130 | return 0; |
131 | } |
132 | |
133 | /* |
134 | ******** tenGradientIdealEdge |
135 | ** |
136 | ** edge length of delauney triangulation of idealized distribution of |
137 | ** N gradients (2*N points), but also allowing a boolean "single" flag |
138 | ** saying that we actually care about N points |
139 | */ |
140 | double |
141 | tenGradientIdealEdge(unsigned int N, int single) { |
142 | |
143 | return sqrt((!single ? 4 : 8)*AIR_PI3.14159265358979323846/(sqrt(3)*N)); |
144 | } |
145 | |
146 | /* |
147 | ******** tenGradientJitter |
148 | ** |
149 | ** moves all gradients by amount dist on tangent plane, in a random |
150 | ** direction, and then renormalizes. The distance is a fraction |
151 | ** of the ideal edge length (via tenGradientIdealEdge) |
152 | */ |
153 | int |
154 | tenGradientJitter(Nrrd *nout, const Nrrd *nin, double dist) { |
155 | static const char me[]="tenGradientJitter"; |
156 | double *grad, perp0[3], perp1[3], len, theta, cc, ss, edge; |
157 | unsigned int gi, num; |
158 | |
159 | if (nrrdConvert(nout, nin, nrrdTypeDouble)) { |
160 | biffMovef(TENtenBiffKey, NRRDnrrdBiffKey, "%s: trouble converting input to double", me); |
161 | return 1; |
162 | } |
163 | if (tenGradientCheck(nout, nrrdTypeDouble, 3)) { |
164 | biffAddf(TENtenBiffKey, "%s: didn't get valid gradients", me); |
165 | return 1; |
166 | } |
167 | grad = AIR_CAST(double*, nout->data)((double*)(nout->data)); |
168 | num = AIR_UINT(nout->axis[1].size)((unsigned int)(nout->axis[1].size)); |
169 | /* HEY: possible confusion between single and not */ |
170 | edge = tenGradientIdealEdge(num, AIR_FALSE0); |
171 | for (gi=0; gi<num; gi++) { |
172 | ELL_3V_NORM(grad, grad, len)(len = (sqrt((((grad))[0]*((grad))[0] + ((grad))[1]*((grad))[ 1] + ((grad))[2]*((grad))[2]))), ((grad)[0] = (1.0/len)*(grad )[0], (grad)[1] = (1.0/len)*(grad)[1], (grad)[2] = (1.0/len)* (grad)[2])); |
173 | ell_3v_perp_d(perp0, grad); |
174 | ELL_3V_CROSS(perp1, perp0, grad)((perp1)[0] = (perp0)[1]*(grad)[2] - (perp0)[2]*(grad)[1], (perp1 )[1] = (perp0)[2]*(grad)[0] - (perp0)[0]*(grad)[2], (perp1)[2 ] = (perp0)[0]*(grad)[1] - (perp0)[1]*(grad)[0]); |
175 | theta = AIR_AFFINE(0, airDrandMT(), 1, 0, 2*AIR_PI)( ((double)(2*3.14159265358979323846)-(0))*((double)(airDrandMT ())-(0)) / ((double)(1)-(0)) + (0)); |
176 | cc = dist*edge*cos(theta); |
177 | ss = dist*edge*sin(theta); |
178 | ELL_3V_SCALE_ADD3(grad, 1.0, grad, cc, perp0, ss, perp1)((grad)[0] = (1.0)*(grad)[0] + (cc)*(perp0)[0] + (ss)*(perp1) [0], (grad)[1] = (1.0)*(grad)[1] + (cc)*(perp0)[1] + (ss)*(perp1 )[1], (grad)[2] = (1.0)*(grad)[2] + (cc)*(perp0)[2] + (ss)*(perp1 )[2]); |
179 | ELL_3V_NORM(grad, grad, len)(len = (sqrt((((grad))[0]*((grad))[0] + ((grad))[1]*((grad))[ 1] + ((grad))[2]*((grad))[2]))), ((grad)[0] = (1.0/len)*(grad )[0], (grad)[1] = (1.0/len)*(grad)[1], (grad)[2] = (1.0/len)* (grad)[2])); |
180 | grad += 3; |
181 | } |
182 | |
183 | return 0; |
184 | } |
185 | |
186 | void |
187 | tenGradientMeasure(double *pot, double *minAngle, double *minEdge, |
188 | const Nrrd *npos, tenGradientParm *tgparm, |
189 | int edgeNormalize) { |
190 | /* static const char me[]="tenGradientMeasure"; */ |
191 | double diff[3], *pos, atmp=0, ptmp, edge, len; |
192 | unsigned int ii, jj, num; |
193 | |
194 | /* allow minAngle NULL */ |
195 | if (!(pot && npos && tgparm )) { |
196 | return; |
197 | } |
198 | |
199 | num = AIR_UINT(npos->axis[1].size)((unsigned int)(npos->axis[1].size)); |
200 | pos = AIR_CAST(double *, npos->data)((double *)(npos->data)); |
201 | edge = (edgeNormalize |
202 | ? tenGradientIdealEdge(num, tgparm->single) |
203 | : 1.0); |
204 | *pot = 0; |
205 | if (minAngle) { |
206 | *minAngle = AIR_PI3.14159265358979323846; |
207 | } |
208 | if (minEdge) { |
209 | *minEdge = 2; |
210 | } |
211 | for (ii=0; ii<num; ii++) { |
212 | for (jj=0; jj<ii; jj++) { |
213 | ELL_3V_SUB(diff, pos + 3*ii, pos + 3*jj)((diff)[0] = (pos + 3*ii)[0] - (pos + 3*jj)[0], (diff)[1] = ( pos + 3*ii)[1] - (pos + 3*jj)[1], (diff)[2] = (pos + 3*ii)[2] - (pos + 3*jj)[2]); |
214 | len = ELL_3V_LEN(diff)(sqrt((((diff))[0]*((diff))[0] + ((diff))[1]*((diff))[1] + (( diff))[2]*((diff))[2]))); |
215 | if (minEdge) { |
216 | *minEdge = AIR_MIN(*minEdge, len)((*minEdge) < (len) ? (*minEdge) : (len)); |
217 | } |
218 | if (tgparm->expo) { |
219 | ptmp = airIntPow(edge/len, tgparm->expo); |
220 | } else { |
221 | ptmp = pow(edge/len, tgparm->expo_d); |
222 | } |
223 | *pot += ptmp; |
224 | if (minAngle) { |
225 | atmp = ell_3v_angle_d(pos + 3*ii, pos + 3*jj); |
226 | *minAngle = AIR_MIN(atmp, *minAngle)((atmp) < (*minAngle) ? (atmp) : (*minAngle)); |
227 | } |
228 | if (!tgparm->single) { |
229 | *pot += ptmp; |
230 | ELL_3V_ADD2(diff, pos + 3*ii, pos + 3*jj)((diff)[0] = (pos + 3*ii)[0] + (pos + 3*jj)[0], (diff)[1] = ( pos + 3*ii)[1] + (pos + 3*jj)[1], (diff)[2] = (pos + 3*ii)[2] + (pos + 3*jj)[2]); |
231 | len = ELL_3V_LEN(diff)(sqrt((((diff))[0]*((diff))[0] + ((diff))[1]*((diff))[1] + (( diff))[2]*((diff))[2]))); |
232 | if (minEdge) { |
233 | *minEdge = AIR_MIN(*minEdge, len)((*minEdge) < (len) ? (*minEdge) : (len)); |
234 | } |
235 | if (tgparm->expo) { |
236 | *pot += 2*airIntPow(edge/len, tgparm->expo); |
237 | } else { |
238 | *pot += 2*pow(edge/len, tgparm->expo_d); |
239 | } |
240 | if (minAngle) { |
241 | *minAngle = AIR_MIN(AIR_PI-atmp, *minAngle)((3.14159265358979323846 -atmp) < (*minAngle) ? (3.14159265358979323846 -atmp) : (*minAngle)); |
242 | } |
243 | } |
244 | } |
245 | } |
246 | return; |
247 | } |
248 | |
249 | /* |
250 | ** Do asynchronous update of positions in "npos', based on force |
251 | ** calculations wherein the distances are normalized "edge". Using a |
252 | ** small "edge" allows forces to either underflow to zero, or be |
253 | ** finite, instead of exploding to infinity, for high exponents. |
254 | ** |
255 | ** The smallest seen edge length is recorded in "*edgeMin", which is |
256 | ** initialized to the given "edge". This allows, for example, the |
257 | ** caller to try again with a smaller edge normalization. |
258 | ** |
259 | ** The mean velocity of the points through the update is recorded in |
260 | ** "*meanVel". |
261 | ** |
262 | ** Based on the observation that when using large exponents, numerical |
263 | ** difficulties arise from the (force-based) update of the positions |
264 | ** of the two (or few) closest particles, this function puts a speed |
265 | ** limit (variable "limit") on the distance a particle may move during |
266 | ** update, expressed as a fraction of the normalizing edge length. |
267 | ** "limit" has been set heuristically, according to the exponent (we |
268 | ** have to clamp speeds more aggresively with higher exponents), as |
269 | ** well as (even more heuristically) according to the number of times |
270 | ** the step size has been decreased. This latter factor has to be |
271 | ** bounded, so that the update is not unnecessarily bounded when the |
272 | ** step size gets very small at the last stages of computation. |
273 | ** Without the step-size-based speed limit, the step size would |
274 | ** sometimes (e.g. num=200, expo=300) have to reduced to a miniscule |
275 | ** value, which slows subsequent convergence terribly. |
276 | ** |
277 | ** this function is not static, though it could be, so that mac's |
278 | ** "Sampler" app can profile this |
279 | */ |
280 | int |
281 | _tenGradientUpdate(double *meanVel, double *edgeMin, |
282 | Nrrd *npos, double edge, tenGradientParm *tgparm) { |
283 | /* static const char me[]="_tenGradientUpdate"; */ |
284 | double *pos, newpos[3], grad[3], ngrad[3], |
285 | dir[3], len, rep, step, diff[3], limit, expo; |
286 | int num, ii, jj, E; |
287 | |
288 | E = 0; |
289 | pos = AIR_CAST(double *, npos->data)((double *)(npos->data)); |
290 | num = AIR_UINT(npos->axis[1].size)((unsigned int)(npos->axis[1].size)); |
291 | *meanVel = 0; |
292 | *edgeMin = edge; |
293 | expo = tgparm->expo ? tgparm->expo : tgparm->expo_d; |
294 | limit = expo*AIR_MIN(sqrt(expo),((sqrt(expo)) < (log(1 + tgparm->initStep/tgparm->step )) ? (sqrt(expo)) : (log(1 + tgparm->initStep/tgparm->step ))) |
295 | log(1 + tgparm->initStep/tgparm->step))((sqrt(expo)) < (log(1 + tgparm->initStep/tgparm->step )) ? (sqrt(expo)) : (log(1 + tgparm->initStep/tgparm->step ))); |
296 | for (ii=0; ii<num; ii++) { |
297 | ELL_3V_SET(grad, 0, 0, 0)((grad)[0] = (0), (grad)[1] = (0), (grad)[2] = (0)); |
298 | for (jj=0; jj<num; jj++) { |
299 | if (ii == jj) { |
300 | continue; |
301 | } |
302 | ELL_3V_SUB(dir, pos + 3*ii, pos + 3*jj)((dir)[0] = (pos + 3*ii)[0] - (pos + 3*jj)[0], (dir)[1] = (pos + 3*ii)[1] - (pos + 3*jj)[1], (dir)[2] = (pos + 3*ii)[2] - ( pos + 3*jj)[2]); |
303 | ELL_3V_NORM(dir, dir, len)(len = (sqrt((((dir))[0]*((dir))[0] + ((dir))[1]*((dir))[1] + ((dir))[2]*((dir))[2]))), ((dir)[0] = (1.0/len)*(dir)[0], (dir )[1] = (1.0/len)*(dir)[1], (dir)[2] = (1.0/len)*(dir)[2])); |
304 | *edgeMin = AIR_MIN(*edgeMin, len)((*edgeMin) < (len) ? (*edgeMin) : (len)); |
305 | if (tgparm->expo) { |
306 | rep = airIntPow(edge/len, tgparm->expo+1); |
307 | } else { |
308 | rep = pow(edge/len, tgparm->expo_d+1); |
309 | } |
310 | ELL_3V_SCALE_INCR(grad, rep/num, dir)((grad)[0] += (rep/num)*(dir)[0], (grad)[1] += (rep/num)*(dir )[1], (grad)[2] += (rep/num)*(dir)[2]); |
311 | if (!tgparm->single) { |
312 | ELL_3V_ADD2(dir, pos + 3*ii, pos + 3*jj)((dir)[0] = (pos + 3*ii)[0] + (pos + 3*jj)[0], (dir)[1] = (pos + 3*ii)[1] + (pos + 3*jj)[1], (dir)[2] = (pos + 3*ii)[2] + ( pos + 3*jj)[2]); |
313 | ELL_3V_NORM(dir, dir, len)(len = (sqrt((((dir))[0]*((dir))[0] + ((dir))[1]*((dir))[1] + ((dir))[2]*((dir))[2]))), ((dir)[0] = (1.0/len)*(dir)[0], (dir )[1] = (1.0/len)*(dir)[1], (dir)[2] = (1.0/len)*(dir)[2])); |
314 | *edgeMin = AIR_MIN(*edgeMin, len)((*edgeMin) < (len) ? (*edgeMin) : (len)); |
315 | if (tgparm->expo) { |
316 | rep = airIntPow(edge/len, tgparm->expo+1); |
317 | } else { |
318 | rep = pow(edge/len, tgparm->expo_d+1); |
319 | } |
320 | ELL_3V_SCALE_INCR(grad, rep/num, dir)((grad)[0] += (rep/num)*(dir)[0], (grad)[1] += (rep/num)*(dir )[1], (grad)[2] += (rep/num)*(dir)[2]); |
321 | } |
322 | } |
323 | ELL_3V_NORM(ngrad, grad, len)(len = (sqrt((((grad))[0]*((grad))[0] + ((grad))[1]*((grad))[ 1] + ((grad))[2]*((grad))[2]))), ((ngrad)[0] = (1.0/len)*(grad )[0], (ngrad)[1] = (1.0/len)*(grad)[1], (ngrad)[2] = (1.0/len )*(grad)[2])); |
324 | if (!( AIR_EXISTS(len)(((int)(!((len) - (len))))) )) { |
325 | /* things blew up, either in incremental force |
326 | additions, or in the attempt at normalization */ |
327 | E = 1; |
328 | *meanVel = AIR_NAN(airFloatQNaN.f); |
329 | break; |
330 | } |
331 | if (0 == len) { |
332 | /* if the length of grad[] underflowed to zero, we can |
333 | legitimately zero out ngrad[] */ |
334 | ELL_3V_SET(ngrad, 0, 0, 0)((ngrad)[0] = (0), (ngrad)[1] = (0), (ngrad)[2] = (0)); |
335 | } |
336 | step = AIR_MIN(len*tgparm->step, edge/limit)((len*tgparm->step) < (edge/limit) ? (len*tgparm->step ) : (edge/limit)); |
337 | ELL_3V_SCALE_ADD2(newpos,((newpos)[0] = (1.0)*(pos + 3*ii)[0] + (step)*(ngrad)[0], (newpos )[1] = (1.0)*(pos + 3*ii)[1] + (step)*(ngrad)[1], (newpos)[2] = (1.0)*(pos + 3*ii)[2] + (step)*(ngrad)[2]) |
338 | 1.0, pos + 3*ii,((newpos)[0] = (1.0)*(pos + 3*ii)[0] + (step)*(ngrad)[0], (newpos )[1] = (1.0)*(pos + 3*ii)[1] + (step)*(ngrad)[1], (newpos)[2] = (1.0)*(pos + 3*ii)[2] + (step)*(ngrad)[2]) |
339 | step, ngrad)((newpos)[0] = (1.0)*(pos + 3*ii)[0] + (step)*(ngrad)[0], (newpos )[1] = (1.0)*(pos + 3*ii)[1] + (step)*(ngrad)[1], (newpos)[2] = (1.0)*(pos + 3*ii)[2] + (step)*(ngrad)[2]); |
340 | ELL_3V_NORM(newpos, newpos, len)(len = (sqrt((((newpos))[0]*((newpos))[0] + ((newpos))[1]*((newpos ))[1] + ((newpos))[2]*((newpos))[2]))), ((newpos)[0] = (1.0/len )*(newpos)[0], (newpos)[1] = (1.0/len)*(newpos)[1], (newpos)[ 2] = (1.0/len)*(newpos)[2])); |
341 | ELL_3V_SUB(diff, pos + 3*ii, newpos)((diff)[0] = (pos + 3*ii)[0] - (newpos)[0], (diff)[1] = (pos + 3*ii)[1] - (newpos)[1], (diff)[2] = (pos + 3*ii)[2] - (newpos )[2]); |
342 | *meanVel += ELL_3V_LEN(diff)(sqrt((((diff))[0]*((diff))[0] + ((diff))[1]*((diff))[1] + (( diff))[2]*((diff))[2]))); |
343 | ELL_3V_COPY(pos + 3*ii, newpos)((pos + 3*ii)[0] = (newpos)[0], (pos + 3*ii)[1] = (newpos)[1] , (pos + 3*ii)[2] = (newpos)[2]); |
344 | } |
345 | *meanVel /= num; |
346 | |
347 | return E; |
348 | } |
349 | |
350 | /* |
351 | ** assign random signs to the vectors and measures the length of their |
352 | ** mean, as quickly as possible |
353 | */ |
354 | static double |
355 | party(Nrrd *npos, airRandMTState *rstate) { |
356 | double *pos, mean[3]; |
357 | unsigned int ii, num, rnd, rndBit; |
358 | |
359 | pos = (double *)(npos->data); |
360 | num = AIR_UINT(npos->axis[1].size)((unsigned int)(npos->axis[1].size)); |
361 | rnd = airUIrandMT_r(rstate); |
362 | rndBit = 0; |
363 | ELL_3V_SET(mean, 0, 0, 0)((mean)[0] = (0), (mean)[1] = (0), (mean)[2] = (0)); |
364 | for (ii=0; ii<num; ii++) { |
365 | if (32 == rndBit) { |
366 | rnd = airUIrandMT_r(rstate); |
367 | rndBit = 0; |
368 | } |
369 | if (rnd & (1 << rndBit++)) { |
370 | ELL_3V_SCALE(pos + 3*ii, -1, pos + 3*ii)((pos + 3*ii)[0] = (-1)*(pos + 3*ii)[0], (pos + 3*ii)[1] = (- 1)*(pos + 3*ii)[1], (pos + 3*ii)[2] = (-1)*(pos + 3*ii)[2]); |
371 | } |
372 | ELL_3V_INCR(mean, pos + 3*ii)((mean)[0] += (pos + 3*ii)[0], (mean)[1] += (pos + 3*ii)[1], ( mean)[2] += (pos + 3*ii)[2]); |
373 | } |
374 | ELL_3V_SCALE(mean, 1.0/num, mean)((mean)[0] = (1.0/num)*(mean)[0], (mean)[1] = (1.0/num)*(mean )[1], (mean)[2] = (1.0/num)*(mean)[2]); |
375 | return ELL_3V_LEN(mean)(sqrt((((mean))[0]*((mean))[0] + ((mean))[1]*((mean))[1] + (( mean))[2]*((mean))[2]))); |
376 | } |
377 | |
378 | /* |
379 | ** parties until the gradients settle down |
380 | */ |
381 | int |
382 | tenGradientBalance(Nrrd *nout, const Nrrd *nin, |
383 | tenGradientParm *tgparm) { |
384 | static const char me[]="tenGradientBalance"; |
385 | double len, lastLen, improv; |
386 | airRandMTState *rstate; |
387 | Nrrd *ncopy; |
388 | unsigned int iter, maxIter; |
389 | int done; |
390 | airArray *mop; |
391 | |
392 | if (!nout || tenGradientCheck(nin, nrrdTypeUnknown, 2) || !tgparm) { |
393 | biffAddf(TENtenBiffKey, "%s: got NULL pointer (%p,%p) or invalid nin", me, |
394 | AIR_VOIDP(nout)((void *)(nout)), AIR_VOIDP(tgparm)((void *)(tgparm))); |
395 | return 1; |
396 | } |
397 | if (nrrdConvert(nout, nin, nrrdTypeDouble)) { |
398 | biffMovef(TENtenBiffKey, NRRDnrrdBiffKey, "%s: can't initialize output with input", me); |
399 | return 1; |
400 | } |
401 | |
402 | mop = airMopNew(); |
403 | ncopy = nrrdNew(); |
404 | airMopAdd(mop, ncopy, (airMopper)nrrdNuke, airMopAlways); |
405 | rstate = airRandMTStateNew(tgparm->seed); |
406 | airMopAdd(mop, rstate, (airMopper)airRandMTStateNix, airMopAlways); |
407 | /* HEY: factor of 100 is an approximate hack */ |
408 | maxIter = 100*tgparm->maxIteration; |
409 | |
410 | lastLen = 1.0; |
411 | done = AIR_FALSE0; |
Value stored to 'done' is never read | |
412 | do { |
413 | iter = 0; |
414 | do { |
415 | iter++; |
416 | len = party(nout, rstate); |
417 | } while (len > lastLen && iter < maxIter); |
418 | if (iter >= maxIter) { |
419 | if (tgparm->verbose) { |
420 | fprintf(stderr__stderrp, "%s: stopping at max iter %u\n", me, maxIter); |
421 | } |
422 | if (nrrdCopy(nout, ncopy)) { |
423 | biffMovef(TENtenBiffKey, NRRDnrrdBiffKey, "%s: trouble copying", me); |
424 | airMopError(mop); return 1; |
425 | } |
426 | done = AIR_TRUE1; |
427 | } else { |
428 | if (nrrdCopy(ncopy, nout)) { |
429 | biffMovef(TENtenBiffKey, NRRDnrrdBiffKey, "%s: trouble copying", me); |
430 | airMopError(mop); return 1; |
431 | } |
432 | improv = lastLen - len; |
433 | lastLen = len; |
434 | if (tgparm->verbose) { |
435 | fprintf(stderr__stderrp, "%s: (iter %u) improvement: %g (mean length = %g)\n", |
436 | me, iter, improv, len); |
437 | } |
438 | done = (improv <= tgparm->minMeanImprovement |
439 | || len < tgparm->minMean); |
440 | } |
441 | } while (!done); |
442 | |
443 | airMopOkay(mop); |
444 | return 0; |
445 | } |
446 | |
447 | /* |
448 | ******** tenGradientDistribute |
449 | ** |
450 | ** Takes the given list of gradients, normalizes their lengths, |
451 | ** optionally jitters their positions, does point repulsion, and then |
452 | ** (optionally) selects a combination of directions with minimum vector sum. |
453 | ** |
454 | ** The complicated part of this is the point repulsion, which uses a |
455 | ** gradient descent with variable set size. The progress of the system |
456 | ** is measured by decrease in potential (when its measurement doesn't |
457 | ** overflow to infinity) or an increase in the minimum angle. When a |
458 | ** step results in negative progress, the step size is halved, and the |
459 | ** iteration is attempted again. Based on the observation that at |
460 | ** some points the step size must be made very small to get progress, |
461 | ** the step size is cautiously increased ("nudged") at every |
462 | ** iteration, to try to avoid using an overly small step. The amount |
463 | ** by which the step is nudged is halved everytime the step is halved, |
464 | ** to avoid endless cycling through step sizes. |
465 | */ |
466 | int |
467 | tenGradientDistribute(Nrrd *nout, const Nrrd *nin, |
468 | tenGradientParm *tgparm) { |
469 | static const char me[]="tenGradientDistribute"; |
470 | char filename[AIR_STRLEN_SMALL(128+1)]; |
471 | unsigned int ii, num, iter, oldIdx, newIdx, edgeShrink; |
472 | airArray *mop; |
473 | Nrrd *npos[2]; |
474 | double *pos, len, meanVelocity, pot, potNew, potD, |
475 | edge, edgeMin, angle, angleNew; |
476 | int E; |
477 | |
478 | if (!nout || tenGradientCheck(nin, nrrdTypeUnknown, 2) || !tgparm) { |
479 | biffAddf(TENtenBiffKey, "%s: got NULL pointer or invalid input", me); |
480 | return 1; |
481 | } |
482 | |
483 | num = AIR_UINT(nin->axis[1].size)((unsigned int)(nin->axis[1].size)); |
484 | mop = airMopNew(); |
485 | npos[0] = nrrdNew(); |
486 | npos[1] = nrrdNew(); |
487 | airMopAdd(mop, npos[0], (airMopper)nrrdNuke, airMopAlways); |
488 | airMopAdd(mop, npos[1], (airMopper)nrrdNuke, airMopAlways); |
489 | if (nrrdConvert(npos[0], nin, nrrdTypeDouble) |
490 | || nrrdConvert(npos[1], nin, nrrdTypeDouble)) { |
491 | biffMovef(TENtenBiffKey, NRRDnrrdBiffKey, "%s: trouble allocating temp buffers", me); |
492 | airMopError(mop); return 1; |
493 | } |
494 | |
495 | pos = (double*)(npos[0]->data); |
496 | for (ii=0; ii<num; ii++) { |
497 | ELL_3V_NORM(pos, pos, len)(len = (sqrt((((pos))[0]*((pos))[0] + ((pos))[1]*((pos))[1] + ((pos))[2]*((pos))[2]))), ((pos)[0] = (1.0/len)*(pos)[0], (pos )[1] = (1.0/len)*(pos)[1], (pos)[2] = (1.0/len)*(pos)[2])); |
498 | pos += 3; |
499 | } |
500 | if (tgparm->jitter) { |
501 | if (tenGradientJitter(npos[0], npos[0], tgparm->jitter)) { |
502 | biffAddf(TENtenBiffKey, "%s: problem jittering input", me); |
503 | airMopError(mop); return 1; |
504 | } |
505 | } |
506 | |
507 | /* initialize things prior to first iteration; have to |
508 | make sure that loop body tests pass 1st time around */ |
509 | meanVelocity = 2*tgparm->minVelocity; |
510 | potD = -2*tgparm->minPotentialChange; |
511 | oldIdx = 0; |
512 | newIdx = 1; |
513 | tgparm->step = tgparm->initStep; |
514 | tgparm->nudge = 0.1; |
515 | tenGradientMeasure(&pot, &angle, NULL((void*)0), |
516 | npos[oldIdx], tgparm, AIR_TRUE1); |
517 | for (iter = 0; |
518 | ((!!tgparm->minIteration && iter < tgparm->minIteration) |
519 | || |
520 | (iter < tgparm->maxIteration |
521 | && (!tgparm->minPotentialChange |
522 | || !AIR_EXISTS(potD)(((int)(!((potD) - (potD))))) |
523 | || -potD > tgparm->minPotentialChange) |
524 | && (!tgparm->minVelocity |
525 | || meanVelocity > tgparm->minVelocity) |
526 | && tgparm->step > FLT_MIN1.17549435e-38F)); |
527 | iter++) { |
528 | /* copy positions from old to new */ |
529 | memcpy(npos[newIdx]->data, npos[oldIdx]->data, 3*num*sizeof(double))__builtin___memcpy_chk (npos[newIdx]->data, npos[oldIdx]-> data, 3*num*sizeof(double), __builtin_object_size (npos[newIdx ]->data, 0)); |
530 | edge = tenGradientIdealEdge(num, tgparm->single); |
531 | edgeShrink = 0; |
532 | /* try to do a position update, which will fail if repulsion values |
533 | explode, from having an insufficiently small edge normalization, |
534 | so retry with smaller edge next time */ |
535 | do { |
536 | E = _tenGradientUpdate(&meanVelocity, &edgeMin, |
537 | npos[newIdx], edge, tgparm); |
538 | if (E) { |
539 | if (edgeShrink > tgparm->maxEdgeShrink) { |
540 | biffAddf(TENtenBiffKey, "%s: %u > %u edge shrinks (%g), update still failed", |
541 | me, edgeShrink, tgparm->maxEdgeShrink, edge); |
542 | airMopError(mop); return 1; |
543 | } |
544 | edgeShrink++; |
545 | /* re-initialize positions (HEY ugly code logic) */ |
546 | memcpy(npos[newIdx]->data, npos[oldIdx]->data, 3*num*sizeof(double))__builtin___memcpy_chk (npos[newIdx]->data, npos[oldIdx]-> data, 3*num*sizeof(double), __builtin_object_size (npos[newIdx ]->data, 0)); |
547 | edge = edgeMin; |
548 | } |
549 | } while (E); |
550 | tenGradientMeasure(&potNew, &angleNew, NULL((void*)0), |
551 | npos[newIdx], tgparm, AIR_TRUE1); |
552 | if ((AIR_EXISTS(pot)(((int)(!((pot) - (pot))))) && AIR_EXISTS(potNew)(((int)(!((potNew) - (potNew))))) && potNew <= pot) |
553 | || angleNew >= angle) { |
554 | /* there was progress of some kind, either through potential |
555 | decrease, or angle increase */ |
556 | potD = 2*(potNew - pot)/(potNew + pot); |
557 | if (!(iter % tgparm->report) && tgparm->verbose) { |
558 | fprintf(stderr__stderrp, "%s(%d): . . . . . . step = %g, edgeShrink = %u\n" |
559 | " velo = %g<>%g, phi = %g ~ %g<>%g, angle = %g ~ %g\n", |
560 | me, iter, tgparm->step, edgeShrink, |
561 | meanVelocity, tgparm->minVelocity, |
562 | pot, potD, tgparm->minPotentialChange, |
563 | angle, angleNew - angle); |
564 | } |
565 | if (tgparm->snap && !(iter % tgparm->snap)) { |
566 | sprintf(filename, "%05d.nrrd", iter/tgparm->snap)__builtin___sprintf_chk (filename, 0, __builtin_object_size ( filename, 2 > 1 ? 1 : 0), "%05d.nrrd", iter/tgparm->snap ); |
567 | if (tgparm->verbose) { |
568 | fprintf(stderr__stderrp, "%s(%d): . . . . . . saving %s\n", |
569 | me, iter, filename); |
570 | } |
571 | if (nrrdSave(filename, npos[newIdx], NULL((void*)0))) { |
572 | char *serr; |
573 | serr = biffGetDone(NRRDnrrdBiffKey); |
574 | if (tgparm->verbose) { /* perhaps shouldn't have this check */ |
575 | fprintf(stderr__stderrp, "%s: iter=%d, couldn't save snapshot:\n%s" |
576 | "continuing ...\n", me, iter, serr); |
577 | } |
578 | free(serr); |
579 | } |
580 | } |
581 | tgparm->step *= 1 + tgparm->nudge; |
582 | tgparm->step = AIR_MIN(tgparm->initStep, tgparm->step)((tgparm->initStep) < (tgparm->step) ? (tgparm->initStep ) : (tgparm->step)); |
583 | pot = potNew; |
584 | angle = angleNew; |
585 | /* swap buffers */ |
586 | newIdx = 1 - newIdx; |
587 | oldIdx = 1 - oldIdx; |
588 | } else { |
589 | /* oops, did not make progress; back off and try again */ |
590 | if (tgparm->verbose) { |
591 | fprintf(stderr__stderrp, "%s(%d): ######## step %g --> %g\n" |
592 | " phi = %g --> %g ~ %g, angle = %g --> %g\n", |
593 | me, iter, tgparm->step, tgparm->step/2, |
594 | pot, potNew, potD, angle, angleNew); |
595 | } |
596 | tgparm->step /= 2; |
597 | tgparm->nudge /= 2; |
598 | } |
599 | } |
600 | |
601 | /* when the for-loop test fails, we stop before computing the next |
602 | iteration (which starts with copying from npos[oldIdx] to |
603 | npos[newIdx]) ==> the final results are in npos[oldIdx] */ |
604 | |
605 | if (tgparm->verbose) { |
606 | fprintf(stderr__stderrp, "%s: .......................... done distribution:\n" |
607 | " (%d && %d) || (%d \n" |
608 | " && (%d || %d || %d) \n" |
609 | " && (%d || %d) \n" |
610 | " && %d) is false\n", me, |
611 | !!tgparm->minIteration, iter < tgparm->minIteration, |
612 | iter < tgparm->maxIteration, |
613 | !tgparm->minPotentialChange, |
614 | !AIR_EXISTS(potD)(((int)(!((potD) - (potD))))), AIR_ABS(potD)((potD) > 0.0f ? (potD) : -(potD)) > tgparm->minPotentialChange, |
615 | !tgparm->minVelocity, meanVelocity > tgparm->minVelocity, |
616 | tgparm->step > FLT_MIN1.17549435e-38F); |
617 | fprintf(stderr__stderrp, " iter=%d, velo = %g<>%g, phi = %g ~ %g<>%g;\n", |
618 | iter, meanVelocity, tgparm->minVelocity, pot, |
619 | potD, tgparm->minPotentialChange); |
620 | fprintf(stderr__stderrp, " minEdge = %g; idealEdge = %g\n", |
621 | 2*sin(angle/2), tenGradientIdealEdge(num, tgparm->single)); |
622 | } |
623 | |
624 | tenGradientMeasure(&pot, NULL((void*)0), NULL((void*)0), npos[oldIdx], tgparm, AIR_FALSE0); |
625 | tgparm->potential = pot; |
626 | tenGradientMeasure(&pot, &angle, &edge, npos[oldIdx], tgparm, AIR_TRUE1); |
627 | tgparm->potentialNorm = pot; |
628 | tgparm->angle = angle; |
629 | tgparm->edge = edge; |
630 | tgparm->itersUsed = iter; |
631 | |
632 | if ((tgparm->minMeanImprovement || tgparm->minMean) |
633 | && !tgparm->single) { |
634 | if (tgparm->verbose) { |
635 | fprintf(stderr__stderrp, "%s: optimizing balance:\n", me); |
636 | } |
637 | if (tenGradientBalance(nout, npos[oldIdx], tgparm)) { |
638 | biffAddf(TENtenBiffKey, "%s: failed to minimize vector sum of gradients", me); |
639 | airMopError(mop); return 1; |
640 | } |
641 | if (tgparm->verbose) { |
642 | fprintf(stderr__stderrp, "%s: .......................... done balancing.\n", me); |
643 | } |
644 | } else { |
645 | if (tgparm->verbose) { |
646 | fprintf(stderr__stderrp, "%s: .......................... (no balancing)\n", me); |
647 | } |
648 | if (nrrdConvert(nout, npos[oldIdx], nrrdTypeDouble)) { |
649 | biffMovef(TENtenBiffKey, NRRDnrrdBiffKey, "%s: couldn't set output", me); |
650 | airMopError(mop); return 1; |
651 | } |
652 | } |
653 | |
654 | airMopOkay(mop); |
655 | return 0; |
656 | } |
657 | |
658 | /* |
659 | ** note that if tgparm->insertZeroVec, there will be one sample more |
660 | ** along axis 1 of nout than the requested #gradients "num" |
661 | */ |
662 | int |
663 | tenGradientGenerate(Nrrd *nout, unsigned int num, tenGradientParm *tgparm) { |
664 | static const char me[]="tenGradientGenerate"; |
665 | Nrrd *nin; |
666 | airArray *mop; |
667 | |
668 | if (!(nout && tgparm)) { |
669 | biffAddf(TENtenBiffKey, "%s: got NULL pointer", me); |
670 | return 1; |
671 | } |
672 | if (!( num >= 3 )) { |
673 | biffAddf(TENtenBiffKey, "%s: can generate minimum of 3 gradient directions " |
674 | "(not %d)", me, num); |
675 | return 1; |
676 | } |
677 | mop = airMopNew(); |
678 | nin = nrrdNew(); |
679 | airMopAdd(mop, nin, (airMopper)nrrdNuke, airMopAlways); |
680 | |
681 | if (tenGradientRandom(nin, num, tgparm->seed) |
682 | || tenGradientDistribute(nout, nin, tgparm)) { |
683 | biffAddf(TENtenBiffKey, "%s: trouble", me); |
684 | airMopError(mop); return 1; |
685 | } |
686 | if (tgparm->insertZeroVec) { |
687 | /* this is potentially confusing: the second axis (axis 1) |
688 | is going to come back one longer than the requested |
689 | number of gradients! */ |
690 | Nrrd *ntmp; |
691 | ptrdiff_t padMin[2] = {0, -1}, padMax[2]; |
692 | padMax[0] = AIR_CAST(ptrdiff_t, nout->axis[0].size-1)((ptrdiff_t)(nout->axis[0].size-1)); |
693 | padMax[1] = AIR_CAST(ptrdiff_t, num-1)((ptrdiff_t)(num-1)); |
694 | ntmp = nrrdNew(); |
695 | airMopAdd(mop, ntmp, (airMopper)nrrdNuke, airMopAlways); |
696 | if (nrrdPad_nva(ntmp, nout, padMin, padMax, |
697 | nrrdBoundaryPad, 0.0) |
698 | || nrrdCopy(nout, ntmp)) { |
699 | biffMovef(TENtenBiffKey, NRRDnrrdBiffKey, "%s: trouble adding zero vector", me); |
700 | airMopError(mop); return 1; |
701 | } |
702 | } |
703 | |
704 | airMopOkay(mop); |
705 | return 0; |
706 | } |