##############################################################################
#                                                                            #
#                 Program to solve linear integral equation                  #
#                                                                            #
#                  by     Honglin Ye & Robert M. Corless                     #
#                                                                            #
#                             December 9, 1991                               #
#                                                                            #
#                                                                            #
# Revised July 10, 1992, RMC                                                 #
#   - removed quotes around local variables in calls, and subsequent         #
#     calls to "eval" in the called routines.                                #
#   - developed a standard test file.                                        #
#                                                                            #
# Revised May 11, RMC                                                        #
#   - Mint run to clean up locals                                            #                                                                             
#   - attempt to fix local evaluation of names problem.                      #
#                                                                            #
# Revised May 9, RMC                                                         #
#   - Extracted logically separate pieces of code for maintainability        #
#     reasons.  Split IntSolve into IntSolve, IntSolve/Standardize,          #
#     IntSolve/Classify, IntSolve/Neumann, IntSolve/Laplace,                 #
#     IntSolve/Eigenfunc, and IntSolve/Differentiate.                        #
#   - Added much documentation.                                              #
#   - Totally rewrote eigenfunction method.  It now works semi-reliably,     #
#     and we can even solve some integral equation eigenvalue problems       #
#     with this routine.                                                     #
#                                                                            #
# Revised May 7, RMC                                                         #
#   - fixed "readlib(laplace)" bug, RETUR misspelling                        #
#   - made alignment consistent                                              #
#   - added RETURN to differentiation option section                         #
#   - added RETURN(NULL) to Laplace method in case no solution found.        #
#   - improved the English in various places.                                #
#   - converted "int" to "Int" where it was only used for printing           #
#     in classification section and Volterra transformation section.         #
#   - added testing for Int as well as int in classifications.               #
#   - changed "ternel" to "kernel", made "methodin" local as detected        #
#     by "MINT".                                                             #
#   - removed assignments to expression sequences as these are disallowed    #
#     in Maple V, Release 2.                                                 #
#                                                                            #
#                                                                            #
# Revised May 5, HY                                                          #
#   - changed from printing results to RETURNing results.                    #
#                                                                            #
##############################################################################

`help/text/IntSolve`  := TEXT(
`FUNCTION: IntSolve - solve a linear integral equation`,
`             `,
`CALLING SEQUENCE:`,
`   infolevel[IntSolve] := 1, 2, 3, or 5;`,
`   then`,
`   IntSolve(Inteqn, funcn)`,
`   or`,
`   IntSolve(Inteqn, funcn, meths)`,
`             `,
`PARAMETERS:`,
`   Inteqn  - linear integral equation in funcn`,
`   funcn   - unknown function to be solved for`,
`   meths   - one of the methods : neumann (or an integer), Laplace`,
`             differentiate, eigenfunc`,
`             `,
`SYNOPSIS:`,
`- IntSolve is able to find closed-form solutions to many integral equations.`,
`  The solution is returned as an explicit expression in whatever independent`,
`  variable was specified for the unknown function funcn, or, if the`,
`  "differentiate" method is used, the result may be an equivalent set`,
`  of differential equations which can be attacked with "dsolve".`,
`  Any arbitrary constants which are returned`,
`  are represented as t1, t2, ...  tn if they occur.`,
`  KNOWN BUG: If these constants are previously assigned, then the`,
`  results will be in error.  This will be changed for the next version.`,
`            `,
`- IntSolve can recognize Fredholm and Volterra integral equations of the`,
`  following kinds:`,
`  Fredholm equation of the first kind (F1):     `,
`> int(k(x,y)*f(y),y=a...b)=g(x);                `,
`  Fredholm equation of the second kind (F2):     `,
`> f(x)+int(k(x,y)*f(y),y=a...b)=g(x);                `,
`  Fredholm equation of the third (homogeneous) kind (F3):     `,
`> f(x) + int(k(x,y)*f(y),y=a...b)= 0;                `,
`  Volterra equation of the first kind (V1):     `,
`> int(k(x,y)*f(y),y=a...x)=g(x);                `,
`  Volterra equation of the second kind (V2):     `,
`> f(x) + int(k(x,y)*f(y),y=a...x)=g(x);                `,
`  Volterra equation of the third (homogeneous) kind (V3):     `,
`> f(x) + int(k(x,y)*f(y),y=a...b)= 0;                `,
`            `,
`  KNOWN BUG:  If the integral equation is not one of these types,`,
`  for example if the upper limit is x^2 instead of x, it is possible`,
`  that an erroneous solution may be generated.`,
`             `,
`- The neumann option causes IntSolve to use the Neumann series method. `,
`  This method is applicable to equations of V2, F2, and some of V1 type. The`,
`  default order of Neumann series in the solution is 4. An alternative `,
`  option is an integer, which causes IntSolve to yield the Neumann series `,
`  solution to the order specified by the integer.`,
`           `,
`- The Laplace option causes IntSolve to use Laplace transforms. This`,
`  method is applicable to equations of V2, V1 and V3 type. One advantage to `,
`  using this option is that the integral equation may contain the Dirac or `,
`  Heaviside functions. These functions are not recognized by the rest of `,
`  IntSolve. This method is not suitable if the equation does not posseses`,
`  a convolution type kernel. In that case, no explicit solution can be found`,
`  by the Laplace transformation method.`,
`           `,
`- The differentiate option causes IntSolve to transform equations of V2 and`,
`  V1 type into an equivalent differential equation plus initial conditions.`,
`  The output of this option may be the solution of the integral equation or`,
`  a set consisting of the differential equation plus the initial conditions.`,
`  Some work may be required to transform the initial conditions into a`,
`  form that dsolve will accept.  For example 2 below, for instance, the`,
`  user must transform the resulting initial conditions {f(0) - 1 = 0,`,
`  D(f)(0) - f(0) - 1 = 0} to {f(0) = 1, D(f)(0) = 2} before "dsolve"`,
`  will solve the differential equation.`,
`           `,
`- The eigenfunc option causes IntSolve to solve equations of F1, F2, and`,
`  F3 types by an eigenfunction approach.`,
`            `,
`- The default methods for various equations are:  `,
`    V1---- neumann or differentiate    F1---- eigenfunc `,
`    V2---- neumann                     F2---- neumann `,
`    V3---- Laplace                     F3---- eigenfunc `,
`           `,
`- infolevel[IntSolve] := 1,2,3 or 5 gives descriptive information on the`,
`  progress of the computation. 5 may result in excessive printing. `,
`          `,
`REFERENCE: Integral Equations, by Ll. G. Chambers `,
`           Integral Equations, by F. G. Tricomi   `,
`           `,
`EXAMPLES:`,
`>eq1 := p(x) -1/2*Int(x*y*p(y),y=0....1) = 5/6*x; IntSolve(eq1,p(x));`,
`>eq2:=f(x)=x+1+Int((1+2*(x-y))*f(y),y=0..x);IntSolve(eq2,f(x),differentiate);`,
`>eq3 := Int(sin(a*(x-y))*f(y),y=0...x) = x; IntSolve(eq3,f(x),Laplace);`,
`>q4:=f(x)+b*Int((x*y+x^2*y^2)*f(y),y=-1..1)=d(x);IntSolve(q4,f(x),eigenfunc);`,
`         `,
`SEE ALSO:  invlaplace, laplace, dsolve, D`
):
#____________________________________________________________________________
# with(student,value):
read Echelon;
#____________________________________________________________________________

`IntSolve/Standardize` := proc(eqn,func,f_out,head_out,body_out,tail_out,
                               kernel_out,x_out,y_out,lowerlimit_out,
                               upperlimit_out)
   local i,j,limvar,eq,f_local2,gun,e,seq1,seq2,term,divisor,m,n,
         head,body,tail,kernel,x,y,lowerlimit,upperlimit;
#
# Transform input equation into standard form
#
# Call:  `IntSolve/Standardize`(eqn,func,head,body,tail,kernel);
#
# Input:  eqn --- input integral equation.
#         func -- unknown function to solve for.
#         head_out,body_out,tail_out,kernel_out
#                 --- names for output of standard form
# Output: 
#         head --- either f(x) or zero, depending on type
#         body --- usually Int(kernel*f(y),y=a..b)
#         tail --- inhomogeneous part, also called the "influence 
#                  function".
#         kernel - function of x and y
#
# Revision history
#
# May 9, 1992 --- RMC --- extracted this from IntSolve, commented it.
#
  if not type(eqn,'equation') then
    eq := subs(int=Int,eqn)
  else
    eq := subs(int=Int,op(1,eqn)-op(2,eqn));
  fi;

#  print(1,eq);

  f_local2 := op(0,func);
  userinfo(3,`IntSolve/Standardize`,`functionname=`,print(f_local2));
  x := op(1,func);
  userinfo(3,`IntSolve/Standardize`,`indepedentvar=`,print(x));

  gun := 0;

  tail := simplify(value(subs(f_local2=gun,eq))):
  body := simplify(eval(subs(func=gun,eq-tail))):
  head := simplify(eq-body-tail):

#  print(2,head,body,tail):

  e := head +body +tail=0:

  if type(body,`+`) then
    n := nops(body):
    seq1 := array(1..n,[op(1...n,body)]):
  else
    n := 1:
    seq1 := array(1..1,[body]):
  fi:

  body := 0:
  for i to n do
    term := 1:
    if type(seq1[i],`*`) then
      m := nops(seq1[i]):
      seq2 := array(1..m,[op(1...m,seq1[i])]):
    else
      m := 1:
      seq2 := array(1..1,[seq1[i]]):
    fi:
    for j to m do
      if type(seq2[j],function) then

        # This section of the code assumes that no nested integrals
        # or iterated integrals are present as part of the kernel.

        if (op(0,seq2[j]) <> int) and (op(0,seq2[j]) <> Int) then
          term := term * seq2[j]:
        else
          # This should happen only once... or if repeatedly,
          # then the integral variables and limits should be
          # identical.

          term := term * op(1,seq2[j]):
          limvar := op(2,seq2[j]):
          y := op(1,limvar):
          lowerlimit := op(1,op(2,limvar)):
          upperlimit := op(2,op(2,limvar)):
        fi:
      else
        term := term * seq2[j]
      fi:
    od:
    body := body + term:
  od:

# print(333333333333333333333333333);

  kernel := normal(body/f_local2(y)):

# print(44444444444444444444444);

  if has(kernel,f_local2) then 
    ERROR(`Integral equation is not linear.`): 
  fi:

# print(5555555555555555555);

  userinfo(3,`IntSolve/Standardize`,`head=`,print(head)):
  userinfo(3,`IntSolve/Standardize`,`body=`,print(body)):
  userinfo(3,`IntSolve/Standardize`,`tail=`,print(tail)):
# print(666666666666666666666666);
  userinfo(3,`IntSolve/Standardize`,`intgralvar=`,print(y)):
  userinfo(3,`IntSolve/Standardize`,`lowerlimit=`,print(eval(lowerlimit))):
  userinfo(3,`IntSolve/Standardize`,`upperlimit=`,print(eval(upperlimit))):
# print(77777777777777777777777);
  if head <> 0 then
    divisor := head/func:
    head    := func:
    kernel  := normal(kernel/divisor):
    tail    := normal(tail/divisor):
  fi:
# print(8888888888888888888);  

  head_out := head;
  
  body := Int(kernel*f_local2(y),
              y=lowerlimit...upperlimit):
  body_out := body;
  tail_out := tail;
  kernel_out := kernel;
  f_out := f_local2;
  x_out := x;
  y_out := y;
  lowerlimit_out := lowerlimit;
  upperlimit_out := upperlimit;
  NULL;
end:  # IntSolve/Standardize

#____________________________________________________________________________

`IntSolve/Classify` := proc(head,body,tail,kernel,input_method, out_meth,n,
                            x,y,lowerlimit,upperlimit,out_name,out_class)
  local f0,f1,work,e,meth,name,class:
   
  if upperlimit = x or lowerlimit = x then
    name := 'Volterra':
  else

    # We ignore the possibility of strange upper and
    # lower limits, e.g. x^2 or sin(x).

    name := 'Fredholm':  
  fi:

  class := 'second':
  if  head = 0 then class := 'first' fi:
  if tail = 0 then class := '`third (homogeneous)`': fi:

  e := head + body = -tail:

  out_name := name:
  out_class := class:

  userinfo(2,`IntSolve/Classify`,`The equation to be solved is a `,
           print(name),
          `integral equation of the `,
           print(class),
          `kind. The standard form is:`):
  userinfo(2,`IntSolve/Classify`,print(e)):

#
# Choose a method for solving
#

  if input_method <> 'none' then
    meth := input_method:
  elif class = 'second' then 
    meth := 'neumann':
  elif name = 'Fredholm' and ( class = 'first' or
             class = '`third (homogeneous)`'   )    then 
    meth := 'eigenfunc':
  elif name = 'Volterra' and class = 'first' then
    work := subs(y=x,kernel):
    if work <> 0 then 
      meth := 'neumann':
    else 
      meth := 'differentiate':
    fi:
  elif name = 'Volterra' and class = '`third (homogeneous)`'  then 
    meth := 'Laplace':
  fi:

  if type(input_method,integer) then
    n := input_method:
    meth := 'neumann':
  else
    n := 4:
  fi:

  out_meth := meth:
  if not (meth = 'neumann' or meth = 'differentiate' or
          meth = 'eigenfunc' or meth = 'Laplace')  then
    ERROR(`Unknown method`,meth):
  fi:

  userinfo(1,`IntSolve/Classify`,`The method chosen is `,print(meth)):

  if name = 'Volterra' and (class = 'first' or class = 'second') then
    f0 := subs(y=0, kernel):
    f1 := subs(x=x-y,f0):
    work := normal(kernel - f1):
    if work = 0 then
      userinfo(5,`IntSolve/Classify`,
           `The equation has convolution type kernel. It`,
           `can be solved using the Laplace transform method.`):
    else
      userinfo(5,`IntSolve/Classify`,
            `The equation apparently does not have convolution type and`,
            `cannot be solved with the Laplace transform method.`):
    fi:
  fi:

end:  # IntSolve/Classify                               

#____________________________________________________________________________

`IntSolve/Neumann` := proc(n,head,kernel,tail,f,x,y,lowerlimit,upperlimit,
                           name, class)
  local body,i,work,dummy,x_loc,
        phi_0,phi_i,int_kernel,int_phi:
#
# Transform Volterra first type to Volterra second type
#
  x_loc := x:

  if class = 'first' then
    work := normal(subs(x_loc=lowerlimit,tail)):
    if work <> 0 then
      ERROR (`Consistency condition failed.  No solution found.`):
    fi:
    work := normal(subs(y=x_loc, kernel)):
    if work <> 0 then
      kernel := - diff(kernel,x_loc)/work:
      tail := diff(tail,x_loc)/work:
      head := f(x_loc):
      body := Int(kernel*f(y),y=lowerlimit...upperlimit):
      class := 'second':
    fi:
    userinfo(5,`IntSolve/Neumann`,
         `The equation has been transformed into a Volterra`,
         `integral equation of the second kind. The standard form is:`):
    userinfo(5,`IntSolve`,print(head +body =-tail)):
  fi:

#
# Resolvent kernel solver
#

  if class = 'second' then
    phi_0 := -value(tail):
    phi_i := phi_0:
    int_kernel  := subs( y=dummy,value(kernel)):
    for i to n do
      int_phi := subs( x_loc=dummy,phi_i):
      phi_i := phi_0 - int(int_kernel*int_phi,dummy=lowerlimit...upperlimit):
      phi_i := simplify(phi_i):
    od:
  fi:
  RETURN(map(value,phi_i)):
end:  # IntSolve/Neumann

#____________________________________________________________________________

`IntSolve/Laplace` := proc(head, kernel,tail,f,x,y,lowerlimit,upperlimit,class)
  local trans,answer,b,s,e:
  readlib(laplace):
  e := head + Int(kernel*f(y),y=lowerlimit..upperlimit) = -tail:
  trans := laplace(e,x,s):
  if has(trans,diff) then
    answer := dsolve(subs(laplace(f(x),x,s)=b(s),trans),b(s)):
    if answer=NULL then
      ERROR(`Dsolve failed to find solution for transform of`,
            `the solution to the singular kernel integral equation.`):
    else
      answer := invlaplace(op(2,answer),s,x):
    fi
  else
    answer := solve(trans,laplace(f(x),x,s)):
    if answer=NULL then
      ERROR(`solve failed to find the solution for the transform`,
            `of the solution to the integral equation.`):
    elif type(answer,set) then
      print(`solve found too many solutions for the transform`,
            `of the solution to the integral equation!`):
      answer := map(invlaplace,answer,s,x);
    else
      answer := invlaplace(answer,s,x):
    fi:
  fi:
answer
end:  # IntSolve/Laplace

#____________________________________________________________________________

`IntSolve/Eigenfunc` := proc(head,kernel,tail,x,y,
                             lowerlimit,upperlimit,
                             lastproviso)
  local inds,const,i,j,m,n,K,b,c,d,terms,factors,detm,
        fac,form,matches,g,F,matrix_dim,matri:
  #
  # Eigenfunction approach to solving degenerate kernel equations,
  # rewritten from scratch May 9, 1992 --- RMC
  #
  # Input:  head, kernel, tail, 
  #         lowerlimit, upperlimit --- integral equation description
  #         f(x) --- unknown function to be solved for
  #         y    --- integration variable
  #
  # Output:  solution f(x), as a sum of eigenfunctions,
  #          possibly containing arbitrary constants.
  #
  #          lastproviso = det(matrix)<>0, and if this is zero,
  #          then the returned solution is incorrect and the
  #          whole process must be re-done (perhaps using
  #          a different normalizer).

  userinfo(3,`IntSolve/Eigenfunc`,`Attempting to separate kernel`):

  inds := map(proc(t,xx,yy) if has(t,xx) or has(t,yy) then t fi end,
              indets(kernel),x,y):

  K := collect(expand(kernel),inds):    
                     # exp(x+y) -> exp(x)*exp(y), etc.

  # In Maple, a constant can be a sum of terms, too, for
  # example -7*lambda + sqrt(13).  It turns out that if this is
  # left as a separate sum, then we get too many indeterminates
  # and an ugly form for the answer.  So we have to separately
  # handle the constant term, if there is one.
  # 
  const := 0:
  if type(K,`+`) then
    # Look for the constants.  This is remarkably difficult.
    for i in {op(1..nops(K),K)} do
      if (not has(i,x)) and (not has(i,y)) then const := const + i fi
    od
  fi: 
  
  K := K - const:
    
  if type(K,`+`) then 
    m := nops(K):
    terms := array(0..m,[const,op(1..m,K)]):
  else
    m := 1:
    terms := array(0..m,[const,K]):
  fi:
  
  c := array(0..m):
  d := array(0..m):
 
  # We are hoping that K(x,y) = const + sum(c[i]*d[i],i=1..m)
  # where each c[i] is a function of x only while each d[i] is
  # a function of y only.  Think of const = c[0]*d[0], where c[0]=1.
  
  c[0] := 1;
  d[0] := terms[0];

  for i to m do
    c[i] := 1:
    d[i] := terms[i]:
    
    # Loop invariant is c[i]*d[i] = terms[i]
    
    if type(d[i],`*`) then
      n := nops(d[i]):
      factors := array(1..n,[op(1..n,d[i])]):
    else
      # Might be pure function of x, or pure function of y.
      if not has(d[i],y) then
        c[i] := d[i]:
        d[i] := 1:
      elif has(d[i],x) then
        ERROR(`Unable to separate the kernel.`):
      fi:
      n := 1:
      factors := array(1..n,[d[i]]):
    fi:

    for j to n do
      fac := factors[j]:
      if has(fac,x) and ( not has(fac,y)) then
        c[i] := c[i]*fac:
        d[i] := d[i]/fac:  # Automatic normalization
      elif has(fac,x) and has(fac,y) then
        ERROR(`Unable to separate kernel`):
      fi:      
          # REMARK:  We leave constant factors in with d[i].
    od:
  od:  

  userinfo(3,`IntSolve/Eigenfunc`,`Kernel separated.`):
  userinfo(5,`IntSolve/Eigenfunc`,`Constant term is `,print(const)):
  userinfo(5,`IntSolve/Eigenfunc`,`Functions of `,x,` are`):
  userinfo(5,`IntSolve/Eigenfunc`,print(c)):
  userinfo(5,`IntSolve/Eigenfunc`,`Functions of `,y,` are`):
  userinfo(5,`IntSolve/Eigenfunc`,print(d)):

  matrix_dim := m+1:
  matri := linalg[matrix](matrix_dim,matrix_dim):
  
  for i from 0 to m do
    for j from 0 to m do
      matri[i+1,j+1] := int(d[i]*subs(x=y,c[j]),y=lowerlimit..upperlimit)
    od:
    if head <> 0 then matri[i+1,i+1] := matri[i+1,i+1] + 1: fi:
  od:
  

  userinfo(5,`IntSolve/Eigenfunc`,`The matrix of linear equations is`):
  userinfo(5,`IntSolve/Eigenfunc`,print(matri)):

  

  g := linalg[vector](matrix_dim): 
  form := 0:
  for i from 0 to m do  form := form + g[i+1]*c[i]: od:
  
  if (head = 0) then
    if match(-tail=form,x,matches) then
      assign(matches):
  
#      F := linalg[linsolve](matri,g):

      F := RowEchelonSolve(matri,g,detm);
      lastproviso := detm <> 0:
      userinfo(1,`IntSolve/Eigenfunc`,`The determinant of the matrix is`,
                  detm):
      
      if F=NULL then
        ERROR(`No solution found for eigenfunction coeffiecients.`):
      fi:
      RETURN(eval(subs(g=F,form)))
    else
      ERROR(`The "influence function" is not the correct form`,
       `according to "match".  There appears to be no solution.`)
    fi
  else
    # We first "subtract off" the influence function:
    b := linalg[vector](matrix_dim):
    for i from 0 to m do
      b[i+1] := int(subs(x=y,tail)*d[i],y=lowerlimit..upperlimit):
    od:
#    F := linalg[linsolve](matri,b):
    F := RowEchelonSolve(matri,b,detm);
    lastproviso := detm <> 0:
    userinfo(1,`IntSolve/Eigenfunc`,`The determinant of the matrix is`,
                detm):
    if F=NULL then
      ERROR(`No solution found for eigenfunction coefficients.`):
    fi:
    RETURN(-tail + eval(subs(g=F,form)))
  fi:
  
end:  # IntSolve/Eigenfunc

#____________________________________________________________________________

`IntSolve/Differentiate` := proc(head,body,tail,kernel,f,x,y,
                                lowerlimit,upperlimit)
  local maxord,seq1,f0,f1,f2,e,work,work1,work2,i,m,divisor:
  
  maxord := 10:   # Allow only this many differentiations.

  e := head + body = -tail:
  seq1 := array(0..maxord):
  f1 := head:
  f2 := tail:
  work := kernel * eval(f)(y):
  f0 := work:
  m := 0:
  seq1[m] := op(1,e)-op(2,e):
  while work <> 0 do
    if f1 <> 0 then
      unapply(",x)(lowerlimit):
      seq1[m] := simplify("):
      m := m + 1:
    fi:
    f1 := diff(f1,x):
    f2 := diff(f2,x):
    work1 := subs(y=upperlimit,work)*diff(upperlimit,x):
    work2 := subs(y=lowerlimit,work)*diff(lowerlimit,x):
    work := diff(work,x):
    f1 := f1 + work1:
    f1 := simplify("):
    f2 := f2 + work2:
    f2 := simplify("):
    divisor := work/f0:
    if diff(divisor,y) = 0 then
      f1 := f1 - divisor * head:
      f2 := f2 - divisor * tail:
      work := 0:
    fi:
    seq1[m] := f1 + f2 + int(value(work),y=lowerlimit..upperlimit):
    convert(",D):
    seq1[m] := simplify("):
    if m = maxord then work := 0: fi:
  od:

  if m = maxord then
    ERROR(`The integral equation has not been `,
           `transformed into differential equations after differentiating`,
           ` more than`, maxord,` times.`):
  fi:

  if m = 0 then
    solve(seq1[m],eval(f)(x)):
    f0 := simplify("):
    RETURN(map(value,f0)):
  else
    userinfo(1,`IntSolve/Differentiate`,
         `The integral equation has been transformed`,
         `into the following set of differential equations.`,
         `A solution may be attempted with "dsolve".`):
    RETURN(map(value,{seq(seq1[i]=0,i=0..m)})):
  fi:

end:

#-------------------------------------------------------------------------
#                       M A I N   P R O G R A M                                  
#_________________________________________________________________________

IntSolve := proc(eqn,func)
  local head,body,tail,f_local1,x,y,n,answer,input_method,
            kernel,name,class,e,lastproviso,
            lowerlimit,upperlimit,method;
  global infolevel;

#
# Transform input equation into standard form
#  

  if not type(infolevel[IntSolve],numeric) then 
    infolevel[IntSolve] := 0:
  fi:

  infolevel[`IntSolve/Standardize`] := infolevel[IntSolve]:

  `IntSolve/Standardize`(eqn,func,f_local1,
                        head,body,tail,
                        kernel,x,y,lowerlimit,upperlimit):
  e := head +body = -tail:
  userinfo(3,`IntSolve`,`The standard form is`,print(e)):

#
# Classify the equation
#
  if nargs > 2 then 
    input_method := args[3] 
  else 
    input_method := 'none' 
  fi:

  infolevel[`IntSolve/Classify`] := infolevel[IntSolve]:

  `IntSolve/Classify`(head,body,tail,kernel,input_method, method,n,
                      x,y,lowerlimit,upperlimit,name,class):
  if method = 'Laplace'  then
    userinfo(5,IntSolve,`The equation is being solved using the `,
                `Laplace transform method.`):
    infolevel[`IntSolve/Laplace`] := infolevel[IntSolve]:
    `IntSolve/Laplace`(head, kernel,tail,f_local1,x,y,lowerlimit,upperlimit,class)
    
  elif method = 'neumann' then
    userinfo(5,`IntSolve`,`The equation is being solved using the `,
                `Neumann series method.`):
    infolevel[`IntSolve/Neumann`] := infolevel[IntSolve]:
    `IntSolve/Neumann`(n,head,kernel,tail,f_local1,x,y,lowerlimit,upperlimit,
                       name, class):

  elif method = 'eigenfunc' then
    userinfo(5,`IntSolve`,`The equation is being solved using the `,
                `eigenfunction method.`):
    infolevel[`IntSolve/Eigenfunc`] := infolevel[IntSolve]:
    answer := `IntSolve/Eigenfunc`(head,kernel,tail,x,y,
                         lowerlimit,upperlimit,
                         lastproviso):
    if nargs > 3 then assign(args[4],lastproviso): fi:
    answer:

  elif method = 'differentiate' then
    userinfo(5,`IntSolve`,`The equation is being solved using the `,
                `differentiation method.`):
    infolevel[`IntSolve/Differentiate`] := infolevel[IntSolve]:
    `IntSolve/Differentiate`(head,body,tail,kernel,f_local1,x,y,
                                lowerlimit,upperlimit):
  else
    ERROR(`Method `,method,` unknown.`):
  fi:
end:
#save `IntSolve.m`:
#quit
