如何在R语言模拟退火算法中添加超立方体搜索空间约束?
解决模拟退火算法搜索空间限制的问题
首先得先指出你原函数里的一个致命错误:你的return语句放在了for循环的内部,这会导致函数在第一次迭代后就直接返回结果,后面的99次迭代根本不会执行!这是必须先修正的问题。
接下来回到你要限制搜索空间在超立方体x_i ∈ [-5.12, 5.12]的需求,你之前用while循环导致停滞,大概率是因为没有设置退出条件——如果一直生成超出范围的邻居点,while会无限循环下去。下面给你两种可靠的解决方案:
方案1:截断法(简单高效,无停滞风险)
这种方法是生成邻居后,直接把每个维度的值截断到指定范围内,超出上界的设为上界,低于下界的设为下界。优点是不会有循环停滞的问题,计算效率也很高。
修正后的完整函数代码:
simulated_annealing <- function(func, s0, niter = 1, epsilon = 0.01) { # s=state, f=function, b=best, c=current, n=neighbour s_b <- s_c <- s_n <- s0 f_b <- f_c <- f_n <- func(s_n) for (k in 1:niter) { Temperatura <- (1 - epsilon)^k # 生成邻居 s_n <- rnorm(2, s_c, 1) # 截断到[-5.12, 5.12]范围 s_n <- pmax(pmin(s_n, 5.12), -5.12) f_n <- func(s_n) # 接受准则 if (f_n < f_c || runif(1, 0, 1) < exp(-(f_n - f_c) / Temperatura)) { s_c <- s_n f_c <- f_n } # 更新最优解 if (f_n < f_b) { s_b <- s_n f_b <- f_n } } # 把return移到循环外面! return(list(iteraciones = niter, Mejor_valor = f_b, Mejor_estado = s_b)) }
方案2:带兜底的拒绝采样法(严格生成范围内点)
如果你希望邻居点严格在搜索空间内,不想用截断,可以用拒绝采样,但必须设置最大尝试次数,避免无限循环。当尝试次数超过阈值时,用截断法兜底:
simulated_annealing <- function(func, s0, niter = 1, epsilon = 0.01) { s_b <- s_c <- s_n <- s0 f_b <- f_c <- f_n <- func(s_n) max_tries <- 100 # 设置最大尝试次数 for (k in 1:niter) { Temperatura <- (1 - epsilon)^k try_count <- 0 # 生成符合范围的邻居 repeat { s_n <- rnorm(2, s_c, 1) # 检查是否在范围内 if (all(s_n >= -5.12) && all(s_n <= 5.12)) { break } try_count <- try_count + 1 # 超过尝试次数,用截断法兜底 if (try_count >= max_tries) { s_n <- pmax(pmin(s_n, 5.12), -5.12) break } } f_n <- func(s_n) if (f_n < f_c || runif(1, 0, 1) < exp(-(f_n - f_c) / Temperatura)) { s_c <- s_n f_c <- f_n } if (f_n < f_b) { s_b <- s_n f_b <- f_n } } return(list(iteraciones = niter, Mejor_valor = f_b, Mejor_estado = s_b)) }
测试调用
假设你的rastr是Rastrigin函数(常用的测试函数),可以这样测试:
# 定义Rastrigin函数 rastr <- function(x) { 20 + x[1]^2 + x[2]^2 - 10*(cos(2*pi*x[1]) + cos(2*pi*x[2])) } # 调用函数 sol <- simulated_annealing(rastr, niter = 100, epsilon = 0.91, s0 = c(0, 2)) print(sol)
这样修改后,既解决了原函数迭代不完整的问题,又完美限制了搜索空间,不会出现停滞的情况。
内容的提问来源于stack exchange,提问作者user9264168
相关产品推荐
相关产品推荐

