--- /dev/null
+## Copyright (C) 2002 Etienne Grossmann <etienne@egdn.net>
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 3 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, see <http://www.gnu.org/licenses/>.
+
+## c = cdiff (func,wrt,N,dfunc,stack,dx) - Code for num. differentiation
+## = "function df = dfunc (var1,..,dvar,..,varN) .. endfunction
+##
+## Returns a string of octave code that defines a function 'dfunc' that
+## returns the derivative of 'func' with respect to it's 'wrt'th
+## argument.
+##
+## The derivatives are obtained by symmetric finite difference.
+##
+## dfunc()'s return value is in the same format as that of ndiff()
+##
+## func : string : name of the function to differentiate
+##
+## wrt : int : position, in argument list, of the differentiation
+## variable. Default:1
+##
+## N : int : total number of arguments taken by 'func'.
+## If N=inf, dfunc will take variable argument list.
+## Default:wrt
+##
+## dfunc : string : Name of the octave function that returns the
+## derivatives. Default:['d',func]
+##
+## stack : string : Indicates whether 'func' accepts vertically
+## (stack="rstack") or horizontally (stack="cstack")
+## arguments. Any other string indicates that 'func'
+## does not allow stacking. Default:''
+##
+## dx : real : Step used in the symmetric difference scheme.
+## Default:10*sqrt(eps)
+##
+## See also : ndiff, eval, todisk
+
+function c = cdiff (func,wrt,nargs,dfunc,stack,dx)
+
+if nargin<2,
+ wrt = 1 ;
+end
+if nargin<3,
+ nargs = wrt ;
+end
+if nargin<4 || strcmp(dfunc,""),
+ dfunc = ["d",func] ;
+ if exist(dfunc)>=2,
+ printf(["cdiff : Warning : name of derivative not specified\n",\
+ " and canonic name '%s' is already taken\n"],\
+ dfunc);
+ ## keyboard
+ end
+end
+if nargin<5, stack = "" ; end
+if nargin<6, dx = 10*sqrt(eps) ; end
+
+## verbose = 0 ;
+## build argstr = "var1,..,dvar,...var_nargs"
+if isfinite (nargs)
+ argstr = sprintf("var%i,",1:nargs);
+else
+ argstr = [sprintf("var%i,",1:wrt),"...,"];
+end
+
+argstr = strrep(argstr,sprintf("var%i",wrt),"dvar") ;
+argstr = argstr(1:length(argstr)-1) ;
+
+if strcmp("cstack",stack) , # Horizontal stacking ################
+
+ calstr = "reshape (kron(ones(1,2*ps), dvar(:))+[-dx*eye(ps),dx*eye(ps)], sz.*[1,2*ps])";
+ calstr = strrep(argstr,"dvar",calstr) ;
+ calstr = sprintf("%s(%s)",func,calstr) ;
+
+ calstr = sprintf(strcat(" res = %s;\n",
+ " pr = prod (size(res)) / (2*ps);\n",
+ " res = reshape (res,pr,2*ps);\n",
+ " df = (res(:,ps+1:2*ps)-res(:,1:ps)) / (2*dx);\n"),
+ calstr) ;
+
+
+elseif strcmp("rstack",stack), # Vertical stacking ##################
+
+ calstr = "kron(ones(2*ps,1),dvar)+dx*[-dv;dv]" ;
+ calstr = strrep(argstr,"dvar",calstr) ;
+ calstr = sprintf("%s(%s)",func,calstr) ;
+
+ calstr = sprintf(strcat(" dv = kron (eye(sz(2)), eye(sz(1))(:));\n",\
+ " res = %s;\n",\
+ " sr = size(res)./[2*ps,1];\n",\
+ " pr = prod (sr);\n",\
+ " df = (res(sr(1)*ps+1:2*sr(1)*ps,:)-res(1:sr(1)*ps,:))/(2*dx);\n",\
+ " scramble = reshape (1:pr,sr(2),sr(1))';\n",\
+ " df = reshape (df',pr,ps)(scramble(:),:);\n"),\
+ calstr) ;
+ ## sayif(verbose,"cdiff : calstr='%s'\n",calstr) ;
+else # No stacking ########################
+ calstr = sprintf("%s (%s)",func,argstr) ;
+ ## "func(var1,dvar%sdv(:,%d:%d),...,varN),"
+ ## calstr = strrep(calstr,"dvar","dvar%sdv(:,(i-1)*sz(2)+1:i*sz(2))")(:)';
+
+ calstr = strrep(calstr,"dvar","dvar%sdv")(:)';
+
+ ## func(..,dvar+dv(:,1:sz(2)),..) - func(..)
+ calstr = strcat(calstr,"-",calstr) ; ## strcat(calstr,"-",calstr) ;
+ calstr = sprintf(calstr,"+","-") ;
+ tmp = calstr ;
+ ## sayif(verbose,"cdiff : calstr='%s'\n",calstr) ;
+ calstr = sprintf(strcat(" dv = zeros (sz); dv(1) = dx;\n",\
+ " df0 = %s;\n",\
+ " sr = size (df0);\n",\
+ " df = zeros(prod (sr),ps); df(:,1) = df0(:);\n",\
+ " for i = 2:ps,\n",\
+ " dv(i) = dx; dv(i-1) = 0;\n",\
+ " df(:,i) = (%s)(:);\n",\
+ " end;\n",\
+ " df ./= 2*dx;\n"
+ ),
+ calstr, tmp) ;
+
+
+ ## sayif(verbose,"cdiff : calstr='%s'\n",calstr) ;
+
+ ## "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)"
+ ## sayif(verbose,"cdiff : calstr='%s'\n",calstr) ;
+end
+argstr = strrep (argstr, "...", "varargin");
+calstr = strrep (calstr, "...", "varargin{:}");
+
+c = sprintf(strcat("function df = %s (%s)\n",\
+ " ## Numerical differentiation of '%s' wrt to it's %d'th argument\n",\
+ " ## This function has been written by 'cdiff()'\n",\
+ " dx = %e;\n",\
+ " sz = size (dvar);\n",\
+ " ps = prod (sz);\n",\
+ "%s",\
+ "endfunction\n"),\
+ dfunc,argstr,\
+ func,wrt,\
+ dx,\
+ calstr) ;
+