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_linalg.cpp,v 1.3 2011/06/17 14:03:31 mbansal Exp $ */ 18 19#include "db_utilities_linalg.h" 20#include "db_utilities.h" 21 22 23 24/***************************************************************** 25* Lean and mean begins here * 26*****************************************************************/ 27 28/*Cholesky-factorize symmetric positive definite 6 x 6 matrix A. Upper 29part of A is used from the input. The Cholesky factor is output as 30subdiagonal part in A and diagonal in d, which is 6-dimensional*/ 31void db_CholeskyDecomp6x6(double A[36],double d[6]) 32{ 33 double s,temp; 34 35 /*[50 mult 35 add 6sqrt=85flops 6func]*/ 36 /*i=0*/ 37 s=A[0]; 38 d[0]=((s>0.0)?sqrt(s):1.0); 39 temp=db_SafeReciprocal(d[0]); 40 A[6]=A[1]*temp; 41 A[12]=A[2]*temp; 42 A[18]=A[3]*temp; 43 A[24]=A[4]*temp; 44 A[30]=A[5]*temp; 45 /*i=1*/ 46 s=A[7]-A[6]*A[6]; 47 d[1]=((s>0.0)?sqrt(s):1.0); 48 temp=db_SafeReciprocal(d[1]); 49 A[13]=(A[8]-A[6]*A[12])*temp; 50 A[19]=(A[9]-A[6]*A[18])*temp; 51 A[25]=(A[10]-A[6]*A[24])*temp; 52 A[31]=(A[11]-A[6]*A[30])*temp; 53 /*i=2*/ 54 s=A[14]-A[12]*A[12]-A[13]*A[13]; 55 d[2]=((s>0.0)?sqrt(s):1.0); 56 temp=db_SafeReciprocal(d[2]); 57 A[20]=(A[15]-A[12]*A[18]-A[13]*A[19])*temp; 58 A[26]=(A[16]-A[12]*A[24]-A[13]*A[25])*temp; 59 A[32]=(A[17]-A[12]*A[30]-A[13]*A[31])*temp; 60 /*i=3*/ 61 s=A[21]-A[18]*A[18]-A[19]*A[19]-A[20]*A[20]; 62 d[3]=((s>0.0)?sqrt(s):1.0); 63 temp=db_SafeReciprocal(d[3]); 64 A[27]=(A[22]-A[18]*A[24]-A[19]*A[25]-A[20]*A[26])*temp; 65 A[33]=(A[23]-A[18]*A[30]-A[19]*A[31]-A[20]*A[32])*temp; 66 /*i=4*/ 67 s=A[28]-A[24]*A[24]-A[25]*A[25]-A[26]*A[26]-A[27]*A[27]; 68 d[4]=((s>0.0)?sqrt(s):1.0); 69 temp=db_SafeReciprocal(d[4]); 70 A[34]=(A[29]-A[24]*A[30]-A[25]*A[31]-A[26]*A[32]-A[27]*A[33])*temp; 71 /*i=5*/ 72 s=A[35]-A[30]*A[30]-A[31]*A[31]-A[32]*A[32]-A[33]*A[33]-A[34]*A[34]; 73 d[5]=((s>0.0)?sqrt(s):1.0); 74} 75 76/*Cholesky-factorize symmetric positive definite n x n matrix A.Part 77above diagonal of A is used from the input, diagonal of A is assumed to 78be stored in d. The Cholesky factor is output as 79subdiagonal part in A and diagonal in d, which is n-dimensional*/ 80void db_CholeskyDecompSeparateDiagonal(double **A,double *d,int n) 81{ 82 int i,j,k; 83 double s; 84 double temp = 0.0; 85 86 for(i=0;i<n;i++) for(j=i;j<n;j++) 87 { 88 if(i==j) s=d[i]; 89 else s=A[i][j]; 90 for(k=i-1;k>=0;k--) s-=A[i][k]*A[j][k]; 91 if(i==j) 92 { 93 d[i]=((s>0.0)?sqrt(s):1.0); 94 temp=db_SafeReciprocal(d[i]); 95 } 96 else A[j][i]=s*temp; 97 } 98} 99 100/*Backsubstitute L%transpose(L)*x=b for x given the Cholesky decomposition 101of an n x n matrix and the right hand side b. The vector b is unchanged*/ 102void db_CholeskyBacksub(double *x,const double * const *A,const double *d,int n,const double *b) 103{ 104 int i,k; 105 double s; 106 107 for(i=0;i<n;i++) 108 { 109 for(s=b[i],k=i-1;k>=0;k--) s-=A[i][k]*x[k]; 110 x[i]=db_SafeDivision(s,d[i]); 111 } 112 for(i=n-1;i>=0;i--) 113 { 114 for(s=x[i],k=i+1;k<n;k++) s-=A[k][i]*x[k]; 115 x[i]=db_SafeDivision(s,d[i]); 116 } 117} 118 119/*Cholesky-factorize symmetric positive definite 3 x 3 matrix A. Part 120above diagonal of A is used from the input, diagonal of A is assumed to 121be stored in d. The Cholesky factor is output as subdiagonal part in A 122and diagonal in d, which is 3-dimensional*/ 123void db_CholeskyDecomp3x3SeparateDiagonal(double A[9],double d[3]) 124{ 125 double s,temp; 126 127 /*i=0*/ 128 s=d[0]; 129 d[0]=((s>0.0)?sqrt(s):1.0); 130 temp=db_SafeReciprocal(d[0]); 131 A[3]=A[1]*temp; 132 A[6]=A[2]*temp; 133 /*i=1*/ 134 s=d[1]-A[3]*A[3]; 135 d[1]=((s>0.0)?sqrt(s):1.0); 136 temp=db_SafeReciprocal(d[1]); 137 A[7]=(A[5]-A[3]*A[6])*temp; 138 /*i=2*/ 139 s=d[2]-A[6]*A[6]-A[7]*A[7]; 140 d[2]=((s>0.0)?sqrt(s):1.0); 141} 142 143/*Backsubstitute L%transpose(L)*x=b for x given the Cholesky decomposition 144of a 3 x 3 matrix and the right hand side b. The vector b is unchanged*/ 145void db_CholeskyBacksub3x3(double x[3],const double A[9],const double d[3],const double b[3]) 146{ 147 /*[42 mult 30 add=72flops]*/ 148 x[0]=db_SafeDivision(b[0],d[0]); 149 x[1]=db_SafeDivision((b[1]-A[3]*x[0]),d[1]); 150 x[2]=db_SafeDivision((b[2]-A[6]*x[0]-A[7]*x[1]),d[2]); 151 x[2]=db_SafeDivision(x[2],d[2]); 152 x[1]=db_SafeDivision((x[1]-A[7]*x[2]),d[1]); 153 x[0]=db_SafeDivision((x[0]-A[6]*x[2]-A[3]*x[1]),d[0]); 154} 155 156/*Backsubstitute L%transpose(L)*x=b for x given the Cholesky decomposition 157of a 6 x 6 matrix and the right hand side b. The vector b is unchanged*/ 158void db_CholeskyBacksub6x6(double x[6],const double A[36],const double d[6],const double b[6]) 159{ 160 /*[42 mult 30 add=72flops]*/ 161 x[0]=db_SafeDivision(b[0],d[0]); 162 x[1]=db_SafeDivision((b[1]-A[6]*x[0]),d[1]); 163 x[2]=db_SafeDivision((b[2]-A[12]*x[0]-A[13]*x[1]),d[2]); 164 x[3]=db_SafeDivision((b[3]-A[18]*x[0]-A[19]*x[1]-A[20]*x[2]),d[3]); 165 x[4]=db_SafeDivision((b[4]-A[24]*x[0]-A[25]*x[1]-A[26]*x[2]-A[27]*x[3]),d[4]); 166 x[5]=db_SafeDivision((b[5]-A[30]*x[0]-A[31]*x[1]-A[32]*x[2]-A[33]*x[3]-A[34]*x[4]),d[5]); 167 x[5]=db_SafeDivision(x[5],d[5]); 168 x[4]=db_SafeDivision((x[4]-A[34]*x[5]),d[4]); 169 x[3]=db_SafeDivision((x[3]-A[33]*x[5]-A[27]*x[4]),d[3]); 170 x[2]=db_SafeDivision((x[2]-A[32]*x[5]-A[26]*x[4]-A[20]*x[3]),d[2]); 171 x[1]=db_SafeDivision((x[1]-A[31]*x[5]-A[25]*x[4]-A[19]*x[3]-A[13]*x[2]),d[1]); 172 x[0]=db_SafeDivision((x[0]-A[30]*x[5]-A[24]*x[4]-A[18]*x[3]-A[12]*x[2]-A[6]*x[1]),d[0]); 173} 174 175 176void db_Orthogonalize6x7(double A[42],int orthonormalize) 177{ 178 int i; 179 double ss[6]; 180 181 /*Compute square sums of rows*/ 182 ss[0]=db_SquareSum7(A); 183 ss[1]=db_SquareSum7(A+7); 184 ss[2]=db_SquareSum7(A+14); 185 ss[3]=db_SquareSum7(A+21); 186 ss[4]=db_SquareSum7(A+28); 187 ss[5]=db_SquareSum7(A+35); 188 189 ss[1]-=db_OrthogonalizePair7(A+7 ,A,ss[0]); 190 ss[2]-=db_OrthogonalizePair7(A+14,A,ss[0]); 191 ss[3]-=db_OrthogonalizePair7(A+21,A,ss[0]); 192 ss[4]-=db_OrthogonalizePair7(A+28,A,ss[0]); 193 ss[5]-=db_OrthogonalizePair7(A+35,A,ss[0]); 194 195 /*Pivot on largest ss (could also be done on ss/(original_ss))*/ 196 i=db_MaxIndex5(ss+1); 197 db_OrthogonalizationSwap7(A+7,i,ss+1); 198 199 ss[2]-=db_OrthogonalizePair7(A+14,A+7,ss[1]); 200 ss[3]-=db_OrthogonalizePair7(A+21,A+7,ss[1]); 201 ss[4]-=db_OrthogonalizePair7(A+28,A+7,ss[1]); 202 ss[5]-=db_OrthogonalizePair7(A+35,A+7,ss[1]); 203 204 i=db_MaxIndex4(ss+2); 205 db_OrthogonalizationSwap7(A+14,i,ss+2); 206 207 ss[3]-=db_OrthogonalizePair7(A+21,A+14,ss[2]); 208 ss[4]-=db_OrthogonalizePair7(A+28,A+14,ss[2]); 209 ss[5]-=db_OrthogonalizePair7(A+35,A+14,ss[2]); 210 211 i=db_MaxIndex3(ss+3); 212 db_OrthogonalizationSwap7(A+21,i,ss+3); 213 214 ss[4]-=db_OrthogonalizePair7(A+28,A+21,ss[3]); 215 ss[5]-=db_OrthogonalizePair7(A+35,A+21,ss[3]); 216 217 i=db_MaxIndex2(ss+4); 218 db_OrthogonalizationSwap7(A+28,i,ss+4); 219 220 ss[5]-=db_OrthogonalizePair7(A+35,A+28,ss[4]); 221 222 if(orthonormalize) 223 { 224 db_MultiplyScalar7(A ,db_SafeSqrtReciprocal(ss[0])); 225 db_MultiplyScalar7(A+7 ,db_SafeSqrtReciprocal(ss[1])); 226 db_MultiplyScalar7(A+14,db_SafeSqrtReciprocal(ss[2])); 227 db_MultiplyScalar7(A+21,db_SafeSqrtReciprocal(ss[3])); 228 db_MultiplyScalar7(A+28,db_SafeSqrtReciprocal(ss[4])); 229 db_MultiplyScalar7(A+35,db_SafeSqrtReciprocal(ss[5])); 230 } 231} 232 233void db_Orthogonalize8x9(double A[72],int orthonormalize) 234{ 235 int i; 236 double ss[8]; 237 238 /*Compute square sums of rows*/ 239 ss[0]=db_SquareSum9(A); 240 ss[1]=db_SquareSum9(A+9); 241 ss[2]=db_SquareSum9(A+18); 242 ss[3]=db_SquareSum9(A+27); 243 ss[4]=db_SquareSum9(A+36); 244 ss[5]=db_SquareSum9(A+45); 245 ss[6]=db_SquareSum9(A+54); 246 ss[7]=db_SquareSum9(A+63); 247 248 ss[1]-=db_OrthogonalizePair9(A+9 ,A,ss[0]); 249 ss[2]-=db_OrthogonalizePair9(A+18,A,ss[0]); 250 ss[3]-=db_OrthogonalizePair9(A+27,A,ss[0]); 251 ss[4]-=db_OrthogonalizePair9(A+36,A,ss[0]); 252 ss[5]-=db_OrthogonalizePair9(A+45,A,ss[0]); 253 ss[6]-=db_OrthogonalizePair9(A+54,A,ss[0]); 254 ss[7]-=db_OrthogonalizePair9(A+63,A,ss[0]); 255 256 /*Pivot on largest ss (could also be done on ss/(original_ss))*/ 257 i=db_MaxIndex7(ss+1); 258 db_OrthogonalizationSwap9(A+9,i,ss+1); 259 260 ss[2]-=db_OrthogonalizePair9(A+18,A+9,ss[1]); 261 ss[3]-=db_OrthogonalizePair9(A+27,A+9,ss[1]); 262 ss[4]-=db_OrthogonalizePair9(A+36,A+9,ss[1]); 263 ss[5]-=db_OrthogonalizePair9(A+45,A+9,ss[1]); 264 ss[6]-=db_OrthogonalizePair9(A+54,A+9,ss[1]); 265 ss[7]-=db_OrthogonalizePair9(A+63,A+9,ss[1]); 266 267 i=db_MaxIndex6(ss+2); 268 db_OrthogonalizationSwap9(A+18,i,ss+2); 269 270 ss[3]-=db_OrthogonalizePair9(A+27,A+18,ss[2]); 271 ss[4]-=db_OrthogonalizePair9(A+36,A+18,ss[2]); 272 ss[5]-=db_OrthogonalizePair9(A+45,A+18,ss[2]); 273 ss[6]-=db_OrthogonalizePair9(A+54,A+18,ss[2]); 274 ss[7]-=db_OrthogonalizePair9(A+63,A+18,ss[2]); 275 276 i=db_MaxIndex5(ss+3); 277 db_OrthogonalizationSwap9(A+27,i,ss+3); 278 279 ss[4]-=db_OrthogonalizePair9(A+36,A+27,ss[3]); 280 ss[5]-=db_OrthogonalizePair9(A+45,A+27,ss[3]); 281 ss[6]-=db_OrthogonalizePair9(A+54,A+27,ss[3]); 282 ss[7]-=db_OrthogonalizePair9(A+63,A+27,ss[3]); 283 284 i=db_MaxIndex4(ss+4); 285 db_OrthogonalizationSwap9(A+36,i,ss+4); 286 287 ss[5]-=db_OrthogonalizePair9(A+45,A+36,ss[4]); 288 ss[6]-=db_OrthogonalizePair9(A+54,A+36,ss[4]); 289 ss[7]-=db_OrthogonalizePair9(A+63,A+36,ss[4]); 290 291 i=db_MaxIndex3(ss+5); 292 db_OrthogonalizationSwap9(A+45,i,ss+5); 293 294 ss[6]-=db_OrthogonalizePair9(A+54,A+45,ss[5]); 295 ss[7]-=db_OrthogonalizePair9(A+63,A+45,ss[5]); 296 297 i=db_MaxIndex2(ss+6); 298 db_OrthogonalizationSwap9(A+54,i,ss+6); 299 300 ss[7]-=db_OrthogonalizePair9(A+63,A+54,ss[6]); 301 302 if(orthonormalize) 303 { 304 db_MultiplyScalar9(A ,db_SafeSqrtReciprocal(ss[0])); 305 db_MultiplyScalar9(A+9 ,db_SafeSqrtReciprocal(ss[1])); 306 db_MultiplyScalar9(A+18,db_SafeSqrtReciprocal(ss[2])); 307 db_MultiplyScalar9(A+27,db_SafeSqrtReciprocal(ss[3])); 308 db_MultiplyScalar9(A+36,db_SafeSqrtReciprocal(ss[4])); 309 db_MultiplyScalar9(A+45,db_SafeSqrtReciprocal(ss[5])); 310 db_MultiplyScalar9(A+54,db_SafeSqrtReciprocal(ss[6])); 311 db_MultiplyScalar9(A+63,db_SafeSqrtReciprocal(ss[7])); 312 } 313} 314 315void db_NullVectorOrthonormal6x7(double x[7],const double A[42]) 316{ 317 int i; 318 double omss[7]; 319 const double *B; 320 321 /*Pivot by choosing row of the identity matrix 322 (the one corresponding to column of A with smallest square sum)*/ 323 omss[0]=db_SquareSum6Stride7(A); 324 omss[1]=db_SquareSum6Stride7(A+1); 325 omss[2]=db_SquareSum6Stride7(A+2); 326 omss[3]=db_SquareSum6Stride7(A+3); 327 omss[4]=db_SquareSum6Stride7(A+4); 328 omss[5]=db_SquareSum6Stride7(A+5); 329 omss[6]=db_SquareSum6Stride7(A+6); 330 i=db_MinIndex7(omss); 331 /*orthogonalize that row against all previous rows 332 and normalize it*/ 333 B=A+i; 334 db_MultiplyScalarCopy7(x,A,-B[0]); 335 db_RowOperation7(x,A+7 ,B[7]); 336 db_RowOperation7(x,A+14,B[14]); 337 db_RowOperation7(x,A+21,B[21]); 338 db_RowOperation7(x,A+28,B[28]); 339 db_RowOperation7(x,A+35,B[35]); 340 x[i]+=1.0; 341 db_MultiplyScalar7(x,db_SafeSqrtReciprocal(1.0-omss[i])); 342} 343 344void db_NullVectorOrthonormal8x9(double x[9],const double A[72]) 345{ 346 int i; 347 double omss[9]; 348 const double *B; 349 350 /*Pivot by choosing row of the identity matrix 351 (the one corresponding to column of A with smallest square sum)*/ 352 omss[0]=db_SquareSum8Stride9(A); 353 omss[1]=db_SquareSum8Stride9(A+1); 354 omss[2]=db_SquareSum8Stride9(A+2); 355 omss[3]=db_SquareSum8Stride9(A+3); 356 omss[4]=db_SquareSum8Stride9(A+4); 357 omss[5]=db_SquareSum8Stride9(A+5); 358 omss[6]=db_SquareSum8Stride9(A+6); 359 omss[7]=db_SquareSum8Stride9(A+7); 360 omss[8]=db_SquareSum8Stride9(A+8); 361 i=db_MinIndex9(omss); 362 /*orthogonalize that row against all previous rows 363 and normalize it*/ 364 B=A+i; 365 db_MultiplyScalarCopy9(x,A,-B[0]); 366 db_RowOperation9(x,A+9 ,B[9]); 367 db_RowOperation9(x,A+18,B[18]); 368 db_RowOperation9(x,A+27,B[27]); 369 db_RowOperation9(x,A+36,B[36]); 370 db_RowOperation9(x,A+45,B[45]); 371 db_RowOperation9(x,A+54,B[54]); 372 db_RowOperation9(x,A+63,B[63]); 373 x[i]+=1.0; 374 db_MultiplyScalar9(x,db_SafeSqrtReciprocal(1.0-omss[i])); 375} 376 377