此代码是我给我朋友写的,如果有人做平行机台订单接受方向或者论文,可以参考此代码,希望对读者有帮助和启示!
可复制直接运行,无需修改!
/*
PSO algrithm for accept order and schedule
Written by tang jun on February 20, 2020
*/
#include <iostream>
# include <fstream>
#include <iomanip>
#include <math.h>
#include <vector>
#include<random>
#include<ctime>
#include <stdlib.h>
using namespace std;
/*
加工时间,收益,延迟惩罚 软时间窗(截止日期前后延长一点),库存成本,序列相依装设,非等效机台
符号索引:
N: 表示订单总数
M: 表示机台总数
i:订单索引,i=1,…,N
m:机台索引,m=1,…,M
参数:
s_0i:订单i在机台上最先被加工所产生的整备时间,i=1,…,N [N,]
s_ij:订单i处理完接着加工订单j在机台上所产生的整备时间,i=1,…,N,j=1,…,N,i≠j。 [N, N]
p_im:订单i在机台m上的加工时间,i=1,…,N。 [N, M]
r_i:订单i的利润,i=1,…,N。 [N,]
w_i:订单i单位延迟处罚权重,i=1,…,N。 [N,]
h_i:订单i单位提早库存成本,i=1,…,N。 [N,]
d_i:订单i的交货时间窗,i=1,…,N。 [ d_i1,d_i2 ] [N , 2]
变数:
C_i:订单i的完工时间,i=1,…,N。 [N,]
T_i:订单i的延迟时间,i=1,…,N。 Ti1= max(0,di1- Ci) >0表示订单i的在时间窗提前完工,提早时间,
有库存成本,否则不考虑 Ti2=max(0,Ci-di2) >0表示订单i 的延迟时间,否则不考虑 [Ti1,Ti2] [N,2]
目标函数:max=ri-Ti1*hi-Ti2*wi i表示被接受的订单
*/
// 下面为全局变量,便于所有函数或类等都可以使用!
const int N = 20; // total number of orders
const int M = 6; // total number of machines
const int K = 10; // toral number of particle for pso algrithm
// 构建矩阵变量来存储需要的数据,共有2部分:
//第一部分:构建存储随机产生的已知变量
float s_0i[N]; //序列相依装设的时间,用于每台机器第一订单位置
float s_ij[N][N]; //序列相依装设的时间
float p_im[N][M]; // 每台机器对应订单的加工时间
float r_i[N]; //每个订单的利润
float w_i[N]; // 订单i单位延迟处罚权重
float h_i[N]; // 订单i单位提早库存成本
float d_i[N][2]; // 订单i的交货时间窗 [d_i1,d_i2][N, 2]
float C_i[N]; // 订单i的完工时间 [N, ]
float T_i[N][2]; // 订单i的提早和延迟时间
float Randnumber = 10; //随机种子
// PSO算法参数设置
int pso_num_iteration_end = 100000;
float pso_time_end = 100;
float pso_w = 0.2;
float pso_c1 = 0.8;
float pso_c2 = 0.8;
float pso_order_vmin = -8;
float pso_order_vmax = 8;
float pso_machine_vmin = -8;
float pso_machine_vmax = 8;
// 第二部分:构建所有的粒子订单矩阵及机器矩阵来保存变量
float order_p_gbest[N]; //保存所有粒子中最佳位置
float order_v_gbest[N]; //保存所有粒子中最佳速度
float machine_p_gbest[N]; //保存所有粒子中最佳位置对应的机器最佳位置
float machine_v_gbest[N]; //保存所有粒子中最佳速度对应的机器最佳速度
class util {
// 辅助函数
public:
// 该函数是随机在[LB, UB]中产生浮点数
float RandomRge(float LB, float UB) { float x; x = LB + (UB - LB) / (RAND_MAX) * (float)rand(); return (x); }
// 该函数是随机在[0, 1]中产生浮点数
float RandomF() { float x; x = (float)1.0 / (float)(RAND_MAX) * (float)rand(); return (x); }
// 该函数给定一维数组,输出从大到小的排序的索引值,此函数是一个指针函数,需要建立指针来读取输出数据。
int *sort_seq( float *p, const int size=N) {
float *f;
static int index_int[N];
float temp[N] ;
float temp1 = 0.0;
int index = 0;
int temp_index = 0;
f = p; // 将指针指向了p地址
for (int i = 0; i < size; i++) {
// 该循环将输入的一维变量传值给了temp的变量
temp[i] = *f;
// cout << "temp[i]" << temp[i]<<endl;
f++;
}
for (int i = 0; i < size; i++) {
temp1 = temp[i];
temp_index = i;
for (int j = 0; j < size; j++) {
if ( temp1 > temp[j] ) {
temp1 = temp[j];
temp_index = j;
index = temp_index;
}
else
{
index = temp_index;
}
}
temp[index] = 999999; // 找到对应的索引将其值变一个很大的数
index_int[i] = index; // 将该最小值索引添加到该index_int数组中,最终是输入序列从小到大的索引值
}
return index_int;
}
// 该函数输入类型clock_t的开始时间,就可以计算出从开始时间截止目前时间的耗费时间长,返回是秒
float clock_time(clock_t time_start) {
float time_period;
clock_t time_end;
time_end = clock();
time_period = (time_start - time_end) / CLOCKS_PER_SEC;
return time_period;
}
}U;
void data_product_init() {
float d_i_temp;
srand(Randnumber); // 产生伪随机,在Randnumber不变情况下,以下变量不变
for (int i = 0; i < N; i++) {
s_0i[i] = U.RandomRge(2, 8);
r_i[i] = U.RandomRge(100, 200); //每个订单的利润
w_i[i] = U.RandomRge(2, 10); // 订单i单位延迟处罚权重
h_i[i] = U.RandomRge(2, 10); // 订单i单位提早库存成本
d_i[i][0] = U.RandomRge(15, 50); // 订单i的交货时间窗 [d_i1,d_i2][N, 2]
d_i_temp = U.RandomRge(0, 10); //中间变量,用来加这一部分时间便是截止窗末端
d_i[i][1] = d_i_temp+ d_i[i][0]; // 订单i的交货时间窗 [d_i1,d_i2][N, 2]
C_i[i] = 0; // 根据计算得到,所以不用产生,初始化为0
T_i[i][0] = 0; // 根据计算得到,所以不用产生,初始化为0
T_i[i][1] = 0; // 根据计算得到,所以不用产生,初始化为0
// 对保存全局最佳变量初始化
order_p_gbest[i]=0; //根据计算得到,所以不用产生,初始化为0
order_v_gbest[i]=0; //根据计算得到,所以不用产生,初始化为0
machine_p_gbest[i]=0; //根据计算得到,所以不用产生,初始化为0
machine_v_gbest[i]=0; //根据计算得到,所以不用产生,初始化为0
for (int j = 0; j < N; j++) {
s_ij[i][j]= U.RandomRge(2, 8); //序列相依装设的时间
}
for (int m = 0; m < M; m++) {
p_im[i][m]= U.RandomRge(5, 20); // 每台机器对应订单的加工时间
}
}
}
class PSO {
public:
//创建每个粒子的变量
float order_position_seq[N]; //创建并保存订单位置序列的变量 16
float order_speed_seq[N]; //创建并保存订单速度序列的变量
float order_p_best[N]; //保存该粒子订单位置最佳位置
float order_v_best[N]; //保存该粒子订单最佳速度
// 创建机器变量,随后迭代保存最佳需要对应粒子保存的最佳
float machine_position_seq[N]; //创建机器位置序列的变量 15
float machine_speed_seq[N]; //创建机器速度序列的变量
float machine_p_best[N]; //保存该粒子机器最佳位置
float machine_v_best[N]; //保存该粒子机器最佳速度
PSO() {
// 构造函数用来随机初始化变量
for (int i = 0; i < N; i++) {
order_position_seq[i]= U.RandomRge(1,N);
order_speed_seq[i] = U.RandomRge(1, N);
order_p_best[i]= order_position_seq[i];
order_v_best[i]= order_speed_seq[i];
machine_position_seq[i] = U.RandomRge(0, M+1-0.00001);
machine_speed_seq[i] = U.RandomRge(0, M + 1 - 0.00001);
machine_p_best[i]= machine_position_seq[i];
machine_v_best[i]= machine_speed_seq[i];
}
}
}particle[K]; //particle[K] 表示已经对象化了,产生了K个粒子
float object(float *order_seq,float *machine_seq) {
// 构建目标函数
float *order; //建立浮点型指针用来读取order_seq的数据
float *machine;//建立浮点型指针用来读取machine_seq的数据
int *index; //建立订单排序函数指针,用来读取排序函数的输出值
float order_sequence[N]; //用来保存order序列
int order_index[N];
float machine_sequence[N];//用来保存机台序列
order = order_seq; //该指针指向order序列
machine = machine_seq;//该指针指向machine序列
for (int i = 0; i < N; i++) {
// 该循环将值赋给上面的变量。
order_sequence[i] = *order;
machine_sequence[i] = *machine;
order++;
machine++;
}
index = U.sort_seq(order_sequence); //用index指针指向输出值的首地址
int machine_sequence_int[N] = { 0 };
for (int i = 0; i < N; i++) {
// 将订单序列从小到大的索引已经赋值给order_index中了。
order_index[i] = *(index+i);
machine_sequence_int[i] = int(machine_sequence[i]);
}
int machine_count[M]; // 保存每个机台对应加工订单的数量
for (int m = 0; m < M; m++) { machine_count[m] = 0; } // 赋值为0
for (int i = 0; i < N; i++ ) {
for (int m = 0; m < M; m++) {
if (machine_sequence_int[i]==m+1) {
// 利用m+1可以排除机台为0的不用计算进去
machine_count[m]++;
}
}
}
// 下面较为复杂,按照每台机器取计算目标值
int order_temp1 = 0;
int order_temp_i = -1;
int order_temp_j = -1;
float object_result = 0.0;
int temp_cont = 0; // 使用计数方法来处理机台的第一订单
for (int m = 0; m < M; m++) {
if (machine_count[m] == 1) {
// 该条件说明机台只有一个订单加工,则只有装设准备时间需要s_0i
for (int i = 0; i < N; i++) {
order_temp1 = order_index[i]; // 将第i个位置加工的订单索引给变量order_temp1
if (machine_sequence_int[order_temp1] == m + 1) {
// 对应机台是否等于该循环的机台,如果是就记住该索引号,停止循环,因为只有一个订单
order_temp_i = order_temp1;
break; // 跳出当前循环
}
}
C_i[order_temp_i]=s_0i[order_temp_i]+ p_im[order_temp_i][machine_sequence_int[order_temp_i]];
T_i[order_temp_i][0]=d_i[order_temp_i][0]- C_i[order_temp_i]; // 如果大于0表示提前完成有库存成本
T_i[order_temp_i][1] = C_i[order_temp_i]-d_i[order_temp_i][1]; // 如果大于0表示延迟完成有惩罚权重
if (T_i[order_temp_i][0] < 0) { T_i[order_temp_i][0] = 0; }
if (T_i[order_temp_i][1] < 0) { T_i[order_temp_i][1] = 0; }
// 计算目标值 ri-Ti1*hi-Ti2*wi
object_result = object_result + r_i[order_temp_i] - h_i[order_temp_i] * T_i[order_temp_i][0] - w_i[order_temp_i] * T_i[order_temp_i][1];
}
if (machine_count[m] > 1) {
// 该条件说明机第(m+1)的机台有多个订单加工
temp_cont = 0; // 将其赋值为0
for (int i = 0; i < N; i++) {
order_temp1 = order_index[i]; // 将第i个位置加工的订单索引给变量order_temp1
if (machine_sequence_int[order_temp1] == m + 1) {
// 对应机台是否等于该循环的机台,如果是就记住该索引号
temp_cont++;//计数,若为1表示该机台首次加工该订单,需要s0i
if (temp_cont==1) {
order_temp_i = order_temp1;
C_i[order_temp_i] = s_0i[order_temp_i] + p_im[order_temp_i][machine_sequence_int[order_temp_i]];
T_i[order_temp_i][0] = d_i[order_temp_i][0] - C_i[order_temp_i]; // 如果大于0表示提前完成有库存成本
T_i[order_temp_i][1] = C_i[order_temp_i] - d_i[order_temp_i][1]; // 如果大于0表示延迟完成有惩罚权重
if (T_i[order_temp_i][0] < 0) { T_i[order_temp_i][0] = 0; }
if (T_i[order_temp_i][1] < 0) { T_i[order_temp_i][1] = 0; }
// 计算目标值 ri-Ti1*hi-Ti2*wi
object_result = object_result + r_i[order_temp_i] - h_i[order_temp_i] * T_i[order_temp_i][0] - w_i[order_temp_i] * T_i[order_temp_i][1];
}
else {
order_temp_j = order_temp1;
C_i[order_temp_j] = C_i[order_temp_i]+s_ij[order_temp_i][order_temp_j] + p_im[order_temp_j][machine_sequence_int[order_temp_j]];
T_i[order_temp_j][0] = d_i[order_temp_j][0] - C_i[order_temp_j]; // 如果大于0表示提前完成有库存成本
T_i[order_temp_j][1] = C_i[order_temp_j] - d_i[order_temp_j][1]; // 如果大于0表示延迟完成有惩罚权重
if (T_i[order_temp_j][0] < 0) { T_i[order_temp_j][0] = 0; }
if (T_i[order_temp_j][1] < 0) { T_i[order_temp_j][1] = 0; }
// 计算目标值 ri-Ti1*hi-Ti2*wi
object_result = object_result + r_i[order_temp_j] - h_i[order_temp_j] * T_i[order_temp_j][0] - w_i[order_temp_j] * T_i[order_temp_j][1];
order_temp_i = order_temp_j; // 将处理订单传给上一个订单变量,下次变成了这个订单
}
}
}
}
}
return object_result;
}
float pso_run() {
// 对生产变量初始化,直接调用函数
data_product_init();
//下面循环将是在k个粒子中找到全局最佳解将其值传给
float object_old=0.0;
float object_new=0.0;
float object_invidual = 0.0;
//在K个粒子中寻找最佳解,并将其赋值给最佳值变量中
for (int k = 0; k < K; k++) {
if (k == 0) {
object_old = object(particle[k].order_p_best, particle[k].machine_p_best);
for (int i = 0; i < N; i++) {
order_p_gbest[i] = particle[k].order_p_best[i];
order_v_gbest[i] = particle[k].order_v_best[i];
machine_p_gbest[i] = particle[k].machine_p_best[i];
machine_v_gbest[i] = particle[k].machine_v_best[i];
}
}
else {
object_new = object(particle[k].order_p_best, particle[k].machine_p_best);
if (object_new > object_old) {
object_old = object_new; // 如果大就换值
for (int i = 0; i < N; i++) {
order_p_gbest[i] = particle[k].order_p_best[i];
order_v_gbest[i] = particle[k].order_v_best[i];
machine_p_gbest[i] = particle[k].machine_p_best[i];
machine_v_gbest[i] = particle[k].machine_v_best[i];
}
}
}
//cout << "object=" << object_old << endl;
}
float order_p_new[N] = { 0 };
float order_v_new[N] = { 0 };
float machine_p_new[N] = { 0 };
float machine_v_new[N] = { 0 };
int iteration_count = 0;
clock_t time_start;
float iteration_time = 0;
time_start = clock(); //建立停止时间
while (iteration_count < pso_num_iteration_end) {
if (iteration_time > pso_time_end) { break; }
// 下面是对每只粒子进行解的迭代
for (int k = 0; k < K; k++) {
// 对粒子循环
for (int i = 0; i < N; i++) {
// 对订单及机台进行领域解的更新
//对订单的解进行更新
order_v_new[i] = pso_w * particle[k].order_position_seq[i] +
pso_c1 * U.RandomF() * (particle[k].order_p_best[i] - particle[k].order_position_seq[i]) +
pso_c2 * U.RandomF() * (order_p_gbest[i] - particle[k].order_position_seq[i]);
// 对速度进行一个判断
if (order_v_new[i] > pso_order_vmax) { order_v_new[i] = pso_order_vmax; }
if (order_v_new[i] < pso_order_vmin) { order_v_new[i] = pso_order_vmin; }
order_p_new[i] = particle[k].order_position_seq[i] + order_v_new[i];
//对机台的解进行更新
machine_v_new[i] = pso_w * particle[k].machine_position_seq[i] +
pso_c1 * U.RandomF() * (particle[k].machine_p_best[i] - particle[k].machine_position_seq[i]) +
pso_c2 * U.RandomF() * (machine_p_gbest[i] - particle[k].machine_position_seq[i]);
// 对速度进行一个判断
if (machine_v_new[i] > pso_machine_vmax) { machine_v_new[i] = pso_machine_vmax; }
if (machine_v_new[i] < pso_machine_vmin) { machine_v_new[i] = pso_machine_vmin; }
machine_p_new[i] = particle[k].machine_position_seq[i] + machine_v_new[i];
// 对机器做一些限制,因为超出机台数量那就有问题了
if (machine_p_new[i] > M) { machine_p_new[i] = M; }
if (machine_p_new[i] < 0) { machine_p_new[i] = 0; }
}
// 求解未更新的解与已经更新的解
object_old = object(particle[k].order_position_seq, particle[k].machine_position_seq);
object_new = object(order_p_new, machine_p_new);
// 下面的代码是根据object_old与object_new是否需要更换解
if (object_new >= object_old) {
object_old = object(order_p_gbest, machine_p_gbest); // 求解全局最佳解的目标值
// 满足该条件表示需要更换该解,我们先把个体最佳解给更新了
for (int i = 0; i < N; i++) {
particle[k].order_position_seq[i]=order_p_new[i];
particle[k].order_speed_seq[i]=order_v_new[i];
particle[k].machine_position_seq[i]=machine_p_new[i];
particle[k].machine_speed_seq[i]=machine_v_new[i];
object_invidual= object(particle[k].order_p_best, particle[k].machine_p_best); // 求解当前粒子个体最佳解的目标值
if (object_invidual> object_new) {
particle[k].order_p_best[i] = order_p_new[i];
particle[k].order_v_best[i] = order_v_new[i];
particle[k].machine_p_best[i] = machine_p_new[i];
particle[k].machine_v_best[i] = machine_v_new[i];
}
if (object_new > object_old) {
// 该条件满足需要更新全局最佳解
order_p_gbest[i] = particle[k].order_position_seq[i];
order_v_gbest[i] = particle[k].order_speed_seq[i];
machine_p_gbest[i] = particle[k].machine_position_seq[i];
machine_v_gbest[i] = particle[k].machine_speed_seq[i];
}
}
}
}
iteration_count++; //迭代次数叠加
iteration_time = U.clock_time(time_start);
float object_end = 0.0; // 打印出最佳值
object_end = object(order_p_gbest, machine_p_gbest);
cout << "value iteratived by pso algrithm :" << object_end << endl;
}
float object_end = 0.0; // 打印出最佳值
object_end= object(order_p_gbest, machine_p_gbest);
cout << "value finished pso algrithm :" << object_end<<endl;
return object_end;
}
int main(){
pso_run();
while (0);
return 0;
}