numpy 具有标准标量积结构的2个Numy数组的定制操作

nnt7mjpx  于 2022-11-10  发布在  其他
关注(0)|答案(1)|浏览(118)

有没有办法以定制的方式利用两个数组之间的标准标量产品结构?为了让它更容易理解,我想使用这种类型的操作:

arr1 = array([a1,b1])
arr2 = array([a2,b2])
scalar_product = arr1@arr2

->其中scalar_product等于:a1a2+b1b2
但与元素之间的‘*’和‘+’不同,我想使用我自己的一些特殊的加法和乘法,所以它类似于:
some_special_scalar_product(arr1,arr2) = my_sum(my_mult(a1,a2),my_mult(b1,b2))
其他信息:

  • 数组的实际输入是字符串,它必须保持字符串(对于进一步的上下文,字符串是伽罗华域元素的字节表示,尽管没有必要理解它对回答我的问题意味着什么。只要考虑到,在我的例子中,谈论一些特殊的字符串和乘法是有意义的)。
  • 我想这么做的原因是为了利用麻木运算评分器的效率,而不是用我的定制方法去寻找一些低效的‘for循环’。因此,只应考虑符合此效率标准的解决方案(如果可能)。
  • 如果这是不可能的,你有什么其他建议来有效地进行这种类型的操作?(在这种情况下存储字符串和访问它们的最佳方式,等等……)

对于完整的细节,我有那些类和函数(正如我在注解中指出的,‘encode()’方法的最后一部分是我想要使用定制的点积的地方):

class BinaryDomains():

    def add(self, x, y):
        return format(int(x, base=2)^int(y, base=2),'08b')    #use bitwise XOR operator

    def multiply(self, x, y):
        prod = 0
        P_ = 0b10100110                              #P_ = irreducible polynomial without last bit (stay on 8 bits)

        #string -> byte:
        x = int(x, base=2)                         
        y = int(y, base=2)

        while y != 0: 
            if y & 1:                                #y has a d°0:
                prod ^= x                            #add with XOR

            if x & 0b10000000:                       #x is d°7:
                x = ((x ^ P_) << 1) ^ 1              #reduce with XOR, increase degree, turn last bit into 1 (missing part of P_)            
            else:       
                x <<= 1                              #increase degree

            y >>= 1                                  #get rid of y0 coefficient, decrease degree

        return format(prod, '08b') 

class ReedSolomon():

    def __init__(self, k, n, x):
        """
        Args:
            k (int): dimension of message to transmit 
            n (int): size of the bloc to transmit
            x (liste de string de taille n): points xi
        """
        self.f = BinaryDomains()
        self.k = k
        self.n = n
        self.x = x

    def encoding(self, message_original):
        bd = self.f
        lst = []

        for i in range(self.n):               #put xi's powers in a list
            x = self.x[i]
            xpow = x
            lst.append([x])
            for j in range(2,self.k):
                x = bd.multiply(xpow,x)
                lst[i].append(x)

        A = []                                

        # THIS IS WHERE I WOULD LIKE TO USE SOME COSTIMIZED FORM OF DOT PRODUCT: 
        for i in range(self.n): #encode single input with xi's powers -> multiple coded outputs           
            A.append(message_original[0])
            for j in range(1,self.k):
                A[i] = bd.add(A[i],
                              bd.multiply(message_original[j],lst[i][j-1]))

        return A

再说一次,我不能更改方法输入/输出的类型(尽管这看起来很愚蠢),也不能导入除NumPy以外的任何东西。

46qrfjad

46qrfjad1#

下面是基于companion matrices和一些巧妙的线性代数。我相信它工作正常,但我会让你找一些例子来错误检查我的方法。

import numpy as np

class GF8(object):

    def __init__(self):
        poly_coeff = np.array([1,0,1,1,0,0,1,0],dtype = int)
        C = np.block([[np.zeros(7,dtype = int),poly_coeff[0]],[np.eye(7,dtype = int),poly_coeff[1:,None]]])
        self.C = C
        current = np.eye(8,dtype = int)
        _pows = [current]
        for _ in range(7):
            current = current@C%2
            _pows.append(current)

        self.pows = np.stack(_pows)

    def to_mat(self,x):
        return np.sum([M for i,M in enumerate(self.pows) if (1<<i)&x],axis=0)%2

    def to_vec(self,x):
        return np.array([int(bool((1<<i)&x)) for i in range(8)])

    def row_rep(self,arr):
        return np.block([self.to_mat(x) for x in arr])

    def col_rep(self,arr):
        return np.hstack([self.to_vec(x) for x in arr])

    def dot(self,arr_1, arr_2):
        vec_result = self.row_rep(arr_1)@self.col_rep(arr_2)%2
        return sum(b<<i for b,i in enumerate(vec_result))

以下是测试脚本

field = GF8()
ans = field.dot([0b00000111,0b00000110,0b00000101],[0b10000001,0b10000000,0b01111111])
print(format(ans,'08b'))

生成打印的答案00100101

相关问题