pf.red 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. module pf; % Compute partial fractions for an expression.
  2. % Author: Anthony C. Hearn.
  3. Comment PF is the top level operator for finding the partial fractions
  4. of an expression. It returns the partial fractions as a list.
  5. The algorithms used here are relatively unsophisticated, and use the
  6. extended Euclidean algorithm to break up expressions into factors.
  7. Much more sophisticated algorithms exist in the literature;
  8. fluid '(!*exp !*limitedfactors !*gcd kord!*);
  9. symbolic operator pf;
  10. flag('(pf),'noval); % Since PF will do its own simplification.
  11. symbolic procedure pf(u,var);
  12. % Convert an algebraic expression into partial fractions.
  13. begin scalar !*exp,!*gcd,kord!*,!*limitedfactors,polypart,rfactor,
  14. u1,u2,u3,u4,var,x,xx,y;
  15. !*exp := !*gcd := t;
  16. xx := updkorder var; % Make var the main variable.
  17. x := subs2 resimp simp!* u; % To allow for OFF EXP forms.
  18. u1 := denr x;
  19. if degr(u1,var) = 0 then <<setkorder xx; return list('list,u)>>;
  20. u2 := qremsq(!*f2q numr x,!*f2q u1,var); %Extract polynomial part.
  21. if caar u2 then polypart := car u2;
  22. rfactor := 1 ./ 1; % Factor for rational part.
  23. u2 := cdr u2;
  24. u3 := fctrf u1; % Factorize denominator.
  25. x := cdr u3;
  26. u3 := car u3;
  27. % Process monomial part.
  28. while not domainp u3 do
  29. <<if mvar u3 eq var then x := (!*k2f mvar u3 . ldeg u3) . x
  30. else <<u4 := !*p2f lpow u3;
  31. rfactor := numr rfactor ./ multf(u4,denr rfactor);
  32. u1 := quotf(u1,u4)>>;
  33. u3 := lc u3>>;
  34. if u3 neq 1 then <<rfactor := numr rfactor
  35. ./ multf(u3,denr rfactor);
  36. u1 := quotf(u1,u3)>>;
  37. % Separate power factors in denominator.
  38. while length x>1 do
  39. <<u3 := exptf(caar x,cdar x);
  40. u1 := quotf(u1,u3);
  41. if degr(u3,var)=0
  42. then rfactor := numr rfactor ./ multf(u3,denr rfactor)
  43. % then <<rfactor := numr rfactor ./ multf(u3,denr rfactor);
  44. % u2 := nil>>
  45. else <<u4 := xeucl(u1,u3,var);
  46. % Remove spurious polynomial in numerator.
  47. y := (multsq(remsq(multsq(car u4,u2),!*f2q u3,var),
  48. rfactor) . car x)
  49. . y;
  50. u2 := multsq(cdr u4,u2)>>;
  51. x := cdr x>>;
  52. u3 := exptf(caar x,cdar x);
  53. if u2 = (nil ./ 1) then nil
  54. else if degr(u3,var)=0
  55. then rfactor := numr rfactor ./ multf(u3,denr rfactor)
  56. % Remove spurious polynomial in numerator.
  57. else y := (multsq(rfactor,remsq(u2,!*f2q u3,var)) . car x) . y;
  58. x := nil;
  59. % Finally break down non-linear terms in denominator.
  60. for each j in y do
  61. if cddr j =1 then x := j . x
  62. else x := append(pfpower(car j,cadr j,cddr j,var),x);
  63. x := for each j in x
  64. collect list('quotient,prepsq!* car j,
  65. if cddr j=1 then prepf cadr j
  66. else list('expt,prepf cadr j,cddr j));
  67. if polypart then x := prepsq!* polypart . x;
  68. setkorder xx;
  69. return 'list . x
  70. end;
  71. symbolic procedure xeucl(u,v,var);
  72. % Extended Euclidean algorithm with rational coefficients.
  73. % I.e., find polynomials Q, R in var with rational coefficients (as
  74. % standard quotients) such that Q*u + R*v = 1, where u and v are
  75. % relatively prime standard forms in variable var. Returns Q . R.
  76. begin scalar q,r,s,w;
  77. q := list(1 ./ 1,nil ./ 1);
  78. r := list(nil ./ 1,1 ./ 1);
  79. if degr(u,var) < degr(v,var)
  80. then <<s := u; u := v; v := s; s := q; q := r; r := s>>;
  81. u := !*f2q u; v := !*f2q v;
  82. while numr v do
  83. <<if degr(numr v,var)=0 then w := quotsq(u,v) . (nil ./ 1)
  84. else w := qremsq(u,v,var);
  85. s := list(addsq(car q,negsq multsq(car w,car r)),
  86. addsq(cadr q,negsq multsq(car w,cadr r)));
  87. u := v;
  88. v := cdr w;
  89. q := r;
  90. r := s>>;
  91. v := lnc numr u ./ denr u; % Is it possible for this not to be
  92. % in lowest terms, and, if so, does
  93. % it matter?
  94. r := quotsq(v,u);
  95. return multsq(r,quotsq(car q,v)) . multsq(r,quotsq(cadr q,v))
  96. end;
  97. symbolic procedure qremsq(u,v,var);
  98. % Find rational quotient and remainder (as standard quotients)
  99. % dividing standard quotients u by v wrt var.
  100. % This should really be done more directly without using quotsq.
  101. (quotsq(addsq(u,negsq x),v) . x) where x=remsq(u,v,var);
  102. symbolic procedure remsq(u,v,var);
  103. % Find rational and remainder (as a standard quotient) on
  104. % dividing standard quotients u by v wrt var.
  105. begin integer m,n; scalar x;
  106. n := degr(numr v,var);
  107. if n=0 then rederr list "Remsq given zero degree polynomial";
  108. while (m := degr(numr u,var))>= n do
  109. <<if m=n then x := v
  110. else x := multsq(!*p2q(var.**(m-n)),v);
  111. u := addsq(u,
  112. negsq multsq(multf(lc numr u,denr v)
  113. ./ multf(lc numr v,denr u),
  114. x))>>;
  115. return u
  116. end;
  117. symbolic procedure pfpower(u,v,n,var);
  118. % Convert u/v^n into partial fractions.
  119. begin scalar x,z;
  120. while degr(numr u,var)>0 do
  121. <<x := qremsq(u,!*f2q v,var);
  122. z := (cdr x . v . n) . z;
  123. n := n-1;
  124. u := car x>>;
  125. if numr u then z := (u . v . n) . z;
  126. return z
  127. end;
  128. endmodule;
  129. end;