Hi,

the attached patch does some corrections and code-optimization to
optim/inst/leasqr.m.

Except minor changes to the comment blocks, all changes apply to the
code after the actual parameter estimation.

Comments on changes which alter the output:

To get the covariance matrices of the residuals and of the data, a
certain matrix must be divided by the number of residuals "m" or the
number of degrees of freedom "m - n", respectively. The previous code
erroneously divided by "m - n" for the cov.-matr. of residuals "covr",
and nevertheless calculated the cov.-matr. of data "Vy" from the
latter by multiplying with "m / (m - n)" (reduced to "1/(1-n/m)")), so
"Vy" was also not correct. The two covariance matrices are now
calculated correctly, although of the latter only the inverse is
computed due to some code-optimization. Affected output: "covr",
"covp", "corp".

Although I found almost no reference for this, I think it is more
sensible to normalize the standard residuals "stdresid" against the
square root of the variance of the _residuals_, not the sqare root of
the variance of the _data_. This has been changed accordingly. The
former normalization was also wrong because it used the wrongly
calculated "Vy" (see above). Affected output: "stdresid"

all changes:

- corrected calculation of covariance matrix of residuals and
  covariance matrix of data, thereby correcting covariance matrix of
  parameters and correlation matrix of parameters

- simplified calculation of covariance matrix of parameters

- standard residuals now normalized against square root of variance of
  residuals, not of data

- some repetitive computation of the same data avoided in calculation
  of covariance matrix of residuals and later, one repetitive
  multiplication of a matrix with a scalar avoided

- removed abs() on non-negative data in line 376

- changed hint to article of Delforge to apply to the currently
  existing variables

- helptext: added comment on bounds

Except code-optimization, the above numeric changes can be
equivalently achieved simply with:

--- leasqr.m    2009-12-16 13:13:57.000000000 +0100
+++ tp_leasqr.m 2009-12-16 13:23:09.000000000 +0100
@@ -375,7 +375,7 @@
     Qinv=diag(wt.*wt);
   end
   resid=y-f;                                    %un-weighted residuals
-  covr=resid'*Qinv*resid*Q/(m-n);                 %covariance of residuals
+  covr=resid'*Qinv*resid*Q/m;                 %covariance of residuals
   Vy=1/(1-n/m)*covr;  % Eq. 7-13-22, Bard         %covariance of the data 
 
   jtgjinv=inv(jac'*Qinv*jac);                  %argument of inv may be
@@ -387,11 +387,11 @@
 
   if (exist('sparse'))
     covr=spdiags(covr,0);
-    stdresid=resid./sqrt(spdiags(Vy,0));
+    stdresid=resid./sqrt(covr);
   else
     covr=diag(covr);                 % convert returned values to
                                % compact storage
-    stdresid=resid./sqrt(diag(Vy));  % compute then convert for compact storage
+    stdresid=resid./sqrt(covr);  % compute then convert for compact storage
   end
   Z=((m-n)*jac'*Qinv*jac)/(n*resid'*Qinv*resid);

You could compare this with the full patch to test whether the same
results are returned (they are, up to 12 digits for "covp" in my
test).

Regards, Olaf
Index: leasqr.m
===================================================================
--- leasqr.m	(revision 6652)
+++ leasqr.m	(working copy)
@@ -74,6 +74,9 @@
   %%   for each parameter. Default: [-Inf, Inf] in each row. If this
   %%   field is used with an existing user-side function for 'dFdp'
   %%   (see above) the functions interface might have to be changed.
+  %%   _Warning_: If bounds are set, returned guesses of corp, covp, and
+  %%   Z are generally invalid, even if final parameters are not at the
+  %%   bounds.
   %%
   %%          OUTPUT VARIABLES
   %% f = column vector of values computed: f = F(x,p).
@@ -89,6 +92,10 @@
   %%
   %% All Zero guesses not acceptable
 
+  %% The following two blocks of comments are chiefly from the original
+  %% version for Matlab. For later changes the logs of the Octave Forge
+  %% svn repository should also be consulted.
+
   %% A modified version of Levenberg-Marquardt
   %% Non-Linear Regression program previously submitted by R.Schrager.
   %% This version corrects an error in that version and also provides
@@ -120,6 +127,7 @@
   %%       5) revise estimates of corp, stdev
   %% Modified by Ray Muzic 11-Oct-1992
   %%	1) revise estimate of Vy.  remove chi2, add Z as return values
+  %%       (later remark: the current code contains no variable Vy)
   %% Modified by Ray Muzic 7-Jan-1994
   %%       1) Replace ones(x) with a construct that is compatible with versions
   %%          newer and older than v 4.1.
@@ -367,37 +375,42 @@
   %% diag(1/wt.^2).  
   %% cov matrix of data est. from Bard Eq. 7-5-13, and Row 1 Table 5.1 
 
+  tp = wt.^2;
   if (exist('sparse'))  % save memory
-    Q=sparse(1:m,1:m,1./wt.^2);
-    Qinv=sparse(1:m,1:m,wt.^2);
+    Q = sparse (1:m, 1:m, 1 ./ tp);
+    Qinv = sparse (1:m, 1:m, tp);
   else
-    Q=diag((0*wt+1)./(wt.^2));
-    Qinv=diag(wt.*wt);
+    Q = diag (ones (m, 1) ./ tp);
+    Qinv = diag (tp);
   end
   resid=y-f;                                    %un-weighted residuals
-  covr=resid'*Qinv*resid*Q/(m-n);                 %covariance of residuals
-  Vy=1/(1-n/m)*covr;  % Eq. 7-13-22, Bard         %covariance of the data 
+  tp = resid.' * Qinv * resid;
+  covr = (tp / m) * Q;    %covariance of residuals
 
-  jtgjinv=inv(jac'*Qinv*jac);			%argument of inv may be
-				%singular
-  covp=jtgjinv*jac'*Qinv*Vy*Qinv*jac*jtgjinv; % Eq. 7-5-13, Bard %cov of
+  Qinv = ((m - n) / tp) * Qinv; % Qinv now contains the inverse of the
+				% guessed covariance matrix of the data.
+				% No new variable was used, but later
+				% calculations and comments using Qinv
+				% remain valid with the new Qinv.
+  %% argument of inv may be singular
+  covp = inv (jac.' * Qinv * jac); % simplified Eq. 7-5-13, Bard %cov of
 				% parm est
-  d=sqrt(abs(diag(covp)));
+  d=sqrt(diag(covp));
   corp=covp./(d*d');
 
   if (exist('sparse'))
     covr=spdiags(covr,0);
-    stdresid=resid./sqrt(spdiags(Vy,0));
+    stdresid=resid ./ sqrt (covr);
   else
     covr=diag(covr);                 % convert returned values to
 				% compact storage
-    stdresid=resid./sqrt(diag(Vy));  % compute then convert for compact storage
+    stdresid=resid ./ sqrt (covr);
   end
   Z=((m-n)*jac'*Qinv*jac)/(n*resid'*Qinv*resid);
 
 %%% alt. est. of cov. mat. of parm.:(Delforge, Circulation, 82:1494-1504, 1990
   %%disp('Alternate estimate of cov. of param. est.')
-  %%acovp=resid'*Qinv*resid/(m-n)*jtgjinv
+  %%acovp=resid'*Qinv*resid/(m-n)*inv(jac'*Qinv*jac);
 
   %%Calculate R^2 (Ref Draper & Smith p.46)
   %%
------------------------------------------------------------------------------
This SF.Net email is sponsored by the Verizon Developer Community
Take advantage of Verizon's best-in-class app development support
A streamlined, 14 day to market process makes app distribution fast and easy
Join now and get one step closer to millions of Verizon customers
http://p.sf.net/sfu/verizon-dev2dev 
_______________________________________________
Octave-dev mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/octave-dev

Reply via email to