zoukankan      html  css  js  c++  java
  • PSO演算法求解订单接受

    此代码是我给我朋友写的,如果有人做平行机台订单接受方向或者论文,可以参考此代码,希望对读者有帮助和启示!

    可复制直接运行,无需修改!

    /*
    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;
    }

  • 相关阅读:
    mysql密码忘记如何恢复(windows/liunx版本:mysql8.0.27)
    Visual Studio Code如何校验yaml格式文件
    python测试小工具
    Lunx vimgo 开发环境搭建
    小白学正则表达式之 regexp
    kubernetes scc 故障排查小记
    Go image registry
    OpenShift image registry 概述
    Go 疑难杂症汇总
    小白学标准库之 http
  • 原文地址:https://www.cnblogs.com/tangjunjun/p/12790228.html
Copyright © 2011-2022 走看看