Mr.Kinn
Mr.Kinn

Reputation: 409

Changing Optimization Variable to Constant Dynamically (Matlab)

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

Answers (1)

mars
mars

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

Related Questions