如何用CVXR获取优化问题的多个解?现有代码结果重复求助
问题:生成满足约束的多组不同解
约束条件
需要找到多组满足以下条件的变量组合(TXs[1], TXs[2], TXs[3], TXs[4], TXs[5], TZs):
# 变量定义 TXs <- Variable(5) TZs <- Variable(1) # 目标:总和尽可能接近100 obj = abs(TXs[1] + TXs[2] + TXs[3] + TXs[4] + TXs[5] + TZs - 100) # 约束条件 # 1. 变量取值范围 abs(TXs[1] - 2) <=1 abs(TXs[2] - 55) <= 2 abs(TXs[3] - 25) <= 0.5 abs(TXs[4] - 8) <= 1 abs(TXs[5] - 7) <= 1 abs(TZs[1] - 1.5) <= 1 # 2. 相关系数约束 cor(TXs[1], TXs[2]) = 0.77 cor(TXs[3], TXs[2]) = 0.85 cor(TXs[4], TXs[2]) = 0.88 cor(TXs[5], TXs[2]) = 0.99 cor(TZs, TXs[2]) = 0.4 # 3. 总和接近100 abs(TXs[1] + TXs[2] + TXs[3] + TXs[4] + TXs[5] + TZs[1] - 100) <= 0.001
现有代码问题
你编写的CVXR代码每次运行都得到相同结果,核心原因是:
- 代码中将相关系数约束转化为严格等式(比如
((TXs[1]-2)/1) == 0.77*(TXs[2]-55)/2),这使得所有变量都被TXs[2]线性表示; - 加上总和约束后,整个系统是唯一解的线性方程组,因此循环多次也只会得到同一个结果。
解决方案
方法一:修改CVXR代码,引入松弛与随机化目标
通过放松约束范围、加入随机化目标函数,让解空间从单点扩展为区域,从而生成多个不同解:
library(CVXR) k <- 10 solutions <- matrix(NA, nrow = k, ncol = 6) set.seed(123) # 可选,保证结果可复现 for (i in 1:k) { # 每次循环重新定义变量,避免CVXR缓存影响 TXs <- Variable(5) TZs <- Variable(1) sum_vars <- sum(TXs) + TZs # 加入随机化小扰动目标,引导优化到不同可行点 rand_weights <- rnorm(6, 0, 0.01) # 小权重,不影响核心目标 obj <- abs(sum_vars - 100) + t(rand_weights) %*% c(TXs, TZs) # 放松相关系数约束为区间(允许微小波动) prob <- Problem(Minimize(obj), list( # 变量范围约束 abs(TXs[1] - 2) <= 1, abs(TXs[2] - 55) <= 2, abs(TXs[3] - 25) <= 0.5, abs(TXs[4] - 8) <= 1, abs(TXs[5] - 7) <= 1, abs(TZs[1] - 1.5) <= 1, # 放松相关系数约束为±0.01的区间 abs( ((TXs[1]-2)/1) - 0.77*((TXs[2]-55)/2) ) <= 0.01, abs( ((TXs[3]-25)/0.5) - 0.85*((TXs[2]-55)/2) ) <= 0.01, abs( ((TXs[4]-8)/1) - 0.88*((TXs[2]-55)/2) ) <= 0.01, abs( ((TXs[5]-7)/1) - 0.99*((TXs[2]-55)/2) ) <= 0.01, abs( ((TZs-1.5)/1) - 0.4*((TXs[2]-55)/2) ) <= 0.01, # 总和约束保留 abs(sum_vars - 100) <= 0.001 )) result <- solve(prob) solutions[i,] <- c(result$getValue(TXs), result$getValue(TZs)) } solutions <- as.data.frame(solutions) colnames(solutions) <- c("TXs[1]","TXs[2]","TXs[3]","TXs[4]","TXs[5]","TZs") solutions$Somme <- rowSums(solutions) print(solutions)
方法二:蒙特卡洛采样+约束验证(无需CVXR)
直接在变量范围内生成随机样本,筛选满足约束的解:
k <- 10 solutions <- data.frame(matrix(NA, nrow = k, ncol = 6)) colnames(solutions) <- c("TXs[1]","TXs[2]","TXs[3]","TXs[4]","TXs[5]","TZs") # 自定义clamp函数,将值限制在指定范围内 clamp <- function(x, min_val, max_val) { return(pmax(min_val, pmin(max_val, x))) } set.seed(123) count <- 0 while(count < k) { # 1. 随机生成核心变量TXs[2] tx2 <- runif(1, 55-2, 55+2) # 2. 根据相关系数计算基准值,加入小扰动并限制范围 tx1 <- clamp(2 + 0.77*(tx2-55)*0.5 + rnorm(1, 0, 0.05), 1, 3) tx3 <- clamp(25 + 0.85*(tx2-55)*0.25 + rnorm(1, 0, 0.02), 24.5, 25.5) tx4 <- clamp(8 + 0.88*(tx2-55)*0.5 + rnorm(1, 0, 0.05), 7, 9) tx5 <- clamp(7 + 0.99*(tx2-55)*0.5 + rnorm(1, 0, 0.05), 6, 8) tz <- clamp(1.5 + 0.4*(tx2-55)*0.5 + rnorm(1, 0, 0.05), 0.5, 2.5) # 3. 验证总和是否符合要求 total <- tx1 + tx2 + tx3 + tx4 + tx5 + tz if(abs(total - 100) <= 0.001) { count <- count +1 solutions[count,] <- c(tx1, tx2, tx3, tx4, tx5, tz) } } solutions$Somme <- rowSums(solutions) print(solutions)
内容的提问来源于stack exchange,提问作者AnonX
相关产品推荐
相关产品推荐

