面向对象的凸优化

CVXPY可以通过面向对象的方法来构建优化问题。与在矩阵中嵌入信息的传统方法相比,面向对象的方法更简单灵活。

考虑具有N个节点和E个边的最大流问题。我们可以通过构造一个N乘E的入射矩阵A来明确定义问题。如果边j进入节点i,则A[i, j]为+1;如果边j离开节点i,则为-1;否则为0。源和汇位于最后两个边上。问题变成了:

# A是入射矩阵。
# c是边容量的向量。
flows = Variable(E-2)
source = Variable()
sink = Variable()
p = Problem(Maximize(source),
              [A*hstack([flows,source,sink]) == 0,
               0 <= flows,
               flows <= c])

然而,描述最大流问题的更自然的方式不是使用入射矩阵,而是使用边和节点的属性。我们可以编写一个`Edge`类来捕捉这些属性。

class Edge(object):
    """一个容量有限的无向边。"""
    def __init__(self, capacity):
        self.capacity = capacity
        self.flow = Variable()

    #通过该边连接两个节点。
    def connect(self, in_node, out_node):
        in_node.edge_flows.append(-self.flow)
        out_node.edge_flows.append(self.flow)

    #返回边的内部约束。
    def constraints(self):
        return [abs(self.flow) <= self.capacity]

`Edge`类公开了流入和流出边的流量。容量约束存储在`Edge`对象中。图的结构也通过为每个边调用`edge.connect(node1, node2)`来存储在本地。

我们还定义了一个`Node`类:.. code:: python

class Node(object):

“”” 一个带有累积量的节点。 “”” def __init__(self, accumulation=0):

self.accumulation = accumulation self.edge_flows = []

# 返回节点的内部约束条件。 def constraints(self):

return [sum(f for f in self.edge_flows) == self.accumulation]

节点有一个累积流量的目标。源节点和汇节点是其累积目标的变量。

假设``nodes``是所有节点的列表,``edges``是所有边的列表,``sink``是汇节点。问题变为:

constraints = []
for obj in nodes + edges:
    constraints += obj.constraints()
prob = Problem(Maximize(sink.accumulation), constraints)

请注意,问题从最大化沿源边的流量转变为最大化汇节点的累积量。我们可以很容易地扩展``Edge``和``Node``类来建模电网。汇节点将是消费者。源节点将是发电站,以一定成本发电。一个节点既可以是源节点也可以是汇节点,这代表能源储存设施或为电网做贡献的消费者。我们可以在边上增加能量损耗以更准确地模拟输电线路。整个电网结构可以嵌入到时间序列模型中。

要查看在更复杂的流量问题中应用面向对象方法,请查看``cvxpy/examples/flows/``目录。