用cplex约束编程完成二进制矩阵

问题描述 投票:0回答:2

我想根据一些约束条件生成一个20x38的二进制矩阵,这些约束条件是我使用dpcplex模型的。矩阵中的一些单元格是预先定义的,如下所示(行,列,参数)。

[(8,3,0),(14,0,0),(14,2,0),(16,0,0),(16,1,0),(12,0,0),(10,0,0),(10,8,0),(10,9,0),(17,7,0),(17,8,0),(8,0,0),(13,8,0),(13,9,0),(1,0,1),(15,19,0)]

我需要在其他矩阵单元格中填写一些约束条件。

  • 列数之和必须等于10
  • 行数总和必须等于19
  • 每行的最后4个单元格必须是备选单元格:只允许有1010或0101两个单元格
  • 不超过2个连续的0或1。
  • 每行5个单元格的总和必须在[2,3]范围内:没有11011或00100。
  • 连续的0对的总和必须是<=3:在每一行中,我们不允许有超过3对00和3对11。

问题是我的模型没有返回任何解决方案。我不确定我的模型是否正确。

这是我的代码。

from docplex.mp.model import Model

cond=[[8,3,0],[1,37,0],[6,9,0]]

model = Model("MatrixComple")

R = [i for i in range(20)]
R1=[i for i in range(38)]
R2=[34,35,36,37]
R3=[i for i in range(36)]
R4=[i for i in range(34)]
R5=[i for i in range(37)]
idx = [(i, j) for i in R for j in R1 ]

x = model.binary_var_dict(idx,name= "x")

"""pre-defined cells"""
for i in R:
    for j in R1:
        for item in cond:
            i1,i2,i3=item
            model.add_constraint(x[i1, i2] == i3)

"""sum of columns must be equal to 10   """    
model.add_constraints(model.sum(x[i, j] for i in R) == 10 for j in R2)

"""sum of rows must be equal to 19  """
model.add_constraints(model.sum(x[i, j] for j in R1) == 19 for i in R)

"""(apply to all rows)last 4 cells of each row must be alternative: just 1010 or 0101 is allowed"""
model.add_constraints(model.sum(x[(i, j)] for j in R2 ) == 2 for i in R  )
model.add_constraints(x[(i, 34)] ==x[(i, 36)]  for i in R  )


"""no more that 2 consecutive 0s or 1s : 110 or 001 or 101 or 010
this rule can not be applied to pre-defined cells. For example if we have 000 or 111 in pre-defined conditions,
we need to apply this rule for the rest of matrix not the pre-defined cells
""" 
model.add_constraints(model.sum(x[i, j]+x[i,j+1]+x[i,j+2] for j in R3) <=2 for i in R)
model.add_constraints(model.sum(x[i, j]+x[i,j+1]+x[i,j+2] for j in R3) >=1 for i in R)


""" (apply to all rows) sum of every 5 cells in each row must be in range [2,3] : no 11011 or 00100 is allowed """
model.add_constraints(model.sum(x[i, j]+x[i,j+1]+x[i,j+2]+x[i,j+3]+x[i,j+4]for j in R4) <=3 for i in R)
model.add_constraints(model.sum(x[i, j]+x[i,j+1]+x[i,j+2]+x[i,j+3]+x[i,j+4]for j in R4) >=2 for i in R)

""" (apply to all rows) sum of pair of consecutive 0s must be <=3 : in each row we are not allowed to have 
more than 3 pair of 00 """

for i in R:
    s=0
    for j in R5:
            if x[i, j]==x[i,j+1]==0:
                    s+=1
    model.add_constraint(s<= 3)

""" (apply to all rows) sum of pair of consecutive 1s must be <=3 : in each row we are not allowed to have 
more than 3 pair of 11 """
for i in R:
    s=0
    for j in R5:
            if x[i, j]==x[i,j+1]==1:
                    s+=1
    model.add_constraint(s<= 3)

solution = model.solve()
print(solution)
python matrix cplex constraint-programming docplex
2个回答
1
投票

我没有时间去解决整个问题,但我可以发现最后两个块(连续值约束)中的严重问题。

TypeError: Cannot use == to test expression equality, try using Python is operator or method equals: x_0_0 == x_0_1

这是有充分理由的:在DOcplex中,变量之间的'=='操作符被重载,以建立一个"=="操作符。约束,也就是模型的一个对象。这个对象没有Python真值,不能用于Python if语句中。

此外,变量 s 你所使用的不是一个DOcplex变量,所以它不能用来发布约束。

要实现你的约束,这里是Docplex中一个可能的方法:对于每个(i, j)单元,定义一个 约束当(i,j)和(i,j+1)都等于零时,满足该约束条件,并将一条线的所有约束条件存储在一个列表中。

for i in R
   twozs = [x[i,j] + x[i, j+1] == 0 for j in R5]

请注意,这些约束条件不会被添加到模型中,因为我们并不关心哪些约束条件是否满足,我们只希望满足的约束条件之和(每行)小于3。AS约束条件可以无缝转换为二进制变量,你可以将其作为普通表达式使用,我们必须添加该 金额 小于3:这意味着最多满足其中的三个约束条件。这块的完整代码是

for i in R
   twozs = [x[i,j] + x[i, j+1] == 0 for j in R5]
   model.add(model.sum(twozs) <= 3)

你可以很容易地计算出如何用类似的方式来解决第二个区块的 "两个单元格等于1 "约束条件。

然而,最后的模型并不能解决。

为了研究不可行的模型,这里有两个Docplex中的通用技巧。

  1. 给你的约束条件起个名字
  2. 使用Relaxer对象并尝试放松问题:Relaxer将放松一些约束条件,并告诉你他必须放松哪些约束条件才能达到可行的解决方案。
    solution = model.solve()
    if solution is None:
        from docplex.mp.relaxer import Relaxer
        rx = Relaxer()
        rs = rx.relax(model)
        rx.print_information()

希望这对你有帮助


1
投票

我发现了是什么使得这个模型不可能:约束条件 "不超过两个连续的0或1 "是不正确的(关于5个连续单元格的约束也是不正确的.你不应该在整行中求和,而应该在每个单元格中锅一个范围。

"""no more that 2 consecutive 0s or 1s : 110 or 001 or 101 or 010
this rule can not be applied to pre-defined cells. For example if we have 000 or 111 in pre-defined conditions,
we need to apply this rule for the rest of matrix not the pre-defined cells
"""
for i in R:
    for j in R3:
        s3ij = x[i, j]+x[i,j+1]+x[i,j+2]
        model.add_range(1, s3ij, 2, f"range3_{i}_{j}")

同样,关于五个连续单元格的约束也可以写成。

for i in R:
for j in R4:
    s5ij = x[i, j]+x[i,j+1]+x[i,j+2] +x[i,j+3] +x[i,j+4]
    model.add_range(2, s5ij, 3, f"range5_{i}_{j}")

通过这些修改,模型变得可行了。

希望这能帮助你。

Philippe.


0
投票

"不超过3个连续的1 0r 0 "约束的修正代码。

for i in r_rows:
    all_consecs = (x[i,j] == x[i,j+1] for j in range(n_cols-1))
    model.add(model.sum(all_consecs) <= 2, f"no_more_than_2_consecs_{i}")

这里主要的兴趣点是逻辑约束如何作为表达式使用.一个逻辑约束可以是真或假,它的真值实际上存储在一个隐藏的二进制变量中,它可以在表达式中自由使用(如这里的Model.sum())

© www.soinside.com 2019 - 2024. All rights reserved.