Reputation: 409
I am using the global maximization toolbox to maximize the following function:
function x = NameOfFunction (w1, w2, w3, a, b, c, Structure1, Structure2, Structure3)
where I am minimizing x
by changing the values of w1
, w2
, and w3
, which are weights that are assigned to other functions calculated in evaluating the value of x
. The remaining parameters are constants and structures containing data. The value of x
, as well as the three weight variables depend on the data that is fed into the function via the structures.
Is there a way to change one of the weight variables (i.e. the variables that the optimizer changes to minimize x
) to a constant from within the function being optimized? Sometimes, depending on conditions met by the input data, one of the w
variables needs to be set to 0. Is there a way to do this from within the function?
I tried doing a simple if
statement, but the optimizer still assigned a non-zero value to the weight in question.
EDIT: Here is a more specific example. Sometimes, the function associated with w3
will evaluate to NaN
(and should therefore be excluded from the calculation of x). When that happens, I would like to assign a 0 to the w
variable for that iteration of the optimization run.
Currently, I have a simple if
statement in the objective function that will exclude the the function associated with w3
from the calculation of x
, but the optimizer assigns a value to w3
regardless.
Upvotes: 0
Views: 330
Reputation: 804
You can abort the search as soon as you encounter a w
that you want to drop. In this case, resume the optimization with the remaining w
.
To keep track of what is currently ignored, you can use a state machine. The following incomplete code shows states w123
for all variables, w12
for only w1
and w2
and so on. Instead of using matlab classes I am using plain structs, writing out the this/self variable where needed for function calls because I don't know if you want to write matlab classes or not.
I am simply assuming that your computation is expensive enough so that any overhead in stopping and starting the optimizer is not critical.
Implementing the missing states is left as an exercise for the reader.
% file so.m (so for stack overflow)
function so
Parameters=0;
w123.description='w1, w2, w3';
w123.getStartvalues=@(w) w; % identity
w123.get_w=@(p) p; % identity
w123.getTargetfunction=@(x) NameOfFunction(x, Parameters);
w123.ignore_w1=@(state) state.w23;
w123.ignore_w2=@(state) state.w13;
w123.ignore_w3=@(state) state.w12;
w12.description='w1, w2, 0';
w12.getStartvalues=@(w) [w(1), w(2)];
w12.get_w=@(p) [p(1), p(2), 0];
w12.getTargetfunction=@(x) NameOfFunction([x(1), x(2), 0], Parameters);
w12.ignore_w1=@(state) state.w2;
w12.ignore_w2=@(state) state.w1;
w12.ignore_w3=@(state) state.w12; % w3 is already ignored
w13.description='w1, 0, w3';
w13.getStartvalues=@(w) [w(1), w(3)];
w13.get_w=@(p) [p(1), 0, p(2)];
w13.getTargetfunction=@(x) NameOfFunction([x(1), 0, x(2)], Parameters);
w13.ignore_w1=@(state) state.w3;
w13.ignore_w2=@(state) state.w13; % w2 is already ignored
w13.ignore_w3=@(state) state.w1;
% ... and so on for w23, w1, w2, w3
% ... fill in all the states from above
state.w123=w123;
state.w12=w12;
state.w13=w13;
state.current=state.w123; % initial state
state.ignore_w1=@(s) s.current.ignore_w1(s);
state.ignore_w2=@(s) s.current.ignore_w2(s);
state.ignore_w3=@(s) s.current.ignore_w3(s);
state.getTargetfunction=@(s) s.current.getTargetfunction;
state.getStartvalues=@(s, w) s.current.getStartvalues(w);
% Startvalues for w
initial_w=[1, 2, 3];
% Don't lose the intermediate result
w_before_abort=initial_w;
best_w=initial_w;
while true
try
fprintf('Starting an optimization run using %s\n', state.current.description);
best_fit=fminsearch(state.getTargetfunction(state), state.getStartvalues(state,best_w));
best_w=state.get_w(state, best_fit);
break;
catch event
if strcmp(event.identifier, 'NameOfFunction:ignore_w1')
state.current = state.ignore_w1(state);
elseif strcmp(event.identifier, 'NameOfFunction:ignore_w2')
state.current = state.ignore_w2(state);
elseif strcmp(event.identifier, 'NameOfFunction:ignore_w3')
state.current = state.ignore_w3(state);
else
event.stack(1)
throw(event);
end
best_w=w_before_abort;
end
end
best_w
% Nested function; watch out for name collisions in the enclosing namespace
% w_before_abort is intentional, everything else is not.
function x=NameOfFunction(w, Parameters)
% debug output:
w1=w(1)
w2=w(2)
w3=w(3)
% run this code if you want to ignore w1:
w_before_abort=w; % save the last inspected w
throw(MException('NameOfFunction:ignore_w1', 'Set w1 to zero.'));
% run this code if you want to ignore w2:
w_before_abort=w; % save the last inspected w
throw(MException('NameOfFunction:ignore_w2', 'Set w2 to zero.'));
end
end
Upvotes: 1