【问题标题】:CVXPY constraints formulationCVXPY 约束公式
【发布时间】:2021-03-29 07:01:33
【问题描述】:

我正在尝试使用 CVXPY 解决来自 Additional Exercises for Convex Optimization 的 Stephen Boyd 的 等周问题 (7.14)。问题表述为:

约束代码如下:

constraints = [ y[1] == 0,
                y[N] == 0,
                y[F] == yfixed[F],
                cp.abs(( y[i+2] - 2 * y[i+1] + y[i]) / h**2) <= C for i in np.arange(1,199) ] #not using the first constraint here

约束有 for 循环,当我尝试根据 CVXPY 文档制定问题时,出现以下错误

语法无效

cp.abs(( y[i+2] - 2 * y[i+1] + y[i]) / h**2) <= C for i in np.arange(1,199) ]
                                                  ^

如何在 CVXPY 约束中使用循环?

【问题讨论】:

    标签: python mathematical-optimization cvxpy


    【解决方案1】:

    您需要根据cvxpyDCP 协议以矩阵向量等式和不等式的形式表达约束。 详细地说,我可以在这个问题中看到三种约束:(我将假设基于 0 的索引以方便编程以供其余答案使用。)

    yN+1维度优化变量。

    1. 定点等式约束:这些基本上将y 向量的一些索引设置为一组给定值。请注意,y[0] == 0y[N] == 0 的零边界条件也属于此范围。
    2. 周界约束:这将使用连续的差异来计算。最后,我们将 1 的 平方根 加上差的 平方sum 设置为小于L。这部分可能是按照cvxpy 协议编写的最复杂的部分。
    3. 曲率约束:这也涉及类似于上面的连续差分的计算,但这更容易编写,因为您会看到这只是一个矩阵向量乘法类型的约束,就像第一个一样。李>

    现在让我们在代码中编写约束。

    必要的进口:

    import numpy as np
    import cvxpy as cp
    import matplotlib.pyplot as plt
    from scipy.linalg import circulant
    

    1。平等约束:

    这些基本上是从y 中挑选一些索引并将它们设置为给定值。这可以按如下方式实现:

    def equality_constraints(N, F, vals):
        '''
        Sets some indices (F) in the y vector to given values. Also sets 
        y[0] == 0 and y[N] == 0.
        Returns E (a matrix) and e (a vector) such that E @ y == e.
        '''
        E = np.zeros((F.shape[0]+2, N+1)) # '+2' for selecting y[0] and y[N] also
        e = np.zeros(F.shape[0]+2)
        
        E[0, 0] = 1
        E[-1, -1] = 1
        if F.shape[0]:
            E[1:-1:1][np.arange(F.shape[0]), F] = 1
            e[1:-1:1] = vals
        return E, e
    

    E 是一个形状为(F.shape[0] + 2) x (N+1) 的二进制矩阵,它在每一行中恰好有一列设置为1,为(N+1) 维向量y 提供索引,e 包含该值y 的索引。

    2。周界约束:

    为此,我们需要y[i+1] - y[i]i = 0, 1, 2, . . . , N-1 形式的连续差异。请注意,我们可以类似地构造一个具有此N 连续差异作为其元素的向量。我们可以使用向量化计算轻松地对该向量执行平方根和其他操作。这里我们构造了一个N x (N+1)矩阵M,乘以y将得到N的差异。

    def length_matrix(N):
        '''
        Returns L with [-1, 1, 0, . . . , 0] as first row and sliding it
        to the right to get the following rows.
        '''
        val = np.array([-1, 1])
        offsets = np.array([0, 1])
        col0 = np.zeros(N+1)
        col0[offsets] = val
        
        M = circulant(col0).T[:-(len(val) - 1)]
        return M
    

    矩阵M 将是一个circulant 矩阵。我只是将其转置并删除了最后一行以获得所需的矩阵。您可以查看此post 以了解如何创建一个这样的矩阵。 M 看起来像这样:

     array([[-1.,  1.,  0., ...,  0.,  0.,  0.],
            [ 0., -1.,  1., ...,  0.,  0.,  0.],
            [ 0.,  0., -1., ...,  0.,  0.,  0.],
            ...,
            [ 0.,  0.,  0., ...,  1.,  0.,  0.],
            [ 0.,  0.,  0., ..., -1.,  1.,  0.],
            [ 0.,  0.,  0., ...,  0., -1.,  1.]])
    

    3。曲率约束:

    与上一个完全相同的矩阵计算。只需重复并沿行滑动[1, -2, 1]

    def curvature_constraints(N, C, h):
        '''
        Returns D and C_vec to be used as D @ y <= C and D @ y >= -C 
        as curvature constraints.
        '''
        val = np.array([1, -2, 1])
        offsets = np.array([0, 1, 2])
        col0 = np.zeros(N+1)
        col0[offsets] = val
        
        D = circulant(col0).T[:-(len(val) - 1)]
        D /= h**2
        C_vec = np.ones(D.shape[0]) * C
        return D, C_vec
    

    我在矩阵本身中除以h**2

    示例:

    我从本书本身的站点中获取了这个示例。数据也可通过here获取。

    L = 1.5
    a = 1
    C = 15
    N = 200
    h = a/N
    
    F = np.array([20,40,140,180]) # fixed points
    vals = np.array([0.1, 0.15, 0.15, 0.2])
    
    # Declare an array for plotting purposes
    yfixed = np.zeros(N+1)
    yfixed[F] = vals
    
    x = np.linspace(0, a, N+1)
    

    问题形成与解决方案:

    我留给您了解我是如何组装矩阵来制定约束的,尤其是周长。这并不难,但可能需要您进行一些练习,具体取决于您对矢量化的熟悉程度。 DCP 页面是一个非常好的起点。

    y = cp.Variable(N+1)
    
    E, e = equality_constraints(N, F, vals)
    M = length_matrix(N)
    D, d = curvature_constraints(N, C, h)
    
    constraints = [
        E @ y == e,
        h * cp.sum(cp.norm(cp.vstack([(M @ y)/h, np.ones(N)]), p = 2, axis = 0)) <= L,
        D @ y <= d,
        D @ y >= -d
    ]
    
    objective_function = h * cp.sum(y)
    objective = cp.Maximize(objective_function)
    
    problem = cp.Problem(objective, constraints)
    problem.solve()
    
    plt.plot(0, 0, 'ko')
    plt.plot(a, 0, 'ko')
    for i in F:
        plt.plot(x[i], yfixed[i], 'bo')
    
    plt.plot(x, y.value) # y.value gives the value of the cp Variable
    plt.savefig('curve.png')
    

    对于上述示例,我得到的答案是0.1594237500556726,曲线如下所示:

    我已经用其他几个人为的测试用例检查了这个解决方案以验证正确性。但是,可能还有其他更有效的解决方案以不同的方式来表述这个问题,或者这里甚至可能出现一些意想不到或令人尴尬的错误!如果有任何错误或您发现答案中有任何难以理解的地方,请随时告诉我。

    【讨论】:

    • 感谢您的精彩解释。当谈到曲率规则时,我发现 DCP 有点令人困惑。你能为此提出一些建议吗?
    • 我认为 Stephen Boyd 的凸优化讲座足以让您有一个基本的整体理解。之后,你用 cvxpy 解决的问题越多,你就会发现越多的技巧和公式。也可以好好学习一下cvxpy的教程页面,对基础问题很有帮助!
    • @swag2198 那本书有两位作者。
    【解决方案2】:

    尝试一分为二:

    constraints = [ y[1] == 0,
                    y[N] == 0,
                    y[F] == yfixed[F] ] +
                  [ cp.abs(( y[i+2] - 2 * y[i+1] + y[i]) / h**2) <= C for i in np.arange(1,199) ]
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多