linop.red 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. module linop; % Linear operator package.
  2. % Author: Anthony C. Hearn.
  3. % Copyright (c) 1987 The RAND Corporation. All rights reserved.
  4. fluid '(!*intstr);
  5. symbolic procedure linear u;
  6. for each x in u do
  7. if not idp x then typerr(x,'operator) else flag(list x,'linear);
  8. rlistat '(linear);
  9. symbolic procedure formlnr u;
  10. begin scalar x,y,z;
  11. x := car u;
  12. if null cdr u or null cddr u
  13. then rerror(alg,29,list("Linear operator",
  14. x,"called with too few arguments"));
  15. y := cadr u;
  16. z := !*a2k caddr u . cdddr u;
  17. return if y = 1 then u
  18. else if not depends(y,car z)
  19. then list('times,y,x . 1 . z)
  20. else if atom y then u
  21. else if car y eq 'plus
  22. then 'plus . for each j in cdr y collect formlnr(x . j. z)
  23. else if car y eq 'minus
  24. then list('minus,formlnr(x . cadr y . z))
  25. else if car y eq 'difference
  26. then list('difference,formlnr(x . cadr y . z),
  27. formlnr(x . caddr y . z))
  28. else if car y eq 'times then formlntms(x,cdr y,z,u)
  29. else if car y eq 'quotient then formlnquot(x,cdr y,z,u)
  30. else if car y eq 'recip
  31. then formlnrecip(x,carx(cdr y,'recip),z,u)
  32. else if y := expt!-separate(y,car z)
  33. then list('times,car y,x . cdr y . z)
  34. else u
  35. end;
  36. symbolic procedure formseparate(u,v);
  37. %separates U into two parts, and returns a dotted pair of them: those
  38. %which are not commutative and do not depend on V, and the remainder;
  39. begin scalar w,x,y;
  40. for each z in u do
  41. if not noncomp z and not depends(z,v) then x := z . x
  42. else if (w := expt!-separate(z,v))
  43. then <<x := car w . x; y := cdr w . y>>
  44. else y := z . y;
  45. return reversip!* x . reversip!* y
  46. end;
  47. symbolic procedure expt!-separate(u,v);
  48. %determines if U is an expression in EXPT that can be separated into
  49. %two parts, one that does not depend on V and one that does,
  50. %except if there is no non-dependent part, NIL is returned;
  51. if not eqcar(u,'expt) or depends(cadr u,v)
  52. or not eqcar(caddr u,'plus)
  53. then nil
  54. else expt!-separate1(cdaddr u,cadr u,v);
  55. symbolic procedure expt!-separate1(u,v,w);
  56. begin scalar x;
  57. x := formseparate(u,w);
  58. return if null car x then nil
  59. else list('expt,v,replus car x) .
  60. if null cdr x then 1 else list('expt,v,replus cdr x)
  61. end;
  62. symbolic procedure formlntms(u,v,w,x);
  63. %U is a linear operator, V its first argument with TIMES removed,
  64. %W the rest of the arguments and X the whole expression.
  65. %Value is the transformed expression;
  66. begin scalar y;
  67. y := formseparate(v,car w);
  68. return if null car y then x
  69. else 'times . aconc!*(car y,
  70. if null cddr y then formlnr(u . cadr y . w)
  71. else u . ('times . cdr y) . w)
  72. end;
  73. symbolic procedure formlnquot(fn,quotargs,rest,whole);
  74. %FN is a linear operator, QUOTARGS its first argument with QUOTIENT
  75. %removed, REST the remaining arguments, WHOLE the whole expression.
  76. %Value is the transformed expression;
  77. begin scalar x;
  78. return if not depends(cadr quotargs,car rest)
  79. then list('quotient,formlnr(fn . car quotargs . rest),
  80. cadr quotargs)
  81. else if not depends(car quotargs,car rest)
  82. and car quotargs neq 1
  83. then list('times,car quotargs,
  84. formlnr(fn . list('recip,cadr quotargs) . rest))
  85. else if eqcar(car quotargs,'plus)
  86. then 'plus . for each j in cdar quotargs
  87. collect formlnr(fn . ('quotient . j . cdr quotargs)
  88. . rest)
  89. else if eqcar(car quotargs,'minus)
  90. then list('minus,formlnr(fn .
  91. ('quotient . cadar quotargs . cdr quotargs)
  92. . rest))
  93. else if eqcar(car quotargs,'times)
  94. and car(x := formseparate(cdar quotargs,car rest))
  95. then 'times . aconc!*(car x,
  96. formlnr(fn . list('quotient,mktimes cdr x,
  97. cadr quotargs) . rest))
  98. else if eqcar(cadr quotargs,'times)
  99. and car(x := formseparate(cdadr quotargs,car rest))
  100. then list('times,list('recip,mktimes car x),
  101. formlnr(fn . list('quotient,car quotargs,mktimes cdr x)
  102. . rest))
  103. else if x := expt!-separate(car quotargs,car rest)
  104. then list('times,car x,formlnr(fn . list('quotient,cdr x,cadr
  105. quotargs) . rest))
  106. else if x := expt!-separate(cadr quotargs,car rest)
  107. then list('times,list('recip,car x),
  108. formlnr(fn . list('quotient,car quotargs,cdr x)
  109. . rest))
  110. else if (x := reval!* cadr quotargs) neq cadr quotargs
  111. then formlnquot(fn,list(car quotargs,x),rest,whole)
  112. else whole
  113. end;
  114. symbolic procedure formlnrecip(fn,reciparg,rest,whole);
  115. % FN is a linear operator, RECIPARG the RECIP argument, REST the
  116. % remaining arguments, WHOLE the whole expression. Value is the
  117. % transformed expression.
  118. begin scalar x;
  119. return if not depends(reciparg,car rest)
  120. then list('quotient,fn . 1 . rest,reciparg)
  121. else if eqcar(reciparg,'minus)
  122. then list('minus,formlnr(fn . ('recip . cdr reciparg) . rest))
  123. else if eqcar(reciparg,'times)
  124. and car(x := formseparate(cdr reciparg,car rest))
  125. then list('times,list('recip,mktimes car x),
  126. formlnr(fn . list('recip,mktimes cdr x)
  127. . rest))
  128. else if x := expt!-separate(reciparg,car rest)
  129. then list('times,list('recip,car x),
  130. formlnr(fn . list('recip,cdr x)
  131. . rest))
  132. else if (x := reval!* reciparg) neq reciparg
  133. then formlnrecip(fn,x,rest,whole)
  134. else whole
  135. end;
  136. symbolic procedure mktimes u;
  137. if null cdr u then car u else 'times . u;
  138. symbolic procedure reval!* u;
  139. %like REVAL, except INTSTR is always ON;
  140. begin scalar !*intstr;
  141. !*intstr := t;
  142. return reval u
  143. end;
  144. endmodule;
  145. end;