• 哈达玛响应


    具体过程

    一、初始化方法:

    属性输入阈值的大小InputSize,输出阈值的大小OutSize,输出位的大小OutBit,隐私预算PrivacyParameters,

    这个方法中输入的值是:阈值的大小AphbetSize,隐私参数,编码精度3个参数

    InputSize=AphbetSize

    OutSize=int(math.pow(2,math.ceil(math.log(AphbetSize+1,2))))

           (上式中存在math类的三个函数,math.pow(),math.ceil(),math.log()

               math.pow(2,3)表示2的3次方,输出结果为8;math.ceil(2.1)表示去2.1向上的最大整数,输出结果为3;math.log(100,10)表示以10为底100的对数,输出结果为2。

               上式中先对阈值求2的对数,再作为次方求其值,比如AphbetSize=20,输出的结果OutSize=32,总之输出值的大小比输入的可能值要大。

           )

    OutBit=int(math.ceil(math.log(AphbetSize+1,2)))   当AphbetSize=7,输出结果OutBit=3,总之输入阈值较大时,输出位仍然会很小。

     PrivacyParameters=1/(1+math.exp(PrivacyParameters))   函数math.exp(3)表示e的3次方,得到的结果是20,PrivacyParameters最后的结果其实是某位(0或1)反转的概率。

    在编码方式中,有encode_acc=0和encode_acc=1两种,前者是精确编码,后者是快速编码。

    那么接下来要说如何利用哈达玛矩阵快速编码:

    def Hadarmard_init(k):
        H = [None] * k
        for row in range(k):
            H[row] = [True] * k
        print(H)

    这里的参数k表示OutSize输出位的大小,其实就是矩阵行数和列数都为k的方阵,矩阵的初始化阶段其实就是将一个输出位转化为了矩阵的一列。

    二:奇偶校验

        def parity_check(self,x,y): #check if the hadamard entry is one (return 0 for if the entry is 1)
            z = x&y #bit and
            z_bit = bin(z)[2:].zfill(self.outbit)
            check = 0
            for i in range(0,self.outbit): #check = sum_i (x_i y_i) (mod 2)
                check = check^int(z_bit[i]) 
            return check

    这个方法的主要作用检查哈达玛矩阵的每一项是否为1,如果为1的项返回0。

    具体分析:

    z=x&y  先传入两个整型的参数x和y,对其进行求位和&运算,&运算先将x和y转化为二进制,都为真则取真,比如5&3可以计算为0101&0011=0001=1

    z_bit=bin(z)[2:].zfill(self.outbit) ,这里的outbit就是OutSize,相对于输入的阈值其实是很小的位数。

    outbit=4
    z=2
    print(bin(z))                          #将2转化成二进制,并在之前用ob区分
    print(bin(z)[2:])                      #取二进制位
    print(bin(z)[2:].zfill(outbit))        #将二进制填充至输出位的长度
    
    输出的结果为:
    0b10
    10
    0010

    check=check^int(z_bit[i])  ^异或运算符,当对位不同输出1,相同输出0,比如输入值=101^110,结果=011

    三、编码单个符号

            bitin = bin(int(in_symbol)+1)[2:].zfill(self.outbit)
            out1 = random.randint(0,math.pow(2,self.outbit)-1) 
            bitout1 = bin(out1)[2:].zfill(self.outbit)

    bitin=bin(int(in_symbol)+1)[2:].zfill(self.outbit)

    in_symbol是输入的位,将其转化为和输出位相等的二进制字符串

    out1=random.randint(0,math.pow(2,self.outbit)-1)

    在可能的输出大小中随机选择一位OutSize

    bitout1=bin(out1)[2:].zfill(self.outbit)

    将随机取中的这一位转换为和输出位相等的二进制字符串

            for i in range(0,self.outbit):
                if int(bitin[i]) == 1:
                    out2 = out1 ^ (pow(2,self.outbit - i -1))
                    break

    对Out1再进行扰动,对于输入二进制串的最左边的1进行扰动  out2=out1^(pow(2,self.outbit-i-1))

    这一步骤相当于在可能输出值中随机抽取一位,对这一位再进行确定性的扰动,得到可能潜在的输出。

        if self.ifencode_acc == 1:
                check = 1 - self.H[int(in_symbol)+1][out1]
            else:
                check = 0
                for i in range(0,self.outbit): # check if the Hadamard entry at position (in_symbol+1, out1) is one or not
                    check = check^(int(bitout1[i])&int(bitin[i]))
        ra = random.random()
            if check == 0:if ra > self.pri_para:
                    return out1
                else:
                    return out2
            else: if ra > self.pri_para:
                    return out2
                else:
                    return out1       
        

    ra=random.random()从0-1中随机选择一个小数

    将其和隐私参数比较,如果ra大于隐私参数,则不进行扰动输出out1,否则进行扰动输出out2

    四、编码串(多个符号)

        def encode_string(self,in_list):  
            out_list = [self.encode_symbol(x) for x in in_list] 
            return out_list

    其实就是将输入的列表,将其中的每个元素进行编码,再将其编码后的列表输出。

    对于编码部分个人的一些理解:

    首先用户的某个属性的阈值是确定的,比如成年人的学历作为一个属性,假设输入值有高中、大专、本科、硕士,我们将用[k]={0,1,2,3}表示,然后将其映射到哈达玛矩阵

    映射方式是将每个符号用二进制表示,二进制长度和输出位大小相同,如果位数不够左边用0补齐。比如0映射为矩阵中第一列,1映射为第二列,以此类推...

    那么编码之后应该如何对其进行扰动:

    当然有一点应该明确,输入的阈值(上面的学历属性)确定后,输出位的大小和可能输出值的大小就确定了,我们在可能的输出值中随机选择一位,并将其转换为二进制串

    并且对其最左边为1的位进行反转得到潜在的输出,再随机取一个0-1的概率值和之前的隐私参数比较,来选择返回反转前的值还是反转后的值,这就其大致的扰动方式。

    其实在上面的encode_string函数中,in_list并不是一个列表,而是一种自定义数据类型,类似于[14  6  4 ...  1  5 20]方式。

    现在需要补充一点重要的知识点:

    输入字符串的类型,ndarray类型,这种类型其实就是一个列表,但是其必须要求列表中的元素类型相同,比如[1 3 6 8 9 5],或者['red' 'blue' 'purple' 'pink' 'black']

    ndarray和list的转化方式为:

    list转numpy     np.array(a)
    ndarray转list    a.tolist()

    五、解码串

            l = len(out_list) 
            count,edges = np.histogram(out_list,range(self.outsz+1))
            dist = count/float(l)

    l=len(out_list) out_list是编码后输出的串,获得其长度;

    count,edges=np.histogram(out_list,range(self.outsz+1))

     np.histogram()中的前两个参数,第一个参数out_list类似于数组,第二个参数range(self.outsz+1)如果outsz去8表示0-9,

    对于返回值edges表示横坐标的边数,count表示每个范围内的数量,比如0-1这一个段有的数量;

    dist=count/float(l)  求得是一个百分比,每一个区域占的百分比;

            if iffast == 1:  # if we use fast hadamard transform
                dist_mid = FWHT_A(self.outsz, dist)  # do fast hadamard transform to the frequency vector
                dist_S = (dist_mid[1:self.insz + 1] + 1) / float(2)  # get the frequencies of C_i

    如果使用快速编码:

    dist_mid=FWHT_A(outsz,dist),

    def FWHT_A(k, dist):
        if k == 1:
            return dist
        dist1 = dist[0 : k//2]
        dist2 = dist[k//2 : k]
        trans1 = FWHT_A(k//2, dist1)
        trans2 = FWHT_A(k//2, dist2)
        trans = np.concatenate((trans1+ trans2, trans1 - trans2))
        return trans

    下面举一个实际例子现实编码的解码的过程:

    1、首先生成编码字符串:

    prob = prob_list['Uniform']
    in_list = np.random.choice(10, 10, p=prob)
     
    在均匀分布下随机生成一个样本空间,样本空间是[0-9],间隔是1,比如样本空间为:[7 6 2 5 5 5 9 5 6 4] 
     
    2、开始编码:
     
    一些理论证明

    -RR的期望差()

     

     

    k-RAPPOR的期望差(

    k-HR的期望差(

     

  • 相关阅读:
    C# winform开发:Graphics、pictureBox同时画多个矩形
    C# “配置系统未能初始化” 异常解决
    Google Maps API V3 之 路线服务
    Google Maps API V3 之 图层
    Google Maps API V3 之绘图库 信息窗口
    Google 地图 API V3 之 叠加层
    驱动开发之libusb函数
    libusb的使用教程和例子
    libusb检测U盘插入
    使用libusb检测USB设备插拔状态
  • 原文地址:https://www.cnblogs.com/Optimism/p/10483099.html
Copyright © 2020-2023  润新知