Skip to content

Commit

Permalink
updates to GF2 multiplication and minor change to to_sparse_matrix fu…
Browse files Browse the repository at this point in the history
…nction
  • Loading branch information
AlexisRalli committed Mar 18, 2024
1 parent 8f39cc1 commit 744dcb5
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 2 deletions.
2 changes: 1 addition & 1 deletion symmer/operators/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1472,7 +1472,7 @@ def to_sparse_matrix(self) -> csr_matrix:
x_int = binary_array_to_int(self.X_block).reshape(-1, 1)
z_int = binary_array_to_int(self.Z_block).reshape(-1, 1)

Y_number = np.sum(np.bitwise_and(self.X_block, self.Z_block).astype(int), axis=1)
Y_number = np.sum(np.bitwise_and(self.X_block, self.Z_block), axis=1)
global_phase = (-1j) ** Y_number

dimension = 2 ** self.n_qubits
Expand Down
71 changes: 70 additions & 1 deletion symmer/operators/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,77 @@
from qiskit._accelerate.sparse_pauli_op import unordered_unique
import numba as nb

@nb.njit(fastmath=True, parallel=True, cache=True)
def matmul_GF2(A: np.array, B: np.array) -> np.array:
"""
Matrix multiplication mod2, i.e. (A@B)%2.
Note this calls one of two numba functions. First one uses numpy dot functionality, the second
does a manual multiplication over GF2 (that is safe for very large matrices)
Args:
A (np.array): boolean numpy array
B (np.array): boolean numpy array
Returns:
matrix multiplication mod 2
"""
if max(*A.shape, *B.shape)<2147483648: # 2**31
return numba_dot_matmal_GF2(A,B)
else:
return numba_binary_matmal_GF2(A,B)

@nb.njit(fastmath=True, parallel=True, cache=True)
def numba_binary_matmal_GF2(A: np.array, B: np.array) -> np.array:
"""
custom GF(2) multiplication using numba. i.e. C = (A@B) mod 2.
Note function uses fact that multiplication over GF2 doesn't require sums for each matrix element in C
instead it uses and AND operation (same as elementwise multiplicaiton of row,col pairs)
followed by XOR operation (same as taking sum of row,col multiplied pairs)
Args:
A (np.array): numpy boolean array
B (np.array): numpy boolean array
Returns:
C (np.array): numpy boolean array of (A@B) mod 2
"""
C = np.empty((A.shape[0], B.shape[1]), dtype=np.bool_)
for i in nb.prange(C.shape[0]):
for j in range(C.shape[1]):

## logical version 1 (slower)
# C[i, j] = bool(np.sum(np.logical_and(A[i, :], B[:, j]))%2)

# # logical version 2 (slower)
# parity = False
# for bit in np.logical_and(A[i, :], B[:, j]):
# parity^=bit
# C[i, j] = parity

## faster loop
acc = False
for k in range(B.shape[0]):
acc ^= A[i, k] & B[k, j]
C[i, j] = acc
return C

@nb.njit('(bool_[:,::1],bool_[:,::1])', fastmath=True, cache=True)
def numba_dot_matmal_GF2(A, B):
"""
Matrix multiplication mod2, i.e. (A@B)%2. Note this function expects boolean input!
Args:
A (np.array): boolean numpy array
B (np.array): boolean numpy array
Returns:
matrix multiplication mod 2
"""
return np.asarray(np.dot(np.asarray(A, dtype = np.float64),
np.asarray(B, dtype = np.float64)
)%2,
dtype = np.bool_)

"""
custom GF(2) multiplication using numba. i.e. C = (A@B) mod 2.
Expand Down

0 comments on commit 744dcb5

Please sign in to comment.