Skip to content

Commit

Permalink
updated anticommuting check to be faster and played with commutes_ter…
Browse files Browse the repository at this point in the history
…mwise sparse (dense method seems fastest for now)
  • Loading branch information
AlexisRalli committed Sep 1, 2023
1 parent b5193d4 commit 014329c
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 2 deletions.
5 changes: 3 additions & 2 deletions symmer/operators/anticommuting_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ def __init__(self,
super().__init__(AC_op_symp_matrix, coeff_list)

# check all operators anticommute
anti_comm_check = self.adjacency_matrix.astype(int) - np.eye(self.adjacency_matrix.shape[0])
assert (np.sum(anti_comm_check) == 0), 'operator needs to be made of anti-commuting Pauli operators'
adj_mat = self.adjacency_matrix
adj_mat[np.diag_indices_from(adj_mat)] = False
assert ~np.any(adj_mat), 'operator needs to be made of anti-commuting Pauli operators'

self.X_sk_rotations = []
self.R_LCU = None
Expand Down
16 changes: 16 additions & 0 deletions symmer/operators/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -975,6 +975,14 @@ def commutes_termwise(self,
np.array: A Boolean array indicating the term-wise commutation.
"""
assert (self.n_qubits == PwordOp.n_qubits), 'Pauliwords defined for different number of qubits'

### sparse code
# adjacency_matrix = (
# csr_matrix(self.symp_matrix.astype(int)) @ csr_matrix(np.hstack((PwordOp.Z_block, PwordOp.X_block)).astype(int)).T)
# adjacency_matrix.data = ((adjacency_matrix.data % 2) != 0)
# return np.logical_not(adjacency_matrix.toarray())

### dense code
Omega_PwordOp_symp = np.hstack((PwordOp.Z_block, PwordOp.X_block)).astype(int)
return (self.symp_matrix @ Omega_PwordOp_symp.T) % 2 == 0

Expand Down Expand Up @@ -1089,6 +1097,14 @@ def is_noncontextual(self) -> bool:
bool: True if the operator is noncontextual, False if contextual.
"""
# if generators of operator (self) are noncontextual then whole of operator (self) must be too!
if self.n_terms<= 2*self.n_qubits+1:
# check edge case where all terms are anticommuting
adj_mat = self.adjacency_matrix
adj_mat[np.diag_indices_from(adj_mat)] = False
if ~np.any(adj_mat):
# operator is all anticommuting
return True

from symmer.utils import get_generators_including_xz_products
xyz_generators = get_generators_including_xz_products(self)

Expand Down
19 changes: 19 additions & 0 deletions tests/test_operators/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,25 @@ def test_is_noncontextual_generators():
# assert check_adjmat_noncontextual(Hnc.generators.adjacency_matrix), 'noncontexutal operator is being correctly defined as noncontextual'
assert Hnc.is_noncontextual, 'noncontexutal operator is being correctly defined as noncontextual'

def test_is_noncontextual_anticommuting_H():
"""
noncontextual test that breaks if only 2n generators are used rather than 3n generators
Returns:
"""
Hnc = PauliwordOp.from_dictionary({
'ZZZI': (1.2532436410975218-0j),
'IIXI': (0.8935108507410493-0j),
'ZIYI': (-1.1362909076230914+0j),
'IXZI': (-0.05373661687140326+0j),
'ZYZI': (-1.0012312990477774+0j),
'XXYI': (-0.045809456087963205+0j),
'YXYZ': (0.21569499626612557-0j),
'YXYX': (-0.5806963175396661+0j),
'YXYY': (0.3218493853030614-0j)})

assert Hnc.is_noncontextual, 'noncontexutal operator is being correctly defined as noncontextual'

def test_multiplication_1():
""" Tests multiplication and the OpenFermion conversion
"""
Expand Down

0 comments on commit 014329c

Please sign in to comment.