面向对象的凸优化
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/``目录。