Source code for qlazy.PauliProduct

# -*- coding: utf-8 -*-
"""  Pauli Product """

[docs]class PauliProduct: """ Pauli Product Attributes ---------- qid : list of int list of qubit id. pauli_list : list of str list of pauli operators. factor : complex factor of pauli product. """ def __init__(self, pauli_str, qid=None, factor=1.+0.j): """ Parameters ---------- pauli_str : str string representation of Pauli Product. ex) "XZZY" qid : list of int, default - [0,1,..,len(pauli_str)-1] list of qubit id. ex) [1, 0, 3, 6] factor : complex, default - 1.+0.j factor of pauli product Notes ----- 'pauli_str' must consist of 'X','Y','Z', and length of 'pauli_str' must be equal to length of 'qid'. factor must be +1, -1, I, or -I. Examples -------- >>> pp = PauliProduct(pauli_str ="XZZY", qid=[1, 0, 3, 6]) represent Pauli Product : X1*Z0*Z3*Y6. >>> pp = PauliProduct(pauli_str ="I") represent identity. """ if pauli_str is None: raise ValueError("pauli_str or qid is not specified") if qid is None: qid = list(range(len(pauli_str))) if len(pauli_str) != len(qid): raise ValueError("length of 'pauli_str' is not equal to length of 'qid'.") if len(qid) != len(set(qid)): raise ValueError("some elements of 'qid' are duplicated") if sum([0 if p in ['X', 'Y', 'Z', 'I'] else 1 for p in list(pauli_str)]) > 0: raise ValueError("'pauli_str' must consist of 'X','Y','Z'.") if factor not in (1.+0.j, -1.+0.j, 0.+1.j, 0.-1.j): raise ValueError("'factor' must be 1.+0.j, -1.+0.j, 0.+1.j, 0.-1.j.") qid_sorted = [] pauli_list_sorted = [] if list(set(pauli_str)) == ['I']: qid_sorted = [0] pauli_list_sorted = ['I'] else: for q, p in sorted(zip(qid, list(pauli_str))): if p == 'I': continue qid_sorted.append(q) pauli_list_sorted.append(p) self.qid = qid_sorted self.qubit_num = max(qid_sorted) + 1 self.pauli_list = pauli_list_sorted self.factor = factor def __get_factor_str(self): if self.factor == 1.+0.j: factor_str = "" elif self.factor == -1.+0.j: factor_str = "- " elif self.factor == 0.+1.j: factor_str = "i " elif self.factor == 0.-1.j: factor_str = "-i " else: raise ValueError("'factor' must be 1.+0.j, -1.+0.j, 0.+1.j, 0.-1.j.") return factor_str def __str__(self): pauli_product = self.__get_factor_str() for i, p in sorted(zip(self.qid, self.pauli_list)): pauli_product += "{0:}({1:}) ".format(p, str(i)) pauli_product = pauli_product.rstrip() return pauli_product def __eq__(self, other): """ Parameters ---------- other : instance of PauliProcuct pauli product Returns ------- ans : bool equal or not """ ans = False if (self.qid == other.qid and self.pauli_list == other.pauli_list and self.factor == other.factor): ans = True return ans def __ne__(self, other): """ Parameters ---------- other : instance of PauliProcuct pauli product Returns ------- ans : bool equal or not """ ans = not self.__eq__(other) return ans def __mul__(self, other): """ Parameters ---------- other : instance of PauliProduct pauli product Returns ------- out : instance of PauliProduct pauli product (result) """ qid = self.qid + other.qid pauli_list = self.pauli_list + other.pauli_list factor_out = self.factor * other.factor qid_out = [] pauli_list_out = [] for i in range(max(qid) + 1): plist = [pauli_list[j] for j, q in enumerate(qid) if q == i] if plist == []: continue elif len(plist) == 1: pstr = plist[0] elif len(plist) == 2: if plist[0] == plist[1]: pstr = 'I' elif plist == ['X','Y']: pstr = 'Z' factor_out *= 0.+1.j elif plist == ['X','Z']: pstr = 'Y' factor_out *= 0.-1.j elif plist == ['Y','X']: pstr = 'Z' factor_out *= 0.-1.j elif plist == ['Y','Z']: pstr = 'X' factor_out *= 0.+1.j elif plist == ['Z','X']: pstr = 'Y' factor_out *= 0.+1.j elif plist == ['Z','Y']: pstr = 'X' factor_out *= 0.-1.j elif plist[0] == 'I' and plist[1] in ('X','Y','Z','I'): pstr = plist[1] elif plist[1] == 'I' and plist[0] in ('X','Y','Z','I'): pstr = plist[0] else: raise ValueError("not supported operator product: []".format(plist)) qid_out.append(i) pauli_list_out.append(pstr) pauli_str_out = "".join(pauli_list_out) out = PauliProduct(pauli_str=pauli_str_out, qid=qid_out, factor=factor_out) return out
[docs] def get_binary_rep(self, qubit_num=None): """ get binary representation of pauli product. Parameters ---------- qubit_num : int, default - max(self.qid)+1 qubit number of binary representation. Returns ------- binary_rep : list of int output binary representation of the pauli product. Examples -------- >>> pp = PauliProduct(pauli_str="XYZ", qid=[0,1,2]) >>> print(pp.get_binary_rep()) [1,1,0,0,1,1] """ if qubit_num is None: qubit_num = self.qubit_num if qubit_num < max(self.qid) + 1: raise ValueError("qubit_num is smaller than the size required by pauli product") binary_rep = [0] * qubit_num * 2 for q in range(qubit_num): if q in self.qid: i = self.qid.index(q) if self.pauli_list[i] == 'X': binary_rep[q] = 1 elif self.pauli_list[i] == 'Z': binary_rep[qubit_num + q] = 1 elif self.pauli_list[i] == 'Y': binary_rep[q] = 1 binary_rep[qubit_num + q] = 1 return binary_rep
[docs] def is_commute(self, pp): """ is pauli product commute to other pauli product or not. Parameters ---------- pp : instance of PauliProduct pauli product Returns ------- ans : bool commute (True) or anti-commute (False) """ qubit_num = max(max(self.qid), max(pp.qid)) + 1 binary_rep_self = self.get_binary_rep(qubit_num) binary_rep_pp = pp.get_binary_rep(qubit_num) inner_prod = 0 for i in range(qubit_num): inner_prod += (binary_rep_self[i] * binary_rep_pp[qubit_num + i]) inner_prod += (binary_rep_self[qubit_num + i] * binary_rep_pp[i]) inner_prod = inner_prod % 2 ans = bool(inner_prod == 0) return ans
[docs] def tenspro(self, pp): """ get tensor product with other pauli product. Parameters ---------- pp : instance of PauliProduct pauli product Returns ------- pp_out : instance of PauliProduct output pauli product """ qubit_num = max(max(self.qid), max(pp.qid)) + 1 binary_rep_self = self.get_binary_rep(qubit_num) binary_rep_pp = pp.get_binary_rep(qubit_num) binary_rep = [(bs + bp) % 2 for bs, bp in zip(binary_rep_self, binary_rep_pp)] pauli_list = [] qid = [] for i in range(qubit_num): if binary_rep[i] == 1 and binary_rep[qubit_num + i] == 1: pauli_list.append('Y') qid.append(i) elif binary_rep[i] == 1: pauli_list.append('X') qid.append(i) elif binary_rep[qubit_num + i] == 1: pauli_list.append('Z') qid.append(i) pauli_str = ''.join(pauli_list) pp_out = self.__class__(pauli_str=pauli_str, qid=qid) return pp_out
[docs] def get_qubit_num(self): """ get the total qubit number considerd Parameters ---------- None Returns ------- qubit_num : inst total qubit number considerd by the pauli product. """ return max(self.qid) + 1