00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #ifndef lint
00039 static const char RCSroots[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/roots.c,v 14.12 2006/09/16 02:04:26 lbutler Exp $ (BRL)";
00040 #endif
00041
00042 #include "common.h"
00043
00044
00045
00046 #include <stdio.h>
00047 #include <math.h>
00048 #include "machine.h"
00049 #include "bu.h"
00050 #include "vmath.h"
00051 #include "bn.h"
00052 #include "raytrace.h"
00053
00054 int rt_poly_roots(register bn_poly_t *eqn, register bn_complex_t *roots, const char *name);
00055 void rt_poly_eval_w_2derivatives(register bn_complex_t *cZ, register bn_poly_t *eqn, register bn_complex_t *b, register bn_complex_t *c, register bn_complex_t *d);
00056 void rt_poly_deflate(register bn_poly_t *oldP, register bn_complex_t *root);
00057 int rt_poly_findroot(register bn_poly_t *eqn, register bn_complex_t *nxZ, const char *str);
00058 int rt_poly_checkroots(register bn_poly_t *eqn, bn_complex_t *roots, register int nroots);
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071 int
00072 rt_poly_roots(register bn_poly_t *eqn,
00073 register bn_complex_t roots[],
00074 const char *name)
00075 {
00076 register int n;
00077 LOCAL fastf_t factor;
00078
00079
00080
00081
00082 while( NEAR_ZERO( eqn->cf[0], SMALL ) ) {
00083 for ( n=0; n <= eqn->dgr; n++ ){
00084 eqn->cf[n] = eqn->cf[n+1];
00085 }
00086 if ( --eqn->dgr <= 0 )
00087 return 0;
00088 }
00089
00090
00091
00092
00093 factor = 1.0 / eqn->cf[0];
00094 (void) bn_poly_scale( eqn, factor );
00095 n = 0;
00096
00097
00098
00099
00100 while( NEAR_ZERO( eqn->cf[eqn->dgr], SMALL ) ) {
00101 roots[n].re = roots[n].im = 0.0;
00102 --eqn->dgr;
00103 ++n;
00104 }
00105
00106 while ( eqn->dgr > 2 ){
00107 if ( eqn->dgr == 4 ) {
00108 if( rt_poly_quartic_roots( eqn, &roots[n] ) ) {
00109 if( rt_poly_checkroots( eqn, &roots[n], 4 ) == 0 ) {
00110 return( n+4 );
00111 }
00112 }
00113 } else if ( eqn->dgr == 3 ) {
00114 if( rt_poly_cubic_roots( eqn, &roots[n] ) ) {
00115 if ( rt_poly_checkroots( eqn, &roots[n], 3 ) == 0 ) {
00116 return ( n+3 );
00117 }
00118 }
00119 }
00120
00121
00122
00123
00124
00125 bn_cx_cons( &roots[n], 0.0, SMALL );
00126 if ( (rt_poly_findroot( eqn, &roots[n], name )) < 0 )
00127 return(n);
00128
00129 if ( fabs(roots[n].im) > 1.0e-5* fabs(roots[n].re) ){
00130
00131
00132
00133
00134 ++n;
00135 roots[n] = roots[n-1];
00136 bn_cx_conj(&roots[n]);
00137 } else {
00138
00139 roots[n].im = 0.0;
00140 }
00141
00142 rt_poly_deflate( eqn, &roots[n] );
00143 ++n;
00144 }
00145
00146
00147
00148
00149 if ( eqn->dgr == 1 ){
00150 roots[n].re = -(eqn->cf[1]);
00151 roots[n].im = 0.0;
00152 ++n;
00153 } else if ( eqn->dgr == 2 ){
00154 rt_poly_quadratic_roots( eqn, &roots[n] );
00155 n += 2;
00156 }
00157 return n;
00158 }
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180 int
00181 rt_poly_findroot(register bn_poly_t *eqn,
00182 register bn_complex_t *nxZ,
00183 const char *str)
00184 {
00185 LOCAL bn_complex_t p0, p1, p2;
00186 LOCAL bn_complex_t p1_H;
00187 LOCAL bn_complex_t cZ, cH;
00188 LOCAL bn_complex_t T;
00189 FAST fastf_t diff=0.0;
00190 FAST fastf_t b=0.0;
00191 LOCAL int n;
00192 register int i;
00193
00194 for( i=0; i < 20; i++ ) {
00195 cZ = *nxZ;
00196 rt_poly_eval_w_2derivatives( &cZ, eqn, &p0, &p1, &p2 );
00197
00198
00199 n = eqn->dgr-1;
00200 bn_cx_mul2( &cH, &p1, &p1 );
00201 bn_cx_scal( &cH, (double)(n*n) );
00202 bn_cx_mul2( &T, &p2, &p0 );
00203 bn_cx_scal( &T, (double)(eqn->dgr*n) );
00204 bn_cx_sub( &cH, &T );
00205
00206
00207
00208
00209
00210
00211 bn_cx_sqrt( &cH, &cH );
00212 p1_H = p1;
00213 bn_cx_sub( &p1_H, &cH );
00214 bn_cx_add( &p1, &cH );
00215 bn_cx_scal( &p0, (double)(eqn->dgr) );
00216 if ( bn_cx_amplsq( &p1_H ) > bn_cx_amplsq( &p1 ) ){
00217 bn_cx_div( &p0, &p1_H);
00218 bn_cx_sub( nxZ, &p0 );
00219 } else {
00220 bn_cx_div( &p0, &p1 );
00221 bn_cx_sub( nxZ, &p0 );
00222 }
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235 b = bn_cx_amplsq( nxZ );
00236 diff = bn_cx_amplsq( &p0 );
00237 if( b < diff )
00238 continue;
00239 if( (b-diff) == b )
00240 return(i);
00241 if( diff > (b - diff)*1.0e-5 )
00242 continue;
00243 return(i);
00244 }
00245
00246
00247 bu_log("rt_poly_findroot: solving for %s didn't converge in %d iterations, b=%g, diff=%g\n",
00248 str, i, b, diff);
00249 bu_log("nxZ=%gR+%gI, p0=%gR+%gI\n", nxZ->re, nxZ->im, p0.re, p0.im);
00250 return(-1);
00251 }
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274 void
00275 rt_poly_eval_w_2derivatives(register bn_complex_t *cZ, register bn_poly_t *eqn, register bn_complex_t *b, register bn_complex_t *c, register bn_complex_t *d)
00276
00277
00278
00279 {
00280 register int n;
00281 register int m;
00282
00283 bn_cx_cons(b,eqn->cf[0],0.0);
00284 *c = *b;
00285 *d = *c;
00286
00287 for ( n=1; ( m = eqn->dgr - n ) >= 0; ++n){
00288 bn_cx_mul( b, cZ );
00289 b->re += eqn->cf[n];
00290 if ( m > 0 ){
00291 bn_cx_mul( c, cZ );
00292 bn_cx_add( c, b );
00293 }
00294 if ( m > 1 ){
00295 bn_cx_mul( d, cZ );
00296 bn_cx_add( d, c );
00297 }
00298 }
00299 }
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324 int
00325 rt_poly_checkroots(register bn_poly_t *eqn, bn_complex_t *roots, register int nroots)
00326 {
00327 register fastf_t er, ei;
00328 register fastf_t zr, zi;
00329 register int n;
00330 int m;
00331
00332 for ( m=0; m < nroots; ++m ){
00333
00334 zr = bn_cx_real( &roots[m] );
00335 zi = bn_cx_imag( &roots[m] );
00336
00337
00338 er = eqn->cf[0];
00339
00340
00341
00342 ei = er*zi;
00343 er = er*zr + eqn->cf[1];
00344
00345
00346 for ( n=2; n <= eqn->dgr; ++n) {
00347 register fastf_t tr, ti;
00348 tr = er*zr - ei*zi + eqn->cf[n];
00349 ti = er*zi + ei*zr;
00350 er = tr;
00351 ei = ti;
00352 }
00353 if ( fabs( er ) > 1.0e-5 || fabs( ei ) > 1.0e-5 )
00354 return 1;
00355 }
00356
00357 return 0;
00358 }
00359
00360
00361
00362
00363
00364
00365
00366
00367 void
00368 rt_poly_deflate(register bn_poly_t *oldP, register bn_complex_t *root)
00369 {
00370 LOCAL bn_poly_t div, rem;
00371
00372
00373
00374
00375
00376 if ( NEAR_ZERO( root->im, SMALL) ) {
00377
00378 div.dgr = 1;
00379 div.cf[0] = 1;
00380 div.cf[1] = - root->re;
00381 } else {
00382
00383 div.dgr = 2;
00384 div.cf[0] = 1;
00385 div.cf[1] = -2 * root->re;
00386 div.cf[2] = bn_cx_amplsq( root );
00387 }
00388
00389
00390
00391
00392
00393 rt_poly_synthetic_division( oldP, &div, oldP, &rem );
00394 }
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404