{VERSION 1 0 "X11/Motif" "1.0"}{GLOBALS 3 1}{FONT 0 "-adobe-helve
tica-bold-r-normal--14-*" "helvetica" "Helvetica-Bold" 8 14 0 "He
lvetica-Bold" 12}{FONT 1 "-adobe-times-medium-r-normal--14-*" "ti
mes" "Times-Roman" 4 14 64 "Times-Roman" 12}{FONT 2 "-adobe-couri
er-medium-r-normal--14-*" "courier" "Courier" 4 14 192 "Courier" 
12}{FONT 3 "-adobe-new century schoolbook-bold-r-normal--17-*" "n
ew century schoolbook" "Times-Bold" 8 17 64 "Times-Bold" 17}
{SCP_R 1 0 58{COM_R 2 0{TEXT 3 23 "Fortran code generation"}}
{COM_R 3 0{TEXT 1 94 "\015Michael Monagan\015This example shows s
ome of the pitfalls of naive use of symbolic computation."}}
{COM_R 4 0{TEXT 1 488 "\015Problem: Given the following 3 by 3 sy
mmetric matrix M (perhaps created in a symbolic computation syste
m like Maple), and we want to evaluate numerically the inverse of
  M at particular values of the parameters q2, q3, p, m10, m30, j
10y, j30x, j30y, j30z  in a Fortran program.  It is tempting to c
ompute the inverse of the matrix M symbolically then use Maple's 
fortran function to generate the Fortran code.  Does this produce
 the most efficient code?  Let's see.  Here is the matrix M"}}
{INP_R 5 0 "> "{TEXT 0 32 "M := array(1..3,1..3,symmetric):"}}
{INP_R 6 0 "> "{TEXT 0 12 "M[2,3] := 0:"}}{INP_R 7 0 "> "{TEXT 0 
51 "M[1,1] := 18*cos(q3)*cos(q2)*m30*p^2-sin(q3)^2*j30y"}}{INP_R 
8 0 "> "{TEXT 0 39 "   + sin(q3)^2*j30z-9*sin(q3)^2*m30*p^2"}}
{INP_R 9 0 "> "{TEXT 0 34 "   + j10y+j30y+m10*p^2+18*m30*p^2:"}}
{INP_R 10 0 "> "{TEXT 0 50 "M[1,2] := 9*cos(q3)*cos(q2)*m30*p^2-s
in(q3)^2*j30y"}}{INP_R 11 0 "> "{TEXT 0 44 "        + sin(q3)^2*j
30z-9*sin(q3)^2*m30*p^2"}}{INP_R 12 0 "> "{TEXT 0 25 "        + j
30y+9*m30*p^2:"}}{INP_R 13 0 "> "{TEXT 0 37 "M[1,3] := -9*sin(q3)
*sin(q2)*m30*p^2:"}}{INP_R 14 0 "> "{TEXT 0 40 "M[2,2] := -sin(q3
)^2*j30y+sin(q3)^2*j30z"}}{INP_R 15 0 "> "{TEXT 0 47 "          -
 9*sin(q3)^2*m30*p^2+j30y+9*m30*p^2:"}}{INP_R 16 0 "> "{TEXT 0 25
 "M[3,3] := 9*m30*p^2+j30x:"}}{COM_R 17 0{TEXT 1 428 "\015So the 
first strategy is to compute the symbolic inverse of the M matrix
 then generate (optimized) Fortran code.  Maple can compute the i
nverse symbolically, but the symbolic inverse contains quit  larg
e expressions.  We can try to simplify these expressions using co
mmands like simplify and factor but typically such expressions do
n't simplify.  This approach becomes increasingly bad for larger 
matrices.  Here is what we get"}}{INP_R 18 0 "> "{TEXT 0 24 "B :=
 linalg[inverse](M):"}}{INP_R 19 0 "> "{TEXT 0 24 "fortran( B, op
timized );"}}{OUT_R 20 0 19{TEXT 2 2093 "      t1 = sin(q3)\012  
    t2 = t1**2\012      t3 = t2*j30y\012      t4 = t2*j30z\012   
   t5 = t2*m30\012      t6 = p**2\012      t7 = t5*t6\012      t8
 = m30*t6\012      t9 = t3-t4+9*t7-j30y-9*t8\012      t10 = 9*t8+
j30x\012      t12 = m30**2\012      t13 = t6**2\012      t14 = t1
2*t13\012      t15 = t14*j30x\012      t17 = j30y*t12*t13\012    
  t18 = t12*m30\012      t19 = t13*t6\012      t20 = t18*t19\012 
     t21 = m10*t19\012      t25 = j10y*j30y\012      t30 = m10*t1
3\012      t31 = j30y*m30\012      t35 = j10y*m30\012      t36 = 
t6*j30x\012      t39 = m10*t6\012      t40 = j30y*j30x\012      t
46 = t2*t12\012      t48 = j10y*t2\012      t49 = t31*t6\012     
 t54 = -81*t15-81*t17-729*t20-81*t21*t12-81*j10y*t12*t13-t25*j30x
+7\012     #29*t2*t18*t19-9*t25*t8-9*t30*t31-9*t30*m30*j30x-9*t35
*t36-9*t31*t3\012     #6-t39*t40+9*t30*t3*m30-9*t30*t4*m30+81*t21
*t46+9*t48*t49-9*t48*j30\012     #z*m30*t6\012      t60 = t8*j30x
\012      t63 = t3*j30x\012      t65 = t4*j30x\012      t73 = cos
(q3)\012      t74 = t73**2\012      t75 = cos(q2)\012      t76 = 
t75**2\012      t77 = t74*t76\012      t80 = t2**2\012      t81 =
 sin(q2)\012      t82 = t81**2\012      t83 = t80*t82\012      t8
8 = t2*t82\012      t91 = 81*t3*t14-81*t4*t14+81*t48*t14+81*t46*t
13*j30x+9*t3*t60-9*t4\012     #*t60+t39*t63-t39*t65+9*t30*t5*j30x
+t48*t40-t48*j30z*j30x+9*t48*t60\012     #+729*t77*t20+81*t77*t15
-81*t83*t17+81*t83*t14*j30z-729*t83*t20+729\012     #*t88*t20+81*
t88*t17\012      t93 = 1/(t54+t91)\012      t95 = t73*t75\012    
  t97 = 9*t95*t8-t3+t4-9*t7+j30y+9*t8\012      t99 = t97*t10*t93\
012      t104 = t1*t81*m30*t6*t9*t93\012      t107 = t3*t8\012   
   t108 = t4*t8\012      t109 = t46*t13\012      t111 = t35*t6\01
2      t113 = t30*m30\012      t116 = 162*t95*t14+18*t95*t60-9*t1
07-t63+9*t108+t65-81*t109-9*t5*t\012     #36+9*t111+j10y*j30x+9*t
49+t40+9*t113+t39*j30x+162*t14+18*t60-81*t8\012     #8*t14\012   
   t121 = t97*t1*t81*t8*t93\012      t130 = -t25-81*t14+81*t109-9
*t113+9*t107-9*t108+t39*t3-t39*t4+9*t3\012     #0*t5+t48*j30y-t48
*j30z-9*t111-9*t49-t39*j30y+9*t48*t8+81*t77*t14\012      B(1,1) =
 t9*t10*t93\012      B(1,2) = t99\012      B(1,3) = 9*t104\012   
   B(2,1) = t99\012      B(2,2) = -t116*t93\012      B(2,3) = 9*t
121\012      B(3,1) = 9*t104\012      B(3,2) = 9*t121\012      B(
3,3) = t130*t93\012"}}{COM_R 21 0{TEXT 1 323 "Here is the cost of
 evaluating the inverse of the matrix by plugging in numbers for 
the variables.  Note we used the optimized option to the fortran 
command.  This means that all common subexpressions in the matrix
 B are computed once only and stored in the temporary variables t
1, t2, ... etc.A = [1 2 3; 3 1 6; 3 11 111]\012"}}{INP_R 22 0 "> 
"{TEXT 0 14 "readlib(cost):"}}{INP_R 23 0 "> "{TEXT 0 20 "cost( o
ptimize(B) );"}}{OUT_R 24 0 23{DAG +Dn5\`additions`j2x0078n6\`mul
tiplications`j2x0181n5\`divisions`j2x0001n5\`functions`j2x0004n5\
`subscripts`j2x0009n5\`assignments`j2x0066}}{COM_R 25 0{TEXT 1 
249 "A more clever approach is to compute the inverse of the M ma
trix before assigning the entries.  Except since M is symmetric a
nd M[2,3] = 0 we should specify this information to simplify the 
symbolic inverse.  This keeps the structure of the inverse."}}
{INP_R 26 0 "> "{TEXT 0 32 "M := array(1..3,1..3,symmetric);"}}
{OUT_R 27 0 26{DAG :3n3\`M`(3n4\`array`,5n5\`symmetric`~3j2x0001j
2x0003pC[2,1}}{INP_R 28 0 "> "{TEXT 0 12 "M[2,3] := 0:"}}{INP_R 
29 0 "> "{TEXT 0 24 "B := linalg[inverse](M);"}}{OUT_R 30 0 29
{DAG :3n3\`B`(3n4\`MATRIX`,2[2,4[2,4+3*7b3n3\`M`,3j2x0002p12j2x00
01b3pF,3j2x0003p1Ap15+7*7b3pF,3p15p15p15pEp15p17p15i2x0001*5b3pF,
3p15p12p12p17p15p15*5b3pF,3p1Ap15p12pEp15p15p2Ap2A*7p2Dp15p17p15p
1Ep2A*7p37p15pEp15p1Ep2A[2,4p42*5+5*5p20p15p17p15p2A*3p37p12p15p1
5p1Ep2A+3*7p2Dp15p37p15p1Ep2Ap2A[2,4p49p62*5+5*5p20p15pEp15p2A*3p
2Dp12p15p15p1Ep2A}}{COM_R 31 0{TEXT 1 102 "\015Now define the ent
ries for M[1,1], M[1,2] etc.  But DON'T try to simplify or expand
 any products out."}}{INP_R 32 0 "> "{TEXT 0 52 " M[1,1] := 18*co
s(q3)*cos(q2)*m30*p^2-sin(q3)^2*j30y"}}{INP_R 33 0 "> "{TEXT 0 39
 "   + sin(q3)^2*j30z-9*sin(q3)^2*m30*p^2"}}{INP_R 34 0 "> "{TEXT
 0 34 "   + j10y+j30y+m10*p^2+18*m30*p^2:"}}{INP_R 35 0 "> "{TEXT
 0 51 " M[1,2] := 9*cos(q3)*cos(q2)*m30*p^2-sin(q3)^2*j30y"}}
{INP_R 36 0 "> "{TEXT 0 44 "        + sin(q3)^2*j30z-9*sin(q3)^2*
m30*p^2"}}{INP_R 37 0 "> "{TEXT 0 25 "        + j30y+9*m30*p^2:"}
}{INP_R 38 0 "> "{TEXT 0 38 " M[1,3] := -9*sin(q3)*sin(q2)*m30*p^
2:"}}{INP_R 39 0 "> "{TEXT 0 41 " M[2,2] := -sin(q3)^2*j30y+sin(q
3)^2*j30z"}}{INP_R 40 0 "> "{TEXT 0 47 "          - 9*sin(q3)^2*m
30*p^2+j30y+9*m30*p^2:"}}{INP_R 41 0 "> "{TEXT 0 26 " M[3,3] := 9
*m30*p^2+j30x:"}}{COM_R 42 0{TEXT 1 195 "\015Now B is defined in 
terms of the M[i,j] and the M[i,j] have been assigned values.  We
 need to evaluate the entries of the B matrix so the M[i,j] are p
lugged in.  Then generate Fortran code for B"}}{INP_R 43 0 "> "
{TEXT 0 18 " B := map(eval,B):"}}{INP_R 44 0 "> "{TEXT 0 22 "fort
ran(B, optimized);"}}{OUT_R 45 0 44{TEXT 2 816 "      t1 = sin(q3
)\012      t2 = t1**2\012      t3 = t2*j30y\012      t4 = t2*j30z
\012      t6 = p**2\012      t7 = t2*m30*t6\012      t8 = m30*t6\
012      t9 = -t3+t4-9*t7+j30y+9*t8\012      t10 = 9*t8+j30x\012 
     t15 = cos(q3)*cos(q2)*t8\012      t17 = 18*t15-t3+t4-9*t7+j1
0y+j30y+m10*t6+18*t8\012      t18 = t17*t9\012      t20 = 9*t15-t
3+t4-9*t7+j30y+9*t8\012      t21 = t20**2\012      t23 = sin(q2)\
012      t24 = t23**2\012      t25 = t2*t24\012      t26 = m30**2
\012      t27 = t6**2\012      t28 = t26*t27\012      t32 = 1/(-t
18*t10+t21*t10+81*t25*t28*t9)\012      t35 = t20*t10*t32\012     
 t40 = t1*t23*m30*t6*t9*t32\012      t48 = t20*t1*t23*t8*t32\012 
     B(1,1) = -t9*t10*t32\012      B(1,2) = t35\012      B(1,3) =
 -9*t40\012      B(2,1) = t35\012      B(2,2) = (-t17*t10+81*t25*
t28)*t32\012      B(2,3) = 9*t48\012      B(3,1) = -9*t40\012    
  B(3,2) = 9*t48\012      B(3,3) = (-t18+t21)*t32\012"}}{INP_R 46
 0 "> "{TEXT 0 24 "c2 := cost(optimize(B));"}}{OUT_R 47 0 46{DAG 
:3n3\`c2`+Dn5\`additions`j2x0022n6\`multiplications`j2x0053n5\`di
visions`j2x0001n5\`functions`j2x0004n5\`subscripts`j2x0009n5\`ass
ignments`j2x0033}}{COM_R 48 0{TEXT 1 400 "This is much better tha
n the naive computation of the symbolic inverse.  But in general 
it is best to not even try to invert the matrix symbolically.  Th
at should be done numerically.  I.e. inverting a 3 by 3 numerical
 matrix is trivial.  So what one should do if one is only interes
ted in evaluating the inverse numerically, it so just generate Fo
rtran code for the contruction of the matrix M, i.e."}}{INP_R 49 
0 "> "{TEXT 0 21 "fortran(M,optimized);"}}{OUT_R 50 0 49{TEXT 2 
464 "      t4 = p**2\012      t5 = m30*t4\012      t6 = cos(q3)*c
os(q2)*t5\012      t7 = sin(q3)\012      t8 = t7**2\012      t9 =
 t8*j30y\012      t10 = t8*j30z\012      t12 = t8*m30*t4\012     
 t15 = 9*t6-t9+t10-9*t12+j30y+9*t5\012      t18 = t7*sin(q2)*t5\0
12      M(1,1) = 18*t6-t9+t10-9*t12+j10y+j30y+m10*t4+18*t5\012   
   M(1,2) = t15\012      M(1,3) = -9*t18\012      M(2,1) = t15\01
2      M(2,2) = -t9+t10-9*t12+j30y+9*t5\012      M(2,3) = 0\012  
    M(3,1) = -9*t18\012      M(3,2) = 0\012      M(3,3) = 9*t5+j3
0x\012"}}{INP_R 51 0 "> "{TEXT 0 26 "c3 := cost( optimize(M) );"}
}{OUT_R 52 0 51{DAG :3n3\`c3`+Bn5\`additions`j2x0017n6\`multiplic
ations`j2x0023n5\`functions`j2x0004n5\`subscripts`j2x0009n5\`assi
gnments`j2x0019}}{COM_R 53 0{TEXT 1 473 "The cost here is quite s
mall.  Now, in order to compare this with the previous two method
s, we need to know how many arithmetic operations it would take t
o compute the inverse of a 3 by 3 matrix numerically.  Not counti
ng any cost of numerical pivoting, and not taking into account th
e fact that the matrix M is symmetric, using Gaussian elimination
 on the so-called ``book keeping'' matrix it would take 3 divisio
ns, 24 subtractions, and 36 multiplications.  Hence we have"}}
{INP_R 54 0 "> "{TEXT 0 59 "c3 := c3 + 3*divisions + 24*additions
 + 36*multiplications;"}}{OUT_R 55 0 54{DAG :3n3\`c3`+Dn5\`additi
ons`j2x0041n6\`multiplications`j2x0059n5\`functions`j2x0004n5\`su
bscripts`j2x0009n5\`assignments`j2x0019n5\`divisions`j2x0003}}
{INP_R 56 0 "> "{TEXT 0 9 "c3 - c2;;"}}{OUT_R 57 0 56{DAG +9n5\`a
dditions`j2x0019n6\`multiplications`j2x0006n5\`assignments`i2x001
4n5\`divisions`j2x0002}}{COM_R 58 0{TEXT 1 362 "That is interesti
ng because it tells us that in this case, there is a small gain i
n this example.  The other gain of course is that we don't have t
o execute a general purpose matrix inversion routine.  We caution
 the reader that even for a 4 by 4 matrix, unless the matrix has 
a lot of structure, no gain will be made by computing the inverse
 symbolically first."}}{INP_R 59 0 "> "{TEXT 0 0 ""}}}{END}
