1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /* $Id: db_utilities_poly.h,v 1.2 2010/09/03 12:00:11 bsouthall Exp $ */ 18 19 #ifndef DB_UTILITIES_POLY 20 #define DB_UTILITIES_POLY 21 22 #include "db_utilities.h" 23 24 25 26 /***************************************************************** 27 * Lean and mean begins here * 28 *****************************************************************/ 29 /*! 30 * \defgroup LMPolynomial (LM) Polynomial utilities (solvers, arithmetic, evaluation, etc.) 31 */ 32 /*\{*/ 33 34 /*! 35 In debug mode closed form quadratic solving takes on the order of 15 microseconds 36 while eig of the companion matrix takes about 1.1 milliseconds 37 Speed-optimized code in release mode solves a quadratic in 0.3 microseconds on 450MHz 38 */ 39 inline void db_SolveQuadratic(double *roots,int *nr_roots,double a,double b,double c) 40 { 41 double rs,srs,q; 42 43 /*For non-degenerate quadratics 44 [5 mult 2 add 1 sqrt=7flops 1func]*/ 45 if(a==0.0) 46 { 47 if(b==0.0) *nr_roots=0; 48 else 49 { 50 roots[0]= -c/b; 51 *nr_roots=1; 52 } 53 } 54 else 55 { 56 rs=b*b-4.0*a*c; 57 if(rs>=0.0) 58 { 59 *nr_roots=2; 60 srs=sqrt(rs); 61 q= -0.5*(b+db_sign(b)*srs); 62 roots[0]=q/a; 63 /*If b is zero db_sign(b) returns 1, 64 so q is only zero when b=0 and c=0*/ 65 if(q==0.0) *nr_roots=1; 66 else roots[1]=c/q; 67 } 68 else *nr_roots=0; 69 } 70 } 71 72 /*! 73 In debug mode closed form cubic solving takes on the order of 45 microseconds 74 while eig of the companion matrix takes about 1.3 milliseconds 75 Speed-optimized code in release mode solves a cubic in 1.5 microseconds on 450MHz 76 For a non-degenerate cubic with two roots, the first root is the single root and 77 the second root is the double root 78 */ 79 DB_API void db_SolveCubic(double *roots,int *nr_roots,double a,double b,double c,double d); 80 /*! 81 In debug mode closed form quartic solving takes on the order of 0.1 milliseconds 82 while eig of the companion matrix takes about 1.5 milliseconds 83 Speed-optimized code in release mode solves a quartic in 2.6 microseconds on 450MHz*/ 84 DB_API void db_SolveQuartic(double *roots,int *nr_roots,double a,double b,double c,double d,double e); 85 /*! 86 Quartic solving where a solution is forced when splitting into quadratics, which 87 can be good if the quartic is sometimes in fact a quadratic, such as in absolute orientation 88 when the data is planar*/ 89 DB_API void db_SolveQuarticForced(double *roots,int *nr_roots,double a,double b,double c,double d,double e); 90 91 inline double db_PolyEval1(const double p[2],double x) 92 { 93 return(p[0]+x*p[1]); 94 } 95 96 inline void db_MultiplyPoly1_1(double *d,const double *a,const double *b) 97 { 98 double a0,a1; 99 double b0,b1; 100 a0=a[0];a1=a[1]; 101 b0=b[0];b1=b[1]; 102 103 d[0]=a0*b0; 104 d[1]=a0*b1+a1*b0; 105 d[2]= a1*b1; 106 } 107 108 inline void db_MultiplyPoly0_2(double *d,const double *a,const double *b) 109 { 110 double a0; 111 double b0,b1,b2; 112 a0=a[0]; 113 b0=b[0];b1=b[1];b2=b[2]; 114 115 d[0]=a0*b0; 116 d[1]=a0*b1; 117 d[2]=a0*b2; 118 } 119 120 inline void db_MultiplyPoly1_2(double *d,const double *a,const double *b) 121 { 122 double a0,a1; 123 double b0,b1,b2; 124 a0=a[0];a1=a[1]; 125 b0=b[0];b1=b[1];b2=b[2]; 126 127 d[0]=a0*b0; 128 d[1]=a0*b1+a1*b0; 129 d[2]=a0*b2+a1*b1; 130 d[3]= a1*b2; 131 } 132 133 134 inline void db_MultiplyPoly1_3(double *d,const double *a,const double *b) 135 { 136 double a0,a1; 137 double b0,b1,b2,b3; 138 a0=a[0];a1=a[1]; 139 b0=b[0];b1=b[1];b2=b[2];b3=b[3]; 140 141 d[0]=a0*b0; 142 d[1]=a0*b1+a1*b0; 143 d[2]=a0*b2+a1*b1; 144 d[3]=a0*b3+a1*b2; 145 d[4]= a1*b3; 146 } 147 /*! 148 Multiply d=a*b where a is one degree and b is two degree*/ 149 inline void db_AddPolyProduct0_1(double *d,const double *a,const double *b) 150 { 151 double a0; 152 double b0,b1; 153 a0=a[0]; 154 b0=b[0];b1=b[1]; 155 156 d[0]+=a0*b0; 157 d[1]+=a0*b1; 158 } 159 inline void db_AddPolyProduct0_2(double *d,const double *a,const double *b) 160 { 161 double a0; 162 double b0,b1,b2; 163 a0=a[0]; 164 b0=b[0];b1=b[1];b2=b[2]; 165 166 d[0]+=a0*b0; 167 d[1]+=a0*b1; 168 d[2]+=a0*b2; 169 } 170 /*! 171 Multiply d=a*b where a is one degree and b is two degree*/ 172 inline void db_SubtractPolyProduct0_0(double *d,const double *a,const double *b) 173 { 174 double a0; 175 double b0; 176 a0=a[0]; 177 b0=b[0]; 178 179 d[0]-=a0*b0; 180 } 181 182 inline void db_SubtractPolyProduct0_1(double *d,const double *a,const double *b) 183 { 184 double a0; 185 double b0,b1; 186 a0=a[0]; 187 b0=b[0];b1=b[1]; 188 189 d[0]-=a0*b0; 190 d[1]-=a0*b1; 191 } 192 193 inline void db_SubtractPolyProduct0_2(double *d,const double *a,const double *b) 194 { 195 double a0; 196 double b0,b1,b2; 197 a0=a[0]; 198 b0=b[0];b1=b[1];b2=b[2]; 199 200 d[0]-=a0*b0; 201 d[1]-=a0*b1; 202 d[2]-=a0*b2; 203 } 204 205 inline void db_SubtractPolyProduct1_3(double *d,const double *a,const double *b) 206 { 207 double a0,a1; 208 double b0,b1,b2,b3; 209 a0=a[0];a1=a[1]; 210 b0=b[0];b1=b[1];b2=b[2];b3=b[3]; 211 212 d[0]-=a0*b0; 213 d[1]-=a0*b1+a1*b0; 214 d[2]-=a0*b2+a1*b1; 215 d[3]-=a0*b3+a1*b2; 216 d[4]-= a1*b3; 217 } 218 219 inline void db_CharacteristicPolynomial4x4(double p[5],const double A[16]) 220 { 221 /*All two by two determinants of the first two rows*/ 222 double two01[3],two02[3],two03[3],two12[3],two13[3],two23[3]; 223 /*Polynomials representing third and fourth row of A*/ 224 double P0[2],P1[2],P2[2],P3[2]; 225 double P4[2],P5[2],P6[2],P7[2]; 226 /*All three by three determinants of the first three rows*/ 227 double neg_three0[4],neg_three1[4],three2[4],three3[4]; 228 229 /*Compute 2x2 determinants*/ 230 two01[0]=A[0]*A[5]-A[1]*A[4]; 231 two01[1]= -(A[0]+A[5]); 232 two01[2]=1.0; 233 234 two02[0]=A[0]*A[6]-A[2]*A[4]; 235 two02[1]= -A[6]; 236 237 two03[0]=A[0]*A[7]-A[3]*A[4]; 238 two03[1]= -A[7]; 239 240 two12[0]=A[1]*A[6]-A[2]*A[5]; 241 two12[1]=A[2]; 242 243 two13[0]=A[1]*A[7]-A[3]*A[5]; 244 two13[1]=A[3]; 245 246 two23[0]=A[2]*A[7]-A[3]*A[6]; 247 248 P0[0]=A[8]; 249 P1[0]=A[9]; 250 P2[0]=A[10];P2[1]= -1.0; 251 P3[0]=A[11]; 252 253 P4[0]=A[12]; 254 P5[0]=A[13]; 255 P6[0]=A[14]; 256 P7[0]=A[15];P7[1]= -1.0; 257 258 /*Compute 3x3 determinants.Note that the highest 259 degree polynomial goes first and the smaller ones 260 are added or subtracted from it*/ 261 db_MultiplyPoly1_1( neg_three0,P2,two13); 262 db_SubtractPolyProduct0_0(neg_three0,P1,two23); 263 db_SubtractPolyProduct0_1(neg_three0,P3,two12); 264 265 db_MultiplyPoly1_1( neg_three1,P2,two03); 266 db_SubtractPolyProduct0_1(neg_three1,P3,two02); 267 db_SubtractPolyProduct0_0(neg_three1,P0,two23); 268 269 db_MultiplyPoly0_2( three2,P3,two01); 270 db_AddPolyProduct0_1( three2,P0,two13); 271 db_SubtractPolyProduct0_1(three2,P1,two03); 272 273 db_MultiplyPoly1_2( three3,P2,two01); 274 db_AddPolyProduct0_1( three3,P0,two12); 275 db_SubtractPolyProduct0_1(three3,P1,two02); 276 277 /*Compute 4x4 determinants*/ 278 db_MultiplyPoly1_3( p,P7,three3); 279 db_AddPolyProduct0_2( p,P4,neg_three0); 280 db_SubtractPolyProduct0_2(p,P5,neg_three1); 281 db_SubtractPolyProduct0_2(p,P6,three2); 282 } 283 284 inline void db_RealEigenvalues4x4(double lambda[4],int *nr_roots,const double A[16],int forced=0) 285 { 286 double p[5]; 287 288 db_CharacteristicPolynomial4x4(p,A); 289 if(forced) db_SolveQuarticForced(lambda,nr_roots,p[4],p[3],p[2],p[1],p[0]); 290 else db_SolveQuartic(lambda,nr_roots,p[4],p[3],p[2],p[1],p[0]); 291 } 292 293 /*! 294 Compute the unit norm eigenvector v of the matrix A corresponding 295 to the eigenvalue lambda 296 [96mult 60add 1sqrt=156flops 1sqrt]*/ 297 inline void db_EigenVector4x4(double v[4],double lambda,const double A[16]) 298 { 299 double a0,a5,a10,a15; 300 double d01,d02,d03,d12,d13,d23; 301 double e01,e02,e03,e12,e13,e23; 302 double C[16],n0,n1,n2,n3,m; 303 304 /*Compute diagonal 305 [4add=4flops]*/ 306 a0=A[0]-lambda; 307 a5=A[5]-lambda; 308 a10=A[10]-lambda; 309 a15=A[15]-lambda; 310 311 /*Compute 2x2 determinants of rows 1,2 and 3,4 312 [24mult 12add=36flops]*/ 313 d01=a0*a5 -A[1]*A[4]; 314 d02=a0*A[6] -A[2]*A[4]; 315 d03=a0*A[7] -A[3]*A[4]; 316 d12=A[1]*A[6]-A[2]*a5; 317 d13=A[1]*A[7]-A[3]*a5; 318 d23=A[2]*A[7]-A[3]*A[6]; 319 320 e01=A[8]*A[13]-A[9] *A[12]; 321 e02=A[8]*A[14]-a10 *A[12]; 322 e03=A[8]*a15 -A[11]*A[12]; 323 e12=A[9]*A[14]-a10 *A[13]; 324 e13=A[9]*a15 -A[11]*A[13]; 325 e23=a10 *a15 -A[11]*A[14]; 326 327 /*Compute matrix of cofactors 328 [48mult 32 add=80flops*/ 329 C[0]= (a5 *e23-A[6]*e13+A[7]*e12); 330 C[1]= -(A[4]*e23-A[6]*e03+A[7]*e02); 331 C[2]= (A[4]*e13-a5 *e03+A[7]*e01); 332 C[3]= -(A[4]*e12-a5 *e02+A[6]*e01); 333 334 C[4]= -(A[1]*e23-A[2]*e13+A[3]*e12); 335 C[5]= (a0 *e23-A[2]*e03+A[3]*e02); 336 C[6]= -(a0 *e13-A[1]*e03+A[3]*e01); 337 C[7]= (a0 *e12-A[1]*e02+A[2]*e01); 338 339 C[8]= (A[13]*d23-A[14]*d13+a15 *d12); 340 C[9]= -(A[12]*d23-A[14]*d03+a15 *d02); 341 C[10]= (A[12]*d13-A[13]*d03+a15 *d01); 342 C[11]= -(A[12]*d12-A[13]*d02+A[14]*d01); 343 344 C[12]= -(A[9]*d23-a10 *d13+A[11]*d12); 345 C[13]= (A[8]*d23-a10 *d03+A[11]*d02); 346 C[14]= -(A[8]*d13-A[9]*d03+A[11]*d01); 347 C[15]= (A[8]*d12-A[9]*d02+a10 *d01); 348 349 /*Compute square sums of rows 350 [16mult 12add=28flops*/ 351 n0=db_sqr(C[0]) +db_sqr(C[1]) +db_sqr(C[2]) +db_sqr(C[3]); 352 n1=db_sqr(C[4]) +db_sqr(C[5]) +db_sqr(C[6]) +db_sqr(C[7]); 353 n2=db_sqr(C[8]) +db_sqr(C[9]) +db_sqr(C[10])+db_sqr(C[11]); 354 n3=db_sqr(C[12])+db_sqr(C[13])+db_sqr(C[14])+db_sqr(C[15]); 355 356 /*Take the largest norm row and normalize 357 [4mult 1 sqrt=4flops 1sqrt]*/ 358 if(n0>=n1 && n0>=n2 && n0>=n3) 359 { 360 m=db_SafeReciprocal(sqrt(n0)); 361 db_MultiplyScalarCopy4(v,C,m); 362 } 363 else if(n1>=n2 && n1>=n3) 364 { 365 m=db_SafeReciprocal(sqrt(n1)); 366 db_MultiplyScalarCopy4(v,&(C[4]),m); 367 } 368 else if(n2>=n3) 369 { 370 m=db_SafeReciprocal(sqrt(n2)); 371 db_MultiplyScalarCopy4(v,&(C[8]),m); 372 } 373 else 374 { 375 m=db_SafeReciprocal(sqrt(n3)); 376 db_MultiplyScalarCopy4(v,&(C[12]),m); 377 } 378 } 379 380 381 382 /*\}*/ 383 #endif /* DB_UTILITIES_POLY */ 384