diff --git a/doc/manual/source/the-model-file.rst b/doc/manual/source/the-model-file.rst index d7fc37c69beee5eacc821048d5e572b31add2b0f..3e5803b8dbb2f7e61ab504d80ddc7ea34d1ecfdb 100644 --- a/doc/manual/source/the-model-file.rst +++ b/doc/manual/source/the-model-file.rst @@ -4652,8 +4652,10 @@ block decomposition of the model (see :opt:`block`). ``1`` Uses ``fmincon`` optimization routine (available under - MATLAB if the Optimization Toolbox is installed; not - available under Octave). + MATLAB if the Optimization Toolbox is installed; available + under Octave if the `optim + <https://octave.sourceforge.io/optim/>`__ package from + Octave-Forge, version 1.6 or above, is installed). ``2`` diff --git a/matlab/optimization/dynare_minimize_objective.m b/matlab/optimization/dynare_minimize_objective.m index 6103fa167a3eede2717e683016db96057a450048..c3988bec951755bbf0e76e5d78c662cd9d19b782 100644 --- a/matlab/optimization/dynare_minimize_objective.m +++ b/matlab/optimization/dynare_minimize_objective.m @@ -26,7 +26,7 @@ function [opt_par_values,fval,exitflag,hessian_mat,options_,Scale,new_rat_hess_i % none. % % -% Copyright (C) 2014-2017 Dynare Team +% Copyright (C) 2014-2019 Dynare Team % % This file is part of Dynare. % @@ -64,13 +64,22 @@ new_rat_hess_info=[]; switch minimizer_algorithm case 1 - if isoctave - error('Optimization algorithm 1 is not available under Octave') - elseif ~user_has_matlab_license('optimization_toolbox') + if isoctave && ~user_has_octave_forge_package('optim', '1.6') + error('Optimization algorithm 1 is not available, you need to install the optim Forge package, version 1.6 or above') + elseif ~isoctave && ~user_has_matlab_license('optimization_toolbox') error('Optimization algorithm 1 requires the Optimization Toolbox') end % Set default optimization options for fmincon. - optim_options = optimset('display','iter', 'LargeScale','off', 'MaxFunEvals',100000, 'TolFun',1e-8, 'TolX',1e-6); + optim_options = optimset('display','iter', 'MaxFunEvals',100000, 'TolFun',1e-8, 'TolX',1e-6); + if ~isoctave + optim_options = optimset(optim_options, 'LargeScale','off'); + end + if isoctave + % Under Octave, use the active-set (i.e. octave_sqp of nonlin_min) + % algorithm. On a simple example (fs2000.mod), the default algorithm + % is not able to even move away from the initial point. + optim_options = optimset(optim_options, 'Algorithm','active-set'); + end if ~isempty(options_.optim_opt) eval(['optim_options = optimset(optim_options,' options_.optim_opt ');']); end @@ -80,8 +89,16 @@ switch minimizer_algorithm if options_.analytic_derivation optim_options = optimset(optim_options,'GradObj','on','TolX',1e-7); end - [opt_par_values,fval,exitflag,output,lamdba,grad,hessian_mat] = ... + if ~isoctave + [opt_par_values,fval,exitflag,output,lamdba,grad,hessian_mat] = ... fmincon(objective_function,start_par_value,[],[],[],[],bounds(:,1),bounds(:,2),[],optim_options,varargin{:}); + else + % Under Octave, use a wrapper, since fmincon() does not have an 11th + % arg. Also, only the first 4 output arguments are available. + func = @(x) objective_function(x,varargin{:}); + [opt_par_values,fval,exitflag,output] = ... + fmincon(func,start_par_value,[],[],[],[],bounds(:,1),bounds(:,2),[],optim_options); + end case 2 %simulating annealing sa_options = options_.saopt; diff --git a/matlab/user_has_octave_forge_package.m b/matlab/user_has_octave_forge_package.m index a3f1bc38dbbb70606dd919e508a1259eae6ceac8..3b0abf484921fc5ca6b248db8198251c2946cf25 100644 --- a/matlab/user_has_octave_forge_package.m +++ b/matlab/user_has_octave_forge_package.m @@ -1,7 +1,8 @@ -function [hasPackage] = user_has_octave_forge_package(package) +function [hasPackage] = user_has_octave_forge_package(package, min_version) % Checks for the availability of a given Octave Forge package +% Optionally, a minimal version can be required for the package -% Copyright (C) 2012 Dynare Team +% Copyright (C) 2012-2019 Dynare Team % % This file is part of Dynare. % @@ -18,13 +19,19 @@ function [hasPackage] = user_has_octave_forge_package(package) % You should have received a copy of the GNU General Public License % along with Dynare. If not, see <http://www.gnu.org/licenses/>. -[desc,flag] = pkg('describe', package); +[desc,flag] = pkg("describe", package); -if isequal(flag{1,1}, 'Not installed') +if isequal(flag{1,1}, "Not installed") hasPackage = 0; else - if isequal(flag{1,1}, 'Not loaded') - pkg('load', package); - end - hasPackage = 1; -end + if isequal(flag{1,1}, "Not loaded") + pkg("load", package); + endif + if nargin > 1 && compare_versions(desc{1,1}.version, min_version, "<") + hasPackage = 0; + else + hasPackage = 1; + endif +endif +endfunction + diff --git a/tests/Makefile.am b/tests/Makefile.am index 7222592ea40c6b4ad7dd6ed53f5849f94c0ca584..1b6fef0141a829bbca544e23b2c6bae58ef66d22 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -333,6 +333,7 @@ MODFILES = \ smoother2histval/fs2000_simul.mod \ smoother2histval/fs2000_smooth.mod \ smoother2histval/fs2000_smooth_stoch_simul.mod \ + optimizers/fs2000_1.mod \ optimizers/fs2000_2.mod \ optimizers/fs2000_3.mod \ optimizers/fs2000_4.mod \ diff --git a/tests/optimizers/fs2000_1.mod b/tests/optimizers/fs2000_1.mod index fe37048359d3731ca32d9bb4e68e33f18f6b89c5..65b261d42d2b4a968baf24bb38c8b37759f5ef5c 100644 --- a/tests/optimizers/fs2000_1.mod +++ b/tests/optimizers/fs2000_1.mod @@ -1,5 +1,5 @@ @#include "fs2000.common.inc" -if ~isoctave() && exist('fmincon','file') +if (isoctave && user_has_octave_forge_package('optim', '1.6')) || (~isoctave && user_has_matlab_license('optimization_toolbox')) estimation(mode_compute=1,order=1, datafile='../fs2000/fsdat_simul', nobs=192, mh_replic=0); end