From 17167094f326608b988df7bcd81c4f9d750d90ea Mon Sep 17 00:00:00 2001 From: guofei Date: Tue, 9 Jun 2020 00:28:20 +0800 Subject: [PATCH] GA: fix a bug in the integer mode, a new algorithm in a way. version 0.5.7. #32 #37 #59 --- docs/en/more_ga.md | 8 ++++---- docs/zh/more_ga.md | 12 ++++++------ sko/GA.py | 33 +++++++++++++++++++++------------ sko/__init__.py | 2 +- 4 files changed, 32 insertions(+), 23 deletions(-) diff --git a/docs/en/more_ga.md b/docs/en/more_ga.md index 58d780f..6ea567a 100644 --- a/docs/en/more_ga.md +++ b/docs/en/more_ga.md @@ -13,11 +13,11 @@ print('best_x:', best_x, '\n', 'best_y:', best_y) ``` Notice: -- if `precision` is an integer, and the number of all possible value is $2^n$, the performance is best -- if `precision` is an integer, and the number of all possible value is not $2^n$, `GA` do these: +- If `precision` is an integer, the number of all possible value would better be $2^n$, in which case the performance is the best. It also works if the number is not $2^n$ + - If `precision` is not an integer, but you still want this mode, manually deal with it. For example, your original `precision=0.5`, just make a new variable, multiplied by `2` @@ -49,7 +49,7 @@ def cal_total_distance(routine): cal_total_distance(np.arange(num_points)) ''' num_points, = routine.shape - routine = np.concatenate([[num_points],routine,[num_points+1]]) + routine = np.concatenate([[num_points], routine, [num_points+1]]) return sum([distance_matrix[routine[i], routine[i + 1]] for i in range(num_points+2-1)]) ``` diff --git a/docs/zh/more_ga.md b/docs/zh/more_ga.md index 9d34389..d072c0b 100644 --- a/docs/zh/more_ga.md +++ b/docs/zh/more_ga.md @@ -14,12 +14,12 @@ print('best_x:', best_x, '\n', 'best_y:', best_y) ``` 说明: -- 当 `precision` 为整数时,会启用整数规划模式。 -- 在整数规划模式下,如果某个变量的取值可能个数是 $2^n$,不会对性能有影响 -- 在整数规划模式下,如果某个变量的取值可能个数不是 $2^n$,`GA` 会做这些事: +- 当 `precision` 为整数时,对应的自变量会启用整数规划模式。 +- 在整数规划模式下,变量的取值可能个数最好是 $2^n$,这样收敛速度快,效果好。 + - 如果 `precision` 不是整数(例如是0.5),则不会进入整数规划模式,如果还想用这个模式,那么把对应自变量乘以2,这样 `precision` 就是整数了。 ## 遗传TSP问题如何固定起点和终点? @@ -50,7 +50,7 @@ def cal_total_distance(routine): ''' num_points, = routine.shape # start_point,end_point 本身不参与优化。给一个固定的值,参与计算总路径 - routine=np.concatenate([[num_points],routine,[num_points+1]]) + routine = np.concatenate([[num_points], routine, [num_points+1]]) return sum([distance_matrix[routine[i], routine[i + 1]] for i in range(num_points+2-1)]) ``` @@ -76,7 +76,7 @@ plt.show() ## 如何设定初始点或初始种群 -- 对于遗传算法 `GA`, 运行 `ga=GA(**params)` 生成模型后,赋值设定初始种群,例如 `ga.Chrom = np.random.randint(0,2,size=(80,20))` +- 对于遗传算法 `GA`, 运行 `ga=GA(**params)` 生成模型后,赋值设定初始种群,例如 `ga.Chrom = np.random.randint(0,2,size=(80,20))` - 对于查分进化算法 `DE`,设定 `de.X` 为初始 X. - 对于模拟退火算法 `SA`,入参 `x0` 就是初始点. - 对于粒子群算法 `PSO`,手动赋值 `pso.X` 为初始 X, 然后执行 `pso.cal_y(); pso.update_gbest(); pso.update_pbest()` 来更新历史最优点 diff --git a/sko/GA.py b/sko/GA.py index 1e91e59..851ce67 100644 --- a/sko/GA.py +++ b/sko/GA.py @@ -150,16 +150,13 @@ def __init__(self, func, n_dim, # if precision is integer: # if Lind_raw is integer, which means the number of all possible value is 2**n, no need to modify - # if Lind_raw is decimal, modify: make the ub bigger and add a constraint_ueq - int_mode = (self.precision % 1 == 0) & (Lind_raw % 1 != 0) - # int_mode is an array of True/False. If True, variable is int constraint and need more code to deal with - for i in range(self.n_dim): - if int_mode[i]: - self.constraint_ueq.append( - lambda x: x[i] - self.ub[i] - ) - self.has_constraint = True - self.ub[i] = self.lb[i] + np.exp2(self.Lind[i]) - 1 + # if Lind_raw is decimal, we need ub_extend to make the number equal to 2**n, + self.int_mode_ = (self.precision % 1 == 0) & (Lind_raw % 1 != 0) + self.int_mode = np.any(self.int_mode_) + if self.int_mode: + self.ub_extend = np.where(self.int_mode_ + , self.lb + (np.exp2(self.Lind) - 1) * self.precision + , self.ub) self.len_chrom = sum(self.Lind) @@ -188,7 +185,14 @@ def chrom2x(self, Chrom): else: Chrom_temp = Chrom[:, cumsum_len_segment[i - 1]:cumsum_len_segment[i]] X[:, i] = self.gray2rv(Chrom_temp) - X = self.lb + (self.ub - self.lb) * X + + if self.int_mode: + X = self.lb + (self.ub_extend - self.lb) * X + X = np.where(X > self.ub, self.ub, X) + # the ub may not obey precision, which is ok. + # for example, if precision=2, lb=0, ub=5, then x can be 5 + else: + X = self.lb + (self.ub - self.lb) * X return X ranking = ranking.ranking @@ -224,7 +228,12 @@ def chrom2x(self, Chrom): else: Chrom_temp = Chrom[:, cumsum_len_segment[i - 1]:cumsum_len_segment[i]] X[:, i] = self.gray2rv(Chrom_temp) - X = self.lb + (self.ub - self.lb) * X + + if self.int_mode: + X = self.lb + (self.ub_extend - self.lb) * X + X = np.where(X > self.ub, self.ub, X) + else: + X = self.lb + (self.ub - self.lb) * X return X self.register('mutation', mutation_gpu.mutation). \ diff --git a/sko/__init__.py b/sko/__init__.py index 011d023..76f59c1 100644 --- a/sko/__init__.py +++ b/sko/__init__.py @@ -1,4 +1,4 @@ -__version__ = '0.5.6' +__version__ = '0.5.7' def start():