File: | src/pull/constraints.c |
Location: | line 398, column 10 |
Description: | Value stored to '_tmpv' during its initialization 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 "pull.h" |
26 | #include "privatePull.h" |
27 | |
28 | #define DEBUG(0) (0) |
29 | /* #define DEBUG (12 == point->idtag) */ |
30 | |
31 | /* |
32 | typedef struct { |
33 | double val, absval, grad[3]; |
34 | } stateIso; |
35 | |
36 | static int |
37 | probeIso(pullTask *task, pullPoint *point, unsigned int iter, int cond, |
38 | double pos[3], |
39 | stateIso *state) { |
40 | static const char me[]="probeIso"; |
41 | |
42 | ELL_3V_COPY(point->pos, pos); / * NB: not touching point->pos[3] * / |
43 | _pullPointHistAdd(point, cond, AIR_NAN); |
44 | if (pullProbe(task, point)) { |
45 | biffAddf(PULL, "%s: on iter %u", me, iter); |
46 | return 1; |
47 | } |
48 | state->val = pullPointScalar(task->pctx, point, |
49 | pullInfoIsovalue, |
50 | state->grad, NULL); |
51 | state->absval = AIR_ABS(state->val); |
52 | return 0; |
53 | } |
54 | */ |
55 | |
56 | /* NOTE: this assumes variables "iter" (uint) and "me" (char*) */ |
57 | #define NORMALIZE_ERR(dir, grad, len)if (task->pctx->flag.zeroZ) grad[2]=0; ((len) = (sqrt(( (((grad)))[0]*(((grad)))[0] + (((grad)))[1]*(((grad)))[1] + ( ((grad)))[2]*(((grad)))[2]))), (((dir))[0] = (1.0/(len))*((grad ))[0], ((dir))[1] = (1.0/(len))*((grad))[1], ((dir))[2] = (1.0 /(len))*((grad))[2])); if (!(len)) { biffAddf(pullBiffKey, "%s: got zero grad at (%g,%g,%g,%g) on iter %u\n" , me, point->pos[0], point->pos[1], point->pos[2], point ->pos[3], iter); return 1; } \ |
58 | if (task->pctx->flag.zeroZ) grad[2]=0; \ |
59 | ELL_3V_NORM((dir), (grad), (len))((len) = (sqrt(((((grad)))[0]*(((grad)))[0] + (((grad)))[1]*( ((grad)))[1] + (((grad)))[2]*(((grad)))[2]))), (((dir))[0] = ( 1.0/(len))*((grad))[0], ((dir))[1] = (1.0/(len))*((grad))[1], ((dir))[2] = (1.0/(len))*((grad))[2])); \ |
60 | if (!(len)) { \ |
61 | biffAddf(PULLpullBiffKey, "%s: got zero grad at (%g,%g,%g,%g) on iter %u\n", me,\ |
62 | point->pos[0], point->pos[1], point->pos[2], \ |
63 | point->pos[3], iter); \ |
64 | return 1; \ |
65 | } |
66 | |
67 | #define NORMALIZE(dir, grad, len) \ |
68 | if (task->pctx->flag.zeroZ) grad[2]=0; \ |
69 | ELL_3V_NORM((dir), (grad), (len))((len) = (sqrt(((((grad)))[0]*(((grad)))[0] + (((grad)))[1]*( ((grad)))[1] + (((grad)))[2]*(((grad)))[2]))), (((dir))[0] = ( 1.0/(len))*((grad))[0], ((dir))[1] = (1.0/(len))*((grad))[1], ((dir))[2] = (1.0/(len))*((grad))[2])); \ |
70 | if (!(len)) { \ |
71 | ELL_3V_SET((dir), 0, 0, 0)(((dir))[0] = (0), ((dir))[1] = (0), ((dir))[2] = (0)) ; \ |
72 | } |
73 | |
74 | |
75 | /* ------------------------------- isosurface */ |
76 | |
77 | |
78 | |
79 | #define PROBE(v, av, g) if (pullProbe(task, point)) { \ |
80 | biffAddf(PULLpullBiffKey, "%s: on iter %u", me, iter); \ |
81 | return 1; \ |
82 | } \ |
83 | (v) = pullPointScalar(task->pctx, point, \ |
84 | pullInfoIsovalue, (g), NULL((void*)0)); \ |
85 | (av) = AIR_ABS(v)((v) > 0.0f ? (v) : -(v)) |
86 | #define SAVE(state, aval, val, grad, pos) \ |
87 | state[0] = aval; \ |
88 | state[1] = val; \ |
89 | ELL_3V_COPY(state + 1 + 1, grad)((state + 1 + 1)[0] = (grad)[0], (state + 1 + 1)[1] = (grad)[ 1], (state + 1 + 1)[2] = (grad)[2]); \ |
90 | ELL_3V_COPY(state + 1 + 1 + 3, pos)((state + 1 + 1 + 3)[0] = (pos)[0], (state + 1 + 1 + 3)[1] = ( pos)[1], (state + 1 + 1 + 3)[2] = (pos)[2]) |
91 | #define RESTORE(aval, val, grad, pos, state) \ |
92 | aval = state[0]; \ |
93 | val = state[1]; \ |
94 | ELL_3V_COPY(grad, state + 1 + 1)((grad)[0] = (state + 1 + 1)[0], (grad)[1] = (state + 1 + 1)[ 1], (grad)[2] = (state + 1 + 1)[2]); \ |
95 | ELL_3V_COPY(pos, state + 1 + 1 + 3)((pos)[0] = (state + 1 + 1 + 3)[0], (pos)[1] = (state + 1 + 1 + 3)[1], (pos)[2] = (state + 1 + 1 + 3)[2]) |
96 | |
97 | static int |
98 | constraintSatIso(pullTask *task, pullPoint *point, |
99 | double stepMax, double constrEps, |
100 | unsigned int iterMax, |
101 | /* output */ |
102 | int *constrFailP) { |
103 | static const char me[]="constraintSatIso"; |
104 | double |
105 | step, /* current step size */ |
106 | val, aval, /* last and current function values */ |
107 | hack, /* how to control re-tries in the context of a single |
108 | for-loop, instead of a nested do-while loop */ |
109 | grad[4], dir[3], len, state[1 + 1 + 3 + 3]; |
110 | unsigned int iter = 0; /* 0: initial probe, 1..iterMax: probes in loop */ |
111 | |
112 | PROBE(val, aval, grad); |
113 | SAVE(state, aval, val, grad, point->pos); |
114 | hack = 1; |
115 | for (iter=1; iter<=iterMax; iter++) { |
116 | /* consider? http://en.wikipedia.org/wiki/Halley%27s_method */ |
117 | NORMALIZE(dir, grad, len); |
118 | if (!len) { |
119 | /* no gradient; back off */ |
120 | hack *= task->pctx->sysParm.backStepScale; |
121 | RESTORE(aval, val, grad, point->pos, state); |
122 | continue; |
123 | } |
124 | step = -val/len; /* the newton-raphson step */ |
125 | step = step > 0 ? AIR_MIN(stepMax, step)((stepMax) < (step) ? (stepMax) : (step)) : AIR_MAX(-stepMax, step)((-stepMax) > (step) ? (-stepMax) : (step)); |
126 | ELL_3V_SCALE_INCR(point->pos, hack*step, dir)((point->pos)[0] += (hack*step)*(dir)[0], (point->pos)[ 1] += (hack*step)*(dir)[1], (point->pos)[2] += (hack*step) *(dir)[2]); |
127 | PROBE(val, aval, grad); |
128 | _pullPointHistAdd(point, pullCondConstraintSatA, val); |
129 | if (aval <= state[0]) { /* we're no further from the root */ |
130 | if (AIR_ABS(step)((step) > 0.0f ? (step) : -(step)) < stepMax*constrEps) { /* HEY stepMax*constrEps vs constrEps */ |
131 | /* we have converged! */ |
132 | break; |
133 | } |
134 | SAVE(state, aval, val, grad, point->pos); |
135 | hack = 1; |
136 | } else { /* oops, try again, don't update dir or len, reset val */ |
137 | hack *= task->pctx->sysParm.backStepScale; |
138 | RESTORE(aval, val, grad, point->pos, state); |
139 | } |
140 | } |
141 | if (iter > iterMax) { |
142 | *constrFailP = pullConstraintFailIterMaxed; |
143 | } else { |
144 | *constrFailP = AIR_FALSE0; |
145 | } |
146 | return 0; |
147 | } |
148 | |
149 | #undef PROBE |
150 | #undef SAVE |
151 | #undef RESTORE |
152 | |
153 | |
154 | |
155 | /* ------------------------------- laplacian */ |
156 | |
157 | |
158 | |
159 | #define PROBE(l) if (pullProbe(task, point)) { \ |
160 | biffAddf(PULLpullBiffKey, "%s: on iter %u", me, iter); \ |
161 | return 1; \ |
162 | } \ |
163 | (l) = pullPointScalar(task->pctx, point, \ |
164 | pullInfoHeightLaplacian, NULL((void*)0), NULL((void*)0)); |
165 | #define PROBEG(l, g) \ |
166 | PROBE(l); \ |
167 | pullPointScalar(task->pctx, point, pullInfoHeight, (g), NULL((void*)0)); |
168 | |
169 | static int |
170 | constraintSatLapl(pullTask *task, pullPoint *point, |
171 | double stepMax, double constrEps, |
172 | unsigned int iterMax, |
173 | /* output */ |
174 | int *constrFailP) { |
175 | static const char me[]="constraintSatLapl"; |
176 | double |
177 | step, /* current step size */ |
178 | valLast, val, /* last and current function values */ |
179 | grad[4], dir[3], len, |
180 | posOld[3], posNew[3], tmpv[3]; |
181 | double a=0, b=1, s, fa, fb, fs, tmp, diff; |
182 | int side = 0; |
183 | unsigned int iter = 0; /* 0: initial probe, 1..iterMax: probes in loop */ |
184 | |
185 | step = stepMax/2; |
186 | PROBEG(val, grad); |
187 | if (0 == val) { |
188 | /* already exactly at the zero, we're done. This actually happens! */ |
189 | /* printf("!%s: a lapl == 0!\n", me); */ |
190 | return 0; |
191 | } |
192 | valLast = val; |
193 | NORMALIZE(dir, grad, len); |
194 | /* first phase: follow normalized gradient until laplacian sign change */ |
195 | for (iter=1; iter<=iterMax; iter++) { |
196 | double sgn; |
197 | ELL_3V_COPY(posOld, point->pos)((posOld)[0] = (point->pos)[0], (posOld)[1] = (point->pos )[1], (posOld)[2] = (point->pos)[2]); |
198 | sgn = airSgn(val); /* lapl < 0 => downhill; lapl > 0 => uphill */ |
199 | ELL_3V_SCALE_INCR(point->pos, sgn*step, dir)((point->pos)[0] += (sgn*step)*(dir)[0], (point->pos)[1 ] += (sgn*step)*(dir)[1], (point->pos)[2] += (sgn*step)*(dir )[2]); |
200 | PROBEG(val, grad); |
201 | _pullPointHistAdd(point, pullCondConstraintSatA, val); |
202 | if (val*valLast < 0) { |
203 | /* laplacian has changed sign; stop looking */ |
204 | break; |
205 | } |
206 | valLast = val; |
207 | NORMALIZE(dir, grad, len); |
208 | } |
209 | if (iter > iterMax) { |
210 | *constrFailP = pullConstraintFailIterMaxed; |
211 | return 0; |
212 | } |
213 | /* second phase: find the zero-crossing, looking between |
214 | f(posOld)=valLast and f(posNew)=val */ |
215 | ELL_3V_COPY(posNew, point->pos)((posNew)[0] = (point->pos)[0], (posNew)[1] = (point->pos )[1], (posNew)[2] = (point->pos)[2]); |
216 | ELL_3V_SUB(tmpv, posNew, posOld)((tmpv)[0] = (posNew)[0] - (posOld)[0], (tmpv)[1] = (posNew)[ 1] - (posOld)[1], (tmpv)[2] = (posNew)[2] - (posOld)[2]); |
217 | len = ELL_3V_LEN(tmpv)(sqrt((((tmpv))[0]*((tmpv))[0] + ((tmpv))[1]*((tmpv))[1] + (( tmpv))[2]*((tmpv))[2]))); |
218 | fa = valLast; |
219 | fb = val; |
220 | if (AIR_ABS(fa)((fa) > 0.0f ? (fa) : -(fa)) < AIR_ABS(fb)((fb) > 0.0f ? (fb) : -(fb))) { |
221 | ELL_SWAP2(a, b, tmp)((tmp)=(a),(a)=(b),(b)=(tmp)); ELL_SWAP2(fa, fb, tmp)((tmp)=(fa),(fa)=(fb),(fb)=(tmp)); |
222 | } |
223 | for (iter=1; iter<=iterMax; iter++) { |
224 | s = AIR_AFFINE(fa, 0, fb, a, b)( ((double)(b)-(a))*((double)(0)-(fa)) / ((double)(fb)-(fa)) + (a)); |
225 | ELL_3V_LERP(point->pos, s, posOld, posNew)((point->pos)[0] = (((s))*(((posNew)[0]) - ((posOld)[0])) + ((posOld)[0])), (point->pos)[1] = (((s))*(((posNew)[1]) - ((posOld)[1])) + ((posOld)[1])), (point->pos)[2] = (((s)) *(((posNew)[2]) - ((posOld)[2])) + ((posOld)[2]))); |
226 | PROBE(fs); |
227 | _pullPointHistAdd(point, pullCondConstraintSatB, 0.0); |
228 | if (0 == fs) { |
229 | /* exactly nailed the zero, we're done. This actually happens! */ |
230 | printf("!%s: b lapl == 0!\n", me); |
231 | break; |
232 | } |
233 | /* "Illinois" false-position. Dumb, but it works. */ |
234 | if (fs*fb > 0) { /* not between s and b */ |
235 | b = s; |
236 | fb = fs; |
237 | if (+1 == side) { |
238 | fa /= 2; |
239 | } |
240 | side = +1; |
241 | } else { /* not between a and s */ |
242 | a = s; |
243 | fa = fs; |
244 | if (-1 == side) { |
245 | fb /= 2; |
246 | } |
247 | side = -1; |
248 | } |
249 | diff = (b - a)*len; |
250 | if (AIR_ABS(diff)((diff) > 0.0f ? (diff) : -(diff)) < stepMax*constrEps) { /* HEY stepMax*constrEps vs constrEps */ |
251 | /* converged! */ |
252 | break; |
253 | } |
254 | } |
255 | if (iter > iterMax) { |
256 | *constrFailP = pullConstraintFailIterMaxed; |
257 | } else { |
258 | *constrFailP = AIR_FALSE0; |
259 | } |
260 | return 0; |
261 | } |
262 | #undef PROBE |
263 | #undef PROBEG |
264 | |
265 | |
266 | /* ------------------------------------------- height (line xor surf) */ |
267 | |
268 | static int |
269 | probeHeight(pullTask *task, pullPoint *point, |
270 | /* output */ |
271 | double *heightP, double grad[3], double hess[9]) { |
272 | static const char me[]="probeHeight"; |
273 | |
274 | if (pullProbe(task, point)) { |
275 | biffAddf(PULLpullBiffKey, "%s: trouble", me); |
276 | return 1; |
277 | } |
278 | *heightP = pullPointScalar(task->pctx, point, pullInfoHeight, grad, hess); |
279 | return 0; |
280 | } |
281 | |
282 | /* |
283 | ** creaseProj |
284 | ** |
285 | ** column-space of output posproj spans the directions along which |
286 | ** particle is allowed to move *downward* (in height) for constraint |
287 | ** satisfaction (according to tangent 1 or tangents 1&2); for seeking |
288 | ** minima where 2nd deriv is positive |
289 | ** |
290 | ** negproj is the same, but for points moving upwards (according to |
291 | ** negativetangent1 or negativetangent 1&2); for seeking |
292 | ** maxima where 2nd deriv is negative |
293 | */ |
294 | static void |
295 | creaseProj(pullTask *task, pullPoint *point, |
296 | int tang1Use, int tang2Use, |
297 | int negtang1Use, int negtang2Use, |
298 | /* output */ |
299 | double posproj[9], double negproj[9]) { |
300 | static const char me[]="creaseProj"; |
301 | double pp[9]; |
302 | double *tng; |
303 | |
304 | ELL_3M_ZERO_SET(posproj)((((posproj)+0)[0] = (0), ((posproj)+0)[1] = (0), ((posproj)+ 0)[2] = (0)), (((posproj)+3)[0] = (0), ((posproj)+3)[1] = (0) , ((posproj)+3)[2] = (0)), (((posproj)+6)[0] = (0), ((posproj )+6)[1] = (0), ((posproj)+6)[2] = (0))); |
305 | if (tang1Use) { |
306 | tng = point->info + task->pctx->infoIdx[pullInfoTangent1]; |
307 | if (DEBUG(0)) { |
308 | fprintf(stderr__stderrp, "!%s: tng1 = %g %g %g\n", me, tng[0], tng[1], tng[2]); |
309 | } |
310 | ELL_3MV_OUTER(pp, tng, tng)((((pp)+0)[0] = ((tng)[0])*((tng))[0], ((pp)+0)[1] = ((tng)[0 ])*((tng))[1], ((pp)+0)[2] = ((tng)[0])*((tng))[2]), (((pp)+3 )[0] = ((tng)[1])*((tng))[0], ((pp)+3)[1] = ((tng)[1])*((tng) )[1], ((pp)+3)[2] = ((tng)[1])*((tng))[2]), (((pp)+6)[0] = (( tng)[2])*((tng))[0], ((pp)+6)[1] = ((tng)[2])*((tng))[1], ((pp )+6)[2] = ((tng)[2])*((tng))[2])); |
311 | ELL_3M_ADD2(posproj, posproj, pp)((posproj)[0] = (posproj)[0] + (pp)[0], (posproj)[1] = (posproj )[1] + (pp)[1], (posproj)[2] = (posproj)[2] + (pp)[2], (posproj )[3] = (posproj)[3] + (pp)[3], (posproj)[4] = (posproj)[4] + ( pp)[4], (posproj)[5] = (posproj)[5] + (pp)[5], (posproj)[6] = (posproj)[6] + (pp)[6], (posproj)[7] = (posproj)[7] + (pp)[7 ], (posproj)[8] = (posproj)[8] + (pp)[8]); |
312 | } |
313 | if (tang2Use) { |
314 | tng = point->info + task->pctx->infoIdx[pullInfoTangent2]; |
315 | ELL_3MV_OUTER(pp, tng, tng)((((pp)+0)[0] = ((tng)[0])*((tng))[0], ((pp)+0)[1] = ((tng)[0 ])*((tng))[1], ((pp)+0)[2] = ((tng)[0])*((tng))[2]), (((pp)+3 )[0] = ((tng)[1])*((tng))[0], ((pp)+3)[1] = ((tng)[1])*((tng) )[1], ((pp)+3)[2] = ((tng)[1])*((tng))[2]), (((pp)+6)[0] = (( tng)[2])*((tng))[0], ((pp)+6)[1] = ((tng)[2])*((tng))[1], ((pp )+6)[2] = ((tng)[2])*((tng))[2])); |
316 | ELL_3M_ADD2(posproj, posproj, pp)((posproj)[0] = (posproj)[0] + (pp)[0], (posproj)[1] = (posproj )[1] + (pp)[1], (posproj)[2] = (posproj)[2] + (pp)[2], (posproj )[3] = (posproj)[3] + (pp)[3], (posproj)[4] = (posproj)[4] + ( pp)[4], (posproj)[5] = (posproj)[5] + (pp)[5], (posproj)[6] = (posproj)[6] + (pp)[6], (posproj)[7] = (posproj)[7] + (pp)[7 ], (posproj)[8] = (posproj)[8] + (pp)[8]); |
317 | } |
318 | |
319 | ELL_3M_ZERO_SET(negproj)((((negproj)+0)[0] = (0), ((negproj)+0)[1] = (0), ((negproj)+ 0)[2] = (0)), (((negproj)+3)[0] = (0), ((negproj)+3)[1] = (0) , ((negproj)+3)[2] = (0)), (((negproj)+6)[0] = (0), ((negproj )+6)[1] = (0), ((negproj)+6)[2] = (0))); |
320 | if (negtang1Use) { |
321 | tng = point->info + task->pctx->infoIdx[pullInfoNegativeTangent1]; |
322 | ELL_3MV_OUTER(pp, tng, tng)((((pp)+0)[0] = ((tng)[0])*((tng))[0], ((pp)+0)[1] = ((tng)[0 ])*((tng))[1], ((pp)+0)[2] = ((tng)[0])*((tng))[2]), (((pp)+3 )[0] = ((tng)[1])*((tng))[0], ((pp)+3)[1] = ((tng)[1])*((tng) )[1], ((pp)+3)[2] = ((tng)[1])*((tng))[2]), (((pp)+6)[0] = (( tng)[2])*((tng))[0], ((pp)+6)[1] = ((tng)[2])*((tng))[1], ((pp )+6)[2] = ((tng)[2])*((tng))[2])); |
323 | ELL_3M_ADD2(negproj, negproj, pp)((negproj)[0] = (negproj)[0] + (pp)[0], (negproj)[1] = (negproj )[1] + (pp)[1], (negproj)[2] = (negproj)[2] + (pp)[2], (negproj )[3] = (negproj)[3] + (pp)[3], (negproj)[4] = (negproj)[4] + ( pp)[4], (negproj)[5] = (negproj)[5] + (pp)[5], (negproj)[6] = (negproj)[6] + (pp)[6], (negproj)[7] = (negproj)[7] + (pp)[7 ], (negproj)[8] = (negproj)[8] + (pp)[8]); |
324 | } |
325 | if (negtang2Use) { |
326 | tng = point->info + task->pctx->infoIdx[pullInfoNegativeTangent2]; |
327 | ELL_3MV_OUTER(pp, tng, tng)((((pp)+0)[0] = ((tng)[0])*((tng))[0], ((pp)+0)[1] = ((tng)[0 ])*((tng))[1], ((pp)+0)[2] = ((tng)[0])*((tng))[2]), (((pp)+3 )[0] = ((tng)[1])*((tng))[0], ((pp)+3)[1] = ((tng)[1])*((tng) )[1], ((pp)+3)[2] = ((tng)[1])*((tng))[2]), (((pp)+6)[0] = (( tng)[2])*((tng))[0], ((pp)+6)[1] = ((tng)[2])*((tng))[1], ((pp )+6)[2] = ((tng)[2])*((tng))[2])); |
328 | ELL_3M_ADD2(negproj, negproj, pp)((negproj)[0] = (negproj)[0] + (pp)[0], (negproj)[1] = (negproj )[1] + (pp)[1], (negproj)[2] = (negproj)[2] + (pp)[2], (negproj )[3] = (negproj)[3] + (pp)[3], (negproj)[4] = (negproj)[4] + ( pp)[4], (negproj)[5] = (negproj)[5] + (pp)[5], (negproj)[6] = (negproj)[6] + (pp)[6], (negproj)[7] = (negproj)[7] + (pp)[7 ], (negproj)[8] = (negproj)[8] + (pp)[8]); |
329 | } |
330 | |
331 | if (!tang1Use && !tang2Use && !negtang1Use && !negtang2Use) { |
332 | /* we must be after points, and so need freedom to go after them */ |
333 | /* for now we do this via posproj not negproj; see haveNada below */ |
334 | ELL_3M_IDENTITY_SET(posproj)((((posproj)+0)[0] = (1), ((posproj)+0)[1] = (0), ((posproj)+ 0)[2] = (0)), (((posproj)+3)[0] = (0), ((posproj)+3)[1] = (1) , ((posproj)+3)[2] = (0)), (((posproj)+6)[0] = (0), ((posproj )+6)[1] = (0), ((posproj)+6)[2] = (1))); |
335 | } |
336 | |
337 | return; |
338 | } |
339 | |
340 | /* HEY: body of probeHeight could really be expanded in here */ |
341 | #define PROBE(height, grad, hess, posproj, negproj) \ |
342 | if (probeHeight(task, point, \ |
343 | &(height), (grad), (hess))) { \ |
344 | biffAddf(PULLpullBiffKey, "%s: trouble on iter %u", me, iter); \ |
345 | return 1; \ |
346 | } \ |
347 | creaseProj(task, point, tang1Use, tang2Use, \ |
348 | negtang1Use, negtang2Use, posproj, negproj) |
349 | #define SAVE(state, height, grad, hess, posproj, negproj, pos) \ |
350 | state[0] = height; \ |
351 | ELL_3V_COPY(state + 1, grad)((state + 1)[0] = (grad)[0], (state + 1)[1] = (grad)[1], (state + 1)[2] = (grad)[2]); \ |
352 | ELL_3M_COPY(state + 1 + 3, hess)((((state + 1 + 3)+0)[0] = ((hess)+0)[0], ((state + 1 + 3)+0) [1] = ((hess)+0)[1], ((state + 1 + 3)+0)[2] = ((hess)+0)[2]), (((state + 1 + 3)+3)[0] = ((hess)+3)[0], ((state + 1 + 3)+3) [1] = ((hess)+3)[1], ((state + 1 + 3)+3)[2] = ((hess)+3)[2]), (((state + 1 + 3)+6)[0] = ((hess)+6)[0], ((state + 1 + 3)+6) [1] = ((hess)+6)[1], ((state + 1 + 3)+6)[2] = ((hess)+6)[2])); \ |
353 | ELL_3M_COPY(state + 1 + 3 + 9, posproj)((((state + 1 + 3 + 9)+0)[0] = ((posproj)+0)[0], ((state + 1 + 3 + 9)+0)[1] = ((posproj)+0)[1], ((state + 1 + 3 + 9)+0)[2] = ((posproj)+0)[2]), (((state + 1 + 3 + 9)+3)[0] = ((posproj)+ 3)[0], ((state + 1 + 3 + 9)+3)[1] = ((posproj)+3)[1], ((state + 1 + 3 + 9)+3)[2] = ((posproj)+3)[2]), (((state + 1 + 3 + 9 )+6)[0] = ((posproj)+6)[0], ((state + 1 + 3 + 9)+6)[1] = ((posproj )+6)[1], ((state + 1 + 3 + 9)+6)[2] = ((posproj)+6)[2])); \ |
354 | ELL_3M_COPY(state + 1 + 3 + 9 + 9, negproj)((((state + 1 + 3 + 9 + 9)+0)[0] = ((negproj)+0)[0], ((state + 1 + 3 + 9 + 9)+0)[1] = ((negproj)+0)[1], ((state + 1 + 3 + 9 + 9)+0)[2] = ((negproj)+0)[2]), (((state + 1 + 3 + 9 + 9)+3) [0] = ((negproj)+3)[0], ((state + 1 + 3 + 9 + 9)+3)[1] = ((negproj )+3)[1], ((state + 1 + 3 + 9 + 9)+3)[2] = ((negproj)+3)[2]), ( ((state + 1 + 3 + 9 + 9)+6)[0] = ((negproj)+6)[0], ((state + 1 + 3 + 9 + 9)+6)[1] = ((negproj)+6)[1], ((state + 1 + 3 + 9 + 9)+6)[2] = ((negproj)+6)[2])); \ |
355 | ELL_3V_COPY(state + 1 + 3 + 9 + 9 + 9, pos)((state + 1 + 3 + 9 + 9 + 9)[0] = (pos)[0], (state + 1 + 3 + 9 + 9 + 9)[1] = (pos)[1], (state + 1 + 3 + 9 + 9 + 9)[2] = (pos )[2]) |
356 | #define RESTORE(height, grad, hess, posproj, negproj, pos, state) \ |
357 | height = state[0]; \ |
358 | ELL_3V_COPY(grad, state + 1)((grad)[0] = (state + 1)[0], (grad)[1] = (state + 1)[1], (grad )[2] = (state + 1)[2]); \ |
359 | ELL_3M_COPY(hess, state + 1 + 3)((((hess)+0)[0] = ((state + 1 + 3)+0)[0], ((hess)+0)[1] = ((state + 1 + 3)+0)[1], ((hess)+0)[2] = ((state + 1 + 3)+0)[2]), ((( hess)+3)[0] = ((state + 1 + 3)+3)[0], ((hess)+3)[1] = ((state + 1 + 3)+3)[1], ((hess)+3)[2] = ((state + 1 + 3)+3)[2]), ((( hess)+6)[0] = ((state + 1 + 3)+6)[0], ((hess)+6)[1] = ((state + 1 + 3)+6)[1], ((hess)+6)[2] = ((state + 1 + 3)+6)[2])); \ |
360 | ELL_3M_COPY(posproj, state + 1 + 3 + 9)((((posproj)+0)[0] = ((state + 1 + 3 + 9)+0)[0], ((posproj)+0 )[1] = ((state + 1 + 3 + 9)+0)[1], ((posproj)+0)[2] = ((state + 1 + 3 + 9)+0)[2]), (((posproj)+3)[0] = ((state + 1 + 3 + 9 )+3)[0], ((posproj)+3)[1] = ((state + 1 + 3 + 9)+3)[1], ((posproj )+3)[2] = ((state + 1 + 3 + 9)+3)[2]), (((posproj)+6)[0] = (( state + 1 + 3 + 9)+6)[0], ((posproj)+6)[1] = ((state + 1 + 3 + 9)+6)[1], ((posproj)+6)[2] = ((state + 1 + 3 + 9)+6)[2])); \ |
361 | ELL_3M_COPY(negproj, state + 1 + 3 + 9 + 9)((((negproj)+0)[0] = ((state + 1 + 3 + 9 + 9)+0)[0], ((negproj )+0)[1] = ((state + 1 + 3 + 9 + 9)+0)[1], ((negproj)+0)[2] = ( (state + 1 + 3 + 9 + 9)+0)[2]), (((negproj)+3)[0] = ((state + 1 + 3 + 9 + 9)+3)[0], ((negproj)+3)[1] = ((state + 1 + 3 + 9 + 9)+3)[1], ((negproj)+3)[2] = ((state + 1 + 3 + 9 + 9)+3)[2 ]), (((negproj)+6)[0] = ((state + 1 + 3 + 9 + 9)+6)[0], ((negproj )+6)[1] = ((state + 1 + 3 + 9 + 9)+6)[1], ((negproj)+6)[2] = ( (state + 1 + 3 + 9 + 9)+6)[2])); \ |
362 | ELL_3V_COPY(pos, state + 1 + 3 + 9 + 9 + 9)((pos)[0] = (state + 1 + 3 + 9 + 9 + 9)[0], (pos)[1] = (state + 1 + 3 + 9 + 9 + 9)[1], (pos)[2] = (state + 1 + 3 + 9 + 9 + 9)[2]) |
363 | #define DNORM(d1, d2, pdir, plen, pgrad, grad, hess, posproj) \ |
364 | ELL_3MV_MUL(pgrad, posproj, grad)((pgrad)[0] = (posproj)[0]*(grad)[0] + (posproj)[1]*(grad)[1] + (posproj)[2]*(grad)[2], (pgrad)[1] = (posproj)[3]*(grad)[0 ] + (posproj)[4]*(grad)[1] + (posproj)[5]*(grad)[2], (pgrad)[ 2] = (posproj)[6]*(grad)[0] + (posproj)[7]*(grad)[1] + (posproj )[8]*(grad)[2]); \ |
365 | if (task->pctx->flag.zeroZ) pgrad[2]=0; \ |
366 | ELL_3V_NORM(pdir, pgrad, plen)(plen = (sqrt((((pgrad))[0]*((pgrad))[0] + ((pgrad))[1]*((pgrad ))[1] + ((pgrad))[2]*((pgrad))[2]))), ((pdir)[0] = (1.0/plen) *(pgrad)[0], (pdir)[1] = (1.0/plen)*(pgrad)[1], (pdir)[2] = ( 1.0/plen)*(pgrad)[2])); \ |
367 | d1 = ELL_3V_DOT(grad, pdir)((grad)[0]*(pdir)[0] + (grad)[1]*(pdir)[1] + (grad)[2]*(pdir) [2]); \ |
368 | d2 = ELL_3MV_CONTR(hess, pdir)((hess)[0]*(pdir)[0]*(pdir)[0] + (hess)[1]*(pdir)[1]*(pdir)[0 ] + (hess)[2]*(pdir)[2]*(pdir)[0] + (hess)[3]*(pdir)[0]*(pdir )[1] + (hess)[4]*(pdir)[1]*(pdir)[1] + (hess)[5]*(pdir)[2]*(pdir )[1] + (hess)[6]*(pdir)[0]*(pdir)[2] + (hess)[7]*(pdir)[1]*(pdir )[2] + (hess)[8]*(pdir)[2]*(pdir)[2]) |
369 | #define PRINT(prefix)fprintf(__stderrp, "-------------- probe results %s (%u @ %g,%g,%g,%g):\n" , prefix, point->idtag, point->pos[0], point->pos[1] , point->pos[2], point->pos[3]); fprintf(__stderrp, "-- val = %g\n" , val); fprintf(__stderrp, "-- grad = %g %g %g\n", grad[0], grad [1], grad[2]); fprintf(__stderrp,"-- hess = %g %g %g; %g %g %g; %g %g %g\n" , hess[0], hess[1], hess[2], hess[3], hess[4], hess[5], hess[ 6], hess[7], hess[8]); fprintf(__stderrp, "-- posproj = %g %g %g; %g %g %g; %g %g %g\n" , posproj[0], posproj[1], posproj[2], posproj[3], posproj[4], posproj[5], posproj[6], posproj[7], posproj[8]); fprintf(__stderrp , "-- negproj = %g %g %g; %g %g %g; %g %g %g\n", negproj[0] , negproj[1], negproj[2], negproj[3], negproj[4], negproj[5], negproj[6], negproj[7], negproj[8]) \ |
370 | fprintf(stderr__stderrp, "-------------- probe results %s (%u @ %g,%g,%g,%g):\n", \ |
371 | prefix, point->idtag, point->pos[0], point->pos[1], \ |
372 | point->pos[2], point->pos[3]); \ |
373 | fprintf(stderr__stderrp, "-- val = %g\n", val); \ |
374 | fprintf(stderr__stderrp, "-- grad = %g %g %g\n", grad[0], grad[1], grad[2]); \ |
375 | fprintf(stderr__stderrp,"-- hess = %g %g %g; %g %g %g; %g %g %g\n", \ |
376 | hess[0], hess[1], hess[2], \ |
377 | hess[3], hess[4], hess[5], \ |
378 | hess[6], hess[7], hess[8]); \ |
379 | fprintf(stderr__stderrp, "-- posproj = %g %g %g; %g %g %g; %g %g %g\n", \ |
380 | posproj[0], posproj[1], posproj[2], \ |
381 | posproj[3], posproj[4], posproj[5], \ |
382 | posproj[6], posproj[7], posproj[8]); \ |
383 | fprintf(stderr__stderrp, "-- negproj = %g %g %g; %g %g %g; %g %g %g\n", \ |
384 | negproj[0], negproj[1], negproj[2], \ |
385 | negproj[3], negproj[4], negproj[5], \ |
386 | negproj[6], negproj[7], negproj[8]) |
387 | |
388 | static int |
389 | constraintSatHght(pullTask *task, pullPoint *point, |
390 | int tang1Use, int tang2Use, |
391 | int negtang1Use, int negtang2Use, |
392 | double stepMax, double constrEps, unsigned int iterMax, |
393 | int *constrFailP) { |
394 | static const char me[]="constraintSatHght"; |
395 | double val, grad[3], hess[9], posproj[9], negproj[9], |
396 | state[1+3+9+9+9+3], hack, step, |
397 | d1, d2, pdir[3], plen, pgrad[3]; |
398 | double _tmpv[3]={0,0,0}; |
Value stored to '_tmpv' during its initialization is never read | |
399 | /* #endif */ |
400 | int havePos, haveNeg, haveNada, zeroGmagOkay; |
401 | unsigned int iter = 0; /* 0: initial probe, 1..iterMax: probes in loop */ |
402 | /* http://en.wikipedia.org/wiki/Newton%27s_method_in_optimization */ |
403 | |
404 | zeroGmagOkay = (1 < task->pctx->iter && 0 == task->pctx->constraintDim); |
405 | havePos = tang1Use || tang2Use; |
406 | haveNeg = negtang1Use || negtang2Use; |
407 | haveNada = !havePos && !haveNeg; |
408 | if (DEBUG(0)) { |
409 | double stpmin; |
410 | /* HEY: shouldn't stpmin also be used later in this function? */ |
411 | stpmin = task->pctx->voxelSizeSpace*constrEps; |
412 | fprintf(stderr__stderrp, "!%s(%u): starting at %g %g %g %g\n", me, point->idtag, |
413 | point->pos[0], point->pos[1], point->pos[2], point->pos[3]); |
414 | fprintf(stderr__stderrp, "!%s: pt %d %d nt %d %d (nada %d) " |
415 | "stepMax %g, iterMax %u\n", me, |
416 | tang1Use, tang2Use, negtang1Use, negtang2Use, haveNada, |
417 | stepMax, iterMax); |
418 | fprintf(stderr__stderrp, "!%s: stpmin = %g = voxsize %g * parm.stepmin %g\n", me, |
419 | stpmin, task->pctx->voxelSizeSpace, constrEps); |
420 | } |
421 | PROBE(val, grad, hess, posproj, negproj); |
422 | _pullPointHistAdd(point, pullCondOld, val); |
423 | if (DEBUG(0)) { |
424 | PRINT("initial probe")fprintf(__stderrp, "-------------- probe results %s (%u @ %g,%g,%g,%g):\n" , "initial probe", point->idtag, point->pos[0], point-> pos[1], point->pos[2], point->pos[3]); fprintf(__stderrp , "-- val = %g\n", val); fprintf(__stderrp, "-- grad = %g %g %g\n" , grad[0], grad[1], grad[2]); fprintf(__stderrp,"-- hess = %g %g %g; %g %g %g; %g %g %g\n" , hess[0], hess[1], hess[2], hess[3], hess[4], hess[5], hess[ 6], hess[7], hess[8]); fprintf(__stderrp, "-- posproj = %g %g %g; %g %g %g; %g %g %g\n" , posproj[0], posproj[1], posproj[2], posproj[3], posproj[4], posproj[5], posproj[6], posproj[7], posproj[8]); fprintf(__stderrp , "-- negproj = %g %g %g; %g %g %g; %g %g %g\n", negproj[0] , negproj[1], negproj[2], negproj[3], negproj[4], negproj[5], negproj[6], negproj[7], negproj[8]); |
425 | } |
426 | SAVE(state, val, grad, hess, posproj, negproj, point->pos); |
427 | hack = 1; |
428 | for (iter=1; iter<=iterMax; iter++) { |
429 | if (DEBUG(0)) { |
430 | fprintf(stderr__stderrp, "!%s: =-============= begin iter %u\n", me, iter); |
431 | } |
432 | /* HEY: no opportunistic increase of hack? */ |
433 | if (havePos || haveNada) { |
434 | DNORM(d1, d2, pdir, plen, pgrad, grad, hess, posproj); |
435 | if (!ELL_3M_FROB(hess)(sqrt((((hess)+0)[0]*((hess)+0)[0] + ((hess)+0)[1]*((hess)+0) [1] + ((hess)+0)[2]*((hess)+0)[2]) + (((hess)+3)[0]*((hess)+3 )[0] + ((hess)+3)[1]*((hess)+3)[1] + ((hess)+3)[2]*((hess)+3) [2]) + (((hess)+6)[0]*((hess)+6)[0] + ((hess)+6)[1]*((hess)+6 )[1] + ((hess)+6)[2]*((hess)+6)[2])))) { |
436 | *constrFailP = pullConstraintFailHessZeroA; |
437 | return 0; |
438 | } |
439 | if (!plen) { |
440 | if (zeroGmagOkay) { |
441 | /* getting to actual zero gradient is possible when looking for |
442 | point extrema (or saddles), and its not a problem, so as a |
443 | lousy hack we set step=0 and skip to the convergence test */ |
444 | step = 0; |
445 | goto convtestA; |
446 | } |
447 | /* this use to be a biff error, which got to be annoying */ |
448 | *constrFailP = pullConstraintFailProjGradZeroA; |
449 | return 0; |
450 | } else if (!AIR_EXISTS(plen)(((int)(!((plen) - (plen)))))) { |
451 | /* this use to be a biff error, which also got to be annoying */ |
452 | *constrFailP = pullConstraintFailProjLenNonExist; |
453 | return 0; |
454 | } |
455 | step = (d2 > 0 ? -d1/d2 : -plen); |
456 | if (DEBUG(0)) { |
457 | fprintf(stderr__stderrp, "!%s: (+) iter %u step = (%g > 0 ? %g=-%g/%g : %g) --> %g\n", |
458 | me, iter, d2, -d1/d2, d1, d2, -plen, step); |
459 | } |
460 | step = step > 0 ? AIR_MIN(stepMax, step)((stepMax) < (step) ? (stepMax) : (step)) : AIR_MAX(-stepMax, step)((-stepMax) > (step) ? (-stepMax) : (step)); |
461 | convtestA: |
462 | if (d2 > 0 && AIR_ABS(step)((step) > 0.0f ? (step) : -(step)) < constrEps) { /* HEY stepMax*constrEps vs constrEps */ |
463 | /* we're converged because its concave up here |
464 | and we're close enough to the bottom */ |
465 | if (DEBUG(0)) { |
466 | fprintf(stderr__stderrp, " |step| %g < %g*%g = %g ==> converged!\n", |
467 | AIR_ABS(step)((step) > 0.0f ? (step) : -(step)), |
468 | stepMax, constrEps, |
469 | stepMax*constrEps); |
470 | } |
471 | if (!haveNeg) { |
472 | break; |
473 | } else { |
474 | goto nextstep; |
475 | } |
476 | } |
477 | /* else we have to take a significant step */ |
478 | if (DEBUG(0)) { |
479 | fprintf(stderr__stderrp, " -> step %g, |pdir| = %g\n", |
480 | step, ELL_3V_LEN(pdir)(sqrt((((pdir))[0]*((pdir))[0] + ((pdir))[1]*((pdir))[1] + (( pdir))[2]*((pdir))[2])))); |
481 | ELL_3V_COPY(_tmpv, point->pos)((_tmpv)[0] = (point->pos)[0], (_tmpv)[1] = (point->pos )[1], (_tmpv)[2] = (point->pos)[2]); |
482 | fprintf(stderr__stderrp, " -> pos (%g,%g,%g,%g) += " |
483 | "%g * %g * (%g,%g,%g)\n", |
484 | point->pos[0], point->pos[1], point->pos[2], point->pos[3], |
485 | hack, step, pdir[0], pdir[1], pdir[2]); |
486 | } |
487 | ELL_3V_SCALE_INCR(point->pos, hack*step, pdir)((point->pos)[0] += (hack*step)*(pdir)[0], (point->pos) [1] += (hack*step)*(pdir)[1], (point->pos)[2] += (hack*step )*(pdir)[2]); |
488 | if (!ELL_4V_EXISTS(point->pos)((((int)(!(((point->pos)[0]) - ((point->pos)[0]))))) && (((int)(!(((point->pos)[1]) - ((point->pos)[1]))))) && (((int)(!(((point->pos)[2]) - ((point->pos)[2]))))) && (((int)(!(((point->pos)[3]) - ((point->pos)[3]))))))) { |
489 | biffAddf(PULLpullBiffKey, "%s: pos proj iter %u: pnt %u bad pos (%g,%g,%g,%g); " |
490 | "hack %g, step %g", |
491 | me, iter, point->idtag, point->pos[0], point->pos[1], |
492 | point->pos[2], point->pos[3], hack, step); |
493 | return 1; |
494 | } |
495 | if (DEBUG(0)) { |
496 | ELL_3V_SUB(_tmpv, _tmpv, point->pos)((_tmpv)[0] = (_tmpv)[0] - (point->pos)[0], (_tmpv)[1] = ( _tmpv)[1] - (point->pos)[1], (_tmpv)[2] = (_tmpv)[2] - (point ->pos)[2]); |
497 | fprintf(stderr__stderrp, " -> moved to %g %g %g %g\n", |
498 | point->pos[0], point->pos[1], point->pos[2], point->pos[3]); |
499 | fprintf(stderr__stderrp, " (moved %g)\n", ELL_3V_LEN(_tmpv)(sqrt((((_tmpv))[0]*((_tmpv))[0] + ((_tmpv))[1]*((_tmpv))[1] + ((_tmpv))[2]*((_tmpv))[2])))); |
500 | } |
501 | PROBE(val, grad, hess, posproj, negproj); |
502 | _pullPointHistAdd(point, pullCondConstraintSatA, val); |
503 | if (DEBUG(0)) { |
504 | fprintf(stderr__stderrp, " (+) probed at (%g,%g,%g,%g)\n", |
505 | point->pos[0], point->pos[1], point->pos[2], point->pos[3]); |
506 | PRINT("after move")fprintf(__stderrp, "-------------- probe results %s (%u @ %g,%g,%g,%g):\n" , "after move", point->idtag, point->pos[0], point-> pos[1], point->pos[2], point->pos[3]); fprintf(__stderrp , "-- val = %g\n", val); fprintf(__stderrp, "-- grad = %g %g %g\n" , grad[0], grad[1], grad[2]); fprintf(__stderrp,"-- hess = %g %g %g; %g %g %g; %g %g %g\n" , hess[0], hess[1], hess[2], hess[3], hess[4], hess[5], hess[ 6], hess[7], hess[8]); fprintf(__stderrp, "-- posproj = %g %g %g; %g %g %g; %g %g %g\n" , posproj[0], posproj[1], posproj[2], posproj[3], posproj[4], posproj[5], posproj[6], posproj[7], posproj[8]); fprintf(__stderrp , "-- negproj = %g %g %g; %g %g %g; %g %g %g\n", negproj[0] , negproj[1], negproj[2], negproj[3], negproj[4], negproj[5], negproj[6], negproj[7], negproj[8]); |
507 | fprintf(stderr__stderrp, " val(%g,%g,%g,%g)=%g %s state[0]=%g\n", |
508 | point->pos[0], point->pos[1], point->pos[2], point->pos[3], |
509 | val, val <= state[0] ? "<=" : ">", state[0]); |
510 | } |
511 | if (val <= state[0]) { |
512 | /* we made progress */ |
513 | if (DEBUG(0)) { |
514 | fprintf(stderr__stderrp, " (+) progress!\n"); |
515 | } |
516 | SAVE(state, val, grad, hess, posproj, negproj, point->pos); |
517 | hack = 1; |
518 | } else { |
519 | /* oops, we went uphill instead of down; try again */ |
520 | if (DEBUG(0)) { |
521 | fprintf(stderr__stderrp, " (+) val *increased* (up from %.17g by %.17g); " |
522 | "backing hack from %g to %g\n", |
523 | state[0], val - state[0], |
524 | hack, hack*task->pctx->sysParm.backStepScale); |
525 | } |
526 | hack *= task->pctx->sysParm.backStepScale; |
527 | RESTORE(val, grad, hess, posproj, negproj, point->pos, state); |
528 | if (DEBUG(0)) { |
529 | fprintf(stderr__stderrp, " restored to pos (%g,%g,%g,%g)\n", |
530 | point->pos[0], point->pos[1], point->pos[2], point->pos[3]); |
531 | } |
532 | } |
533 | } |
534 | nextstep: |
535 | if (haveNeg) { |
536 | /* HEY: copy and paste from above, minus fluff, and with A->B */ |
537 | DNORM(d1, d2, pdir, plen, pgrad, grad, hess, negproj); |
538 | if (!ELL_3M_FROB(hess)(sqrt((((hess)+0)[0]*((hess)+0)[0] + ((hess)+0)[1]*((hess)+0) [1] + ((hess)+0)[2]*((hess)+0)[2]) + (((hess)+3)[0]*((hess)+3 )[0] + ((hess)+3)[1]*((hess)+3)[1] + ((hess)+3)[2]*((hess)+3) [2]) + (((hess)+6)[0]*((hess)+6)[0] + ((hess)+6)[1]*((hess)+6 )[1] + ((hess)+6)[2]*((hess)+6)[2])))) { |
539 | *constrFailP = pullConstraintFailHessZeroB; |
540 | return 0; |
541 | } |
542 | if (!plen) { |
543 | if (zeroGmagOkay) { |
544 | step = 0; |
545 | goto convtestB; |
546 | } |
547 | *constrFailP = pullConstraintFailProjGradZeroB; |
548 | return 0; |
549 | } |
550 | step = (d2 < 0 ? -d1/d2 : plen); |
551 | if (DEBUG(0)) { |
552 | fprintf(stderr__stderrp, "!%s: -+) iter %u step = (%g < 0 ? %g : %g) --> %g\n", |
553 | me, iter, d2, -d1/d2, plen, step); |
554 | } |
555 | step = step > 0 ? AIR_MIN(stepMax, step)((stepMax) < (step) ? (stepMax) : (step)) : AIR_MAX(-stepMax, step)((-stepMax) > (step) ? (-stepMax) : (step)); |
556 | convtestB: |
557 | if (d2 < 0 && AIR_ABS(step)((step) > 0.0f ? (step) : -(step)) < constrEps) { /* HEY stepMax*constrEps vs constrEps */ |
558 | /* we're converged because its concave down here |
559 | and we're close enough to the top */ |
560 | if (DEBUG(0)) { |
561 | fprintf(stderr__stderrp, " |step| %g < %g*%g = %g ==> converged!\n", |
562 | AIR_ABS(step)((step) > 0.0f ? (step) : -(step)), |
563 | stepMax, constrEps, |
564 | stepMax*constrEps); |
565 | } |
566 | /* no further iteration needed; we're converged */ |
567 | break; |
568 | } |
569 | /* else we have to take a significant step */ |
570 | if (DEBUG(0)) { |
571 | fprintf(stderr__stderrp, " -> step %g, |pdir| = %g\n", |
572 | step, ELL_3V_LEN(pdir)(sqrt((((pdir))[0]*((pdir))[0] + ((pdir))[1]*((pdir))[1] + (( pdir))[2]*((pdir))[2])))); |
573 | ELL_3V_COPY(_tmpv, point->pos)((_tmpv)[0] = (point->pos)[0], (_tmpv)[1] = (point->pos )[1], (_tmpv)[2] = (point->pos)[2]); |
574 | fprintf(stderr__stderrp, " -> pos (%g,%g,%g,%g) += " |
575 | "%g * %g * (%g,%g,%g)\n", |
576 | point->pos[0], point->pos[1], point->pos[2], point->pos[3], |
577 | hack, step, pdir[0], pdir[1], pdir[2]); |
578 | } |
579 | ELL_3V_SCALE_INCR(point->pos, hack*step, pdir)((point->pos)[0] += (hack*step)*(pdir)[0], (point->pos) [1] += (hack*step)*(pdir)[1], (point->pos)[2] += (hack*step )*(pdir)[2]); |
580 | if (!ELL_4V_EXISTS(point->pos)((((int)(!(((point->pos)[0]) - ((point->pos)[0]))))) && (((int)(!(((point->pos)[1]) - ((point->pos)[1]))))) && (((int)(!(((point->pos)[2]) - ((point->pos)[2]))))) && (((int)(!(((point->pos)[3]) - ((point->pos)[3]))))))) { |
581 | biffAddf(PULLpullBiffKey, "%s: neg proj iter %u: pnt %u bad pos (%g,%g,%g,%g); " |
582 | "hack %g, step %g", |
583 | me, iter, point->idtag, point->pos[0], point->pos[1], |
584 | point->pos[2], point->pos[3], hack, step); |
585 | return 1; |
586 | } |
587 | if (DEBUG(0)) { |
588 | ELL_3V_SUB(_tmpv, _tmpv, point->pos)((_tmpv)[0] = (_tmpv)[0] - (point->pos)[0], (_tmpv)[1] = ( _tmpv)[1] - (point->pos)[1], (_tmpv)[2] = (_tmpv)[2] - (point ->pos)[2]); |
589 | fprintf(stderr__stderrp, " -> moved to %g %g %g %g\n", |
590 | point->pos[0], point->pos[1], point->pos[2], point->pos[3]); |
591 | fprintf(stderr__stderrp, " (moved %g)\n", ELL_3V_LEN(_tmpv)(sqrt((((_tmpv))[0]*((_tmpv))[0] + ((_tmpv))[1]*((_tmpv))[1] + ((_tmpv))[2]*((_tmpv))[2])))); |
592 | } |
593 | PROBE(val, grad, hess, posproj, negproj); |
594 | _pullPointHistAdd(point, pullCondConstraintSatB, val); |
595 | if (DEBUG(0)) { |
596 | fprintf(stderr__stderrp, " (-) probed at (%g,%g,%g,%g)\n", |
597 | point->pos[0], point->pos[1], point->pos[2], point->pos[3]); |
598 | PRINT("after move")fprintf(__stderrp, "-------------- probe results %s (%u @ %g,%g,%g,%g):\n" , "after move", point->idtag, point->pos[0], point-> pos[1], point->pos[2], point->pos[3]); fprintf(__stderrp , "-- val = %g\n", val); fprintf(__stderrp, "-- grad = %g %g %g\n" , grad[0], grad[1], grad[2]); fprintf(__stderrp,"-- hess = %g %g %g; %g %g %g; %g %g %g\n" , hess[0], hess[1], hess[2], hess[3], hess[4], hess[5], hess[ 6], hess[7], hess[8]); fprintf(__stderrp, "-- posproj = %g %g %g; %g %g %g; %g %g %g\n" , posproj[0], posproj[1], posproj[2], posproj[3], posproj[4], posproj[5], posproj[6], posproj[7], posproj[8]); fprintf(__stderrp , "-- negproj = %g %g %g; %g %g %g; %g %g %g\n", negproj[0] , negproj[1], negproj[2], negproj[3], negproj[4], negproj[5], negproj[6], negproj[7], negproj[8]); |
599 | fprintf(stderr__stderrp, " val(%g,%g,%g,%g)=%g %s state[0]=%g\n", |
600 | point->pos[0], point->pos[1], point->pos[2], point->pos[3], |
601 | val, val >= state[0] ? ">=" : "<", state[0]); |
602 | } |
603 | if (val >= state[0]) { |
604 | /* we made progress */ |
605 | if (DEBUG(0)) { |
606 | fprintf(stderr__stderrp, " (-) progress!\n"); |
607 | } |
608 | SAVE(state, val, grad, hess, posproj, negproj, point->pos); |
609 | hack = 1; |
610 | } else { |
611 | /* oops, we went downhill instead of up; try again */ |
612 | if (DEBUG(0)) { |
613 | fprintf(stderr__stderrp, " (-) val *decreased* (down from %.17g by %.17g); " |
614 | "backing hack from %g to %g\n", |
615 | state[0], state[0] - val, |
616 | hack, hack*task->pctx->sysParm.backStepScale); |
617 | } |
618 | hack *= task->pctx->sysParm.backStepScale; |
619 | RESTORE(val, grad, hess, posproj, negproj, point->pos, state); |
620 | if (DEBUG(0)) { |
621 | fprintf(stderr__stderrp, " restored to pos (%g,%g,%g,%g)\n", |
622 | point->pos[0], point->pos[1], point->pos[2], point->pos[3]); |
623 | } |
624 | } |
625 | } |
626 | } |
627 | if (iter > iterMax) { |
628 | *constrFailP = pullConstraintFailIterMaxed; |
629 | } else { |
630 | *constrFailP = AIR_FALSE0; |
631 | } |
632 | _pullPointHistAdd(point, (*constrFailP |
633 | ? pullCondConstraintFail |
634 | : pullCondConstraintSuccess), AIR_NAN); |
635 | if (DEBUG(0)) { |
636 | printf("!%s: Finished %s: %s (%d)\n", me, |
637 | *constrFailP ? "with failure" : "OK", |
638 | *constrFailP ? airEnumStr(pullConstraintFail, *constrFailP) : "", |
639 | *constrFailP); |
640 | } |
641 | return 0; |
642 | } |
643 | #undef PROBE |
644 | #undef DNORM |
645 | #undef SAVE |
646 | #undef RESTORE |
647 | |
648 | double |
649 | _pullSigma(const pullContext *pctx, const double pos[4]) { |
650 | double ret=0; |
651 | |
652 | if (pos && pos[3]) { |
653 | ret = (pctx->flag.scaleIsTau |
654 | ? gageSigOfTau(pos[3])airSigmaOfTau(pos[3]) |
655 | : pos[3]); |
656 | } |
657 | return ret; |
658 | } |
659 | |
660 | /* ------------------------------------------- */ |
661 | |
662 | /* have to make sure that scale position point->pos[3] |
663 | ** is not modified anywhere in here: constraints are ONLY spatial |
664 | ** |
665 | ** This uses biff, but only for showstopper problems |
666 | */ |
667 | int |
668 | _pullConstraintSatisfy(pullTask *task, pullPoint *point, |
669 | double travelMax, |
670 | /* output */ |
671 | int *constrFailP) { |
672 | static const char me[]="_pullConstraintSatisfy"; |
673 | double stepMax, constrEps; |
674 | unsigned int iterMax; |
675 | double pos3Orig[3], pos3Diff[3], travel; |
676 | |
677 | ELL_3V_COPY(pos3Orig, point->pos)((pos3Orig)[0] = (point->pos)[0], (pos3Orig)[1] = (point-> pos)[1], (pos3Orig)[2] = (point->pos)[2]); |
678 | /* HEY the "10*" is based on isolated experiments; what's the principle? */ |
679 | stepMax = 10*task->pctx->voxelSizeSpace; |
680 | iterMax = task->pctx->iterParm.constraintMax; |
681 | constrEps = task->pctx->voxelSizeSpace*task->pctx->sysParm.constraintStepMin; |
682 | /* * (1 + 0.2*_pullSigma(task->pctx, point->pos)); */ |
683 | if (DEBUG(0)) { |
684 | fprintf(stderr__stderrp, "!%s(%d): hi ==== %g %g %g, stepMax = %g, iterMax = %u\n", |
685 | me, point->idtag, point->pos[0], point->pos[1], point->pos[2], |
686 | stepMax, iterMax); |
687 | } |
688 | task->pctx->count[pullCountConstraintSatisfy] += 1; |
689 | switch (task->pctx->constraint) { |
690 | case pullInfoHeightLaplacian: /* zero-crossing edges */ |
691 | if (constraintSatLapl(task, point, stepMax/4, constrEps, |
692 | 4*iterMax, constrFailP)) { |
693 | biffAddf(PULLpullBiffKey, "%s: trouble", me); |
694 | return 1; |
695 | } |
696 | break; |
697 | case pullInfoIsovalue: |
698 | if (constraintSatIso(task, point, stepMax, constrEps, |
699 | iterMax, constrFailP)) { |
700 | biffAddf(PULLpullBiffKey, "%s: trouble", me); |
701 | return 1; |
702 | } |
703 | break; |
704 | case pullInfoHeight: |
705 | if (constraintSatHght(task, point, |
706 | !!task->pctx->ispec[pullInfoTangent1], |
707 | !!task->pctx->ispec[pullInfoTangent2], |
708 | !!task->pctx->ispec[pullInfoNegativeTangent1], |
709 | !!task->pctx->ispec[pullInfoNegativeTangent2], |
710 | stepMax, constrEps, iterMax, constrFailP)) { |
711 | biffAddf(PULLpullBiffKey, "%s: trouble", me); |
712 | return 1; |
713 | } |
714 | break; |
715 | default: |
716 | fprintf(stderr__stderrp, "%s: constraint on %s (%d) unimplemented!!\n", me, |
717 | airEnumStr(pullInfo, task->pctx->constraint), |
718 | task->pctx->constraint); |
719 | } |
720 | ELL_3V_SUB(pos3Diff, pos3Orig, point->pos)((pos3Diff)[0] = (pos3Orig)[0] - (point->pos)[0], (pos3Diff )[1] = (pos3Orig)[1] - (point->pos)[1], (pos3Diff)[2] = (pos3Orig )[2] - (point->pos)[2]); |
721 | if (travelMax) { |
722 | travel = ELL_3V_LEN(pos3Diff)(sqrt((((pos3Diff))[0]*((pos3Diff))[0] + ((pos3Diff))[1]*((pos3Diff ))[1] + ((pos3Diff))[2]*((pos3Diff))[2])))/task->pctx->voxelSizeSpace; |
723 | if (travel > travelMax) { |
724 | *constrFailP = pullConstraintFailTravel; |
725 | if (DEBUG(0)) { |
726 | fprintf(stderr__stderrp, "!%s: travel %g > travelMax %g\n", me, |
727 | travel, travelMax); |
728 | } |
729 | } |
730 | } |
731 | if (DEBUG(0)) { |
732 | fprintf(stderr__stderrp, "!%s(%u) %s @ (%g,%g,%g) = (%g,%g,%g) + (%g,%g,%g)\n", me, |
733 | point->idtag, |
734 | (*constrFailP |
735 | ? airEnumStr(pullConstraintFail, *constrFailP) |
736 | : "#GOOD#"), |
737 | point->pos[0], point->pos[1], point->pos[2], |
738 | pos3Diff[0], pos3Diff[1], pos3Diff[2], |
739 | pos3Orig[0], pos3Orig[1], pos3Orig[2]); |
740 | #if PULL_PHIST0 |
741 | if (1) { |
742 | Nrrd *nhist; |
743 | FILE *fhist; |
744 | char fname[AIR_STRLEN_LARGE(512+1)]; |
745 | nhist = nrrdNew(); |
746 | sprintf(fname, "%04u-%04u-phist.nrrd", task->pctx->iter, point->idtag)__builtin___sprintf_chk (fname, 0, __builtin_object_size (fname , 2 > 1 ? 1 : 0), "%04u-%04u-phist.nrrd", task->pctx-> iter, point->idtag); |
747 | if (pullPositionHistoryNrrdGet(nhist, task->pctx, point)) { |
748 | biffAddf(PULLpullBiffKey, "%s: trouble", me); |
749 | return 1; |
750 | } |
751 | if ((fhist = fopen(fname, "w"))) { |
752 | if (nrrdSave(fname, nhist, NULL((void*)0))) { |
753 | biffMovef(PULLpullBiffKey, NRRDnrrdBiffKey, "%s: trouble", me); |
754 | return 1; |
755 | } |
756 | fclose(fhist); |
757 | } |
758 | nrrdNuke(nhist); |
759 | } |
760 | #endif |
761 | } |
762 | return 0; |
763 | } |
764 | |
765 | #undef NORMALIZE |
766 | |
767 | /* |
768 | ** _pullConstraintTangent |
769 | ** |
770 | ** eigenvectors (with non-zero eigenvalues) of output proj are |
771 | ** (hopefully) approximate tangents to the manifold to which particles |
772 | ** are constrained. It is *not* the local tangent of the directions |
773 | ** along which particles are allowed to move during constraint |
774 | ** satisfaction (that is given by creaseProj for creases) |
775 | ** |
776 | ** this can assume that probe() has just been called |
777 | */ |
778 | void |
779 | _pullConstraintTangent(pullTask *task, pullPoint *point, |
780 | /* output */ |
781 | double proj[9]) { |
782 | double vec[4], nvec[3], outer[9], len, posproj[9], negproj[9]; |
783 | |
784 | ELL_3M_IDENTITY_SET(proj)((((proj)+0)[0] = (1), ((proj)+0)[1] = (0), ((proj)+0)[2] = ( 0)), (((proj)+3)[0] = (0), ((proj)+3)[1] = (1), ((proj)+3)[2] = (0)), (((proj)+6)[0] = (0), ((proj)+6)[1] = (0), ((proj)+6 )[2] = (1))); /* NOTE: we are starting with identity . . . */ |
785 | switch (task->pctx->constraint) { |
786 | case pullInfoHeight: |
787 | creaseProj(task, point, |
788 | !!task->pctx->ispec[pullInfoTangent1], |
789 | !!task->pctx->ispec[pullInfoTangent2], |
790 | !!task->pctx->ispec[pullInfoNegativeTangent1], |
791 | !!task->pctx->ispec[pullInfoNegativeTangent2], |
792 | posproj, negproj); |
793 | /* .. and subracting out output from creaseProj */ |
794 | ELL_3M_SUB(proj, proj, posproj)((proj)[0] = (proj)[0] - (posproj)[0], (proj)[1] = (proj)[1] - (posproj)[1], (proj)[2] = (proj)[2] - (posproj)[2], (proj)[3 ] = (proj)[3] - (posproj)[3], (proj)[4] = (proj)[4] - (posproj )[4], (proj)[5] = (proj)[5] - (posproj)[5], (proj)[6] = (proj )[6] - (posproj)[6], (proj)[7] = (proj)[7] - (posproj)[7], (proj )[8] = (proj)[8] - (posproj)[8]); |
795 | ELL_3M_SUB(proj, proj, negproj)((proj)[0] = (proj)[0] - (negproj)[0], (proj)[1] = (proj)[1] - (negproj)[1], (proj)[2] = (proj)[2] - (negproj)[2], (proj)[3 ] = (proj)[3] - (negproj)[3], (proj)[4] = (proj)[4] - (negproj )[4], (proj)[5] = (proj)[5] - (negproj)[5], (proj)[6] = (proj )[6] - (negproj)[6], (proj)[7] = (proj)[7] - (negproj)[7], (proj )[8] = (proj)[8] - (negproj)[8]); |
796 | break; |
797 | case pullInfoHeightLaplacian: |
798 | case pullInfoIsovalue: |
799 | if (pullInfoHeightLaplacian == task->pctx->constraint) { |
800 | /* using gradient of height as approx normal to laplacian 0-crossing */ |
801 | pullPointScalar(task->pctx, point, pullInfoHeight, vec, NULL((void*)0)); |
802 | } else { |
803 | pullPointScalar(task->pctx, point, pullInfoIsovalue, vec, NULL((void*)0)); |
804 | } |
805 | ELL_3V_NORM(nvec, vec, len)(len = (sqrt((((vec))[0]*((vec))[0] + ((vec))[1]*((vec))[1] + ((vec))[2]*((vec))[2]))), ((nvec)[0] = (1.0/len)*(vec)[0], ( nvec)[1] = (1.0/len)*(vec)[1], (nvec)[2] = (1.0/len)*(vec)[2] )); |
806 | if (len) { |
807 | /* .. or and subracting out tensor product of normal with itself */ |
808 | ELL_3MV_OUTER(outer, nvec, nvec)((((outer)+0)[0] = ((nvec)[0])*((nvec))[0], ((outer)+0)[1] = ( (nvec)[0])*((nvec))[1], ((outer)+0)[2] = ((nvec)[0])*((nvec)) [2]), (((outer)+3)[0] = ((nvec)[1])*((nvec))[0], ((outer)+3)[ 1] = ((nvec)[1])*((nvec))[1], ((outer)+3)[2] = ((nvec)[1])*(( nvec))[2]), (((outer)+6)[0] = ((nvec)[2])*((nvec))[0], ((outer )+6)[1] = ((nvec)[2])*((nvec))[1], ((outer)+6)[2] = ((nvec)[2 ])*((nvec))[2])); |
809 | ELL_3M_SUB(proj, proj, outer)((proj)[0] = (proj)[0] - (outer)[0], (proj)[1] = (proj)[1] - ( outer)[1], (proj)[2] = (proj)[2] - (outer)[2], (proj)[3] = (proj )[3] - (outer)[3], (proj)[4] = (proj)[4] - (outer)[4], (proj) [5] = (proj)[5] - (outer)[5], (proj)[6] = (proj)[6] - (outer) [6], (proj)[7] = (proj)[7] - (outer)[7], (proj)[8] = (proj)[8 ] - (outer)[8]); |
810 | } |
811 | break; |
812 | } |
813 | return; |
814 | } |
815 | |
816 | /* |
817 | ** returns the *dimension* (not codimension) of the constraint manifold: |
818 | ** 0 for points |
819 | ** 1 for lines |
820 | ** 2 for surfaces |
821 | ** This is nontrivial because of the different ways that constraints |
822 | ** can be expressed, combined with the possibility of pctx->flag.zeroZ |
823 | ** |
824 | ** a -1 return value represents a biff-able error |
825 | */ |
826 | int |
827 | _pullConstraintDim(const pullContext *pctx) { |
828 | static const char me[]="_pullConstraintDim"; |
829 | int ret, t1, t2, nt1, nt2; |
830 | |
831 | switch (pctx->constraint) { |
832 | case pullInfoHeightLaplacian: /* zero-crossing edges */ |
833 | ret = (pctx->flag.zeroZ ? 1 : 2); |
834 | break; |
835 | case pullInfoIsovalue: |
836 | ret = (pctx->flag.zeroZ ? 1 : 2); |
837 | break; |
838 | case pullInfoHeight: |
839 | t1 = !!pctx->ispec[pullInfoTangent1]; |
840 | t2 = !!pctx->ispec[pullInfoTangent2]; |
841 | nt1 = !!pctx->ispec[pullInfoNegativeTangent1]; |
842 | nt2 = !!pctx->ispec[pullInfoNegativeTangent2]; |
843 | switch (t1 + t2 + nt1 + nt2) { |
844 | case 0: |
845 | ret = 0; |
846 | break; |
847 | case 3: |
848 | if (pctx->flag.zeroZ) { |
849 | biffAddf(PULLpullBiffKey, "%s: can't have three of (%s,%s,%s,%s) tangents with " |
850 | "2-D data (pctx->flag.zeroZ)", me, |
851 | airEnumStr(pullInfo, pullInfoTangent1), |
852 | airEnumStr(pullInfo, pullInfoTangent2), |
853 | airEnumStr(pullInfo, pullInfoNegativeTangent1), |
854 | airEnumStr(pullInfo, pullInfoNegativeTangent2)); |
855 | return -1; |
856 | } /* else we're in 3D; 3 constraints -> point features */ |
857 | ret = 0; |
858 | break; |
859 | case 1: |
860 | ret = (pctx->flag.zeroZ ? 1 : 2); |
861 | break; |
862 | case 2: |
863 | ret = (pctx->flag.zeroZ ? 0 : 1); |
864 | break; |
865 | default: |
866 | biffAddf(PULLpullBiffKey, "%s: can't simultaneously use all tangents " |
867 | "(%s,%s,%s,%s) as this implies co-dimension of -1", me, |
868 | airEnumStr(pullInfo, pullInfoTangent1), |
869 | airEnumStr(pullInfo, pullInfoTangent2), |
870 | airEnumStr(pullInfo, pullInfoNegativeTangent1), |
871 | airEnumStr(pullInfo, pullInfoNegativeTangent2)); |
872 | return -1; |
873 | } |
874 | break; |
875 | default: |
876 | biffAddf(PULLpullBiffKey, "%s: constraint on %s (%d) unimplemented", me, |
877 | airEnumStr(pullInfo, pctx->constraint), pctx->constraint); |
878 | return -1; |
879 | } |
880 | return ret; |
881 | } |
882 |