当前位置:   article > 正文

python实现分支定界算法求解整数规划问题_分支定界法python

分支定界法python

 

一、构建函数

1.对整数规划模型松弛并求解,若解全部为整数,则直接返回,若不全为整数,则找到第一个不为整数的解及对应的变量;

2.对找到的解进行上下取整,分别作为索引对应的变量的新约束条件的上下界。

3.更新约束条件,并递归调用该求解整数规划模型的函数。得到较小区间和较大区间上的可行解。

4.比较两个区间的可行解得到的目标函数值的大小,返回所需可行解。

二、取一个包含7个变量10个约束条件的整数规划例子

目标函数:

Max z = x1 + 2x2 + 3x3 + x4 + 2x5 + x6 + 3x7

约束条件:

x1 + x2 + x3 <= 30

2x4 + x5 + x6 <= 20

x2 + 2x3 + x7 <= 25

x1 – x2 + x3 <= 10

x4 + x5 – 2x6 <= 5

x1 + x3 + x5 + x7 <=40

x2 + x4 + x6 <= 30

x3 + x5 + x7 <= 35

x1 + x4 + x7 <= 25

2x1 + x2 + x6 <= 15

所有变量都是非负的

以下为转换为矩阵形式:

三 、将分支定界算法求得的整数规划解与松弛线性规划的解进行比较。

可以得到整数规划的解相对于松弛线性规划的解要差一些或一样(当松弛线性规划求解直接得到整数解的情况下)的结论。

四、完整代码

可根据需要更改目标函数和约束条件,参数Aeq和beq是等式约束条件。值得一提的是linprog函数默认求解最小值,若要求解最大值则需将目标函数系数c乘以负一。分支定界算法原理可到其他文章学习。

  1. from scipy.optimize import linprog
  2. import numpy as np
  3. #自定义分支定界算法函数
  4. def branch_and_bound(c, A, b, Aeq=None, beq=None, bounds=None):
  5. # 默认变量非负
  6. if bounds is None:
  7. bounds = [(0, None) for _ in range(len(c))]
  8. # 调用函数求解线性规划问题
  9. res = linprog(c, A_ub=A, b_ub=b, A_eq=Aeq, b_eq=beq, bounds=bounds, method='highs')
  10. # 如果线性规划无解,则返回None
  11. if not res.success:
  12. return None
  13. # 检查是否所有变量都是整数
  14. if all(np.isclose(np.round(res.x), res.x)):
  15. return res.x # 如果是,返回结果
  16. # 选择第一个非整数变量进行分支
  17. # 变量的索引,即位置
  18. non_int_index = next(i for i, x in enumerate(res.x) if not np.isclose(x, np.round(x)))
  19. # 变量的值
  20. non_int_value = res.x[non_int_index]
  21. # 创建新的约束条件
  22. # 初始化新的两个约束条件,这里需要使用copy方法复制原有约束条件,以便后面更新约束条件的时候不会互相影响
  23. lower_bound = bounds.copy()
  24. upper_bound = bounds.copy()
  25. # 通过遍历找到我们刚刚选择的第一个非整数变量,对它的约束条件进行更新,即将非整数解进行上下取整,分别作为两个新区间的上下界
  26. for i, (l,u) in enumerate(bounds):
  27. if i == non_int_index:
  28. #向下取整作为较小区间的上界
  29. u1 = np.floor(non_int_value)
  30. lower_bound[i] = (l,u1)
  31. for i, (l,u) in enumerate(bounds):
  32. if i == non_int_index:
  33. #向上取整作为较大区间的下界
  34. l1 = np.ceil(non_int_value)
  35. upper_bound[i] = (l1,u)
  36. # 对两个新区间分别递归调用分支定界算法
  37. lower_res = branch_and_bound(c, A, b, Aeq, beq, bounds=lower_bound)
  38. upper_res = branch_and_bound(c, A, b, Aeq, beq, bounds=upper_bound)
  39. # 选择最优解
  40. if lower_res is not None and upper_res is not None:
  41. #解与系数点乘,返回较小的解。由于在求解最大值时对系数乘了-1,所以这里选择较小值的解。
  42. return lower_res if c @ lower_res <= c @ upper_res else upper_res
  43. elif lower_res is not None:
  44. return lower_res
  45. elif upper_res is not None:
  46. return upper_res
  47. else:
  48. return None
  49. # 以下为随机选取的一个可求解且松弛优化下解不全为整数的例子
  50. # 目标函数系数
  51. c = [-1, -2, -3, -1, -2, -1, -3]
  52. # 不等式约束的系数矩阵
  53. A = [
  54. [1, 1, 1, 0, 0, 0, 0],
  55. [0, 0, 0, 2, 1, 1, 0],
  56. [0, 1, 2, 0, 0, 0, 1],
  57. [1, -1, 1, 0, 0, 0, 0],
  58. [0, 0, 0, 1, 1, -2, 0],
  59. [1, 0, 1, 0, 1, 0, 1],
  60. [0, 1, 0, 1, 0, 1, 0],
  61. [0, 0, 1, 0, 1, 0, 1],
  62. [1, 0, 0, 1, 0, 0, 1],
  63. [2, 1, 0, 0, 0, 1, 0]
  64. ]
  65. # 不等式约束的右侧值
  66. b = [30, 20, 25, 10, 5, 40, 30, 35, 25, 15]
  67. # 将分支定界算法求解的整数规划的解与松弛线性规划的解对比
  68. # 调用分支定界算法并输出结果
  69. solution = branch_and_bound(c, A, b)
  70. print("整数规划最优解:{0},目标函数值:{1}".format(solution, -(c @ solution)))
  71. # 求解松弛线性规划
  72. result = linprog(c, A_ub=A, b_ub=b, bounds=None, method='highs')
  73. # 输出结果
  74. if result.success:
  75. print("松弛线性规划最优解:{0},目标函数值:{1}".format(result.x,-(c@result.x)) )
  76. else:
  77. print("无解")

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/空白诗007/article/detail/938539
推荐阅读
相关标签
  

闽ICP备14008679号