理论部分详细内容见https://blog.csdn.net/yusijinfs/article/details/127292028?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22127292028%22%2C%22source%22%3A%22yusijinfs%22%7D
记 P \mathcal{P} P 为一 n n n 维多面体. 一个 0-1 规划问题为:
max { F ( x ) : x ∈ P ∩ { 0 , 1 } n } \max\{F(x): ~~~x\in\mathcal{P}\cap\{0,1\}^n\} max{F(x): x∈P∩{0,1}n}
其中, F ( x ) F(x) F(x) 为目标函数, P \mathcal P P 为约束条件.
则, 存在 pipage rounding 的方法,使: 给定任意的分数向量 x ∈ P x\in\mathcal P x∈P, 总能找到整数向量 x int ∈ P x^{\text{int}}\in\mathcal P xint∈P, 使得 F ( x int ) ≥ F ( x ) F(x^{\text{int}})\geq F(x) F(xint)≥F(x) 成立.
记 P : = { x ∈ [ 0 , 1 ] n : ∑ j = 1 n x j = k } \mathcal P:=\{x\in[0,1]^n: \sum_{j=1}^n x_j=k\} P:={x∈[0,1]n:∑j=1nxj=k}.
假设 x x x 是 P \mathcal P P 中的非整数向量, 则至少存在两个分数坐标, 记为 x p x_p xp 和 x q x_q xq.
令 e p e_p ep 和 e q e_q eq 为 x p x_p xp 和 x q x_q xq 分量方向上的单位向量. 即 e p e_p ep 在第 p p p 个坐标为 1 1 1, 其它坐标为 0 0 0, e q e_q eq 同理.
令 v x = e p − e q v_x=e_p-e_q vx=ep−eq, 令 α x = min ( 1 − x p , x q ) \alpha_x=\min(1-x_p,x_q) αx=min(1−xp,xq), 令 β x = min ( 1 − x q , x p ) \beta_x=\min(1-x_q,x_p) βx=min(1−xq,xp).
则 x + α x v x x+\alpha_x v_x x+αxvx 和 x − β x v x x-\beta_x v_x x−βxvx 总是能在第 p p p 和 q q q 分量上取整数, 且由于 F ( x ) F(x) F(x) 在 v x v_x vx 是凸的, 则必有 F ( x + α x v x ) ≥ F ( x ) F(x+\alpha_x v_x)\geq F(x) F(x+αxvx)≥F(x) 和 F ( x − β x v x ) ≥ F ( x ) F(x-\beta_x v_x)\geq F(x) F(x−βxvx)≥F(x) 成立.
Step 1: 给定非整数点 x x x, 选择一个尽量小的 tight 的集合 T T T. 注意, x x x 至少有两个非整数点 0 < x ( e ) < 1 , 0 < x ( f ) < 1 0
Step 2: 过点 x x x 画一条直线, 记往 x ( e ) x(e) x(e) 递增方向为 + 1 +1 +1, 往 x ( f ) x(f) x(f) 递增方向为 − 1 -1 −1. 保持 x ( e ) + x ( f ) x(e)+x(f) x(e)+x(f) 不变, 随机地在该直线上移动, 直到碰到多面体的表面.
记 x 1 x_1 x1 和 x 2 x_2 x2 分别为直线在 + 1 +1 +1 和 − 1 -1 −1 方向上与拟阵多面体的交点, 我们以概率 p p p 从 x x x 到达 x 1 x_1 x1, 以概率 1 − p 1-p 1−p 从 x x x 到达 x 2 x_2 x2. p p p 取 p x 1 + ( 1 − p ) x 2 = x px_1+(1-p)x_2=x px1+(1−p)x2=x 的解.
这一做法得到得到一个 tight 的集合 S S S.
Step 3: 令 x ← x 1 x\gets x_1 x←x1 (或 x 2 x_2 x2), T ← S ∩ T T\gets S\cap T T←S∩T, 重复 Step 1, 直到 x x x 为整数点.
算法至多需要 ∣ E ∣ ⋅ r M ( E ) |E|\cdot r_M(E) ∣E∣⋅rM(E) 次迭代.
import numpy as np
def pipage_rounding(x):
x = np.array(x)
n = len(x)
satisfy = np.zeros(n,dtype=np.bool8)
for i in range(n-1):
idx = np.random.choice(np.where(satisfy==False)[0],2,replace=False)
x_select = x[idx]
a,b = x_select
if a + b <= 1:
if np.random.uniform()< (a/(a+b)):
x[idx[0]] += x[idx[1]]
x[idx[1]] = 0
satisfy[idx[1]]=True
else:
x[idx[1]] += x[idx[0]]
x[idx[0]] = 0
satisfy[idx[0]]=True
else:
if np.random.uniform()< ((1-a)/(2-a-b)):
x[idx[0]] -= 1-x[idx[1]]
x[idx[1]] = 1
satisfy[idx[1]]=True
else:
x[idx[1]] -= 1-x[idx[0]]
x[idx[0]] = 1
satisfy[idx[0]]=True
return (x+0.01).astype(np.int32)
测试单次pipage rounding
# test
pipage_rounding([0.1,0.8,0.4,0.7]) # result: [0,1,0,1]
测试pipage rounding分布期望
epoch = 10000
x = [0.1,0.9,0.3,0.7,0.4,0.6]
cnt = np.zeros(len(x))
for i in range(epoch):
x_round = pipage_rounding(x)
cnt += x_round
cnt/epoch