changeset 8720:f80846665d3b octave-forge

Use Fotios' complex step derivative approximation. And a few small fixes.
author i7tiol
date Tue, 01 Nov 2011 13:17:41 +0000
parents b87070d83277
children c159aea4f7df
files main/optim/DESCRIPTION main/optim/PKG_ADD main/optim/inst/nonlin_residmin.m main/optim/inst/private/__collect_constraints__.m main/optim/inst/private/__nonlin_residmin__.m main/optim/inst/private/__residmin_stat__.m main/optim/inst/residmin_stat.m
diffstat 7 files changed, 87 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/main/optim/DESCRIPTION	Tue Nov 01 10:45:54 2011 +0000
+++ b/main/optim/DESCRIPTION	Tue Nov 01 13:17:41 2011 +0000
@@ -1,6 +1,6 @@
 Name: Optim
 Version: 1.0.17
-Date: 2011-05-20
+Date: 2011-11-01
 Author: Various Authors
 Maintainer: The Octave Community
 Title: Optimzation.
--- a/main/optim/PKG_ADD	Tue Nov 01 10:45:54 2011 +0000
+++ b/main/optim/PKG_ADD	Tue Nov 01 13:17:41 2011 +0000
@@ -1,6 +1,6 @@
 if (compare_versions (version (), "3.3.55", ">="))
   ## optimset mechanism was fixed for option names with underscores
   ## sometime in 3.3.54+, if I remember right
-  __all_opts__ ("__nonlin_residmin__");
-  __all_opts__ ("__residmin_stat__");
+  __all_opts__ ("nonlin_residmin");
+  __all_opts__ ("residmin_stat");
 endif
--- a/main/optim/inst/nonlin_residmin.m	Tue Nov 01 10:45:54 2011 +0000
+++ b/main/optim/inst/nonlin_residmin.m	Tue Nov 01 13:17:41 2011 +0000
@@ -91,6 +91,18 @@
 ## intervals should be used by jacobian functions performing finite
 ## differencing. Default: @code{false (size (parameters))}.
 ##
+## @code{complex_step_derivative}, @code{complex_step_derivative_inequc},
+## @code{complex_step_derivative_equc}: logical scalars, default: false.
+## Estimate Jacobian of model function, general inequality constraints,
+## and general equality constraints, respectively, with complex step
+## derivative approximation. Use only if you know that your model
+## function, function of general inequality constraints, or function of
+## general equality constraints, respectively, is suitable for this. No
+## user function for the respective Jacobian must be specified.
+##
+## @code{cstep}: scalar step size for complex step derivative
+## approximation. Default: 1e-20.
+##
 ## @code{fixed}: logical column vector indicating which parameters
 ## should not be optimized, but kept to their inital value. Fixing is
 ## done independently of the backend, but the backend may choose to fix
--- a/main/optim/inst/private/__collect_constraints__.m	Tue Nov 01 10:45:54 2011 +0000
+++ b/main/optim/inst/private/__collect_constraints__.m	Tue Nov 01 13:17:41 2011 +0000
@@ -14,7 +14,7 @@
 ## along with this program; If not, see <http://www.gnu.org/licenses/>.
 
 function [mc, vc, f_gencstr, df_gencstr, user_df] = \
-      __collect_constraints__ (cstr)
+      __collect_constraints__ (cstr, do_cstep, context)
 
   mc = vc = f_gencstr = df_gencstr = [];
   user_df = false;
@@ -59,13 +59,21 @@
 	tf_gencstr (f_gencstr, varargin{:});
 
     if (user_df)
+      if (do_cstep)
+	error ("both complex step derivative chosen and user Jacobian function specified for %s", context);
+      endif
       if (ischar (df_gencstr))
 	df_gencstr = str2func (df_gencstr);
       endif
       df_gencstr = @ (p, func, idx, hook) \
 	  df_gencstr (p, idx, hook);
     else
-      df_gencstr = @ (p, func, idx, hook) __dfdp__ (p, func, hook);
+      if (do_cstep)
+	df_gencstr = @ (p, func, idx, hook) jacobs (p, func, hook);
+      else
+	__dfdp__ = @ __dfdp__; # for bug #31484 (Octave <= 3.2.4)
+	df_gencstr = @ (p, func, idx, hook) __dfdp__ (p, func, hook);
+      endif
     endif
   endif
 
--- a/main/optim/inst/private/__nonlin_residmin__.m	Tue Nov 01 10:45:54 2011 +0000
+++ b/main/optim/inst/private/__nonlin_residmin__.m	Tue Nov 01 13:17:41 2011 +0000
@@ -36,6 +36,7 @@
   ## NA here in the frontend
   diffp_default = .001;
   stol_default = .0001;
+  cstep_default = 1e-20;
 
   if (nargin == 1 && ischar (f) && strcmp (f, "defaults"))
     p = optimset ("param_config", [], \
@@ -55,6 +56,10 @@
 		  "fract_prec", [], \
 		  "diffp", [], \
 		  "diff_onesided", [], \
+		  "complex_step_derivative", false, \
+		  "complex_step_derivative_inequc", false, \
+		  "complex_step_derivative_equc", false, \
+		  "cstep", cstep_default, \
 		  "fixed", [], \
 		  "inequc", [], \
 		  "equc", [], \
@@ -107,6 +112,14 @@
   diffp = optimget (settings, "diffp");
   diff_onesided = optimget (settings, "diff_onesided");
   fixed = optimget (settings, "fixed");
+  do_cstep = optimget (settings, "complex_step_derivative", false);
+  cstep = optimget (settings, "cstep", cstep_default);
+  if (do_cstep && ! isempty (dfdp))
+    error ("both 'complex_step_derivative' and 'dfdp' are set");
+  endif
+  do_cstep_inequc = \
+      optimget (settings, "complex_step_derivative_inequc", false);
+  do_cstep_equc = optimget (settings, "complex_step_derivative_equc", false);
 
   any_vector_conf = ! (isempty (lbound) && isempty (ubound) && \
 		       isempty (max_fract_change) && \
@@ -115,9 +128,11 @@
 
   ## collect constraints
   [mc, vc, f_genicstr, df_gencstr, user_df_gencstr] = \
-      __collect_constraints__ (optimget (settings, "inequc"));
+      __collect_constraints__ (optimget (settings, "inequc"), \
+			       do_cstep_inequc, "inequality constraints");
   [emc, evc, f_genecstr, df_genecstr, user_df_genecstr] = \
-      __collect_constraints__ (optimget (settings, "equc"));
+      __collect_constraints__ (optimget (settings, "equc"), \
+			       do_cstep_equc, "equality constraints");
   mc_struct = isstruct (mc);
   emc_struct = isstruct (emc);
 
@@ -440,8 +455,12 @@
 
   ## jacobian of model function
   if (isempty (dfdp))
-    __dfdp__ = @ __dfdp__; # for bug #31484 (Octave <= 3.2.4)
-    dfdp = @ (p, hook) __dfdp__ (p, f, hook);
+    if (do_cstep)
+      dfdp = @ (p, hook) jacobs (p, f, hook);
+    else
+      __dfdp__ = @ __dfdp__; # for bug #31484 (Octave <= 3.2.4)
+      dfdp = @ (p, hook) __dfdp__ (p, f, hook);
+    endif
   endif
   if (dfdp_pstruct)
     if (pnonscalar)
@@ -730,17 +749,18 @@
 	      ({s_diffp, s_diff_onesided, s_orig_lbound, \
 		s_orig_ubound, s_plabels, \
 		cell2fields(num2cell(hook.fixed), pord(nonfixed), \
-			    1, s_orig_fixed)}, \
+			    1, s_orig_fixed), cstep}, \
 	       {"diffp", "diff_onesided", "lbound", "ubound", \
-		"plabels", "fixed"}, \
+		"plabels", "fixed", "h"}, \
 	       2, hook));
   else
     dfdp = @ (p, hook) \
 	dfdp (p, cell2fields \
 	      ({diffp, diff_onesided, orig_lbound, orig_ubound, \
-		plabels, assign(orig_fixed, nonfixed, hook.fixed)}, \
+		plabels, assign(orig_fixed, nonfixed, hook.fixed), \
+		cstep}, \
 	       {"diffp", "diff_onesided", "lbound", "ubound", \
-		"plabels", "fixed"}, \
+		"plabels", "fixed", "h"}, \
 	       2, hook));
   endif
 
@@ -751,18 +771,18 @@
 		    ({s_diffp, s_diff_onesided, s_orig_lbound, \
 		      s_orig_ubound, s_plabels, \
 		      cell2fields(num2cell(hook.fixed), pord(nonfixed), \
-				  1, s_orig_fixed)}, \
+				  1, s_orig_fixed), cstep}, \
 		     {"diffp", "diff_onesided", "lbound", "ubound", \
-		      "plabels", "fixed"}, \
+		      "plabels", "fixed", "h"}, \
 		     2, hook));
   else
     df_gencstr = @ (p, func, idx, hook) \
 	df_gencstr (p, func, idx, cell2fields \
 		    ({diffp, diff_onesided, orig_lbound, \
 		      orig_ubound, plabels, \
-		      assign(orig_fixed, nonfixed, hook.fixed)}, \
+		      assign(orig_fixed, nonfixed, hook.fixed), cstep}, \
 		     {"diffp", "diff_onesided", "lbound", "ubound", \
-		      "plabels", "fixed"}, \
+		      "plabels", "fixed", "h"}, \
 		     2, hook));
   endif
 
@@ -773,18 +793,18 @@
 		     ({s_diffp, s_diff_onesided, s_orig_lbound, \
 		       s_orig_ubound, s_plabels, \
 		       cell2fields(num2cell(hook.fixed), pord(nonfixed), \
-				   1, s_orig_fixed)}, \
+				   1, s_orig_fixed), cstep}, \
 		      {"diffp", "diff_onesided", "lbound", "ubound", \
-		       "plabels", "fixed"}, \
+		       "plabels", "fixed", "h"}, \
 		      2, hook));
   else
     df_genecstr = @ (p, func, idx, hook) \
 	df_genecstr (p, func, idx, cell2fields \
 		     ({diffp, diff_onesided, orig_lbound, \
 		       orig_ubound, plabels, \
-		       assign(orig_fixed, nonfixed, hook.fixed)}, \
+		       assign(orig_fixed, nonfixed, hook.fixed), cstep}, \
 		      {"diffp", "diff_onesided", "lbound", "ubound", \
-		       "plabels", "fixed"}, \
+		       "plabels", "fixed", "h"}, \
 		      2, hook));
   endif
 
--- a/main/optim/inst/private/__residmin_stat__.m	Tue Nov 01 10:45:54 2011 +0000
+++ b/main/optim/inst/private/__residmin_stat__.m	Tue Nov 01 13:17:41 2011 +0000
@@ -44,6 +44,10 @@
     optimget = @ __optimget__;
   endif
 
+  ## scalar defaults
+  diffp_default = .001;
+  cstep_default = 1e-20;
+
   if (nargin == 1 && ischar (f) && strcmp (f, "defaults"))
     ret = optimset ("param_config", [], \
 		    "param_order", [], \
@@ -53,6 +57,8 @@
 		    "dfdp", [], \
 		    "diffp", [], \
 		    "diff_onesided", [], \
+		    "complex_step_derivative", false, \
+		    "cstep", cstep_default, \
 		    "fixed", [], \
 		    "weights", [], \
 		    "residuals", [], \
@@ -65,9 +71,6 @@
     return;
   endif
 
-  ## scalar defaults
-  diffp_default = .001;
-
   assign = @ assign; # Is this faster in repeated calls?
 
   if (nargin != 4)
@@ -98,6 +101,11 @@
   diff_onesided = optimget (settings, "diff_onesided");
   fixed = optimget (settings, "fixed");
   residuals = optimget (settings, "residuals");
+  do_cstep = optimget (settings, "complex_step_derivative", false);
+  cstep = optimget (settings, "cstep", cstep_default);
+  if (do_cstep && ! isempty (dfdp))
+    error ("both 'complex_step_derivative' and 'dfdp' are set");
+  endif
 
   any_vector_conf = ! (isempty (diffp) && isempty (diff_onesided) && \
 		       isempty (fixed));
@@ -335,8 +343,12 @@
   ## jacobian of model function
   if (isempty (dfdp))
     if (! isempty (f))
-      __dfdp__ = @ __dfdp__; # for bug #31484 (Octave <= 3.2.4)
-      dfdp = @ (p, hook) __dfdp__ (p, f, hook);
+      if (do_cstep)
+	dfdp = @ (p, hook) jacobs (p, f, hook);
+      else
+	__dfdp__ = @ __dfdp__; # for bug #31484 (Octave <= 3.2.4)
+	dfdp = @ (p, hook) __dfdp__ (p, f, hook);
+      endif
     endif
   elseif (! isa (dfdp, "function_handle"))
     if (ismatrix (dfdp))
@@ -484,15 +496,15 @@
   if (dfdp_pstruct)
     dfdp = @ (p, hook) \
 	dfdp (p, cell2fields \
-	      ({s_diffp, s_diff_onesided, s_plabels, s_fixed}, \
-	       {"diffp", "diff_onesided", "plabels", "fixed"}, \
+	      ({s_diffp, s_diff_onesided, s_plabels, s_fixed, cstep}, \
+	       {"diffp", "diff_onesided", "plabels", "fixed", "h"}, \
 	       2, hook));
   else
     if (! isempty (dfdp))
       dfdp = @ (p, hook) \
 	  dfdp (p, cell2fields \
-		({diffp, diff_onesided, plabels, fixed}, \
-		 {"diffp", "diff_onesided", "plabels", "fixed"}, \
+		({diffp, diff_onesided, plabels, fixed, cstep}, \
+		 {"diffp", "diff_onesided", "plabels", "fixed", "h"}, \
 		 2, hook));
     endif
   endif
--- a/main/optim/inst/residmin_stat.m	Tue Nov 01 10:45:54 2011 +0000
+++ b/main/optim/inst/residmin_stat.m	Tue Nov 01 13:17:41 2011 +0000
@@ -39,7 +39,7 @@
 ##
 ## @code{dfdp}: Jacobian of model function with respect to parameters.
 ##
-## @code{covr}: Covariance matrix of data (typically guessed by applying
+## @code{covd}: Covariance matrix of data (typically guessed by applying
 ## a factor to the covariance matrix of the residuals).
 ##
 ## @code{covp}: Covariance matrix of final parameters.
@@ -54,10 +54,10 @@
 ## The following settings have the same meaning as in
 ## @code{nonlin_residmin} (please refer to there): @code{param_order},
 ## @code{param_dims}, @code{f_pstruct}, @code{dfdp_pstruct},
-## @code{diffp}, @code{diff_onesided}, @code{fixed}, and @code{weights}.
-## Similarly, @code{param_config} can be used, but only with fields
-## corresponding to the settings @code{fixed}, @code{diffp}, and
-## @code{diff_onesided}.
+## @code{diffp}, @code{diff_onesided}, @code{complex_step_derivative},
+## @code{cstep}, @code{fixed}, and @code{weights}. Similarly,
+## @code{param_config} can be used, but only with fields corresponding
+## to the settings @code{fixed}, @code{diffp}, and @code{diff_onesided}.
 ##
 ## @code{dfdp} can be set in the same way as in @code{nonlin_residmin},
 ## but alternatively may already contain the computed Jacobian of the