[Index for tmp_for_tar/misc] [Return to Master Index]

ndiff

(tmp_for_tar/misc/ndiff.m)


Function Synopsis

df = ndiff( func, ... )

Help text

       df = ndiff( func [, options], argument(s) )

 Numerical differentiation of 'func', by symmetric (default) or
 assymetric difference scheme.

 By default, differentiation is with respect to the first argument
 found after the eventual options.

 If this variable (call it 'x') is of size RxC, and the output 'y' of
 'func' is SxD, then 'df' will be (S*D)x(R*C).

                  df(i,j) = dy(i)/dx(j)

 For quicker differentiation, see cdiff and compare_speed_ncdiff. 

 OPTIONS :
 ---------
 "dx" , small_value : Value of the small perturbation.
                                                      Default = 1e-6 

 "wrt", variable    : With Respect To : Name or number, in argument
                      list, of the differentiation variable. "varnum"
                      can be used instead of "wrt". 
                      Octave>=2.1.XX is needed for specifying a
                      variable by its name. 
                                                          Default = 1 

 "rstack"  : allow stacking of arguments in rows. This means that

             [ func(x1) ; func(x2) ] == func( [ x1 ; x2 ] )

             (for a one-arg function). When this option is passed,
             'func' is called once only, so this may provide some
             speed-up. 

 "cstack"  : allow stacking of arguments in columns. This means that

             [ func(x1) , func(x2) ] == func( [ x1 , x2 ] )

             (for a one-arg function). When this option is passed,
             'func' is called once only. 

 "nostack" : is ignored.

 "assym"   : Perform calculation using an assymetric finite difference
             scheme rather than the symmetric scheme. With this
             option, 'func' is evaluated at R*C+1 points rather than
             the 2*R*C that are necessary for the symmetric scheme.
             Beware that error is then linear in the value of 'dx'
             rather than quadratic.

 "args"    : When 'ndiff' finds the "args" option, it stops reading
             options. All remaining arguments are passed to 'func'.
             Without "args", 'ndiff' stops after reading the first
             argument that it does not understand. This arg and the
             following are passed to 'func'.

 EXAMPLES :
 ----------
 function y = foo(x,y,z) ... end

 df = ndiff("foo","wrt","y0",x0,y0,z0)

 ## Returns an approximation of the differential of 'foo' wrt. 2nd
 ## variable, at (x0,y0,z0). 

 df = ndiff("foo",x0,y0,z0)

 ## Returns an approximation of the differential of 'foo' wrt. 'x', at
 ## (x0,y0,z0). 

 Last modified: April 2001



Listing of function file tmp_for_tar/misc/ndiff.m

##       df = ndiff( func [, options], argument(s) )
##
## Numerical differentiation of 'func', by symmetric (default) or
## assymetric difference scheme.
##
## By default, differentiation is with respect to the first argument
## found after the eventual options.
##
## If this variable (call it 'x') is of size RxC, and the output 'y' of
## 'func' is SxD, then 'df' will be (S*D)x(R*C).
##
##                  df(i,j) = dy(i)/dx(j)
##
## For quicker differentiation, see cdiff and compare_speed_ncdiff. 
## 
## OPTIONS :
## ---------
## "dx" , small_value : Value of the small perturbation.
##                                                      Default = 1e-6 
##
## "wrt", variable    : With Respect To : Name or number, in argument
##                      list, of the differentiation variable. "varnum"
##                      can be used instead of "wrt". 
##                      Octave>=2.1.XX is needed for specifying a
##                      variable by its name. 
##                                                          Default = 1 
##
## "rstack"  : allow stacking of arguments in rows. This means that
##
##             [ func(x1) ; func(x2) ] == func( [ x1 ; x2 ] )
##
##             (for a one-arg function). When this option is passed,
##             'func' is called once only, so this may provide some
##             speed-up. 
##
## "cstack"  : allow stacking of arguments in columns. This means that
##
##             [ func(x1) , func(x2) ] == func( [ x1 , x2 ] )
##
##             (for a one-arg function). When this option is passed,
##             'func' is called once only. 
##             
## "nostack" : is ignored.
## 
## "assym"   : Perform calculation using an assymetric finite difference
##             scheme rather than the symmetric scheme. With this
##             option, 'func' is evaluated at R*C+1 points rather than
##             the 2*R*C that are necessary for the symmetric scheme.
##             Beware that error is then linear in the value of 'dx'
##             rather than quadratic.
## 
## "args"    : When 'ndiff' finds the "args" option, it stops reading
##             options. All remaining arguments are passed to 'func'.
##             Without "args", 'ndiff' stops after reading the first
##             argument that it does not understand. This arg and the
##             following are passed to 'func'.
## 
## EXAMPLES :
## ----------
## function y = foo(x,y,z) ... end
## 
## df = ndiff("foo","wrt","y0",x0,y0,z0)
##
## ## Returns an approximation of the differential of 'foo' wrt. 2nd
## ## variable, at (x0,y0,z0). 
##
## df = ndiff("foo",x0,y0,z0)
##
## ## Returns an approximation of the differential of 'foo' wrt. 'x', at
## ## (x0,y0,z0). 
 

## Author:        Etienne Grossmann  <etienne@isr.ist.utl.pt>
## Last modified: April 2001

function df = ndiff( func, ... )


verbose = 0;
prudent = 1 ;
assym = 0;
rstack = cstack = 0 ;

dx = 1e-6 ;

filename = "ndiff" ;
opt0 = " verbose assym rstack nostack cstack " ;
opt1 = " dx wrt varnum " ;
nargin -= 1 ;
nargin_orig = nargin ;
opt_quiet = 1 ;

read_options ;

nvars = nargin + 1 ;		# Number of args to func

vskip = nargin_orig - nvars ;	# 1st arg to func on arg list

if isstr(last_option_name) && strcmp(last_option_name,"args"),
  nvars-- ;
  vskip++ ;
end
				# Default varnum
if exist("varnum","var")!=1, 
  if exist("wrt","var")==1, varnum = wrt ;
  else                varnum = 1 ;
  end
end

if isstr(varnum),		# find variable's number
  varname = varnum ;
  ## printf("Looking for argument called '%s'!\n",varnum) ;
  for cnt = 1:vskip+nvars+1,
    aname =  sprintf("%s",argn(cnt,:));
    ## printf("arg %d is called '%s'\n",cnt,aname);
    if strcmp(aname,varname), 
      ## printf("found!\n") ;
      if isstr(varnum),
	varnum = cnt-vskip-1 ;
      else
	printf(["ndiff wrt '%s' Whoa!! multiple args w/ that name\n",\
		"      will use arg number %d\n"], varname,varnum) ;
	break 
      end
    end
  end
end


sayif(verbose,strcat("ndiff : differentiating          func='%s'\n",\
		     "        number of variables is  nvars= %d\n",\
		     "        diff is wrt var number varnum= %d\n",\
		     "        assymetric difference?  assym= %d\n",\
		     "        step size                  dx= %g\n"),
      func,nvars,varnum,assym,dx);

ckcnt = 1;			# Check
for i= [ !isstr(varnum), varnum>0, !rstack || !cstack ],
  if !i,
    printf("ndiff : check %d fails\n",ckcnt) ;
    keyboard ;
  end
  ckcnt++ ;
end


				# Second loop thru args
va_start() ;			# skip options
cnt = 1 ;
while cnt++ <= vskip, va_arg(); end

				# read the other args
varstr = sprintf("var%d=va_arg();",1:nvars) ;
varstr = strrep(varstr,sprintf("var%d",varnum),"dvar") ;
sayif(verbose,"ndiff : reading args as ---\n%s\n--\n",varstr) ;
eval(varstr) ;
dvar0 = dvar ;

				# Function call string
## ",var1,var2,...,varN"
funcstr = sprintf(",var%d",1:nvars) ;
sayif(verbose,"ndiff : funcstr=%s\n",funcstr) ;

## ",var1,dvar,...,varN"
funcstr = strrep(funcstr,sprintf("var%d",varnum),"dvar") ;
sayif(verbose,"ndiff : funcstr=%s\n",funcstr) ;

## "func(var1,dvar,...,varN);"
funcstr = sprintf("%s(%s);",func,funcstr(2:length(funcstr)));
sayif(verbose,"ndiff : funcstr=%s\n",funcstr) ;

sz = size(dvar0) ;
nv = prod(sz) ;			# Number of scalars in dvar

				# Points of evaluation
## if rstack, dvar = dvar' ; end
  
if assym,  
  ## keyboard
  dvar = [zeros(nv,1), dx*eye(nv) ] + kron(dvar(:),ones(1,nv+1));
  np = nv+1 ;
else         
  dvar = [-dx*eye(nv), dx*eye(nv) ] + kron(dvar(:),ones(1,2*nv));
  np = 2*nv ;
end

				# Evaluate function

				# rsz will be size of one point's image
if cstack, 
  dvar = reshape(dvar,sz(1),sz(2)*np);
  result = eval(funcstr);	# rsz(1) x (rsz(2)*np)
  rsz = [size(result) ./ [1,np]] ;
  ## keyboard
  ixy = [ones(1,np)              ;\ # start row
	 rsz(1)*ones(1,np)       ;\ # end row
	 1:rsz(2):np*rsz(2)      ;\ # start col
	 rsz(2):rsz(2):np*rsz(2) ]; # end col

elseif rstack,
  scramble = reshape(1:nv,sz(1),sz(2))' ;
  dvar = reshape(dvar(scramble,:),sz(2),sz(1)*np)';
  result = eval(funcstr);	# (rsz(1)*np) x (rsz(2))
  rsz = [size(result) ./ [np,1]] ;
  ## keyboard

  ixy = [ 1:rsz(1):np*rsz(1)     ;\ # start row
	 rsz(1):rsz(1):np*rsz(1) ;\ # end row
	 ones(1,np)              ;\ # start col
	 rsz(2)*ones(1,np)       ]; # end col


else
				# Must do 'np' function calls. Massage
				# funcstr to do a single eval().

  ## "func(var1,dvar,...,varN),"
  funcstr = strrep(funcstr,";",",") ;
  ## sayif(verbose,"ndiff : funcstr='%s'\n",funcstr) ;

  ## "func(var1,reshape(dvar(%d:%d,%d),SZ1,SZ2),...,varN),"
  funcstr = strrep(funcstr,"dvar",                                    \
		   ["reshape(dvar(%d:%d,%d)",sprintf(",%d,%d)",sz)]);
  ## sayif(verbose,"ndiff : funcstr='%s'\n",funcstr) ;

  ## "func(var1,reshape(dvar(1:NV,1),SZ1,SZ2),...,varN)," , 
  ## "func(var1,reshape(dvar(1:NV,2),SZ1,SZ2),...,varN)," , ...
  ## "func(var1,reshape(dvar(1:NV,NP),SZ1,SZ2),...,varN)"
  funcstr = sprintf(funcstr,[ones(1,np);nv*ones(1,np);1:np]) ;
  ## sayif(verbose,"ndiff : funcstr='%s'\n",funcstr) ;
  funcstr = ["[",funcstr(1:length(funcstr)-1),"];"] ;
  sayif(verbose,"ndiff : funcstr='%s'\n",funcstr) ;
  ## keyboard
  result = eval(funcstr) ;
  rsz = [size(result) ./ [1,np]] ;
  ## keyboard
  ixy = [ones(1,np)              ;\ # start row
	 rsz(1)*ones(1,np)       ;\ # end row
	 1:rsz(2):np*rsz(2)      ;\ # start col
	 rsz(2):rsz(2):np*rsz(2) ]; # end col

end

				# Compute derivatives
if assym,
  ipt = [ones(1,nv) ; 2:nv+1    ] ;
  dx = 0.5*dx ;
else 
  ipt = [      1:nv ; nv+1:2*nv ] ;
end
## keyboard
df = zeros(prod(rsz),nv) ;
for i = 1:nv,
  df(:,i) = [result(ixy(1,ipt(2,i)):ixy(2,ipt(2,i)),   \
		    ixy(3,ipt(2,i)):ixy(4,ipt(2,i))) - \
	     result(ixy(1,ipt(1,i)):ixy(2,ipt(1,i)),   \
		    ixy(3,ipt(1,i)):ixy(4,ipt(1,i))) ](:) ;
end
df = df ./(2*dx) ;

Produced by oct2html on Sat Apr 28 21:14:54 2001
Cross-Directory links are: ON