reorder := proc( form, ind1, ind2)
#
# restructures form by interchanging the order in which two
# sums, limits, or integrals are performed.
# the sums affected are those whose controlling variable is ind1 or ind2.
#
   local ind, innerind, summand, insum, rest;
   
   if nargs > 3 or nops( {ind1, ind2, FAIL}) < 3 then
      ERROR( `illegal arguments`)
   fi;
   if type( form, {numeric, string}) then
      RETURN( form)        # bottom of recursion
   fi;
   ind := `reorder/indexof`( form);
   if ind = ind1 or ind = ind2 then
      # form is the outermost sum of the sums of interest
      if ind = ind1 then
	 innerind := ind2
      else
	 innerind := ind1
      fi;
      if not has( op( 2, form), innerind) then
	 summand := op( 1, form);
	 # split up summand = insum * rest
	 if type( summand, `*`) then
	    insum := map( proc( x, var) if has( x, var) then x else 1 fi end,
		      	  summand,
		      	  innerind);
      	    rest := map( proc( x, var) if has( x, var) then 1 else x fi end,
		      	 summand,
		      	 innerind);
      	 else
	    insum := summand;
	    rest := 1;
	 fi;
	 # if exactly one factor of summand contains references to innerind
	 # then insum will be that factor.
	 # if insum is 1 or a product it will fail the following test.
	 if `reorder/indexof`( insum) = innerind and
	    not has( op( 2, insum), ind)
	 then
	    RETURN( subsop( 1=subsop( 1=rest*op( 1, insum), form), insum))
	 fi;
      fi;
   fi;
   map( procname, args)
end:

`reorder/indexof` := proc( form)
#
# returns the index variable of a sum,
# the variable of integration of an integral,
# or the controlling variable of a limit expression,
# IF  form  actually is a sum/integral/limit expression,
# otherwise returns  FAIL.
#
   local ind;
   
   if type( form, function) and
      member( op( 0, form), {sum, Sum, int, Int, limit, Limit})
   then
      ind := op( 2, form);
      if type( ind, `=`) then  ind := op( 1, ind)  fi;
      ind
   else
      `FAIL`
   fi
end:

`help/text/reorder` := TEXT(
`FUNCTION: reorder - interchange order of sums, integrals, limits`,
`   `,
`CALLING SEQUENCE: reorder( expr, ind1, ind2);`,
`   `,
`PARAMETERS: expr - an expression`,
`	    ind1, ind2 - strings naming the control variables involved`,
`   `,
`SYNOPSIS:   `,
`- The call  reorder( expr, ind1, ind2)  restructures  expr  by`,
`  interchanging the order in which two sums, integrals, or limits are`,
`  performed.  The sums, integrals, or limits affected are those whose`,
`  controlling variable is  ind1  and  ind2.`,
`   `,
`- No change is effected if the expressions involved fail certain`,
`  requirements:  the range of  ind1  must not refer to  ind2, and`,
`  vice-versa, the inner sum, integral, or limit involved must`,
`  appear as a factor of the first argument to the outer sum,`,
`  integral, or limit, (the other factors containing no references`,
`  to the inner index), and  ind1  and  ind2  must not be identical`,
`  to each other, nor equal to  ``FAIL``.`,
`   `,
`- It is the responsibility of the user to determine that the`,
`  operation requested is permissible, by whatever argument of`,
`  uniform convergence or absolute summability is appropriate.`,
`  Interchanging a double sum with finite limits is always permitted.`,
`   `,
`EXAMPLES:   `,
`   `,
`> a * Int( b(x)*Sum( f(n,x), n=0..m), x=0..1);   `,
`                             1      /  m          \\`,
`                             /      |-----        |`,
`                            |       | \\           |`,
`                         a  |  b(x) |  )   f(n, x)| dx`,
`                            |       | /           |`,
`                           /        |-----        |`,
`                           0        \\n = 0        /`,
`   `,
`> reorder( ", x, n);`,
`                           /  m     1                \\`,
`                           |-----   /                |`,
`                           | \\     |                 |`,
`                         a |  )    |  b(x) f(n, x) dx|`,
`                           | /     |                 |`,
`                           |----- /                  |`,
`                           \\n = 0 0                  /`,
`   `,
`> Sum(Sum(Sum( a(i,j,k), i=0..infinity), j=0..infinity), k=0..infinity);`,
`                   infinity /infinity /infinity           \\\\`,
`                    -----   | -----   | -----             ||`,
`                     \\      |  \\      |  \\                ||`,
`                      )     |   )     |   )     a(i, j, k)||`,
`                     /      |  /      |  /                ||`,
`                    -----   | -----   | -----             ||`,
`                    k = 0   \\ j = 0   \\ i = 0             //`,
`   `,
`> reorder( ", i, j);`,
`                   infinity /infinity /infinity           \\\\`,
`                    -----   | -----   | -----             ||`,
`                     \\      |  \\      |  \\                ||`,
`                      )     |   )     |   )     a(i, j, k)||`,
`                     /      |  /      |  /                ||`,
`                    -----   | -----   | -----             ||`,
`                    k = 0   \\ i = 0   \\ j = 0             //`,
`   `,
`SEE ALSO:  student[changevar]`,
`   `,
`AUTHOR: Vincent Broman, Naval Command Control and Ocean Surveillance Center`
):

#save `reorder.m`;
#quit
