/*THIS BLOCK CHECKS FOR A POLYNOMIAL IN N*/
POLYP(G,N):=BLOCK([D,F,C],
     G:RATEXPAND(G), IF FREEOF(N,G) THEN RETURN(TRUE),
     D:HIPOW(G,N), F:TRUE,
     FOR I:D STEP -1 THRU 0 DO
     (C:COEFF(G,N,I), IF NOT(FREEOF(N,C)) THEN F:FALSE,
      G:RATEXPAND(G-C*N**I)),
     RETURN(IS(G=0 AND F)))$
   


/*THIS BLOCK CHECKS FOR A CONSTANT TO A POLYNOMIAL POWER*/
POLYINN(X,N):=BLOCK([B,E],
     IF INPART(X,0)="*" THEN
     RETURN(POLYINN(INPART(G,1),N) AND POLYINN(INPART(G,2),N)),
     IF INPART(X,0)#"**" THEN RETURN(FALSE),
     B:INPART(X,1),
     E:INPART(X,2),
     IF NOT FREEOF(N,B) THEN RETURN(FALSE),
     RETURN(POLYP(E,N)))$



/*THIS BLOCK IMPLEMENTS THE CHARACTERISTIC EQUATION METHOD*/
CHAR(E,G,U,N,K,IV):=BLOCK([GENSOL,HOMSOL,PARSOL,LOS,MULTIPLICITIES,
H,V,L,SS,DISPFLAG],
LOCAL(A,AA,B,R,M),
DISPFLAG:FALSE,
  FOR I:0 THRU K DO
    AA[I]:COEFF(E,U(N+K-I)),
    H:0,
  FOR I:0 THRU K DO
    H:H+AA[I]*U(N+K-I),
  IF H#E THEN RETURN("ERRONEOUS INPUT"),

  FOR I:0 THRU K DO
    H:SUBST(U**(K-I),U(N+K-I),H),

  MULTIPLICITIES:TRUE,
  LOS:SOLVE(H,U),
  FOR I:1 THRU LENGTH(LOS) DO
    (R[I]:LOS[I], R[I]:RHS(EV(R[I])),
     M[I]:MULTIPLICITIES[I]),
  HOMSOL:
    SUM(SUM(A[I,J]*N**(M[I]-J),J,1,M[I])*R[I]**N,I,1,LENGTH(LOS)),


  IF G=0 THEN
     (V:[ ],
      FOR I:1 THRU LENGTH(LOS) DO
      FOR J:1 THRU M[I] DO V:CONS(A[I,J],V),
         L:[ ],
      FOR Q:0 THRU K-1 DO L:CONS(SUBST(Q,N,HOMSOL)=U(Q),L),
      SS:EV(SOLVE(L,V),IV),
      RETURN(U(N)=(EV(HOMSOL,SS))))

  ELSE IF POLYP(G,N) = TRUE THEN
     (G:RATEXPAND(G), PARSOL:SUM(B[J]*N**J,J,0,HIPOW(G,N)),
      FOR J:0 THRU K DO
       (L:0, V:E,
         FOR I:0 THRU K DO
         (L:RATEXPAND(SUBST(N+K-I,N,B[J]*N**J)),
          V:RATEXPAND(SUBST(L,U(N+K-I),V))),
          V:RATSIMP(V),
           IF V#0 THEN RETURN(V) ELSE PARSOL:N*PARSOL),
         V:E,
      FOR I:0 THRU K DO (L:RATEXPAND(SUBST(N+K-I,N,PARSOL)),
         V:RATEXPAND(SUBST(L,U(N+K-I),V))),
         L:[ ],
      FOR I:0 THRU HIPOW(PARSOL,N) DO
         L:CONS(COEFF(V=G,N,I),L),
         V:[ ],
      FOR J:0 THRU HIPOW(PARSOL,N) DO
         V:CONS(B[J],V),
      SS:SOLVE(L,V),
      PARSOL:EV(PARSOL,SS))

  ELSE IF POLYINN(G,N) = TRUE THEN
     (PARSOL:B1*G,
      FOR J:0 THRU K DO
       (L:0, V:E,
         FOR I:0 THRU K DO
         (L:SUBST(N+K-I,N,PARSOL), V:SUBST(L,U(N+K-I),V)),
          V:RATSIMP(V),
          IF V#0 THEN RETURN(V) ELSE PARSOL:N*PARSOL),
      SS:SOLVE(V=G,B1),
      PARSOL:EV(PARSOL,SS))

  ELSE IF INPART(G,0)=SIN OR INPART(G,0) = COS THEN
     (PARSOL:B[1]*SIN(INPART(G,1)) + B[2]*COS(INPART(G,1)),
      FOR J:0 THRU K DO
       (L:0, V:E,
         FOR I:0 THRU K DO
         (L:EXPAND(SUBST(N+K-I,N,PARSOL)),
          V:EXPAND(SUBST(L,U(N+K-I),V))),
      V:TRIGEXPAND(V),
      IF V#0 THEN RETURN(V) ELSE PARSOL:N*PARSOL),
         V:E,
      FOR I:0 THRU K DO(L:EXPAND(SUBST(N+K-I,N,PARSOL)),
         V:EXPAND(SUBST(L,U(N+K-I),V))),
      V:TRIGEXPAND(V),
         L:[ ],
      LT:[SIN(INPART(G,1)),COS(INPART(G,1))],
      FOR JJ:1 THRU 2 DO
         L:CONS(COEFF(V=G,LT[JJ]),L),
         V:[ ],
      FOR J:1 THRU 2 DO
         V:CONS(B[J],V),
      SS:SOLVE(L,V),
      PARSOL:EV(PARSOL,SS))


  ELSE RETURN("CAN'T BE SOLVED IN CLOSED FORM BY PROGRAM"),

  GENSOL:HOMSOL + PARSOL,
     V:[ ],
  FOR I:1 THRU LENGTH(LOS) DO
  FOR J:1 THRU M[I] DO V:CONS(A[I,J],V),
     L:[ ],
  FOR Q:0 THRU K-1 DO
  L:CONS(SUBST(Q,N,GENSOL)=U(Q),L),
  SS:EV(SOLVE(L,V),IV),
  RETURN(U(N)=(EV(GENSOL,SS))))$




/*THIS BLOCK IMPLEMENTS THE GENERATING FUNCTION METHOD*/
GENF(E,G,U,N,K,IV):=BLOCK([MULTIPLICITIES,L,V,SS,VV,LOS,
NR,F,SOL,P,DISPFLAG],
LOCAL(A,AA,B),
DISPFLAG:FALSE,
  FOR I:0 THRU K DO
    AA[I]:COEFF(E,U(N+K-I)),
    H:0,
  FOR I:0 THRU K DO
    H:H+AA[I]*U(N+K-I),
  IF H#E THEN RETURN("ERRONEOUS INPUT"),

     L:E,
  FOR I:0 THRU K DO
    L:SUBST((F-SUM(U(J)*X**J,J,0,K-I-1))*X**I,U(N+K-I),L),

  IF G=0 THEN
     (S:SOLVE(L,F),
      F:EV(F,S))

  ELSE IF POLYP(G,N) = TRUE THEN
     (G:RATEXPAND(G),
      V:SUBST(X**K/(1-X)*COEFF(G,N,0),COEFF(G,N,0),G),
      VV:RATSIMP(DIFF(1/(1-X),X)),
      FOR I:1 THRU HIPOW(G,N) DO
        (V:SUBST(X**K*X*VV*COEFF(G,N,I),COEFF(G,N,I)*N**I,V),
         VV:RATSIMP(DIFF(X*VV,X))),
      V:RATSIMP(V),
      SS:SOLVE(L=V,F),
      F:EV(F,SS))

  ELSE IF POLYINN(G,N) = TRUE AND HIPOW(INPART(G,2),N) < 2 THEN
     (G1:(X**K)*(INPART(G,1)**COEFF(INPART(G,2),N,0)),
      G2:1 - X*(INPART(G,1)**COEFF(INPART(G,2),N,1)),
      V:RATSIMP(G1/G2),
      SS:SOLVE(L=V,F),
      F:EV(F,SS))

  ELSE RETURN("CAN'T BE SOLVED IN CLOSED FORM BY PROGRAM"),


  MULTIPLICITIES:TRUE,
  LOS:SOLVE(NEWRAT(F),X),
  FOR I:1 THRU LENGTH(LOS) DO
     (R[I]:LOS[I], R[I]:RHS(EV(R[I])),
      M[I]:MULTIPLICITIES[I]),

     V:[ ],
  B:PRODUCT((1-R[I]*X)**M[I],I,1,LENGTH(LOS)),
  FOR I:1 THRU LENGTH(LOS) DO
  FOR J:1 THRU M[I] DO
     (P[I,J]:B*A[I,J]/((1-R[I]*X)**J),  V:CONS(A[I,J],V)),
  P:SUM(SUM(P[I,J],J,1,M[I]),I,1,LENGTH(LOS)),

     L:[ ],
  NF:RATEXPAND(NUM(F)/ABS(COEFF(DENOM(F),X,0))), P:RATEXPAND(P),
  FOR I:0 THRU HIPOW(RATEXPAND(B),X)-1  DO
     L:CONS(COEFF(NF=P,X,I),L),
  SSS:EV(SOLVE(L,V),IV),

  SOL:SUM(SUM(A[I,J]*COEFF(DENOM(F),X,0)/ABS(COEFF(DENOM(F),X,0))*
     BINOMIAL(J+N-1,N)*R[I]**N,J,1,M[I]),I,1,LENGTH(LOS)),

  RETURN(U(N)=(EV(SOL,SSS))))$


/*THIS BLOCK FINDS THE NEW POLYNOMIAL ASSOCIATED TO F*/
NEWRAT(F):=BLOCK([HD,CP,DP],
     HD:HIPOW(DENOM(F),X),
     CP:COEFF(DENOM(F),X,HD),
     DP:SUM((COEFF(DENOM(F),X,I))/CP*X**I,I,0,HD),
     RETURN(SUM(COEFF(DP,X,HD-I)*X**I,I,0,HD)))$





/*THIS BLOCK IMPLEMENTS THE VARIABLE COEFFICIENT METHOD*/
VARC1(E,G,U,N,K,IV):=BLOCK([V,VV,EQ,Y,CAUCHYSUM,FINSOL,SERSOL,DISPFLAG],
LOCAL(A,B),DISPFLAG:FALSE,
  FOR I:0 THRU K DO
    (A[I]:COEFF(E,U(N+I)),
     A[I]:RATEXPAND(A[I]),
     IF POLYP(A[I],N)=FALSE THEN RETURN("CAN'T DO IT")),
  IF K=2 AND (B:BESSELCHECK(E,K) # FALSE) THEN RETURN(B),
  V:RATEXPAND(E),
  FOR I:K STEP -1 THRU 0 DO
     FOR J:HIPOW(A[I],N) STEP -1 THRU 0 DO
       (V:RATSUBST(X**J*'DIFF(Y,X,I+J),N**J*U(N+I),V),
        V:RATEXPAND(V)),
  V:RATSUBST(Y,'DIFF(Y,X,0),V),
  V:RATEXPAND(V),
  IF POLYP(G,N) = TRUE THEN
    (G:RATEXPAND(G), VV:G,
     FOR I:0 THRU HIPOW(G,N) DO
        VV:SUBST(X**I,N**I,VV),
        VV:%E**X*VV)
  ELSE RETURN("CAN'T DO IT"),

     EQ:V-VV,
  DEPENDENCIES(Y(X)),
  SOL:ODE2(EQ=0,Y,X),
        IF K=1 THEN FINSOL:IC1(SOL,X=0,Y=EV(U(0),IV))
        ELSE IF K=2 THEN FINSOL:IC2(SOL,X=0,Y=EV(U(0),IV),'DIFF(Y,X)=EV(U(1),IV))
  ELSE RETURN("O.D.E. CAN'T BE SOLVED AT PRESENT BY MACSYMA"),
     CAUCHYSUM:TRUE,
  SERSOL:POWERSERIES(RHS(FINSOL),X,0), SERSOL:EXPAND(SERSOL),
  B:INPART(SERSOL,1),
  B:EV(B,X=1),
  IF ATOM(B)=FALSE THEN B:SUBSTPART(N,B,4),
  RETURN(U(N)=((N!)*B)))$


/*THIS BLOCK CHECKS FOR A BESSEL RECURRENCE RELATION*/

BESSELCHECK(E,K):=BLOCK([A,ANS],
LOCAL(A),
     FOR I:0 THRU K DO
     (A[I]:COEFF(E,U(N+I)),
      A[I]:RATEXPAND(A[I])),
     IF NOT(INTEGERP(A[0])) THEN RETURN(FALSE),
     IF NOT(INTEGERP(EV(A[1],N=0))) THEN RETURN(FALSE),
     IF NOT(HIPOW(A[1],N)=1) THEN RETURN(FALSE),
     IF NOT(INTEGERP(COEFF(A[1],N,1))) THEN RETURN(FALSE),
     IF NOT(A[2]=1) THEN RETURN(FALSE),
     ANS:"A LINEAR COMBINATION OF BESSEL FUNCTIONS",
     /*EXACT DETAILS ARE OF NO SIGNIFICANCE,SINCE WE ARE MERELY
       DEMONSTRATING THE FEASIBILITY OF THIS APPROACH*/
     RETURN(ANS))$





/*THIS BLOCK IMPLEMENTS THE FIRST ORDER METHOD*/
VARC2(E,G,U,N,K,IV):=BLOCK([H,P,V,C,SOL],
LOCAL(AP,P),
     P:(-1)*COEFF(E,U(N))/COEFF(E,U(N+1)),
     V:G/COEFF(E,U(N+1)),
     S[J]:SUBST(J,N,P),
     S[I]:SUBST(I,N,P),
     P[N]:PRODUCT(S[I],I,1,N-1),
     H[I]:SUBST(I,N,V)/PRODUCT(S[J],J,1,I-1),
     V1:SUM(H[I],I,0,N),
     AP:EV(U(0)-SUBST(0,N,V),IV),
     RETURN(U(N)=AP*P[N]+P[N]*V1))$
