1 /* _________________________________________________________________________
2 *
3 * Acro: A Common Repository for Optimizers
4 * Copyright (c) 2008 Sandia Corporation.
5 * This software is distributed under the BSD License.
6 * Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
7 * the U.S. Government retains certain rights in this software.
8 * For more information, see the README.txt file in the top Acro directory.
9 * _________________________________________________________________________
10 */
11 //
12 // Coliny_DockingPS.cpp
13 //
14
15 #include <acro_config.h>
16
17 #include <scolib/DockingPS.h>
18
19 #include <colin/SolverMngr.h>
20
21 #define M_TWO_PI (2.0*M_PI)
22 #define TESTING
23
24 using namespace std;
25 using namespace utilib;
26
27 namespace scolib {
28
29 namespace {
30
renormalize(double & nx,double & ny,double & nz)31 void renormalize(double& nx, double& ny, double& nz)
32 {
33 double norm = sqrt(nx*nx + ny*ny + nz*nz);
34 nx /= norm;
35 ny /= norm;
36 nz /= norm;
37 }
38
compute_z(double x,double y)39 double compute_z(double x, double y)
40 {
41 double tmp = 1.0 - x*x - y*y;
42 if (tmp < -1e-7)
43 EXCEPTION_MNGR(runtime_error, "Bad x/y values!");
44 return sqrt(max(0.0,tmp));
45 }
46
47
48 }
49
DockingPS()50 DockingPS::DockingPS()
51 {
52 num_rotations=4;
53 last_x=last_y=last_theta=0.0;
54 properties.privilegedGet("expansion_factor").set_readonly();
55 initial_angle=80.0;
56
57 reset_signal.connect(boost::bind(&DockingPS::reset_DockingPS, this));
58 }
59
60
61
reset_DockingPS()62 void DockingPS::reset_DockingPS()
63 {
64 if ( problem.empty() ) return;
65
66 if (Delta_init > 1.0)
67 Delta_init = 1.0;
68
69 basis_str = "coordinate";
70
71 ntrials = ncore_trials = 2*problem->num_real_vars.as<size_t>()
72 - 4 + num_rotations;
73 ex_factor=1.0;
74 }
75
76
77
generate_trial(int id,const DoubleVector & x_,DoubleVector & trial,double scale,bool & feasible,const DoubleVector & _bias)78 void DockingPS::generate_trial(int id, const DoubleVector& x_,
79 DoubleVector& trial, double scale,
80 bool& feasible, const DoubleVector& _bias)
81 {
82 //
83 // Initial setup
84 //
85 feasible=true;
86 if (debug > 4) {
87 ucout << "Current Point: " << x_ << endl;
88 }
89 //
90 // The index of the dimension that is being changed
91 // 0 - 2 positive steps in the positional parameters
92 // 3 - n-4 positive steps in the torsion angles
93 // n-3 - n-1 negative steps in the positional parameters
94 // n - 2n-7 negative steps in the torsion angles
95 // 2n-6 - 2n-5 positive/negative steps in rotations
96 // 2n-4 - 2n-4+k k rotations of quarternion angles
97 //
98 size_type curr = ndx[id];
99 size_type n = x_.size();
100 trial << x_;
101
102 if (curr <= 2) {
103 trial[curr] += scale*Sigma[curr];
104 if (trial[curr] > upper_bc[curr])
105 feasible=false;
106 }
107
108 else if (curr <= (n-4)) {
109 trial[curr+3] += scale*Sigma[curr+3];
110 if (trial[curr+3] > (2*upper_bc[curr+3]-lower_bc[curr+3]))
111 feasible=false;
112 }
113
114 else if (curr <= (n-1)) {
115 trial[curr-n+3] -= scale*Sigma[curr-n+3];
116 if (trial[curr-n+3] < lower_bc[curr-n+3])
117 feasible=false;
118 }
119
120 else if (curr <= (2*n-7)) {
121 trial[curr-n+6] -= scale*Sigma[curr-n+6];
122 if (trial[curr-n+6] < (2*lower_bc[curr-n+6]-upper_bc[curr-n+6]))
123 feasible=false;
124 if (trial[curr-n+6] < 0.0)
125 trial[curr-n+6] += M_TWO_PI;
126 }
127
128 else if (curr == (2*n-6)) {
129 trial[5] -= scale*Sigma[5];
130 if (trial[5] < (2*lower_bc[5]-upper_bc[5]))
131 feasible=false;
132 if (trial[5] < 0.0)
133 trial[5] += M_TWO_PI;
134 }
135
136 else if (curr == (2*n-5)) {
137 trial[5] += scale*Sigma[5];
138 if (trial[5] > (2*upper_bc[5]-lower_bc[5]))
139 feasible=false;
140 if (trial[5] > M_TWO_PI)
141 trial[5] -= M_TWO_PI;
142 }
143
144 else {
145 if (scale != Delta_min)
146 EXCEPTION_MNGR(runtime_error, "BUG HERE");
147
148 rotation_trial(min(scale,Delta_min), curr-(2*n-4), x_[3], x_[4], x_[5],
149 trial[3], trial[4], trial[5]);
150 #if 0
151 else {
152 int tmp = curr-(2*n-4);
153 if (tmp == 0) {
154 trial[3] += scale*Sigma[3];
155 if (trial[3] > (2*upper_bc[3]-lower_bc[3]))
156 feasible=false;
157 }
158 else if (tmp == 1) {
159 trial[4] += scale*Sigma[4];
160 if (trial[4] > (2*upper_bc[4]-lower_bc[4]))
161 feasible=false;
162 }
163 else if (tmp == 2) {
164 trial[3] -= scale*Sigma[3];
165 if (trial[3] > lower_bc[3])
166 feasible=false;
167 }
168 else {
169 trial[4] -= scale*Sigma[4];
170 if (trial[4] > lower_bc[4])
171 feasible=false;
172 }
173 if (feasible && ((trial[3]*trial[3]+trial[4]*trial[4]) > 1.0)) {
174 double z=0.0;
175 renormalize(trial[3],trial[4],z);
176 }
177 }
178 #endif
179 }
180
181 if (debug > 4) {
182 ucout << "Trial Point: " << trial << endl;
183 ucout << "Feasible: " << feasible << endl;
184 }
185 if (debug > 4) {
186 double val=0.0;
187 for (unsigned int i=0; i<x_.size(); i++)
188 val += (trial[i]-x_[i])*(trial[i]-x_[i]);
189 ucout << "Trial Point Length: " << sqrt(val) << endl;
190 }
191
192 //
193 // Collect running stats
194 //
195 if (output_level == 3) {
196 ntrial_points++;
197 if (feasible == true) nfeasible_points++;
198 }
199 }
200
201
202
update_pattern(DoubleVector & prev_iter,DoubleVector & curr_iter,bool flag)203 void DockingPS::update_pattern(DoubleVector& prev_iter,
204 DoubleVector& curr_iter,
205 bool flag)
206 {
207 if (update_flag == 3)
208 EXCEPTION_MNGR(runtime_error, "DockingPS::update_pattern - bad step length update!");
209
210 bool quaternion_diff = ((curr_iter[3] != prev_iter[3]) ||
211 (curr_iter[4] != prev_iter[4]));
212 DEBUGPR(1000, ucout << "DockingPS::update_pattern - update=" << update_flag <<
213 " succ=" << flag <<
214 " quaternion-diff=" << quaternion_diff << endl);
215 //
216 // Don't update the pattern if the quaternion info hasn't changed.
217 // Update the angle if it is negative.
218 //
219 if (curr_iter[5] > M_TWO_PI)
220 EXCEPTION_MNGR(runtime_error, "BUG HERE 3");
221 if ((curr_iter[5] < 0.0) && !flag)
222 EXCEPTION_MNGR(runtime_error, "BUG HERE 4");
223 //
224 // After an unsuccessful iteration, we don't change the pattern orientation,
225 // but we _do_ reduce it in size
226 //
227 if (!flag) {
228 if (update_flag == 2) {
229 last_x = (prev_iter[3] + last_x)/2.0;
230 last_y = (prev_iter[4] + last_y)/2.0;
231 last_z = (last_z + compute_z(prev_iter[3],prev_iter[4]))/2.0;
232 renormalize(last_x,last_y,last_z);
233 last_theta = prev_iter[5];
234 }
235 else
236 EXCEPTION_MNGR(runtime_error, "BUG HERE 2");
237 return;
238 }
239 //
240 // This is a successful iteration, but don't change the quaternion unless
241 // it was the reason for the new iterate.
242 //
243 if (!quaternion_diff) {
244 return;
245 }
246 //
247 // After a successful iteration, last_x,y,z is the previous iteration.
248 //
249 last_x = prev_iter[3];
250 last_y = prev_iter[4];
251 last_z = compute_z(prev_iter[3],prev_iter[4]);
252 if (curr_iter[5] < 0.0) {
253 curr_iter[5] += M_TWO_PI;
254 last_x *= -1;
255 last_y *= -1;
256 last_z *= -1;
257 }
258 renormalize(last_x,last_y,last_z);
259 #if 0
260 WEH - do we need to rotate the pattern?????
261
262 //
263 // After a successful iteration, we need to rotate the pattern.
264 // We may also need to rescale it larger, but we won't be doing that for now
265 //
266 //
267 // Compute a vector 'n' which is perpendicular to the previous iteration
268 // and current iteration
269 //
270 double nx,ny,nz;
271 double cz = sqrt(1-curr_iter[3]*curr_iter[3]-curr_iter[4]*curr_iter[4]);
272 if (flag && quaternion_diff) {
273 double pz = sqrt(1-prev_iter[3]*prev_iter[3]-prev_iter[4]*prev_iter[4]);
274
275 nx = curr_iter[4]*pz - cz*prev_iter[4];
276 ny = cz*prev_iter[3] - curr_iter[3]*pz;
277 nz = curr_iter[3]*prev_iter[4] - curr_iter[4]*prev_iter[3];
278 }
279 else {
280 nx = curr_iter[4]*last_z - cz*last_y;
281 ny = cz*last_x - curr_iter[3]*last_z;
282 nz = curr_iter[3]*last_y - curr_iter[4]*last_x;
283 }
284 renormalize(nx,ny,nz);
285 //
286 //
287 //
288 #if defined(TESTING)
289 double tmp = nx*prev_iter[3] +
290 ny*prev_iter[4] +
291 nz*sqrt(1-prev_iter[3]*prev_iter[3]-prev_iter[4]*prev_iter[4]);
292 if (fabs(tmp) > 1e-5)
293 EXCEPTION_MNGR(runtime_error, "The normal vector doesn't seem normal enough.");
294 if (fabs(min(nx,min(ny,nz))) < 1e-5)
295 EXCEPTION_MNGR(runtime_error, "The normal vector doesn't seem long enough.");
296 #endif
297 //
298 // Rotate the initial point M_PI/2 times Delta about n.
299 // This gives a reference value
300 // for a 'last point'. Rotations of this 'last point' will define subsequent
301 // steps.
302 //
303 rotate(angle, curr_iter[3], curr_iter[4], cz,
304 nx, ny, nz,
305 last_x, last_y, last_z);
306 #endif
307 //
308 // Misc testing
309 //
310 #if 0
311 #if defined(TESTING)
312 double angle = min(1.0, Sigma[3]*Delta)*M_PI/2.0;
313 if (curr_iter[5] < 0.0)
314 EXCEPTION_MNGR(runtime_error, "THIS CANNOT HAPPEN, RIGHT?");
315 double est_dist = 2*sin(angle/2.0);
316 double dist = sqrt((curr_iter[3]-last_x)*(curr_iter[3]-last_x) +
317 (curr_iter[4]-last_y)*(curr_iter[4]-last_y) +
318 (cz-last_z)*(cz-last_z));
319 DEBUGPR(1000, ucout << "UpdatePattern Test: angle=" << angle <<
320 " est=" << est_dist << " dist=" << dist << endl << Flush);
321 DEBUGPR(1000, ucout << "x=" << curr_iter[3] << " y=" << curr_iter[4]
322 << " z=" << cz << " rx=" << last_x << " ry=" << last_y
323 << " rz=" << last_z << endl << Flush);
324 if (fabs(est_dist - dist) > Delta*1e-5)
325 EXCEPTION_MNGR(runtime_error,"The last_* data appears to be incorrect.");
326 #endif
327 #endif
328 }
329
330
331
rotation_trial(double scale,int id,double x,double y,double theta,double & new_x,double & new_y,double & new_theta)332 void DockingPS::rotation_trial(double scale, int id,
333 double x, double y, double theta,
334 double& new_x, double& new_y, double& new_theta)
335 {
336 double z = compute_z(x,y);
337 double new_z;
338 if (id==0) {
339 new_x = last_x;
340 new_y = last_y;
341 new_z = last_z;
342 //new_z = sqrt(1-new_x*new_x-new_y*new_y);
343 }
344 else {
345 rotate( id*2*M_PI/num_rotations,
346 last_x, last_y, last_z,
347 x, y, z,
348 new_x, new_y, new_z);
349 }
350
351
352 //
353 // Misc testing
354 //
355 #if defined(TESTING)
356 double angle = id*2*M_PI/num_rotations;
357 double est_dist = 2*sin(angle/2.0);
358 double dist = sqrt((x-new_x)*(x-new_x) +
359 (y-new_y)*(y-new_y) +
360 (z-new_z)*(z-new_z));
361 double dist2 = sqrt((last_x-new_x)*(last_x-new_x) +
362 (last_y-new_y)*(last_y-new_y) +
363 (last_z-new_z)*(last_z-new_z));
364 DEBUGPR(1000, ucout << "RotationTest: angle=" << angle << " est=" <<
365 est_dist << " dist=" << dist << " DIST=" << dist2 << endl << Flush);
366 DEBUGPR(1000, ucout << "x=" << x << " y=" << y << " z=" << z <<
367 " rx=" << new_x << " ry=" << new_y << " rz=" << new_z <<
368 endl << Flush);
369 DEBUGPR(1000, ucout << "lx=" << last_x << " ly=" << last_y << " lz="
370 << last_z << " rx=" << new_x << " ry=" << new_y << " rz="
371 << new_z << endl << Flush);
372 #if 0
373 if (fabs(est_dist - dist) > scale*1e-5)
374 EXCEPTION_MNGR(runtime_error,"The new_* data appears to be incorrect.");
375 #endif
376 #endif
377
378 if (new_z < 0.0) {
379 new_x *= -1.0;
380 new_y *= -1.0;
381 new_z *= -1.0;
382 new_theta *= -1.0;
383 }
384 }
385
386
387
388 //
389 // Rotate the 'p' vector about 'n', returning the value in 'r'
390 //
rotate(double angle,double px,double py,double pz,double nx,double ny,double nz,double & rx,double & ry,double & rz)391 void DockingPS::rotate(double angle,
392 double px, double py, double pz,
393 double nx, double ny, double nz,
394 double& rx, double& ry, double& rz)
395 {
396 if (angle == 0.0) {
397 rx = px;
398 ry = py;
399 rz = pz;
400 return;
401 }
402
403 double c = cos(angle);
404 double s = sin(angle);
405 double t = 1-c;
406
407 #if 0
408 double p11 = t*nx*nx + c;
409 double p12 = t*nx*ny + s*nz;
410 double p13 = t*nx*nz + s*ny;
411 double p21 = t*nx*ny - s*nz;
412 double p22 = t*ny*ny + c;
413 double p23 = t*ny*nz + s*nz;
414 double p31 = t*nx*nz + s*ny;
415 double p32 = t*ny*nz - s*nx;
416 double p33 = t*nz*nz + c;
417 #endif
418
419 double p11 = t*nx*nx + c;
420 double p21 = t*ny*nx + s*nz;
421 double p31 = t*nz*nx - s*ny;
422 double p12 = t*nx*ny - s*nz;
423 double p22 = t*ny*ny + c;
424 double p32 = t*nz*ny + s*nx;
425 double p13 = t*nx*nz + s*ny;
426 double p23 = t*ny*nz - s*nx;
427 double p33 = t*nz*nz + c;
428
429 #if 0
430 rx = px*p11 + py*p12 + pz*p13;
431 ry = px*p21 + py*p22 + pz*p23;
432 rz = px*p31 + py*p32 + pz*p33;
433 #endif
434 rx = px*p11 + py*p21 + pz*p31;
435 ry = px*p12 + py*p22 + pz*p32;
436 rz = px*p13 + py*p23 + pz*p33;
437 }
438
439
440
set_initial_point(const utilib::AnyRef & point)441 void DockingPS::set_initial_point(const utilib::AnyRef& point)
442 {
443 initial_point_flag=true;
444 utilib::TypeManager()->lexical_cast(point, initial_point);
445 //
446 // Compute an (x,y,z) vector that we assume is co-planar with 'initial_point'
447 //
448 double x=0.0;
449 double y=0.0;
450 double z=0.0;
451 double pz = compute_z(initial_point[3],initial_point[4]);
452 if (initial_point[3] < initial_point[4]) {
453 if (initial_point[3] < pz)
454 x = 1.0;
455 else
456 z = 1.0;
457 }
458 else {
459 if (initial_point[4] > pz)
460 z = 1.0;
461 else
462 y = 1.0;
463 }
464 //
465 // Compute a vector 'n' which is perpendicular to the initial point and
466 // a vector (x,y,z) defined along the largest dimension of the initial point
467 //
468 double nx = y*pz - z*initial_point[4];
469 double ny = z*initial_point[3] - x*pz;
470 double nz = x*initial_point[4] - y*initial_point[3];
471 renormalize(nx,ny,nz);
472 //
473 // Rotate the initial point M_PI/2 times Delta. This gives a reference value
474 // for a 'last point'. Rotations of this 'last point' will define subsequent
475 // steps.
476 //
477 rotate((min(75.0,initial_angle)/90)*M_PI/2.0, initial_point[3], initial_point[4], pz,
478 nx, ny, nz,
479 last_x, last_y, last_z);
480 //
481 // Misc testing
482 //
483 #if defined(TESTING)
484 #if 0
485 double est_dist = 2*sin(angle/2.0);
486 double dist = sqrt((initial_point[3]-last_x)*(initial_point[3]-last_x) +
487 (initial_point[4]-last_y)*(initial_point[4]-last_y) +
488 (pz-last_z)*(pz-last_z));
489 if (fabs(est_dist - dist) > 1e-5)
490 EXCEPTION_MNGR(runtime_error,"The last_* data appears to be incorrect.");
491 #endif
492 #endif
493 }
494
495
496 // Defines scolib::StaticInitializers::DockingPS_bool
497 REGISTER_COLIN_SOLVER_WITH_ALIAS(DockingPS,"sco:DockingPS","sco:dockingps", "The SCO DockingPS optimizer")
498
499 } // namespace scolib
500