package com.aps.service.Algorithm;

import lombok.Data;

import java.text.DecimalFormat;

/**
 * 作者：佟礼
 * 时间：2025-11-26
 */
@Data
public class AdaptiveGaParams {
    // 基础参数（自适应调整的基准值）
    private static final int MIN_POPULATION_SIZE = 50;
    private static final int MAX_POPULATION_SIZE = 500;
    private static final int MIN_MAX_ITERATIONS = 50;
    private static final int MAX_MAX_ITERATIONS = 200;
    private static final float MIN_CROSSOVER_PROB = 0.6f;
    private static final float MAX_CROSSOVER_PROB = 0.9f;
    private static final float MIN_MUTATION_PROB = 0.05f;
    private static final float MAX_MUTATION_PROB = 0.2f;
    private static final int MIN_TOURNAMENT_SIZE = 3;
    private static final int MAX_TOURNAMENT_SIZE = 7;
    private static final int MIN_LOW_PRIORITY_THRESHOLD = 3;
    private static final int MAX_LOW_PRIORITY_THRESHOLD = 6;
    private static final int DELIVERY_DEADLINE_BASE = 1000; // 交付期基准值

    // 自适应调整后的参数（公开可访问）
    private int populationSize;
    private int maxIterations;
    private float crossoverProb;
    private float mutationProb;
    private int tournamentSize;
    private int lowPriorityThreshold;
    private int deliveryDeadline;

    // 自适应调整系数（可根据实际场景微调）
    private float populationSizeCoeff = 0.1f; // 种群大小对工序数的敏感系数
    private float maxIterationsCoeff = 0.05f; // 迭代次数对工序数的敏感系数
    private float crossoverProbCoeff = 0.0001f; // 交叉概率对工序数的敏感系数
    private float mutationProbCoeff = 0.00005f; // 变异概率对工序数的敏感系数
    private float tournamentSizeCoeff = 200f; // 锦标赛规模对工序数的敏感系数（分母越大越不敏感）
    private float lowPriorityThresholdCoeff = 300f; // 低优先级阈值对工序数的敏感系数（分母越大越不敏感）
    private float deliveryDeadlineCoeff = 0.5f; // 交付期对工序数的敏感系数



    /**
     * 根据总工序数初始化自适应参数（一次性调整）
     *
     * @param totalOps 总工序数
     */
    public void initAdaptiveParams(int totalOps) {
        // 1. 种群大小：50 ~ 500，随工序数线性增加
        double populationSizeTemp = MIN_POPULATION_SIZE + totalOps * populationSizeCoeff;
        populationSize = (int) clamp(populationSizeTemp, MIN_POPULATION_SIZE, MAX_POPULATION_SIZE);
        // 确保偶数（方便交叉）
        if (populationSize % 2 != 0) {
            populationSize += 1;
        }

        // 2. 最大迭代次数：50 ~ 200，随工序数线性减少
        double maxIterationsTemp = MAX_MAX_ITERATIONS - totalOps * maxIterationsCoeff;
        maxIterations = (int) clamp(maxIterationsTemp, MIN_MAX_ITERATIONS, MAX_MAX_ITERATIONS);

        // 3. 交叉概率：0.6 ~ 0.9，随工序数轻微减少
        double crossoverProbTemp = MAX_CROSSOVER_PROB - totalOps * crossoverProbCoeff;
        crossoverProb = (float) clamp(crossoverProbTemp, MIN_CROSSOVER_PROB, MAX_CROSSOVER_PROB);

        // 4. 变异概率：0.05 ~ 0.2，随工序数轻微增加
        double mutationProbTemp = MIN_MUTATION_PROB + totalOps * mutationProbCoeff;
        mutationProb = (float) clamp(mutationProbTemp, MIN_MUTATION_PROB, MAX_MUTATION_PROB);

        // 5. 锦标赛规模：3 ~ 7，随工序数阶梯式增加
        double tournamentSizeTemp = MIN_TOURNAMENT_SIZE + totalOps / tournamentSizeCoeff;
        tournamentSize = (int) clamp(tournamentSizeTemp, MIN_TOURNAMENT_SIZE, MAX_TOURNAMENT_SIZE);

        // 6. 低优先级阈值：3 ~ 6，随工序数阶梯式减少
        double lowPriorityThresholdTemp = MAX_LOW_PRIORITY_THRESHOLD - totalOps / lowPriorityThresholdCoeff;
        lowPriorityThreshold = (int) clamp(lowPriorityThresholdTemp, MIN_LOW_PRIORITY_THRESHOLD, MAX_LOW_PRIORITY_THRESHOLD);

        // 7. 交付期：基准1000 + 工序数*0.5（随工序数增加）
        deliveryDeadline = (int) (DELIVERY_DEADLINE_BASE + totalOps * deliveryDeadlineCoeff);

        // 输出自适应参数日志
        DecimalFormat df = new DecimalFormat("#.###");
        System.out.println("=== 自适应参数初始化完成（总工序数：" + totalOps + "）===");
        System.out.println("种群大小：" + populationSize);
        System.out.println("最大迭代次数：" + maxIterations);
        System.out.println("交叉概率：" + df.format(crossoverProb));
        System.out.println("变异概率：" + df.format(mutationProb));
        System.out.println("锦标赛规模：" + tournamentSize);
        System.out.println("低优先级阈值：" + lowPriorityThreshold);
        System.out.println("交付期：" + deliveryDeadline);
        System.out.println("============================================\n");
    }

    /**
     * 迭代中动态微调参数（根据种群收敛情况）
     *
     * @param currentIter 当前迭代次数
     * @param fitnessStd  当前种群适应度标准差（越小收敛越好）
     */
    public void fineTuneParams(int currentIter, float fitnessStd) {
        // 每10代微调一次，避免频繁调整
        if (currentIter % 10 != 0) {
            return;
        }

        // 适应度标准差阈值（可调整）：小于0.05视为收敛过慢，大于0.2视为收敛过快
        final float LOW_STD_THRESHOLD = 0.05f;
        final float HIGH_STD_THRESHOLD = 0.2f;
        final float ADJUST_STEP = 0.05f; // 调整步长

        DecimalFormat df = new DecimalFormat("#.###");

        // 1. 收敛过慢（适应度方差小）：增加变异概率，降低交叉概率
        if (fitnessStd < LOW_STD_THRESHOLD) {
            mutationProb = (float) clamp(mutationProb + ADJUST_STEP * 0.5f, MIN_MUTATION_PROB, MAX_MUTATION_PROB);
            crossoverProb = (float) clamp(crossoverProb - ADJUST_STEP * 0.3f, MIN_CROSSOVER_PROB, MAX_CROSSOVER_PROB);
            System.out.println("迭代" + currentIter + "：收敛过慢，微调参数→变异概率：" + df.format(mutationProb) +
                    "，交叉概率：" + df.format(crossoverProb));
        }
        // 2. 收敛过快（适应度方差大）：降低变异概率，增加交叉概率
        else if (fitnessStd > HIGH_STD_THRESHOLD) {
            mutationProb = (float) clamp(mutationProb - ADJUST_STEP * 0.5f, MIN_MUTATION_PROB, MAX_MUTATION_PROB);
            crossoverProb = (float) clamp(crossoverProb + ADJUST_STEP * 0.3f, MIN_CROSSOVER_PROB, MAX_CROSSOVER_PROB);
            System.out.println("迭代" + currentIter + "：收敛过快，微调参数→变异概率：" + df.format(mutationProb) +
                    "，交叉概率：" + df.format(crossoverProb));
        }

        // 3. 后期迭代（超过80%迭代次数）：降低变异概率，稳定最优解
        if (currentIter > maxIterations * 0.8f) {
            mutationProb = (float) clamp(mutationProb * 0.8f, MIN_MUTATION_PROB, MAX_MUTATION_PROB);
            System.out.println("迭代" + currentIter + "：后期迭代，微调参数→变异概率：" + df.format(mutationProb));
        }
    }
    /**
     *
     *
     * @param value  需要限制的值
     * @param min    最小值
     * @param max    最大值
     * @return       限制后的值
     */
    private double clamp(double value, double min, double max) {
        return Math.max(min, Math.min(max, value));
    }
}
