在 [pso] C 語言第一個 pso 程式 這篇文章中,大致上已把 C 語言撰寫粒子移動演算法架構都寫了出來,這篇「續集」,主要是在討論一般在 C language 中,在一般數學式極值情況下,較常使用到的架構。
在該程式碼裡面,假設了適應函數 max f(x) = | x3 - 0.8x2 - 1000x + 8000 | ,
這只有單變數而已,故粒子群裡的位置,只有一個 position。
然而某些適應函式,變數個數卻不只一個的情況下,如
max f(x, y) = | x3y - 0.8x2 - 1000xy + 8000 | ,這問題便有 x, y 變數之存在,
在做 struct 定義時,是可以輕易改變成
/* 定義結構體particle */ typedef struct tag_particle{ double position_x; /* 目前位置 x value */
double position_y; /* 目前位置 y value */ double velocity; /* 目前粒子速度 */ double fitness ; /* 適應函式值 */ double pbest_pos; /* particle 目前最好位置 */ double pbest_fit; /* particle 目前最佳適應值 */ }particle;
新增了 position_y ,但相對的,
在速度上也必須分 x 變數上之速度與 y 變數上之速度;
而最佳位置也又分了 particle 目前最佳 x 位置與最佳 y 位置,
整體考慮下來,完整的結構體就變如下
/* 定義結構體particle */ typedef struct tag_particle{ double position_x; /* 目前位置 x value */
double position_y; /* 目前位置 y value */ double velocity_x; /* 目前粒子 x 速度 */
double velocity_y; /* 目前粒子 y 速度 */ double fitness ; /* 適應函式值 */ double pbest_pos_x; /* particle 目前最好 x 位置 */
double pbest_pos_y; /* particle 目前最好 y 位置 */ double pbest_fit; /* particle 目前最佳適應值 */ }particle;
這樣下去,只要當變數個數變多時,如 f(x1, x2, x3, ..., xn) 時,
就要寫 n 次,架構會愈來愈麻煩,且不易維護,故一般考慮維護及通用性情況下,
存位置時,通常都假設有 n 維變數,裡面再放一個 double* position,
到時做動態分配,變成 double position[n],這是較為容易維護的,大致上會長這樣。
/* 定義結構體particle */ typedef struct tag_particle{int dim; /* 變數維度個數 */ double* position; /* 目前位置 (dim 維) position[dim] */ double* velocity; /* 目前速度 (dim 維) velocity[dim] */
double fitness ; /* 適應函式值 */ double* pbest_pos; /* particle 目前最好位置 pbest_pos[dim] */ double pbest_fit; /* particle 目前最佳適應值 */ }particle;
這種設計模式是一種方式,但在撰程式碼中確顯得較麻煩,因會看到一堆
particle[i].pbest_pos[j] = particle[i].position[j]
之類的敘述式,同時在分配記憶體空間時不夠連續,
雖整體架構「擬物化」 ( 專業一點叫封裝、抽像化) 是夠的,
若是用 C++ 進行 Coding ,
用 vector + class + overload operator 可改善這問題,
上述架構也算合適、適當。但若不想花這時間建構 firendly class ( C++ 需有一定程度),
或只想用 C language coding (此系列文之目的),便不再適用 struct 方式架構,
故將整個 struct 全都打散開來,
全都用 array 表示法去表示,整個架構裡之重要變數大致如下所述。
static unsigned pcnt; /* 粒子群個數 */
static unsigned dim;
/* 解空間維度 */
static double **particle_pos; /* 各粒子目前位置[pcnt][dim] */
static double **particle_v; /* 各粒子目前速度[pcnt][dim] */
static double *particle_fv;
/* 各粒子目前適應值[pcnt] */
static double **pbest_pos; /* 各粒子目前找到最佳位置[pcnt][dim] */
static double *pbest_fv ;
/* 各粒子目前最佳適應值[pcnt] */
static double *gbest_pos;
/* 全域目前找到最佳位置[dim] */
static double gbest_fv;
/* 全域目前最佳適應值 */
注意上面宣告之變數,用的是一維或是二維,
會用 static 方式宣告,乃因到時設計時,會將這些變數獨立出來到另一個 .c file 裡,
欲擬 private member ( 這二行看不懂的話請暫時跳過,這是 C 語言裡一個籌範)。