opti_lab_3_simp.m

 avatar
unknown
matlab
2 months ago
3.7 kB
3
Indexable
% opti_lab_2.m

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% tikslo funkcijos ir tt.


% tikslo funkcija
f = @(X) -1 * X(1) * X(2) * X(3);

% lygybinis apribojimas g1 (2xy+2yz+2xz-1)
g1 = @(X) 2*X(1)*X(2) + 2*X(2)*X(3) + 2*X(1)*X(3) - 1;

% kvadratine bauda
b_h1 = @(X) (max(0, -X(1)))^2; % -X(1) yra h1
b_h2 = @(X) (max(0, -X(2)))^2;
b_h3 = @(X) (max(0, -X(3)))^2;
b_g1 = @(X) (g1(X))^2;
kvadratinebauda = @(X) b_h1(X) + b_h2(X) + b_h3(X) + b_g1(X);

% baudos funkcija
baudosf = @(X,r) f(X) + 1/r * kvadratinebauda(X);


% tikslo funkcijos ir tt.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% nelder mead simplex

function result = nelderMeadSimplex(point_0, f, r, epsilon)

    result = Result();

    % consts
    alpha = r/100;
    delta_1 = alpha*(sqrt(2+1)+2-1)/(2*sqrt(2));
    delta_2 = alpha*(sqrt(2+1)-1)/(2*sqrt(2));
    coeff_base = 1;
    coeff_expand = 2;
    coeff_shrink = 0.5;
    coeff_shrink_max = -0.5;
    
    % create base simplex
    simplex = [
        point_0(1)          ,     point_0(2)          ,     point_0(3)          ,     NaN; 
        point_0(1) + delta_2,     point_0(2) + delta_1,     point_0(3) + delta_1,     NaN;
        point_0(1) + delta_1,     point_0(2) + delta_2,     point_0(3) + delta_1,     NaN;
        point_0(1) + delta_1,     point_0(2) + delta_1,     point_0(3) + delta_2,     NaN;
    ];
    
    % fill base simplex 4th column with func values
    for i = 1:4
        simplex(i, 4) = f(simplex(i, 1:3), r);
        result.incFuncCallCount();
        result.addIterSimplex(simplex(i, :));
        result.addSimplex(simplex);
    end
    
    % sort descending based on function result
    simplex = sortrows(simplex, -4);

    % function for generating new simplex point
    function point = nextPoint(coeff, simplex)
        centroid = 0.5 * (simplex(3, 1:3) + simplex(4, 1:3));

        % X_naujas = X_h + (1 + coeff)(X_c - X_h)
        new_x_y = simplex(1, 1:3) + (1 + coeff) * (centroid - simplex(1, 1:3));
        point = [new_x_y(1), new_x_y(2), new_x_y(3), f(new_x_y, r)];
        result.incFuncCallCount();
    end

    % iteration loop
    maxiter = 20;
    counter = 0;
    while vecnorm(simplex(4, 1:3) - simplex(3, 1:3)) > epsilon && counter <= maxiter
        counter = counter + 1;
        % create new point
        old_point = simplex(1, :);
        new_point = nextPoint(coeff_base, simplex);

        % adjust new point
        if new_point(4) > simplex(1, 4) % higher than highest
            new_point = nextPoint(coeff_shrink_max, simplex); 

        elseif new_point(4) > simplex(2, 4) % between high and mid
            new_point = nextPoint(coeff_shrink, simplex);

        elseif new_point(4) > simplex(4, 4) % between mid and low
            

        else % lower than lowest
            new_point = nextPoint(coeff_expand, simplex);
        end
        
        simplex(1, :) = new_point;
        result.addIterSimplex(simplex(1, :));
        result.addSimplex(simplex);
        result.addArrow(old_point, new_point);
        simplex = sortrows(simplex, -4);

    end
end

% nelder mead simplex
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% main

start_points = {[0, 0, 0], [1, 1, 1], [0.4, 0.5, 0.2]};
epsilon = 0.0001;
r = 50;

result = nelderMeadSimplex(start_points{1}, baudosf, r, epsilon);
while vecnorm(result.simplexes{end}(4, 1:3) - result.simplexes{end}(3, 1:3)) > epsilon
    r = r/2;
    result = nelderMeadSimplex(result.simplexes{end}(4, 1:3), baudosf, r, epsilon);
end

Leave a Comment