对具有标准标量积结构的两个NumPy数组的自定义操作

vmjh9lq9  于 2023-04-21  发布在  其他
关注(0)|答案(1)|浏览(350)

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

arr1 = array([a1, b1])
arr2 = array([a2, b2])
scalar_product = arr1@arr2
  • 〉其中scalar_product等于:a1 * a2 + b1 * b2
    但是,我想使用我自己的一些特殊的加法和乘法方法,而不是元素之间的'*'和'+',所以它会像这样:
    some_special_scalar_product(arr1, arr2) = my_sum(my_mult(a1, a2), my_mult(b1, b2))
    额外信息:
  • 数组的实际输入是字符串,而且必须是字符串(为了进一步说明上下文,字符串是伽罗瓦域元素的字节表示,尽管回答我的问题并不一定要理解它的含义,只要考虑到在我的例子中讨论一些特殊的字符串求和和乘法是有意义的)。
  • 我想这样做的原因是使用NumPy操作的效率,而不是使用我的自定义方法进行一些低效的“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
        #      customised 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以外的任何东西。

zvms9eto

zvms9eto1#

下面是基于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

相关问题