列生成算法在电信网络中的虚拟网络功能编排问题中的应用示例
题目描述
假设有一个电信服务提供商,需要为客户提供虚拟网络功能链服务。给定一个物理网络,表示为有向图 \(G = (V, E)\) ,其中每条边 \(e \in E\) 有一个带宽容量 \(c(e)\) 。现在有 \(K\) 个服务请求(也称服务功能链请求)。每个请求 \(k\) 由以下要素定义:
- 源节点 \(s_k\) 和目的节点 \(t_k\) 。
- 带宽需求 \(d_k\) 。
- 功能链:一个有序的虚拟网络功能序列 \((f_1^k, f_2^k, ..., f_{n_k}^k)\) 。
- 放置约束:每个虚拟网络功能 \(f_i^k\) 必须被放置在一个满足其计算资源需求的候选物理节点集合 \(V_i^k \subseteq V\) 上,且对于同一个请求 \(k\),其功能必须按照顺序放置在不同的物理节点上(即功能不能共置)。
- 目标:接受并路由一部分请求,在满足物理链路带宽容量和节点计算资源容量的约束下,最大化被接受请求的总权重(或总收益),假设每个请求 \(k\) 的收益为 \(w_k\) 。
这是一个复杂的组合优化问题,是网络功能虚拟化中的关键问题。我们将使用列生成算法来求解其线性规划松弛,以获取高质量的解或上界。
解题过程
1. 问题建模与分解
直接为每个请求枚举所有可能的“路径与功能放置”组合(即从 \(s_k\) 到 \(t_k\) 的一条路径,并为路径上的每一个“跳”指定放置哪个功能)是指数级的。列生成非常适合处理这种“从大量可能列(配置)中选择一部分”的问题。
- 主问题 (Master Problem, MP):决定接受哪些“配置”,并分配资源。
- 对于每个请求 \(k\),定义其所有可能的有效配置的集合为 \(P_k\)。一个配置 \(p \in P_k\) 指定了:
- 从 \(s_k\) 到 \(t_k\) 的一条物理路径。
- 在该路径的中间节点上,如何有序地放置其功能链 \((f_1^k, ..., f_{n_k}^k)\) 。
- 决策变量:\(y_{kp} \in \{0, 1\}\),如果请求 \(k\) 使用配置 \(p\) 被接受,则为1,否则为0。在线性规划松弛中,我们允许 \(0 \leq y_{kp} \leq 1\)。
- 目标:最大化总收益。\(\max \sum_{k=1}^{K} \sum_{p \in P_k} w_k y_{kp}\)。
- 约束:
- 每个请求至多一个配置:\(\sum_{p \in P_k} y_{kp} \leq 1, \quad \forall k\)。(每个请求最多被服务一次)。
- 链路带宽容量:对于每条物理边 \(e \in E\),所有请求使用的所有配置中,经过该边的流量总和不能超过其容量。
\(\sum_{k=1}^{K} \sum_{p \in P_k} a_{kp}^e d_k y_{kp} \leq c(e), \quad \forall e \in E\)。
其中 \(a_{kp}^e\) 是指示系数,如果配置 \(p\) 为请求 \(k\) 使用的路径包含了边 \(e\),则为1,否则为0。 - 节点计算资源容量(简化模型):假设每个节点 \(v\) 有总的计算资源 \(C(v)\),每个功能 \(f_i^k\) 放置到节点 \(v\) 上消耗计算资源 \(r_{i,v}^k\)。
\(\sum_{k=1}^{K} \sum_{p \in P_k} b_{kp}^v y_{kp} \leq C(v), \quad \forall v \in V\)。
其中 \(b_{kp}^v\) 是配置 \(p\) 在节点 \(v\) 上放置的所有功能消耗的计算资源总和。
- 对于每个请求 \(k\),定义其所有可能的有效配置的集合为 \(P_k\)。一个配置 \(p \in P_k\) 指定了:
主问题的变量数(即所有 \(|P_k|\) 之和)是天文数字,无法显式列出。这就是列生成发挥作用的地方。
2. 列生成算法框架
我们只初始化主问题的一个小子集(称为限制主问题,RMP)的列(配置),然后迭代地:
a. 求解当前RMP的线性规划松弛,得到对偶变量的值。
b. 为每个请求 \(k\) ,利用对偶变量构造一个定价子问题。求解子问题的目标是:为请求 \(k\) 找到一个“新配置”(即一条带功能放置的路径),其检验数(Reduced Cost)为负。这等价于寻找一个能“获利”的新列加入RMP。
c. 如果所有请求的子问题都找不到检验数为负的新配置,则当前RMP的解就是原主问题线性规划松弛的最优解。否则,将找到的负检验数配置作为新列加入RMP,重复步骤a。
3. 定价子问题详解
假设我们求解了当前的RMP,得到了最优的对偶变量:
- \(\alpha_k \geq 0\):对应每个请求的“至多一个配置”约束。
- \(\beta_e \geq 0\):对应每条边 \(e\) 的带宽容量约束。
- \(\gamma_v \geq 0\):对应每个节点 \(v\) 的计算资源容量约束。
现在,对于某个特定的请求 \(k\),我们想为它生成一个新配置 \(p\)。
- 新配置 \(p\) 在目标函数中的系数:\(w_k\)。
- 新配置 \(p\) 在约束中的系数:
- 在“至多一个配置”约束中系数为1。
- 在边 \(e\) 的容量约束中系数为 \(a_{kp}^e d_k\)。
- 在节点 \(v\) 的计算容量约束中系数为 \(b_{kp}^v\)。
- 新配置 \(p\) 的检验数为:
\[ \bar{c}_{kp} = w_k - \alpha_k \cdot 1 - \sum_{e \in E} \beta_e \cdot (a_{kp}^e d_k) - \sum_{v \in V} \gamma_v \cdot b_{kp}^v \]
在单纯形法中,要找到能进基的变量(即加入RMP能改善目标函数的列),就需要找到检验数为负的列。即我们需要找到:
\[ \bar{c}_{kp} = (w_k - \alpha_k) - d_k \sum_{e \in p} \beta_e - \sum_{\text{v在p上放置了功能}} \gamma_v \cdot r_{\text{功能},v}^k < 0 \]
这里我们做了简化,$ b_{kp}^v $ 是放置在节点 $ v $ 上所有功能资源消耗的和 $ \sum r_{\text{功能},v}^k $。
因此,为请求 \(k\) 寻找负检验数配置的定价子问题,转化为一个图上的最短路径/资源受限最短路径问题:
- 构建扩展图:为请求 \(k\) 构建一个分层图(Layered Graph)。
- 第0层:源节点 \(s_k\)。
- 第 \(i\) 层(\(1 \le i \le n_k\)):放置第 \(i\) 个功能 \(f_i^k\) 的所有候选物理节点 \(v \in V_i^k\) 的副本。
- 第 \(n_k + 1\) 层:目的节点 \(t_k\)。
- 边与成本:
- 从 \(s_k\) 到第一层节点 \(v_1\):边的权重为 \(d_k \cdot \text{SP}_{\beta}(s_k, v_1) + \gamma_{v_1} \cdot r_{1,v_1}^k\)。其中 \(\text{SP}_{\beta}(s_k, v_1)\) 是在原图 \(G\) 上,以 \(\beta_e\) 作为边权重,从 \(s_k\) 到 \(v_1\) 的最短路径长度。这体现了路由的“对偶成本”和第一个功能的放置成本。
- 从第 \(i\) 层的节点 \(v_i\) 到第 \(i+1\) 层的节点 \(v_{i+1}\) :边的权重为 \(d_k \cdot \text{SP}_{\beta}(v_i, v_{i+1}) + \gamma_{v_{i+1}} \cdot r_{i+1, v_{i+1}}^k\)。
- 从第 \(n_k\) 层的节点 \(v_{n_k}\) 到 \(t_k\):边的权重为 \(d_k \cdot \text{SP}_{\beta}(v_{n_k}, t_k)\)。
- 子问题目标:在这个分层图上,找到从 \(s_k\)(第0层)到 \(t_k\)(第 \(n_k+1\) 层)的一条路径。这条路径对应于一个完整的配置 \(p\):路径经过的各层节点决定了功能的放置位置,路径中连接各层节点的最短路径片段决定了实际的数据路由。
- 路径的总权重 = \(d_k \sum_{e \in p} \beta_e + \sum_{\text{v在p上放置了功能}} \gamma_v \cdot r_{\text{功能},v}^k\)。
- 检验数判断:比较 \(w_k - \alpha_k\) 与找到的路径总权重。如果路径总权重 > \(w_k - \alpha_k\),则检验数 \(\bar{c}_{kp} < 0\),我们找到了一个可以加入RMP的有利可图的配置。这条路径的详细信息(经过的边和节点)就构成了新的一列。
4. 算法步骤总结
- 初始化:为每个请求 \(k\) 生成一个或多个简单的可行配置(例如,最短路径,随机可行放置)加入RMP。确保RMP是可行的(有解)。
- 循环:
a. 求解RMP:求解当前限制主问题的线性规划松弛,得到最优解 \(y^*\) 和对应的对偶变量 \(\alpha^*, \beta^*, \gamma^*\)。
b. 定价:对于每个请求 \(k\):
* 利用对偶变量 \(\beta^*, \gamma^*\) 构建其分层图,并赋予边权重。
* 在分层图上,运行最短路径算法(如Dijkstra算法,如果图无负环;如果边权可能有负,则用Bellman-Ford)。
* 设找到的最短路径权重为 \(L_k\)。
* 如果 \(L_k < w_k - \alpha_k^*\),则该路径对应的配置检验数为负,将其加入RMP(添加新变量 \(y_{kp}\) 及它在各约束中对应的系数)。
c. 终止判断:如果遍历所有请求 \(k\),都没有找到检验数为负的新配置,则算法终止。当前RMP的解就是原问题线性规划松弛的最优解。否则,返回步骤2a。
5. 后续处理
得到线性规划松弛的最优解和最优值后:
- 上界:这个最优值就是原整数规划问题的上界。
- 启发式构造可行解:可以利用RMP的解进行舍入或启发式搜索,构造一个可行的整数解(实际接受哪些请求,使用何种配置)。例如,可以按 \(y_{kp}^*\) 值从大到小处理请求,尝试按分数解中最优的配置来接受请求,如果资源冲突则拒绝或调整。
- 分支定价:如果需要精确最优解,可以将此列生成过程嵌入到分支定界框架中,形成分支定价算法。在分支定界树的每个节点,都使用列生成求解线性规划松弛。
这个示例展示了列生成如何将一个复杂的、变量数极多的网络功能编排问题,分解为一个主问题和一系列独立的、结构良好的最短路径子问题,从而高效地求解其线性规划松弛。