PSO优化算法的C语言快速设置流程详解

本文指导如何快速上手PSO(粒子群优化)算法,包括参数选择(如维度、边界、误差阈值)、结构体pso_settings_t设置详解,目标函数设置,以及关键步骤如gBest初始化和核心算法实现。适合初学者了解PSO基本配置与应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

本文目的在于快速上手PSO的基本设置和应用,关于PSO具体原理请见参考文献。PSO算法参数设置简单,使用方便。

本文所用PSO算法程序参考github:GitHub - kkentzo/pso: Particle Swarm Optimization (PSO) in C

1.参数设置

在设置参数前,我们先选择系统中的待优化参数的初值和范围,以及建立相应的评价函数,然后利用结构体pso_settings_t设置参数。结构体定义如下:

// PSO SETTINGS
typedef struct {

    int dim; // problem dimensionality
    double *range_lo; // lower range limit (array of length DIM)
    double *range_hi; // higher range limit (array of length DIM)
    double goal; // optimization goal (error threshold)

    int size; // swarm size (number of particles)
    int print_every; // ... N steps (set to 0 for no output)
    int steps; // maximum number of iterations
    int step; // current PSO step
    double c1; // cognitive coefficient
    double c2; // social coefficient
    double w_max; // max inertia weight value
    double w_min; // min inertia weight value

    int clamp_pos; // whether to keep particle position within defined bounds (TRUE)
    // or apply periodic boundary conditions (FALSE)
    int nhood_strategy; // neighborhood strategy (see PSO_NHOOD_*)
    int nhood_size; // neighborhood size
    int w_strategy; // inertia weight strategy (see PSO_W_*)

} pso_settings_t;

接下来,对结构体中各参数设置进行说明。

以下参数的设置需要结合实际问题确定,需要额外注意:

dim:维数,根据待优化参量的个数确定。比如优化一个三维向量,则设置维数为3.

range_lo&range_hi:粒子位置的数组边界;这些是数组 ( double *),其长度由维数确定。根据待优化参量的物理意义定义各参量的边界范围。

goal:优化的误差阈值,满足误差要求即可。如果目标函数返回的值低于此目标,则搜索将停止。

nhood_strategy:领域吸引子的策略选择。

pso 提供了三种不同的策略来确定每个粒子的邻域吸引子:

  1. 全局拓扑 ( PSO_NHOOD_GLOBAL),其中每个粒子都由群体中的每个其他粒子通知

  2. 环形拓扑 ( PSO_NHOOD_RING) 其中存在一个固定的环形拓扑,每个粒子由其相邻粒子通知

  3. 随机拓扑 ( PSO_NHOOD_RANDOM),其中使用随机拓扑,当两次连续迭代 [3,4] 中的误差未得到改善时更新。用于调整每个粒子nhood_sizepso_settings_t平均告密者数量。

以下参数的设置可根据经验取值确定,根据优化需求适当调整:

size:粒子群规模,可根据维数计算。推荐取值范围:[20,1000],简单问题一般取20~40,较难或特定类别的问题可以取100~200。

// calulate swarm size based on dimensionality
int pso_calc_swarm_size(int dim) {
    int size = 10. + 2. * sqrt(dim);
    return (size > PSO_MAX_SIZE ? PSO_MAX_SIZE : size);
}

print_every:步骤数。如果大于零,则此值指定在屏幕上打印有关搜索状态的信息之前应经过多少步

steps:算法的最大迭代次数。

c1,c2:学习因子,调节学习最大步长,即粒子经验来源的权重。根据经验值取值。默认值为 c1 = c2 = 1.496

clamp_pos:取TRUE则将粒子位置保持在定义的边界内。取FALSE则应用周期边界条件。一般取TRUE(1)。

nhood_size:邻域大小。

w_strategy:惯性权重策略。惯性权重 (w) 的值决定了全局搜索和局部搜索之间的平衡。实施了两种不同的策略:

  1. 使用 w=0.7298 [5] 的常数值 (PSO_W_CONST)

  2. 线性递减惯性权重 ( PSO_W_LIN_DEC) 。使用 w_maxw_mininpso_settings_t分别控制起点和终点。

w_max&w_min:惯性因子的范围,可调节对解空间的搜索范围。根据经验取值。

以下为参考github的pso设置函数示例。

// create pso settings
pso_settings_t *pso_settings_new(int dim, double range_lo, double range_hi) {
    pso_settings_t *settings = (pso_settings_t *)malloc(sizeof(pso_settings_t));
    if (settings == NULL) { return NULL; }

    // set some default values
    settings->dim = dim;
    settings->goal = 1e-5;

    // set up the range arrays
    settings->range_lo = (double *)malloc(settings->dim * sizeof(double));
    if (settings->range_lo == NULL) { free(settings); return NULL; }

    settings->range_hi = (double *)malloc(settings->dim * sizeof(double));
    if (settings->range_hi == NULL) { free(settings); free(settings->range_lo); return NULL; }

    for (int i=0; i<settings->dim; i++) {
        settings->range_lo[i] = range_lo;
        settings->range_hi[i] = range_hi;
    }

    settings->size = pso_calc_swarm_size(settings->dim);
    settings->print_every = 1000;
    settings->steps = 100000;
    settings->c1 = 1.496;
    settings->c2 = 1.496;
    settings->w_max = PSO_INERTIA;
    settings->w_min = 0.3;

    settings->clamp_pos = 1;
    settings->nhood_strategy = PSO_NHOOD_RING;
    settings->nhood_size = 5;
    settings->w_strategy = PSO_W_LIN_DEC;

    return settings;
}

函数使用示例:

pso_settings_t *settings = NULL;
settings = pso_settings_new(30, -2.048, 2.048);
printf("Optimizing function: rosenbrock (dim=%d, swarm size=%d)\n",
                   settings->dim, settings->size);

2.算法设置

2.1目标函数设置

我们需要将已知目标函数(误差评价函数)导入算法,这里提供了一个自定义函数来接收目标函数,用于更新适应值。三个形参的意义分别为:粒子的顺序数,维数,目标函数的参数

// OBJECTIVE FUNCTION TYPE
typedef double (*pso_obj_fun_t)(double *, int, void *);

我们编写好目标函数后,用pso_obj_fun_t接收即可。github示例如下:

//目标函数
double pso_rosenbrock(double *vec, int dim, void *params) {

    double sum = 0;
    int i;
    for (i=0; i<dim-1; i++)
        sum += 100 * pow((vec[i+1] - pow(vec[i], 2)), 2) +	\
            pow((1 - vec[i]), 2);

    return sum;

}
//main函数中应用
pso_obj_fun_t obj_fun = NULL;
obj_fun = pso_rosenbrock;

2.2gbest初始化

gbest为所有粒子搜寻到的整体最佳解,在迭代过程中不断更新。当算法运行结束时,gbest为目标解,因此需要初始化并分配内存,以保存最优解和最小误差。

首先定义一个结构体用来接收数据。

// PSO SOLUTION -- Initialized by the user
typedef struct {

    double error;
    double *gbest; // should contain DIM elements!!

} pso_result_t;

然后根据维数为数据分配内存。

// initialize GBEST solution
    pso_result_t solution;
    // allocate memory for the best position buffer
    solution.gbest = (double *)malloc(settings->dim * sizeof(double));

2.3优化算法

关于PSO算法的核心程序在github中封装为函数pso_solve(),设置好参数后运行即可。

void pso_solve(pso_obj_fun_t obj_fun, void *obj_fun_params,
	       pso_result_t *solution, pso_settings_t *settings)

以下为函数使用示例,运行完毕后注意释放内存。

// run optimization algorithm
    pso_solve(obj_fun, NULL, &solution, settings);

// free the gbest buffer
    free(solution.gbest);

// free the settings
    pso_settings_free(settings);

3.总结

关于github源程序的使用请见作者的自述文件,PSO核心的设置流程为:设置一般参数,设置目标函数,分配内存,运行算法,释放内存。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑化咸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值