function nn = nnbp(nn)
%NNBP performs backpropagation
% nn = nnbp(nn) returns an neural network structure with updated weights 
    
    n = nn.n;
    sparsityError = 0;

    [mm,mmm] = size(nn.a{2});
    [ww,www] = size(nn.W{2});

    switch nn.output
        case 'sigm'
            d{n} = - nn.e .* (nn.a{n} .* (1 - nn.a{n}));
        case {'softmax','linear'}
            d{n} = - nn.e;
    end
    for i = (n - 1) : -1 : 2
        % Derivative of the activation function
        switch nn.activation_function 
            case 'sigm'
                %d_act = (sign(nn.a{i}) +1)/2;
                d_act = nn.a{i}.*(1-nn.a{i});
            case 'tanh_opt'
                d_act = 1.7159 * 2/3 * (1 - 1/(1.7159)^2 * nn.a{i}.^2);
        end
        
        if(nn.nonSparsityPenalty>0)
            pi = repmat(nn.p{i}, size(nn.a{i}, 1), 1);
            sparsityError = [zeros(size(nn.a{i},1),1) nn.nonSparsityPenalty * (-nn.sparsityTarget ./ pi + (1 - nn.sparsityTarget) ./ (1 - pi))];
        end

        %sparsityError = 0;
        
        % Backpropagate first derivatives
        if i+1==n % in this case in d{n} there is not the bias term to be removed             
            d{i} = (d{i + 1} * nn.W{i} + sparsityError) .* d_act; %( Bishop (5.56)

            %d{i} = d{i + 1} * nn.W{i} + sparsityError;
        end
                   % in this case in d{i} the bias term has to be removed
        if i==2
            %da2 = (sign(nn.p{i}) +1)/2;
            %da2 = nn.p{i} .* (1 - nn.p{i});
            %da1 = (sign(nn.a{i}) +1)/2;
            da1 = nn.a{i+1} .* (1 - nn.a{i+1});
              
            ww = nn.ww;

            vv1 = ww(:,1);
            vv2 = ww(:,2:end);

            
            %scc = tarjan(vv2);
            vv2 = vv2';
            ww = [vv1,vv2];
            
            %ww = nn.W{i};
            pp = d{i+1};
            pp = pp(:,2:end);

            for k = 1:mm 

                daa = da1(k,:);
                z_G = pp;
                options = optimset('TolFun',0.0001);

                alpha = nn.alpha;
                wii = nn.Wii;

                wc = ww(:,2:end);
                scc = tarjan(wc);

                mx = max(nn.wflag);
                [Wii1,Wii2] = size(nn.Wii);
                z = zeros(1,Wii2);

                sucw = 1;
                tempsee = [];
                while sucw == 1
                    sucw = 0;
                    ppw = pp;
                    seew = find(sum(ww(:,2:end)) == 0);
                    seew = setdiff(seew,tempsee);

                    [seew1,seew2] = size(seew);

                    while seew2 > 0
                        fwIndices = seew;
                        tempsee = union(tempsee,fwIndices);

                        mw = zeros(1,www-1);
                        mw(fwIndices) = 1;
                        mww = mw;

                        whyw = size(mww);

                        ppw_gpu = gpuArray(ppw);
                        mww_gpu = gpuArray(mww);
                        ww_gpu = gpuArray(ww);

                        ppw_gpu = ppw_gpu.*mww_gpu*ww_gpu(:,2:end)';
                        ppw = gather(ppw_gpu);

                        [fw1,fw2] = size(fwIndices);

                          % 向量化改进版本
                        if fw2 > 0
                            rows = fwIndices(1, 1:fw2);  % 一次性获取所有需要置零的行索引
                            ww(rows, :) = 0;             % 单次操作完成所有行的置零
                        end
        
                        seew = find(sum(ww(:,2:end)) == 0);
                        seew = setdiff(seew,tempsee);
                        [seew1,seew2] = size(seew);
                        sucw = 1;
                    end

                    z = z + ppw;

                    [scc1, scc2] = size(scc);
             
                    sccflag = zeros(1,scc2);
      
                    wflag = zeros(1,www-1);
                    for scci = 1:scc2
                        scctemp = scc{scci};

                        wcwc = ww(:,2:end);
                        seewff = wcwc(scctemp,scctemp);

                        seews = sum(wcwc);
                        seewsf = seews(1,scctemp);

                        kan = seewsf-sum(seewff);
                        kankan = find(abs(kan) > 0.0001);
                               
                        if sum(seewsf-sum(seewff)) > 0.0001
                            continue
                        end
                          
                        scctempc = setdiff(scctemp,tempsee);
                        [scctempc1,scctempc2] = size(scctempc);
                        if scctempc2 > 0
                            sccflag(1,scci) = 1;
                        end


                        [scctemp1,scctemp2] = size(scctemp);

                        % 优化后代码
                        if scctemp2 > 0
                            % 一次性获取所有索引
                            indices = scctemp(1, 1:scctemp2);
                            
                            % 向量化更新 wflag
                            wflag(1, indices) = scci;
                            
                            % 向量化更新 Wii - 创建逻辑索引矩阵
                            Wii(indices, indices) = scctemp2;
                        end                        
                    end

                    mx = max(wflag);
                    zc = cell(1,mx);
                    parfor mi = 1:mx
                    %for mi = 1:mx
                        if sccflag(1,mi) == 0 || length(scc{mi}) == 1
                            continue
                        end

                        sucw = 1;
                        %disp(mi);
                        mvec = [0];
                        mpp = [1];
                        mdaa = daa(1,1);
                        [pp1,pp2] = size(wflag);
    
                        mcol = [];
                        miol = [];
                        for mj = 1:pp2
                            %disp(wflag(1,mj));
                            if mi == wflag(1,mj)
                                if mi == 19
                                    disp('here');
                                end
                                mvec = [mvec,mj];
                                mpp = [mpp,pp(1,mj)];
                                mdaa = [mdaa,daa(1,mj+1)];
                                mcol = [mcol;ww(mj,1)];
                                miol = [miol,wii(mj,1)];
                            end
                        end

                         %mpp = [1,mpp];
                         mvec(:,1) = [];
                         %mpp(:,1) = [];
    
                         [mc1,mc2] = size(mvec);
                         mww = zeros(mc2,mc2);
                         mwii = zeros(mc2,mc2);
                         
                        try
                            if mc2 > 0
                                % 验证索引范围
                                max_row = max(mvec(1, 1:mc2)) + 1;
                                max_col = max(mvec(1, 1:mc2)) + 1;
                                
                                if max_row > size(ww, 1) || max_col > size(ww, 2)
                                    error('ww矩阵索引越界: 需要[%d,%d], 实际[%d,%d]', ...
                                        max_row, max_col, size(ww,1), size(ww,2));
                                end
                                
                                if max_row > size(wii, 1) || max_col > size(wii, 2)
                                    error('wii矩阵索引越界: 需要[%d,%d], 实际[%d,%d]', ...
                                        max_row, max_col, size(wii,1), size(wii,2));
                                end
                                
                                % 高性能向量化实现
                                ww_rows = size(ww, 1);
                                wii_rows = size(wii, 1);
                                rows = mvec(1, 1:mc2);
                                cols = mvec(1, 1:mc2);
                                
                                % 使用bsxfun替代meshgrid（更内存高效）
                                row_vec = rows(:);
                                col_vec = cols(:);
                                row_mat = repmat(row_vec, 1, mc2);
                                col_mat = repmat(col_vec, 1, mc2)';
                                
                                % 计算线性索引
                                ww_idx = (col_mat + 1 - 1)*ww_rows + row_mat;
                                wii_idx = (col_mat - 1)*wii_rows + (row_mat + 1);
                                
                                % 获取数据
                                mww = ww(ww_idx);
                                mwii = wii(wii_idx);
                            else
                                mww = [];
                                mwii = [];
                            end
                        catch ME
                            % 提供详细错误信息
                            fprintf('矩阵操作错误: %s\n', ME.message);
                            fprintf('mc2 = %d, 矩阵大小: ww=[%d %d], wii=[%d %d]\n', ...
                                mc2, size(ww,1), size(ww,2), size(wii,1), size(wii,2));
                            rethrow(ME);
                        end

    
                         mww = [mcol, mww];
                         mwii = [miol; mwii];
    
                         %disp(mi);
                         %if mi == 19
                         %    disp('here');
                         %end

                         mz_G = mpp(:,2:end);

                         mpp_gpu = gpuArray(mpp);
                         mww_gpu = gpuArray(mww);
                         alpha_gpu = gpuArray(alpha);
                         mwii_gpu = gpuArray(mwii);
                         mdaa_gpu = gpuArray(mdaa);
                         mz_G_gpu = mz_G;
                         options_gpu = options;
                         %mz = fsolve(@(xx)root8d(xx,mpp_gpu,mww_gpu,mdaa_gpu,alpha_gpu,mwii_gpu), mz_G_gpu, options_gpu);
                         mz = fsolve(@(xx)root8d(xx,mpp,mww,mdaa,alpha,mwii), mz_G, options);
                                
                         %for mj = 1:mc2
                         %     z(1,mvec(1,mj)) = mz(1,mj);
                         %end
                         zc{mi} = mz;
                     end
    
                     %{
                     for mi = 1:mx
                         if mi == 296
                             disp('here');
                         end

                         mvec = [0];
                         [pp1,pp2] = size(wflag);
    
                         for mj = 1:pp2
                             if mi == wflag(1,mj)
                                 mvec = [mvec,mj];
                             end
                         end
                         mvec(:,1) = [];
                         [mc1,mc2] = size(mvec);
                                    
                         temppp = zc{mi};
                         [temppp1,temppp2] = size(temppp);

                         if temppp2 == 0
                             continue
                         end

                         for mj = 1:mc2
                             mz = zc{mi};
                             z(1,mvec(1,mj)) = mz(1,mj);
                         end

                         tempsee = union(tempsee,scc{mi});
                     end
                     %}
% 并行处理版本 (适用于mx > 10000)
if mx > 0
    % 预分配
    mvec = cell(1, mx);
    wflag_vec = wflag(1, :);
    
    % 并行构建索引映射
    parfor mi = 1:mx
        mvec{mi} = find(wflag_vec == mi);
    end
    
    % 批量处理zc数据
    all_scc = cell(1, mx);
    z_values = cell(1, mx);
    z_indices = cell(1, mx);
    
    parfor mi = 1:mx
        current_mvec = mvec{mi};
        mc2 = numel(current_mvec);
        temppp = zc{mi};
        temppp2 = numel(temppp);
        
        all_scc{mi} = scc{mi};
        
        if temppp2 > 0 && mc2 > 0
            assign_len = min(mc2, temppp2);
            z_values{mi} = temppp(1:assign_len);
            z_indices{mi} = current_mvec(1:assign_len);
        else
            z_values{mi} = [];
            z_indices{mi} = [];
        end
    end
    
    % 合并结果
    all_indices = [z_indices{:}];
    all_values = [z_values{:}];
    z(1, all_indices) = all_values;
    
    % 批量合并scc
    tempsee = unique([all_scc{:}]);
end

                     %for scci = 1:scc2
                     %    scctemp = scc{scci};
                     %    [scctemp1,scctemp2] = size(scctemp);
                     %    for sccj = 1:scctemp2
                     %        for scck = 1:scctemp2
                     %            ww(scctemp(1,sccj),scctemp(1,scck)) = 0;
                     %        end
                     %    end
                     %end 
for scci = 1:scc2
    % 统一转换为行向量
    nodes = scc{scci}(:)';  % 确保为行向量
    
    % 安全处理空分量
    if ~isempty(nodes)
        ww(nodes, nodes) = 0;
    end
end
                
                end
                % = fsolve(@(xx)root8d(xx,pp,ww,da1(k,:),alpha,wii), z_G, options);
                %nn.a{i}(k,:) = sigm(z);pp
                disp(k);
                disp(i);

                %d{i}(k,2:mmm) = z.*da1(1,2:mmm);
                d{i}(k,2:mmm) = z;
            end

            %if i == 3
                %nn.a{i} = nn.a{i} + nn.weightPenaltyL1 * sum(abs(nn.W{i - 1}')) + 1.0000e-08 * sum(abs(nn.W{i-1}') .* connect(nn.W{i-1}'));
                %[Wii, wflag] = connect_module2(abs(nn.W{i-1}'));
                %nn.Wii = connect_value(abs(nn.W{i-1}'), Wii, wflag);
                %nn.wflag = wflag;

                %nn.Wii = connect_module6(abs(nn.W{i-1}'));
                %nn.a{i} = nn.a{i} + nn.alpha * sum(abs(nn.W{i-1}') .* nn.Wii) + nn.weightPenaltyL1 * sum(abs(nn.W{i-1}')) + nn.weightPenaltyL2 * sum(nn.W{i-1}' .* nn.W{i-1}');
                %nn.a{i} = nn.a{i} + nn.weightPenaltyL1 * sum(abs(nn.W{i - 1}')) + 0 * sum(abs(nn.W{i-1}' .* nn.Wii));
            %else
                %nn.a{i} = nn.a{i} + nn.weightPenaltyL1 * sum(abs(nn.W{i - 1}'));
                %disp('ok');
            %end
        end
        
        if(nn.dropoutFraction>0)
            d{i} = d{i} .* [ones(size(d{i},1),1) nn.dropOutMask{i}];
        end

    end

    for i = 1 : (n - 1)
        if i+1==n
            nn.dW{i} = (d{i + 1}' * nn.a{i}) / size(d{i + 1}, 1);
        else
            if i== 1
                nn.dW{i} = (d{i + 1}(:,2:end)' * nn.a{i}) / size(d{i + 1}, 1); 
            else 
                if i == 2
                    %for j = 1:50
                    %    D = d{i + 1}(:,j+1)';
                    %    A = nn.a{i};
    
                        %D(:,j) = [];
                    %    A(:,j) = zeros(100,1);seros
        
                    %    nn.dW{i}(j,:) = D * A;
                    %end
                    %nn.dW{i} = nn.dW{i} / size(d{i + 1}, 1);
                    disp("bp");
                    disp(i);
    
                    %dw1=zeros(www-1,www);
                    %for j = 1:www-1
                    %    for k = 2:www
                    %        ap = nn.a{i+1};
                    %        ap(:,k) = zeros(mm,1);

                    %        dw1(k-1,:) = (d{i}(:,k)' * ap) / size(d{i}, 1);

                        %    if k == 2
                        %        ddw = dw1;
                        %    else
                        %        ddw = [ddw;dw1];
                        %    end
                    %    end
                    %end
                    % 优化后代码
                    if www > 1
                        A = nn.a{i+1};  % 原始激活值矩阵 (mm × www)
                        D = d{i};       % 梯度矩阵 (mm × www)
                        mm_val = size(A, 1);  % 样本数量
                        
                        % 预计算全矩阵乘积 (关键优化点)
                        full_product = D(:, 2:end)' * A;  % (www-1) × www
                        
                        % 计算需要减去的修正项
                        correction = zeros(www-1, www);
                        for k = 2:www
                            % 只需计算被置零列的贡献
                            correction(k-1, k) = D(:, k)' * A(:, k);
                        end
                        
                        % 向量化计算结果
                        dw1 = (full_product - correction) / mm_val;
                    end


                    %ddw = (d{i + 1}(:,2:end)' * nn.a{i}) / size(d{i + 1}, 1); 
                    dw = dw1;

                    %for wk=1:www-1
                    %    dw(wk,wk+1) = 0;
                    %end
                    % 最佳优化方案
                    if www > 1
                        % 获取矩阵行数
                        rowsk = size(dw,1);
                        
                        % 计算线性索引范围
                        start_idx = rowsk + 1;  % 第一个目标元素 (1,2)
                        end_idx = www * rowsk;  % 最后一个目标元素 (www-1, www)
                        
                        % 向量化置零
                        dw(start_idx:(rows+1):end_idx) = 0;
                    end
                    
    
                    %[dw1,dw2] = size(dw);
    
                    %nn.dW{i} = zeros(dw1,dw2);
                    nn.dW{i} = dw;

                    metaWi = nn.Wii;
                    [mw1, mw2] = size(metaWi);
                    Wij = metaWi';
                    %nn.dW{i} = nn.dW{i} + nn.alpha * sign(nn.W{i}) .* Wij + nn.weightPenaltyL1 * sign(nn.W{i}) + nn.weightPenaltyL2 * nn.W{i};
                    %disp(Wii2);
                    %[sWii1,sWii2] = size(Wii)
                    %disp(size(Wii));
                    wii22 = nn.Wii22;
                    nnd = nn.dW{i};
                    nnd200 = nnd(:,2:end);
                    nnd1 = nnd(:,1);


                    %nnd200 = nnd200 + alpha * sign(nnd200).*((wii22'*wii22)./nn.Wii66');
                    nnd200 = nnd200 + alpha * nnd200.*((wii22'*wii22)./nn.Wii66');
                    nn.dW{i} = [nnd1,nnd200];
                    %nn.dW{i} = nn.dW{i} + alpha * nn.W{i}.*Wij;
                    %nn.dW{i} = nn.dW{i} + alpha * sign(nn.W{i});
                    %.dW{i} = nn.dW{i};
                end
            end
        end
    end
end
