cs-ind04@penelope.Oswego.EDU (Jason E. Forbes) (08/03/90)
Before I reinvent the wheel, does anyone have a C function that can find the inverse of a 4 by 4 matrix? Thanks, Jason Forbes cs-ind04@penelope.oswego.edu cs-ind04@oswego.oswego.edu Veterans Administration Hospital, Research Department Syracuse, NY -----------------------------------------------------
dodson@convex.COM (Dave Dodson) (08/03/90)
In article <1990Aug3.021200.21023@oswego.Oswego.EDU> cs-ind04@penelope.Oswego.EDU (Jason E. Forbes) writes: >Before I reinvent the wheel, does anyone have a C function that can >find the inverse of a 4 by 4 matrix? First, I would ask why you want to invert a matrix. While papers and books extensively use the notation A-inverse * b to denote the solution of the system of linear equations Ax = b, it is better to solve the system directly than to compute the inverse and multiply it times the right hand side. By _better_, I mean faster and more accurate. So if you are wanting to solve linear equations, do it directly. ---------------------------------------------------------------------- Dave Dodson dodson@convex.COM Convex Computer Corporation Richardson, Texas (214) 497-4234
ted@nmsu.edu (Ted Dunning) (08/04/90)
From: cs-ind04@penelope.Oswego.EDU (Jason E. Forbes) Newsgroups: comp.sources.wanted,sci.math Before I reinvent the wheel, does anyone have a C function that can find the inverse of a 4 by 4 matrix? ... the real answer to your question is to buy yourself a copy of numerical recipes in c. just for fun, though, i revved maple up and had it spit out the inversion in fortran and then used emacs to change it into c. the total time including cursory debugging was about 30 minutes, and the resulting code obviously would provide a major opportunity for a fancy optimizer, but would probably be a disaster on a vectorizer. but, of course, 4x4 inversion isn't what you would be doing on a vector machine anyway. no guarantees for numerical stability, but anything at all should work pretty well for such small matrices. it would be an interesting question to to an operation count on the resulting compiled code and comparing the result to what a looping version would do. it would also be interesting to compare the number of operations that a common subexpression optimizer could save. so anyway, have fun with this. /* invert a 4x4 matrix stored in a and store the result in b. both a and b must be preallocated. this code was generated automatically in fortran and then translated to c, so it should be thoroughly tested before use */ invert_4_4(a,b) double **a, **b; { double t1, t2, t4, t5, t6, t7, t8, t9, t11, t12, t14, t15, t17; double t19, t22, t23, t26, t27, t29, t30, t32, t33, t48, t50, t53, t56; double t58, t59, t61, t62, t66, t69, t71, t73, t76, t79, t84, t116, t118; double t121, t124, t126, t128, t133, t135, t138, t141, t143, t145, t151; double t153, t159, t161, t166, t168, t174, t176, t187, t189, t212, t214; t1 = a[2][2]*a[3][3]; t2 = a[0][1]*t1; t4 = a[2][3]*a[3][2]; t5 = a[0][1]*t4; t6 = a[0][2]*a[3][3]; t7 = a[2][1]*t6; t8 = a[0][3]*a[3][2]; t9 = a[2][1]*t8; t11 = a[0][2]*a[2][3]; t12 = a[3][1]*t11; t14 = a[0][3]*a[2][2]; t15 = a[3][1]*t14; t17 = a[1][1]*t1; t19 = a[1][1]*t4; t22 = a[1][2]*a[3][3]; t23 = a[2][1]*t22; t26 = a[1][3]*a[3][2]; t27 = a[2][1]*t26; t29 = a[1][2]*a[2][3]; t30 = a[3][1]*t29; t32 = a[1][3]*a[2][2]; t33 = a[3][1]*t32; t48 = a[0][1]*t22; t50 = a[0][1]*t26; t53 = a[1][1]*t6; t56 = a[1][1]*t8; t58 = a[0][2]*a[1][3]; t59 = a[3][1]*t58; t61 = a[0][3]*a[1][2]; t62 = a[3][1]*t61; t66 = a[0][1]*t29; t69 = a[0][1]*t32; t71 = a[1][1]*t11; t73 = a[1][1]*t14; t76 = a[2][1]*t58; t79 = a[2][1]*t61; t84 = 1/(a[0][0]*t17-a[0][0]*t19-a[0][0]*t23+a[0][0]*t27+a[0][0]*t30-a[0][0]*t33-a[1][0]*t2+a[1][0]*t5+a[1][0]*t7-a[1][0]*t9-a[1][0]*t12+a[1][0]*t15+a[2][0]*t48-a[2][0]*t50-a[2][0]*t53+a[2][0]*t56+a[2][0]*t59-a[2][0]*t62-a[3][0]*t66+a[3][0]*t69+a[3][0]*t71-a[3][0]*t73-a[3][0]*t76+a[3][0]*t79); t116 = a[2][1]*a[3][2]; t118 = a[2][2]*a[3][1]; t121 = a[0][1]*a[3][2]; t124 = a[0][2]*a[3][1]; t126 = a[0][1]*a[2][2]; t128 = a[0][2]*a[2][1]; t133 = a[2][1]*a[3][3]; t135 = a[2][3]*a[3][1]; t138 = a[0][1]*a[3][3]; t141 = a[0][3]*a[3][1]; t143 = a[0][1]*a[2][3]; t145 = a[0][3]*a[2][1]; t151 = a[1][1]*a[2][2]; t153 = a[1][2]*a[2][1]; t159 = a[0][1]*a[1][2]; t161 = a[0][2]*a[1][1]; t166 = a[1][1]*a[3][3]; t168 = a[1][3]*a[3][1]; t174 = a[0][1]*a[1][3]; t176 = a[0][3]*a[1][1]; t187 = a[1][1]*a[2][3]; t189 = a[1][3]*a[2][1]; t212 = a[1][1]*a[3][2]; t214 = a[1][2]*a[3][1]; b[0][1] = (-t2+t5+t7-t9-t12+t15)*t84; b[0][2] = -(-t48+t50+t53-t56-t59+t62)*t84; b[1][2] = -(a[0][0]*t22-a[0][0]*t26-a[1][0]*t6+a[1][0]*t8+a[3][0]*t58-a[3][0]*t61)*t84; b[1][3] = -(-a[0][0]*t29+a[0][0]*t32+a[1][0]*t11-a[1][0]*t14-a[2][0]*t58+a[2][0]*t61)*t84; b[3][1] = (a[0][0]*t116-a[0][0]*t118-a[2][0]*t121+a[2][0]*t124+a[3][0]*t126-a[3][0]*t128)*t84; b[2][1] = -(a[0][0]*t133-a[0][0]*t135-a[2][0]*t138+a[2][0]*t141+a[3][0]*t143-a[3][0]*t145)*t84; b[3][3] = (a[0][0]*t151-a[0][0]*t153-a[1][0]*t126+a[1][0]*t128+a[2][0]*t159-a[2][0]*t161)*t84; b[2][2] = (a[0][0]*t166-a[0][0]*t168-a[1][0]*t138+a[1][0]*t141+a[3][0]*t174-a[3][0]*t176)*t84; b[2][0] = (a[1][0]*t133-a[1][0]*t135-a[2][0]*t166+a[2][0]*t168+a[3][0]*t187-a[3][0]*t189)*t84; b[1][0] = -(a[1][0]*t1-a[1][0]*t4-a[2][0]*t22+a[2][0]*t26+a[3][0]*t29-a[3][0]*t32)*t84; b[0][3] = -(t66-t69-t71+t73+t76-t79)*t84; b[3][2] = -(a[0][0]*t212-a[0][0]*t214-a[1][0]*t121+a[1][0]*t124+a[3][0]*t159-a[3][0]*t161)*t84; b[0][0] = (t17-t19-t23+t27+t30-t33)*t84; b[2][3] = -(a[0][0]*t187-a[0][0]*t189-a[1][0]*t143+a[1][0]*t145+a[2][0]*t174-a[2][0]*t176)*t84; b[3][0] = -(a[1][0]*t116-a[1][0]*t118-a[2][0]*t212+a[2][0]*t214+a[3][0]*t151-a[3][0]*t153)*t84; b[1][1] = (a[0][0]*t1-a[0][0]*t4-a[2][0]*t6+a[2][0]*t8+a[3][0]*t11-a[3][0]*t14)*t84; } /* multiply a times b to get c. c must be preallocated. code generated in fortran by maple and then converted semi-automatically to c. it may well be buggy. */ mul_4_4(a,b,c) double **a, **b, **c; { c[0][1] = a[0][0]*b[0][1]+a[0][1]*b[1][1]+a[0][2]*b[2][1]+a[0][3]*b[3][1]; c[0][2] = a[0][0]*b[0][2]+a[0][1]*b[1][2]+a[0][2]*b[2][2]+a[0][3]*b[3][2]; c[1][2] = a[1][0]*b[0][2]+a[1][1]*b[1][2]+a[1][2]*b[2][2]+a[1][3]*b[3][2]; c[1][3] = a[1][0]*b[0][3]+a[1][1]*b[1][3]+a[1][2]*b[2][3]+a[1][3]*b[3][3]; c[3][1] = a[3][0]*b[0][1]+a[3][1]*b[1][1]+a[3][2]*b[2][1]+a[3][3]*b[3][1]; c[2][1] = a[2][0]*b[0][1]+a[2][1]*b[1][1]+a[2][2]*b[2][1]+a[2][3]*b[3][1]; c[3][3] = a[3][0]*b[0][3]+a[3][1]*b[1][3]+a[3][2]*b[2][3]+a[3][3]*b[3][3]; c[2][2] = a[2][0]*b[0][2]+a[2][1]*b[1][2]+a[2][2]*b[2][2]+a[2][3]*b[3][2]; c[2][0] = a[2][0]*b[0][0]+a[2][1]*b[1][0]+a[2][2]*b[2][0]+a[2][3]*b[3][0]; c[1][0] = a[1][0]*b[0][0]+a[1][1]*b[1][0]+a[1][2]*b[2][0]+a[1][3]*b[3][0]; c[0][3] = a[0][0]*b[0][3]+a[0][1]*b[1][3]+a[0][2]*b[2][3]+a[0][3]*b[3][3]; c[3][2] = a[3][0]*b[0][2]+a[3][1]*b[1][2]+a[3][2]*b[2][2]+a[3][3]*b[3][2]; c[0][0] = a[0][0]*b[0][0]+a[0][1]*b[1][0]+a[0][2]*b[2][0]+a[0][3]*b[3][0]; c[2][3] = a[2][0]*b[0][3]+a[2][1]*b[1][3]+a[2][2]*b[2][3]+a[2][3]*b[3][3]; c[3][0] = a[3][0]*b[0][0]+a[3][1]*b[1][0]+a[3][2]*b[2][0]+a[3][3]*b[3][0]; c[1][1] = a[1][0]*b[0][1]+a[1][1]*b[1][1]+a[1][2]*b[2][1]+a[1][3]*b[3][1]; } /* simple cursory test of the inversion and multiplication routines */ main() { double **a,**b,**c; void *calloc(); int i,j; a = calloc(4,sizeof(a[0])); b = calloc(4,sizeof(b[0])); c = calloc(4,sizeof(c[0])); for (i=0;i<4;i++) { a[i] = calloc(4,sizeof(a[0][0])); b[i] = calloc(4,sizeof(b[0][0])); c[i] = calloc(4,sizeof(c[0][0])); for (j=0;j<4;j++) { a[i][j] = random()%1000; } } invert_4_4(a,b); mul_4_4(a,b,c); for (i=0;i<4;i++) { for (j=0;j<4;j++) { printf("%19.17lf ", c[i][j]); } printf("\n"); } } -- Offer void except where prohibited by law.