Skip to content

Commit

Permalink
Add vary arg to simplex and lm4 (and tests)
Browse files Browse the repository at this point in the history
  • Loading branch information
RichardWaiteSTFC committed Nov 15, 2024
1 parent 8cb0a1a commit 5b72585
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 12 deletions.
14 changes: 14 additions & 0 deletions +sw_tests/+unit_tests/unittest_ndbase_optimisers.m
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,26 @@ function test_optimise_rosen_parameter_fixed_minimum_not_accessible(testCase, op
testCase.verify_val(cost_val, 1, 'abs_tol', 1e-6);
end

function test_optimise_rosen_parameter_fixed_minimum_not_accessible_with_vary_arg(testCase, optimiser)
% note intital guess is outside bounds
[pars_fit, cost_val, ~] = optimiser([], testCase.rosenbrock, [0,-1], 'lb', [nan, -0.5], 'ub', [nan, 0], 'vary', [false, true]);
testCase.verify_val(pars_fit, [0, 0], 'abs_tol', 1e-3);
testCase.verify_val(cost_val, 1, 'abs_tol', 1e-6);
end

function test_optimise_rosen_parameter_all_fixed(testCase, optimiser)
% note intital guess is outside bounds
[pars_fit, cost_val, ~] = optimiser([], testCase.rosenbrock, [-1,-1], 'lb', [0, 0], 'ub', [0, 0]);
testCase.verify_val(pars_fit, [0, 0], 'abs_tol', 1e-3);
testCase.verify_val(cost_val, 1, 'abs_tol', 1e-6);
end

function test_optimise_rosen_parameter_all_fixed_with_vary_arg(testCase, optimiser)
% note intital guess is outside bounds
[pars_fit, cost_val, ~] = optimiser([], testCase.rosenbrock, [0, 0], 'vary', [false, false]);
testCase.verify_val(pars_fit, [0, 0], 'abs_tol', 1e-3);
testCase.verify_val(cost_val, 1, 'abs_tol', 1e-6);
end

end
end
11 changes: 7 additions & 4 deletions swfiles/+ndbase/cost_function_wrapper.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@
% ### Input Arguments
%
% `func`
% : Function handle or char with one of the following definition:
% * `R2 = func(p)` if `dat` is empty,
% : Function handle with one of the following definition:
% * `R = func(p)` if `dat` is empty,
% * `y = func(x,p)` if `dat` is a struct.
% Here `x` is a vector of $N$ independent variables, `p` are the
% $M$ parameters to be optimized and `y` is the simulated model, `R2`
% is the value to minimize.
% $M$ parameters to be optimized and `y` is the simulated model.
% If `resid_handle` argument is false (default) then the function returns
% a scalar (the cost function to minimise e.g. chi-squared). If
% `resid_handle` is true then the function returns a vector of residuals
% (not the residuals squared).
%
% `parameters`
% : Vector of doubles
Expand Down
16 changes: 14 additions & 2 deletions swfiles/+ndbase/lm4.m
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
% Here `x` is a vector of $N$ independent variables, `p` are the
% $M$ parameters to be optimized and `y` is the simulated model.
% If `resid_handle` argument is false (default) then the function returns
% a scalar (the cost funciton to minimsie e.g. chi-squared). If
% a scalar (the cost funciton to minimise e.g. chi-squared). If
% `resid_handle` is true then the function returns a vector of residuals
% (not the residuals squared).
%
Expand Down Expand Up @@ -89,6 +89,11 @@
% decreasing lambda to speed-up convergence by taking larger steps as
% the cost-function surface becomes increasingly parabolic.
%
% `'vary'`
% : Boolean vector with $M$ elements (one per parameter), if an element is
% false, the corresponding parameter will be fixed (not optimised).
% Default is true for all parameters.
%
% ### Output
%
% `pOpt`
Expand Down Expand Up @@ -138,9 +143,16 @@
inpForm.defval = [inpForm.defval {5 0.3, false}];
inpForm.size = [inpForm.size {[1 1] [1 1], [1 1]}];

inpForm.fname = [inpForm.fname {'vary'}];
inpForm.defval = [inpForm.defval {true(1, nparams)}];
inpForm.size = [inpForm.size {[1 nparams]}];

param = sw_readparam(inpForm, varargin{:});

cost_func_wrap = ndbase.cost_function_wrapper(func, p0, "data", dat, 'lb', param.lb, 'ub', param.ub, 'resid_handle', param.resid_handle);
cost_func_wrap = ndbase.cost_function_wrapper(func, p0, "data", dat, ...
'lb', param.lb, 'ub', param.ub, ...
'resid_handle', param.resid_handle, ...
'ifix', find(~param.vary));
% transform starting values into their unconstrained surrogates.
p0_free = cost_func_wrap.get_free_parameters(p0);

Expand Down
20 changes: 14 additions & 6 deletions swfiles/+ndbase/simplex.m
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
% Here `x` is a vector of $N$ independent variables, `p` are the
% $M$ parameters to be optimized and `y` is the simulated model.
% If `resid_handle` argument is false (default) then the function returns
% a scalar (the cost funciton to minimsie e.g. chi-squared). If
% a scalar (the cost funciton to minimise e.g. chi-squared). If
% `resid_handle` is true then the function returns a vector of residuals
% (not the residuals squared).
%
Expand Down Expand Up @@ -138,10 +138,15 @@
% returns array of residuals, if false (default) then function handle
% returns a scalar cost function.
%
% `'vary'`
% : Boolean vector with $M$ elements (one per parameter), if an element is
% false, the corresponding parameter will be fixed (not optimised).
% Default is true for all parameters.
%
% ### See Also
%
% [ndbase.lm] \| [ndbase.pso]

%
% Original author: John D'Errico
% E-mail: [email protected]
% Release: 4
Expand All @@ -161,13 +166,16 @@
inpForm.size = {[1 -1] [1 1] [1 1] [1 1] [-5 -2] [-3 -4] };
inpForm.soft = {false false false false true true };

inpForm.fname = [inpForm.fname {'resid_handle'}];
inpForm.defval = [inpForm.defval {false}];
inpForm.size = [inpForm.size {[1 1]}];
inpForm.fname = [inpForm.fname {'resid_handle', 'vary'}];
inpForm.defval = [inpForm.defval {false, true(1, Np)}];
inpForm.size = [inpForm.size {[1 1], [1, Np]}];

param = sw_readparam(inpForm, varargin{:});

cost_func_wrap = ndbase.cost_function_wrapper(func, p0, "data", dat, 'lb', param.lb, 'ub', param.ub, 'resid_handle', param.resid_handle);
cost_func_wrap = ndbase.cost_function_wrapper(func, p0, "data", dat, ...
'lb', param.lb, 'ub', param.ub, ...
'resid_handle', param.resid_handle, ...
'ifix', find(~param.vary));

% transform starting values into their unconstrained surrogates.
p0_free = cost_func_wrap.get_free_parameters(p0);
Expand Down

0 comments on commit 5b72585

Please sign in to comment.