On Tue, Aug 04, 2009 at 09:57:28PM +0200, Søren Hauberg wrote:
> tir, 04 08 2009 kl. 13:02 +0200, skrev Olaf Till:
> > A lot of
> > cosmetic changes have been made to make leasqr.m better editable under
> > emacs, so almost each line is changed and its not much use making
> > diffs :-(.
>
> Then could you please start out by doing a diff where you do not change
> coding style. Once we have the content in place, you can always change
> the coding style.
Ok, attached is an SVN diff inside main/optim/inst/.
Olaf
Index: leasqr.m
===================================================================
--- leasqr.m (revision 6076)
+++ leasqr.m (working copy)
@@ -46,17 +46,28 @@
% stol = scalar tolerance on fractional improvement in scalar sum of
% squares = sum((wt.*(y-f))^2); default stol = .0001;
% niter = scalar maximum number of iterations; default = 20;
-% options = matrix of n rows (same number of rows as pin) containing
-% column 1: desired fractional precision in parameter estimates.
-% Iterations are terminated if change in parameter vector (chg) on two
-% consecutive iterations is less than their corresponding elements
-% in options(:,1). [ie. all(abs(chg*current parm est) < options(:,1))
-% on two consecutive iterations.], default = zeros().
-% column 2: maximum fractional step change in parameter vector.
-% Fractional change in elements of parameter vector is constrained to be
-% at most options(:,2) between sucessive iterations.
-% [ie. abs(chg(i))=abs(min([chg(i) options(i,2)*current param estimate])).],
-% default = Inf*ones().
+% options = structure, currently recognized fields are 'fract_prec',
+% 'max_fract_change', and 'bounds'. For backwards compatibility,
+% 'options' can also be a matrix whose first and second column
+% contains the values of 'fract_prec' and 'max_fract_change',
+% respectively.
+% Field 'options.fract_prec': column vector (same length as 'pin') of
+% desired fractional precisions in parameter estimates. Iterations
+% are terminated if change in parameter vector (chg) on two
+% consecutive iterations is less than their corresponding elements in
+% 'options.fract_prec'. [ie. all(abs(chg*current parm est) <
+% options.fract_prec) on two consecutive iterations.], default =
+% zeros().
+% Field 'options.max_fract_change': column vector (same length as
+% 'pin) of maximum fractional step changes in parameter vector.
+% Fractional change in elements of parameter vector is constrained to
+% be at most 'options.max_fract_change' between sucessive iterations.
+% [ie. abs(chg(i))=abs(min([chg(i)
+% options.max_fract_change(i)*current param estimate])).], default =
+% Inf*ones().
+% Field 'options.bounds': two-column-matrix, one row for each
+% parameter in 'pin'. Each row contains a minimal and maximal value
+% for each parameter. Default: [-Inf, Inf] in each row.
%
% OUTPUT VARIABLES
% f = column vector of values computed: f = F(x,p).
@@ -122,6 +133,7 @@
% MATLAB version >= 4.0) in computation of covp, corp, stdresid.
% Modified by Francesco Potortì
% for use in Octave
+% Added bounds feature to this file and to dfdp.m, Olaf Till 4-Aug-2009
%
% References:
% Bard, Nonlinear Parameter Estimation, Academic Press, 1974.
@@ -158,27 +170,64 @@
y=y(:); wt=wt(:); pin=pin(:); dp=dp(:); %change all vectors to columns
% check data vectors- same length?
-m=length(y); n=length(pin); p=pin;[m1,m2]=size(x);
+m=length(y); n=length(pin); [m1,m2]=size(x);
if m1~=m ,error('input(x)/output(y) data must have same number of rows ') ,end;
-if (nargin <= 9),
- options=[zeros(n,1), Inf*ones(n,1)];
- nor = n; noc = 2;
-else
- [nor, noc]=size(options);
- if (nor ~= n),
- error('options and parameter matrices must have same number of rows'),
- end;
- if (noc ~= 2),
- options=[options(:,1), Inf*ones(nor,1)];
- end;
-end;
-pprec=options(:,1);
-maxstep=options(:,2);
-%
+ %% processing of 'options'
+ pprec = zeros (n, 1);
+ maxstep = Inf * ones (n, 1);
+ bounds = cat (2, -Inf * ones (n, 1), Inf * ones (n, 1));
+ if (nargin > 9)
+ if (ismatrix (options)) % backwards compatibility
+ tp = options;
+ options = struct ("fract_prec", tp(:, 1));
+ if (columns (tp) > 1)
+ options.max_fract_change = tp(:, 2);
+ endif
+ endif
+ if (isfield (options, "fract_prec"))
+ pprec = options.fract_prec;
+ if (rows (pprec) != n || columns (pprec) != 1)
+ error ("fractional precisions: wrong dimensions");
+ endif
+ endif
+ if (isfield (options, "max_fract_change"))
+ maxstep = options.max_fract_change;
+ if (rows (maxstep) != n || columns (maxstep) != 1)
+ error ("maximum fractional step changes: wrong dimensions");
+ endif
+ endif
+ if (isfield (options, "bounds"))
+ bounds = options.bounds;
+ if (rows (bounds) != n || columns (bounds) != 2)
+ error ("bounds: wrong dimensions");
+ endif
+ idx = bounds(:, 1) > bounds(:, 2);
+ tp = bounds(idx, 2);
+ bounds(idx, 2) = bounds(idx, 1);
+ bounds(idx, 1) = tp;
+ if (any (idx = bounds(:, 1) == bounds(:, 2)))
+ warning ("lower and upper bounds identical for some parameters, setting the respective elements of 'dp' to zero");
+ dp(idx) = 0;
+ endif
+ if (any (idx = pin < bounds(:, 1)))
+ warning ("some initial parameters set to lower bound");
+ pin(idx) = bounds(idx, 1);
+ endif
+ if (any (idx = pin > bounds(:, 2)))
+ warning ("some initial parameters set to upper bound");
+ pin(idx) = bounds(idx, 2);
+ endif
+ endif
+ endif
+ if (all (dp == 0))
+ error ("no free parameters");
+ endif
+
% set up for iterations
%
+p = pin;
f=feval(F,x,p); fbest=f; pbest=p;
r=wt.*(y-f);
ss=r'*r;
@@ -193,7 +242,7 @@
%
for iter=1:niter,
pprev=pbest;
- prt=feval(dFdp,x,fbest,pprev,dp,F);
+ prt=feval(dFdp,x,fbest,pprev,dp,F,bounds);
r=wt.*(y-fbest);
sprev=sbest;
sgoal=(1-stol)*sprev;
@@ -234,6 +283,20 @@
% ss=scalar sum of squares=sum((wt.*(y-f))^2).
if (any(abs(chg) > 0.1*aprec)),%--- % only worth evaluating function if
p=chg+pprev; % there is some non-miniscule change
+ %% apply bounds; preserving the direction of the attempted step
+ %% might lead to fixing _all_ parameters at their current value,
+ %% so decided not to do that and to simply reset parameters to
+ %% bounds
+ lidx = p < bounds(:, 1);
+ p(lidx) = bounds(lidx, 1);
+ uidx = p > bounds(:, 2);
+ p(uidx) = bounds(uidx, 2);
+ if (verbose && any (idx = lidx | uidx))
+ printf ("bounds apply for parameters number %s %i\n", \
+ sprintf ("%i, ", find (idx)(1:end - 1)), \
+ find (idx)(end));
+ endif
+ %%
f=feval(F,x,p);
r=wt.*(y-f);
ss=r'*r;
@@ -280,7 +343,7 @@
% CALC VARIANCE COV MATRIX AND CORRELATION MATRIX OF PARAMETERS
% re-evaluate the Jacobian at optimal values
-jac=feval(dFdp,x,f,p,dp,F);
+jac=feval(dFdp,x,f,p,dp,F,bounds);
msk = dp ~= 0;
n = sum(msk); % reduce n to equal number of estimated parameters
jac = jac(:, msk); % use only fitted parameters
Index: dfdp.m
===================================================================
--- dfdp.m (revision 6076)
+++ dfdp.m (working copy)
@@ -15,7 +15,7 @@
% You should have received a copy of the GNU General Public License
% along with this program; If not, see <http://www.gnu.org/licenses/>.
-function prt=dfdp(x,f,p,dp,func)
+function prt=dfdp(x,f,p,dp,func,bounds)
% numerical partial derivatives (Jacobian) df/dp for use with leasqr
% --------INPUT VARIABLES---------
% x=vec or matrix of indep var(used as arg to func) x=[x0 x1 ....]
@@ -27,26 +27,55 @@
% dp(j)=0 sets corresponding partials to zero; i.e. holds p(j) fixed
% func=string naming the function (.m) file
% e.g. to calc Jacobian for function expsum prt=dfdp(x,f,p,dp,'expsum')
+% bounds=two-column-matrix of lower and upper bounds for parameters
%----------OUTPUT VARIABLES-------
% prt= Jacobian Matrix prt(i,j)=df(i)/dp(j)
%================================
m=size(x,1); if (m==1), m=size(x,2); end %# PAK: in case #cols > #rows
n=length(p); %dimensions
-ps=p; prt=zeros(m,n);del=zeros(n,1); % initialise Jacobian to Zero
-for j=1:n
- del(j)=dp(j) .*p(j); %cal delx=fract(dp)*param value(p)
- if p(j)==0
- del(j)=dp(j); %if param=0 delx=fraction
- end
- p(j)=ps(j) + del(j);
- if del(j)~=0, f1=feval(func,x,p);
- if dp(j) < 0, prt(:,j)=(f1-f)./del(j);
- else
- p(j)=ps(j)- del(j);
- prt(:,j)=(f1-feval(func,x,p))./(2 .*del(j));
- end
- end
- p(j)=ps(j); %restore p(j)
-end
-return
+prt=zeros(m,n);del=zeros(n,1); % initialise Jacobian to Zero
+del = dp .* p; %cal delx=fract(dp)*param value(p)
+idx = p == 0;
+del(idx) = dp(idx); %if param=0 delx=fraction
+idx = dp > 0;
+del(idx) = abs (del(idx)); % not for one-sided intervals, changed
+ % direction of intervals could change
+ % behavior of optimization without bounds
+min_del = min (abs (del), bounds(:, 2) - bounds(:, 1));
+ for j=1:n
+ ps = p;
+ if (dp(j)~=0)
+ if (dp(j) < 0)
+ ps(j) = p(j) + del(j);
+ if (ps(j) < bounds(j, 1) || ps(j) > bounds(j, 2))
+ t_del1 = max (bounds(j, 1) - p(j), - abs (del(j))); %
+ %non-positive
+ t_del2 = min (bounds(j, 2) - p(j), abs (del(j))); %
+ %non-negative
+ if (- t_del1 > t_del2)
+ del(j) = t_del1;
+ else
+ del(j) = t_del2;
+ endif
+ ps(j) = p(j) + del(j);
+ endif
+ prt(:, j) = (feval (func, x, ps) - f) / del(j);
+ else
+ if (p(j) - del(j) < bounds(j, 1))
+ tp = bounds(j, 1);
+ ps(j) = tp + min_del(j);
+ elseif (p(j) + del(j) > bounds(j, 2))
+ ps(j) = bounds(j, 2);
+ tp = ps(j) - min_del(j);
+ else
+ ps(j) = p(j) + del(j);
+ tp = p(j) - del(j);
+ min_del(j) = 2 * del(j);
+ endif
+ f1 = feval (func, x, ps);
+ ps(j) = tp;
+ prt(:, j) = (f1 - feval (func, x, ps)) / (min_del(j));
+ endif
+ endif
+ endfor
------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now. http://p.sf.net/sfu/bobj-july
_______________________________________________
Octave-dev mailing list
Octave-dev@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/octave-dev