package com.aps.service.Algorithm;

import com.aps.common.util.FileHelper;
import com.aps.common.util.GlobalCacheUtil;
import com.aps.common.util.ProductionDeepCopyUtil;
import com.aps.entity.Algorithm.*;
import com.aps.entity.Algorithm.IDAndChildID.GroupResult;
import com.aps.entity.basic.*;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

/**
 * 变邻域搜索算法
 * 作者：佟礼
 * 时间：2026-03-17
 */
public class VariableNeighborhoodSearch {
    private final Random rnd = new Random();

    // ==================== 策略选择与轮换参数 ====================
    private static final int MAX_CONSECUTIVE_SAME_STRATEGY = 4;  // 同一策略最多连续使用次数，避免陷入局部最优
    private static final int MAX_NEIGHBORHOODS = 3;  // 使用的邻域数量（0-3：插单/交换/并行合并/重排）

    // ==================== 邻域搜索参数 ====================
    private static final double HIGH_PRIORITY_GROUP_PROBABILITY = 0.7;  // 优先选择高优先级工单的概率
    private static final int MAX_ATTEMPTS = 30;  // 每次邻域搜索最大尝试次数，减少无效搜索
    private static final int NEIGHBOR_SELECTION_TOP_K = 3;  // 每次选择K个候选工序进行操作

    // ==================== 工序移动参数 ====================
    private static final int MOVE_STEPS_MIN = 1;  // 工序移动最小步数
    private static final int MOVE_STEPS_MAX = 5;  // 工序移动最大步数
    private static final int NON_BOTTLENECK_MOVE_STEPS_MAX = 3;  // 非瓶颈设备工序移动最大步数

    // ==================== 随机邻域参数 ====================
    private static final int RANDOM_NEIGHBOR_TYPE_COUNT = 3;  // 随机邻域尝试次数

    // ==================== 策略成功率评分参数 ====================
    private static final double INITIAL_SUCCESS_RATE = 0.3;  // 新策略的初始成功率（未使用时的默认值）
    private static final double LOW_SUCCESS_RATE_THRESHOLD = 0.1;  // 低成功率阈值，低于此值需要额外探索奖励
    private static final int LOW_SUCCESS_RATE_MIN_TRIALS = 10;  // 低成功率判断的最小尝试次数
    private static final double EXPLORATION_BONUS_FOR_LOW_USE = 0.15;  // 低使用次数策略的探索奖励分
    private static final double EXPLORATION_BONUS_FOR_LOW_SUCCESS = 0.1;  // 低成功率策略的探索奖励分
    private static final double RANDOM_NOISE_FACTOR = 0.1;  // 策略排序时的随机扰动因子，避免陷入局部最优
    private static final double FORCE_ROTATE_PENALTY = 0.5;  // 强制轮换时的惩罚系数
    private static final double CHANGE_MACHINE_BONUS = 0.25;  // 策略1(换设备)的额外奖励：换设备是最可能产生大改进的策略

    // ==================== 瓶颈设备评分参数 ====================
    private static final double PERCENTILE_90 = 0.90;  // 计算瓶颈评分时使用的90分位数，避免极端值影响
    private static final double BOTTLENECK_MACHINE_BASE_SCORE = 10000;  // 瓶颈设备工序的基础评分，确保排在前面
    private static final double WAIT_TIME_WEIGHT = 30;  // 工序等待时间在瓶颈评分中的权重
    private static final double MACHINE_WAIT_TIME_WEIGHT = 30;  // 设备等待时间在瓶颈评分中的权重
    private static final double CRITICAL_PATH_WEIGHT_ON_BOTTLENECK = 25;  // 关键路径在瓶颈设备评分中的权重
    private static final double CRITICAL_PATH_WEIGHT_OFF_BOTTLENECK = 20;  // 关键路径在非瓶颈设备评分中的权重
    private static final double DELAY_CONTRIBUTION_WEIGHT_ON_BOTTLENECK = 15;  // 延迟贡献度在瓶颈设备评分中的权重
    private static final double DELAY_CONTRIBUTION_WEIGHT_OFF_BOTTLENECK = 10;  // 延迟贡献度在非瓶颈设备评分中的权重
    private static final double NORMALIZATION_CAP = 1.5;  // 归一化截断值，避免极端值过度影响

    // ==================== 日志与输出参数 ====================
    private static final int TOP_BOTTLENECK_OPS_TO_RETURN = 10;  // 返回的瓶颈工序数量
    private static final int TOP_MACHINES_TO_LOG = 5;  // 日志输出的设备数量
    private static final int MIN_USE_COUNT_FOR_EXPLORATION_BONUS = 5;  // 低使用次数判断的最小阈值

    // ==================== 改进判断参数 ====================
    private static final double SIGNIFICANT_IMPROVEMENT_THRESHOLD = 0.002; // 显著改进阈值：提高到0.01以减少无效搜索
    private static final int MAX_MINOR_IMPROVEMENTS = 5; // 最大连续微小改进次数，超过后提前终止

    // ==================== 设备选择多样性参数 ====================
    private static final double LOAD_BALANCE_WEIGHT = 0.5; // 负载均衡权重（越高越倾向低负载设备）
    private static final double DIVERSITY_WEIGHT = 0.4; // 设备选择多样性权重（越高越倾向选择次数少的设备）
    private static final double RANDOM_NOISE_FOR_MACHINE = 0.1; // 机器选择的随机扰动因子

    private static final int MAX_LOCAL_SEARCH_NEIGHBORS = 2; // 从5减少到2，大幅减少解码次数


    private List<Entry> allOperations;

    private FitnessCalculator fitnessCalculator;

    private  List<Order> orders;
    private  TreeMap<String, Material> materials;

    private  List<GroupResult> _entryRel;

    private Map<String, Entry> entrys;
    private  Map<Integer, Entry> entrybyids;

    // 预检查：是否有工序有多个机器选项
    private boolean hasMultipleMachineOptions = false;

    // 工序-设备选择频率：opKey(groupId_sequence) -> machineId -> 选择次数（用于鼓励设备选择多样性）
    private Map<String, Map<Long, Integer>> opMachineSelectFrequency = new HashMap<>();

    // 瓶颈设备选择频率：machineId -> 被当作"瓶颈设备"的次数（用于鼓励探索不同的设备）
    private Map<Long, Integer> bottleneckMachineFrequency = new HashMap<>();

    // 瓶颈工序选择频率：operationId -> 被当作"优化目标"的次数（用于鼓励探索不同的工序）
    private Map<Integer, Integer> bottleneckOpFrequency = new HashMap<>();

    // 策略成功率统计
    private int[] strategySuccessCount = new int[3];
    private int[] strategyTotalCount = new int[3];

    // 策略实际选择次数（被成功选中并使用），用于频率驱动的策略轮换
    private int[] strategySelectFrequency = new int[3];

    // 强制策略轮换：跟踪最后使用的策略
    private int lastUsedStrategy = -1;
    private int consecutiveSameStrategyCount = 0;

    // 缓存的深拷贝列表，用于解码优化
    private List<Machine> cachedMachines;
    private List<Order> cachedOrders;
    private List<GroupResult> cachedEntryRel;
    private TreeMap<String, Material> cachedMaterials;
    private List<Entry> cachedAllOperations;

    // CP-SAT 邻域需要的缓存
    private GeneticDecoder cpSatDecoder;
    private List<Machine> cpSatMachines;
    private ObjectiveWeights cpSatWeights;
    private boolean cpSatEnabled = false;

    /**
     * 启用 CP-SAT 邻域
     */
    public void enableCpSatNeighborhood(GeneticDecoder decoder, List<Machine> machines, ObjectiveWeights weights) {
        this.cpSatDecoder = decoder;
        this.cpSatMachines = machines;
        this.cpSatWeights = weights;
        this.cpSatEnabled = true;
        FileHelper.writeLogFile("[VNS-CpSat] CP-SAT 邻域已启用");
    }

    private  GeneticOperations geneticOperations;

    // 邻域结构成功率统计（用于 search() 方法）
    private static class NeighborhoodWithStats {
        NeighborhoodStructure structure;
        int successCount;
        int totalCount;

        NeighborhoodWithStats(NeighborhoodStructure structure) {
            this.structure = structure;
            this.successCount = 0;
            this.totalCount = 0;
        }

        double getSuccessRate() {
            return totalCount > 0 ? (double) successCount / totalCount : 0.5;
        }
    }

    private List<NeighborhoodWithStats> neighborhoodsWithStats;

    private int maxNoImproveRounds = 3;

    public void setMaxNoImproveRounds(int maxNoImproveRounds) {
        this.maxNoImproveRounds = maxNoImproveRounds;
    }

    public VariableNeighborhoodSearch( List<Entry> allOperations, List<Order> orders,
                                       TreeMap<String, Material> materials,List<GroupResult> entryRel,  FitnessCalculator fitnessCalculator) {
        this(allOperations, orders, materials, entryRel, fitnessCalculator, 3);
    }

    public VariableNeighborhoodSearch( List<Entry> allOperations, List<Order> orders,
                                       TreeMap<String, Material> materials,List<GroupResult> entryRel,
                                       FitnessCalculator fitnessCalculator, int maxNoImproveRounds) {
        this.maxNoImproveRounds = maxNoImproveRounds;
        this.allOperations = allOperations;
        this.orders = orders;
        this.materials = materials;

        _entryRel=entryRel;
        this.fitnessCalculator = fitnessCalculator;
        Map<Integer, Object> mp = buildEntryKey();

        entrys=(Map<String, Entry>)mp.get(1);
        entrybyids=(Map<Integer, Entry>)mp.get(2);

        // 预检查：是否有工序有多个机器选项
        for (Entry entry : allOperations) {
            if (entry.getMachineOptions() != null && entry.getMachineOptions().size() > 1) {
                hasMultipleMachineOptions = true;
                break;
            }
        }

        // 预缓存解码需要的深拷贝列表，避免重复拷贝
        cachedAllOperations = ProductionDeepCopyUtil.deepCopyList(new CopyOnWriteArrayList<>(allOperations), Entry.class);
        cachedOrders = ProductionDeepCopyUtil.deepCopyList(new CopyOnWriteArrayList<>(orders), Order.class);
        cachedEntryRel = ProductionDeepCopyUtil.deepCopyList(new CopyOnWriteArrayList<>(entryRel), GroupResult.class);
        cachedMaterials = ProductionDeepCopyUtil.deepCopyTreeMap(materials, String.class, Material.class);


        // 初始化邻域结构统计
        neighborhoodsWithStats = new ArrayList<>();
        List<NeighborhoodStructure> initialNeighborhoods = defineNeighborhoodsInternal();
        for (NeighborhoodStructure ns : initialNeighborhoods) {
            neighborhoodsWithStats.add(new NeighborhoodWithStats(ns));
        }
        geneticOperations=new GeneticOperations();
        //log("VariableNeighborhoodSearch初始化: hasMultipleMachineOptions=" + hasMultipleMachineOptions);
    }

    /**
     * 内部方法：定义邻域结构（不排序）
     */
    private List<NeighborhoodStructure> defineNeighborhoodsInternal() {
        List<NeighborhoodStructure> neighborhoods = new ArrayList<>();

        //瓶颈工序机器选择变异
        neighborhoods.add(new NeighborhoodStructure("SmartBottleneckChange", this::ChangeMachineForBottleneckOpWrapper));

        //瓶颈工序在相同设备上移动
        neighborhoods.add(new NeighborhoodStructure("moveBottleneckSameMachine", this::moveBottleneckSameMachineWrapper));

        //瓶颈工序往前移动
        neighborhoods.add(new NeighborhoodStructure("MoveBottleneckForward", this::moveBottleneckForwardWrapper));

        //非瓶颈工序往后移动
        neighborhoods.add(new NeighborhoodStructure("MoveNonBottleneckBackward", this::moveNonBottleneckBackwardWrapper));

        //瓶颈设备工序激进重排
        neighborhoods.add(new NeighborhoodStructure("AggressiveBottleneckReorder", this::aggressiveBottleneckReorderWrapper));

        //关键路径工序优化
        neighborhoods.add(new NeighborhoodStructure("CriticalPathOptimize", this::criticalPathOptimizeWrapper));
        //// 交换相同设备的两个工序
        neighborhoods.add(new NeighborhoodStructure("SwapSameMachine", this::generateSameMachineSwapNeighbor));

        // 交换两个工序的顺序
        neighborhoods.add(new NeighborhoodStructure("Swap", this::generateSwapNeighborWrapper));
        // 反转一个工序子序列
        neighborhoods.add(new NeighborhoodStructure("Reverse", this::generateReverseNeighborWrapper));
        // 插入一个工序到另一个位置
        neighborhoods.add(new NeighborhoodStructure("Insert", this::generateInsertNeighborWrapper));
        // 机器选择变异
        neighborhoods.add(new NeighborhoodStructure("MachineChange", this::generateMachineChangeNeighbor));

        // ==================== 新增激进变邻域方法 ====================

        // BlockMove - 移动工序块
        neighborhoods.add(new NeighborhoodStructure("BlockMove", this::blockMoveWrapper));

        // MultiOperationSwap - 一次交换多个工序
        neighborhoods.add(new NeighborhoodStructure("MultiOperationSwap", this::multiOperationSwapWrapper));

        // MultiMachineChange - 一次改变多个工序的机器选择
        neighborhoods.add(new NeighborhoodStructure("MultiMachineChange", this::multiMachineChangeWrapper));

        // HybridShake - 混合抖动：综合调整
        neighborhoods.add(new NeighborhoodStructure("HybridShake", this::hybridShakeWrapper));

        // CpSatLocalOptimize - CP-SAT 局部重优化（仅当启用时）
        neighborhoods.add(new NeighborhoodStructure("CpSatLocalOptimize", this::cpSatLocalOptimizeWrapper));

        return neighborhoods;
    }

    /**
     * 定义邻域结构（按成功率排序，CP-SAT 始终保留一个名额）
     */
    private List<NeighborhoodStructure> defineNeighborhoods() {
        // 按成功率排序
        List<NeighborhoodWithStats> sorted = new ArrayList<>(neighborhoodsWithStats);
        sorted.sort((a, b) -> Double.compare(b.getSuccessRate(), a.getSuccessRate()));

        List<NeighborhoodStructure> result = new ArrayList<>();

        // 始终保留 CP-SAT 邻域（避免因成功率低被挤出前 N 名后永远无法被选中）
        NeighborhoodWithStats cpSatNs = null;
        int maxNeighborhoods = Math.min(MAX_NEIGHBORHOODS, sorted.size());
        for (int i = 0; i < maxNeighborhoods; i++) {
            NeighborhoodWithStats ns = sorted.get(i);
            if ("CpSatLocalOptimize".equals(ns.structure.name)) {
                cpSatNs = ns;
            }
            result.add(ns.structure);
        }

        // 如果 CP-SAT 未被前 N 名选中且已启用，额外追加
        if (cpSatNs == null && cpSatEnabled) {
            for (NeighborhoodWithStats ns : neighborhoodsWithStats) {
                if ("CpSatLocalOptimize".equals(ns.structure.name)) {
                    result.add(ns.structure);
                    break;
                }
            }
        }

        return result;
    }

    /**
     * 记录邻域结构使用结果
     */
    private void recordNeighborhoodResult(NeighborhoodStructure structure, boolean success) {
        for (NeighborhoodWithStats ns : neighborhoodsWithStats) {
            if (ns.structure.equals(structure)) {
                ns.totalCount++;
                if (success) {
                    ns.successCount++;
                }
                break;
            }
        }
    }

    /**
     * 对种群中的每个个体进行变邻域搜索
     */
    public List<Chromosome> search(List<Chromosome> population, TabuSearch tabuSearch, GeneticDecoder decoder, List<Machine> machines) {
        List<Chromosome> improvedPopulation = new ArrayList<>();

        for (Chromosome chromosome : population) {
            Chromosome improvedChromosome = search(chromosome,tabuSearch, decoder, machines);
            improvedPopulation.add(improvedChromosome);
        }

        return improvedPopulation;
    }

    /**
     * 判断是否为显著改进（只有超过阈值的改进才重置无改进计数）
     */
    private boolean isSignificantImprovement(Chromosome newChromo, Chromosome oldChromo) {
        if (!isBetter(newChromo, oldChromo)) {
            return false;
        }
        double newFitness = newChromo.getFitness();
        double oldFitness = oldChromo.getFitness();
        return (newFitness - oldFitness) > SIGNIFICANT_IMPROVEMENT_THRESHOLD;
    }

    /**
     * 对单个个体进行变邻域搜索（通过 TabuSearch 共享禁忌表：渴望准则 + 概率劣解接受 + 时间预算）
     *
     * @param chromosome 初始解
     * @param tabuSearch 负责禁忌表生命周期（禁忌表、渴望准则、三粒度 key 检查）
     * @param decoder    解码
     * @param machines   机器列表
     */
    public Chromosome search(Chromosome chromosome, TabuSearch tabuSearch, GeneticDecoder decoder, List<Machine> machines) {
        log("变邻域搜索(共用禁忌表) - 开始执行",true);

        // 深拷贝当前染色体
        Chromosome current = lightCopy(chromosome);
        Chromosome best = copyChromosome(chromosome);

        writeKpi(best);

        // 记录初始KPI用于跟踪改进
        double[] initialFitnessLevel = best.getFitnessLevel().clone();
        double initialFitness = best.getFitness();

        // 提前结束参数
        int noImproveRoundCount = 0;
        int totalRounds = 0;
        int totalImprovements = 0;
        int totalSignificantImprovements = 0;
        int consecutiveMinorImprovements = 0;

        int k = 0;
        List<NeighborhoodStructure> neighborhoods = defineNeighborhoods();

        // 用于动态计算"显著改进"的参考 fitness（每次更新 best 后更新）
        double currentBestFitness = best.getFitness();
        // 时间预算：从现在起最多执行 TabuSearch.TS_TIME_BUDGET_MS
        long tsStartTimeMs = System.currentTimeMillis();
        long remainingBudgetMs = Math.max(5L * 60L * 1000L, TabuSearch.TS_TIME_BUDGET_MS / 2);
        // 估算最大迭代次数（与 TabuSearch 的融合版本保持一致）
        int sizeBasedMaxIter = Math.max(60, cachedAllOperations.size() / 50);
        int timeBasedMaxIter = (int) Math.max(30, remainingBudgetMs / TabuSearch.TS_PER_ITER_BUDGET_MS);
        int maxIterationsCap = Math.min(Math.max(60, sizeBasedMaxIter), Math.max(150, timeBasedMaxIter));

        while (noImproveRoundCount < maxNoImproveRounds && totalRounds < maxIterationsCap) {
            totalRounds++;
            boolean roundHadImprovement = false;

            // 检查时间预算
            long elapsedMs = System.currentTimeMillis() - tsStartTimeMs;
            if (elapsedMs > remainingBudgetMs) {
                log(String.format("变邻域搜索(融合禁忌) - 达到时间预算(耗时%.1fmin)，提前退出", elapsedMs / 60000.0));
                break;
            }

            // ============ 第一阶段：瓶颈感知策略 ============
            for (int strategyAttempt = 0; strategyAttempt < 3; strategyAttempt++) {
                geneticOperations.DelOrder(current);

                Chromosome neighbor = generateNeighbor(current);
                if (neighbor == null) continue;

                // ---- 禁忌检查：命中则直接跳过，不解码 ----
                boolean tabuHit = tabuSearch.isChromosomeTabu(neighbor);
                boolean sameAsCurrent = (neighbor.getGeneStr() != null &&
                        neighbor.getGeneStr().equals(current.getGeneStr()));
                if (sameAsCurrent) {
                    tabuSearch.addChromosomeToTabu(neighbor);
                    continue;
                }

                // 局部搜索
                Chromosome localBest = localSearch(neighbor, decoder, machines);
                // 产生邻居后，加入禁忌表（无论最终是否接受，避免反复返回同样的邻居）
                tabuSearch.addChromosomeToTabu(localBest);

                // ============ 接受逻辑（融合 TS 渴望准则 + 概率劣解） ============
                boolean betterThanBest = isBetter(localBest, best);
                boolean betterThanCurrent = isBetter(localBest, current);

                boolean accept;
                if (betterThanBest) {
                    // 比 best 好：无条件接受（渴望准则），即使命中禁忌也接受
                    accept = true;
                } else if (!tabuHit && betterThanCurrent) {
                    // 非禁忌且比 current 好：接受
                    accept = true;
                } else if (!tabuHit) {
                    // 非禁忌但劣解：按概率接受（随迭代降低）
                    double progress = Math.min(1.0, (double) totalRounds / (double) Math.max(30, maxIterationsCap));
                    double acceptProb = TabuSearch.WORSE_ACCEPT_PROB_START - (TabuSearch.WORSE_ACCEPT_PROB_START - TabuSearch.WORSE_ACCEPT_PROB_MIN) * progress;
                    accept = rnd.nextDouble() < acceptProb;
                } else {
                    // 禁忌且劣于 best：拒绝
                    accept = false;
                }

                if (accept) {
                    current = lightCopy(localBest);
                    if (betterThanBest) {
                        best = lightCopy(localBest);
                        writeKpi(best);
                        totalImprovements++;
                        roundHadImprovement = true;
                        double delta = best.getFitness() - currentBestFitness;
                        if (delta > TabuSearch.SIGNIFICANT_IMPROVEMENT_THRESHOLD) {
                            noImproveRoundCount = 0;
                            consecutiveMinorImprovements = 0;
                            totalSignificantImprovements++;
                            currentBestFitness = best.getFitness();
                            logVNSImprovement(best, initialFitnessLevel, initialFitness, totalRounds, "BottleneckStrategy(显著)");
                            log(String.format("变邻域搜索(融合禁忌) - 瓶颈策略成功(显著), 轮次=%d, fitness=%.12f",
                                    totalRounds, best.getFitness()), true);
                            break;
                        } else {
                            // 微小改进
                            if (delta > TabuSearch.MINOR_IMPROVEMENT_THRESHOLD) {
                                noImproveRoundCount = 0;
                                currentBestFitness = best.getFitness();
                            }
                            consecutiveMinorImprovements++;
                            log(String.format("变邻域搜索(融合禁忌) - 瓶颈策略成功(微小), 轮次=%d, fitness=%.12f, delta=%.2e",
                                    totalRounds, best.getFitness(), delta), true);
                        }
                    }
                }
            }

            // ============ 第二阶段：简单邻域补充（策略多样化） ============
            if (!roundHadImprovement) {
                geneticOperations.DelOrder(current);
                NeighborhoodStructure neighborhood = neighborhoods.get(k);

                Chromosome neighbor = generateNeighbor(current, neighborhood);
                if (neighbor != null) {
                    // 若连续多轮无改进，额外做点工序级扰动，增加探索能力
                    if (noImproveRoundCount >= 2) {
                        Chromosome shuffled = tryShuffleOperationPart(neighbor);
                        if (shuffled != null) neighbor = shuffled;
                    }

                    boolean tabuHit = tabuSearch.isChromosomeTabu(neighbor);
                    if (!tabuHit) {
                        Chromosome localBest = localSearch(neighbor, decoder, machines);
                        tabuSearch.addChromosomeToTabu(localBest);

                        boolean betterThanBest = isBetter(localBest, best);
                        boolean betterThanCurrent = isBetter(localBest, current);
                        boolean acceptLocal;
                        if (betterThanBest) {
                            acceptLocal = true;
                        } else if (!tabuHit && betterThanCurrent) {
                            acceptLocal = true;
                        } else if (!tabuHit) {
                            double progress = Math.min(1.0, (double) totalRounds / (double) Math.max(30, maxIterationsCap));
                            double p = TabuSearch.WORSE_ACCEPT_PROB_START - (TabuSearch.WORSE_ACCEPT_PROB_START - TabuSearch.WORSE_ACCEPT_PROB_MIN) * progress;
                            acceptLocal = rnd.nextDouble() < p;
                        } else {
                            acceptLocal = false;
                        }

                        if (acceptLocal) {
                            current = ProductionDeepCopyUtil.deepCopy(localBest, Chromosome.class);
                            if (betterThanBest) {
                                best = ProductionDeepCopyUtil.deepCopy(localBest, Chromosome.class);
                                writeKpi(best);
                                totalImprovements++;
                                roundHadImprovement = true;
                                double delta = best.getFitness() - currentBestFitness;
                                if (delta > TabuSearch.SIGNIFICANT_IMPROVEMENT_THRESHOLD) {
                                    noImproveRoundCount = 0;
                                    consecutiveMinorImprovements = 0;
                                    totalSignificantImprovements++;
                                    currentBestFitness = best.getFitness();
                                    logVNSImprovement(best, initialFitnessLevel, initialFitness, totalRounds, neighborhood.name + "(显著)");
                                    log(String.format("变邻域搜索(融合禁忌) - 邻域成功(显著): %s, fitness=%.12f",
                                            neighborhood.name, best.getFitness()), true);
                                } else {
                                    if (delta > TabuSearch.MINOR_IMPROVEMENT_THRESHOLD) {
                                        noImproveRoundCount = 0;
                                        currentBestFitness = best.getFitness();
                                    }
                                    consecutiveMinorImprovements++;
                                    log(String.format("变邻域搜索(融合禁忌) - 邻域成功(微小): %s, fitness=%.12f",
                                            neighborhood.name, best.getFitness()), true);
                                }
                            }
                        }
                    }
                }

                k++;
                if (k >= neighborhoods.size()) k = 0;
            }

            // 轮次结束：若无改进则增加计数
            if (!roundHadImprovement) {
                noImproveRoundCount++;
                log(String.format("变邻域搜索(融合禁忌) - 轮次%d无改进, 连续无改进=%d/%d",
                        totalRounds, noImproveRoundCount, maxNoImproveRounds));
            }

            if (noImproveRoundCount >= maxNoImproveRounds) {
                log(String.format("变邻域搜索(融合禁忌) - 提前结束: 连续%d轮无改进, 总轮次=%d",
                        maxNoImproveRounds, totalRounds));
                logVNSFinalSummary(best, initialFitnessLevel, initialFitness, totalRounds, totalImprovements, totalSignificantImprovements);
                break;
            }
        }

        logVNSFinalSummary(best, initialFitnessLevel, initialFitness, totalRounds, totalImprovements, totalSignificantImprovements);
        log(String.format("变邻域搜索(融合禁忌) - 结束, 总轮次=%d", totalRounds), true);

        decode(decoder, best, machines);
        return best;
    }

    /**
     * 记录变邻域搜索改进详情
     */
    private void logVNSImprovement(Chromosome best, double[] initialFitnessLevel, double initialFitness,
                                   int round, String neighborhoodName) {
        StringBuilder sb = new StringBuilder("变邻域搜索 - 改进详情: 轮次" + round + ", 邻域=" + neighborhoodName + ", ");
        double[] currentFitness = best.getFitnessLevel();

        // 处理null或空数组的情况
        if (currentFitness != null && currentFitness.length > 0 &&
                initialFitnessLevel != null && initialFitnessLevel.length > 0) {
            int minLength = Math.min(currentFitness.length, initialFitnessLevel.length);
            for (int i = 0; i < minLength; i++) {
                double improvement = currentFitness[i] - initialFitnessLevel[i];
                sb.append(String.format("KPI%d: %.4f→%.4f(+%.4f) ", i+1, initialFitnessLevel[i], currentFitness[i], improvement));
            }
        } else {
            sb.append("(KPI数据不可用) ");
        }

        double totalImprovement = best.getFitness() - initialFitness;
        sb.append(String.format("总Fitness: %.4f→%.4f(+%.4f)", initialFitness, best.getFitness(), totalImprovement));
        log(sb.toString(),true);
    }

    /**
     * 记录变邻域搜索最终总结
     */
    private void logVNSFinalSummary(Chromosome best, double[] initialFitnessLevel, double initialFitness,
                                    int totalRounds, int totalImprovements, int totalSignificantImprovements) {
        StringBuilder sb = new StringBuilder("变邻域搜索 - 最终总结: ");
        double[] currentFitness = best.getFitnessLevel();

        sb.append(String.format("总轮次%d次, 成功改进%d次(显著%d次), 改进率%.2f%%. ",
                totalRounds, totalImprovements, totalSignificantImprovements,
                totalRounds > 0 ? (double)totalImprovements / totalRounds * 100 : 0));

        // 记录各邻域结构的成功率
        sb.append("邻域成功率: ");
        for (NeighborhoodWithStats ns : neighborhoodsWithStats) {
            double rate = ns.getSuccessRate();
            sb.append(String.format("[%s: %d/%d(%.1f%%)] ",
                    ns.structure.name, ns.successCount, ns.totalCount, rate * 100));
        }
        sb.append("\n");

        // 记录KPI改进
        if (currentFitness != null && currentFitness.length > 0 &&
                initialFitnessLevel != null && initialFitnessLevel.length > 0) {
            int minLength = Math.min(currentFitness.length, initialFitnessLevel.length);
            for (int i = 0; i < minLength; i++) {
                double improvement = currentFitness[i] - initialFitnessLevel[i];
                sb.append(String.format("KPI%d: %.4f→%.4f(%.2f%%) ", i+1, initialFitnessLevel[i], currentFitness[i],
                        initialFitnessLevel[i] > 0 ? improvement / initialFitnessLevel[i] * 100 : 0));
            }
        } else {
            sb.append("(KPI数据不可用) ");
        }

        double totalImprovement = best.getFitness() - initialFitness;
        sb.append(String.format("总Fitness: %.4f→%.4f(%.2f%%)", initialFitness, best.getFitness(),
                initialFitness > 0 ? totalImprovement / initialFitness * 100 : 0));
        log(sb.toString());
    }

    private  void  writeKpi(Chromosome chromosome) {
        String fitness = "";
        double[] fitness1 = chromosome.getFitnessLevel();
        if (fitness1 != null) {
            for (int i = 0; i < fitness1.length; i++) {
                fitness += fitness1[i] + ",";
            }
        } else {
            fitness = "null (未计算)";
        }

        log(String.format("变邻域搜索 - kpi：%s", fitness),true);
        if(chromosome.getMakespan()!=0) {
            log(String.format("变邻域搜索 - kpi-Makespan: %f",  chromosome.getMakespan()));
        }
        if(chromosome.getDelayTime()!=0) {
            log(String.format("变邻域搜索 - kpi-DelayTime: %f",  chromosome.getDelayTime()));
        }
        if(chromosome.getTotalChangeoverTime()!=0) {

            log(String.format("变邻域搜索 - kpi-ChangeoverTime: %f", chromosome.getTotalChangeoverTime()));
        }
        if(chromosome.getMachineLoadStd()!=0) {
            log(String.format("变邻域搜索 - kpi-MachineLoad: %f", chromosome.getMachineLoadStd()));
        }
        if(chromosome.getTotalFlowTime()!=0) {
            log(String.format("变邻域搜索 - kpi-FlowTime: %f",chromosome.getTotalFlowTime()));
        }

        // ==================== 打印各 KPI 的 Gap ====================
        log(KpiLowerBoundCalculator.generateGapReport(chromosome));

    }

    /**
     * 定义邻域结构
     */
    private Chromosome generateNeighbor(Chromosome chromosome, NeighborhoodStructure neighborhood) {
        return neighborhood.apply(chromosome);
    }
    /**
     * 生成邻域解 - 智能策略：优先处理瓶颈工序/设备
     * 策略：
     * 1. 优先处理瓶颈设备上的工序（换设备）
     * 2. 瓶颈设备上的工序往前移动
     * 3. 非瓶颈设备上的工序往后移动（给瓶颈工序腾位置）
     */
    public Chromosome generateNeighbor(Chromosome chromosome) {
        List<GAScheduleResult> results = chromosome.getResult().stream().
                filter(t->!t.getCapacityTypeName().equals("Infinite"))
                .collect(Collectors.toList());

        // 构建位置索引
        Map<String, Integer> positionIndex = buildPositionIndex(chromosome);
        Map<Integer, Object> obj = buildPositionToEntryIndex(chromosome);
        Map<Integer, Entry> positionToEntryIndex =(Map<Integer, Entry>)obj.get(1);
        List<List<Integer>> positionByPriority = (List<List<Integer>>)obj.get(2);

        Map<String, Integer> MachinePositionIndex = buildEntryMachinePositionIndex(chromosome);

        if (results == null || results.isEmpty()) {
            log("generateNeighbor: results为空，使用随机邻域");
            return generateRandomNeighbor(chromosome,positionToEntryIndex,positionByPriority);
        }

        // 1. 找出瓶颈设备和关键工序
        Map<String, Object> bottleneckAnalysis = findBottleneckMachineWithDetails(chromosome);
        Long bottleneckMachineId = (Long) bottleneckAnalysis.get("bottleneckMachineId");
        List<GAScheduleResult> criticalOps = (List<GAScheduleResult>) bottleneckAnalysis.get("criticalOps");
        logBottleneckAnalysis(bottleneckAnalysis);

        if (bottleneckMachineId != null && criticalOps != null && !criticalOps.isEmpty()) {
            if (rnd.nextDouble() < 0.8) { // 增加使用智能策略的概率
                // 构建策略顺序，考虑成功率
                List<Integer> strategyOrder = buildStrategyOrder();
                log(String.format("瓶颈设备-策略顺序=%s, 关键工序数=%d", strategyOrder, criticalOps.size()), true);

                Chromosome result = null;

                for (int attempt = 0; attempt < strategyOrder.size(); attempt++) {
                    int strategyIndex = strategyOrder.get(attempt);

                    // 如果没有多个机器选项，跳过策略1
                    if (strategyIndex == 0 && !hasMultipleMachineOptions) {
                        log(String.format("跳过%d/3: 策略1-无多机器选项", attempt + 1));
                        continue;
                    }

                    strategyTotalCount[strategyIndex]++;

                    if(strategyIndex == 0) {
                        log(String.format("尝试%d/3: 策略1-关键工序换设备", attempt + 1));
                        result = tryChangeMachineForBottleneckOp(chromosome, criticalOps, MachinePositionIndex, positionToEntryIndex, positionByPriority);
                    } else if(strategyIndex == 1) {
                        log(String.format("尝试%d/3: 策略2-关键工序往前移动", attempt + 1));
                        result = tryMoveBottleneckOpForward(chromosome, criticalOps, positionIndex, positionByPriority,positionToEntryIndex,MachinePositionIndex,false);
                    } else {
                        log(String.format("尝试%d/3: 策略3-相同设备工序交换", attempt + 1));
                        result = tryMoveBottleneckOpForward(chromosome, criticalOps, positionIndex, positionByPriority,positionToEntryIndex,MachinePositionIndex,true);
                    }

                    if (result != null) {
                        strategySuccessCount[strategyIndex]++;
                        strategySelectFrequency[strategyIndex]++;  // 记录策略被成功使用的次数

                        // 更新策略使用跟踪信息
                        if (strategyIndex == lastUsedStrategy) {
                            consecutiveSameStrategyCount++;
                        } else {
                            lastUsedStrategy = strategyIndex;
                            consecutiveSameStrategyCount = 1;
                        }

                        logStrategyStats();
                        log(String.format("策略成功，使用策略%d (连续%d次)", strategyIndex + 1, consecutiveSameStrategyCount), true);
                        return result;
                    }
                    log("当前策略失败，尝试下一个...", false);
                }

                log("所有瓶颈策略都失败，使用随机邻域", false);
            }
        } else {
            log("没有找到瓶颈设备或关键工序", false);
        }

        log("使用随机邻域", false);
        return generateRandomNeighbor(chromosome,positionToEntryIndex,positionByPriority);
    }

    /**
     * 识别瓶颈设备及关键工序（更精准的分析）
     * 优先选择订单数多的优先级组的工序
     */
    private Map<String, Object> findBottleneckMachineWithDetails(Chromosome chromosome) {
        Map<String, Object> result = new HashMap<>();
        List<GAScheduleResult> allResults = chromosome.getResult().stream().filter(t->!t.getCapacityTypeName().equals("Infinite")).collect(Collectors.toList());
        Map<Long, Double> utilization = calculateMachineUtilization(chromosome,false);
        Map<Long, List<GAScheduleResult>> machineOps = allResults != null ?
                allResults.stream().collect(Collectors.groupingBy(GAScheduleResult::getMachineId)) :
                new HashMap<>();

        if (utilization.isEmpty()) {
            result.put("bottleneckMachineId", null);
            result.put("criticalOps", new ArrayList<GAScheduleResult>());
            result.put("allResults", allResults);
            return result;
        }

        // === 频率驱动的瓶颈设备选择 ===
        // 不再总是选利用率最高的，而是给利用率高+历史被选次数少的设备更高评分
        List<Map.Entry<Long, Double>> machineEntries = new ArrayList<>(utilization.entrySet());
        machineEntries.sort((a, b) -> Double.compare(b.getValue(), a.getValue()));

        // 第一步：筛选出真正的"瓶颈候选"设备
        // 必须满足：利用率 >= 50%（如果符合条件的少于3台，降至40%）
        double minUtilThreshold = 0.50;
        List<Map.Entry<Long, Double>> bottleneckCandidates = new ArrayList<>();
        for (Map.Entry<Long, Double> entry : machineEntries) {
            if (entry.getValue() >= minUtilThreshold) {
                bottleneckCandidates.add(entry);
            }
        }
        // 如果候选太少，放宽到40%
        if (bottleneckCandidates.size() < 3) {
            bottleneckCandidates.clear();
            minUtilThreshold = 0.40;
            for (Map.Entry<Long, Double> entry : machineEntries) {
                if (entry.getValue() >= minUtilThreshold) {
                    bottleneckCandidates.add(entry);
                }
            }
        }
        // 再次兜底：如果还不够3台，直接取利用率最高的3台
        if (bottleneckCandidates.size() < 3) {
            bottleneckCandidates = new ArrayList<>(machineEntries.subList(0, Math.min(3, machineEntries.size())));
            minUtilThreshold = bottleneckCandidates.isEmpty() ? 0 : bottleneckCandidates.get(bottleneckCandidates.size() - 1).getValue();
        }

        // 第二步：取候选池中前topN（不超过总数30%，但至少3台、最多8台）
        int maxCandidates = Math.min(8, Math.max(3, Math.min(bottleneckCandidates.size(),
                (int) Math.ceil(machineEntries.size() * 0.3))));
        List<Map.Entry<Long, Double>> topMachines = bottleneckCandidates.subList(0, Math.min(maxCandidates, bottleneckCandidates.size()));

        // 给每个候选设备计算综合评分（利用率 + 频率多样性）
        double maxUtil = topMachines.get(0).getValue();
        double minUtil = topMachines.get(topMachines.size() - 1).getValue();
        double utilRange = Math.max(0.01, maxUtil - minUtil);

        // 计算候选设备中的最大频率，用于归一化判断
        int maxFreq = 1;
        for (Map.Entry<Long, Double> entry : topMachines) {
            int freq = bottleneckMachineFrequency.getOrDefault(entry.getKey(), 0);
            maxFreq = Math.max(maxFreq, freq);
        }

        List<Object[]> scoredMachines = new ArrayList<>();
        for (Map.Entry<Long, Double> entry : topMachines) {
            Long machineId = entry.getKey();
            double util = entry.getValue();
            int freq = bottleneckMachineFrequency.getOrDefault(machineId, 0);

            // 归一化评分
            double normalizedUtil = (util - minUtil) / utilRange;  // 0~1

            // 改进的频率评分：使用更强的非线性衰减，前2次影响小，之后指数增强
            // 0次→1.0, 2次→0.36, 4次→0.13, 6次→0.05
            double diversityScore = Math.pow(0.6, freq);

            // 根据利用率差距和频率动态调整权重
            double utilGapRatio = utilRange;  // 0~1
            double utilizationWeight;
            double diversityWeight;

            // 频率驱动的权重：被选次数越多，多样性权重越大
            // 利用率差距驱动：差距越大，利用率权重越大
            // 综合两个因素：
            if (freq >= 4) {
                // 被选次数非常多 - 强制让给其他设备
                utilizationWeight = 0.30;
                diversityWeight = 0.70;
            } else if (freq >= 2 && maxFreq >= 3) {
                // 中高频率：显著增加多样性权重
                utilizationWeight = 0.40;
                diversityWeight = 0.60;
            } else if (utilGapRatio < 0.2) {
                // 利用率差距小（20%以内）：多样性更重要
                utilizationWeight = 0.35;
                diversityWeight = 0.65;
            } else if (utilGapRatio < 0.4) {
                // 利用率差距中等
                utilizationWeight = 0.50;
                diversityWeight = 0.50;
            } else {
                // 利用率差距大，且频率低：以利用率为主
                utilizationWeight = 0.65;
                diversityWeight = 0.35;
            }

            // 综合评分：动态权重 + 小随机扰动
            double score = utilizationWeight * normalizedUtil + diversityWeight * diversityScore + 0.1 * rnd.nextDouble();

            scoredMachines.add(new Object[]{machineId, score, util, freq, utilizationWeight, diversityWeight});
        }

        // 按综合评分降序排序
        scoredMachines.sort((a, b) -> Double.compare((Double) b[1], (Double) a[1]));

        // 70%选评分最高的，30%按加权随机
        Long selectedMachineId;
        if (rnd.nextDouble() < 0.7 || scoredMachines.size() <= 1) {
            selectedMachineId = (Long) scoredMachines.get(0)[0];
        } else {
            // 加权轮盘赌
            double totalScore = 0;
            for (Object[] m : scoredMachines) {
                totalScore += (Double) m[1];
            }
            double r = rnd.nextDouble() * totalScore;
            double cumSum = 0;
            selectedMachineId = (Long) scoredMachines.get(scoredMachines.size() - 1)[0];
            for (Object[] m : scoredMachines) {
                cumSum += (Double) m[1];
                if (r <= cumSum) {
                    selectedMachineId = (Long) m[0];
                    break;
                }
            }
        }

        // 更新该设备被选为瓶颈设备的频率
        bottleneckMachineFrequency.merge(selectedMachineId, 1, Integer::sum);

        // === 日志：输出瓶颈设备选择决策（enableLogging=true）===
        StringBuilder bottleneckLog = new StringBuilder();
        bottleneckLog.append(String.format("[瓶颈设备选择] 选中=设备%d(利用率=%.2f%%, 历史被选次数=%d) | 利用率差距=%.2f%%, 候选%d台:",
                selectedMachineId,
                utilization.getOrDefault(selectedMachineId, 0.0) * 100,
                bottleneckMachineFrequency.getOrDefault(selectedMachineId, 0),
                utilRange * 100,
                scoredMachines.size()));
        for (int i = 0; i < Math.min(5, scoredMachines.size()); i++) {
            Object[] m = scoredMachines.get(i);
            Long mid = (Long) m[0];
            double score = (Double) m[1];
            double util = (Double) m[2];
            int freq = (Integer) m[3];
            double uw = (Double) m[4];  // utilizationWeight
            double dw = (Double) m[5];  // diversityWeight
            bottleneckLog.append(String.format(" 设备%d(评分=%.3f, 利用率=%.2f%%, 次数=%d, 权重=util%.2f/div%.2f)%s",
                    mid, score, util * 100, freq, uw, dw,
                    mid.equals(selectedMachineId) ? "←选中" : (i == 0 ? "←最高评分" : "")));
        }
        log(bottleneckLog.toString(), true);

        Long bottleneckMachineId = selectedMachineId;

        result.put("bottleneckMachineId", bottleneckMachineId);
        result.put("utilization", utilization);
        result.put("allResults", allResults);

        // 找出关键工序：瓶颈设备上的工序 + 延迟订单的工序
        List<GAScheduleResult> criticalOps = new ArrayList<>();
        if (bottleneckMachineId != null) {
            criticalOps.addAll(machineOps.getOrDefault(bottleneckMachineId, new ArrayList<>()));
        }

        // 找出延迟的订单工序
        List<GAScheduleResult> delayedOps = findDelayedOperations(chromosome);
        criticalOps.addAll(delayedOps);

        // 去重
        Set<Integer> seenOpIds = new HashSet<>();
        List<GAScheduleResult> uniqueCriticalOps = new ArrayList<>();
        for (GAScheduleResult op : criticalOps) {
            if (!seenOpIds.contains(op.getOperationId())) {
                seenOpIds.add(op.getOperationId());
                uniqueCriticalOps.add(op);
            }
        }

        // 优先选择订单数多的优先级组的工序
        if (!uniqueCriticalOps.isEmpty()) {
            // 构建优先级->订单数的映射
            Map<Double, Set<Integer>> priorityToGroupIds = new HashMap<>();
            for (GAScheduleResult op : uniqueCriticalOps) {
                Entry entry = entrybyids.get(op.getOperationId());
                if (entry != null) {
                    double priority = entry.getPriority();
                    priorityToGroupIds.computeIfAbsent(priority, k -> new HashSet<>()).add(op.getGroupId());
                }
            }

            // 按订单数从多到少排序关键工序
            uniqueCriticalOps.sort((op1, op2) -> {
                Entry entry1 = entrybyids.get(op1.getOperationId());
                Entry entry2 = entrybyids.get(op2.getOperationId());

                if (entry1 == null && entry2 == null) {
                    return 0;
                }
                if (entry1 == null) {
                    return 1;
                }
                if (entry2 == null) {
                    return -1;
                }

                int size1 = priorityToGroupIds.getOrDefault(entry1.getPriority(), new HashSet<>()).size();
                int size2 = priorityToGroupIds.getOrDefault(entry2.getPriority(), new HashSet<>()).size();

                // 订单数多的优先级排前面
                int sizeCompare = Integer.compare(size2, size1);
                if (sizeCompare != 0) {
                    return sizeCompare;
                }

                // 订单数相同时，按优先级排序
                return Double.compare(entry1.getPriority(), entry2.getPriority());
            });
        }

        result.put("criticalOps", uniqueCriticalOps);
        result.put("delayedOps", delayedOps);

        return result;
    }

    /**
     * 找出延迟的工序
     */
    private List<GAScheduleResult> findDelayedOperations(Chromosome chromosome) {
        List<GAScheduleResult> delayedOps = new ArrayList<>();
        List<GAScheduleResult> results = chromosome.getResult().stream().filter(t->!t.getCapacityTypeName().equals("Infinite")).collect(Collectors.toList());

        if (results == null || results.isEmpty()) {
            return delayedOps;
        }

        // 按订单分组，计算订单完成时间
        Map<Integer, Integer> orderCompletionTimes = new HashMap<>();
        for (GAScheduleResult result : results) {
            int groupId = result.getGroupId();
            int endTime = result.getEndTime();
            orderCompletionTimes.put(groupId, Math.max(orderCompletionTimes.getOrDefault(groupId, 0), endTime));
        }

        // 找出完成时间较晚的订单（超过平均完成时间的1.5倍）
        if (!orderCompletionTimes.isEmpty()) {
            double avgCompletionTime = orderCompletionTimes.values().stream()
                    .mapToInt(Integer::intValue)
                    .average()
                    .orElse(0);

            double threshold = avgCompletionTime * 1.5;
            Set<Integer> delayedOrderIds = orderCompletionTimes.entrySet().stream()
                    .filter(e -> e.getValue() > threshold)
                    .map(Map.Entry::getKey)
                    .collect(Collectors.toSet());

            // 收集这些延迟订单的工序
            for (GAScheduleResult result : results) {
                if (delayedOrderIds.contains(result.getGroupId())&&!result.getCapacityTypeName().equals("Infinite")) {
                    delayedOps.add(result);
                }
            }
        }

        return delayedOps;
    }

    /**
     * 瓶颈工序分析结果类
     */
    private static class BottleneckOperationAnalysis {
        GAScheduleResult operation;
        double bottleneckScore; // 瓶颈评分（越高越可能是瓶颈）
        int waitTime; // 工序等待时间（前一道工序结束到本工序开始）
        int machineWaitTime; // 设备等待时间（设备上一道工序结束到本工序开始）
        boolean onCriticalPath; // 是否在关键路径上
        double delayContribution; // 延迟贡献度

        BottleneckOperationAnalysis(GAScheduleResult op) {
            this.operation = op;
            this.bottleneckScore = 0;
            this.waitTime = 0;
            this.machineWaitTime = 0;
            this.onCriticalPath = false;
            this.delayContribution = 0;
        }
    }

    /**
     * 记录瓶颈分析详情（增强版）
     */
    private void logBottleneckAnalysis(Map<String, Object> analysis) {
        StringBuilder sb = new StringBuilder("变邻域搜索 - 瓶颈分析: ");

        Long bottleneckMachineId = (Long) analysis.get("bottleneckMachineId");
        List<GAScheduleResult> criticalOps = (List<GAScheduleResult>) analysis.get("criticalOps");
        List<GAScheduleResult> delayedOps = (List<GAScheduleResult>) analysis.get("delayedOps");
        Map<Long, Double> utilization = (Map<Long, Double>) analysis.get("utilization");
        List<GAScheduleResult> allResults = (List<GAScheduleResult>) analysis.get("allResults");

        allResults = allResults.stream().filter(t->!t.getCapacityTypeName().equals("Infinite"))
                .collect(Collectors.toList());


        sb.append(String.format("瓶颈设备ID=%d, ", bottleneckMachineId));
        sb.append(String.format("关键工序数=%d, ", criticalOps != null ? criticalOps.size() : 0));
        sb.append(String.format("延迟工序数=%d, ", delayedOps != null ? delayedOps.size() : 0));

        if (utilization != null && !utilization.isEmpty()) {
            sb.append("设备利用率: ");
            utilization.entrySet().stream()
                    .sorted(Map.Entry.<Long, Double>comparingByValue().reversed())
                    .limit(5)
                    .forEach(e -> sb.append(String.format("[%d:%.1f%%] ", e.getKey(), e.getValue() * 100)));
        }

        log(sb.toString());

        // 新增：精准瓶颈工序分析
        if (allResults != null && !allResults.isEmpty()) {
            List<BottleneckOperationAnalysis> bottleneckAnalyses = analyzeBottleneckOperations(allResults, bottleneckMachineId);

            // 输出瓶颈工序TOP
            log(String.format("变邻域搜索 - ===== 瓶颈工序TOP %d (按瓶颈评分) =====", TOP_MACHINES_TO_LOG));
            for (int i = 0; i < Math.min(TOP_MACHINES_TO_LOG, bottleneckAnalyses.size()); i++) {
                BottleneckOperationAnalysis boa = bottleneckAnalyses.get(i);
                GAScheduleResult op = boa.operation;
                log(String.format(
                        "  TOP%d: [工单%d-工序%d(设备%d)] | 评分=%.2f | 等待=%ds | 设备等待=%ds | 关键路径=%s | 延迟贡献=%.2f",
                        i + 1, op.getGroupId(), op.getOperationId(), op.getMachineId(),
                        boa.bottleneckScore, boa.waitTime, boa.machineWaitTime,
                        boa.onCriticalPath ? "是" : "否", boa.delayContribution
                ),false);
            }

            // 更新关键工序为识别出的瓶颈工序
            if (criticalOps != null && !criticalOps.isEmpty() && !bottleneckAnalyses.isEmpty()) {
                List<GAScheduleResult> topBottlenecks = bottleneckAnalyses.stream()
                        .limit(Math.min(TOP_BOTTLENECK_OPS_TO_RETURN, bottleneckAnalyses.size()))
                        .map(boa -> boa.operation)
                        .collect(Collectors.toList());
                analysis.put("criticalOps", topBottlenecks);
            }
        }

        // 记录原始关键工序详情（前5个）作为参考
        if (criticalOps != null && !criticalOps.isEmpty()) {
            StringBuilder criticalOpsSb = new StringBuilder("变邻域搜索 - 原始关键工序(前5个): ");
            criticalOps.stream()
                    .limit(5)
                    .forEach(op -> criticalOpsSb.append(String.format("[工单%d-工序%d(设备%d)] ",
                            op.getGroupId(), op.getOperationId(), op.getMachineId())));
            log(criticalOpsSb.toString());
        }
    }

    /**
     * 精准分析瓶颈工序
     */
    private List<BottleneckOperationAnalysis> analyzeBottleneckOperations(List<GAScheduleResult> allResults, Long bottleneckMachineId) {
        if (allResults == null || allResults.isEmpty()) {
            return new ArrayList<>();
        }

        // 1. 按工单和工序顺序组织数据
        Map<Integer, List<GAScheduleResult>> opsByGroup = allResults.stream()
                .collect(Collectors.groupingBy(GAScheduleResult::getGroupId));

        Map<Long, List<GAScheduleResult>> opsByMachine = allResults.stream()
                .collect(Collectors.groupingBy(GAScheduleResult::getMachineId));

        // 2. 计算每个订单的完成时间
        Map<Integer, Integer> orderCompletionTime = new HashMap<>();
        for (List<GAScheduleResult> ops : opsByGroup.values()) {
            int maxEndTime = ops.stream()
                    .mapToInt(GAScheduleResult::getEndTime)
                    .max()
                    .orElse(0);
            for (GAScheduleResult op : ops) {

                orderCompletionTime.put(op.getGroupId(), maxEndTime);

            }
        }

        // 3. 创建分析对象
        List<BottleneckOperationAnalysis> analyses = new ArrayList<>();
        Map<Integer, BottleneckOperationAnalysis> opIdToAnalysis = new HashMap<>();

        for (GAScheduleResult op : allResults) {
            BottleneckOperationAnalysis boa = new BottleneckOperationAnalysis(op);
            analyses.add(boa);
            opIdToAnalysis.put(op.getOperationId(), boa);
        }

        // 4. 计算工序等待时间（同一工单内，前一工序结束到本工序开始）
        for (List<GAScheduleResult> ops : opsByGroup.values()) {
            ops.sort(Comparator.comparingInt(GAScheduleResult::getStartTime));
            for (int i = 1; i < ops.size(); i++) {
                GAScheduleResult prevOp = ops.get(i - 1);
                GAScheduleResult currOp = ops.get(i);
                BottleneckOperationAnalysis boa = opIdToAnalysis.get(currOp.getOperationId());
                if (boa != null) {
                    boa.waitTime = Math.max(0, currOp.getStartTime() - prevOp.getEndTime());
                }
            }
        }

        // 5. 计算设备等待时间（同一设备上，前一工序结束到本工序开始）
        for (List<GAScheduleResult> ops : opsByMachine.values()) {
            ops.sort(Comparator.comparingInt(GAScheduleResult::getStartTime));
            for (int i = 1; i < ops.size(); i++) {
                GAScheduleResult prevOp = ops.get(i - 1);
                GAScheduleResult currOp = ops.get(i);
                BottleneckOperationAnalysis boa = opIdToAnalysis.get(currOp.getOperationId());
                if (boa != null) {
                    boa.machineWaitTime = Math.max(0, currOp.getStartTime() - prevOp.getEndTime());
                }
            }
        }

        // 6. 识别关键路径（从后往前推，没有松弛时间的工序）
        int maxMakespan = allResults.stream()
                .mapToInt(GAScheduleResult::getEndTime)
                .max()
                .orElse(0);

        // 按结束时间倒序排列
        List<GAScheduleResult> sortedByEndTime = new ArrayList<>(allResults);
        sortedByEndTime.sort((a, b) -> Integer.compare(b.getEndTime(), a.getEndTime()));

        // 找出在最大完工时间的工序作为关键路径起点
        for (GAScheduleResult op : sortedByEndTime) {
            if (op.getEndTime() == maxMakespan) {
                BottleneckOperationAnalysis boa = opIdToAnalysis.get(op.getOperationId());
                if (boa != null) {
                    boa.onCriticalPath = true;
                }
            }
        }

        // 7. 计算延迟贡献度（工序结束时间与订单完成时间的接近程度）
        double avgCompletionTime = orderCompletionTime.values().stream()
                .mapToInt(Integer::intValue)
                .average()
                .orElse(1);

        for (BottleneckOperationAnalysis boa : analyses) {
            GAScheduleResult op = boa.operation;
            Integer orderEndTime = orderCompletionTime.get(op.getGroupId());
            if (orderEndTime != null && orderEndTime > 0) {
                // 工序越接近订单完成时间，延迟贡献度越高
                boa.delayContribution = (double) op.getEndTime() / orderEndTime;
            }
        }

        // 8. 计算综合瓶颈评分 - 修复版（防数据偏倚）
        // 使用中位数和截断来避免极端值影响（如设备2341有2000多工序的情况）
        List<Integer> waitTimes = analyses.stream().mapToInt(a -> a.waitTime).boxed().collect(Collectors.toList());
        List<Integer> machineWaitTimes = analyses.stream().mapToInt(a -> a.machineWaitTime).boxed().collect(Collectors.toList());
        Collections.sort(waitTimes);
        Collections.sort(machineWaitTimes);

        // 使用90分位数代替最大值，避免极端值影响
        double p90WaitTime = Math.max(1, getPercentile(waitTimes, PERCENTILE_90)); // 防止0导致NaN
        double p90MachineWaitTime = Math.max(1, getPercentile(machineWaitTimes, PERCENTILE_90)); // 防止0导致NaN

        // 优先找出瓶颈设备上的工序
        List<BottleneckOperationAnalysis> bottleneckMachineOps = new ArrayList<>();
        if (bottleneckMachineId != null) {
            for (BottleneckOperationAnalysis boa : analyses) {
                if (boa.operation.getMachineId() == bottleneckMachineId) {
                    bottleneckMachineOps.add(boa);
                }
            }
        }

        // 统计各设备的工序数量，用于后续分析
        Map<Long, Long> machineOpCount = analyses.stream()
                .collect(Collectors.groupingBy(a -> a.operation.getMachineId(), Collectors.counting()));

        for (BottleneckOperationAnalysis boa : analyses) {
            double score = 0;
            boolean isOnBottleneckMachine = (bottleneckMachineId != null && boa.operation.getMachineId() == bottleneckMachineId);

            if (isOnBottleneckMachine) {
                // 瓶颈设备上的工序：基础分极高，确保排在最前面
                score += BOTTLENECK_MACHINE_BASE_SCORE; // 绝对保证排在前面

                // 在瓶颈设备工序内部进行排序（使用截断值）
                // 工序等待时间
                double normalizedWaitTime = Math.min(boa.waitTime / p90WaitTime, NORMALIZATION_CAP);
                score += normalizedWaitTime * WAIT_TIME_WEIGHT;

                // 设备等待时间
                double normalizedMachineWaitTime = Math.min(boa.machineWaitTime / p90MachineWaitTime, NORMALIZATION_CAP);
                score += normalizedMachineWaitTime * MACHINE_WAIT_TIME_WEIGHT;

                // 关键路径评分
                if (boa.onCriticalPath) {
                    score += CRITICAL_PATH_WEIGHT_ON_BOTTLENECK;
                }

                // 延迟贡献度评分
                score += boa.delayContribution * DELAY_CONTRIBUTION_WEIGHT_ON_BOTTLENECK;
            } else {
                // 非瓶颈设备上的工序：基础分低
                score += 0;

                // 使用截断值，避免极端值影响
                double normalizedMachineWaitTime = Math.min(boa.machineWaitTime / p90MachineWaitTime, NORMALIZATION_CAP);
                score += normalizedMachineWaitTime * MACHINE_WAIT_TIME_WEIGHT;

                double normalizedWaitTime = Math.min(boa.waitTime / p90WaitTime, NORMALIZATION_CAP);
                score += normalizedWaitTime * WAIT_TIME_WEIGHT;

                // 关键路径评分
                if (boa.onCriticalPath) {
                    score += CRITICAL_PATH_WEIGHT_OFF_BOTTLENECK;
                }

                // 延迟贡献度评分
                score += boa.delayContribution * DELAY_CONTRIBUTION_WEIGHT_OFF_BOTTLENECK;
            }

            boa.bottleneckScore = score;
        }

        // 记录修复后的瓶颈工序信息
        log(String.format("变邻域搜索 - 瓶颈设备ID=%d, 其上工序数=%d",
                bottleneckMachineId, bottleneckMachineOps.size()));

        // 输出各设备工序数量统计
        List<Map.Entry<Long, Long>> topMachinesByCount = machineOpCount.entrySet().stream()
                .sorted((a, b) -> Long.compare(b.getValue(), a.getValue()))
                .limit(TOP_MACHINES_TO_LOG)
                .collect(Collectors.toList());
        StringBuilder machineCountStr = new StringBuilder(String.format("变邻域搜索 - 设备工序数(前%d): ", TOP_MACHINES_TO_LOG));
        for (Map.Entry<Long, Long> entry : topMachinesByCount) {
            machineCountStr.append(String.format("[%d:%d] ", entry.getKey(), entry.getValue()));
        }
        log(machineCountStr.toString());

        // 9. 按瓶颈评分排序
        analyses.sort((a, b) -> Double.compare(b.bottleneckScore, a.bottleneckScore));

        return analyses;
    }

    /**
     * 计算百分位数（用于防数据偏倚）
     */
    private double getPercentile(List<Integer> sortedValues, double percentile) {
        if (sortedValues.isEmpty()) {
            return 1;
        }
        int index = (int) Math.ceil(percentile * sortedValues.size()) - 1;
        index = Math.max(0, Math.min(index, sortedValues.size() - 1));
        return sortedValues.get(index);
    }

    /**
     * 构建策略顺序，基于成功率+频率驱动的动态调整
     * 目标：避免单一策略被反复使用，确保3个策略都被尝试
     */
    private List<Integer> buildStrategyOrder() {
        List<Integer> strategies = new ArrayList<>(Arrays.asList(0, 1, 2));

        // 计算策略选择频率的最大值、总成功数
        int maxStrategyFreq = 0;
        int totalStrategyFreq = 0;
        for (int freq : strategySelectFrequency) {
            maxStrategyFreq = Math.max(maxStrategyFreq, freq);
            totalStrategyFreq += freq;
        }

        // 强制策略轮换：如果某个策略被连续使用超过 MAX_CONSECUTIVE_SAME_STRATEGY 次，强制换一个
        boolean needForceRotate = (lastUsedStrategy >= 0 && consecutiveSameStrategyCount >= MAX_CONSECUTIVE_SAME_STRATEGY);

        if (needForceRotate) {
            log(String.format("强制策略轮换：策略%d已连续使用%d次",
                    lastUsedStrategy + 1, consecutiveSameStrategyCount), true);
        }

        // 计算"未被探索的策略数"，用于加强探索
        int unexploredCount = 0;
        for (int i = 0; i < 3; i++) {
            if (strategyTotalCount[i] == 0) unexploredCount++;
        }

        // 为每个策略计算评分
        final double[] scores = new double[3];
        for (int strategy : strategies) {
            double successRate = strategyTotalCount[strategy] > 0 ?
                    (double) strategySuccessCount[strategy] / strategyTotalCount[strategy] : INITIAL_SUCCESS_RATE;

            // 频率多样性评分：被成功选中次数越少，分越高
            int freq = strategySelectFrequency[strategy];
            // 更强的频率衰减：0次→1.0, 2次→0.36, 4次→0.13, 6次→0.05
            double freqDiversity = Math.pow(0.6, freq);

            // 动态权重调整：
            // - 如果有策略被成功使用 ≥ 2次，就开始加强探索
            // - 如果有未探索的策略，给它们更大的激励
            double successWeight;
            double diversityWeight;

            if (totalStrategyFreq >= 8) {
                // 后期：平衡为主，避免搜索空间塌陷
                successWeight = 0.40;
                diversityWeight = 0.60;
            } else if (totalStrategyFreq >= 4) {
                // 中期：稍微偏重多样性
                successWeight = 0.45;
                diversityWeight = 0.55;
            } else if (maxStrategyFreq >= 2) {
                // 有策略被用了2次以上：开始引入平衡
                successWeight = 0.50;
                diversityWeight = 0.50;
            } else {
                // 前期：以成功率为主，建立基线
                successWeight = 0.70;
                diversityWeight = 0.30;
            }

            double score = successWeight * successRate + diversityWeight * freqDiversity;

            // "未探索策略"额外加分：从未被尝试过的策略大幅提升
            if (strategyTotalCount[strategy] == 0) {
                score += 0.40;  // 大幅激励从未被尝试的策略
            } else if (strategySelectFrequency[strategy] == 0 && strategyTotalCount[strategy] < 3) {
                // 被尝试过但从未成功的策略，给中等激励
                score += 0.15;
            }

            // 强制轮换：给最后使用的策略降权
            if (needForceRotate && strategy == lastUsedStrategy) {
                score -= FORCE_ROTATE_PENALTY;
            }

            // 给使用次数少的策略加分
            if (strategyTotalCount[strategy] < MIN_USE_COUNT_FOR_EXPLORATION_BONUS) {
                score += EXPLORATION_BONUS_FOR_LOW_USE * 0.5;  // 减半，避免与上面的未探索重复
            }

            // 如果策略被尝试次数很多但成功率很低，给它额外加分鼓励探索
            if (strategyTotalCount[strategy] > LOW_SUCCESS_RATE_MIN_TRIALS && score < LOW_SUCCESS_RATE_THRESHOLD) {
                score += EXPLORATION_BONUS_FOR_LOW_SUCCESS;
            }

            // ========== 新增: 策略1（换设备）额外奖励 ==========
            // 换设备是最可能产生"大改动"的策略类型，提高其被选择概率
            if (strategy == 0) {
                score += CHANGE_MACHINE_BONUS;
            }

            // 加入随机扰动
            score += rnd.nextDouble() * RANDOM_NOISE_FACTOR;

            scores[strategy] = score;
        }

        // 按评分排序
        strategies.sort((a, b) -> Double.compare(scores[b], scores[a]));

        return strategies;
    }

    /**
     * 记录策略统计信息（包括频率信息）
     */
    private void logStrategyStats() {
        StringBuilder sb = new StringBuilder("策略统计: ");
        for (int i = 0; i < 3; i++) {
            double rate = strategyTotalCount[i] > 0 ?
                    (double) strategySuccessCount[i] / strategyTotalCount[i] : 0.0;
            sb.append(String.format("[%d]%d/%d(%.1f%%)被选%d次 ", i + 1,
                    strategySuccessCount[i], strategyTotalCount[i], rate * 100,
                    strategySelectFrequency[i]));
        }
        log(sb.toString(), true);
    }
    /**
     * 识别瓶颈设备（利用率最高的设备）
     */
    private Long findBottleneckMachine(Chromosome chromosome) {
        Map<Long, Double> utilization = calculateMachineUtilization(chromosome,false);
        if (utilization.isEmpty()) {
            return null;
        }

        return utilization.entrySet().stream()
                .max(Map.Entry.comparingByValue())
                .map(Map.Entry::getKey)
                .orElse(null);
    }

    /**
     * 查找在瓶颈设备上的工序
     */
    private List<GAScheduleResult> findOpsOnBottleneckMachine(Chromosome chromosome, Long bottleneckMachineId) {
        if (bottleneckMachineId == null) {
            return new ArrayList<>();
        }

        return chromosome.getResult().stream()
                .filter(r -> r.getMachineId() == bottleneckMachineId)
                .collect(Collectors.toList());
    }
    /**
     * 计算设备利用率
     */
    private Map<Long, Double> calculateMachineUtilization(Chromosome chromosome,boolean isInfinite) {
        Map<Long, Double> utilization = new HashMap<>();
        List<GAScheduleResult> results=new ArrayList<>();
        if (isInfinite) {
            results = chromosome.getResult().stream()

                    .collect(Collectors.toList());
        }else {
            results = chromosome.getResult().stream().
                    filter(t->!t.getCapacityTypeName().equals("Infinite"))
                    .collect(Collectors.toList());
        }


        if (results == null || results.isEmpty()) {
            return utilization;
        }

        int maxEndTime = results.stream()
                .mapToInt(GAScheduleResult::getEndTime)
                .max()
                .orElse(1);

        Map<Long, List<GAScheduleResult>> machineResults = results.stream().filter(t->!t.getCapacityTypeName().equals("Infinite"))
                .collect(Collectors.groupingBy(GAScheduleResult::getMachineId));

        for (Map.Entry<Long, List<GAScheduleResult>> entry : machineResults.entrySet()) {
            long machineId = entry.getKey();
            List<GAScheduleResult> machineOps = entry.getValue();

            int totalProcessingTime = machineOps.stream()
                    .mapToInt(r -> r.getEndTime() - r.getStartTime())
                    .sum();

            double util = (double) totalProcessingTime / maxEndTime;
            utilization.put(machineId, util);
        }

        return utilization;
    }
    /**
     * 尝试给瓶颈设备上的工序换设备
     */
    private Chromosome tryChangeMachineForBottleneckOp(Chromosome chromosome, List<GAScheduleResult> bottleneckOps,Map<String, Integer> MachinePositionIndex,Map<Integer, Entry> positionIndex,List<List<Integer>> positionByPriority) {
        List<GAScheduleResult> candidates = bottleneckOps.stream()
                .filter(op -> {
                    Entry entry = entrybyids.get(op.getOperationId());
                    return entry != null && entry.getMachineOptions().size() > 1;
                })
                .collect(Collectors.toList());

        log(String.format("tryChangeMachineForBottleneckOp: 候选工序数=%d (瓶颈工序总数=%d)", candidates.size(), bottleneckOps.size()));

        if (candidates.isEmpty()) {
            log("tryChangeMachineForBottleneckOp: 没有可换设备的候选工序");
            return null;
        }

        // === 频率驱动的瓶颈工序选择 ===
        // 不再只按优先级排序，综合考虑优先级+历史被选次数，鼓励探索不同工序
        Map<Double, Set<Integer>> priorityToGroupIds = new HashMap<>();
        int maxGroupCount = 1;
        for (GAScheduleResult op : candidates) {
            Entry entry = entrybyids.get(op.getOperationId());
            if (entry != null) {
                double priority = entry.getPriority();
                int groupCount = priorityToGroupIds.computeIfAbsent(priority, k -> new HashSet<>()).size() + 1;
                priorityToGroupIds.get(priority).add(op.getGroupId());
                maxGroupCount = Math.max(maxGroupCount, priorityToGroupIds.get(priority).size());
            }
        }

        // 给每个候选工序计算综合评分
        List<Object[]> scoredOps = new ArrayList<>();
        int maxOpFreq = 1;
        for (GAScheduleResult op : candidates) {
            int freq = bottleneckOpFrequency.getOrDefault(op.getOperationId(), 0);
            maxOpFreq = Math.max(maxOpFreq, freq);
        }

        for (GAScheduleResult op : candidates) {
            Entry entry = entrybyids.get(op.getOperationId());
            if (entry == null) continue;

            // 优先级评分：订单数多的优先级组排前面（0~1归一化）
            int groupCount = priorityToGroupIds.getOrDefault(entry.getPriority(), new HashSet<>()).size();
            double priorityScore = (double) groupCount / maxGroupCount;

            // 改进的频率多样性评分：非线性衰减，避免同一工序被反复选中
            int freq = bottleneckOpFrequency.getOrDefault(op.getOperationId(), 0);
            double diversityScore = Math.pow(0.6, freq);  // 0次→1.0, 3次→0.22, 6次→0.05

            // 根据整体频率动态调整权重
            double priorityWeight = maxOpFreq >= 3 ? 0.45 : 0.55;
            double diversityWeight = maxOpFreq >= 3 ? 0.55 : 0.45;

            // 综合评分：动态权重 + 小随机
            double score = priorityWeight * priorityScore + diversityWeight * diversityScore + 0.1 * rnd.nextDouble();

            scoredOps.add(new Object[]{op, score, groupCount, freq});
        }

        // 按综合评分降序排序
        scoredOps.sort((a, b) -> Double.compare((Double) b[1], (Double) a[1]));

        // 70%概率选择前3个候选，30%概率在更后面选
        GAScheduleResult selectedOp;
        if (scoredOps.size() <= 3) {
            selectedOp = (GAScheduleResult) scoredOps.get(rnd.nextInt(scoredOps.size()))[0];
        } else {
            if (rnd.nextDouble() < 0.7) {
                selectedOp = (GAScheduleResult) scoredOps.get(rnd.nextInt(Math.min(3, scoredOps.size())))[0];
            } else {
                int otherCount = scoredOps.size() - 3;
                selectedOp = (GAScheduleResult) scoredOps.get(3 + rnd.nextInt(otherCount))[0];
            }
        }

        // 更新该工序被选为优化目标的频率
        bottleneckOpFrequency.merge(selectedOp.getOperationId(), 1, Integer::sum);

        // === 日志：输出换设备工序选择决策 ===
        Entry selEntry = entrybyids.get(selectedOp.getOperationId());
        StringBuilder opChangeLog = new StringBuilder();
        if (selEntry != null) {
            int opFreq = bottleneckOpFrequency.getOrDefault(selectedOp.getOperationId(), 0);
            opChangeLog.append(String.format("[换设备-工序选择] 选中=工序%d(组=%d_序号=%d, 优先级=%.2f, 被选次数=%d) | top%d候选:",
                    selectedOp.getOperationId(), selEntry.getGroupId(), selEntry.getSequence(),
                    selEntry.getPriority(), opFreq, scoredOps.size()));
            for (int i = 0; i < Math.min(5, scoredOps.size()); i++) {
                Object[] item = scoredOps.get(i);
                GAScheduleResult opItem = (GAScheduleResult) item[0];
                double sc = (Double) item[1];
                int gc = (Integer) item[2];
                int fr = (Integer) item[3];
                opChangeLog.append(String.format(" 工序%d(评分=%.3f, 组订单数=%d, 次数=%d)%s",
                        opItem.getOperationId(), sc, gc, fr,
                        opItem.getOperationId() == selectedOp.getOperationId() ? "←选中" : ""));
            }
            log(opChangeLog.toString(), true);
        }

        int maPos = -1;

        Entry entry= entrybyids.get(selectedOp.getOperationId());
        if (entry != null && entry.getMachineOptions().size() > 1) {
            maPos = MachinePositionIndex.get(entry.getGroupId() + "_" + entry.getSequence());
            if (maPos >= 0) {
                log("tryChangeMachineForBottleneckOp: 成功找到工序，执行换设备");
                return generateMachineChangeForSpecificOp(chromosome, entry.getMachineOptions(), maPos);
            }
        }

        log("tryChangeMachineForBottleneckOp: 找不到工序位置，尝试通用换设备");
        Chromosome result = generateMachineChangeNeighbor(chromosome);
        return result != null ? result : null;
    }
    private Chromosome ChangeMachineForBottleneckOpWrapper(Chromosome chromosome) {
        log("ChangeMachineForBottleneckOpWrapper");
        List<GAScheduleResult> results = chromosome.getResult().stream().
                filter(t->!t.getCapacityTypeName().equals("Infinite"))
                .collect(Collectors.toList());
        Map<Integer, Object> obj = buildPositionToEntryIndex(chromosome);
        Map<Integer, Entry> positionToEntryIndex = (Map<Integer, Entry>) obj.get(1);
        List<List<Integer>> positionByPriority = (List<List<Integer>>) obj.get(2);

        if (results == null || results.isEmpty()) {
            return generateRandomNeighbor(chromosome, positionToEntryIndex, positionByPriority);
        }

        Map<String, Integer> machinePositionIndex = buildEntryMachinePositionIndex(chromosome);

        Long bottleneckMachineId = findBottleneckMachine(chromosome);

        if (bottleneckMachineId != null) {
            List<GAScheduleResult> bottleneckOps = findOpsOnBottleneckMachine(chromosome, bottleneckMachineId);

            if (!bottleneckOps.isEmpty()) {
                Chromosome result = tryChangeMachineForBottleneckOp(chromosome, bottleneckOps, machinePositionIndex, positionToEntryIndex, positionByPriority);
                if (result != null) {
                    return result;
                }
            }
        }

        return generateRandomNeighbor(chromosome, positionToEntryIndex, positionByPriority);
    }

    /**
     * 给指定位置的工序换设备 - 综合考虑设备负载均衡和选择多样性
     * 优先选择负载低且选择次数少的设备
     */
    private Chromosome generateMachineChangeForSpecificOp(Chromosome chromosome, List<MachineOption> machineOptions, int idx) {

        Chromosome neighbor=copyChromosome(chromosome);
        CopyOnWriteArrayList<Integer> ms = neighbor.getMachineSelection();
        if (!ms.isEmpty() && idx >= 0 && idx < ms.size()) {
            if (machineOptions.size() > 1) {
                // 获取工序信息，用于频率跟踪
                String opKey = null;
                if (idx < chromosome.getGlobalOpList().size()) {
                    Entry op = chromosome.getGlobalOpList().get(idx).getOp();
                    opKey = op.getGroupId() + "_" + op.getSequence();
                }

                int currentMachineSeq = ms.get(idx);
                List<Integer> availableMachines = new ArrayList<>();
                for (int i = 1; i <= machineOptions.size(); i++) {
                    if (i != currentMachineSeq) {
                        availableMachines.add(i);
                    }
                }

                if (!availableMachines.isEmpty()) {
                    // 选择综合考虑负载均衡和选择多样性的设备
                    int newMachineSeq = selectMachineByLoad(availableMachines, machineOptions, chromosome, opKey);
                    ms.set(idx, newMachineSeq);
                    neighbor.setMachineSelection(ms);

                    // 更新该设备被选择的频率记录
                    Long selectedMachineId = machineOptions.get(newMachineSeq - 1).getMachineId();
                    updateMachineSelectFrequency(opKey, selectedMachineId);
                }
            }
        }
        return neighbor;
    }


    private Chromosome moveBottleneckForwardWrapper(Chromosome chromosome) {
        List<GAScheduleResult> results = chromosome.getResult().stream().
                filter(t->!t.getCapacityTypeName().equals("Infinite"))
                .collect(Collectors.toList());
        log("moveBottleneckForwardWrapper");

        Map<String, Integer> positionIndex = buildPositionIndex(chromosome);
        Map<Integer, Object> obj = buildPositionToEntryIndex(chromosome);
        Map<Integer, Entry> positionToEntryIndex =(Map<Integer, Entry>)obj.get(1);
        List<List<Integer>> positionByPriority = (List<List<Integer>>)obj.get(2);
        Map<String, Integer> MachinePositionIndex = buildEntryMachinePositionIndex(chromosome);
        if (results == null || results.isEmpty()) {
            return generateRandomNeighbor(chromosome,positionToEntryIndex,positionByPriority);
        }
        Long bottleneckMachineId = findBottleneckMachine(chromosome);
        if (bottleneckMachineId != null) {
            List<GAScheduleResult> bottleneckOps = findOpsOnBottleneckMachine(chromosome, bottleneckMachineId);
            if (!bottleneckOps.isEmpty()) {
                Chromosome result = tryMoveBottleneckOpForward(chromosome, bottleneckOps, positionIndex,positionByPriority,positionToEntryIndex,MachinePositionIndex,false);
                if (result != null) {
                    return result;
                }
            }
        }
        return generateRandomNeighbor(chromosome,positionToEntryIndex,positionByPriority);
    }

    private Chromosome moveBottleneckSameMachineWrapper(Chromosome chromosome) {
        List<GAScheduleResult> results = chromosome.getResult().stream().
                filter(t->!t.getCapacityTypeName().equals("Infinite"))
                .collect(Collectors.toList());

        log("moveBottleneckSameMachineWrapper");
        Map<String, Integer> positionIndex = buildPositionIndex(chromosome);
        Map<Integer, Object> obj = buildPositionToEntryIndex(chromosome);
        Map<Integer, Entry> positionToEntryIndex =(Map<Integer, Entry>)obj.get(1);
        List<List<Integer>> positionByPriority = (List<List<Integer>>)obj.get(2);
        Map<String, Integer> MachinePositionIndex = buildEntryMachinePositionIndex(chromosome);
        if (results == null || results.isEmpty()) {
            return generateRandomNeighbor(chromosome,positionToEntryIndex,positionByPriority);
        }
        Long bottleneckMachineId = findBottleneckMachine(chromosome);
        if (bottleneckMachineId != null) {
            List<GAScheduleResult> bottleneckOps = findOpsOnBottleneckMachine(chromosome, bottleneckMachineId);
            if (!bottleneckOps.isEmpty()) {
                Chromosome result = tryMoveBottleneckOpForward(chromosome, bottleneckOps, positionIndex,positionByPriority,positionToEntryIndex,MachinePositionIndex,true);
                if (result != null) {
                    return result;
                }
            }
        }
        return generateRandomNeighbor(chromosome,positionToEntryIndex,positionByPriority);
    }

    /**
     * 尝试将瓶颈设备上的工序往前移动
     */
    private Chromosome tryMoveBottleneckOpForward(Chromosome chromosome, List<GAScheduleResult> bottleneckOps,
                                                  Map<String, Integer> positionkey,List<List<Integer>> positionByPriority,Map<Integer, Entry> positionIndex,Map<String, Integer> machinePositionIndex,boolean isSameMachine) {
        log(String.format("tryMoveBottleneckOpForward: isSameMachine=%b", isSameMachine));
        log("tryMoveBottleneckOpForward:positionIndex"+positionIndex.size());

        if (bottleneckOps.isEmpty()) {
            log("tryMoveBottleneckOpForward: 瓶颈工序为空");
            return null;
        }

        List<GAScheduleResult> allResults = chromosome.getResult()
                .stream().
                filter(t->!t.getCapacityTypeName().equals("Infinite"))
                .collect(Collectors.toList());
        Map<Integer, Integer> orderCompletionTimes = calculateOrderCompletionTimes(allResults);

        // === 频率驱动的瓶颈工序选择（与tryChangeMachineForBottleneckOp相同策略） ===
        Map<Double, Set<Integer>> priorityToGroupIds = new HashMap<>();
        int maxGroupCount = 1;
        for (GAScheduleResult op : bottleneckOps) {
            Entry entry = entrybyids.get(op.getOperationId());
            if (entry != null) {
                double priority = entry.getPriority();
                int groupCount = priorityToGroupIds.computeIfAbsent(priority, k -> new HashSet<>()).size() + 1;
                priorityToGroupIds.get(priority).add(op.getGroupId());
                maxGroupCount = Math.max(maxGroupCount, priorityToGroupIds.get(priority).size());
            }
        }

        // 计算候选工序中的最大频率
        int maxOpFreqMove = 1;
        for (GAScheduleResult op : bottleneckOps) {
            int freq = bottleneckOpFrequency.getOrDefault(op.getOperationId(), 0);
            maxOpFreqMove = Math.max(maxOpFreqMove, freq);
        }

        // 给每个候选工序计算综合评分
        List<Object[]> scoredOps = new ArrayList<>();
        for (GAScheduleResult op : bottleneckOps) {
            Entry entry = entrybyids.get(op.getOperationId());
            if (entry == null) continue;

            // 优先级评分（0~1归一化）
            int groupCount = priorityToGroupIds.getOrDefault(entry.getPriority(), new HashSet<>()).size();
            double priorityScore = (double) groupCount / maxGroupCount;

            // 订单完成时间评分：完成时间越晚，越需要优化（0~1归一化）
            int endTime = orderCompletionTimes.getOrDefault(op.getGroupId(), 0);
            int maxEndTime = 0;
            for (int t : orderCompletionTimes.values()) {
                maxEndTime = Math.max(maxEndTime, t);
            }
            double timeScore = maxEndTime > 0 ? (double) endTime / maxEndTime : 0.5;

            // 改进的频率多样性评分：非线性衰减，避免同一工序被反复选中
            int freq = bottleneckOpFrequency.getOrDefault(op.getOperationId(), 0);
            double diversityScore = Math.pow(0.6, freq);  // 0次→1.0, 3次→0.22, 6次→0.05

            // 根据整体频率动态调整权重：频率越高，多样性权重越大
            double priorityWeight = maxOpFreqMove >= 3 ? 0.3 : 0.35;
            double timeWeight = maxOpFreqMove >= 3 ? 0.2 : 0.25;
            double diversityWeight = maxOpFreqMove >= 3 ? 0.5 : 0.4;

            // 综合评分：动态权重 + 小随机
            double score = priorityWeight * priorityScore + timeWeight * timeScore + diversityWeight * diversityScore + 0.1 * rnd.nextDouble();

            scoredOps.add(new Object[]{op, score, freq});
        }

        // 按综合评分降序排序
        scoredOps.sort((a, b) -> Double.compare((Double) b[1], (Double) a[1]));

        if (scoredOps.isEmpty()) {
            log("tryMoveBottleneckOpForward: 排序后为空");
            return null;
        }

        // 70%选前5个中的随机，30%选更后面的
        GAScheduleResult selectedOp;
        int topN = Math.min(5, scoredOps.size());
        if (rnd.nextDouble() < 0.7 || scoredOps.size() <= 5) {
            selectedOp = (GAScheduleResult) scoredOps.get(rnd.nextInt(topN))[0];
        } else {
            selectedOp = (GAScheduleResult) scoredOps.get(topN + rnd.nextInt(scoredOps.size() - topN))[0];
        }

        // 更新该工序被选为优化目标的频率
        bottleneckOpFrequency.merge(selectedOp.getOperationId(), 1, Integer::sum);

        // === 日志：输出移动工序选择决策 ===
        Entry moveEntry = entrybyids.get(selectedOp.getOperationId());
        StringBuilder moveLog = new StringBuilder();
        if (moveEntry != null) {
            int opFreq = bottleneckOpFrequency.getOrDefault(selectedOp.getOperationId(), 0);
            int endTime = orderCompletionTimes.getOrDefault(selectedOp.getGroupId(), 0);
            moveLog.append(String.format("[移动工序选择] 选中=工序%d(组=%d_序号=%d, 优先级=%.2f, 完成时间=%d, 被选次数=%d) | top%d候选:",
                    selectedOp.getOperationId(), moveEntry.getGroupId(), moveEntry.getSequence(),
                    moveEntry.getPriority(), endTime, opFreq, scoredOps.size()));
            for (int i = 0; i < Math.min(5, scoredOps.size()); i++) {
                Object[] item = scoredOps.get(i);
                GAScheduleResult opItem = (GAScheduleResult) item[0];
                double sc = (Double) item[1];
                int fr = (Integer) item[2];
                moveLog.append(String.format(" 工序%d(评分=%.3f, 次数=%d)%s",
                        opItem.getOperationId(), sc, fr,
                        opItem.getOperationId() == selectedOp.getOperationId() ? "←选中" : ""));
            }
            log(moveLog.toString(), true);
        }

        Entry entry = entrybyids.get(selectedOp.getOperationId());
        if (entry == null) {
            log("tryMoveBottleneckOpForward: 找不到工序", false);
            return null;
        }

        String key = entry.getGroupId() + "_" + entry.getSequence();
        Integer opPos = positionkey.get(key);

        if (opPos == null || opPos <= 0) {
            log("tryMoveBottleneckOpForward: 找不到工序位置");
            return null;
        }

        log(String.format("tryMoveBottleneckOpForward: 找到工序位置=%d", opPos));

        if(isSameMachine) {
            Chromosome result = generateSameMachineSwapNeighbor(chromosome,opPos,positionIndex,machinePositionIndex);
            log("tryMoveBottleneckOpForward: 相同设备交换完成");
            return result;
        } else {
            int steps = rnd.nextInt(5) + 1;
            Chromosome result = insertOperationForward(chromosome, opPos, steps, entrys, positionIndex);
            log(String.format("tryMoveBottleneckOpForward: 往前插入%d步完成", steps));
            return result;
        }
    }
    /**
     * 计算每个订单的最后完成时间
     */
    private Map<Integer, Integer> calculateOrderCompletionTimes(List<GAScheduleResult> allResults) {
        Map<Integer, Integer> orderEndTimes = new HashMap<>();
        for (GAScheduleResult result : allResults) {
            int groupId = result.getGroupId();
            int endTime = result.getEndTime();
            orderEndTimes.put(groupId, Math.max(orderEndTimes.getOrDefault(groupId, 0), endTime));
        }
        return orderEndTimes;
    }

    private Chromosome moveNonBottleneckBackwardWrapper(Chromosome chromosome) {
        List<GAScheduleResult> results = chromosome.getResult().stream().
                filter(t->!t.getCapacityTypeName().equals("Infinite"))
                .collect(Collectors.toList());

        log("moveNonBottleneckBackwardWrapper");
        Map<String, Integer> positionIndex = buildPositionIndex(chromosome);
        Map<Integer, Object> obj = buildPositionToEntryIndex(chromosome);
        Map<Integer, Entry> positionToEntryIndex =(Map<Integer, Entry>)obj.get(1);
        List<List<Integer>> positionByPriority = (List<List<Integer>>)obj.get(2);
        if (results == null || results.isEmpty()) {
            return generateRandomNeighbor(chromosome,positionToEntryIndex,positionByPriority);
        }
        Long bottleneckMachineId = findBottleneckMachine(chromosome);
        if (bottleneckMachineId != null) {
            Chromosome result = tryMoveNonBottleneckOpBackward(chromosome, bottleneckMachineId, positionIndex,positionByPriority, positionToEntryIndex);
            if (result != null) {
                return result;
            }
        }
        return generateRandomNeighbor(chromosome,positionToEntryIndex,positionByPriority);
    }

    /**
     * 尝试将非瓶颈设备上的工序往后移动（给瓶颈工序腾位置）
     */
    private Chromosome tryMoveNonBottleneckOpBackward(Chromosome chromosome, Long bottleneckMachineId,
                                                      Map<String, Integer> positionIndex,List<List<Integer>> positionByPriority,
                                                      Map<Integer, Entry> positionToEntryIndex
    ) {
        log(String.format("tryMoveNonBottleneckOpBackward: 瓶颈设备ID=%d", bottleneckMachineId));
        log("tryMoveNonBottleneckOpBackward:positionIndex"+positionIndex.size());
        log("tryMoveNonBottleneckOpBackward:positionToEntryIndex"+positionToEntryIndex.size());

        List<GAScheduleResult> results = chromosome.getResult().stream().
                filter(t->!t.getCapacityTypeName().equals("Infinite"))
                .collect(Collectors.toList());
        if (results == null) {
            log("tryMoveNonBottleneckOpBackward: results为空");
            return null;
        }

        List<GAScheduleResult> nonBottleneckOps = results.stream()
                .filter(r -> r.getMachineId()!=(bottleneckMachineId))
                .collect(Collectors.toList());

        log(String.format("tryMoveNonBottleneckOpBackward: 非瓶颈工序数=%d", nonBottleneckOps.size()));

        if (nonBottleneckOps.isEmpty()) {
            log("tryMoveNonBottleneckOpBackward: 没有非瓶颈工序");
            return null;
        }

        GAScheduleResult randomOp = nonBottleneckOps.get(rnd.nextInt(nonBottleneckOps.size()));
        Entry entry = entrybyids.get(randomOp.getOperationId());

        if (entry == null) {
            log("tryMoveNonBottleneckOpBackward: 找不到工序");
            return null;
        }

        String key = entry.getGroupId() + "_" + entry.getSequence();
        Integer opPos = positionIndex.get(key);

        if (opPos == null || opPos >= chromosome.getOperationSequencing().size() - 1) {
            log("tryMoveNonBottleneckOpBackward: 工序位置无效");
            return null;
        }

        log(String.format("tryMoveNonBottleneckOpBackward: 找到工序位置=%d", opPos));

        int steps = rnd.nextInt(3) + 1;
        Chromosome result = moveOperationBackward(chromosome, positionToEntryIndex, opPos, steps);
        log(String.format("tryMoveNonBottleneckOpBackward: 往后移动%d步完成", steps));
        return result;
    }
    /**
     * 将工序往前移动
     */
    private Chromosome moveOperationForward(Chromosome chromosome, Map<Integer, Entry> originalPositionIndex,int pos, int steps) {
        geneticOperations.DelOrder(chromosome);
        Chromosome neighbor = ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
        CopyOnWriteArrayList<Integer> os = neighbor.getOperationSequencing();

        if (pos <= 0 || pos >= os.size()) {
            return neighbor;
        }

        // 获取要移动的工序和目标位置的工序（基于原始chromosome）
        Entry opToMove = originalPositionIndex.get(pos);
        if (opToMove == null) {
            return neighbor;
        }

        int targetPos = Math.max(0, pos - steps);
        Entry targetOp = originalPositionIndex.get(targetPos);

        // 检查是否可以交换
        if (targetOp != null && opToMove.getGroupId() == targetOp.getGroupId()) {
            return neighbor;
        }
        if (targetOp != null && Math.abs(targetOp.getPriority() - opToMove.getPriority()) > 0.001) {
            return neighbor;
        }

        // 直接交换到目标位置
        java.util.Collections.swap(os, pos, targetPos);
        neighbor.setOperationSequencing(os);
        return neighbor;
    }

    /**
     * 将工序往后移动
     */
    private Chromosome moveOperationBackward(Chromosome chromosome,Map<Integer, Entry> originalPositionIndex, int pos, int steps) {
        log("moveOperationBackward:originalPositionIndex"+originalPositionIndex.size());

        Chromosome neighbor=copyChromosome(chromosome);// ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
        CopyOnWriteArrayList<Integer> os = neighbor.getOperationSequencing();

        if (pos < 0 || pos >= os.size() - 1) {
            return neighbor;
        }

        // 获取要移动的工序和目标位置的工序（基于原始chromosome）

        Entry opToMove = originalPositionIndex.get(pos);
        if (opToMove == null) {
            return neighbor;
        }

        int targetPos = Math.min(os.size() - 1, pos + steps);
        Entry targetOp = originalPositionIndex.get(targetPos);

        // 检查是否可以交换
        if (targetOp != null && opToMove.getGroupId() == targetOp.getGroupId()) {
            return neighbor;
        }
        if (targetOp != null && Math.abs(targetOp.getPriority() - opToMove.getPriority()) > 0.001) {
            return neighbor;
        }

        // 直接交换到目标位置
        java.util.Collections.swap(os, pos, targetPos);
        neighbor.setOperationSequencing(os);
        return neighbor;
    }

    /**
     * 将工序往前插入（不交换，直接插入到目标位置）
     */
    private Chromosome insertOperationForward(Chromosome chromosome, int pos, int steps, Map<String, Entry> entrys,Map<Integer, Entry> originalPositionIndex) {
        log("insertOperationForward:originalPositionIndex"+originalPositionIndex.size());

        Chromosome neighbor=copyChromosome(chromosome);// ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
        CopyOnWriteArrayList<Integer> os = neighbor.getOperationSequencing();

        if (pos <= 0 || pos >= os.size()) {
            return neighbor;
        }

        // 获取要移动的工序（基于原始chromosome）
        // Map<Integer, Entry> originalPositionIndex = buildPositionToEntryIndex(chromosome);
        Entry opToMove = originalPositionIndex.get(pos);
        if (opToMove == null) {
            return neighbor;
        }

        // 找到最远可以插入的位置（不打破优先级）
        int targetPos = Math.max(0, pos - steps);
        int finalTargetPos = pos;

        for (int i = pos - 1; i >= targetPos; i--) {
            Entry leftOp = originalPositionIndex.get(i);
            if (leftOp != null && opToMove.getGroupId() == leftOp.getGroupId()) {
                break;
            }
            if (leftOp != null && Math.abs(leftOp.getPriority() - opToMove.getPriority()) > 0.001) {
                break;
            }
            finalTargetPos = i;
        }

        if (finalTargetPos == pos) {
            return neighbor;
        }

        // 执行插入：移除原位置，插入到目标位置
        int value = os.remove(pos);
        os.add(finalTargetPos, value);
        neighbor.setOperationSequencing(os);
        return neighbor;
    }
    /**
     * 随机生成邻域解（兜底策略）
     */
    private Chromosome generateRandomNeighbor(Chromosome chromosome,Map<Integer, Entry> positionIndex,List<List<Integer>> positionByPriority) {
        int neighborType =4;// rnd.nextInt(5);
        log(String.format("随机生成邻域解-"+neighborType));
        log("generateRandomNeighbor:positionIndex"+positionIndex.size());
        log("generateRandomNeighbor:positionByPriority"+positionByPriority.size());

        switch (neighborType) {
            case 0:
                return generateSwapNeighbor(chromosome,positionIndex,positionByPriority);
            case 1:
                return generateReverseNeighbor(chromosome,positionIndex,positionByPriority);
            case 2:
                return generateInsertNeighbor(chromosome,positionIndex,positionByPriority);
            case 3:
                return generateMachineChangeNeighbor(chromosome);
            case 4:
                return generateSameMachineSwapNeighbor(chromosome);
            default:
                return generateSwapNeighbor(chromosome,positionIndex,positionByPriority);
        }
    }


    private Chromosome generateSwapNeighborWrapper(Chromosome chromosome) {
        log("generateSwapNeighborWrapper");

        Map<Integer, Object> obj = buildPositionToEntryIndex(chromosome);
        Map<Integer, Entry> positionToEntryIndex = (Map<Integer, Entry>) obj.get(1);
        List<List<Integer>> positionByPriority = (List<List<Integer>>) obj.get(2);
        return generateSwapNeighbor(chromosome, positionToEntryIndex, positionByPriority);
    }

    public Chromosome  copyChromosome(Chromosome chromosome)
    {
        geneticOperations.DelOrder(chromosome);
        Chromosome neighbor=new  Chromosome();
        neighbor.setGenerateType(chromosome.getGenerateType());
        neighbor.setID(UUID.randomUUID().toString());
        neighbor.setOperationSequencing(new CopyOnWriteArrayList<>(chromosome.getOperationSequencing()));
        neighbor.setMachineSelection(new CopyOnWriteArrayList<>(chromosome.getMachineSelection()));
        neighbor.setGlobalOpList(new CopyOnWriteArrayList<>(chromosome.getGlobalOpList()));

        neighbor.setScenarioID(chromosome.getScenarioID());
        neighbor.setBaseTime(chromosome.getBaseTime());
        neighbor.setFitnessLevel(chromosome.getFitnessLevel());
        // 拷贝 orders/allOperations/operatRel，确保 DelOrder 能正常清理 SF 工序
        if (chromosome.getOrders() != null) {
            neighbor.setOrders(new CopyOnWriteArrayList<>(chromosome.getOrders()));
        }
        if (chromosome.getAllOperations() != null) {
            neighbor.setAllOperations(new CopyOnWriteArrayList<>(chromosome.getAllOperations()));
        }
        if (chromosome.getOperatRel() != null) {
            neighbor.setOperatRel(new CopyOnWriteArrayList<>(chromosome.getOperatRel()));
        }
        return neighbor;
    }

    /**
     * 生成交换邻域解 - 只在相同优先级的工序之间交换
     */
    private Chromosome generateSwapNeighbor(Chromosome chromosome,Map<Integer, Entry> positionIndex,List<List<Integer>> positionByPriority) {
        log("generateSwapNeighbor"+positionIndex.size());
        Chromosome neighbor=copyChromosome(chromosome);
        CopyOnWriteArrayList<Integer> os = neighbor.getOperationSequencing();
        if (os.size() >= 2 && !positionByPriority.isEmpty()) {
            int maxAttempts = 50;
            for (int attempt = 0; attempt < maxAttempts; attempt++) {
                // 优先选择前面的优先级组（订单数多的），使用加权随机
                int priorityGroupIndex;
                if (positionByPriority.size() <= 3) {
                    priorityGroupIndex = rnd.nextInt(positionByPriority.size());
                } else {
                    // 70%概率选择前3个优先级组，30%概率选择其他
                    if (rnd.nextDouble() < 0.7) {
                        priorityGroupIndex = rnd.nextInt(Math.min(3, positionByPriority.size()));
                    } else {
                        int otherCount = positionByPriority.size() - 3;
                        priorityGroupIndex = 3 + rnd.nextInt(otherCount);
                    }
                }

                List<Integer> positionos = positionByPriority.get(priorityGroupIndex);
                if (positionos.size() < 2) continue;

                int idx1 = positionos.get(rnd.nextInt(positionos.size()));
                int idx2 = positionos.get(rnd.nextInt(positionos.size()));
                if (idx1 == idx2) continue;

                Entry op1 = positionIndex.get(idx1);
                Entry op2 = positionIndex.get(idx2);

                if (op1 != null && op2 != null) {
                    if (op1.getGroupId() != op2.getGroupId()) {
                        java.util.Collections.swap(os, idx1, idx2);
                        neighbor.setOperationSequencing(os);
                        break;
                    }
                }
            }
        }
        return neighbor;
    }
    private Chromosome generateReverseNeighborWrapper(Chromosome chromosome) {
        log("generateReverseNeighborWrapper");
        Map<Integer, Object> obj = buildPositionToEntryIndex(chromosome);
        Map<Integer, Entry> positionToEntryIndex = (Map<Integer, Entry>) obj.get(1);
        List<List<Integer>> positionByPriority = (List<List<Integer>>) obj.get(2);
        return generateReverseNeighbor(chromosome, positionToEntryIndex, positionByPriority);
    }
    /**
     * 生成反转邻域解 - 只反转相同优先级的连续工序
     */
    private Chromosome generateReverseNeighbor(Chromosome chromosome,Map<Integer, Entry> positionIndex,List<List<Integer>> positionByPriority) {
        log("generateReverseNeighbor"+positionIndex.size());

        Chromosome neighbor = copyChromosome(chromosome); //ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
        CopyOnWriteArrayList<Integer> os = neighbor.getOperationSequencing();
        if (os.size() >= 2&&positionByPriority.size()>0) {
            // Map<Integer, Entry> positionIndex = buildPositionToEntryIndex(neighbor);

            int maxAttempts = 50;
            for (int attempt = 0; attempt < maxAttempts; attempt++) {

                // 优先选择前面的优先级组（订单数多的），使用加权随机
                int priorityGroupIndex;
                if (positionByPriority.size() <= 3) {
                    priorityGroupIndex = rnd.nextInt(positionByPriority.size());
                } else {
                    // 70%概率选择前3个优先级组，30%概率选择其他
                    if (rnd.nextDouble() < 0.7) {
                        priorityGroupIndex = rnd.nextInt(Math.min(3, positionByPriority.size()));
                    } else {
                        int otherCount = positionByPriority.size() - 3;
                        priorityGroupIndex = 3 + rnd.nextInt(otherCount);
                    }
                }

                List<Integer> positionos = positionByPriority.get(priorityGroupIndex);
                if (positionos.size() < 2) continue;

                int startIdxInList = rnd.nextInt(positionos.size());
                int endIdxInList = rnd.nextInt(positionos.size());

                if (endIdxInList <= startIdxInList) continue;

                int start = positionos.get(startIdxInList);
                int end = positionos.get(endIdxInList);



                if (end <= start) continue;

                Entry startOp = positionIndex.get(start);
                if (startOp == null) continue;

                double priority = startOp.getPriority();
                boolean allSameGroupId = true;

//                for (int i = start; i <= end; i++) {
//                    Entry op = positionIndex.get(i);
//                    if (op == null||op.getGroupId()==startOp.getGroupId() ) {
//                        allSameGroupId = false;
//                        break;
//                    }
//                }

                //if (allSameGroupId) {
                java.util.Collections.reverse(os.subList(start, end + 1));
                neighbor.setOperationSequencing(os);
                break;
                // }
            }
        }
        return neighbor;
    }

    private Chromosome generateInsertNeighborWrapper(Chromosome chromosome) {
        log("generateInsertNeighborWrapper");
        Map<Integer, Object> obj = buildPositionToEntryIndex(chromosome);
        Map<Integer, Entry> positionToEntryIndex = (Map<Integer, Entry>) obj.get(1);
        List<List<Integer>> positionByPriority = (List<List<Integer>>) obj.get(2);
        return generateInsertNeighbor(chromosome, positionToEntryIndex, positionByPriority);
    }
    /**
     * 生成插入邻域解 - 只插入到相同优先级的位置
     */
    private Chromosome generateInsertNeighbor(Chromosome chromosome,Map<Integer, Entry> positionIndex,List<List<Integer>> positionByPriority) {
        Chromosome neighbor=copyChromosome(chromosome);// ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
        log("generateInsertNeighbor"+positionIndex.size());
        CopyOnWriteArrayList<Integer> os = neighbor.getOperationSequencing();
        if (os.size() >= 2&&positionByPriority.size()>0) {
            // Map<Integer, Entry> positionIndex = buildPositionToEntryIndex(neighbor);

            int maxAttempts = 50;
            for (int attempt = 0; attempt < maxAttempts; attempt++) {



                // 优先选择前面的优先级组（订单数多的），使用加权随机
                int priorityGroupIndex;
                if (positionByPriority.size() <= 3) {
                    priorityGroupIndex = rnd.nextInt(positionByPriority.size());
                } else {
                    // 70%概率选择前3个优先级组，30%概率选择其他
                    if (rnd.nextDouble() < 0.7) {
                        priorityGroupIndex = rnd.nextInt(Math.min(3, positionByPriority.size()));
                    } else {
                        int otherCount = positionByPriority.size() - 3;
                        priorityGroupIndex = 3 + rnd.nextInt(otherCount);
                    }
                }

                List<Integer> positionos = positionByPriority.get(priorityGroupIndex);

                if (positionos.size() < 2) continue;

                int idx1InList = rnd.nextInt(positionos.size());
                int idx2InList = rnd.nextInt(positionos.size());

                if (idx1InList == idx2InList) continue;

                int idx1 = positionos.get(idx1InList);
                int idx2 = positionos.get(idx2InList);

                if (idx1 == idx2) continue;

                Entry op1 = positionIndex.get(idx1);
                Entry op2 = positionIndex.get(idx2);

                if (op1 != null && op2 != null) {
                    if (op1.getGroupId()!=op2.getGroupId()) {
                        int value = os.remove(idx1);
                        os.add(idx2, value);
                        neighbor.setOperationSequencing(os);
                        break;
                    }
                }
            }
        }
        return neighbor;
    }

    /**
     * 生成机器选择邻域解 - 不受优先级限制
     */
    private Chromosome generateMachineChangeNeighbor(Chromosome chromosome) {
        log("generateMachineChangeNeighbor");
        Chromosome neighbor=copyChromosome(chromosome);
        CopyOnWriteArrayList<Integer> ms = neighbor.getMachineSelection();
        if (!ms.isEmpty()) {
            int idx = rnd.nextInt(ms.size());
            GlobalOperationInfo globalOp = chromosome.getGlobalOpList().get(idx);
            Entry op = globalOp.getOp();

            if (op.getMachineOptions().size() > 1) {
                // 构建工序唯一键，用于频率跟踪
                String opKey = op.getGroupId() + "_" + op.getSequence();

                int currentMachineSeq = ms.get(idx);
                List<Integer> availableMachines = new ArrayList<>();
                List<MachineOption> machineOptions = new ArrayList<>();
                for (int i = 1; i <= op.getMachineOptions().size(); i++) {
                    if (i != currentMachineSeq) {
                        availableMachines.add(i);
                        machineOptions.add(op.getMachineOptions().get(i-1));
                    }
                }

                if (!availableMachines.isEmpty()) {
                    // 综合考虑负载均衡和选择多样性
                    int newMachineSeq = selectMachineByLoad(availableMachines, machineOptions, chromosome, opKey);
                    ms.set(idx, newMachineSeq);
                    neighbor.setMachineSelection(ms);

                    // 更新频率记录
                    Long selectedMachineId = op.getMachineOptions().get(newMachineSeq - 1).getMachineId();
                    updateMachineSelectFrequency(opKey, selectedMachineId);
                }
            }
        }
        return neighbor;
    }

    Chromosome generateSameMachineSwapNeighbor(Chromosome chromosome){
        log("generateSameMachineSwapNeighbor");

        List<Integer> os = chromosome.getOperationSequencing();

        Map<String, Integer> machinePositionIndex = buildEntryMachinePositionIndex(chromosome);

        Map<Integer, Object> obj = buildPositionToEntryIndex(chromosome);
        Map<Integer, Entry> positionIndex =(Map<Integer, Entry>)obj.get(1);
        List<List<Integer>> positionByPriority = (List<List<Integer>>)obj.get(2);

        return  generateSameMachineSwapNeighbor(chromosome,rnd.nextInt(os.size()),positionIndex,machinePositionIndex);
    }

    private Chromosome generateSameMachineSwapNeighbor(Chromosome chromosome,int idx1,Map<Integer, Entry> positionIndex,Map<String, Integer> machinePositionIndex) {
        log("generateSameMachineSwapNeighbor");
        Chromosome neighbor=copyChromosome(chromosome);
        CopyOnWriteArrayList<Integer> os = neighbor.getOperationSequencing();
        CopyOnWriteArrayList<Integer> ms = neighbor.getMachineSelection();

        log(String.format("generateSameMachineSwapNeighbor: os.size=%d, ms.size=%d, idx1=%d, globalOpList.size=%d",
                os.size(), ms.size(), idx1,
                neighbor.getGlobalOpList() != null ? neighbor.getGlobalOpList().size() : 0));

        if (os.size() < 2 || ms.size() < 2) {
            log("generateSameMachineSwapNeighbor: os或ms太小，返回");
            return neighbor;
        }

        // ========== 修复1: op1 必须非 null ==========
        Entry op1 = positionIndex.get(idx1);
        if (op1 == null) {
            log(String.format("generateSameMachineSwapNeighbor: positionIndex中找不到idx1=%d", idx1));
            return neighbor;
        }
        log(String.format("generateSameMachineSwapNeighbor: op1=订单%d工序%d, machineOptions.size=%d",
                op1.getGroupId(), op1.getSequence(), op1.getMachineOptions().size()));

        // ========== 修复2: machinePositionIndex 查找必须非 null 且有效 ==========
        String op1Key = op1.getGroupId() + "_" + op1.getSequence();
        Integer maPos1 = machinePositionIndex.get(op1Key);
        if (maPos1 == null || maPos1 < 0 || maPos1 >= ms.size()) {
            log(String.format("generateSameMachineSwapNeighbor: maPos1=%s无效 (ms.size=%d)", maPos1, ms.size()));
            return neighbor;
        }

        int machineSeq1 = ms.get(maPos1);
        if (machineSeq1 < 1 || machineSeq1 > op1.getMachineOptions().size()) {
            log(String.format("generateSameMachineSwapNeighbor: machineSeq1=%d超出范围[1-%d]",
                    machineSeq1, op1.getMachineOptions().size()));
            return neighbor;
        }

        MachineOption machineOption1 = op1.getMachineOptions().get(machineSeq1 - 1);
        Long machineId1 = machineOption1.getMachineId();

        // ========== 修复3: 收集 os 位置（i）而非 ms 位置（maPos）==========
        List<Integer> sameMachineOsPositions = new ArrayList<>();

        for (int i = 0; i < os.size(); i++) {
            if (i == idx1) continue;

            Entry op = positionIndex.get(i);
            if (op == null) continue;

            String opKey = op.getGroupId() + "_" + op.getSequence();
            Integer maPos = machinePositionIndex.get(opKey);
            if (maPos == null || maPos < 0 || maPos >= ms.size()) continue;

            int machineSeq = ms.get(maPos);
            if (machineSeq < 1 || machineSeq > op.getMachineOptions().size()) continue;

            MachineOption machineOption = op.getMachineOptions().get(machineSeq - 1);
            Long machineId = machineOption.getMachineId();
            if (machineId == null) continue;

            if (machineId.equals(machineId1) && op1.getPriority() == op.getPriority() && op1.getGroupId() != op.getGroupId()) {
                sameMachineOsPositions.add(i);  // 关键: 存储 os 位置 i，不是 ms 位置 maPos
            }
        }

        if (sameMachineOsPositions.isEmpty()) {
            return neighbor;
        }

        // ========== 修复4: 确保 idx2 在 os 有效范围内 ==========
        int idx2 = sameMachineOsPositions.get(rnd.nextInt(sameMachineOsPositions.size()));
        if (idx2 < 0 || idx2 >= os.size() || idx1 < 0 || idx1 >= os.size()) {
            return neighbor;
        }

        // ========== 修复5: swap 使用两个 os 位置，完全一致 ==========
        Collections.swap(os, idx1, idx2);
        neighbor.setOperationSequencing(os);

        log(String.format("generateSameMachineSwapNeighbor: swap完成 idx1=%d(订单%d工序%d) <-> idx2=%d(订单%d工序%d), 同机器候选数=%d",
                idx1, op1.getGroupId(), op1.getSequence(),
                idx2, positionIndex.get(idx2).getGroupId(), positionIndex.get(idx2).getSequence(),
                sameMachineOsPositions.size()));

        return neighbor;
    }


//    private Chromosome generateSameMachineSwapNeighbor(Chromosome chromosome,int idx1,Map<Integer, Entry> positionIndex,Map<String, Integer> machinePositionIndex) {
//
//            Chromosome neighbor = ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
//            List<Integer> os = neighbor.getOperationSequencing();
//            List<Integer> ms = neighbor.getMachineSelection();
//
//            if (os.size() >= 2 && ms.size() >= 2) {
//
//                Map<Long, List<Integer>> machineToPositionsMap = new HashMap<>();
//
//                for (int i = 0; i < os.size(); i++) {
//                    Entry op = positionIndex.get(i);
//                    if (op == null) continue;
//
//                    int maPos = machinePositionIndex.get(op.getGroupId() + "_" + op.getSequence());
//                    if (maPos < 0) continue;
//
//                    int machineSeq = ms.get(maPos);
//                    if (machineSeq < 1 || machineSeq > op.getMachineOptions().size()) continue;
//
//                    MachineOption machineOption = op.getMachineOptions().get(machineSeq - 1);
//                    Long machineId = machineOption.getMachineId();
//                    if (machineId == null) continue;
//
//                    machineToPositionsMap.computeIfAbsent(machineId, k -> new ArrayList<>()).add(i);                }
//
//                List<int[]> validPairs = new ArrayList<>();
//
//                for (List<Integer> positions : machineToPositionsMap.values()) {
//                    if (positions.size() < 2) continue;
//
//                    for (int i = 0; i < positions.size(); i++) {
//                        for (int j = i + 1; j < positions.size(); j++) {
//                            int idx1 = positions.get(i);
//                            int idx2 = positions.get(j);
//
//                            Entry op1 = positionIndex.get(idx1);
//                            Entry op2 = positionIndex.get(idx2);
//
//                            if (op1 == null || op2 == null) continue;
//                            if (Math.abs(op1.getPriority() - op2.getPriority()) > 0.001) continue;
//                            if (op1.getGroupId()==(op2.getGroupId())) continue;
//
//                            validPairs.add(new int[]{idx1, idx2});
//                        }
//                    }
//                }
//
//                if (!validPairs.isEmpty()) {
//                    int[] pair = validPairs.get(rnd.nextInt(validPairs.size()));
//                    Collections.swap(os, pair[0], pair[1]);
//                    neighbor.setOperationSequencing(os);
//                }
//            }
//            return neighbor;
//        }

    /**
     * 局部搜索
     */
    private Chromosome localSearch(Chromosome chromosome, GeneticDecoder decoder, List<Machine> machines) {

        Chromosome best =copyChromosome(chromosome);
        decode(decoder, best, machines);
        Chromosome current = lightCopy(best);

        writeKpi(best);
        // 预定义邻域结构，避免每次循环重复创建
        List<NeighborhoodStructure> neighborhoods = defineNeighborhoods();

        // 生成邻域解（限制数量以提高性能）
        List<Chromosome> neighbors = new ArrayList<>();

        for (NeighborhoodStructure neighborhood : neighborhoods) {
            if (neighbors.size() >= MAX_LOCAL_SEARCH_NEIGHBORS) {
                break;
            }

            Chromosome neighbor = generateNeighbor(current, neighborhood);
            if (neighbor != null) {
                neighbors.add(neighbor);
            }
        }

        if (neighbors.isEmpty()) {
            return best;
        }

        Batchdecode(decoder, neighbors, machines);

        // 评估所有邻域解，找到最佳改进
        Chromosome bestNeighbor = best;
        for (Chromosome neighbor : neighbors) {
            if (neighbor != null && isBetter(neighbor, bestNeighbor)) {
                bestNeighbor = neighbor;
            }
        }

        if (bestNeighbor != best) {
            writeKpi(bestNeighbor);
        }

        return bestNeighbor;
    }


    /**
     * 解码染色体
     */
    private void decode(GeneticDecoder decoder, Chromosome chromosome , List<Machine> machines) {
        // MS 校验：解码前检查 machineSelection 与 machineOptions 是否匹配
        List<GlobalOperationInfo> gops = chromosome.getGlobalOpList();
        List<Integer> msCheck = chromosome.getMachineSelection();
        if (gops != null && msCheck != null) {
            int msErrors = 0;
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < Math.min(gops.size(), msCheck.size()); i++) {
                Entry op = gops.get(i).getOp();
                int msVal = msCheck.get(i);
                if (op != null && op.getMachineOptions() != null
                        && (msVal < 1 || msVal > op.getMachineOptions().size())) {
                    msErrors++;
                    if (msErrors <= 3) {
                        sb.append(String.format(" [idx=%d 订单%d工序%d ms=%d range=1-%d]",
                                i, op.getGroupId(), op.getSequence(), msVal, op.getMachineOptions().size()));
                    }
                }
            }
            if (msErrors > 0) {
                log(String.format("decode-MS校验失败: 共%d处越界 %s", msErrors, sb.toString()));
            }
        }

        chromosome.setResult(new CopyOnWriteArrayList<>());

        // 缓存 Machine 列表（第一次调用时缓存）
        if (cachedMachines == null) {
            cachedMachines = ProductionDeepCopyUtil.deepCopyList(machines, Machine.class);
        }

        // 使用缓存的列表，避免重复深拷贝
        chromosome.setMachines(ProductionDeepCopyUtil.deepCopyList(cachedMachines, Machine.class));
        chromosome.setOrders(ProductionDeepCopyUtil.deepCopyList(new CopyOnWriteArrayList<>(cachedOrders), Order.class));
        chromosome.setOperatRel(ProductionDeepCopyUtil.deepCopyList(new CopyOnWriteArrayList<>(cachedEntryRel), GroupResult.class));
        chromosome.setMaterials(ProductionDeepCopyUtil.deepCopyTreeMap(cachedMaterials, String.class, Material.class));
        chromosome.setAllOperations(ProductionDeepCopyUtil.deepCopyList(new CopyOnWriteArrayList<>(cachedAllOperations), Entry.class));

        // 加载锁定工单到ResultOld
        List<GAScheduleResult> lockedOrders = GlobalCacheUtil.get("locked_orders_" + chromosome.getScenarioID());
        if (lockedOrders != null && !lockedOrders.isEmpty()) {
            chromosome.setResultOld(ProductionDeepCopyUtil.deepCopyList(lockedOrders, GAScheduleResult.class));
        } else {
            chromosome.setResultOld(new CopyOnWriteArrayList<>());
        }
        decoder.decodeChromosomeWithCache(chromosome,false);
    }

    private void Batchdecode(GeneticDecoder decoder, List<Chromosome> chromosomes , List<Machine> machines) {
        // 缓存 Machine 列表（第一次调用时缓存）
        if (cachedMachines == null) {
            cachedMachines = ProductionDeepCopyUtil.deepCopyList(machines, Machine.class);
        }
        log(String.format("变邻域搜索 -复制对象S, 染色体数=" + chromosomes.size()));

        // 并行设置染色体字段
        chromosomes.parallelStream().forEach(chromosome -> {
            if (chromosome == null) return;

            chromosome.setResult(new CopyOnWriteArrayList<>());

            // 使用缓存的列表，避免重复深拷贝
            chromosome.setMachines(ProductionDeepCopyUtil.deepCopyList(cachedMachines, Machine.class));
            chromosome.setOrders(ProductionDeepCopyUtil.deepCopyList(new CopyOnWriteArrayList<>(cachedOrders), Order.class));
            chromosome.setOperatRel(ProductionDeepCopyUtil.deepCopyList(new CopyOnWriteArrayList<>(cachedEntryRel), GroupResult.class));
            chromosome.setMaterials(ProductionDeepCopyUtil.deepCopyTreeMap(cachedMaterials,String.class, Material.class));
            chromosome.setAllOperations(ProductionDeepCopyUtil.deepCopyList(new CopyOnWriteArrayList<>(cachedAllOperations), Entry.class));

            // 加载锁定工单到ResultOld
            List<GAScheduleResult> lockedOrders = GlobalCacheUtil.get("locked_orders_" + chromosome.getScenarioID());
            if (lockedOrders != null && !lockedOrders.isEmpty()) {
                chromosome.setResultOld(ProductionDeepCopyUtil.deepCopyList(lockedOrders, GAScheduleResult.class));
            } else {
                chromosome.setResultOld(new CopyOnWriteArrayList<>());
            }
        });

        log(String.format("变邻域搜索 -复制对象E"));

        // 并行解码所有候选方案
        decoder.Chromosomedecode(chromosomes);
    }


    /**
     * 比较两个染色体的优劣
     */
    private boolean isBetter(Chromosome c1, Chromosome c2) {
        return fitnessCalculator.isBetter(c1,c2);
    }

    // ==================== VNS 内部辅助工具 ====================

    /**
     * 估计两个逗号分隔字符串的汉明距离（位置不同的元素数）。
     * 用于辅助判断"是否只是微调"。
     */
    private int estimateHammingDistance(String a, String b) {
        if (a == null || b == null) return Integer.MAX_VALUE;
        if (a.isEmpty() || b.isEmpty()) return Integer.MAX_VALUE;
        String[] sa = a.split(",");
        String[] sb = b.split(",");
        int minLen = Math.min(sa.length, sb.length);
        int diff = 0;
        for (int i = 0; i < minLen; i++) {
            if (!sa[i].equals(sb[i])) diff++;
        }
        diff += Math.abs(sa.length - sb.length);
        return diff;
    }

    /**
     * 对 chromosome 的 operationSequencing（工序排序片段）做一次小型随机扰动，
     * 用于策略多样化（连续换设备策略后强制做点工序级探索）。
     */
    private Chromosome tryShuffleOperationPart(Chromosome c) {
        if (c == null) return null;
        String opStr = c.getOperationStr();
        if (opStr == null || opStr.isEmpty()) return c;
        String[] parts = opStr.split(",");
        if (parts.length < 4) return c;

        Chromosome copy = ProductionDeepCopyUtil.deepCopy(c, Chromosome.class);

        int n = parts.length;
        int swaps = Math.max(5, Math.min(15, n / 400));
        for (int s = 0; s < swaps; s++) {
            int i = rnd.nextInt(n);
            int j = rnd.nextInt(n);
            if (i != j) {
                String tmp = parts[i];
                parts[i] = parts[j];
                parts[j] = tmp;
            }
        }
        CopyOnWriteArrayList<Integer> newOps = new CopyOnWriteArrayList<>();
        for (String p : parts) {
            try {
                newOps.add(Integer.parseInt(p.trim()));
            } catch (NumberFormatException ignored) {
            }
        }
        if (newOps.size() >= 2) {
            copy.setOperationSequencing(newOps);
        }
        return copy;
    }

    /**
     * 构建位置索引：groupId_sequence -> position
     */
    private Map<String, Integer> buildPositionIndex(Chromosome chromosome) {
        Map<String, Integer> index = new HashMap<>();
        List<Integer> os = chromosome.getOperationSequencing();



        Map<Integer, Integer> orderProcessCounter = new HashMap<>();

        for (int i = 0; i < os.size(); i++) {
            int groupId = os.get(i);
            int count = orderProcessCounter.getOrDefault(groupId, 0) + 1;
            orderProcessCounter.put(groupId, count);

            String key = groupId + "_" + count;
            index.put(key, i);
        }


        return index;
    }

    /**
     * 构建位置索引：groupId_sequence -> Machines position
     */
    private Map<String, Integer> buildEntryMachinePositionIndex(Chromosome chromosome) {
        Map<String, Integer> index = new HashMap<>();
        List<GlobalOperationInfo> globalOpList = chromosome.getGlobalOpList();

        for (int i = 0; i < globalOpList.size(); i++) {
            GlobalOperationInfo globalOp = globalOpList.get(i);
            Entry op = globalOp.getOp();
            int groupId = op.getGroupId();
            int count = op.getSequence();

            String key = groupId + "_" + count;
            index.put(key, i);
        }
        return index;
    }
    /**
     * 轻量拷贝：只复制 generateNeighbor/DelOrder 需要的字段，避免全量 JSON 深拷贝导致 OOM。
     * result/machines/operatRel 等重型数据共享引用（generateNeighbor 只读，不修改）。
     */
    private Chromosome lightCopy(Chromosome source) {
        Chromosome copy = new Chromosome();
        copy.setOperationSequencing(new CopyOnWriteArrayList<>(source.getOperationSequencing()));
        copy.setMachineSelection(new CopyOnWriteArrayList<>(source.getMachineSelection()));
        copy.setGlobalOpList(new CopyOnWriteArrayList<>(source.getGlobalOpList()));
        copy.setOrders(new CopyOnWriteArrayList<>(source.getOrders()));
        copy.setAllOperations(new CopyOnWriteArrayList<>(source.getAllOperations()));
        copy.setResult(source.getResult());
        copy.setMachines(source.getMachines());
        copy.setOperatRel(new CopyOnWriteArrayList<>(source.getOperatRel()));
        copy.setScenarioID(source.getScenarioID());
        copy.setBaseTime(source.getBaseTime());
        copy.setGenerateType(source.getGenerateType());
        copy.setFitnessLevel(source.getFitnessLevel());
        copy.setFitness(source.getFitness());
        geneticOperations.DelOrder(copy);
        return copy;
    }
    /**
     * 构建位置->Entry索引
     */
    private Map<Integer, Object> buildPositionToEntryIndex(Chromosome chromosome) {
        Map<Integer, Object> obj = new HashMap<>();

        Map<Integer, Entry> index = new HashMap<>();
        //将位置按照优先级分组
        Map<Double, List<Integer>> indexByPriorityMap = new HashMap<>();

        Map<Double, Set<Integer>> groupidByPriority = new HashMap<>();

        List<Integer> os = chromosome.getOperationSequencing();
        log(String.format("buildPositionToEntryIndex--工序: %d,工序序列: %d，设备: %d,设备序列: %d",
                chromosome.getAllOperations().size(), os.size(), chromosome.getGlobalOpList().size(), chromosome.getMachineSelection().size()));

        Map<Integer, Integer> orderProcessCounter = new HashMap<>();

        for (int i = 0; i < os.size(); i++) {
            int groupId = os.get(i);
            int count = orderProcessCounter.getOrDefault(groupId, 0) + 1;
            orderProcessCounter.put(groupId, count);

            String key = groupId + "_" + count;
            Entry op = entrys.get(key);

            if (op != null) {
                index.put(i, op);
                double priority = op.getPriority();
                indexByPriorityMap.computeIfAbsent(priority, k -> new ArrayList<>()).add(i);
                groupidByPriority.computeIfAbsent(priority, k -> new HashSet()).add(op.getGroupId());
            }
        }

        groupidByPriority.entrySet().removeIf(entry -> entry.getValue().size() == 1);
//        if(groupidByPriority.size()!=0)
//        {
        indexByPriorityMap.keySet().removeIf(key -> !groupidByPriority.containsKey(key));

        //}

        List<Map.Entry<Double, List<Integer>>> sortedEntries = new ArrayList<>(indexByPriorityMap.entrySet());
        // if(groupidByPriority.size()!=0) {
        sortedEntries.sort((e1, e2) -> {
            int size1 = groupidByPriority.get(e1.getKey()).size();
            int size2 = groupidByPriority.get(e2.getKey()).size();
            return Integer.compare(size2, size1); // 降序：订单数多的排前面
        });
        // }

        List<List<Integer>> indexByPriority = new ArrayList<>();
        for (Map.Entry<Double, List<Integer>> entry : sortedEntries) {
            indexByPriority.add(entry.getValue());
        }
        obj.put(1,index);
        obj.put(2,indexByPriority);
        return obj;
    }

    /**
     * 构建Entry索引：op.getGroupId() + "_" + op.getSequence() -> Entry
     */
    private Map<Integer, Object> buildEntryKey() {
        Map<Integer, Object> index0 = new HashMap<>();
        Map<String, Entry> index = new HashMap<>();
        Map<Integer, Entry> index2 = new HashMap<>();
        List<Entry> allOps = this.allOperations;

        for (Entry op : allOps) {
            String key = op.getGroupId() + "_" + op.getSequence();

            index.put(key, op);
            index2.put(op.getId(), op);
        }
        index0.put(1,index);
        index0.put(2,index2);
        return index0;
    }

    /**
     * 邻域结构接口
     */
    private interface NeighborhoodOperator {
        Chromosome apply(Chromosome chromosome);
    }

    /**
     * 邻域结构类
     */
    private class NeighborhoodStructure {
        private String name;
        private NeighborhoodOperator operator;

        public NeighborhoodStructure(String name, NeighborhoodOperator operator) {
            this.name = name;
            this.operator = operator;
        }

        public Chromosome apply(Chromosome chromosome) {
            return operator.apply(chromosome);
        }
    }

    /**
     * 机器选项和负载信息的辅助类
     */
    private static class MachineOptionWithScore {
        int seq;
        MachineOption option;
        double score;  // 综合评分（越高越优）
        double utilization;  // 设备利用率
        int frequency;  // 该设备被该工序选择的次数
        double diversityScore;  // 多样性评分

        MachineOptionWithScore(int seq, MachineOption option, double utilization, int frequency, double diversityScore) {
            this.seq = seq;
            this.option = option;
            this.utilization = utilization;
            this.frequency = frequency;
            this.diversityScore = diversityScore;
            this.score = 0.0;
        }
    }

    /**
     * 选择设备 - 综合考虑负载均衡和设备选择多样性
     * 综合评分：score = 负载均衡分 * 权重 + 多样性分 * 权重 + 随机扰动
     * - 负载均衡分 = 1 - utilization（利用率越低越好）
     * - 多样性分 = 1 / (1 + frequency)（选择次数越少越好）
     * - 然后使用加权轮盘赌选择，得分最高的设备
     */
    private int selectMachineByLoad(List<Integer> availableMachineSeqs, List<MachineOption> machineOptions, Chromosome chromosome, String opKey) {
        // 计算当前各设备的负载（利用率）— 只计算有限产能设备（false）
        // 这样利用率计算更准确，不会被无限产能机器的工序"稀释"
        Map<Long, Double> machineUtilization = calculateMachineUtilization(chromosome, false);

        // 预计算无限产能机器ID集合（这些设备可以作为目标，因为不受时间约束）
        Set<Long> infiniteMachineIds = new HashSet<>();
        List<GAScheduleResult> allResults = chromosome.getResult();
        if (allResults != null) {
            for (GAScheduleResult r : allResults) {
                if ("Infinite".equals(r.getCapacityTypeName())) {
                    infiniteMachineIds.add(r.getMachineId());
                }
            }
        }

        // 构建候选机器列表：包含有限产能和无限产能机器
        // - 有限产能机器：用真实利用率评分
        // - 无限产能机器：视为利用率=0（永远空闲），给予高评分
        List<MachineOptionWithScore> availableMachines = new ArrayList<>();

        for (int seq : availableMachineSeqs) {
            if (seq - 1 >= machineOptions.size()) {
                break;
            }
            MachineOption option = machineOptions.get(seq - 1);
            Long machineId = option.getMachineId();

            double utilization;
            boolean isInfiniteMachine = infiniteMachineIds.contains(machineId);

            if (isInfiniteMachine) {
                // 无限产能机器：视为 utilization=0，因为它不受时间约束
                utilization = 0.0;
            } else {
                // 有限产能机器：用真实利用率
                utilization = machineUtilization.getOrDefault(machineId, 0.0);
            }

            // 获取该工序对该设备的选择次数
            int frequency = 0;
            if (opKey != null && opMachineSelectFrequency.containsKey(opKey)) {
                frequency = opMachineSelectFrequency.get(opKey).getOrDefault(machineId, 0);
            }

            // 归一化多样性分：选择次数越少，分越高（0~1范围
            double diversity = 1.0 / (1.0 + frequency);  // 0次→1, 1次→0.5, 2次→0.33...

            // 综合评分：优先选负载低（1-utilization）且历史选择次数少的设备
            // 对于无限产能机器，因为 utilization=0，loadBalanceScore=1.0，会得到较高评分
            double loadBalanceScore = (1.0 - utilization);
            double noise = rnd.nextDouble() * RANDOM_NOISE_FOR_MACHINE;
            double score = LOAD_BALANCE_WEIGHT * loadBalanceScore
                    + DIVERSITY_WEIGHT * diversity
                    + noise;

            MachineOptionWithScore machineWithScore = new MachineOptionWithScore(seq, option, utilization, frequency, diversity);
            machineWithScore.score = score;
            availableMachines.add(machineWithScore);
        }

        // 如果没有可用机器，返回第一个选项（兜底）
        if (availableMachines.isEmpty()) {
            return availableMachineSeqs.get(0);
        }

        // 按综合评分降序排序
        availableMachines.sort((m1, m2) -> Double.compare(m2.score, m1.score));

        // 先计算选中的机器，再输出日志，最后返回
        int selectedMachineSeq;
        if (rnd.nextDouble() < 0.7) {
            selectedMachineSeq = availableMachines.get(0).seq;
        } else {
            // 按评分加权随机选择
            double totalScore = 0;
            for (MachineOptionWithScore m : availableMachines) {
                totalScore += Math.max(m.score, 0.001);
            }
            double r = rnd.nextDouble() * totalScore;
            double cumSum = 0;
            selectedMachineSeq = availableMachines.get(availableMachines.size() - 1).seq;
            for (MachineOptionWithScore m : availableMachines) {
                cumSum += Math.max(m.score, 0.001);
                if (r <= cumSum) {
                    selectedMachineSeq = m.seq;
                    break;
                }
            }
        }

        // === 日志：输出设备分配决策 ===
        StringBuilder machineLog = new StringBuilder();
        Long selectedId = machineOptions.get(selectedMachineSeq - 1).getMachineId();
        boolean selectedIsInfinite = infiniteMachineIds.contains(selectedId);
        machineLog.append(String.format("[设备分配] 工序=%s, 选中=设备%d(%s, 利用率=%.2f%%, 历史次数=%d) | 候选%d台:",
                opKey != null ? opKey : "未知",
                selectedId,
                selectedIsInfinite ? "无限产能" : "有限产能",
                machineUtilization.getOrDefault(selectedId, 0.0) * 100,
                opKey != null ? opMachineSelectFrequency.getOrDefault(opKey, new HashMap<>()).getOrDefault(selectedId, 0) : 0,
                availableMachines.size()));

        // 找到选中设备的准确评分
        for (MachineOptionWithScore m : availableMachines) {
            String machineType = infiniteMachineIds.contains(m.option.getMachineId()) ? "无限" : "有限";
            machineLog.append(String.format(" 设备%d(%s产能, 评分=%.3f, 利用率=%.2f%%, 次数=%d)%s",
                    m.option.getMachineId(), machineType, m.score, m.utilization * 100, m.frequency,
                    m.seq == selectedMachineSeq ? "←选中" : ""));
        }
        log(machineLog.toString(), false);

        return selectedMachineSeq;
    }

    /**
     * 更新工序-设备选择频率记录
     */
    private void updateMachineSelectFrequency(String opKey, Long machineId) {
        if (opKey == null || opKey.isEmpty() || machineId == null || machineId <= 0) return;
        opMachineSelectFrequency.computeIfAbsent(opKey, k -> new HashMap<>()).merge(machineId, 1, Integer::sum);
    }

    /**
     * 初始化所有频率表（在整个优化流程开始时调用一次）
     * 频率在模拟退火、变邻域搜索、禁忌搜索等所有算法中共享，不会随单个算法search调用而重置
     * 这样才能真正鼓励探索多样性：
     *   1) 同一工序尝试不同的设备
     *   2) 尝试不同的瓶颈设备
     *   3) 尝试不同的瓶颈工序作为优化目标
     */
    public void initMachineSelectFrequency() {
        opMachineSelectFrequency.clear();
        bottleneckMachineFrequency.clear();
        bottleneckOpFrequency.clear();
    }

    /**
     * 获取频率表（用于调试日志）
     */
    public Map<String, Map<Long, Integer>> getMachineSelectFrequency() {
        return opMachineSelectFrequency;
    }

    public Map<Long, Integer> getBottleneckMachineFrequency() {
        return bottleneckMachineFrequency;
    }

    public Map<Integer, Integer> getBottleneckOpFrequency() {
        return bottleneckOpFrequency;
    }

    /**
     * 交换候选对象，包含位置和评分（用于准备时间优化）
     */
    private static class SwapCandidate {
        int position;
        double score;

        SwapCandidate(int position, double score) {
            this.position = position;
            this.score = score;
        }
    }

    /**
     * 瓶颈设备工序激进重排 - Wrapper方法
     */
    private Chromosome aggressiveBottleneckReorderWrapper(Chromosome chromosome) {
        log("aggressiveBottleneckReorderWrapper");
        List<GAScheduleResult> results = chromosome.getResult().stream().
                filter(t->!t.getCapacityTypeName().equals("Infinite"))
                .collect(Collectors.toList());
        Map<Integer, Object> obj = buildPositionToEntryIndex(chromosome);
        Map<Integer, Entry> positionToEntryIndex = (Map<Integer, Entry>) obj.get(1);
        List<List<Integer>> positionByPriority = (List<List<Integer>>) obj.get(2);
        Map<String, Integer> machinePositionIndex = buildEntryMachinePositionIndex(chromosome);

        if (results == null || results.isEmpty()) {
            return generateRandomNeighbor(chromosome, positionToEntryIndex, positionByPriority);
        }

        Long bottleneckMachineId = findBottleneckMachine(chromosome);
        if (bottleneckMachineId != null) {
            Chromosome result = tryAggressiveBottleneckReorder(chromosome, bottleneckMachineId, positionToEntryIndex, machinePositionIndex);
            if (result != null) {
                return result;
            }
        }
        return generateRandomNeighbor(chromosome, positionToEntryIndex, positionByPriority);
    }

    /**
     * 瓶颈设备工序激进重排 - 更激进地调整瓶颈设备上的工序顺序
     * 策略：将延迟订单的工序和高优先级工序尽可能往前移动
     */
    private Chromosome tryAggressiveBottleneckReorder(Chromosome chromosome, Long bottleneckMachineId,
                                                      Map<Integer, Entry> positionIndex,
                                                      Map<String, Integer> machinePositionIndex) {
        log("tryAggressiveBottleneckReorder: 开始激进重排瓶颈设备工序");

        List<GAScheduleResult> allResults = chromosome.getResult().stream().
                filter(t->!t.getCapacityTypeName().equals("Infinite"))
                .collect(Collectors.toList());
        if (allResults == null || allResults.isEmpty()) {
            return null;
        }

        // 获取瓶颈设备上的所有工序
        List<GAScheduleResult> bottleneckOps = allResults.stream()
                .filter(r -> r.getMachineId()==(bottleneckMachineId))
                .collect(Collectors.toList());

        if (bottleneckOps.size() < 2) {
            log("tryAggressiveBottleneckReorder: 瓶颈设备上工序太少，无法重排");
            return null;
        }

        // 计算订单完成时间
        Map<Integer, Integer> orderCompletionTimes = calculateOrderCompletionTimes(allResults);

        // 找出延迟订单（结束时间 > 到期时间，假设Entry有dueDate字段，这里简化为结束时间较晚的订单）
        Set<Integer> delayedOrderIds = new HashSet<>();
        int avgCompletionTime = (int) orderCompletionTimes.values().stream()
                .mapToInt(Integer::intValue)
                .average()
                .orElse(0);

        for (Map.Entry<Integer, Integer> entry : orderCompletionTimes.entrySet()) {
            if (entry.getValue() > avgCompletionTime * 1.2) { // 超过平均完成时间20%视为延迟
                delayedOrderIds.add(entry.getKey());
            }
        }

        Chromosome neighbor = copyChromosome(chromosome);
        List<Integer> os = neighbor.getOperationSequencing();

        // 对瓶颈设备上的工序进行评分
        List<OperationScore> scoredOps = new ArrayList<>();
        for (GAScheduleResult op : bottleneckOps) {
            Entry entry = entrybyids.get(op.getOperationId());
            if (entry == null) continue;

            double score = 0;
            // 1. 延迟订单的工序加分
            if (delayedOrderIds.contains(op.getGroupId())) {
                score += 100;
            }
            // 2. 高优先级工序加分（注意：priority值越低优先级越高）
            score += (10.0 / (entry.getPriority() + 0.1)) * 50; // 优先级值越低，得分越高
            // 3. 结束时间晚的工序加分（优先移动）
            score += (double) op.getEndTime() / 10000;

            String key = entry.getGroupId() + "_" + entry.getSequence();
            Integer pos = buildPositionIndex(chromosome).get(key);
            if (pos != null) {
                scoredOps.add(new OperationScore(pos, score));
            }
        }

        if (scoredOps.size() < 2) {
            return null;
        }

        // 按评分从高到低排序
        scoredOps.sort((a, b) -> Double.compare(b.score, a.score));

        // 选择评分最高的工序，尝试往前移动
        OperationScore selectedOp = scoredOps.get(0);
        int steps = rnd.nextInt(Math.min(10, selectedOp.position)) + 1; // 最多往前移动10步

        log(String.format("tryAggressiveBottleneckReorder: 选择位置%d，往前移动%d步", selectedOp.position, steps));

        return insertOperationForward(neighbor, selectedOp.position, steps, entrys, positionIndex);
    }

    /**
     * 工序评分辅助类
     */
    private static class OperationScore {
        int position;
        double score;

        OperationScore(int position, double score) {
            this.position = position;
            this.score = score;
        }
    }

    /**
     * 关键路径工序优化 - Wrapper方法
     */
    private Chromosome criticalPathOptimizeWrapper(Chromosome chromosome) {
        log("criticalPathOptimizeWrapper");

        List<GAScheduleResult> results = chromosome.getResult().stream().
                filter(t->!t.getCapacityTypeName().equals("Infinite"))
                .collect(Collectors.toList());
        Map<Integer, Object> obj = buildPositionToEntryIndex(chromosome);
        Map<Integer, Entry> positionToEntryIndex = (Map<Integer, Entry>) obj.get(1);
        List<List<Integer>> positionByPriority = (List<List<Integer>>) obj.get(2);

        if (results == null || results.isEmpty()) {
            return generateRandomNeighbor(chromosome, positionToEntryIndex, positionByPriority);
        }

        Long bottleneckMachineId = findBottleneckMachine(chromosome);
        Chromosome result = tryCriticalPathOptimize(chromosome, bottleneckMachineId, positionToEntryIndex);
        if (result != null) {
            return result;
        }
        return generateRandomNeighbor(chromosome, positionToEntryIndex, positionByPriority);
    }

    /**
     * 关键路径工序优化 - 专门针对关键路径上的工序进行优化
     * 策略：
     * 1. 找出关键路径上的工序
     * 2. 优先尝试将关键路径工序往前移动
     * 3. 尝试为关键路径工序换设备（如果有选择）
     */
    private Chromosome tryCriticalPathOptimize(Chromosome chromosome, Long bottleneckMachineId,
                                               Map<Integer, Entry> positionIndex) {
        log("tryCriticalPathOptimize: 开始关键路径工序优化");

        List<GAScheduleResult> allResults = chromosome.getResult().stream().
                filter(t->!t.getCapacityTypeName().equals("Infinite"))
                .collect(Collectors.toList());
        if (allResults == null || allResults.isEmpty()) {
            return null;
        }

        // 分析瓶颈工序，获取关键路径信息
        List<BottleneckOperationAnalysis> analyses = analyzeBottleneckOperations(allResults, bottleneckMachineId);

        // 找出关键路径上的工序
        List<BottleneckOperationAnalysis> criticalPathOps = analyses.stream()
                .filter(a -> a.onCriticalPath)
                .collect(Collectors.toList());

        if (criticalPathOps.isEmpty()) {
            log("tryCriticalPathOptimize: 没有找到关键路径工序");
            return null;
        }

        log(String.format("tryCriticalPathOptimize: 找到%d个关键路径工序", criticalPathOps.size()));

        Chromosome neighbor = copyChromosome(chromosome);
        List<Integer> os = neighbor.getOperationSequencing();

        // 对关键路径工序进行评分
        List<CriticalPathOpScore> scoredOps = new ArrayList<>();
        for (BottleneckOperationAnalysis boa : criticalPathOps) {
            GAScheduleResult op = boa.operation;
            Entry entry = entrybyids.get(op.getOperationId());
            if (entry == null) continue;

            double score = 0;
            // 1. 在瓶颈设备上的关键工序加分
            if (bottleneckMachineId != null && op.getMachineId()==(bottleneckMachineId)) {
                score += 100;
            }
            // 2. 等待时间长的工序加分
            score += boa.waitTime / 100.0;
            // 3. 机器等待时间长的工序加分
            score += boa.machineWaitTime / 100.0;
            // 4. 高优先级加分（注意：priority值越低优先级越高）
            score += (10.0 / (entry.getPriority() + 0.1)) * 30; // 优先级值越低，得分越高

            String key = entry.getGroupId() + "_" + entry.getSequence();
            Integer pos = buildPositionIndex(chromosome).get(key);
            if (pos != null) {
                scoredOps.add(new CriticalPathOpScore(pos, entry, score));
            }
        }

        if (scoredOps.isEmpty()) {
            return null;
        }

        // 按评分从高到低排序
        scoredOps.sort((a, b) -> Double.compare(b.score, a.score));

        CriticalPathOpScore selected = scoredOps.get(0);

        // 50%概率尝试往前移动，50%概率尝试换设备（如果有选择）
        if (rnd.nextDouble() < 0.5 && selected.position > 0) {
            // 尝试往前移动
            int steps = rnd.nextInt(Math.min(5, selected.position)) + 1;
            log(String.format("tryCriticalPathOptimize: 关键路径工序往前移动%d步", steps));
            return insertOperationForward(neighbor, selected.position, steps, entrys, positionIndex);
        } else if (selected.entry.getMachineOptions().size() > 1) {
            // 尝试换设备
            log("tryCriticalPathOptimize: 关键路径工序尝试换设备");
            Map<String, Integer> machinePositionIndex = buildEntryMachinePositionIndex(chromosome);
            int maPos = machinePositionIndex.get(selected.entry.getGroupId() + "_" + selected.entry.getSequence());
            if (maPos >= 0) {
                return generateMachineChangeForSpecificOp(neighbor, selected.entry.getMachineOptions(), maPos);
            }
        }

        // 如果以上都失败，尝试简单的往前移动
        if (selected.position > 0) {
            int steps = rnd.nextInt(Math.min(3, selected.position)) + 1;
            return insertOperationForward(neighbor, selected.position, steps, entrys, positionIndex);
        }

        return null;
    }

    /**
     * 关键路径工序评分辅助类
     */
    private static class CriticalPathOpScore {
        int position;
        Entry entry;
        double score;

        CriticalPathOpScore(int position, Entry entry, double score) {
            this.position = position;
            this.entry = entry;
            this.score = score;
        }
    }

    // ==================== 激进变邻域方法 ====================

    /**
     * BlockMove - 移动工序块的变邻域方法包装器
     */
    private Chromosome blockMoveWrapper(Chromosome chromosome) {
        Map<Integer, Object> obj = buildPositionToEntryIndex(chromosome);
        Map<Integer, Entry> positionToEntryIndex = (Map<Integer, Entry>) obj.get(1);
        List<List<Integer>> positionByPriority = (List<List<Integer>>) obj.get(2);
        return blockMove(chromosome, positionToEntryIndex, positionByPriority);
    }

    /**
     * BlockMove - 移动一段连续的工序块到新位置
     * 优先选择包含瓶颈工序的块，遵守优先级约束
     */
    private Chromosome blockMove(Chromosome chromosome, Map<Integer, Entry> positionIndex, List<List<Integer>> positionByPriority) {
        Chromosome neighbor = copyChromosome(chromosome);
        List<Integer> os = neighbor.getOperationSequencing();
        int n = os.size();

        if (n < 5) return null; // 工序太少，无法进行块移动

        // 获取瓶颈工序
        Set<Integer> bottleneckOpIds = new HashSet<>();
        try {
            Map<String, Object> bottleneckAnalysis = findBottleneckMachineWithDetails(chromosome);
            List<GAScheduleResult> criticalOps = (List<GAScheduleResult>) bottleneckAnalysis.get("criticalOps");

            if (criticalOps != null) {
                for (GAScheduleResult op : criticalOps) {
                    bottleneckOpIds.add(op.getOperationId());
                }
            }
        } catch (Exception e) {
            log("BlockMove: 获取瓶颈信息失败，使用正常模式");
        }

        // 找出包含瓶颈工序的位置
        Set<Integer> bottleneckPositions = new HashSet<>();
        for (Map.Entry<Integer, Entry> entry : positionIndex.entrySet()) {
            if (bottleneckOpIds.contains(entry.getValue().getId())) {
                bottleneckPositions.add(entry.getKey());
            }
        }

        int maxAttempts = 20;
        for (int attempt = 0; attempt < maxAttempts; attempt++) {
            // 1. 选择块的起始位置 - 优先选择包含瓶颈工序的区域
            int blockStart;
            if (!bottleneckPositions.isEmpty() && rnd.nextDouble() < 0.7) {
                // 70%概率从瓶颈工序附近选择
                List<Integer> bottleneckPosList = new ArrayList<>(bottleneckPositions);
                int bottleneckPos = bottleneckPosList.get(rnd.nextInt(bottleneckPosList.size()));
                // 在瓶颈工序周围选择起始位置
                int minStart = Math.max(0, bottleneckPos - 5);
                int maxStart = Math.min(n - 4, bottleneckPos);
                blockStart = minStart + rnd.nextInt(maxStart - minStart + 1);
            } else {
                // 否则从高优先级组中选择
                if (!positionByPriority.isEmpty()) {
                    int priorityGroupIndex;
                    if (positionByPriority.size() <= 3) {
                        priorityGroupIndex = rnd.nextInt(positionByPriority.size());
                    } else {
                        if (rnd.nextDouble() < 0.7) {
                            priorityGroupIndex = rnd.nextInt(Math.min(3, positionByPriority.size()));
                        } else {
                            int otherCount = positionByPriority.size() - 3;
                            priorityGroupIndex = 3 + rnd.nextInt(otherCount);
                        }
                    }
                    List<Integer> positionos = positionByPriority.get(priorityGroupIndex);
                    if (!positionos.isEmpty()) {
                        blockStart = positionos.get(rnd.nextInt(positionos.size()));
                        blockStart = Math.max(0, Math.min(n - 4, blockStart));
                    } else {
                        blockStart = rnd.nextInt(n - 3);
                    }
                } else {
                    blockStart = rnd.nextInt(n - 3);
                }
            }

            // 2. 确定块大小：3-8个工序
            int maxBlockSize = Math.min(8, n - blockStart);
            int blockSize = rnd.nextInt(maxBlockSize - 2) + 3;
            int blockEnd = blockStart + blockSize;

            // 检查块中的工序是否都属于相似的优先级
            boolean validBlock = true;
            Double blockPriority = null;
            int bottleneckCount = 0;

            for (int i = blockStart; i < blockEnd && i < os.size(); i++) {
                Entry entry = positionIndex.get(i);
                if (entry != null) {
                    if (blockPriority == null) {
                        blockPriority = entry.getPriority();
                    } else if (Math.abs(entry.getPriority() - blockPriority) > 0.5) {
                        // 优先级差异太大，跳过这个块
                        validBlock = false;
                        break;
                    }
                    if (bottleneckOpIds.contains(entry.getId())) {
                        bottleneckCount++;
                    }
                }
            }

            if (!validBlock) continue;

            // 3. 选择新位置：不能在块内部，且尽量在同一优先级区域
            List<Integer> possiblePositions = new ArrayList<>();
            for (int pos = 0; pos < n - blockSize + 1; pos++) {
                if (pos < blockStart - 1 || pos > blockEnd + 1) {
                    possiblePositions.add(pos);
                }
            }

            if (possiblePositions.isEmpty()) continue;

            // 优先选择同样是高优先级的位置
            int newPosition;
            if (!positionByPriority.isEmpty() && blockPriority != null) {
                // 查找目标优先级组的位置
                List<Integer> targetPositions = new ArrayList<>();
                for (int pos : possiblePositions) {
                    Entry entry = positionIndex.get(pos);
                    if (entry != null && Math.abs(entry.getPriority() - blockPriority) <= 0.5) {                        targetPositions.add(pos);
                    }
                }
                if (!targetPositions.isEmpty() && rnd.nextDouble() < 0.7) {
                    newPosition = targetPositions.get(rnd.nextInt(targetPositions.size()));
                } else {
                    newPosition = possiblePositions.get(rnd.nextInt(possiblePositions.size()));
                }
            } else {
                newPosition = possiblePositions.get(rnd.nextInt(possiblePositions.size()));
            }

            log(String.format("BlockMove: 移动工序块 [%d,%d) -> %d, 块大小=%d, 瓶颈工序=%d/%d",
                    blockStart, blockEnd, newPosition, blockSize, bottleneckCount, blockSize));

            // 4. 执行块移动
            List<Integer> block = new ArrayList<>(os.subList(blockStart, blockEnd));
            os.subList(blockStart, blockEnd).clear();

            // 调整newPosition（因为移除块后索引变化了）
            if (newPosition > blockStart) {
                newPosition -= blockSize;
            }

            os.addAll(newPosition, block);

            return neighbor;
        }

        return null;
    }

    /**
     * MultiOperationSwap - 一次交换多个工序的包装器
     */
    private Chromosome multiOperationSwapWrapper(Chromosome chromosome) {
        Map<Integer, Object> obj = buildPositionToEntryIndex(chromosome);
        Map<Integer, Entry> positionToEntryIndex = (Map<Integer, Entry>) obj.get(1);
        List<List<Integer>> positionByPriority = (List<List<Integer>>) obj.get(2);
        return multiOperationSwap(chromosome, positionToEntryIndex, positionByPriority);
    }

    /**
     * MultiOperationSwap - 一次交换多对工序
     * 优先选择瓶颈工序和关键路径工序，遵守优先级约束
     */
    private Chromosome multiOperationSwap(Chromosome chromosome, Map<Integer, Entry> positionIndex, List<List<Integer>> positionByPriority) {
        Chromosome neighbor = copyChromosome(chromosome);
        List<Integer> os = neighbor.getOperationSequencing();
        int n = os.size();

        if (n < 4) return null; // 工序太少

        // 获取瓶颈工序和关键路径工序
        List<Integer> priorityPositions = new ArrayList<>();
        Set<Integer> bottleneckOpIds = new HashSet<>();

        try {
            Map<String, Object> bottleneckAnalysis = findBottleneckMachineWithDetails(chromosome);
            List<GAScheduleResult> criticalOps = (List<GAScheduleResult>) bottleneckAnalysis.get("criticalOps");

            if (criticalOps != null) {
                for (GAScheduleResult op : criticalOps) {
                    bottleneckOpIds.add(op.getOperationId());
                }
            }

            // 构建瓶颈工序的位置索引
            Map<String, Integer> posIndex = buildPositionIndex(chromosome);
            for (Map.Entry<Integer, Entry> entry : positionIndex.entrySet()) {
                if (bottleneckOpIds.contains(entry.getValue().getId())) {
                    priorityPositions.add(entry.getKey());
                }
            }
        } catch (Exception e) {
            log("MultiOperationSwap: 获取瓶颈信息失败，使用正常模式");
        }

        int swapPairs = rnd.nextInt(Math.min(3, n / 2)) + 1; // 1-3对交换
        Set<Integer> usedPositions = new HashSet<>();

        log(String.format("MultiOperationSwap: 准备执行 %d 对工序交换, 瓶颈工序数=%d", swapPairs, priorityPositions.size()));

        for (int pair = 0; pair < swapPairs; pair++) {
            int maxAttempts = 50;
            boolean found = false;

            for (int attempt = 0; attempt < maxAttempts && !found; attempt++) {
                int pos1, pos2;

                // 优先从瓶颈工序中选择，70%概率
                if (!priorityPositions.isEmpty() && rnd.nextDouble() < 0.7) {
                    pos1 = priorityPositions.get(rnd.nextInt(priorityPositions.size()));
                } else {
                    // 否则从优先级组中选择
                    if (positionByPriority.isEmpty()) {
                        pos1 = rnd.nextInt(n);
                    } else {
                        // 优先选择前面的优先级组
                        int priorityGroupIndex;
                        if (positionByPriority.size() <= 3) {
                            priorityGroupIndex = rnd.nextInt(positionByPriority.size());
                        } else {
                            if (rnd.nextDouble() < 0.7) {
                                priorityGroupIndex = rnd.nextInt(Math.min(3, positionByPriority.size()));
                            } else {
                                int otherCount = positionByPriority.size() - 3;
                                priorityGroupIndex = 3 + rnd.nextInt(otherCount);
                            }
                        }
                        List<Integer> positionos = positionByPriority.get(priorityGroupIndex);
                        if (positionos.isEmpty()) continue;
                        pos1 = positionos.get(rnd.nextInt(positionos.size()));
                    }
                }

                // 从同一个优先级组中选择pos2，确保优先级约束
                Entry entry1 = positionIndex.get(pos1);
                if (entry1 == null) continue;

                List<Integer> possiblePos2 = new ArrayList<>();

                // 查找同优先级的工序位置
                for (List<Integer> priorityGroup : positionByPriority) {
                    if (priorityGroup.contains(pos1)) {
                        possiblePos2 = priorityGroup.stream()
                                .filter(p -> p != pos1 && !usedPositions.contains(p))
                                .collect(Collectors.toList());
                        break;
                    }
                }

                // 如果没有找到同优先级的，从瓶颈工序中找一个
                if (possiblePos2.isEmpty() && !priorityPositions.isEmpty()) {
                    possiblePos2 = priorityPositions.stream()
                            .filter(p -> p != pos1 && !usedPositions.contains(p))
                            .collect(Collectors.toList());
                }

                // 如果还是没有，随机找一个（放宽约束）
                if (possiblePos2.isEmpty()) {
                    for (int i = 0; i < n; i++) {
                        if (i != pos1 && !usedPositions.contains(i)) {
                            possiblePos2.add(i);
                        }
                    }
                }

                if (possiblePos2.isEmpty()) continue;

                pos2 = possiblePos2.get(rnd.nextInt(possiblePos2.size()));

                if (pos1 == pos2 || usedPositions.contains(pos1) || usedPositions.contains(pos2)) {
                    continue;
                }

                Entry entry2 = positionIndex.get(pos2);
                if (entry1 == null || entry2 == null) continue;

                // 执行交换
                Integer temp = os.get(pos1);
                os.set(pos1, os.get(pos2));
                os.set(pos2, temp);

                usedPositions.add(pos1);
                usedPositions.add(pos2);

                String bottleneckTag1 = bottleneckOpIds.contains(entry1.getId()) ? "[瓶颈]" : "";
                String bottleneckTag2 = bottleneckOpIds.contains(entry2.getId()) ? "[瓶颈]" : "";

                log(String.format("  交换对 %d: pos=%d%s <-> pos=%d%s, 工单=%d<->%d",
                        pair + 1, pos1, bottleneckTag1, pos2, bottleneckTag2,
                        entry1.getGroupId(), entry2.getGroupId()));
                found = true;
                break;
            }
        }

        if (usedPositions.size() >= 2) {
            return neighbor;
        }

        return null;
    }

    /**
     * MultiMachineChange - 一次改变多个工序的机器选择的包装器
     */
    private Chromosome multiMachineChangeWrapper(Chromosome chromosome) {
        return multiMachineChange(chromosome);
    }

    /**
     * MultiMachineChange - 一次改变多个工序的机器选择
     * 优先选择瓶颈工序和关键路径工序
     */
    private Chromosome multiMachineChange(Chromosome chromosome) {
        Chromosome neighbor = copyChromosome(chromosome);
        List<GlobalOperationInfo> globalOps = neighbor.getGlobalOpList();
        List<Integer> machineSelection = neighbor.getMachineSelection();

        // 获取瓶颈工序
        Set<Integer> bottleneckOpIds = new HashSet<>();
        try {
            Map<String, Object> bottleneckAnalysis = findBottleneckMachineWithDetails(chromosome);
            List<GAScheduleResult> criticalOps = (List<GAScheduleResult>) bottleneckAnalysis.get("criticalOps");

            if (criticalOps != null) {
                for (GAScheduleResult op : criticalOps) {
                    bottleneckOpIds.add(op.getOperationId());
                }
            }
        } catch (Exception e) {
            log("MultiMachineChange: 获取瓶颈信息失败，使用正常模式");
        }

        // 收集有多个机器选项的工序，优先瓶颈工序
        List<Integer> eligibleOps = new ArrayList<>();
        List<Integer> bottleneckEligibleOps = new ArrayList<>();

        for (int i = 0; i < globalOps.size(); i++) {
            Entry entry = globalOps.get(i).getOp();
            if (entry != null && entry.getMachineOptions() != null && entry.getMachineOptions().size() > 1) {
                eligibleOps.add(i);
                if (bottleneckOpIds.contains(entry.getId())) {
                    bottleneckEligibleOps.add(i);
                }
            }
        }

        if (eligibleOps.size() < 2) {
            log("MultiMachineChange: 没有足够的多机器选项工序");
            return null;
        }

        // 选择要改变的工序数量：2-5个
        int changeCount = Math.min(rnd.nextInt(4) + 2, eligibleOps.size());
        Set<Integer> selectedIndices = new HashSet<>();

        log(String.format("MultiMachineChange: 准备改变 %d 个工序的机器选择, 瓶颈工序数=%d/%d",
                changeCount, bottleneckEligibleOps.size(), eligibleOps.size()));

        // 优先选择瓶颈工序，70%概率从瓶颈中选择
        while (selectedIndices.size() < changeCount) {
            int idx;
            if (!bottleneckEligibleOps.isEmpty() && rnd.nextDouble() < 0.7) {
                idx = bottleneckEligibleOps.get(rnd.nextInt(bottleneckEligibleOps.size()));
            } else {
                idx = eligibleOps.get(rnd.nextInt(eligibleOps.size()));
            }

            if (!selectedIndices.contains(idx)) {
                selectedIndices.add(idx);
            }
        }

        // 为每个选中的工序随机选择新机器
        for (int idx : selectedIndices) {
            Entry entry = globalOps.get(idx).getOp();
            List<MachineOption> options = entry.getMachineOptions();
            int currentSelection = machineSelection.get(idx);

            // 随机选择一个不同于当前的机器
            int newSelection;
            if (options.size() == 2) {
                newSelection = (currentSelection == 1) ? 2 : 1;
            } else {
                do {
                    newSelection = rnd.nextInt(options.size()) + 1;
                } while (newSelection == currentSelection);
            }

            machineSelection.set(idx, newSelection);

            String bottleneckTag = bottleneckOpIds.contains(entry.getId()) ? "[瓶颈]" : "";
            log(String.format("  工序%d%s (工单%d): 机器选择 %d -> %d",
                    idx, bottleneckTag, entry.getGroupId(), currentSelection, newSelection));
        }

        return neighbor;
    }

    /**
     * HybridShake - 混合抖动：同时进行位置和机器的综合调整
     * 最激进的变邻域方法，用于彻底跳出局部最优
     */
    private Chromosome hybridShakeWrapper(Chromosome chromosome) {
        Chromosome neighbor = copyChromosome(chromosome);

        log("HybridShake: 开始混合抖动调整");

        // 50%概率进行块移动
        if (rnd.nextDouble() < 0.5) {
            Map<Integer, Object> obj = buildPositionToEntryIndex(chromosome);
            Map<Integer, Entry> positionToEntryIndex = (Map<Integer, Entry>) obj.get(1);
            List<List<Integer>> positionByPriority = (List<List<Integer>>) obj.get(2);

            Chromosome blockResult = blockMove(neighbor, positionToEntryIndex, positionByPriority);
            if (blockResult != null) {
                neighbor = blockResult;
            }
        }

        // 50%概率进行多机器改变
        if (rnd.nextDouble() < 0.5) {
            Chromosome machineResult = multiMachineChange(neighbor);
            if (machineResult != null) {
                neighbor = machineResult;
            }
        }

        // 30%概率进行多工序交换
        if (rnd.nextDouble() < 0.3) {
            Map<Integer, Object> obj = buildPositionToEntryIndex(chromosome);
            Map<Integer, Entry> positionToEntryIndex = (Map<Integer, Entry>) obj.get(1);
            List<List<Integer>> positionByPriority = (List<List<Integer>>) obj.get(2);

            Chromosome swapResult = multiOperationSwap(neighbor, positionToEntryIndex, positionByPriority);
            if (swapResult != null) {
                neighbor = swapResult;
            }
        }

        log("HybridShake: 混合抖动完成");
        return neighbor;
    }

    /**
     * CP-SAT 局部重优化邻域
     * 在当前调度的基础上，释放一部分工序，用 CP-SAT 重优化机器选择
     */
    private Chromosome cpSatLocalOptimizeWrapper(Chromosome chromosome) {
        if (!cpSatEnabled || cpSatDecoder == null || cpSatMachines == null) {
            return null;
        }

        try {
            // CP-SAT 需要解码后的时间信息，先做一次解码
            cpSatDecoder.serialDecode(chromosome);

            // 只做一次快速重优化（释放约 10% 的工序）
            CpSatLnsNeighborhood lns = new CpSatLnsNeighborhood(
                    cachedAllOperations, cpSatMachines,orders,materials,_entryRel, fitnessCalculator);
            int releaseCount = Math.max(30, (int)(cachedAllOperations.size() * 0.10));
            int timeLimitSec = Math.min(8, 12000 / Math.max(100, cachedAllOperations.size()));

            Chromosome neighbor = lns.optimizeNeighborhood(chromosome, releaseCount, timeLimitSec);
            if (neighbor != null) {
                log("CpSatLocalOptimize: 生成邻居成功");
            }
            return neighbor;

        } catch (Exception e) {
            log("CpSatLocalOptimize: 异常 - " + e.getMessage());
            return null;
        }
    }
    public static void log(String message) {
        log(message, true);
    }

    public static void log(String message, boolean enableLogging) {
       FileHelper.log(message, enableLogging);
    }

}