微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 cvxpy 中指定约束时违反了 DCP 要求,可能需要重新考虑问题的整个表述 更新旁注

如何解决在 cvxpy 中指定约束时违反了 DCP 要求,可能需要重新考虑问题的整个表述 更新旁注

这是对早期 specific question 的后续,但是随着我为问题的表述增加了更多的复杂性,我意识到我需要退后一步,考虑 cvxpy 是否是解决我的问题的最佳工具.

我想要解决的问题:创建一个类别和公司的最大集群,其中平均值高于特定阈值。诀窍是,如果我们为集群中的一家公司包含特定类别,为了添加另一家公司,该公司也应该对相同类别具有较高的值。

Screenshot of dummy example

我已将其表述为整数线性优化问题,并在其中扩展了所有变量。有两个主要问题:

  1. 约束 8 违反了 DCP 规则。约束 8 旨在使集群中包含的值保持在特定阈值以上。我通过取非零变量的平均值来检查这一点。
  2. 实际问题需要指定数千个变量和约束(有 100 个类别和超过 1 万家公司)。这让我怀疑这是否是正确的方法
import numpy as np
import cvxpy as cp
import cvxopt 

util = np.array([0.7,0.95,0.3,2,1.05,2.2,4,1,3])

# The variable we are solving for
dec_vars = cp.Variable(len(util),boolean = True)

tot_util = util @ dec_vars

is_zero_bucket1= cp.Variable(1,boolean = True)
is_zero_bucket2= cp.Variable(1,boolean = True)
is_zero_bucket3= cp.Variable(1,boolean = True)

is_zero_cat1 = cp.Variable(1,boolean=True)
is_zero_cat2 = cp.Variable(1,boolean=True)
is_zero_cat3 = cp.Variable(1,boolean=True)

# at least 2 categories should be included for a given company
constr1 = sum(dec_vars[0:3]) >= 2 * is_zero_bucket1
constr2 = sum(dec_vars[3:6]) >= 2 * is_zero_bucket2
constr3 = sum(dec_vars[6:9]) >= 2 * is_zero_bucket3

# at least 2 columns (companies) for a given category that's selected
constr4 = dec_vars[0] + dec_vars[3] + dec_vars[6] >= 2 * is_zero_cat1
constr5 = dec_vars[1] + dec_vars[4] + dec_vars[7] >= 2 * is_zero_cat2
constr6 = dec_vars[2] + dec_vars[5] + dec_vars[8] >= 2 * is_zero_cat3

constr7 = np.ones(len(util)) @ dec_vars >= 2

constr8 = (tot_util/cp.sum(dec_vars)) >= 1.3

cluster_problem = cp.Problem(cp.Maximize(tot_util),[constr1,constr2,constr3,constr4,constr5,constr6,constr8])

cluster_problem.solve()

更新

我按照建议进行了修改。现在的问题是决策变量矩阵本身没有包含相邻公司/类别的规则。为此,我可以使目标函数成为最终决策 vars 矩阵与 zero_comp_vars 和 zero_cat_vars 向量的乘积。但是,执行此操作时出现 Problem does not follow DCP rules 错误。一定是因为两个矩阵乘以两个向量。另外,我想知道是否有办法让程序在决策矩阵中适当位置的变量不满足至少 2 家公司和 3 个类别为非零的标准时将其归零,以便被包括在内。就目前而言,决策变量矩阵对于实际上由 zero_comp_vars 和 zero_cat_vars 变量清零的行/列将具有 1 值

util = np.array([[0.7,0.3],[2,2.2],[4,3]])

# The variable we are solving for
dec_vars = cp.Variable(util.shape,boolean = True)

zero_comp_vars = cp.Variable(util.shape[0],boolean = True)
zero_cat_vars = cp.Variable(util.shape[1],boolean = True)

# define constraints
zero_comp_constr = cp.sum(dec_vars,axis=1) >= 2 * zero_comp_vars
zero_cat_constr = cp.sum(dec_vars,axis=0) >= 3 * zero_cat_vars
# need the following two constraints,otherwise all the values in the zero_comp_constr and zero_cat_constr vectors can be 0
above_one_non_zero_comp = cp.sum(zero_comp_vars) >= 1
above_one_non_zero_cat = cp.sum(zero_cat_vars) >= 1

# min tin array
min_comp_array=np.empty(dec_vars.shape[0])
min_comp_array.fill(2)

min_comp_constr = cp.sum(dec_vars,axis=1) >= min_comp_array
tot_avg_constr = tot_util >= 2.0 * cp.sum(dec_vars)

# this is the section that gives error
temp = cp.multiply(util,dec_vars)
temp2 = cp.multiply(temp,cp.reshape(zero_comp_vars,(3,1)))
temp3 = cp.multiply(temp2,cp.reshape(zero_cat_vars,1)))

tot_util = cp.sum(temp3)
#tot_util = cp.sum(cp.multiply(util,dec_vars))

cluster_problem = cp.Problem(cp.Maximize(tot_util),[zero_comp_constr,zero_cat_constr,above_one_non_zero_comp,above_one_non_zero_cat,min_comp_constr,tot_avg_constr])

cluster_problem.solve()

解决方法

只需转换它:

constr8 = (tot_util/cp.sum(dec_vars)) >= 1.3

->

constr8 = tot_util >= 1.3 * cp.sum(dec_vars)

您可能需要强制 cp.sum(dec_vars) 是肯定的,否则:0 >= 0 是一个有效的解决方案。

另见:lpsolve docs: Ratios

旁注

是的,您的目标是使用通用优化工具处理机器学习规模数据,这些工具会很快达到极限,即使是纯连续的情况也是如此。在您的情况下,使用离散优化,您可能会遇到可扩展性问题(听起来像 100 万个二进制变量),尤其是在仅限于开源求解器时。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。