Pipage Rounding的python代码实现

理论部分详细内容见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

Pipage Rounding

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):   xP{0,1}n}

其中, F ( x ) F(x) F(x) 为目标函数, P \mathcal P P 为约束条件.

假设:

  1. 对所有非整数的 x ∈ P x\in\mathcal P xP, 总是存在一个向量 v x v_x vx 与两个标量 α x , β x > 0 \alpha_x, \beta_x>0 αx,βx>0, 使得:
    x + α x v x x+\alpha_x v_x x+αxvx x − β x v x x-\beta_x v_x xβxvx 比起 x x x 都有严格更大数量的整数坐标.
  2. F ( x ) F(x) F(x) v x v_x vx 方向上是凸函数.

则, 存在 pipage rounding 的方法,使: 给定任意的分数向量 x ∈ P x\in\mathcal P xP, 总能找到整数向量 x int ∈ P x^{\text{int}}\in\mathcal P xintP, 使得 F ( x int ) ≥ F ( x ) F(x^{\text{int}})\geq F(x) F(xint)F(x) 成立.

Pipage Rounding 的一个例子

  • 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=epeq, 令 α x = min ⁡ ( 1 − x p , x q ) \alpha_x=\min(1-x_p,x_q) αx=min(1xp,xq), 令 β x = min ⁡ ( 1 − x q , x p ) \beta_x=\min(1-x_q,x_p) βx=min(1xq,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) 成立.

Pipage Rounding 算法

Step 1: 给定非整数点 x x x, 选择一个尽量小的 tight 的集合 T T T. 注意, x x x 至少有两个非整数点 0 < x ( e ) < 1 , 0 < x ( f ) < 1 00<x(e)<1,0<x(f)<1.

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 1p 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+(1p)x2=x 的解.

这一做法得到得到一个 tight 的集合 S S S.

Step 3: 令 x ← x 1 x\gets x_1 xx1 (或 x 2 x_2 x2), T ← S ∩ T T\gets S\cap T TST, 重复 Step 1, 直到 x x x 为整数点.

算法至多需要 ∣ E ∣ ⋅ r M ( E ) |E|\cdot r_M(E) ErM(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

你可能感兴趣的:(python,numpy)