线性规划:在变量偏离最优值时添加惩罚,但单一数值除外。

huangapple go评论82阅读模式
英文:

Linear Programming: Add penalty as variable diverge from optimal value, with single value exception

问题

我试图在我的线性规划项目中引入一个惩罚约束,求解器正在寻找x的最优值(整数值),在其他约束条件中,我希望当x偏离最优值时,对x进行惩罚。

我将这个约束添加为:

  1. self.prob += x - optimal_size <= _SP
  2. self.prob += x - optimal_size >= -_SP

将_SP添加到我的目标函数作为惩罚:

  1. objective += other_values - 0.1 * SP

在这种情况下,optimal_size等于3,但我也希望在x等于0时不应用这个惩罚。你有什么建议可以实现这一点的好方法吗?

英文:

I am trying to have a penalty constraint in my LP project, the solver is looking for an optimal value of x (integer value), among other constraints, I want x to be penalized the more it diverges from an optimal value.

I added this constraint as

  1. self.prob += x - optimal_size &lt;= _SP
  2. self.prob += x - optimal_size &gt;= -_SP

Adding _SP as penalty to my objective function

  1. objective += other_values - 0.1 * SP

In this case, optimal_size is == 3, but I'd also like however that this penalty would not be applied if x == 0. Do you have a suggestion on what would be a nice way to do it?

答案1

得分: 0

我的方法如下:

  1. 计算xoptimal_x_fixed的偏差,存储在变量divergence_x_from_fixed_raw
  2. 取上述偏差的绝对值,存储在变量divergence_x_from_fixed_absolute
  3. 创建一个布尔变量:impose_penalty_bool,以突出以下情况:
    • 如果x == 0 => impose_penalty_bool == 0
    • 如果x >= 1 => impose_penalty_bool == 1
  4. 创建一个整数变量final_penalty_value,以存储impose_penalty_booldivergence_x_from_fixed_absolute的乘积
  5. 根据第4步的效果:
    • 如果x == 0 => impose_penalty_bool == 0 => final_penalty_value == 0
    • 如果x == optimal_x_fixed => impose_penalty_bool == 1 => final_penalty_value == 0(因为偏差的绝对值等于0)
    • 如果x != 0 且偏差的绝对值 > 0 => impose_penalty_bool = 1 => final_penalty_value > 0

我已经使用Google OR-Tools的线性求解器实现了上述逻辑,但以下实现也适用于任何其他线性求解器:

  1. from ortools.linear_solver import pywraplp
  2. solver = pywraplp.Solver("penalty_obj", pywraplp.Solver.SCIP_MIXED_INTEGER_PROGRAMMING)
  3. # 以下值在给定迭代中是固定的,但可以在后续运行中更改
  4. optimal_x_fixed = 3
  5. # 决策变量
  6. x = solver.IntVar(lb=-10, ub=10, name="x")
  7. # 由于我们(我)不知道目标函数,为了测试逻辑,我固定了x的值
  8. x.SetBounds(lb=3, ub=3)
  9. # 绝对值是非线性函数,我们需要线性化它
  10. # ------------------- 步骤 1 和 2,开始 ----------------------#
  11. # 在这里,我们计算“x”与“optimal_x_fixed”之间的偏差
  12. divergence_x_from_fixed_raw = solver.IntVar(lb=-20, ub=20, name="divergence_raw")
  13. solver.Add(divergence_x_from_fixed_raw == optimal_x_fixed - x)
  14. # 创建一个变量,它将存储偏差的绝对值
  15. divergence_x_from_fixed_absolute = solver.IntVar(lb=0, ub=20, name="divergence_abs")
  16. # 创建正部分和负部分
  17. # 思路是在任何时候只有一个部分可以具有非零值
  18. divergence_x_from_fixed_pos = solver.IntVar(lb=0, ub=20, name="divergence_pos")
  19. divergence_x_from_fixed_neg = solver.IntVar(lb=0, ub=20, name="divergence_neg")
  20. divergence_x_binary = solver.BoolVar("")
  21. solver.Add(divergence_x_from_fixed_raw == divergence_x_from_fixed_pos - divergence_x_from_fixed_neg)
  22. # 以下约束确保只有正部分或负部分可以具有非零值
  23. # 100 是大M(大的正数)
  24. solver.Add(divergence_x_from_fixed_pos <= 100 * divergence_x_binary)
  25. solver.Add(divergence_x_from_fixed_neg <= 100 * (1 - divergence_x_binary))
  26. solver.Add(divergence_x_from_fixed_absolute == divergence_x_from_fixed_pos + divergence_x_from_fixed_neg)
  27. # ------------------- 步骤 1 和 2,结束 ----------------------#
  28. # ------------------- 步骤 3,开始 ----------------------#
  29. # 接下来,我们要创建一个布尔变量:“impose_penalty_bool”
  30. # 我们希望的是,如果 x == 0,则 impose_penalty_bool == 0:
  31. # 如果 x >= 1,则 mpose_penalty_bool == 1
  32. # 但是,如果 x == 3,那么我们也不希望有任何惩罚,
  33. # 这将解决下一个问题
  34. impose_penalty_bool = solver.BoolVar("")
  35. # 100 是 x 的上界
  36. # 以下 2 个约束实现了:
  37. # 如果 x == 0,则 impose_penalty_bool == 0:
  38. # 如果 x >= 1,则 mpose_penalty_bool == 1
  39. solver.Add(x - (100 * impose_penalty_bool) <= 0)
  40. solver.Add(x - impose_penalty_bool >= 0)
  41. # ------------------- 步骤 3,结束 ----------------------#
  42. # ------------------- 步骤 4,开始 ----------------------#
  43. # 最后,我们要做的是将“impose_penalty_bool”与之前计算的“optimal_x_fixed = 3”的偏差的绝对值相乘
  44. # 效果将是:
  45. # 如果 x == 0 => impose_penalty_bool == 0 => final_penalty_value == 0
  46. # 如果 x == optimal_x_fixed => impose_penalty_bool = 1 => final_penalty_value == 0
  47. # (因为偏差的绝对值 == 0)
  48. # 如果 x != 0 且偏差的绝对值 > 0 => impose_penalty_bool = 1 => final_penalty_value > 0
  49. # 用 impose_penalty_bool 乘以 divergence_x_from_fixed_absolute
  50. final_penalty_value = solver.IntVar(lb=0, ub=20, name="final_penalty")
  51. # u 是 divergence_x_from_fixed_absolute 的上界。 u = 30(假设)
  52. solver.Add(final_penalty_value <= 30 * impose_penalty_bool)
  53. solver.Add(final_penalty_value <= divergence_x_from_fixed_absolute)
  54. solver.Add(final_penalty_value >= divergence_x_from_fixed_absolute - 30 * (1 - impose_penalty_bool))
  55. # 通过上述操作,我们线性化了二进制变量:impose_penalty_bool 和整数变量:divergence_x_from_fixed_absolute
  56. # 通常,如果 x1 是二进制变量,x2 是连续/整数变量
  57. # u 是 x2 的上界。引入一个 y 变量来保存乘积
  58. # 引入以下约束
  59. # y <= u * x1
  60. # y <= x2
  61. # y <= x2 - u * (1 - x1)
  62. # y >= 0
  63. # ------------------- 步骤 4,结束 ----------------------#
  64. # 定义目标函数
  65. obj_function = x + final_penalty_value
  66. solver.Maximize(obj_function) #
  67. <details>
  68. <summary>英文:</summary>
  69. My approach is as follows :
  70. 1) calculate the divergence of `x` from `optimal_x_fixed` in variable : `divergence_x_from_fixed_raw`
  71. 2) take the absolute of the above divergence in variable : `divergence_x_from_fixed_absolute`
  72. 3) create a boolean variable : `impose_penalty_bool` to highlight that: &lt;br /&gt;
  73. if `x == 0` =&gt; `impose_penalty_bool == 0` &lt;br /&gt;
  74. if `x &gt;= 1` =&gt; `impose_penalty_bool == 1` &lt;br /&gt;
  75. 4) create an integer variable `final_penalty_value` to store the multiplication of `impose_penalty_bool` and `divergence_x_from_fixed_absolute`
  76. 5) effect from 4) will be &lt;br /&gt;
  77. if `x == 0` =&gt; `impose_penalty_bool == 0` =&gt; `final_penalty_value == 0` &lt;br /&gt;
  78. if `x == optimal_x_fixed` =&gt; `impose_penalty_bool == 1` =&gt; `final_penalty_value == 0` (beacuse absolute of deviance == 0) &lt;br /&gt;
  79. if `x != 0` and `absolute of deviance &gt; 0` =&gt; `impose_penalty_bool = 1` =&gt; `final_penalty_value &gt; 0`
  80. I have used Google-ortool&#39;s linear solver, but below implementation can be used with any other linear solver:

from ortools.linear_solver import pywraplp

solver = pywraplp.Solver("penalty_obj",pywraplp.Solver.SCIP_MIXED_INTEGER_PROGRAMMING)

below value is fixed for a given iteration, but can be changed in subsequent run

optimal_x_fixed = 3

decision variable

x = solver.IntVar(lb = -10, ub = 10, name = "x")

since we (I) dont know the objective function, in order to test the logic,

I have fixed the value of x

x.SetBounds(lb = 3, ub = 3)

The absolute value is a non-linear function. We will have to linearise it

------------------- STEPS 1 and 2, START ----------------------#

here we calculate the divergence between "x" and the "optimal_x_fixed"

divergence_x_from_fixed_raw = solver.IntVar(lb = -20, ub = 20, name = "divergence_raw")
solver.Add(divergence_x_from_fixed_raw == optimal_x_fixed - x)

create a variable which will store the absolute value of the divergence

divergence_x_from_fixed_absolute = solver.IntVar(lb = 0, ub = 20, name = "divergence_abs")

create a positive and negative part

idea is only one of the parts can have a value other than zero at any time

divergence_x_from_fixed_pos = solver.IntVar(lb = 0, ub = 20, name = "divergence_pos")
divergence_x_from_fixed_neg = solver.IntVar(lb = 0, ub = 20, name = "divergence_neg")
divergence_x_binary = solver.BoolVar("")

solver.Add(divergence_x_from_fixed_raw == divergence_x_from_fixed_pos - divergence_x_from_fixed_neg)

below constraint ensure that only positive or negative part takes value other than zero

100 is big_M

solver.Add(divergence_x_from_fixed_pos <= 100 * divergence_x_binary)
solver.Add(divergence_x_from_fixed_neg <= 100 * (1 - divergence_x_binary))

solver.Add(divergence_x_from_fixed_absolute == divergence_x_from_fixed_pos + divergence_x_from_fixed_neg)

------------------- STEPS 1 and 2, END ----------------------#

------------------- STEPS 3, START ----------------------#

next we want to create a boolean variable : "impose_penalty_bool"

what we want is if x == 0, then impose_penalty_bool == 0

if x >= 1, then mpose_penalty_bool == 1

however, if x == 3, then also we dont want any penalty,

this will tackle next

impose_penalty_bool = solver.BoolVar("")

100 is upper bound on x

below 2 constraints achieve:

  1. # if x == 0, then impose_penalty_bool == 0:
  2. # if x &gt;= 1, then mpose_penalty_bool == 1

solver.Add(x - (100 * impose_penalty_bool) <= 0)
solver.Add(x - impose_penalty_bool >= 0)

------------------- STEPS 3, END ----------------------#

------------------- STEPS 4, START ----------------------#

finally what we want to do is multiply "impose_penalty_bool"

with the absolute of deviance from "optimal_x_fixed = 3" we calculated earlier

the effect will be:

  1. # if x == 0 =&gt; impose_penalty_bool == 0 =&gt; final_penalty_value == 0
  2. # if x == optimal_x_fixed =&gt; impose_penalty_bool = 1 =&gt; final_penalty_value == 0
  3. # (beacuse absolute of deviance == 0)
  4. # if x != 0 and absolute of deviance &gt; 0 =&gt; impose_penalty_bool = 1 =&gt; final_penalty_value &gt; 0

multiply impose_penalty_bool with divergence_x_from_fixed_absolute

final_penalty_value = solver.IntVar(lb = 0, ub = 20, name = "final_penalty")

u is the upper bound on divergence_x_from_fixed_absolute. u = 30 (say)

solver.Add(final_penalty_value <= 30 * impose_penalty_bool)
solver.Add(final_penalty_value <= divergence_x_from_fixed_absolute)
solver.Add(final_penalty_value >= divergence_x_from_fixed_absolute - 30 * (1 - impose_penalty_bool))

by doing above we linearise the product of binary : impose_penalty_bool # and the integer variable : divergence_x_from_fixed_absolute

generally, if x1 is binary, and x2 is continuous / integer

u is upper bound on x2. introduce a y variable to hold the product

impose following constraints

y <= u * x1

y <= x2

y <= x2 - u * (1 - x1)

y >= 0

------------------- STEPS 4, END ----------------------#

DEFINE OBJECTIVE FUNCTION

obj_function = x + final_penalty_value

solver.Maximize(obj_function) # or minimise, depends
solver.Solve()

solver.Objective().Value()

-----------------------------------

  1. I have checked with different values of `x`, outcome is on expected lines.
  2. final_penalty_value == 0 if x == 0 or x == 3 (equal to fixed value)
  3. for x != 3 or x != 0, final_penalty_value &gt; 0
  4. </details>

huangapple
  • 本文由 发表于 2023年6月19日 16:53:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/76505079.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定