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 |
|
18 |
ret = (tenGradientParm *)calloc(1, sizeof(tenGradientParm)); |
32 |
✓✗ |
9 |
if (ret) { |
33 |
|
9 |
ret->initStep = 1.0; |
34 |
|
9 |
ret->jitter = 0.2; |
35 |
|
9 |
ret->minVelocity = 0.000000001; |
36 |
|
9 |
ret->minPotentialChange = 0.000000001; |
37 |
|
9 |
ret->minMean = 0.0001; |
38 |
|
9 |
ret->minMeanImprovement = 0.00005; |
39 |
|
9 |
ret->single = AIR_FALSE; |
40 |
|
9 |
ret->insertZeroVec = AIR_FALSE; |
41 |
|
9 |
ret->verbose = 1; |
42 |
|
9 |
ret->snap = 0; |
43 |
|
9 |
ret->report = 400; |
44 |
|
9 |
ret->expo = 1; |
45 |
|
9 |
ret->expo_d = 0; |
46 |
|
9 |
ret->seed = 42; |
47 |
|
9 |
ret->maxEdgeShrink = 20; |
48 |
|
9 |
ret->minIteration = 0; |
49 |
|
9 |
ret->maxIteration = 1000000; |
50 |
|
9 |
ret->step = 0; |
51 |
|
9 |
ret->nudge = 0; |
52 |
|
9 |
ret->itersUsed = 0; |
53 |
|
9 |
ret->potential = 0; |
54 |
|
9 |
ret->potentialNorm = 0; |
55 |
|
9 |
ret->angle = 0; |
56 |
|
9 |
ret->edge = 0; |
57 |
|
9 |
} |
58 |
|
9 |
return ret; |
59 |
|
|
} |
60 |
|
|
|
61 |
|
|
tenGradientParm * |
62 |
|
|
tenGradientParmNix(tenGradientParm *tgparm) { |
63 |
|
|
|
64 |
|
18 |
airFree(tgparm); |
65 |
|
9 |
return NULL; |
66 |
|
|
} |
67 |
|
|
|
68 |
|
|
int |
69 |
|
|
tenGradientCheck(const Nrrd *ngrad, int type, unsigned int minnum) { |
70 |
|
|
static const char me[]="tenGradientCheck"; |
71 |
|
|
|
72 |
✗✓ |
128 |
if (nrrdCheck(ngrad)) { |
73 |
|
|
biffMovef(TEN, NRRD, "%s: basic validity check failed", me); |
74 |
|
|
return 1; |
75 |
|
|
} |
76 |
✓✗✗✓
|
128 |
if (!( 3 == ngrad->axis[0].size && 2 == ngrad->dim )) { |
77 |
|
|
char stmp[AIR_STRLEN_SMALL]; |
78 |
|
|
biffAddf(TEN, "%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 |
✓✓✗✓
|
72 |
if (nrrdTypeDefault != type && type != ngrad->type) { |
83 |
|
|
biffAddf(TEN, "%s: requested type %s but got type %s", me, |
84 |
|
|
airEnumStr(nrrdType, type), airEnumStr(nrrdType, ngrad->type)); |
85 |
|
|
return 1; |
86 |
|
|
} |
87 |
✗✓ |
64 |
if (nrrdTypeBlock == ngrad->type) { |
88 |
|
|
biffAddf(TEN, "%s: sorry, can't use %s type", me, |
89 |
|
|
airEnumStr(nrrdType, nrrdTypeBlock)); |
90 |
|
|
return 1; |
91 |
|
|
} |
92 |
✗✓ |
64 |
if (!( minnum <= ngrad->axis[1].size )) { |
93 |
|
|
char stmp[AIR_STRLEN_SMALL]; |
94 |
|
|
biffAddf(TEN, "%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 |
|
64 |
return 0; |
100 |
|
64 |
} |
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 |
✗✓ |
8 |
if (nrrdMaybeAlloc_va(ngrad, nrrdTypeDouble, 2, |
114 |
|
16 |
AIR_CAST(size_t, 3), AIR_CAST(size_t, num))) { |
115 |
|
|
biffMovef(TEN, NRRD, "%s: couldn't allocate output", me); |
116 |
|
|
return 1; |
117 |
|
|
} |
118 |
|
8 |
airSrandMT(seed); |
119 |
|
8 |
grad = AIR_CAST(double*, ngrad->data); |
120 |
✓✓ |
176 |
for (gi=0; gi<num; gi++) { |
121 |
|
|
do { |
122 |
|
160 |
grad[0] = AIR_AFFINE(0, airDrandMT(), 1, -1, 1); |
123 |
|
160 |
grad[1] = AIR_AFFINE(0, airDrandMT(), 1, -1, 1); |
124 |
|
160 |
grad[2] = AIR_AFFINE(0, airDrandMT(), 1, -1, 1); |
125 |
|
160 |
len = ELL_3V_LEN(grad); |
126 |
✓✓✗✓
|
240 |
} while (len > 1 || !len); |
127 |
|
80 |
ELL_3V_SCALE(grad, 1.0/len, grad); |
128 |
|
80 |
grad += 3; |
129 |
|
|
} |
130 |
|
8 |
return 0; |
131 |
|
8 |
} |
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 |
|
15312 |
return sqrt((!single ? 4 : 8)*AIR_PI/(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 |
|
16 |
double *grad, perp0[3], perp1[3], len, theta, cc, ss, edge; |
157 |
|
|
unsigned int gi, num; |
158 |
|
|
|
159 |
✗✓ |
8 |
if (nrrdConvert(nout, nin, nrrdTypeDouble)) { |
160 |
|
|
biffMovef(TEN, NRRD, "%s: trouble converting input to double", me); |
161 |
|
|
return 1; |
162 |
|
|
} |
163 |
✗✓ |
8 |
if (tenGradientCheck(nout, nrrdTypeDouble, 3)) { |
164 |
|
|
biffAddf(TEN, "%s: didn't get valid gradients", me); |
165 |
|
|
return 1; |
166 |
|
|
} |
167 |
|
8 |
grad = AIR_CAST(double*, nout->data); |
168 |
|
8 |
num = AIR_UINT(nout->axis[1].size); |
169 |
|
|
/* HEY: possible confusion between single and not */ |
170 |
|
8 |
edge = tenGradientIdealEdge(num, AIR_FALSE); |
171 |
✓✓ |
176 |
for (gi=0; gi<num; gi++) { |
172 |
|
80 |
ELL_3V_NORM(grad, grad, len); |
173 |
|
80 |
ell_3v_perp_d(perp0, grad); |
174 |
|
80 |
ELL_3V_CROSS(perp1, perp0, grad); |
175 |
|
80 |
theta = AIR_AFFINE(0, airDrandMT(), 1, 0, 2*AIR_PI); |
176 |
|
80 |
cc = dist*edge*cos(theta); |
177 |
|
80 |
ss = dist*edge*sin(theta); |
178 |
|
80 |
ELL_3V_SCALE_ADD3(grad, 1.0, grad, cc, perp0, ss, perp1); |
179 |
|
80 |
ELL_3V_NORM(grad, grad, len); |
180 |
|
80 |
grad += 3; |
181 |
|
|
} |
182 |
|
|
|
183 |
|
8 |
return 0; |
184 |
|
8 |
} |
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 |
✗✓ |
7680 |
if (!(pot && npos && tgparm )) { |
196 |
|
|
return; |
197 |
|
|
} |
198 |
|
|
|
199 |
|
3840 |
num = AIR_UINT(npos->axis[1].size); |
200 |
|
3840 |
pos = AIR_CAST(double *, npos->data); |
201 |
✓✓ |
11512 |
edge = (edgeNormalize |
202 |
|
3832 |
? tenGradientIdealEdge(num, tgparm->single) |
203 |
|
|
: 1.0); |
204 |
|
3840 |
*pot = 0; |
205 |
✓✓ |
3840 |
if (minAngle) { |
206 |
|
3832 |
*minAngle = AIR_PI; |
207 |
|
3832 |
} |
208 |
✓✓ |
3840 |
if (minEdge) { |
209 |
|
8 |
*minEdge = 2; |
210 |
|
8 |
} |
211 |
✓✓ |
84480 |
for (ii=0; ii<num; ii++) { |
212 |
✓✓ |
422400 |
for (jj=0; jj<ii; jj++) { |
213 |
|
172800 |
ELL_3V_SUB(diff, pos + 3*ii, pos + 3*jj); |
214 |
|
172800 |
len = ELL_3V_LEN(diff); |
215 |
✓✓ |
172800 |
if (minEdge) { |
216 |
✓✓ |
1080 |
*minEdge = AIR_MIN(*minEdge, len); |
217 |
|
360 |
} |
218 |
✓✗✓✗
|
345600 |
if (tgparm->expo) { |
219 |
|
345600 |
ptmp = airIntPow(edge/len, tgparm->expo); |
220 |
|
172800 |
} else { |
221 |
|
|
ptmp = pow(edge/len, tgparm->expo_d); |
222 |
|
|
} |
223 |
|
172800 |
*pot += ptmp; |
224 |
✓✓ |
172800 |
if (minAngle) { |
225 |
|
172440 |
atmp = ell_3v_angle_d(pos + 3*ii, pos + 3*jj); |
226 |
✓✓ |
517320 |
*minAngle = AIR_MIN(atmp, *minAngle); |
227 |
|
172440 |
} |
228 |
✓✗ |
172800 |
if (!tgparm->single) { |
229 |
|
172800 |
*pot += ptmp; |
230 |
|
172800 |
ELL_3V_ADD2(diff, pos + 3*ii, pos + 3*jj); |
231 |
|
172800 |
len = ELL_3V_LEN(diff); |
232 |
✓✓ |
172800 |
if (minEdge) { |
233 |
✓✓ |
1080 |
*minEdge = AIR_MIN(*minEdge, len); |
234 |
|
360 |
} |
235 |
✓✗✓✗
|
345600 |
if (tgparm->expo) { |
236 |
|
345600 |
*pot += 2*airIntPow(edge/len, tgparm->expo); |
237 |
|
172800 |
} else { |
238 |
|
|
*pot += 2*pow(edge/len, tgparm->expo_d); |
239 |
|
|
} |
240 |
✓✓ |
172800 |
if (minAngle) { |
241 |
✓✓ |
517320 |
*minAngle = AIR_MIN(AIR_PI-atmp, *minAngle); |
242 |
|
172440 |
} |
243 |
|
|
} |
244 |
|
|
} |
245 |
|
|
} |
246 |
|
3840 |
return; |
247 |
|
3840 |
} |
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 |
|
7632 |
pos = AIR_CAST(double *, npos->data); |
290 |
|
3816 |
num = AIR_UINT(npos->axis[1].size); |
291 |
|
3816 |
*meanVel = 0; |
292 |
|
3816 |
*edgeMin = edge; |
293 |
✓✗ |
11448 |
expo = tgparm->expo ? tgparm->expo : tgparm->expo_d; |
294 |
✗✓ |
11448 |
limit = expo*AIR_MIN(sqrt(expo), |
295 |
|
|
log(1 + tgparm->initStep/tgparm->step)); |
296 |
✓✓ |
83952 |
for (ii=0; ii<num; ii++) { |
297 |
|
|
ELL_3V_SET(grad, 0, 0, 0); |
298 |
✓✓ |
839520 |
for (jj=0; jj<num; jj++) { |
299 |
✓✓ |
381600 |
if (ii == jj) { |
300 |
|
|
continue; |
301 |
|
|
} |
302 |
|
343440 |
ELL_3V_SUB(dir, pos + 3*ii, pos + 3*jj); |
303 |
|
343440 |
ELL_3V_NORM(dir, dir, len); |
304 |
✓✓ |
1030320 |
*edgeMin = AIR_MIN(*edgeMin, len); |
305 |
✓✗✓✗
|
686880 |
if (tgparm->expo) { |
306 |
|
686880 |
rep = airIntPow(edge/len, tgparm->expo+1); |
307 |
|
343440 |
} else { |
308 |
|
|
rep = pow(edge/len, tgparm->expo_d+1); |
309 |
|
|
} |
310 |
|
343440 |
ELL_3V_SCALE_INCR(grad, rep/num, dir); |
311 |
✓✗ |
343440 |
if (!tgparm->single) { |
312 |
|
343440 |
ELL_3V_ADD2(dir, pos + 3*ii, pos + 3*jj); |
313 |
|
343440 |
ELL_3V_NORM(dir, dir, len); |
314 |
✓✓ |
1030320 |
*edgeMin = AIR_MIN(*edgeMin, len); |
315 |
✓✗✓✗
|
686880 |
if (tgparm->expo) { |
316 |
|
686880 |
rep = airIntPow(edge/len, tgparm->expo+1); |
317 |
|
343440 |
} else { |
318 |
|
|
rep = pow(edge/len, tgparm->expo_d+1); |
319 |
|
|
} |
320 |
|
343440 |
ELL_3V_SCALE_INCR(grad, rep/num, dir); |
321 |
|
343440 |
} |
322 |
|
|
} |
323 |
|
38160 |
ELL_3V_NORM(ngrad, grad, len); |
324 |
✗✓ |
38160 |
if (!( AIR_EXISTS(len) )) { |
325 |
|
|
/* things blew up, either in incremental force |
326 |
|
|
additions, or in the attempt at normalization */ |
327 |
|
|
E = 1; |
328 |
|
|
*meanVel = AIR_NAN; |
329 |
|
|
break; |
330 |
|
|
} |
331 |
✗✓ |
38160 |
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); |
335 |
|
|
} |
336 |
✓✓ |
114480 |
step = AIR_MIN(len*tgparm->step, edge/limit); |
337 |
|
38160 |
ELL_3V_SCALE_ADD2(newpos, |
338 |
|
|
1.0, pos + 3*ii, |
339 |
|
|
step, ngrad); |
340 |
|
38160 |
ELL_3V_NORM(newpos, newpos, len); |
341 |
|
38160 |
ELL_3V_SUB(diff, pos + 3*ii, newpos); |
342 |
|
38160 |
*meanVel += ELL_3V_LEN(diff); |
343 |
|
38160 |
ELL_3V_COPY(pos + 3*ii, newpos); |
344 |
|
|
} |
345 |
|
3816 |
*meanVel /= num; |
346 |
|
|
|
347 |
|
3816 |
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 |
|
560 |
pos = (double *)(npos->data); |
360 |
|
280 |
num = AIR_UINT(npos->axis[1].size); |
361 |
|
280 |
rnd = airUIrandMT_r(rstate); |
362 |
|
|
rndBit = 0; |
363 |
|
|
ELL_3V_SET(mean, 0, 0, 0); |
364 |
✓✓ |
6160 |
for (ii=0; ii<num; ii++) { |
365 |
✗✓ |
2800 |
if (32 == rndBit) { |
366 |
|
|
rnd = airUIrandMT_r(rstate); |
367 |
|
|
rndBit = 0; |
368 |
|
|
} |
369 |
✓✓ |
2800 |
if (rnd & (1 << rndBit++)) { |
370 |
|
1384 |
ELL_3V_SCALE(pos + 3*ii, -1, pos + 3*ii); |
371 |
|
1384 |
} |
372 |
|
2800 |
ELL_3V_INCR(mean, pos + 3*ii); |
373 |
|
|
} |
374 |
|
280 |
ELL_3V_SCALE(mean, 1.0/num, mean); |
375 |
|
280 |
return ELL_3V_LEN(mean); |
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 |
✓✗✗✓
|
24 |
if (!nout || tenGradientCheck(nin, nrrdTypeUnknown, 2) || !tgparm) { |
393 |
|
|
biffAddf(TEN, "%s: got NULL pointer (%p,%p) or invalid nin", me, |
394 |
|
|
AIR_VOIDP(nout), AIR_VOIDP(tgparm)); |
395 |
|
|
return 1; |
396 |
|
|
} |
397 |
✗✓ |
8 |
if (nrrdConvert(nout, nin, nrrdTypeDouble)) { |
398 |
|
|
biffMovef(TEN, NRRD, "%s: can't initialize output with input", me); |
399 |
|
|
return 1; |
400 |
|
|
} |
401 |
|
|
|
402 |
|
8 |
mop = airMopNew(); |
403 |
|
8 |
ncopy = nrrdNew(); |
404 |
|
8 |
airMopAdd(mop, ncopy, (airMopper)nrrdNuke, airMopAlways); |
405 |
|
8 |
rstate = airRandMTStateNew(tgparm->seed); |
406 |
|
8 |
airMopAdd(mop, rstate, (airMopper)airRandMTStateNix, airMopAlways); |
407 |
|
|
/* HEY: factor of 100 is an approximate hack */ |
408 |
|
8 |
maxIter = 100*tgparm->maxIteration; |
409 |
|
|
|
410 |
|
|
lastLen = 1.0; |
411 |
|
|
done = AIR_FALSE; |
412 |
|
8 |
do { |
413 |
|
|
iter = 0; |
414 |
|
40 |
do { |
415 |
|
280 |
iter++; |
416 |
|
280 |
len = party(nout, rstate); |
417 |
✓✓✓✗
|
520 |
} while (len > lastLen && iter < maxIter); |
418 |
✗✓ |
40 |
if (iter >= maxIter) { |
419 |
|
|
if (tgparm->verbose) { |
420 |
|
|
fprintf(stderr, "%s: stopping at max iter %u\n", me, maxIter); |
421 |
|
|
} |
422 |
|
|
if (nrrdCopy(nout, ncopy)) { |
423 |
|
|
biffMovef(TEN, NRRD, "%s: trouble copying", me); |
424 |
|
|
airMopError(mop); return 1; |
425 |
|
|
} |
426 |
|
|
done = AIR_TRUE; |
427 |
|
|
} else { |
428 |
✗✓ |
40 |
if (nrrdCopy(ncopy, nout)) { |
429 |
|
|
biffMovef(TEN, NRRD, "%s: trouble copying", me); |
430 |
|
|
airMopError(mop); return 1; |
431 |
|
|
} |
432 |
|
40 |
improv = lastLen - len; |
433 |
|
|
lastLen = len; |
434 |
✗✓ |
40 |
if (tgparm->verbose) { |
435 |
|
|
fprintf(stderr, "%s: (iter %u) improvement: %g (mean length = %g)\n", |
436 |
|
|
me, iter, improv, len); |
437 |
|
|
} |
438 |
|
40 |
done = (improv <= tgparm->minMeanImprovement |
439 |
✓✓ |
112 |
|| len < tgparm->minMean); |
440 |
|
|
} |
441 |
✓✓ |
40 |
} while (!done); |
442 |
|
|
|
443 |
|
8 |
airMopOkay(mop); |
444 |
|
8 |
return 0; |
445 |
|
8 |
} |
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 |
|
16 |
char filename[AIR_STRLEN_SMALL]; |
471 |
|
|
unsigned int ii, num, iter, oldIdx, newIdx, edgeShrink; |
472 |
|
|
airArray *mop; |
473 |
|
8 |
Nrrd *npos[2]; |
474 |
|
8 |
double *pos, len, meanVelocity, pot, potNew, potD, |
475 |
|
|
edge, edgeMin, angle, angleNew; |
476 |
|
|
int E; |
477 |
|
|
|
478 |
✓✗✗✓
|
16 |
if (!nout || tenGradientCheck(nin, nrrdTypeUnknown, 2) || !tgparm) { |
479 |
|
|
biffAddf(TEN, "%s: got NULL pointer or invalid input", me); |
480 |
|
|
return 1; |
481 |
|
|
} |
482 |
|
|
|
483 |
|
8 |
num = AIR_UINT(nin->axis[1].size); |
484 |
|
8 |
mop = airMopNew(); |
485 |
|
8 |
npos[0] = nrrdNew(); |
486 |
|
8 |
npos[1] = nrrdNew(); |
487 |
|
8 |
airMopAdd(mop, npos[0], (airMopper)nrrdNuke, airMopAlways); |
488 |
|
8 |
airMopAdd(mop, npos[1], (airMopper)nrrdNuke, airMopAlways); |
489 |
✗✓ |
16 |
if (nrrdConvert(npos[0], nin, nrrdTypeDouble) |
490 |
✓✗ |
16 |
|| nrrdConvert(npos[1], nin, nrrdTypeDouble)) { |
491 |
|
|
biffMovef(TEN, NRRD, "%s: trouble allocating temp buffers", me); |
492 |
|
|
airMopError(mop); return 1; |
493 |
|
|
} |
494 |
|
|
|
495 |
|
8 |
pos = (double*)(npos[0]->data); |
496 |
✓✓ |
176 |
for (ii=0; ii<num; ii++) { |
497 |
|
80 |
ELL_3V_NORM(pos, pos, len); |
498 |
|
80 |
pos += 3; |
499 |
|
|
} |
500 |
✓✗ |
8 |
if (tgparm->jitter) { |
501 |
✗✓ |
8 |
if (tenGradientJitter(npos[0], npos[0], tgparm->jitter)) { |
502 |
|
|
biffAddf(TEN, "%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 |
|
8 |
meanVelocity = 2*tgparm->minVelocity; |
510 |
|
8 |
potD = -2*tgparm->minPotentialChange; |
511 |
|
|
oldIdx = 0; |
512 |
|
|
newIdx = 1; |
513 |
|
8 |
tgparm->step = tgparm->initStep; |
514 |
|
8 |
tgparm->nudge = 0.1; |
515 |
|
8 |
tenGradientMeasure(&pot, &angle, NULL, |
516 |
|
8 |
npos[oldIdx], tgparm, AIR_TRUE); |
517 |
✓✗ |
7640 |
for (iter = 0; |
518 |
✗✓ |
3824 |
((!!tgparm->minIteration && iter < tgparm->minIteration) |
519 |
|
|
|| |
520 |
|
3824 |
(iter < tgparm->maxIteration |
521 |
✓✗ |
7648 |
&& (!tgparm->minPotentialChange |
522 |
✓✗ |
7648 |
|| !AIR_EXISTS(potD) |
523 |
✓✗ |
7648 |
|| -potD > tgparm->minPotentialChange) |
524 |
✓✓ |
7640 |
&& (!tgparm->minVelocity |
525 |
✓✗ |
7632 |
|| meanVelocity > tgparm->minVelocity) |
526 |
✓✗ |
7632 |
&& tgparm->step > FLT_MIN)); |
527 |
|
3816 |
iter++) { |
528 |
|
|
/* copy positions from old to new */ |
529 |
|
3816 |
memcpy(npos[newIdx]->data, npos[oldIdx]->data, 3*num*sizeof(double)); |
530 |
|
3816 |
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 |
|
3816 |
do { |
536 |
|
3816 |
E = _tenGradientUpdate(&meanVelocity, &edgeMin, |
537 |
|
3816 |
npos[newIdx], edge, tgparm); |
538 |
✗✓ |
3816 |
if (E) { |
539 |
|
|
if (edgeShrink > tgparm->maxEdgeShrink) { |
540 |
|
|
biffAddf(TEN, "%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)); |
547 |
|
|
edge = edgeMin; |
548 |
|
|
} |
549 |
✗✓ |
3816 |
} while (E); |
550 |
|
3816 |
tenGradientMeasure(&potNew, &angleNew, NULL, |
551 |
|
3816 |
npos[newIdx], tgparm, AIR_TRUE); |
552 |
✓✗✓✗ ✗✗ |
11448 |
if ((AIR_EXISTS(pot) && AIR_EXISTS(potNew) && potNew <= pot) |
553 |
✗✓ |
3816 |
|| angleNew >= angle) { |
554 |
|
|
/* there was progress of some kind, either through potential |
555 |
|
|
decrease, or angle increase */ |
556 |
|
3816 |
potD = 2*(potNew - pot)/(potNew + pot); |
557 |
✓✓✗✓
|
3832 |
if (!(iter % tgparm->report) && tgparm->verbose) { |
558 |
|
|
fprintf(stderr, "%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 |
✗✓✗✗
|
3816 |
if (tgparm->snap && !(iter % tgparm->snap)) { |
566 |
|
|
sprintf(filename, "%05d.nrrd", iter/tgparm->snap); |
567 |
|
|
if (tgparm->verbose) { |
568 |
|
|
fprintf(stderr, "%s(%d): . . . . . . saving %s\n", |
569 |
|
|
me, iter, filename); |
570 |
|
|
} |
571 |
|
|
if (nrrdSave(filename, npos[newIdx], NULL)) { |
572 |
|
|
char *serr; |
573 |
|
|
serr = biffGetDone(NRRD); |
574 |
|
|
if (tgparm->verbose) { /* perhaps shouldn't have this check */ |
575 |
|
|
fprintf(stderr, "%s: iter=%d, couldn't save snapshot:\n%s" |
576 |
|
|
"continuing ...\n", me, iter, serr); |
577 |
|
|
} |
578 |
|
|
free(serr); |
579 |
|
|
} |
580 |
|
|
} |
581 |
|
3816 |
tgparm->step *= 1 + tgparm->nudge; |
582 |
✓✗ |
11448 |
tgparm->step = AIR_MIN(tgparm->initStep, tgparm->step); |
583 |
|
3816 |
pot = potNew; |
584 |
|
3816 |
angle = angleNew; |
585 |
|
|
/* swap buffers */ |
586 |
|
3816 |
newIdx = 1 - newIdx; |
587 |
|
3816 |
oldIdx = 1 - oldIdx; |
588 |
|
3816 |
} else { |
589 |
|
|
/* oops, did not make progress; back off and try again */ |
590 |
|
|
if (tgparm->verbose) { |
591 |
|
|
fprintf(stderr, "%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 |
✗✓ |
8 |
if (tgparm->verbose) { |
606 |
|
|
fprintf(stderr, "%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), AIR_ABS(potD) > tgparm->minPotentialChange, |
615 |
|
|
!tgparm->minVelocity, meanVelocity > tgparm->minVelocity, |
616 |
|
|
tgparm->step > FLT_MIN); |
617 |
|
|
fprintf(stderr, " iter=%d, velo = %g<>%g, phi = %g ~ %g<>%g;\n", |
618 |
|
|
iter, meanVelocity, tgparm->minVelocity, pot, |
619 |
|
|
potD, tgparm->minPotentialChange); |
620 |
|
|
fprintf(stderr, " minEdge = %g; idealEdge = %g\n", |
621 |
|
|
2*sin(angle/2), tenGradientIdealEdge(num, tgparm->single)); |
622 |
|
|
} |
623 |
|
|
|
624 |
|
8 |
tenGradientMeasure(&pot, NULL, NULL, npos[oldIdx], tgparm, AIR_FALSE); |
625 |
|
8 |
tgparm->potential = pot; |
626 |
|
8 |
tenGradientMeasure(&pot, &angle, &edge, npos[oldIdx], tgparm, AIR_TRUE); |
627 |
|
8 |
tgparm->potentialNorm = pot; |
628 |
|
8 |
tgparm->angle = angle; |
629 |
|
8 |
tgparm->edge = edge; |
630 |
|
8 |
tgparm->itersUsed = iter; |
631 |
|
|
|
632 |
✗✓✓✗
|
16 |
if ((tgparm->minMeanImprovement || tgparm->minMean) |
633 |
✗✗ |
8 |
&& !tgparm->single) { |
634 |
✗✓ |
8 |
if (tgparm->verbose) { |
635 |
|
|
fprintf(stderr, "%s: optimizing balance:\n", me); |
636 |
|
|
} |
637 |
✗✓ |
8 |
if (tenGradientBalance(nout, npos[oldIdx], tgparm)) { |
638 |
|
|
biffAddf(TEN, "%s: failed to minimize vector sum of gradients", me); |
639 |
|
|
airMopError(mop); return 1; |
640 |
|
|
} |
641 |
✗✓ |
8 |
if (tgparm->verbose) { |
642 |
|
|
fprintf(stderr, "%s: .......................... done balancing.\n", me); |
643 |
|
|
} |
644 |
|
|
} else { |
645 |
|
|
if (tgparm->verbose) { |
646 |
|
|
fprintf(stderr, "%s: .......................... (no balancing)\n", me); |
647 |
|
|
} |
648 |
|
|
if (nrrdConvert(nout, npos[oldIdx], nrrdTypeDouble)) { |
649 |
|
|
biffMovef(TEN, NRRD, "%s: couldn't set output", me); |
650 |
|
|
airMopError(mop); return 1; |
651 |
|
|
} |
652 |
|
|
} |
653 |
|
|
|
654 |
|
8 |
airMopOkay(mop); |
655 |
|
8 |
return 0; |
656 |
|
8 |
} |
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 |
✗✓ |
16 |
if (!(nout && tgparm)) { |
669 |
|
|
biffAddf(TEN, "%s: got NULL pointer", me); |
670 |
|
|
return 1; |
671 |
|
|
} |
672 |
✗✓ |
8 |
if (!( num >= 3 )) { |
673 |
|
|
biffAddf(TEN, "%s: can generate minimum of 3 gradient directions " |
674 |
|
|
"(not %d)", me, num); |
675 |
|
|
return 1; |
676 |
|
|
} |
677 |
|
8 |
mop = airMopNew(); |
678 |
|
8 |
nin = nrrdNew(); |
679 |
|
8 |
airMopAdd(mop, nin, (airMopper)nrrdNuke, airMopAlways); |
680 |
|
|
|
681 |
✗✓ |
16 |
if (tenGradientRandom(nin, num, tgparm->seed) |
682 |
✓✗ |
16 |
|| tenGradientDistribute(nout, nin, tgparm)) { |
683 |
|
|
biffAddf(TEN, "%s: trouble", me); |
684 |
|
|
airMopError(mop); return 1; |
685 |
|
|
} |
686 |
✓✗ |
8 |
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 |
|
8 |
ptrdiff_t padMin[2] = {0, -1}, padMax[2]; |
692 |
|
8 |
padMax[0] = AIR_CAST(ptrdiff_t, nout->axis[0].size-1); |
693 |
|
8 |
padMax[1] = AIR_CAST(ptrdiff_t, num-1); |
694 |
|
8 |
ntmp = nrrdNew(); |
695 |
|
8 |
airMopAdd(mop, ntmp, (airMopper)nrrdNuke, airMopAlways); |
696 |
✗✓ |
16 |
if (nrrdPad_nva(ntmp, nout, padMin, padMax, |
697 |
|
|
nrrdBoundaryPad, 0.0) |
698 |
✓✗ |
16 |
|| nrrdCopy(nout, ntmp)) { |
699 |
|
|
biffMovef(TEN, NRRD, "%s: trouble adding zero vector", me); |
700 |
|
|
airMopError(mop); return 1; |
701 |
|
|
} |
702 |
✓✗ |
16 |
} |
703 |
|
|
|
704 |
|
8 |
airMopOkay(mop); |
705 |
|
8 |
return 0; |
706 |
|
8 |
} |