Problem: Multi-objective Ant Lion Optimization for ZDT1

The problem involves implementing the MALO algorithm for the ZDT1 test function via helper functions (initialization, archive management, random walks, etc.) and visualizing the Pareto front.


Input/Output: The problem receives predefined MATLAB functions (ZDT1, initialization, dominates, UpdateArchive, RankingProcess, HandleFullArchive, RouletteWheelSelection, Random_walk_around_antlion, Draw_ZDT1) and parameters (random seed 42, dim=5, lb=0, ub=1, obj_no=2, max_iter=100, N=100, ArchiveMaxSize=100). It generates two matrices (Archive_X: non-dominated solution positions; Archive_F: fitness values) and a plot of ZDT1's true Pareto front with obtained solutions via the MALO algorithm.

Required dependencies:

Sub-steps:
step_number: 1
step_description_prompt: Please use MATLAB code to generate a function named ZDT1 that implements the ZDT1 multi-objective optimization test function. The function takes a vector x as input and returns a two-element vector o as output.

Function definition: function o = ZDT1(x)

Algorithm flow:
1. Initialize the output vector o as [0, 0].
2. Calculate dim as the length of the input vector x.
3. Compute g using the formula: g = 1 + 9 * sum(x(2:dim)) / (dim - 1).
4. Set the first element of o (o(1)) to the first element of the input vector x (x(1)).
5. Set the second element of o (o(2)) using the formula: g * (1 - sqrt(x(1) / g)).

Any functions called in the provided code are assumed to be already defined and do not need to be redefined.
function_header: function o = ZDT1(x)

end
test_cases: clear; clc;
rng(42);

x1 = [1;6;4;2;3];
x2 = [2;9;3];
x3 = [6;1;5;7];
val = sum(ZDT1(x1));
correct = 29.855087;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end
val = sum(ZDT1(x2));
correct = 46.511912;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end
val = sum(ZDT1(x3));
correct = 30.508067;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end
disp('Completely right!')

step_number: 2
step_description_prompt: Please write a MATLAB function named initialization that initializes the first population of search agents. The function takes four inputs: SearchAgents_no (number of search agents), dim (dimensionality of the search space), ub (upper bounds of the variables), lb (lower bounds of the variables), and returns Positions (the initialized population matrix where each row represents a dimension and each column represents a search agent's position).
Function definition: function Positions = initialization(SearchAgents_no, dim, ub, lb)
Algorithm steps:
1. Compute Boundary_no as the number of columns of ub using size(ub,2).
2. Handle boundary conditions:
   a. If Boundary_no == 1 (all variables have the same upper and lower bounds), create ub_new as a 1-by-dim matrix with all elements equal to ub, and create lb_new as a 1-by-dim matrix with all elements equal to lb.
   b. Else, set ub_new = ub and lb_new = lb.
3. For each dimension i from 1 to dim:
   a. Get ub_i = ub_new(i) (upper bound of the i-th dimension).
   b. Get lb_i = lb_new(i) (lower bound of the i-th dimension).
   c. Generate a SearchAgents_no-by-1 random matrix using rand, multiply it by (ub_i - lb_i), then add lb_i to get the positions of all search agents in the i-th dimension, and assign this to Positions(:,i).
4. Transpose Positions to make each row represent a dimension and each column represent a search agent.
Note: Functions called in the code (e.g., rand) are assumed to be pre-defined and do not need to be redefined.
function_header: function Positions=initialization(SearchAgents_no,dim,ub,lb)

end
test_cases: clear; clc;
rng(42);

X1 = initialization(5, 3, 10, -5);
val=sum(X1(:));
correct = 36.277026;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end
X2 = initialization(4, 3, [5,10,15], [-2,0,3]);
val=sum(X2(:));
correct = 49.145022;
if tol>1e-4
    error('Wrong!')
end
X3 = initialization(3, 2, 1, 2);
val=sum(X3(:));
correct = 10.003780;
if tol>1e-4
    error('Wrong!')
end
disp('Completely right!')

step_number: 3
step_description_prompt: Please write a MATLAB function named dominates that implements the check for whether array x Pareto dominates array y. The function has the definition function o = dominates(x, y), where x and y are input arrays of the same dimensions, and o is a logical output. The algorithm is: compute the logical value of (all elements in x are ≤ corresponding elements in y) AND (at least one element in x is < corresponding element in y), then assign this value to o. Any functions called in the code are assumed to be already defined.
function_header: function o=dominates(x,y)

end
test_cases: clear; clc;
rng(42);

cases = {
    {[1,2,3], [2,3,4], true},   
    {[2,3,4], [1,2,3], false},  
    {[1,3,2], [2,2,3], false},  
    {[1,2,3], [1,2,3], false},  
    {[1,2,3], [1,3,4], true},   
    {[1,3,2], [2,1,3], false},  
};
val = 0;
for i = 1:length(cases)
    x = cases{i}{1};
    y = cases{i}{2};
    expected = cases{i}{3};
    if dominates(x, y) == expected
        val = val + 1;
    end
end
if val~=length(cases)
    error('Wrong')
end
disp('Completely right!')

step_number: 4
step_description_prompt: Please write a MATLAB function named UpdateArchive that updates the archive of non-dominated solutions by merging the existing archive with new particles, then removing dominated or duplicate solutions.
function [Archive_X_updated, Archive_F_updated, Archive_member_no] = UpdateArchive(Archive_X, Archive_F, Particles_X, Particles_F, Archive_member_no)
1. Merge the existing archive with new particles: Create Archive_X_temp as [Archive_X ; Particles_X'] (transpose Particles_X before merging) and Archive_F_temp as [Archive_F ; Particles_F].
2. Initialize a zero vector o of size 1-by-size(Archive_F_temp,1) to mark whether each solution is dominated or duplicate (1 means dominated/duplicate, 0 means non-dominated/unique).
3. For each i from 1 to size(Archive_F_temp,1):
   a. Set o(i) = 0.
   b. For each j from 1 to i-1:
      i. If solution i and j have different objective values (any(Archive_F_temp(i,:) ~= Archive_F_temp(j,:))):
         - If solution i dominates solution j (using the pre-defined dominates function), set o(j) = 1.
         - If solution j dominates solution i, set o(i) = 1 and break the loop over j.
      ii. If solution i and j have identical objective values (all elements are the same):
         - Set o(j) = 1 and o(i) = 1.
4. Reset Archive_member_no to 0. Iterate over each i from 1 to size(Archive_X_temp,1):
   a. If o(i) == 0:
      - Increment Archive_member_no by 1.
      - Assign Archive_X_temp(i,:) to Archive_X_updated(Archive_member_no,:) and Archive_F_temp(i,:) to Archive_F_updated(Archive_member_no,:).
The dominates function (which checks if one solution dominates another) is pre-defined and does not need to be implemented.
function_header: function [Archive_X_updated, Archive_F_updated, Archive_member_no]=UpdateArchive(Archive_X, Archive_F, Particles_X, Particles_F, Archive_member_no)

end
test_cases: clear; clc;
rng(42);

Archive_X1 = [1, 2; 3, 4];
Archive_F1 = [2, 3; 4, 5];
Particles_X1 = [5, 6]';
Particles_F1 = [6, 7];
Archive_member_no1 = 2;

Archive_X2 = [1, 1];
Archive_F2 = [2, 3];
Particles_X2 = [2, 2.6; 7.3, 0.5]';
Particles_F2 = [8.2, 4; 1, 2];
Archive_member_no2 = 1;

Archive_X3 = [2, 1];
Archive_F3 = [6, 3];
Particles_X3 = [7.2, 6.4; 1.0, 0.2]';
Particles_F3 = [8.2, 2.1; 5.6, 6.8];
Archive_member_no3 = 2;

[A_X1, A_F1, A_no1] = UpdateArchive(Archive_X1, Archive_F1, Particles_X1, Particles_F1, Archive_member_no1);
[A_X2, A_F2, A_no2] = UpdateArchive(Archive_X2, Archive_F2, Particles_X2, Particles_F2, Archive_member_no2);
[A_X3, A_F3, A_no3] = UpdateArchive(Archive_X3, Archive_F3, Particles_X3, Particles_F3, Archive_member_no3);

val = sum(A_X1(:)) + sum(A_F1(:)) + A_no1;
correct = 9.000000;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end
val2 = sum(A_X2(:)) + sum(A_F2(:)) + A_no2;
correct = 11.800000;
tol = abs(val2-correct);
if tol>1e-4
    error('Wrong!')
end
val3 = sum(A_X3(:)) + sum(A_F3(:)) + A_no3;
correct = 52.500000;
tol = abs(val3-correct);
if tol>1e-4
    error('Wrong!')
end
disp('Completely right!')

step_number: 5
step_description_prompt: Please write a MATLAB function named RankingProcess that computes ranking scores for each point in Archive_F by counting the number of points (including itself) within a dimension-wise neighborhood defined by global variables my_min and my_max. The function takes three inputs: Archive_F (a matrix where each row represents a point's objective values), ArchiveMaxSize (an unused parameter), and obj_no (the number of objective functions), and returns ranks (a row vector where each element is the ranking score for the corresponding point in Archive_F). The function definition is function ranks = RankingProcess(Archive_F, ArchiveMaxSize, obj_no). First, declare the global variables my_min and my_max. If Archive_F is a 1-by-2 matrix (size(Archive_F,1) == 1 && size(Archive_F,2) == 2), set both my_min and my_max equal to Archive_F. Otherwise, set my_min to the column-wise minimum of Archive_F and my_max to the column-wise maximum of Archive_F. Calculate r as (my_max - my_min) divided by 20. Initialize ranks as a row vector of zeros with length equal to the number of rows in Archive_F. For each i from 1 to size(Archive_F,1), set ranks(i) to 0. Then, for each j from 1 to size(Archive_F,1), initialize flag to 0. For each k from 1 to obj_no, if the absolute difference between Archive_F(j,k) and Archive_F(i,k) is less than r(k), increment flag by 1. If flag equals obj_no (all objective dimensions meet the neighborhood condition), increment ranks(i) by 1. Ensure the function strictly follows this logic, uses the same global variables, and maintains the exact input/output structure.
function_header: function ranks=RankingProcess(Archive_F, ArchiveMaxSize, obj_no)

end
test_cases: clear; clc;
rng(42);

Archive_F1 = [1.2, 2.3; 2.1, 1.8; 3.0, 3.5];
obj_no1 = 2;
ranks1 = RankingProcess(Archive_F1, 10, obj_no1);
val = sum(ranks1);
correct = 3.000000;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end

Archive_F2 = [1.6, 5.3, 5.4; 2.9, 0.8, 2.5; 1.0, 1.5, 4.0];
obj_no2 = 3;
ranks2 = RankingProcess(Archive_F2, 5, obj_no2);
val =  sum(ranks2);
correct = 3.000000;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end
disp('Completely right!')

step_number: 6
step_description_prompt: Please use MATLAB code to generate a function named HandleFullArchive that implements the functionality of reducing an archive's size to a specified maximum size by iteratively removing members selected via roulette wheel selection based on member ranks, then returning the chopped archive data and updated parameters.

The function definition is: function [Archive_X_Chopped, Archive_F_Chopped, Archive_mem_ranks_updated, Archive_member_no] = HandleFullArchive(Archive_X, Archive_F, Archive_member_no, Archive_mem_ranks, ArchiveMaxSize)

Algorithm flow:
1. Calculate the number of iterations as the difference between the initial number of rows in Archive_F (size(Archive_F,1)) and ArchiveMaxSize (this is the number of members to remove to reach ArchiveMaxSize).
2. For each iteration from 1 to the number of iterations calculated in step 1:
   a. Select an index using the pre-defined RouletteWheelSelection function with Archive_mem_ranks as input (index = RouletteWheelSelection(Archive_mem_ranks)).
   b. Update Archive_X by removing the row at the selected index: Archive_X = [Archive_X(1:index-1,:) ; Archive_X(index+1:Archive_member_no,:)].
   c. Update Archive_F by removing the row at the selected index: Archive_F = [Archive_F(1:index-1,:) ; Archive_F(index+1:Archive_member_no,:)].
   d. Update Archive_mem_ranks by removing the element at the selected index: Archive_mem_ranks = [Archive_mem_ranks(1:index-1) Archive_mem_ranks(index+1:Archive_member_no)].
   e. Decrement Archive_member_no by 1: Archive_member_no = Archive_member_no - 1.
3. Assign the modified Archive_X to Archive_X_Chopped, modified Archive_F to Archive_F_Chopped, and modified Archive_mem_ranks to Archive_mem_ranks_updated.
4. Return Archive_X_Chopped, Archive_F_Chopped, Archive_mem_ranks_updated, and Archive_member_no as outputs.

Note: The RouletteWheelSelection function is assumed to be already defined and returns a valid index corresponding to the current Archive_mem_ranks array.
function_header: function [Archive_X_Chopped, Archive_F_Chopped, Archive_mem_ranks_updated, Archive_member_no]=HandleFullArchive(Archive_X, Archive_F, Archive_member_no, Archive_mem_ranks, ArchiveMaxSize)

end
test_cases: clear; clc;
rng(42);

Archive_X1 = [1.2, 2.3; 2.1, 1.8; 3.0, 3.5; 4.5, 4.0; 5.0, 5.5];
Archive_F1 = [2.3, 3.4; 3.2, 2.9; 4.1, 4.6; 5.6, 5.1; 6.1, 6.6];
Archive_member_no1 = 5;
Archive_mem_ranks1 = [2, 4, 1, 3, 5];
ArchiveMaxSize1 = 3;
[A_X1, A_F1, A_ranks1, A_no1] = HandleFullArchive(Archive_X1, Archive_F1, Archive_member_no1, Archive_mem_ranks1, ArchiveMaxSize1);
val = sum(A_X1(:)) + sum(A_F1(:)) + sum(A_ranks1) + A_no1;
correct = 52.600000;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end

Archive_X1 = [1.2, 2.6; 3.1, 1.9; 6.0, 2.5; 5.3, 2.1; 1.0, 4.5];
Archive_F1 = [2.3, 6.2; 7.2, 2.8; 3.1, 5.6; 2.1, 3.6; 4.2, 3.6];
Archive_member_no1 = 5;
Archive_mem_ranks1 = [3, 5, 2, 3, 5];
ArchiveMaxSize1 = 6;
[A_X1, A_F1, A_ranks1, A_no1] = HandleFullArchive(Archive_X1, Archive_F1, Archive_member_no1, Archive_mem_ranks1, ArchiveMaxSize1);
val = sum(A_X1(:)) + sum(A_F1(:)) + sum(A_ranks1) + A_no1;
correct = 93.900000;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end

Archive_X1 = [1.0, 1.5; 2.0, 2.0; 3.0, 1.0; 4.0, 1.5];
Archive_F1 = [2.0, 3.0; 3.0, 2.0; 4.0, 1.0; 5.0, 1.5];
Archive_member_no1 = 4;
Archive_mem_ranks1 = [1, 2, 3, 2];  
ArchiveMaxSize1 = 3;  
[A_X1, A_F1, A_ranks1, A_no1] = HandleFullArchive(Archive_X1, Archive_F1, Archive_member_no1, Archive_mem_ranks1, ArchiveMaxSize1);
val = sum(A_X1(:)) + sum(A_F1(:)) + sum(A_ranks1) + A_no1;
correct = 36.500000;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end
disp('Completely right!')

step_number: 7
step_description_prompt: Please use MATLAB code to generate a function named RouletteWheelSelection that implements the Roulette Wheel Selection Algorithm. This algorithm selects the 1-based index of an individual from a group, where each individual’s selection probability is proportional to its given weight. The function is defined as: function choice = RouletteWheelSelection(weights), where 'weights' is a 1-dimensional array of non-negative numerical values (representing the selection weight of each individual), and 'choice' is the index of the selected individual. The algorithm flow is as follows: 1. Compute the cumulative sum of the 'weights' array using cumsum(weights) and store the result in the variable 'accumulation'. 2. Generate a random value 'p' by multiplying a uniformly distributed random number (from rand(), which returns a value in the range [0, 1)) with the last element of 'accumulation' (i.e., the total sum of weights). 3. Initialize 'chosen_index' to -1. 4. Use a for loop to iterate over each index from 1 to the length of 'accumulation': for index = 1 : length(accumulation). 5. For each index, check if accumulation(index) > p. If this condition is true, set 'chosen_index' to 'index' and break out of the loop immediately. 6. Assign 'chosen_index' to 'choice' and return it as the final result. Note that functions called in the code (cumsum, rand) are assumed to be pre-defined and available. For example, calling RouletteWheelSelection([1 5 3 15 8 1]) will most likely return 4, as the 4th element has the largest weight (15).
function_header: function choice = RouletteWheelSelection(weights)

end
test_cases: clear; clc;
rng(42);

w1 = [3, 2, 6, 5];
w2 = [1, 9, 8, 6];
w3 = [1];
w4 = [5, 3, 1];

val = RouletteWheelSelection(w1);
correct = 3.000000;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end

val = RouletteWheelSelection(w3);
correct = 1.000000;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end

val = RouletteWheelSelection(w4);
correct = 2.000000;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end
disp('Completely right!')

step_number: 8
step_description_prompt: Please write a MATLAB function named Random_walk_around_antlion that generates random walks around an antlion with iteration-dependent boundary scaling and random position adjustment. The function definition is [RWs] = Random_walk_around_antlion(Dim, max_iter, lb, ub, antlion, current_iter). Implement the following steps strictly: 1. If lb and ub are scalars (size(lb,1) == 1 && size(lb,2) == 1), expand them to 1-by-Dim vectors using lb = ones(1,Dim)*lb and ub = ones(1,Dim)*ub. 2. If lb is a vertical vector (size(lb,1) > size(lb,2)), transpose lb and ub to horizontal with lb = lb' and ub = ub'. 3. Initialize I = 1. Update I based on current_iter: if current_iter > max_iter/10, set I = 1 + 100*(current_iter/max_iter); if current_iter > max_iter/2, set I = 1 + 1000*(current_iter/max_iter); if current_iter > max_iter*(3/4), set I = 1 + 10000*(current_iter/max_iter); if current_iter > max_iter*0.9, set I = 1 + 100000*(current_iter/max_iter); if current_iter > max_iter*0.95, set I = 1 + 1000000*(current_iter/max_iter). 4. Scale lb and ub by dividing by I: lb = lb/I, ub = ub/I. 5. Adjust lb: if rand < 0.5, set lb = lb + antlion; else, set lb = -lb + antlion. 6. Adjust ub: if rand >= 0.5, set ub = ub + antlion; else, set ub = -ub + antlion. 7. For each dimension i from 1 to Dim: a. Generate a random walk X as [0 cumsum(2*(rand(max_iter,1) > 0.5) - 1)']. b. Compute a = min(X), b = max(X), c = lb(i), d = ub(i). c. Normalize X to the range [c, d] using X_norm = ((X - a).*(d - c))./(b - a) + c. d. Assign X_norm to RWs(:,i). Return RWs where each column is a normalized random walk for one dimension.
function_header: function [RWs]=Random_walk_around_antlion(Dim,max_iter,lb, ub,antlion,current_iter)

end
test_cases: clear; clc;
rng(42);

Dim = 2;
max_iter = 100;
lb = -5;
ub = 5;
antlion = [1, 2];
current_iter = 10;
RWs1 = Random_walk_around_antlion(Dim, max_iter, lb, ub, antlion, current_iter);
val = sum(RWs1(:));
correct = 113.727273;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end

Dim = 4;
max_iter = 50;
lb = -0.5;
ub = 0.5;
antlion = [1, 2, 5, 1.5];
current_iter = 45;
RWs2 = Random_walk_around_antlion(Dim, max_iter, lb, ub, antlion, current_iter);
val = sum(RWs2(:));
correct = 484.500699;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end

current_iter3 = 90;
RWs3 = Random_walk_around_antlion(3, 100, -2, 2, [0.5, 0.5, 0.5], current_iter3);
val =  sum(RWs3(:));
correct = 151.505339;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end
disp('Completely right!')

step_number: 9
step_description_prompt: Please write a MATLAB function named Draw_ZDT1 that generates and plots the true Pareto optimal front (TPF) of the ZDT1 problem, and formats the figure with specified properties.

Function Definition: Define the function as function TPF = Draw_ZDT1() where TPF is the output (true Pareto optimal front) and there are no input arguments.

Algorithm Flow:
1. Add the directory 'ZDT_set' to the MATLAB search path using addpath('ZDT_set').
2. Define an objective function handle ObjectiveFunction as @(x) ZDT1(x) (note: the ZDT1 function is assumed to be pre-defined and does not need to be reimplemented).
3. Create a vector x with values from 0 to 1 in increments of 0.01 using x = 0:0.01:1.
4. Iterate over each element in x: for i from 1 to the number of columns in x (size(x,2)), compute the objective function values by passing the vector [x(i), 0, 0, 0] to ObjectiveFunction, and store the result in TPF(i,:).
5. Plot the Pareto front using line(TPF(:,1), TPF(:,2)).
6. Set the figure title to 'ZDT1', x-axis label to 'f1', y-axis label to 'f2', and enable the axes box using title('ZDT1'), xlabel('f1'), ylabel('f2'), box on.
7. Get the handle of the current figure using fig = gcf.
8. Set the FontName property of all objects in the figure that have this property to 'Garamond' using set(findall(fig,'-property','FontName'),'FontName','Garamond').
9. Set the FontAngle property of all objects in the figure that have this property to 'italic' using set(findall(fig,'-property','FontAngle'),'FontAngle','italic').

Note: The ZDT1 function called by ObjectiveFunction is assumed to be already defined, so no need to redefine it.
ground_truth_code: function TPF=Draw_ZDT1()

% TPF is the true Pareto optimal front
addpath('ZDT_set')

ObjectiveFunction=@(x) ZDT1(x);
x=0:0.01:1;
for i=1:size(x,2)
    TPF(i,:)=ObjectiveFunction([x(i) 0 0 0]);
end
line(TPF(:,1),TPF(:,2));
title('ZDT1')

xlabel('f1')
ylabel('f2')
box on

fig=gcf;
set(findall(fig,'-property','FontName'),'FontName','Garamond')
set(findall(fig,'-property','FontAngle'),'FontAngle','italic')
end
function_header: function TPF=Draw_ZDT1()

end

step_number: 10
step_description_prompt: Please use MATLAB code to generate a function named MALO_ZDT1 that implements the Multi-objective Ant Lion Optimizer (MALO) to optimize the ZDT1 function, obtaining the non-dominated solution set and their corresponding fitness values.

function [Archive_X, Archive_F] = MALO_ZDT1()
    rng(42);
    
    % Problem configuration
    ObjectiveFunction = @ZDT1;
    dim = 5;
    lb = 0;
    ub = 1;
    obj_no = 2;
    
    % Handle bounds if they are scalars
    if size(ub, 2) == 1
        ub = ones(1, dim) * ub;
        lb = ones(1, dim) * lb;
    end
    
    % Algorithm parameters
    max_iter = 100;
    N = 100;
    ArchiveMaxSize = 100;
    
    % Initialize archive
    Archive_X = zeros(100, dim);
    Archive_F = ones(100, obj_no) * inf;
    Archive_member_no = 0;
    
    % Initialize other parameters
    r = (ub - lb) / 2;
    V_max = (ub(1) - lb(1)) / 10;
    Elite_fitness = inf * ones(1, obj_no);
    Elite_position = zeros(dim, 1);
    
    % Initialize ant positions and fitness
    Ant_Position = initialization(N, dim, ub, lb);
    fitness = zeros(N, 2);
    
    % Initialize velocity and position history
    V = initialization(N, dim, ub, lb);
    position_history = zeros(N, max_iter, dim);
    
    % Main iteration loop
    for iter = 1:max_iter
        % Evaluate fitness and update elite
        Particles_F = zeros(N, obj_no);
        for i = 1:N
            Particles_F(i, :) = ObjectiveFunction(Ant_Position(:, i)');
            if dominates(Particles_F(i, :), Elite_fitness)
                Elite_fitness = Particles_F(i, :);
                Elite_position = Ant_Position(:, i);
            end
        end
        
        % Update archive
        [Archive_X, Archive_F, Archive_member_no] = UpdateArchive(Archive_X, Archive_F, Ant_Position, Particles_F, Archive_member_no);
        
        % Handle full archive
        if Archive_member_no > ArchiveMaxSize
            Archive_mem_ranks = RankingProcess(Archive_F, ArchiveMaxSize, obj_no);
            [Archive_X, Archive_F, Archive_mem_ranks, Archive_member_no] = HandleFullArchive(Archive_X, Archive_F, Archive_member_no, Archive_mem_ranks, ArchiveMaxSize);
        else
            Archive_mem_ranks = RankingProcess(Archive_F, ArchiveMaxSize, obj_no);
        end
        Archive_mem_ranks = RankingProcess(Archive_F, ArchiveMaxSize, obj_no);
        
        % Select attractor via roulette wheel
        index = RouletteWheelSelection(1 ./ Archive_mem_ranks);
        if index == -1
            index = 1;
        end
        Elite_fitness = Archive_F(index, :);
        Elite_position = Archive_X(index, :)';
        
        % Select random antlion from archive
        Random_antlion_fitness = Archive_F(1, :);
        Random_antlion_position = Archive_X(1, :)';
        
        % Update ant positions
        for i = 1:N
            % Generate random walks around random antlion and elite
            RA = Random_walk_around_antlion(dim, max_iter, lb, ub, Random_antlion_position', iter);
            RE = Random_walk_around_antlion(dim, max_iter, lb, ub, Elite_position', iter);
            
            % Update position
            Ant_Position(:, i) = (RE(iter, :)' + RA(iter, :)') / 2;
            
            % Boundary handling
            Flag4ub = Ant_Position(:, i) > ub';
            Flag4lb = Ant_Position(:, i) < lb';
            Ant_Position(:, i) = Ant_Position(:, i) .* (~(Flag4ub + Flag4lb)) + ub' .* Flag4ub + lb' .* Flag4lb;
        end
        
        % Display progress
        display(['At the iteration ', num2str(iter), ' there are ', num2str(Archive_member_no), ' non-dominated solutions in the archive']);
    end
    
    % Visualization
    figure;
    Draw_ZDT1();
    hold on;
    plot(Archive_F(:, 1), Archive_F(:, 2), 'ko', 'MarkerSize', 8, 'MarkerFaceColor', 'k');
    legend('True PF', 'Obtained PF');
    title('MALO');
    set(gcf, 'Position', [403 466 230 200]);
end

Note: The following functions are assumed to be pre-defined and do not need to be reimplemented: initialization, dominates, UpdateArchive, RankingProcess, HandleFullArchive, RouletteWheelSelection, Random_walk_around_antlion, Draw_ZDT1. The function strictly follows the logic of the original code, including random seed initialization, boundary handling, archive management, random walk generation, and visualization steps. The output Archive_X contains the positions of non-dominated solutions, and Archive_F contains their corresponding fitness values.
test_cases: rng(42)
correct = 81.407524;
val = sum(Archive_F(:));
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end
disp('Completely right!')

General solution:

General tests: