function [sFeat, Sf, Nf, curve] = jWOA(feat, label, N, max_Iter, HO)

% Whale Optimization Algorithm (WOA) for Feature Selection
% Inputs:
%   - feat: Feature matrix
%   - label: Class labels
%   - N: Population size
%   - max_Iter: Maximum iterations
%   - HO: Hold-out validation partition
% Outputs:
%   - sFeat: Selected features
%   - Sf: Indices of selected features
%   - Nf: Number of selected features
%   - curve: Convergence curve of best fitness

% Parameter Initialization
lb = 0; % Lower bound
ub = 1; % Upper bound
b = 1;  % Spiral movement parameter

dim = size(feat, 2); % Number of features
fun = @jFitnessFunction; % Fitness function

% Initialize search agents
X = lb + (ub - lb) * rand(N, dim);

% Initialize fitness values
fit = zeros(1, N);
fitG = inf; % Global best fitness

% Evaluate initial solutions
for i = 1:N
    fit(i) = fun(feat, label, (X(i, :) > 0.5), HO);
    if fit(i) < fitG
        fitG = fit(i); 
        Xgb = X(i, :); % Global best position
    end
end

curve = inf(1, max_Iter); % Initialize convergence curve

t = 1; % Iteration counter

% Main WOA optimization loop
while t <= max_Iter
    a = 2 - t * (2 / max_Iter); % Linearly decreasing parameter
    
    for i = 1:N
        A = 2 * a * rand() - a; % Exploration coefficient
        C = 2 * rand(); % Random coefficient
        p = rand(); % Probability factor
        l = -1 + 2 * rand(); % Random number in range [-1,1]

        if p < 0.5 % Exploration and exploitation phase
            if abs(A) < 1
                % Encircling prey (exploitation)
                for d = 1:dim
                    Dx = abs(C * Xgb(d) - X(i, d));
                    X(i, d) = Xgb(d) - A * Dx;
                end
            else
                % Searching for prey (exploration)
                k = randi([1, N]); % Select a random search agent
                for d = 1:dim
                    Dx = abs(C * X(k, d) - X(i, d));
                    X(i, d) = X(k, d) - A * Dx;
                end
            end
        else
            % Bubble-net attacking (spiral movement)
            for d = 1:dim
                dist = abs(Xgb(d) - X(i, d));
                X(i, d) = dist * exp(b * l) * cos(2 * pi * l) + Xgb(d);
            end
        end
        
        % Ensure boundaries are respected
        X(i, X(i, :) > ub) = ub;
        X(i, X(i, :) < lb) = lb;
    end
    
    % Evaluate new solutions
    for i = 1:N
        fit(i) = fun(feat, label, (X(i, :) > 0.5), HO);
        if fit(i) < fitG
            fitG = fit(i);
            Xgb = X(i, :);
        end
    end
    
    % Store best fitness in convergence curve
    curve(t) = fitG;
    t = t + 1;
end

% Extract selected features
Pos = 1:dim;
Sf = Pos((Xgb > 0.5) == 1);
Nf = length(Sf);
sFeat = feat(:, Sf); % Final selected feature subset

end
