当前位置: 首页 > news >正文

基于布谷鸟算法实现率定系数的starter

  布谷鸟算法(Cuckoo Search, CS)是一种基于群体智能的优化算法,灵感来源于布谷鸟的繁殖行为以及宿主鸟发现外来蛋的概率。该算法由 Xin-She Yang 和 Suash Deb 在2009年提出。它结合了莱维飞行(Lévy flight)这一随机漫步模式,这种模式在自然界中被观察到是某些动物寻找食物时采用的方式,具有高效探索大范围空间的能力。之前把matlab的率定系数的转成java实现后,希望做成一个更加通用的模块,便有了此文。

1. 概述

CJH HUP Optimization Starter 是一个基于 Spring Boot 的优化算法工具包,支持从 Excel或 JSON 中读取数据,并通过多目标优化算法计算最优解。该工具包适用于水文分析、流量预测等场景。

2. 功能特性

  • 多数据源支持:支持 Excel 和 JSON 文件格式。

  • 多目标优化:基于 布谷鸟种群算法实现多目标优化。

  • 灵活配置:通过配置文件调整算法参数。

  • 高性能:优化后的算法执行速度快,适合大规模数据处理。

  • 易扩展:支持自定义数据源和优化算法。


3.代码编写

3.1 设置项目结构

3.2定义默认的配置文件

cjh:hup:data-source-type: excel #目前支持excel和json 默认为excelnum-pop: 500 #种群规模num-obj: 2 #目标函数个数:随机不确定度、系统误差num-opt: 5 #优化变量个数low-limit: -10 #系数取值范围下限up-limit: 20 #系数取值范围上限h1: 173.9 #第一层声路高程h2: 175.4 #第二层声路高程h3: 177.1 #第三层声路高程h4: 178.6 #第四层声路高程w: 0.6 #河底流速系数max-gen: 1000 #最大迭代次数q_obs_col: 5 #流量数据所在列hs_col: 6 #hs数据所在列v-cols: [8, 9, 10, 11] #流速数据列lg-hs: #水位面积关系164.95: 0164.96: 0.01164.97: 0.02164.98: 0.03

3.3编写自动配置类

@Configuration
@EnableConfigurationProperties(HupProperties.class)
public class HupAutoConfiguration {public HupAutoConfiguration() {System.out.println("HupAutoConfiguration has been instantiated.");}@Bean@ConditionalOnMissingBeanpublic HupOptimizer hupOptimizer(HupProperties properties) {System.out.println("HupOptimizer has been instantiated.");return new HupOptimizer(properties);}@Bean@ConditionalOnMissingBeanpublic HupDataSource hupDataSource(HupProperties properties) {if ("json".equalsIgnoreCase(properties.getDataSourceType())) {System.out.println("YourAutoConfigurationClass has been instantiated and use type json");return new JsonDataSource();} else {System.out.println("YourAutoConfigurationClass has been instantiated and use type excel");return new ExcelDataSource();}}@Bean@ConditionalOnMissingBeanpublic HupService hupService(HupDataSource dataSource, HupOptimizer optimizer) {System.out.println("HupService has been instantiated." );return new HupService(dataSource, optimizer);}
}

3.4 定义数据源

定义父集数据源接口

public interface HupDataSource {Map<String, Object> loadData(String filePath) throws RuntimeException;default void validateData(Map<String, Object> data) {if (!data.containsKey("Q_obs") || !data.containsKey("v")) {throw new RuntimeException("Invalid data format");}}
}

json数据源

@Component
@ConditionalOnProperty(name = "cjh.hup.data-source-type", havingValue = "json")
public class JsonDataSource implements HupDataSource {@Overridepublic Map<String, Object> loadData(String jsonData) {try {FlowData flowData = JSONUtil.toBean(jsonData, FlowData.class, true);Map<String, Object> map = new HashMap<>();// 添加Q_obsmap.put("Q_obs", flowData.getQ_obs());map.put("Q_obs_len", flowData.getQ_obs().length);// 添加v,这里直接放入了double[][]类型的值,因为Java中的Object可以持有任何类型的数据map.put("v", flowData.getV());map.put("v_len", flowData.getV().length);// 添加Hsmap.put("Hs", flowData.getHs());map.put("Hs_len", flowData.getHs().length);validateData(map);return map;} catch (Exception e) {throw new RuntimeException("JSON data loading failed", e);}}
}
@Component
@ConditionalOnProperty(name = "cjh.hup.data-source-type", havingValue = "excel")
public class ExcelDataSource implements HupDataSource {@ResourceHupProperties properties;@Overridepublic Map<String, Object> loadData(String filePath) {try (ExcelReader reader = ExcelUtil.getReader(new File(filePath))) {List<List<Object>> data = reader.read();Map<String, Object> result = new HashMap<>();double[] doubles = extractColumn(data, properties.getQ_obs_col());result.put("Q_obs", doubles);result.put("Q_obs_len", doubles.length);double[][] doubles1 = extractColumns(data, properties.getvCols());result.put("v", doubles1);result.put("v_len", doubles1.length);double[] doubles2 = extractColumn(data, properties.getHs_col());result.put("Hs", doubles2);result.put("Hs_len", doubles2);validateData(result);return result;} catch (Exception e) {throw new RuntimeException("Excel data loading failed", e);}}// 实现列提取逻辑private static double[] extractColumn(List<List<Object>> data, int col) {double[] columnData = new double[data.size() - 1]; // 减去第一行标题for (int i = 1; i < data.size(); i++) { // 从第2行开始读取数据List<Object> row = data.get(i);if (row.get(col) instanceof Number) {columnData[i - 1] = ((Number) row.get(col)).doubleValue();} else {columnData[i - 1] = Double.NaN; // 如果非数值型数据则设为NaN}}return columnData;}// 从Excel中读取指定列(indices)数据// 实现多列提取逻辑public static double[][] extractColumns(List<List<Object>> data, int[] indices) {double[][] columnData = new double[indices.length][data.size() - 1]; // 减去第一行标题for (int i = 1; i < data.size(); i++) { // 从第2行开始读取数据List<Object> row = data.get(i);for (int j = 0; j < indices.length; j++) {int colIndex = indices[j];if (row.get(colIndex) instanceof Number) {columnData[j][i - 1] = ((Number) row.get(colIndex)).doubleValue();} else {columnData[j][i - 1] = Double.NaN; // 非数值型数据设置为NaN}}}return columnData;}
}

 3.5定义优化算法

public class HupOptimizer {private final HupProperties properties;public HupOptimizer(HupProperties properties) {this.properties = properties;}public OptimizationResult optimize(Map<String, Object> inputData) {Long t1 = System.currentTimeMillis();// 实现优化算法主体逻辑InitializeData initializeData = initializePopulation(inputData);double[][] nest = initializeData.getNest();double[] b = initializeData.getB();double[][] Q_shicha = initializeData.getQ_shicha();List<Object> Q_fenceng = initializeData.getQ_fenceng();int NUM_POP = properties.getNumPop();int NUM_OPT = properties.getNumOpt();int NUM_OBJ = properties.getNumObj();int q_len = (int) inputData.get("Q_obs_len");// 创建一个新的数组,大小为NUM_POP行目标+变量个+2数列double[][] expandedArray = new double[NUM_POP][NUM_OBJ + NUM_OPT +2 ];// 将原始数组的数据复制到新数组中for (int t = 0; t < NUM_POP; t++) {for (int j = 0; j < NUM_OBJ + NUM_OPT; j++) {expandedArray[t][j] = nest[t][j];}}//初始化新添加的列,这里设置为0,你可以根据需要设置为其他值for (int i = 0; i < NUM_POP; i++) {expandedArray[i][7] = 0;expandedArray[i][8] = 0;}expandedArray = nonDominationSort(expandedArray, NUM_OBJ, NUM_OPT);// 优化求解System.out.println("计算中...");double[][] optimizedNest = optimize(expandedArray, inputData);double[] temp = new double[NUM_OPT];for (int jj = 0; jj < NUM_POP; jj++) {for (int m = 0; m < NUM_OPT; m++) {temp[m] = optimizedNest[jj][m];}FobjData fobj = fobj(temp, inputData);double[] f = fobj.getF();double bx = fobj.getB();b[jj] = bx;double[] Q_shichatemp = fobj.getQ_shicha();double[][] Q_fencengTemp = fobj.getQ_fenceng();for (int t = 0; t < NUM_OBJ; t++) {optimizedNest[jj][NUM_OPT + t] = f[0];}Q_shicha[jj] = Q_shichatemp;Q_fenceng.add(jj, Q_fencengTemp);}// 提取优化变量部分double[][] nest_Pareto = new double[nest.length][NUM_OPT];for (int i = 0; i < nest.length; i++) {System.arraycopy(nest[i], 0, nest_Pareto[i], 0, NUM_OPT);}// 提取目标函数值部分double[][] f_Pareto = new double[nest.length][NUM_OBJ];for (int i = 0; i < nest.length; i++) {System.arraycopy(nest[i], NUM_OPT, f_Pareto[i], 0, NUM_OBJ);}// 构建 Pareto 矩阵double[][] Pareto = new double[nest.length][NUM_OPT + 1 + NUM_OBJ + q_len];for (int i = 0; i < nest.length; i++) {System.arraycopy(nest_Pareto[i], 0, Pareto[i], 0, NUM_OPT);Pareto[i][NUM_OPT] = b[i];System.arraycopy(Q_shicha[i], 0, Pareto[i], NUM_OPT + 1, q_len);System.arraycopy(f_Pareto[i], 0, Pareto[i], NUM_OPT + q_len + 1, NUM_OBJ);}// 寻找随机不确定度最小行及对应的结果double minF1 = Double.MAX_VALUE;int Y = -1;for (int i = 0; i < f_Pareto.length; i++) {if (f_Pareto[i][0] < minF1) {minF1 = f_Pareto[i][0];Y = i;}}double[] k_opt = Arrays.copyOf(nest_Pareto[Y], nest_Pareto[Y].length);double b_opt = b[Y];double f1_opt = f_Pareto[Y][0];double f2_opt = f_Pareto[Y][1];// 打印结果System.out.printf("k= %.2f %.2f %.2f %.2f %.2f, b= %.2f, 随机不确定度= %.4f, 系统误差= %.4f\n",k_opt[0], k_opt[1], k_opt[2], k_opt[3], k_opt[4], b_opt, f1_opt, f2_opt);OptimizationResult result = new OptimizationResult();result.setB(b_opt);result.setK(k_opt);result.setUncertainty(f1_opt);result.setSystemError(f2_opt);Long t2 = System.currentTimeMillis();System.out.println("耗时:" + (t2 - t1) / 1000 + "s");return result;}// 优化求解private double[][] optimize(double[][] nest, Map<String, Object> simuPara) {int gen = 0;int MAX_GEN = properties.getMaxGen();int NUM_POP = properties.getNumPop();int NUM_OPT = properties.getNumOpt();int NUM_OBJ = properties.getNumObj();while (gen < MAX_GEN) {gen++;double pa = 0.5 - gen * (0.5 - 0.05) / MAX_GEN;double[][] newNest = emptyNests(nest, pa, simuPara);double[][] Tempnest = verticalConcatenate(nest, newNest);Tempnest = nonDominationSort(Tempnest, NUM_OBJ, NUM_OPT);nest = replace(Tempnest, NUM_OBJ, NUM_OPT, NUM_POP);}return nest;}//预生成所有随机数private final ThreadLocal<Random> random = ThreadLocal.withInitial(Random::new);private InitializeData initializePopulation(Map<String, Object> data) {InitializeData resultData = new InitializeData();int NUM_POP = properties.getNumPop();int NUM_OPT = properties.getNumOpt();int NUM_OBJ = properties.getNumObj();double LOW_LIMIT = properties.getLowLimit();double UP_LIMIT = properties.getUpLimit();double[][] nest = new double[NUM_POP][NUM_OPT + NUM_OBJ];double[][] Q_shicha = new double[NUM_POP][(int) data.get("Q_obs_len")];List<Object> Q_fenceng = new ArrayList<>();double[] b = new double[NUM_POP];// 并行初始化种群IntStream.range(0, NUM_POP).parallel().forEach(i -> {double[] KK = new double[NUM_OPT];Random rand = random.get();for (int j = 0; j < NUM_OPT; j++) {KK[j] = LOW_LIMIT + rand.nextDouble() * (UP_LIMIT - LOW_LIMIT);}System.arraycopy(KK, 0, nest[i], 0, KK.length);FobjData fobjData = fobj(KK, data);System.arraycopy(fobjData.getF(), 0, nest[i], NUM_OPT, NUM_OBJ);});resultData.setNest(nest);resultData.setQ_shicha(Q_shicha);resultData.setQ_fenceng(Q_fenceng);resultData.setB(b);return resultData;}private double[][] emptyNests(double[][] oldNest, double pa, Map<String, Object> simuPara) {int m = properties.getNumObj(); // 目标函数个数int nd = properties.getNumOpt(); // 优化变量的个数// 深拷贝 oldNest 到 newNestdouble[][] newNest = new double[oldNest.length][oldNest[0].length];for (int i = 0; i < oldNest.length; i++) {System.arraycopy(oldNest[i], 0, newNest[i], 0, oldNest[i].length);}double[][] nest = new double[oldNest.length][nd];// 复制 oldNest 到 newNest 并提取优化变量for (int i = 0; i < oldNest.length; i++) {System.arraycopy(oldNest[i], 0, nest[i], 0, nd);}int n = nest.length;Random rand = new Random();// 生成布尔矩阵 Kboolean[][] K = new boolean[n][nd];for (int i = 0; i < K.length; i++) {for (int j = 0; j < K[i].length; j++) {K[i][j] = rand.nextDouble() > pa;}}// 找到每行中 true 值的数量等于 nd 的行索引List<Integer> x = new ArrayList<>();for (int i = 0; i < K.length; i++) {int count = 0;for (int j = 0; j < K[i].length; j++) {if (K[i][j]) {count++;}}if (count == nd) {x.add(i);}}// 修改布尔矩阵 K 中特定行的最后一列for (int row : x) {K[row][K[row].length - 1] = false;}// 生成布尔矩阵 Lboolean[][] L = new boolean[K.length][K[0].length];for (int i = 0; i < K.length; i++) {for (int j = 0; j < K[i].length; j++) {L[i][j] = !K[i][j];}}// 计算每行中 0 的数量int[] count = new int[K.length];for (int i = 0; i < K.length; i++) {int rowCount = 0;for (int j = 0; j < K[i].length; j++) {if (L[i][j]) {rowCount++;}}count[i] = rowCount;}// 生成随机排列List<Integer> indices = new ArrayList<>();for (int i = 0; i < n; i++) {indices.add(i);}Collections.shuffle(indices);int[] rand1 = indices.stream().mapToInt(Integer::intValue).toArray();Collections.shuffle(indices);int[] rand2 = indices.stream().mapToInt(Integer::intValue).toArray();// 生成随机缩放因子double randNum = rand.nextDouble();// 计算 deltadouble[][] delta = new double[n][nd];for (int i = 0; i < n; i++) {for (int j = 0; j < nd; j++) {delta[i][j] = randNum * (nest[rand1[i]][j] - nest[rand2[i]][j]);}}// 计算 stepsize1double[][] stepsize1 = new double[n][nd];for (int i = 0; i < n; i++) {for (int j = 0; j < nd; j++) {stepsize1[i][j] = K[i][j] ? delta[i][j] : 0.0;}}// 计算 delta2double[] delta2 = new double[n];for (int i = 0; i < n; i++) {double sum = 0.0;for (int j = 0; j < nd; j++) {sum += stepsize1[i][j];}delta2[i] = sum / count[i];}// 计算 stepsize2double[][] stepsize2 = new double[nest.length][nest[0].length];for (int i = 0; i < nest.length; i++) {for (int j = 0; j < nest[0].length; j++) {stepsize2[i][j] = delta2[i] * (L[i][j] ? 1.0 : 0.0);}}// 计算最终步长 stepsizedouble[][] stepsize = new double[nest.length][nest[0].length];for (int i = 0; i < nest.length; i++) {for (int j = 0; j < nest[0].length; j++) {stepsize[i][j] = stepsize1[i][j] - stepsize2[i][j];}}// 更新巢穴位置+stepsize new_nestdouble[][] new_nest = new double[nest.length][nest[0].length];for (int i = 0; i < nest.length; i++) {for (int j = 0; j < nest[0].length; j++) {new_nest[i][j] = nest[i][j] + stepsize[i][j];}}//fobj计算2个函数值for (int i = 0; i < n; i++) {for (int j = 0; j < nd; j++) {newNest[i][j] = nest[i][j] + stepsize1[i][j];}// 评估 new nest 并存储结果double[] f = fobj(newNest[i], simuPara).getF();System.arraycopy(f, 0, newNest[i], nd, m);}return newNest;}private FobjData fobj(double[] KK, Map<String, Object> data) {FobjData fobjData = new FobjData();// 初始化目标函数值double[] f = new double[2];// 参数传递double[][] lgHS = DataUtil.mapToArray(properties.getLgHs());double[] Q_obs = (double[]) data.get("Q_obs");double[][] v = (double[][]) data.get("v");double[] Hs = (double[]) data.get("Hs");double H1 = properties.getH1();double H2 = properties.getH2();double H3 = properties.getH3();double H4 = properties.getH4();double w = properties.getW();int n = (int) data.get("Q_obs_len");double lowlimit = properties.getLowLimit();double uplimit = properties.getUpLimit();double[] k = KK; // matlab中kk是一个一行NUM_OPT列的数组 经过转秩变成了一个 NUM_OPT列1行的数组// 推算流量double[] v0 = new double[v[0].length];for (int i = 0; i < v[0].length; i++) {v0[i] = w * v[0][i]; // 计算v0}double[] rows0 = exColsWithNum(lgHS, 0);double[] rows1 = exColsWithNum(lgHS, 1);double[] S0 = chazhi(rows0, rows1, new double[]{H1});double[] S1 = subtract(chazhi(rows0, rows1, new double[]{H2}), S0);double[] S2 = subtract(chazhi(rows0, rows1, new double[]{H3}), chazhi(rows0, rows1, new double[]{H2}));double[] S3 = subtract(chazhi(rows0, rows1, new double[]{H4}), chazhi(rows0, rows1, new double[]{H3}));double[] S4 = subtract(chazhi(rows0, rows1, Hs), chazhi(rows0, rows1, new double[]{H4}));double[] Q0 = new double[v0.length];double[] Q1 = new double[v[0].length];double[] Q2 = new double[v[1].length];double[] Q3 = new double[v[2].length];double[] Q4 = new double[v[3].length];for (int i = 0; i < v0.length; i++) {Q0[i] = (v0[i] + v[0][i]) * 0.5 * S0[0];}for (int i = 0; i < Q1.length; i++) {Q1[i] = (v[0][i] + v[1][i]) * 0.5 * S1[0];}for (int i = 0; i < Q2.length; i++) {Q2[i] = (v[1][i] + v[2][i]) * 0.5 * S2[0];}for (int i = 0; i < Q3.length; i++) {Q3[i] = (v[2][i] + v[3][i]) * 0.5 * S3[0];}for (int i = 0; i < Q4.length; i++) {Q4[i] = v[3][i] * S4[i];}// 合并流量double[][] Q_fenceng = {Q0, Q1, Q2, Q3, Q4};double[] Q_shicha = new double[Q_fenceng[0].length]; // 按列求和,初始化为零的数组double[][] tempx = new double[Q_fenceng.length][Q_fenceng[0].length]; // 按列求和,初始化为零的数组// 构建点乘矩阵 合并为单层循环int rows = Q_fenceng.length;int cols = Q_fenceng[0].length;for (int i = 0; i < rows * cols; i++) {int j = i / cols;int kIndex = i % cols;tempx[j][kIndex] = k[j] * Q_fenceng[j][kIndex];}//按列求和for (int i = 0; i < Q_shicha.length; i++) {Q_shicha[i] = Arrays.stream(exColsWithNum(tempx, i)).sum();}// 计算误差均值,修正推算流量//计算 Q_obs 和 Q_shicha 之间的差的平均值double sumDifference = 0.0;for (int i = 0; i < Q_obs.length; i++) {sumDifference += Q_obs[i] - Q_shicha[i];}double b = sumDifference / Q_obs.length;//更新 Q_shichafor (int i = 0; i < Q_shicha.length; i++) {Q_shicha[i] += b;}// 增加惩罚函数double penalty = 0.0;int s1 = 0;int s2 = 0;for (double ki : k) {if (ki < lowlimit) {s1 += 1;}if (ki > uplimit) {s2 += 1;}}if (s1 > 0 || s2 > 0) {penalty = 100;}// 计算两个目标函数f[0] = 2 * Math.sqrt(sumSquaredError(Q_obs, Q_shicha) / (n - 2)) + penalty; //随机不确定度f[1] = Math.abs(sumRelativeError(Q_obs, Q_shicha) / n) + penalty; // 系统误差fobjData.setF(f);fobjData.setB(b);fobjData.setQ_fenceng(Q_fenceng);fobjData.setQ_shicha(Q_shicha);return fobjData;}// 辅助方法:计算平方误差和private static double sumSquaredError(double[] Q_obs, double[] Q_shicha) {double sum = 0.0;for (int i = 0; i < Q_obs.length; i++) {sum += Math.pow((Q_obs[i] - Q_shicha[i]) / Q_shicha[i], 2);}return sum;}// 辅助方法:计算相对误差之和private static double sumRelativeError(double[] Q_obs, double[] Q_shicha) {double sum = 0.0;for (int i = 0; i < Q_obs.length; i++) {sum += (Q_obs[i] - Q_shicha[i]) / Q_shicha[i];}return sum;}public static double[] exColsWithNum(double[][] matrix, int columnIndex) {// 创建一个一维数组来存储列向量double[] columnVector = new double[matrix.length];// 遍历二维数组的行,提取指定列的元素for (int i = 0; i < matrix.length; i++) {columnVector[i] = matrix[i][columnIndex];}return columnVector;}/*** 按对应位置相减两个 double[] 数组,并返回结果数组。* 如果其中一个数组只有一个元素,则将该元素与另一个数组的每个元素进行相减。** @param a 第一个 double[] 数组* @param b 第二个 double[] 数组* @return 按对应位置相减后的结果数组*/public static double[] subtract(double[] a, double[] b) {int lengthA = a.length;int lengthB = b.length;double[] result;if (lengthA == 1 && lengthB > 1) {// a 只有一个元素,b 有多个元素result = new double[lengthB];for (int i = 0; i < lengthB; i++) {result[i] = a[0] - b[i];}} else if (lengthB == 1 && lengthA > 1) {// b 只有一个元素,a 有多个元素result = new double[lengthA];for (int i = 0; i < lengthA; i++) {result[i] = a[i] - b[0];}} else {// 两个数组都有多个元素,或者都只有一个元素int minLength = Math.min(lengthA, lengthB);result = new double[minLength];for (int i = 0; i < minLength; i++) {result[i] = a[i] - b[i];}}return result;}// chazhi 方法,根据 x 和 y 进行线性插值 二分插值优化private static double[] chazhi(double[] x, double[] y, double[] x0) {double[] z = new double[x0.length];for (int jj = 0; jj < x0.length; jj++) {double xc = x0[jj];if (xc <= x[0]) {z[jj] = y[0];continue;}if (xc >= x[x.length - 1]) {z[jj] = y[y.length - 1];continue;}// 使用二分查找替代线性搜索int idx = Arrays.binarySearch(x, xc);if (idx >= 0) {z[jj] = y[idx];} else {int insertionPoint = -idx - 1;int ii = insertionPoint - 1;double weight = (xc - x[ii]) / (x[ii + 1] - x[ii]);z[jj] = y[ii] * (1 - weight) + y[ii + 1] * weight;}}return z;}// 主函数:非支配排序和拥挤距离计算public static double[][] nonDominationSort(double[][] x, int M, int V) {int N = x.length;// 存储不同层级的非支配解集ArrayList<ArrayList<Integer>> F = new ArrayList<>();F.add(new  ArrayList<>());// 创建个体数组Individual[] individuals = new Individual[N];// 初始化个体信息for (int i = 0; i < N; i++) {individuals[i] = new Individual();for (int j = 0; j < N; j++) {// 比较个体 i 和个体 j 的支配关系int domLess = 0, domEqual = 0, domMore = 0;for (int k = 0; k < M; k++) {if (x[i][V + k] < x[j][V + k]) {domLess++;} else if (x[i][V + k] == x[j][V + k]) {domEqual++;} else {domMore++;}}if (domLess == 0 && domEqual!= M) {individuals[i].n++;}if (domMore == 0 && domEqual!= M) {individuals[i].p.add(j);}}if (individuals[i].n == 0) {x[i][M + V] = 0;F.get(0).add(i);}}// 分层处理非支配解集int front = 0;while (!F.get(front).isEmpty())  {ArrayList<Integer> Q = new ArrayList<>();for (int i : F.get(front))  {for (int j : individuals[i].p) {if (--individuals[j].n == 0) {x[j][M + V] = front + 1;Q.add(j);}}}front++;F.add(Q);}// 根据层级排序double[][] sortedBasedOnFront = Arrays.copyOf(x,  N);Arrays.sort(sortedBasedOnFront,  Comparator.comparingDouble(o  -> o[M + V]));// 结果矩阵,包含层级和拥挤距离ArrayList<double[]> z = new ArrayList<>();int currentIndex = 0;// 遍历所有层级(除了最后一个空层级)for (int f = 0; f < F.size()  - 1; f++) {int frontSize = F.get(f).size();double[][] y = new double[frontSize][M + V + 1 + M];// 将当前层级的个体复制到 y 矩阵for (int i = 0; i < frontSize; i++) {System.arraycopy(sortedBasedOnFront[currentIndex  + i], 0, y[i], 0, sortedBasedOnFront[0].length);}currentIndex += frontSize;// 计算每个目标的拥挤距离for (int i = 0; i < M; i++) {final int columnToSort = V + i;// 根据第 i 个目标排序Integer[] indexOfObjectives = new Integer[frontSize];for (int j = 0; j < frontSize; j++) {indexOfObjectives[j] = j;}Arrays.sort(indexOfObjectives,  Comparator.comparingDouble(a  -> y[a][columnToSort]));double fMax = y[indexOfObjectives[frontSize - 1]][columnToSort];double fMin = y[indexOfObjectives[0]][columnToSort];// 设置边界个体的拥挤距离为无穷大y[indexOfObjectives[frontSize - 1]][M + V + 1 + i] = Double.POSITIVE_INFINITY;y[indexOfObjectives[0]][M + V + 1 + i] = Double.POSITIVE_INFINITY;// 计算中间个体的拥挤距离for (int j = 1; j < frontSize - 1; j++) {double nextObj = y[indexOfObjectives[j + 1]][columnToSort];double prevObj = y[indexOfObjectives[j - 1]][columnToSort];if (fMax - fMin == 0) {y[indexOfObjectives[j]][M + V + 1 + i] = Double.POSITIVE_INFINITY;} else {y[indexOfObjectives[j]][M + V + 1 + i] = (nextObj - prevObj) / (fMax - fMin);}}}// 计算总拥挤距离double[] distance = new double[frontSize];for (int i = 0; i < M; i++) {for (int j = 0; j < frontSize; j++) {distance[j] += y[j][M + V + 1 + i];}}// 将总拥挤距离存入 y 矩阵for (int j = 0; j < frontSize; j++) {y[j][M + V + 1] = distance[j];}// 截取 y 矩阵的前 M + V + 2 列double[][] yTruncated = new double[frontSize][M + V + 2];for (int i = 0; i < frontSize; i++) {System.arraycopy(y[i],  0, yTruncated[i], 0, M + V + 2);}// 将 yTruncated 复制到 z 矩阵appendToZ(z, yTruncated, currentIndex - frontSize, currentIndex);}return convertTo2DArray(z);}// 将 ArrayList 转换为二维数组public static double[][] convertTo2DArray(ArrayList<double[]> list) {double[][] array = new double[list.size()][];for (int i = 0; i < list.size();  i++) {array[i] = list.get(i);}return array;}// 将 y 矩阵的内容复制到 z 矩阵的指定位置public static void appendToZ(ArrayList<double[]> z, double[][] y, int previousIndex, int currentIndex) {while (z.size()  < currentIndex) {z.add(new  double[y[0].length]);}for (int i = 0; i < y.length;  i++) {System.arraycopy(y[i],  0, z.get(previousIndex  + i), 0, y[i].length);}}// 个体类,存储个体的被支配次数和支配的个体索引列表private static class Individual {int n = 0;ArrayList<Integer> p = new ArrayList<>();}private static double[][] replace(double[][] nest, int numObj, int numOpt, int pop) {int N = nest.length;double[][] sortedChromosome = Arrays.copyOf(nest, N); // 复制原始数据Arrays.sort(sortedChromosome, Comparator.comparingDouble(o -> o[numObj + numOpt])); // 根据层级排序// 找到当前种群中等级最大的个体double maxRank = sortedChromosome[N - 1][numObj + numOpt];// 根据排名和拥挤距离选择个体,直到整个种群规模达到规定值double[][] f = new double[pop][numObj + numOpt + 2];int previousIndex = 0;for (int i = 1; i <= maxRank; i++) {int currentIndex = 0;final int tempI = i;double[] column = exColsWithNum(sortedChromosome, numObj + numOpt);// 找到等于 tempI 的最大索引currentIndex = IntStream.range(0, column.length).filter(j -> column[j] == tempI).max().orElse(-1) - 1;if (currentIndex > pop) { // 如果当前索引大于保留种群规模限制int remaining = pop - previousIndex;double[][] tempPop = Arrays.copyOfRange(sortedChromosome, previousIndex, currentIndex);Integer[] tempSortIndex = new Integer[tempPop.length];for (int j = 0; j < tempPop.length; j++) {tempSortIndex[j] = j;}Arrays.sort(tempSortIndex, (i1, i2) -> Double.compare(tempPop[i2][numObj + numOpt + 1], tempPop[i1][numObj + numOpt + 1])); // 按拥挤距离降序排列for (int j = 0; j < remaining; j++) {f[previousIndex + j] = tempPop[tempSortIndex[j]];}return f; // 将保留的种群作为选择结果输出} else if (currentIndex < pop) { // 如果当前位置小于最大规模限制for (int j = previousIndex; j < currentIndex; j++) {f[j] = sortedChromosome[j];}} else {for (int j = previousIndex; j < currentIndex; j++) {f[j] = sortedChromosome[j];}return f; // 如果当前位置等于最大规模,直接返回}previousIndex = currentIndex;}return f; // 返回最终的种群}// 垂直拼接矩阵public static double[][] verticalConcatenate(double[][] matrix1, double[][] matrix2) {//直接复制二维数组double[][] result = Arrays.copyOf(matrix1, matrix1.length + matrix2.length);System.arraycopy(matrix2, 0, result, matrix1.length, matrix2.length);return result;}
}

 3.6定义服务类

public class HupService {private final HupDataSource dataSource;private final HupOptimizer optimizer;public HupService(HupDataSource dataSource, HupOptimizer optimizer) {this.dataSource = dataSource;this.optimizer = optimizer;}public OptimizationResult performOptimization(String filePath) {Map<String, Object> data = dataSource.loadData(filePath);return optimizer.optimize(data);}
}

4. 快速开始

4.1 添加依赖

pom.xml 中添加以下依赖:

<dependency><groupId>com.cjh</groupId><artifactId>cjh-hup-starter</artifactId><version>1.0.0</version>
</dependency>

4.2 配置文件

application.yml 中配置算法参数默认参数如下:

cjh:hup:data-source-type: excel #目前支持excel和json 默认为excelnum-pop: 500 #种群规模num-obj: 2 #目标函数个数:随机不确定度、系统误差num-opt: 5 #优化变量个数low-limit: -10 #系数取值范围下限up-limit: 20 #系数取值范围上限h1: 173.9 #第一层声路高程h2: 175.4 #第二层声路高程h3: 177.1 #第三层声路高程h4: 178.6 #第四层声路高程w: 0.6 #河底流速系数max-gen: 1000 #最大迭代次数q_obs_col: 5 #流量数据所在列hs_col: 6 #hs数据所在列v-cols: [8, 9, 10, 11] #流速数据列lg-hs: #水位面积关系164.95: 0164.96: 0.01164.97: 0.02164.98: 0.03

4.3 数据格式

Excel 文件
  • 文件名:1000-2000.xlsx

  • 数据格式:

    • 第5列:实测流量 Q_obs

    • 第8-11列:四层流速 v

    • 第6列:水位 Hs

JSON 数据
  • 数据格式:

{"Q_obs":[1430.0, 1010.0, 1450.0, 1200.0, 1470.0, 1990.0, 1860.0, 1550.0, 1600.0, 1520.0, 1780.0, 1650.0, 1440.0, 1530.0, 1340.0, 1580.0],"v": [[0.4825, 0.398, 0.628, 0.422, 0.664, 0.6522, 0.606, 0.5292, 0.534, 0.5111, 0.586, 0.56, 0.485, 0.5106, 0.46, 0.5373],[0.5, 0.374, 0.54, 0.46, 0.538, 0.6722, 0.664, 0.55, 0.55, 0.5363, 0.6, 0.5833, 0.5033, 0.52, 0.478, 0.5545],[0.515, 0.374, 0.55, 0.48, 0.562, 0.72, 0.67, 0.5633, 0.57, 0.5474, 0.614, 0.6017, 0.53, 0.5589, 0.482, 0.56],[0.525, 0.388, 0.54, 0.5, 0.574, 0.7611, 0.69, 0.56, 0.58, 0.5853, 0.524, 0.6, 0.54, 0.5667, 0.508, 0.5691]],"Hs":[179.59, 179.18, 179.18, 178.92, 179.58, 179.72, 179.59, 179.42, 179.65, 179.4, 179.68, 179.49, 179.43, 179.56, 179.18, 179.48]
}
水位面积关系线使用map配置
  • 数据配置为:

cjh:hup:lg-hs: #水位面积关系164.95: 0164.96: 0.01164.97: 0.02164.98: 0.03164.99: 0.04165: 0.07165.01: 0.09

5. 核心 API

5.1 HupService 服务类

方法说明
  • performOptimization(String dataPath)

    • 功能:执行优化算法。

    • 参数:

      • dataPath:数据文件路径或者是数据(支持 Excel、JSON)。

    • 返回值:OptimizationResult,包含优化结果。

示例代码
@RestController
@RequestMapping("/optimization")
public class OptimizationController {
​@Autowiredprivate HupService hupService;
​@PostMappingpublic ResponseEntity<OptimizationResult> optimize(@RequestParam String dataPath) {try {OptimizationResult result = hupService.performOptimization(dataPath);return ResponseEntity.ok(result);} catch (DataProcessingException e) {return ResponseEntity.badRequest().build();}}
}

5.2 OptimizationResult 结果类

字段说明
  • k:优化变量系数(double[])。

  • b:偏差值(double)。

  • uncertainty:随机不确定度(double)。

  • systemError:系统误差(double)。

示例输出
{"k": [1.23, 2.34, 3.45, 4.56, 5.67],"b": 0.12,"uncertainty": 0.05,"systemError": 0.02
}

6. 扩展功能

6.1 自定义数据源

  1. 实现 DataSource 接口:

@Component
public class CustomDataSource implements DataSource {@Overridepublic Map<String, Object> loadData(String filePath) {// 自定义数据加载逻辑}
}
  1. 在配置文件中指定数据源类型:

cjh:hup:data-source-type: custom

6.2 自定义优化算法

  1. 继承 HupOptimizer 类:

@Component
public class CustomOptimizer extends HupOptimizer {@Overridepublic OptimizationResult optimize(Map<String, Object> inputData) {// 自定义优化逻辑}
}
  1. 在配置文件中指定优化器:

cjh:hup:optimizer: customOptimizer

7. 性能优化建议

  • 数据预处理:确保输入数据格式正确,避免无效数据。

  • 并行计算:启用多线程处理大规模数据。

  • JVM 调优:调整堆内存和垃圾回收器参数。


8. 常见问题

8.1 数据文件加载失败

  • 原因:文件路径错误或格式不正确。

  • 解决方案:检查文件路径和格式是否符合要求。

8.2 优化结果不理想

  • 原因:算法参数配置不当。

  • 解决方案:调整 num-popmax-gen 等参数。

9.代码测试与下载

9.1代码测试

 本地测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class CjhHupSpringBootStarterApplicationTests {@Autowiredprivate HupService hupService;@Testpublic void testExcelOptimization() {OptimizationResult optimizationResult = hupService.performOptimization("D:\\waterConservancy\\CJH_HUP_JAVA -dev\\src\\test\\resources\\RLine\\excel\\1000-2000.xls");System.out.println(optimizationResult.toString());}@Testpublic void testJsonOptimization() {OptimizationResult optimizationResult = hupService.performOptimization("{\"Q_obs\":[1430.0,1010.0,1450.0,1200.0,1470.0,1990.0,1860.0,1550.0,1600.0,1520.0,1780.0,1650.0,1440.0,1530.0,1340.0,1580.0],\"v\":[[0.4825,0.398,0.628,0.422,0.664,0.6522,0.606,0.5292,0.534,0.5111,0.586,0.56,0.485,0.5106,0.46,0.5373],[0.5,0.374,0.54,0.46,0.538,0.6722,0.664,0.55,0.55,0.5363,0.6,0.5833,0.5033,0.52,0.478,0.5545],[0.515,0.374,0.55,0.48,0.562,0.72,0.67,0.5633,0.57,0.5474,0.614,0.6017,0.53,0.5589,0.482,0.56],[0.525,0.388,0.54,0.5,0.574,0.7611,0.69,0.56,0.58,0.5853,0.524,0.6,0.54,0.5667,0.508,0.5691]],\"Hs\":[179.59,179.18,179.18,178.92,179.58,179.72,179.59,179.42,179.65,179.4,179.68,179.49,179.43,179.56,179.18,179.48]}");System.out.println(optimizationResult.toString());}
}

引用测试时

在项目中引入starter如下:

编写测试control如下:

@Controller
public class BasicController {@Resourceprivate  HupService hupService;@RequestMapping("/hello")@ResponseBodypublic String hello() {OptimizationResult result = hupService.performOptimization("D:\\waterConservancy\\CJH_HUP_JAVA -dev\\src\\test\\resources\\RLine\\excel\\1000-2000.xls");System.out.println(result.toString());return result.toString();}
}

结果如下:

9.2代码下载

https://download.csdn.net/download/u012440725/90355887

相关文章:

基于布谷鸟算法实现率定系数的starter

布谷鸟算法&#xff08;Cuckoo Search, CS&#xff09;是一种基于群体智能的优化算法&#xff0c;灵感来源于布谷鸟的繁殖行为以及宿主鸟发现外来蛋的概率。该算法由 Xin-She Yang 和 Suash Deb 在2009年提出。它结合了莱维飞行&#xff08;Lvy flight&#xff09;这一随机漫步…...

Java之自定义注解

介绍&#xff1a;在Java中&#xff0c;自定义注解是通过 interface 关键字定义的。注解是一种元数据&#xff0c;可以附加到类、方法、字段等代码元素上&#xff0c;用于提供额外的信息或配置。 1. 自定义注解的基本语法 使用 interface 关键字定义注解&#xff0c;注解中可以…...

SpringCloud面试题----Nacos和Eureka的区别

功能特性 服务发现 Nacos&#xff1a;支持基于 DNS 和 RPC 的服务发现&#xff0c;提供了更为灵活的服务发现机制&#xff0c;能满足不同场景下的服务发现需求。Eureka&#xff1a;主要基于 HTTP 的 RESTful 接口进行服务发现&#xff0c;客户端通过向 Eureka Server 发送 HT…...

prometheus配置大盘与告警

1、prometheus配置大盘 kube-prometheus-stack 定义 dashboard https://stackoverflow.com/questions/77271449/persist-grafana-dashboard-on-kube-prometheus-and-expose-itAlso to persist dashboards to outlive pod deletion follow the below steps: Create your cust…...

记录 | WPF创建和基本的页面布局

目录 前言一、创建新项目注意注意点1注意点2 解决方案名称和项目名称 二、布局2.1 Grid2.1.1 RowDefinitions 行分割2.1.2 Row & Column 行列定位区分 2.1.3 ColumnDefinitions 列分割 2.2 StackPanel2.2.1 Orientation 修改方向 三、模板水平布局【Grid中套StackPanel】中…...

git代理设置

在 Git 中&#xff0c;可以通过以下命令查看当前设置的代理配置&#xff1a; 查看 HTTP 代理 git config --get http.proxy查看 HTTPS 代理 git config --get https.proxy查看全局代理设置 如果你设置了全局代理&#xff0c;可以通过以下命令查看&#xff1a; git config …...

使用 Axios ——个人信息修改与提示框实现

目录 详细介绍&#xff1a;个人信息设置与修改页面实现 1. HTML 结构 2. CSS 样式 3. JavaScript 核心逻辑 a. 信息渲染与表单提交 b. 头像上传与预览 4. 功能详解 5. 总结 提示&#xff1a; 这段代码展示了如何创建一个简单的个人信息设置页面&#xff0c;包含用户个…...

(done) openMP学习 (Day11: 可怕的东西:内存模型,Atomics,Flush(Pairwise同步))

url: https://dazuozcy.github.io/posts/introdution-to-openmp-intel/#19-%E6%8A%80%E8%83%BD%E8%AE%AD%E7%BB%83%E9%93%BE%E8%A1%A8%E5%92%8Copenmp 这一节介绍了一些概念&#xff0c;包括 OpenMP 内存模型&#xff0c;串行一致性的概念&#xff0c;以及 Flush 操作&#xff…...

docker数据持久化的意义

Docker 数据持久化是指在 Docker 容器中保存的数据不会因为容器的停止、删除或重启而丢失。Docker 容器本身是临时性的&#xff0c;默认情况下&#xff0c;容器内的文件系统是临时的&#xff0c;容器停止或删除后&#xff0c;其中的数据也会随之丢失。为了确保重要数据&#xf…...

【漫话机器学习系列】084.偏差和方差的权衡(Bias-Variance Tradeoff)

偏差和方差的权衡&#xff08;Bias-Variance Tradeoff&#xff09; 1. 引言 在机器学习模型的训练过程中&#xff0c;我们常常面临一个重要的挑战&#xff1a;如何平衡 偏差&#xff08;Bias&#xff09; 和 方差&#xff08;Variance&#xff09;&#xff0c;以提升模型的泛…...

android的Compose 简介

Jetpack Compose 简介 Jetpack Compose 是 Android 官方推出的声明式 UI 工具包&#xff0c;用于替代传统 XML 布局&#xff0c;简化界面开发流程。它基于 Kotlin 语言&#xff0c;通过函数式编程实现高效、灵活的 UI 构建&#xff0c;支持实时预览和更直观的状态管理。 优势…...

git学习

报错504&#xff1a;代理有问题 查看代理&#xff1a; 法1 export | grep proxy 法2 env | grep xxx设置代理HTTPS_PROXY为空&#xff1a; export HTTPS_PROXY重进入git bash&#xff0c;HTTPS_PROXYxxx&#xff0c;又出现了 有效的办法 无效的办法&#xff1a; #取消htt…...

Spring Boot 对接深度求索接口实现知识问答功能

Spring Boot 对接深度求索接口实现知识问答功能 一、概述 本文将详细介绍如何使用 Spring Boot 对接深度求索&#xff08;DeepSeek&#xff09;接口&#xff0c;实现知识问答功能。深度求索是一个强大的自然语言处理平台&#xff0c;提供多种 API 接口&#xff0c;包括知识问…...

探索Scikit-learn:Python中的机器学习宝库

探索Scikit-learn&#xff1a;Python中的机器学习宝库 引言 在数据科学和机器学习的世界中&#xff0c;Python无疑是最受欢迎的编程语言之一。而在Python的众多机器学习库中&#xff0c;Scikit-learn无疑是最闪耀的明星之一。Scikit-learn是一个开源的Python库&#xff0c;它…...

活动预告 | Power Hour: Copilot 引领商业应用的未来

课程介绍 智能化时代&#xff0c;商业应用如何实现突破&#xff1f;微软全球副总裁 Charles Lamanna 将为您深度解析&#xff0c;剖析其中关键因素。 在本次线上研讨会中&#xff0c;Charles Lamanna 将分享他在增强商业运营方面的独到见解与实战策略&#xff0c;深度解读商业…...

MIT6.824 Lecture 2-RPC and Threads Lecture 3-GFS

Lecture 2-RPC and Threads Go语言在多线程、同步&#xff0c;还有很好用的RPC包 《Effective Go》 线程是实现并发的重要工具 在分布式系统里关注多线程的原因&#xff1a; I/O concurrencyParallelismConvenience Thread challenges 用锁解决race问题 Coordination channel…...

MariaDB *MaxScale*实现mysql8读写分离

1.MaxScale 是干什么的&#xff1f; MaxScale是maridb开发的一个mysql数据中间件&#xff0c;其配置简单&#xff0c;能够实现读写分离&#xff0c;并且可以根据主从状态实现写库的自动切换&#xff0c;对多个从服务器能实现负载均衡。 2.MaxScale 实验环境 中间件192.168.12…...

Linux之Http协议分析以及cookie和session

Linux之Http协议分析以及cookie和session 一.分析请求行与响应行1.1请求行1.1.1资源的URL路径1.1.2常见的方法1.2响应行 二.cookie和session2.1cookie2.2session 一.分析请求行与响应行 在我们简单了解了请求和响应的格式以及模拟实现了请求和响应后我们已经可以通过网页来访问…...

Python Pandas(5):Pandas Excel 文件操作

Pandas 提供了丰富的 Excel 文件操作功能&#xff0c;帮助我们方便地读取和写入 .xls 和 .xlsx 文件&#xff0c;支持多表单、索引、列选择等复杂操作&#xff0c;是数据分析中必备的工具。 操作方法说明读取 Excel 文件pd.read_excel()读取 Excel 文件&#xff0c;返回 DataF…...

iOS主要知识点梳理回顾-3-运行时

运行时&#xff08;runtime&#xff09; 运行时是OC的重要特性&#xff0c;也是OC动态性的根本支撑。动态&#xff0c;如果利用好了&#xff0c;扩展性就很强。当然了&#xff0c;OC的动态性只能算是一个一般水平。与swift、java这种强类型校验的语言相比&#xff0c;OC动态性很…...

[渗透测试]热门搜索引擎推荐— — shodan篇

[渗透测试]热门搜索引擎推荐— — shodan篇 免责声明&#xff1a;本文仅用于分享渗透测试工具&#xff0c;大家使用时&#xff0c;一定需要遵守相关法律法规。 除了shodan&#xff0c;还有很多其他热门的&#xff0c;比如&#xff1a;fofa、奇安信的鹰图、钟馗之眼等&#xff0…...

java-初识List

List&#xff1a; List 是一个接口&#xff0c;属于 java.util 包&#xff0c;用于表示有序的元素集合。List 允许存储重复元素&#xff0c;并且可以通过索引访问元素。它是 Java 集合框架&#xff08;Java Collections Framework&#xff09;的一部分 特点&#xff1a; 有序…...

ElasticSearch集群因索引关闭重打开导致飘红问题排查

背景 某组件向 ElasticSearch 写入数据&#xff0c;从最近某一天开始写入速度变慢&#xff0c;数据一直有积压。推测是 ElasticSearch 集群压力导致的&#xff0c;查看 ElasticSearch 集群状态&#xff0c;发现集群确实处于 red 状态。 本文记录 ElasticSearch 集群因索引关闭…...

idea 如何使用deepseek 保姆级教程

1.安装idea插件codegpt 2.注册deepseek并生成apikey deepseek 开发平台&#xff1a; DeepSeek​​​​​​​ 3.在idea进行codegpt配置 打开idea的File->Settings->Tools->CodeGPT->Providers->Custom OpenAI Chat Completions的URL填写 https://api.deepseek…...

【大模型】硅基流动对接DeepSeek使用详解

目录 一、前言 二、硅基流动介绍 2.1 硅基流动平台介绍 2.1.1 平台是做什么的 2.2 主要特点与功能 2.2.1 适用场景 三、硅基流动快速使用 3.1 账户注册 3.2 token获取 3.2.1 获取token技巧 四、Cherry-Studio对接DeepSeek 4.1 获取 Cherry-Studio 4.2 Cherry-Stud…...

机器学习数学基础:14.矩阵的公式

1. 操作顺序可交换 对于矩阵 A A A&#xff0c;若存在两种运算 ? ? ?和 ? ? ?&#xff0c;使得 ( A ? ) ? ( A ? ) ? (A^{?})^{?}\ (A^{?})^{?} (A?)? (A?)?&#xff0c;这意味着这两种运算的顺序可以交换。由此我们得到以下三个重要等式&#xff1a; ( A …...

t113-qt

修改QT配置: # # qmake configuration for building with arm-linux-gnueabi-g ## MAKEFILE_GENERATOR UNIX # CONFIG incremental # QMAKE_INCREMENTAL_STYLE sublib# include(../common/linux.conf) # include(../common/gcc-base-unix.conf) # inc…...

SQL自学,mysql从入门到精通 --- 第 14天,主键、外键的使用

1.主键 PRIMARY KEY 主键的使用 字段值不允许重复,且不允许赋NULL值 创建主键 root@mysqldb 10:11: [d1]> CREATE TABLE t3(-> name varchar(10) PRIMARY KEY,-> age int,-> class varchar(8)-> ); Query OK, 0 rows affected (0.01 sec)root@mysqldb 10:…...

整合 Redis 分布式锁:从数据结构到缓存问题解决方案

引言 在现代分布式系统中&#xff0c;Redis 作为高性能的键值存储系统&#xff0c;广泛应用于缓存、消息队列、实时计数器等多种场景。然而&#xff0c;在高并发和分布式环境下&#xff0c;如何有效地管理和控制资源访问成为一个关键问题。Redis 分布式锁正是为了解决这一问题…...

ASP.NET Core WebSocket、SignalR

目录 WebSocket SignalR SignalR的基本使用 WebSocket WebSocket基于TCP协议&#xff0c;支持二进制通信&#xff0c;双工通信。性能和并发能力更强。WebSocket独立于HTTP协议&#xff0c;不过我们一般仍然把WebSocket服务器端部署到Web服务器上&#xff0c;因为可以借助HT…...

array_walk. array_map. array_filter

1. array_walk 函数 array_walk 用于遍历数组并对每个元素执行回调函数。它不会受到数组内部指针位置的影响&#xff0c;会遍历整个数组。回调函数接收的前两个参数分别是元素的值和键名&#xff0c;如果有第三个参数&#xff0c;则数组所有的值都共用这个参数。 示例代码&am…...

解锁国内主流前端与后端框架

前端框架大揭秘 在当今的 Web 开发领域&#xff0c;前端框架的地位愈发举足轻重。随着用户对 Web 应用交互性和体验性要求的不断攀升&#xff0c;前端开发不再仅仅是简单的页面布局与样式设计&#xff0c;更需要构建复杂且高效的用户界面。前端框架就像是一位得力助手&#xf…...

Nginx进阶篇 - nginx多进程架构详解

文章目录 1. nginx的应用特点2. nginx多进程架构2.1 nginx多进程模型2.2 master进程的作用2.3 进程控制2.4 worker进程的作用2.5 worker进程处理请求的过程2.6 nginx处理网络事件 1. nginx的应用特点 Nginx是互联网企业使用最为广泛的轻量级高性能Web服务器&#xff0c;其特点是…...

【PDF提取内容】如何批量提取PDF里面的文字内容,把内容到处表格或者批量给PDF文件改名,基于C++的实现方案和步骤

以下分别介绍基于 C 批量提取 PDF 里文字内容并导出到表格&#xff0c;以及批量给 PDF 文件改名的实现方案、步骤和应用场景。 批量提取 PDF 文字内容并导出到表格 应用场景 文档数据整理&#xff1a;在处理大量学术论文、报告等 PDF 文档时&#xff0c;需要提取其中的关键信…...

HTML之CSS定位、浮动、盒子模型

HTML之CSS定位、浮动、盒子模型 定位 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document<…...

【Java基础】为什么不支持多重继承?方法重载和方法重写之间区别、Exception 和 Error 区别?

Hi~&#xff01;这里是奋斗的明志&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f331;&#x1f331;个人主页&#xff1a;奋斗的明志 &#x1f331;&#x1f331;所属专栏&#xff1a;Java基础面经 &#x1f4da;本系列文章为个…...

使用scoop 下载速度慢怎么办

在国内使用 Scoop 下载速度慢是一个常见问题&#xff0c;主要是因为 Scoop 默认的软件源&#xff08;bucket&#xff09;和下载服务器通常位于国外。以下是一些提高下载速度的方法&#xff1a; 1. 更换 Scoop 镜像源&#xff08;Bucket 镜像&#xff09;&#xff1a; 原理&…...

使用Redis解决使用Session登录带来的共享问题

在学习项目的过程中遇到了使用Session实现登录功能所带来的共享问题&#xff0c;此问题可以使用Redis来解决&#xff0c;也即是加上一层来解决问题。 接下来介绍一些Session的相关内容并且采用Session实现登录功能&#xff08;并附上代码&#xff09;&#xff0c;进行分析其存在…...

OnlyOffice docker 运行(详细)

下载镜像 推荐使用 GitHub Action 方式下载&#xff1a; Action 地址&#xff1a;https://github.com/Shixuebin/DockerTarBuilder 教程地址&#xff1a;https://www.bilibili.com/video/BV1EZ421M7mL/ docker 镜像安装 docker load -i xxx.tar镜像运行 docker run -i -t -…...

CNN 卷积神经网络处理图片任务 | PyTorch 深度学习实战

前一篇文章&#xff0c;学习率调整策略 | PyTorch 深度学习实战 本系列文章 GitHub Repo: https://github.com/hailiang-wang/pytorch-get-started CNN 卷积神经网络 CNN什么是卷积工作原理深度学习的卷积运算提取特征不同特征核的效果比较卷积核感受野共享权重池化 示例源码 …...

自动驾驶数据集三剑客:nuScenes、nuImages 与 nuPlan 的技术矩阵与生态协同

目录 1、引言 2、主要内容 2.1、定位对比&#xff1a;感知与规划的全维覆盖 2.2、数据与技术特性对比 2.3、技术协同&#xff1a;构建全栈研发生态 2.4、应用场景与评估体系 2.5、总结与展望 3、参考文献 1、引言 随着自动驾驶技术向全栈化迈进&#xff0c;Motional 团…...

02.07 TCP服务器与客户端的搭建

一.思维导图 二.使用动态协议包实现服务器与客户端 1. 协议包的结构定义 首先&#xff0c;是协议包的结构定义。在两段代码中&#xff0c;pack_t结构体都被用来表示协议包&#xff1a; typedef struct Pack {int size; // 记录整个协议包的实际大小enum Type type; …...

基于机器学习时序库pmdarima实现时序预测

目录 一、Pmdarima实现单变量序列预测1.1 核心功能与特性1.2 技术优势对比1.3 python案例1.3.1 时间序列交叉验证1.3.1.1 滚动交叉验证1.3.1.2 滑窗交叉验证 时间序列相关参考文章&#xff1a; 时间序列预测算法—ARIMA 基于VARMAX模型的多变量时序数据预测 基于机器学习时序库…...

计算机视觉的研究方向、发展历程、发展前景介绍

以下将分别从图像分类、目标检测、语义分割、图像分割&#xff08;此处应主要指实例分割&#xff09;四个方面&#xff0c;为你介绍研究生人工智能计算机视觉领域的应用方向、发展历程以及发展前景。 文章目录 1.图像分类应用方向发展历程发展前景 2.目标检测应用方向发展历程…...

NLP_[2]-认识文本预处理

文章目录 1 认识文本预处理1 文本预处理及其作用2. 文本预处理中包含的主要环节2.1 文本处理的基本方法2.2 文本张量表示方法2.3 文本语料的数据分析2.4 文本特征处理2.5数据增强方法2.6 重要说明 2 文本处理的基本方法1. 什么是分词2 什么是命名实体识别3 什么是词性标注 1 认…...

单硬盘槽笔记本更换硬盘

背景 本人的笔记本电脑只有一个硬盘槽&#xff0c;而且没有M.2的硬盘盒&#xff0c;只有一个移动硬盘 旧硬盘&#xff1a;512G 新硬盘&#xff1a;1T 移动硬盘&#xff1a;512G 参考链接&#xff1a;https://www.bilibili.com/video/BV1iP41187SW/?spm_id_from333.1007.t…...

在stm32mp257的yocto中设置用户名和密码

在STM32MP257的Yocto环境中设置用户名和密码,通常需要修改根文件系统的用户配置。以下是详细步骤: 1. 设置root密码 默认情况下,root账户可能无密码或使用默认密码。通过以下方法修改: 方法1:在local.conf中直接设置 # 打开Yocto工程的配置文件 vi conf/local.conf# 添…...

力扣--链表

相交链表 法一&#xff1a; 把A链表的节点都存HashSet里&#xff0c;遍历B链表找相同的节点 法二&#xff1a; 把A、B指针都移到末尾&#xff0c;再同时往回走&#xff0c;每次往回走都比较 当前节点的下一节点&#xff08;a.next b.next ?)是否相同&#xff0c;当不相同…...

【redis】数据类型之hash

Redis中的Hash数据类型是一种用于存储键值对集合的数据结构。与Redis的String类型不同&#xff0c;Hash类型允许你将多个字段&#xff08;field&#xff09;和值&#xff08;value&#xff09;存储在一个单独的key下&#xff0c;从而避免了将多个相关数据存储为多个独立的key。…...

多路文件IO

一、思维导图...