def test_pauli_sgn_prod(self): p1 = Pauli(np.array([0]), np.array([1])) p2 = Pauli(np.array([1]), np.array([1])) self.log.info("sign product:") p3, sgn = sgn_prod(p1, p2) self.log.info("p1: %s", p1.to_label()) self.log.info("p2: %s", p2.to_label()) self.log.info("p3: %s", p3.to_label()) self.log.info("sgn_prod(p1, p2): %s", str(sgn)) self.assertEqual(p1.to_label(), 'X') self.assertEqual(p2.to_label(), 'Y') self.assertEqual(p3.to_label(), 'Z') self.assertEqual(sgn, 1j) self.log.info("sign product reverse:") p3, sgn = sgn_prod(p2, p1) self.log.info("p2: %s", p2.to_label()) self.log.info("p1: %s", p1.to_label()) self.log.info("p3: %s", p3.to_label()) self.log.info("sgn_prod(p2, p1): %s", str(sgn)) self.assertEqual(p1.to_label(), 'X') self.assertEqual(p2.to_label(), 'Y') self.assertEqual(p3.to_label(), 'Z') self.assertEqual(sgn, -1j)
def _setup_qpe(self): self._operator._check_representation('paulis') self._ret['translation'] = sum( [abs(p[0]) for p in self._operator.paulis]) self._ret['stretch'] = 0.5 / self._ret['translation'] # translate the operator self._operator._simplify_paulis() translation_op = Operator([[ self._ret['translation'], Pauli(np.zeros(self._operator.num_qubits), np.zeros(self._operator.num_qubits)) ]]) translation_op._simplify_paulis() self._operator += translation_op # stretch the operator for p in self._operator._paulis: p[0] = p[0] * self._ret['stretch'] # check for identify paulis to get its coef for applying global phase shift on ancillae later num_identities = 0 for p in self._operator.paulis: if np.all(p[1].v == 0) and np.all(p[1].w == 0): num_identities += 1 if num_identities > 1: raise RuntimeError( 'Multiple identity pauli terms are present.') self._ancilla_phase_coef = p[0].real if isinstance( p[0], complex) else p[0] self._construct_qpe_evolution() logger.info('QPE circuit qasm length is roughly {}.'.format( len(self._circuit.qasm().split('\n'))))
def get_partition_qubitops(values): """Construct the Hamiltonian for a given Partition instance. Given a list of numbers for the Number Partitioning problem, we construct the Hamiltonian described as a list of Pauli gates. Args: values (numpy.ndarray): array of values. Returns: operator.Operator, float: operator for the Hamiltonian and a constant shift for the obj function. """ n = len(values) # The Hamiltonian is: # \sum_{i,j=1,\dots,n} ij z_iz_j + \sum_{i=1,\dots,n} i^2 pauli_list = [] for i in range(n): for j in range(i): wp = np.zeros(n) vp = np.zeros(n) vp[i] = 1 vp[j] = 1 pauli_list.append([2 * values[i] * values[j], Pauli(vp, wp)]) return Operator(paulis=pauli_list), sum(values*values)
def test_imul(self): """Test in-place multiplication.""" p1 = self.ref_p p2 = Pauli.from_label('ZXXI') p3 = deepcopy(p2) p2 *= p1 self.assertTrue(p2 != p3) self.assertEqual(p2.to_label(), 'ZYIY')
def test_label_to_pauli(self): label = 'ZXYI' p = label_to_pauli(label) v = np.asarray([1, 0, 1, 0]) w = np.asarray([0, 1, 1, 0]) p2 = Pauli(v, w) self.assertEqual(p, p2)
def setUp(self): v = np.zeros(3) w = np.zeros(3) v[0] = 1 w[1] = 1 v[2] = 1 w[2] = 1 self.p3 = Pauli(v, w)
def test_pauli(self): v = np.zeros(3) w = np.zeros(3) v[0] = 1 w[1] = 1 v[2] = 1 w[2] = 1 p = Pauli(v, w) self.log.info(p) self.log.info("In label form:") self.log.info(p.to_label()) self.log.info("In matrix form:") self.log.info(p.to_matrix()) q = random_pauli(2) self.log.info(q) r = inverse_pauli(p) self.log.info("In label form:") self.log.info(r.to_label()) self.log.info("Group in tensor order:") grp = pauli_group(3, case=1) for j in grp: self.log.info(j.to_label()) self.log.info("Group in weight order:") grp = pauli_group(3) for j in grp: self.log.info(j.to_label()) self.log.info("sign product:") p1 = Pauli(np.array([0]), np.array([1])) p2 = Pauli(np.array([1]), np.array([1])) p3, sgn = sgn_prod(p1, p2) self.log.info(p1.to_label()) self.log.info(p2.to_label()) self.log.info(p3.to_label()) self.log.info(sgn) self.log.info("sign product reverse:") p3, sgn = sgn_prod(p2, p1) self.log.info(p2.to_label()) self.log.info(p1.to_label()) self.log.info(p3.to_label()) self.log.info(sgn)
def get_graphpartition_qubitops(weight_matrix): """Generate Hamiltonian for the graph partitioning Args: weight_matrix (numpy.ndarray) : adjacency matrix. Returns: operator.Operator, float: operator for the Hamiltonian and a constant shift for the obj function. Goals: 1 separate the vertices into two set of the same size 2 make sure the number of edges between the two set is minimized. Hamiltonian: H = H_A + H_B H_A = sum\_{(i,j)\in E}{(1-ZiZj)/2} H_B = (sum_{i}{Zi})^2 = sum_{i}{Zi^2}+sum_{i!=j}{ZiZj} H_A is for achieving goal 2 and H_B is for achieving goal 1. """ num_nodes = len(weight_matrix) pauli_list = [] shift = 0 for i in range(num_nodes): for j in range(i): if (weight_matrix[i, j] != 0): wp = np.zeros(num_nodes) vp = np.zeros(num_nodes) vp[i] = 1 vp[j] = 1 pauli_list.append([-0.5, Pauli(vp, wp)]) shift += 0.5 for i in range(num_nodes): for j in range(num_nodes): if i != j: wp = np.zeros(num_nodes) vp = np.zeros(num_nodes) vp[i] = 1 vp[j] = 1 pauli_list.append([1, Pauli(vp, wp)]) else: shift += 1 return Operator(paulis=pauli_list), shift
def test_hamiltonian(self): # printing an example from a H2 file hfile = self._get_resource_path("H2Equilibrium.txt") self.log.info(make_Hamiltonian(Hamiltonian_from_file(hfile))) # printing an example from a graph input n = 3 v0 = np.zeros(n) v0[2] = 1 v1 = np.zeros(n) v1[0] = 1 v1[1] = 1 v2 = np.zeros(n) v2[0] = 1 v2[2] = 1 v3 = np.zeros(n) v3[1] = 1 v3[2] = 1 pauli_list = [(1, Pauli(v0, np.zeros(n))), (1, Pauli(v1, np.zeros(n))), (1, Pauli(v2, np.zeros(n))), (1, Pauli(v3, np.zeros(n)))] a = make_Hamiltonian(pauli_list) self.log.info(a) w, v = la.eigh(a, eigvals=(0, 0)) self.log.info(w) self.log.info(v) data = {'000': 10} self.log.info(Energy_Estimate(data, pauli_list)) data = {'001': 10} self.log.info(Energy_Estimate(data, pauli_list)) data = {'010': 10} self.log.info(Energy_Estimate(data, pauli_list)) data = {'011': 10} self.log.info(Energy_Estimate(data, pauli_list)) data = {'100': 10} self.log.info(Energy_Estimate(data, pauli_list)) data = {'101': 10} self.log.info(Energy_Estimate(data, pauli_list)) data = {'110': 10} self.log.info(Energy_Estimate(data, pauli_list)) data = {'111': 10} self.log.info(Energy_Estimate(data, pauli_list))
def _parity_mode(self, n): """ Parity mode. Args: n (int): number of modes """ a = [] for i in range(n): Xv = [0] * (i - 1) + [1] if i > 0 else [] Xw = [0] * (i - 1) + [0] if i > 0 else [] Yv = [0] * (i - 1) + [0] if i > 0 else [] Yw = [0] * (i - 1) + [0] if i > 0 else [] Xv = np.asarray(Xv + [0] + [0] * (n - i - 1)) Xw = np.asarray(Xw + [1] + [1] * (n - i - 1)) Yv = np.asarray(Yv + [1] + [0] * (n - i - 1)) Yw = np.asarray(Yw + [1] + [1] * (n - i - 1)) a.append((Pauli(Xv, Xw), Pauli(Yv, Yw))) return a
def _parity_mode(self, n): """ Parity mode. Args: n (int): number of modes """ a = [] for i in range(n): x_v = [0] * (i - 1) + [1] if i > 0 else [] x_w = [0] * (i - 1) + [0] if i > 0 else [] y_v = [0] * (i - 1) + [0] if i > 0 else [] y_w = [0] * (i - 1) + [0] if i > 0 else [] x_v = np.asarray(x_v + [0] + [0] * (n - i - 1)) x_w = np.asarray(x_w + [1] + [1] * (n - i - 1)) y_v = np.asarray(y_v + [1] + [0] * (n - i - 1)) y_w = np.asarray(y_w + [1] + [1] * (n - i - 1)) a.append((Pauli(x_v, x_w), Pauli(y_v, y_w))) return a
def test_random_pauli(self): """Test random pauli creation.""" length = 4 q = Pauli.random(length) self.log.info(q) self.assertEqual(q.numberofqubits, length) self.assertEqual(len(q.z), length) self.assertEqual(len(q.x), length) self.assertEqual(len(q.to_label()), length) self.assertEqual(len(q.to_matrix()), 2 ** length)
def test_insert_paulis(self): """Test inserting paulis via pauli object.""" p1 = deepcopy(self.ref_p) new_p = Pauli.from_label('XY') p1.insert_paulis(indices=[0], paulis=new_p) self.assertTrue(p1 != self.ref_p) self.assertEqual(len(p1), 6) self.assertEqual(p1.to_label(), self.ref_label + 'XY')
def test_group_paulis(self): """ qiskit.tools.apps.optimization.group_paulis function""" ham_name = self._get_resource_path( "../performance/H2/H2Equilibrium.txt") zz = np.array([0, 0]) oo = np.array([1, 1]) pauli_list = Hamiltonian_from_file(ham_name) pauli_list_grouped = group_paulis(pauli_list) self.assertEqual(len(pauli_list_grouped), 2) r0 = [i[0] for i in pauli_list_grouped] r1 = [i[1] for i in pauli_list_grouped] self.assertEqual(len(r0), 2) r00 = [i[0] for i in r0] r01 = [i[1] for i in r0] e01 = [Pauli(oo, zz), Pauli(zz, oo)] self.assertEqual([0, 0], r00) self.assertEqual(e01, r01) self.assertEqual(len(r1), 2) r10 = [i[0] for i in r1] r11 = [i[1] for i in r1] e11 = [Pauli(oo, zz), Pauli(zz, oo)] self.assertEqual([0.011279956224107712, 0.18093133934472627], r10) self.assertEqual(e11, r11) expected_stout = ( "Post Rotations of TPB set 0:\nZZ\n0\n\nZZ\n0.0112800\n" "II\n-1.0523761\nZI\n0.3979357\nIZ\n" "0.3979357\n\n\nPost Rotations of TPB set 1:\nXX\n0\n\n" "XX\n0.1809313") with patch('sys.stdout', new=StringIO()) as fakeOutput: print_pauli_list_grouped(pauli_list_grouped) self.assertMultiLineEqual(fakeOutput.getvalue().strip(), expected_stout)
def get_portfolio_qubitops(mu, sigma, q, budget, penalty): # get problem dimension n = len(mu) e = np.ones(n) E = np.matmul(np.asmatrix(e).T, np.asmatrix(e)) # map problem to Ising model offset = -np.dot( mu, e ) / 2 + penalty * budget**2 - budget * n * penalty + n**2 * penalty / 4 + q / 4 * np.dot( e, np.dot(sigma, e)) mu_z = mu / 2 + budget * penalty * e - n * penalty / 2 * e - q / 2 * np.dot( sigma, e) sigma_z = penalty / 4 * E + q / 4 * sigma # construct operator pauli_list = [] for i in range(n): i_ = i # i_ = n-i-1 if np.abs(mu_z[i_]) > 1e-6: wp = np.zeros(n) vp = np.zeros(n) vp[i_] = 1 pauli_list.append([mu_z[i_], Pauli(vp, wp)]) for j in range(i): j_ = j # j_ = n-j-1 if np.abs(sigma_z[i_, j_]) > 1e-6: wp = np.zeros(n) vp = np.zeros(n) vp[i_] = 1 vp[j_] = 1 pauli_list.append([2 * sigma_z[i_, j_], Pauli(vp, wp)]) offset += sigma_z[i_, i_] return Operator(paulis=pauli_list), offset
def __init__(self, cost_operator, p): self.cost_operator = cost_operator self.p = p self.num_parameters = 2 * p self.parameter_bounds = [(0, np.pi)] * p + [(0, 2 * np.pi)] * p self.preferred_init_points = [0] * p * 2 # prepare the mixer operator v = np.zeros(self.cost_operator.num_qubits) ws = np.eye(self.cost_operator.num_qubits) self.mixer_operator = reduce(lambda x, y: x + y, [ Operator([[1, Pauli(v, ws[i, :])]]) for i in range(self.cost_operator.num_qubits) ])
def test_two_qubit_reduction(self): """ qiskit.tools.apps.fermion.two_qubit_reduction""" pauli_list = [] n = 4 w = np.arange(n ** 2).reshape(n, n) for i in range(n): for j in range(i): if w[i, j] != 0: wp = np.zeros(n) vp = np.zeros(n) vp[n - i - 1] = 1 vp[n - j - 1] = 1 pauli_list.append((w[i, j], Pauli(vp, wp))) r = two_qubit_reduction(pauli_list, 10) r0 = [i[0] for i in r] self.assertEqual([-5, -8, -2, 13], r0) r1 = [i[1] for i in r] e = [Pauli(self.zo, self.zz), Pauli(self.zz, self.zz), Pauli(self.oz, self.zz), Pauli(self.oo, self.zz)] self.assertEqual(e, r1)
def edge_operator_aij(edge_list, i, j): """Calculate the edge operator A_ij. The definitions used here are consistent with arXiv:quant-ph/0003137 Args: edge_list (numpy.ndarray): a 2xE matrix, where E is total number of edge and each pair denotes (from, to) i (int): specifying the edge operator A j (int): specifying the edge operator A Returns: Operator: qubit operator """ v = np.zeros(edge_list.shape[1]) w = np.zeros(edge_list.shape[1]) position_ij = -1 qubit_position_i = np.asarray(np.where(edge_list == i)) for edge_index in range(edge_list.shape[1]): # does the order of number matters? if set((i, j)) == set(edge_list[:, edge_index]): position_ij = edge_index # can we break? break w[position_ij] = 1 for edge_index in range(qubit_position_i.shape[1]): ii, jj = qubit_position_i[:, edge_index] ii = 1 if ii == 0 else 0 # int(not(ii)) if edge_list[ii][jj] < j: v[jj] = 1 qubit_position_j = np.asarray(np.where(edge_list == j)) for edge_index in range(qubit_position_j.shape[1]): ii, jj = qubit_position_j[:, edge_index] ii = 1 if ii == 0 else 0 # int(not(ii)) if edge_list[ii][jj] < i: v[jj] = 1 qubit_op = Operator(paulis=[[1.0, Pauli(v, w)]]) return qubit_op
def test_fermionic_maps_binary_tree(self): """ qiskit.tools.apps.fermion.fermionic_maps with BINARY_TREE map type""" r = fermionic_maps(self.a2, self.a5, "BINARY_TREE") self.assertEqual(len(r), 6) r0 = [i[0] for i in r] self.assertEqual(self.e0, r0) r1 = [i[1] for i in r] e = [Pauli(self.zo, self.oz), Pauli(self.zz, self.oz), Pauli(self.oo, self.oz), Pauli(self.oz, self.oz), Pauli(self.oo, self.zz), Pauli(self.zz, self.zz)] self.assertEqual(r1, e)
def test_fermionic_maps_parity(self): """ qiskit.tools.apps.fermion.fermionic_maps with PARITY map type""" r = fermionic_maps(self.a2, self.a5, "PARITY") self.assertEqual(len(r), 6) r0 = [i[0] for i in r] self.assertEqual(self.e0, r0) r1 = [i[1] for i in r] e = [Pauli(self.zo, self.oz), Pauli(self.zz, self.oz), Pauli(self.oo, self.oz), Pauli(self.oz, self.oz), Pauli(self.oo, self.zz), Pauli(self.zz, self.zz)] self.assertEqual(r1, e)
def edge_operator_bi(edge_list, i): """Calculate the edge operator B_i. The definitions used here are consistent with arXiv:quant-ph/0003137 Args: edge_list (numpy.ndarray): a 2xE matrix, where E is total number of edge and each pair denotes (from, to) i (int): index for specifying the edge operator B. Returns: Operator: qubit operator """ qubit_position_matrix = np.asarray(np.where(edge_list == i)) qubit_position = qubit_position_matrix[1] v = np.zeros(edge_list.shape[1]) w = np.zeros(edge_list.shape[1]) v[qubit_position] = 1 qubit_op = Operator(paulis=[[1.0, Pauli(v, w)]]) return qubit_op
def test_fermionic_maps_jordan_wigner(self): """ qiskit.tools.apps.fermion.fermionic_maps with JORDAN_WIGNER map type""" self.e0[0] = np.complex(0.75, 0) r = fermionic_maps(self.a2, self.a5, "JORDAN_WIGNER") self.assertEqual(len(r), 6) r0 = [i[0] for i in r] self.assertEqual(self.e0, r0) r1 = [i[1] for i in r] e = [Pauli(self.oo, self.oo), Pauli(self.zz, self.oo), Pauli(self.zo, self.oo), Pauli(self.oz, self.oo), Pauli(self.zo, self.zz), Pauli(self.zz, self.zz)] self.assertEqual(r1, e)
def _compute_energy(self): self._operator._check_representation('paulis') self._ret['translation'] = sum( [abs(p[0]) for p in self._operator.paulis]) self._ret['stretch'] = 0.5 / self._ret['translation'] # translate the operator self._operator._simplify_paulis() translation_op = Operator([[ self._ret['translation'], Pauli(np.zeros(self._operator.num_qubits), np.zeros(self._operator.num_qubits)) ]]) translation_op._simplify_paulis() self._operator += translation_op # stretch the operator for p in self._operator._paulis: p[0] = p[0] * self._ret['stretch'] # check for identify paulis to get its coef for applying global phase shift on ancilla later num_identities = 0 for p in self._operator.paulis: if np.all(p[1].v == 0) and np.all(p[1].w == 0): num_identities += 1 if num_identities > 1: raise RuntimeError( 'Multiple identity pauli terms are present.') self._ancilla_phase_coef = p[0].real if isinstance( p[0], complex) else p[0] self._ret['phase'] = self._estimate_phase_iteratively() self._ret['top_measurement_decimal'] = sum([ t[0] * t[1] for t in zip([1 / 2**p for p in range(1, self._num_iterations + 1)], [int(n) for n in self._ret['top_measurement_label']]) ]) self._ret['energy'] = self._ret['phase'] / self._ret[ 'stretch'] - self._ret['translation']
def _one_body(edge_list, p, q, h1_pq): r""" Map the term a^\dagger_p a_q + a^\dagger_q a_p to qubit operator. Args: edge_list (numpy.ndarray): 2xE matrix, each indicates (from, to) pair p (int): index of the one body term q (int): index of the one body term h1_pq (complex): coeffient of the one body term at (p, q) Return: Operator: mapped qubit operator """ # Handle off-diagonal terms. final_coeff = 1.0 if p != q: a, b = sorted([p, q]) b_a = edge_operator_bi(edge_list, a) b_b = edge_operator_bi(edge_list, b) a_ab = edge_operator_aij(edge_list, a, b) qubit_op = a_ab * b_b + b_a * a_ab final_coeff = -1j * 0.5 # Handle diagonal terms. else: b_p = edge_operator_bi(edge_list, p) v = np.zeros(edge_list.shape[1]) w = np.zeros(edge_list.shape[1]) id_pauli = Pauli(v, w) id_op = Operator(paulis=[[1.0, id_pauli]]) qubit_op = id_op - b_p final_coeff = 0.5 qubit_op.scaling_coeff(final_coeff * h1_pq) qubit_op.zeros_coeff_elimination() return qubit_op
def get_maxcut_qubitops(weight_matrix): """Generate Hamiltonian for the maximum stableset in a graph. Args: weight_matrix (numpy.ndarray) : adjacency matrix. Returns: operator.Operator, float: operator for the Hamiltonian and a constant shift for the obj function. """ num_nodes = weight_matrix.shape[0] pauli_list = [] shift = 0 for i in range(num_nodes): for j in range(i): if (weight_matrix[i,j] != 0): wp = np.zeros(num_nodes) vp = np.zeros(num_nodes) vp[i] = 1 vp[j] = 1 pauli_list.append([0.5 * weight_matrix[i, j], Pauli(vp, wp)]) shift -= 0.5 * weight_matrix[i, j] return Operator(paulis=pauli_list), shift
def fermionic_maps(h1, h2, map_type, out_file=None, threshold=0.000000000001): """Creates a list of Paulis with coefficients from fermionic one and two-body operator. Args: h1 (list): second-quantized fermionic one-body operator h2 (list): second-quantized fermionic two-body operator map_type (str): "JORDAN_WIGNER", "PARITY", "BINARY_TREE" out_file (str): name of the optional file to write the Pauli list on threshold (float): threshold for Pauli simplification Returns: list: A list of Paulis with coefficients """ # pylint: disable=invalid-name #################################################################### # ########### DEFINING MAPPED FERMIONIC OPERATORS ############# #################################################################### pauli_list = [] n = len(h1) # number of fermionic modes / qubits a = [] if map_type == 'JORDAN_WIGNER': for i in range(n): xv = np.append(np.append(np.ones(i), 0), np.zeros(n - i - 1)) xw = np.append(np.append(np.zeros(i), 1), np.zeros(n - i - 1)) yv = np.append(np.append(np.ones(i), 1), np.zeros(n - i - 1)) yw = np.append(np.append(np.zeros(i), 1), np.zeros(n - i - 1)) # defines the two mapped Pauli components of a_i and a_i^\dag, # according to a_i -> (a[i][0]+i*a[i][1])/2, # a_i^\dag -> (a_[i][0]-i*a[i][1])/2 a.append((Pauli(xv, xw), Pauli(yv, yw))) if map_type == 'PARITY': for i in range(n): if i > 1: Xv = np.append(np.append(np.zeros(i - 1), [1, 0]), np.zeros(n - i - 1)) Xw = np.append(np.append(np.zeros(i - 1), [0, 1]), np.ones(n - i - 1)) Yv = np.append(np.append(np.zeros(i - 1), [0, 1]), np.zeros(n - i - 1)) Yw = np.append(np.append(np.zeros(i - 1), [0, 1]), np.ones(n - i - 1)) elif i > 0: Xv = np.append((1, 0), np.zeros(n - i - 1)) Xw = np.append([0, 1], np.ones(n - i - 1)) Yv = np.append([0, 1], np.zeros(n - i - 1)) Yw = np.append([0, 1], np.ones(n - i - 1)) else: Xv = np.append(0, np.zeros(n - i - 1)) Xw = np.append(1, np.ones(n - i - 1)) Yv = np.append(1, np.zeros(n - i - 1)) Yw = np.append(1, np.ones(n - i - 1)) # defines the two mapped Pauli components of a_i and a_i^\dag, # according to a_i -> (a[i][0]+i*a[i][1])/2, # a_i^\dag -> (a_[i][0]-i*a[i][1])/2 a.append((Pauli(Xv, Xw), Pauli(Yv, Yw))) if map_type == 'BINARY_TREE': # FIND BINARY SUPERSET SIZE bin_sup = 1 while n > np.power(2, bin_sup): bin_sup += 1 # DEFINE INDEX SETS FOR EVERY FERMIONIC MODE update_sets = [] update_pauli = [] parity_sets = [] parity_pauli = [] flip_sets = [] remainder_sets = [] remainder_pauli = [] for j in range(n): update_sets.append(update_set(j, np.power(2, bin_sup))) update_sets[j] = update_sets[j][update_sets[j] < n] parity_sets.append(parity_set(j, np.power(2, bin_sup))) parity_sets[j] = parity_sets[j][parity_sets[j] < n] flip_sets.append(flip_set(j, np.power(2, bin_sup))) flip_sets[j] = flip_sets[j][flip_sets[j] < n] remainder_sets.append(np.setdiff1d(parity_sets[j], flip_sets[j])) update_pauli.append(Pauli(np.zeros(n), np.zeros(n))) parity_pauli.append(Pauli(np.zeros(n), np.zeros(n))) remainder_pauli.append(Pauli(np.zeros(n), np.zeros(n))) for k in range(n): if np.in1d(k, update_sets[j]): update_pauli[j].w[k] = 1 if np.in1d(k, parity_sets[j]): parity_pauli[j].v[k] = 1 if np.in1d(k, remainder_sets[j]): remainder_pauli[j].v[k] = 1 x_j = Pauli(np.zeros(n), np.zeros(n)) x_j.w[j] = 1 y_j = Pauli(np.zeros(n), np.zeros(n)) y_j.v[j] = 1 y_j.w[j] = 1 # defines the two mapped Pauli components of a_i and a_i^\dag, # according to a_i -> (a[i][0]+i*a[i][1])/2, a_i^\dag -> # (a_[i][0]-i*a[i][1])/2 a.append((update_pauli[j] * x_j * parity_pauli[j], update_pauli[j] * y_j * remainder_pauli[j])) #################################################################### # ########### BUILDING THE MAPPED HAMILTONIAN ############### #################################################################### # ###################### One-body ############################# for i in range(n): for j in range(n): if h1[i, j] != 0: for alpha in range(2): for beta in range(2): pauli_prod = sgn_prod(a[i][alpha], a[j][beta]) pauli_term = [h1[i, j] * 1 / 4 * pauli_prod[1] * np.power(-1j, alpha) * np.power(1j, beta), pauli_prod[0]] pauli_list = pauli_term_append( pauli_term, pauli_list, threshold) # ###################### Two-body ############################ for i in range(n): for j in range(n): for k in range(n): for m in range(n): if h2[i, j, k, m] != 0: for alpha in range(2): for beta in range(2): for gamma in range(2): for delta in range(2): # Note: chemists' notation for the # labeling, # h2(i,j,k,m) adag_i adag_k a_m a_j pauli_prod_1 = sgn_prod( a[i][alpha], a[k][beta]) pauli_prod_2 = sgn_prod( pauli_prod_1[0], a[m][gamma]) pauli_prod_3 = sgn_prod( pauli_prod_2[0], a[j][delta]) phase1 = pauli_prod_1[1] *\ pauli_prod_2[1] * pauli_prod_3[1] phase2 = np.power(-1j, alpha + beta) *\ np.power(1j, gamma + delta) pauli_term = [ h2[i, j, k, m] * 1 / 16 * phase1 * phase2, pauli_prod_3[0]] pauli_list = pauli_term_append( pauli_term, pauli_list, threshold) #################################################################### # ################ WRITE TO FILE ################## #################################################################### if out_file is not None: out_stream = open(out_file, 'w') for pauli_term in pauli_list: out_stream.write(pauli_term[1].to_label() + '\n') out_stream.write('%.15f' % pauli_term[0].real + '\n') out_stream.close() return pauli_list
def test_pauli_sgn_prod(self): p1 = Pauli(np.array([0]), np.array([1])) p2 = Pauli(np.array([1]), np.array([1])) self.log.info("sign product:") p3, sgn = sgn_prod(p1, p2) self.log.info("p1: %s", p1.to_label()) self.log.info("p2: %s", p2.to_label()) self.log.info("p3: %s", p3.to_label()) self.log.info("sgn_prod(p1, p2): %s", str(sgn)) self.assertEqual(p1.to_label(), 'X') self.assertEqual(p2.to_label(), 'Y') self.assertEqual(p3.to_label(), 'Z') self.assertEqual(sgn, 1j) self.log.info("sign product reverse:") p3, sgn = sgn_prod(p2, p1) self.log.info("p2: %s", p2.to_label()) self.log.info("p1: %s", p1.to_label()) self.log.info("p3: %s", p3.to_label()) self.log.info("sgn_prod(p2, p1): %s", str(sgn)) self.assertEqual(p1.to_label(), 'X') self.assertEqual(p2.to_label(), 'Y') self.assertEqual(p3.to_label(), 'Z') self.assertEqual(sgn, -1j)
def fermionic_maps(h1, h2, map_type, out_file=None, threshold=0.000000000001): """Creates a list of Paulis with coefficients from fermionic one and two-body operator. Args: h1 (list): second-quantized fermionic one-body operator h2 (list): second-quantized fermionic two-body operator map_type (str): "JORDAN_WIGNER", "PARITY", "BINARY_TREE" out_file (str): name of the optional file to write the Pauli list on threshold (float): threshold for Pauli simplification Returns: list: A list of Paulis with coefficients """ # pylint: disable=invalid-name #################################################################### # ########### DEFINING MAPPED FERMIONIC OPERATORS ############# #################################################################### pauli_list = [] n = len(h1) # number of fermionic modes / qubits a = [] if map_type == 'JORDAN_WIGNER': for i in range(n): xv = np.append(np.append(np.ones(i), 0), np.zeros(n - i - 1)) xw = np.append(np.append(np.zeros(i), 1), np.zeros(n - i - 1)) yv = np.append(np.append(np.ones(i), 1), np.zeros(n - i - 1)) yw = np.append(np.append(np.zeros(i), 1), np.zeros(n - i - 1)) # defines the two mapped Pauli components of a_i and a_i^\dag, # according to a_i -> (a[i][0]+i*a[i][1])/2, # a_i^\dag -> (a_[i][0]-i*a[i][1])/2 a.append((Pauli(xv, xw), Pauli(yv, yw))) if map_type == 'PARITY': for i in range(n): if i > 1: Xv = np.append(np.append(np.zeros(i - 1), [1, 0]), np.zeros(n - i - 1)) Xw = np.append(np.append(np.zeros(i - 1), [0, 1]), np.ones(n - i - 1)) Yv = np.append(np.append(np.zeros(i - 1), [0, 1]), np.zeros(n - i - 1)) Yw = np.append(np.append(np.zeros(i - 1), [0, 1]), np.ones(n - i - 1)) elif i > 0: Xv = np.append((1, 0), np.zeros(n - i - 1)) Xw = np.append([0, 1], np.ones(n - i - 1)) Yv = np.append([0, 1], np.zeros(n - i - 1)) Yw = np.append([0, 1], np.ones(n - i - 1)) else: Xv = np.append(0, np.zeros(n - i - 1)) Xw = np.append(1, np.ones(n - i - 1)) Yv = np.append(1, np.zeros(n - i - 1)) Yw = np.append(1, np.ones(n - i - 1)) # defines the two mapped Pauli components of a_i and a_i^\dag, # according to a_i -> (a[i][0]+i*a[i][1])/2, # a_i^\dag -> (a_[i][0]-i*a[i][1])/2 a.append((Pauli(Xv, Xw), Pauli(Yv, Yw))) if map_type == 'BINARY_TREE': # FIND BINARY SUPERSET SIZE bin_sup = 1 while n > np.power(2, bin_sup): bin_sup += 1 # DEFINE INDEX SETS FOR EVERY FERMIONIC MODE update_sets = [] update_pauli = [] parity_sets = [] parity_pauli = [] flip_sets = [] remainder_sets = [] remainder_pauli = [] for j in range(n): update_sets.append(update_set(j, np.power(2, bin_sup))) update_sets[j] = update_sets[j][update_sets[j] < n] parity_sets.append(parity_set(j, np.power(2, bin_sup))) parity_sets[j] = parity_sets[j][parity_sets[j] < n] flip_sets.append(flip_set(j, np.power(2, bin_sup))) flip_sets[j] = flip_sets[j][flip_sets[j] < n] remainder_sets.append(np.setdiff1d(parity_sets[j], flip_sets[j])) update_pauli.append(Pauli(np.zeros(n), np.zeros(n))) parity_pauli.append(Pauli(np.zeros(n), np.zeros(n))) remainder_pauli.append(Pauli(np.zeros(n), np.zeros(n))) for k in range(n): if np.in1d(k, update_sets[j]): update_pauli[j].w[k] = 1 if np.in1d(k, parity_sets[j]): parity_pauli[j].v[k] = 1 if np.in1d(k, remainder_sets[j]): remainder_pauli[j].v[k] = 1 x_j = Pauli(np.zeros(n), np.zeros(n)) x_j.w[j] = 1 y_j = Pauli(np.zeros(n), np.zeros(n)) y_j.v[j] = 1 y_j.w[j] = 1 # defines the two mapped Pauli components of a_i and a_i^\dag, # according to a_i -> (a[i][0]+i*a[i][1])/2, a_i^\dag -> # (a_[i][0]-i*a[i][1])/2 a.append((update_pauli[j] * x_j * parity_pauli[j], update_pauli[j] * y_j * remainder_pauli[j])) #################################################################### # ########### BUILDING THE MAPPED HAMILTONIAN ############### #################################################################### # ###################### One-body ############################# for i in range(n): for j in range(n): if h1[i, j] != 0: for alpha in range(2): for beta in range(2): pauli_prod = sgn_prod(a[i][alpha], a[j][beta]) pauli_term = [h1[i, j] * 1 / 4 * pauli_prod[1] * np.power(-1j, alpha) * np.power(1j, beta), pauli_prod[0]] pauli_list = pauli_term_append( pauli_term, pauli_list, threshold) # ###################### Two-body ############################ for i in range(n): for j in range(n): for k in range(n): for m in range(n): if h2[i, j, k, m] != 0: for alpha in range(2): for beta in range(2): for gamma in range(2): for delta in range(2): # Note: chemists' notation for the # labeling, # h2(i,j,k,m) adag_i adag_k a_m a_j pauli_prod_1 = sgn_prod( a[i][alpha], a[k][beta]) pauli_prod_2 = sgn_prod( pauli_prod_1[0], a[m][gamma]) pauli_prod_3 = sgn_prod( pauli_prod_2[0], a[j][delta]) phase1 = pauli_prod_1[1] *\ pauli_prod_2[1] * pauli_prod_3[1] phase2 = np.power(-1j, alpha + beta) *\ np.power(1j, gamma + delta) pauli_term = [ h2[i, j, k, m] * 1 / 16 * phase1 * phase2, pauli_prod_3[0]] pauli_list = pauli_term_append( pauli_term, pauli_list, threshold) #################################################################### # ################ WRITE TO FILE ################## #################################################################### if out_file is not None: out_stream = open(out_file, 'w') for pauli_term in pauli_list: out_stream.write(pauli_term[1].to_label() + '\n') out_stream.write('%.15f' % pauli_term[0].real + '\n') out_stream.close() return pauli_list
class TestPauli(QiskitTestCase): """Tests for Pauli class""" def setUp(self): v = np.zeros(3) w = np.zeros(3) v[0] = 1 w[1] = 1 v[2] = 1 w[2] = 1 self.p3 = Pauli(v, w) def test_constructor_list(self): v = [1, 0, 1, 0] w = [0, 1, 1, 0] p = Pauli(v, w) length = 4 self.assertEqual(p.numberofqubits, length) self.assertEqual(p.to_label(), 'ZXYI') self.assertEqual(p.id, 'ZXYI') def test_constructor_npbool(self): v = np.asarray([True, False, True, False]) w = np.asarray([False, True, True, False]) p = Pauli(v, w) length = 4 self.assertEqual(p.numberofqubits, length) self.assertEqual(p.to_label(), 'ZXYI') self.assertEqual(p.id, 'ZXYI') def test_random_pauli5(self): length = 2 q = random_pauli(length) self.log.info(q) self.assertEqual(q.numberofqubits, length) self.assertEqual(len(q.v), length) self.assertEqual(len(q.w), length) self.assertEqual(len(q.to_label()), length) self.assertEqual(len(q.to_matrix()), 2 ** length) def test_label_to_pauli(self): label = 'ZXYI' p = label_to_pauli(label) v = np.asarray([1, 0, 1, 0]) w = np.asarray([0, 1, 1, 0]) p2 = Pauli(v, w) self.assertEqual(p, p2) def test_pauli_invert(self): self.log.info("===== p3 =====") self.log.info(self.p3) self.assertEqual(str(self.p3), 'v = 1.0\t0.0\t1.0\t\nw = 0.0\t1.0\t1.0\t') self.log.info("\tIn label form:") self.log.info(self.p3.to_label()) self.assertEqual(self.p3.to_label(), 'ZXY') self.log.info("\tIn matrix form:") self.log.info(self.p3.to_matrix()) m = np.array([ [0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. - 1.j, 0. + 0.j], [0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 1.j], [0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. - 1.j, 0. + 0.j, 0. + 0.j, 0. + 0.j], [0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 1.j, 0. + 0.j, 0. + 0.j], [0. + 0.j, 0. + 0.j, 0. + 1.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j], [0. + 0.j, 0. - 0.j, 0. + 0.j, 0. - 1.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j], [0. + 1.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j], [0. + 0.j, 0. - 1.j, 0. + 0.j, 0. - 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j]]) self.assertTrue((self.p3.to_matrix() == m).all()) self.log.info("\tIn spatrix matrix form:") self.log.info(self.p3.to_spmatrix()) self.assertTrue((self.p3.to_spmatrix().toarray() == m).all()) self.log.info("===== r =====") r = inverse_pauli(self.p3) self.assertEqual(str(r), 'v = 1.0\t0.0\t1.0\t\nw = 0.0\t1.0\t1.0\t') self.log.info("In label form:") self.log.info(r.to_label()) self.assertEqual(r.to_label(), 'ZXY') self.log.info("\tIn matrix form:") self.assertTrue((r.to_matrix() == m).all()) def test_pauli_group(self): self.log.info("Group in tensor order:") expected = ['III', 'XII', 'YII', 'ZII', 'IXI', 'XXI', 'YXI', 'ZXI', 'IYI', 'XYI', 'YYI', 'ZYI', 'IZI', 'XZI', 'YZI', 'ZZI', 'IIX', 'XIX', 'YIX', 'ZIX', 'IXX', 'XXX', 'YXX', 'ZXX', 'IYX', 'XYX', 'YYX', 'ZYX', 'IZX', 'XZX', 'YZX', 'ZZX', 'IIY', 'XIY', 'YIY', 'ZIY', 'IXY', 'XXY', 'YXY', 'ZXY', 'IYY', 'XYY', 'YYY', 'ZYY', 'IZY', 'XZY', 'YZY', 'ZZY', 'IIZ', 'XIZ', 'YIZ', 'ZIZ', 'IXZ', 'XXZ', 'YXZ', 'ZXZ', 'IYZ', 'XYZ', 'YYZ', 'ZYZ', 'IZZ', 'XZZ', 'YZZ', 'ZZZ'] grp = pauli_group(3, case=1) for j in grp: self.log.info('==== j (tensor order) ====') self.log.info(j.to_label()) self.assertEqual(expected.pop(0), j.to_label()) self.log.info("Group in weight order:") expected = ['III', 'XII', 'YII', 'ZII', 'IXI', 'IYI', 'IZI', 'IIX', 'IIY', 'IIZ', 'XXI', 'YXI', 'ZXI', 'XYI', 'YYI', 'ZYI', 'XZI', 'YZI', 'ZZI', 'XIX', 'YIX', 'ZIX', 'IXX', 'IYX', 'IZX', 'XIY', 'YIY', 'ZIY', 'IXY', 'IYY', 'IZY', 'XIZ', 'YIZ', 'ZIZ', 'IXZ', 'IYZ', 'IZZ', 'XXX', 'YXX', 'ZXX', 'XYX', 'YYX', 'ZYX', 'XZX', 'YZX', 'ZZX', 'XXY', 'YXY', 'ZXY', 'XYY', 'YYY', 'ZYY', 'XZY', 'YZY', 'ZZY', 'XXZ', 'YXZ', 'ZXZ', 'XYZ', 'YYZ', 'ZYZ', 'XZZ', 'YZZ', 'ZZZ'] grp = pauli_group(3) for j in grp: self.log.info('==== j (weight order) ====') self.log.info(j.to_label()) self.assertEqual(expected.pop(0), j.to_label()) def test_pauli_sgn_prod(self): p1 = Pauli(np.array([0]), np.array([1])) p2 = Pauli(np.array([1]), np.array([1])) self.log.info("sign product:") p3, sgn = sgn_prod(p1, p2) self.log.info("p1: %s", p1.to_label()) self.log.info("p2: %s", p2.to_label()) self.log.info("p3: %s", p3.to_label()) self.log.info("sgn_prod(p1, p2): %s", str(sgn)) self.assertEqual(p1.to_label(), 'X') self.assertEqual(p2.to_label(), 'Y') self.assertEqual(p3.to_label(), 'Z') self.assertEqual(sgn, 1j) self.log.info("sign product reverse:") p3, sgn = sgn_prod(p2, p1) self.log.info("p2: %s", p2.to_label()) self.log.info("p1: %s", p1.to_label()) self.log.info("p3: %s", p3.to_label()) self.log.info("sgn_prod(p2, p1): %s", str(sgn)) self.assertEqual(p1.to_label(), 'X') self.assertEqual(p2.to_label(), 'Y') self.assertEqual(p3.to_label(), 'Z') self.assertEqual(sgn, -1j) def test_equality_equal(self): """Test equality operator: equal Paulis""" p1 = self.p3 p2 = deepcopy(p1) self.log.info(p1 == p2) self.assertTrue(p1 == p2) self.log.info(p2.to_label()) self.log.info(p1.to_label()) self.assertEqual(p1.to_label(), 'ZXY') self.assertEqual(p2.to_label(), 'ZXY') def test_equality_different(self): """Test equality operator: different Paulis""" p1 = self.p3 p2 = deepcopy(p1) p2.v[0] = (p1.v[0] + 1) % 2 self.log.info(p1 == p2) self.assertFalse(p1 == p2) self.log.info(p2.to_label()) self.log.info(p1.to_label()) self.assertEqual(p1.to_label(), 'ZXY') self.assertEqual(p2.to_label(), 'IXY') def test_inequality_equal(self): """Test inequality operator: equal Paulis""" p1 = self.p3 p2 = deepcopy(p1) self.log.info(p1 != p2) self.assertFalse(p1 != p2) self.log.info(p2.to_label()) self.log.info(p1.to_label()) self.assertEqual(p1.to_label(), 'ZXY') self.assertEqual(p2.to_label(), 'ZXY') def test_inequality_different(self): """Test inequality operator: different Paulis""" p1 = self.p3 p2 = deepcopy(p1) p2.v[0] = (p1.v[0] + 1) % 2 self.log.info(p1 != p2) self.assertTrue(p1 != p2) self.log.info(p2.to_label()) self.log.info(p1.to_label()) self.assertEqual(p1.to_label(), 'ZXY') self.assertEqual(p2.to_label(), 'IXY') def test_pauli_singles(self): qubit_index = 3 num_qubits = 5 ps = pauli_singles(qubit_index, num_qubits) self.assertEqual(ps[0].to_label(), 'IIXII') self.assertEqual(ps[1].to_label(), 'IIYII') self.assertEqual(ps[2].to_label(), 'IIZII')
def _two_body(edge_list, p, q, r, s, h2_pqrs): r""" Map the term a^\dagger_p a^\dagger_q a_r a_s + h.c. to qubit operator. Args: edge_list (numpy.ndarray): 2xE matrix, each indicates (from, to) pair p (int): index of the two body term q (int): index of the two body term r (int): index of the two body term s (int): index of the two body term h2_pqrs (complex): coeffient of the two body term at (p, q, r, s) Returns: Operator: mapped qubit operator """ # Handle case of four unique indices. v = np.zeros(edge_list.shape[1]) id_op = Operator(paulis=[[1, Pauli(v, v)]]) final_coeff = 1.0 if len(set([p, q, r, s])) == 4: b_p = edge_operator_bi(edge_list, p) b_q = edge_operator_bi(edge_list, q) b_r = edge_operator_bi(edge_list, r) b_s = edge_operator_bi(edge_list, s) a_pq = edge_operator_aij(edge_list, p, q) a_rs = edge_operator_aij(edge_list, r, s) a_pq = -a_pq if q < p else a_pq a_rs = -a_rs if s < r else a_rs qubit_op = (a_pq * a_rs) * (-id_op - b_p * b_q + b_p * b_r + b_p * b_s + b_q * b_r + b_q * b_s - b_r * b_s + b_p * b_q * b_r * b_s) final_coeff = 0.125 # Handle case of three unique indices. elif len(set([p, q, r, s])) == 3: b_p = edge_operator_bi(edge_list, p) b_q = edge_operator_bi(edge_list, q) if p == r: b_s = edge_operator_bi(edge_list, s) a_qs = edge_operator_aij(edge_list, q, s) a_qs = -a_qs if s < q else a_qs qubit_op = (a_qs * b_s + b_q * a_qs) * (id_op - b_p) final_coeff = 1j * 0.25 elif p == s: b_r = edge_operator_bi(edge_list, r) a_qr = edge_operator_aij(edge_list, q, r) a_qr = -a_qr if r < q else a_qr qubit_op = (a_qr * b_r + b_q * a_qr) * (id_op - b_p) final_coeff = 1j * -0.25 elif q == r: b_s = edge_operator_bi(edge_list, s) a_ps = edge_operator_aij(edge_list, p, s) a_ps = -a_ps if s < p else a_ps qubit_op = (a_ps * b_s + b_p * a_ps) * (id_op - b_q) final_coeff = 1j * -0.25 elif q == s: b_r = edge_operator_bi(edge_list, r) a_pr = edge_operator_aij(edge_list, p, r) a_pr = -a_pr if r < p else a_pr qubit_op = (a_pr * b_r + b_p * a_pr) * (id_op - b_q) final_coeff = 1j * 0.25 else: pass # Handle case of two unique indices. elif len(set([p, q, r, s])) == 2: b_p = edge_operator_bi(edge_list, p) b_q = edge_operator_bi(edge_list, q) qubit_op = (id_op - b_p) * (id_op - b_q) if p == s: final_coeff = 0.25 else: final_coeff = -0.25 else: pass qubit_op.scaling_coeff(final_coeff * h2_pqrs) qubit_op.zeros_coeff_elimination() return qubit_op
def fermionic_maps(h1,h2,map_type,out_file=None,threshold=0.000000000001): """ Takes fermionic one and two-body operators in the form of numpy arrays with real entries, e.g. h1=np.zeros((n,n)) h2=np.zeros((n,n,n,n)) where n is the number of fermionic modes, and gives a pauli_list of mapped pauli terms and coefficients, according to the map_type specified, with values map_type: JORDAN_WIGNER PARITY BINARY_TREE the notation for the two-body operator is the chemists' one, h2(i,j,k,m) a^dag_i a^dag_k a_m a_j Options: - writes the mapped pauli_list to a file named out_file given as an input (does not do this as default) - neglects mapped terms below a threshold defined by the user (default is 10^-12) """ pauli_list=[] n=len(h1) # number of fermionic modes / qubits """ #################################################################### ############ DEFINING MAPPED FERMIONIC OPERATORS ############## #################################################################### """ a=[] if map_type=='JORDAN_WIGNER': for i in range(n): Xv=np.append(np.append(np.ones(i),0),np.zeros(n-i-1)) Xw=np.append(np.append(np.zeros(i),1),np.zeros(n-i-1)) Yv=np.append(np.append(np.ones(i),1),np.zeros(n-i-1)) Yw=np.append(np.append(np.zeros(i),1),np.zeros(n-i-1)) # defines the two mapped Pauli components of a_i and a_i^\dag, according to a_i -> (a[i][0]+i*a[i][1])/2, a_i^\dag -> (a_[i][0]-i*a[i][1])/2 a.append((Pauli(Xv,Xw),Pauli(Yv,Yw))) if map_type=='PARITY': for i in range(n): if i>1: Xv=np.append(np.append(np.zeros(i-1),[1,0]),np.zeros(n-i-1)) Xw=np.append(np.append(np.zeros(i-1),[0,1]),np.ones(n-i-1)) Yv=np.append(np.append(np.zeros(i-1),[0,1]),np.zeros(n-i-1)) Yw=np.append(np.append(np.zeros(i-1),[0,1]),np.ones(n-i-1)) elif i>0: Xv=np.append((1,0),np.zeros(n-i-1)) Xw=np.append([0,1],np.ones(n-i-1)) Yv=np.append([0,1],np.zeros(n-i-1)) Yw=np.append([0,1],np.ones(n-i-1)) else: Xv=np.append(0,np.zeros(n-i-1)) Xw=np.append(1,np.ones(n-i-1)) Yv=np.append(1,np.zeros(n-i-1)) Yw=np.append(1,np.ones(n-i-1)) # defines the two mapped Pauli components of a_i and a_i^\dag, according to a_i -> (a[i][0]+i*a[i][1])/2, a_i^\dag -> (a_[i][0]-i*a[i][1])/2 a.append((Pauli(Xv,Xw),Pauli(Yv,Yw))) if map_type=='BINARY_TREE': # FIND BINARY SUPERSET SIZE bin_sup=1 while n>np.power(2,bin_sup): bin_sup+=1 # DEFINE INDEX SETS FOR EVERY FERMIONIC MODE update_sets=[] update_pauli=[] parity_sets=[] parity_pauli=[] flip_sets=[] flip_pauli=[] remainder_sets=[] remainder_pauli=[] for j in range(n): update_sets.append(update_set(j,np.power(2,bin_sup))) update_sets[j]=update_sets[j][update_sets[j]<n] parity_sets.append(parity_set(j,np.power(2,bin_sup))) parity_sets[j]=parity_sets[j][parity_sets[j]<n] flip_sets.append(flip_set(j,np.power(2,bin_sup))) flip_sets[j]=flip_sets[j][flip_sets[j]<n] remainder_sets.append(np.setdiff1d(parity_sets[j],flip_sets[j])) update_pauli.append(Pauli(np.zeros(n),np.zeros(n))) parity_pauli.append(Pauli(np.zeros(n),np.zeros(n))) remainder_pauli.append(Pauli(np.zeros(n),np.zeros(n))) for k in range(n): if np.in1d(k,update_sets[j]): update_pauli[j].w[k]=1 if np.in1d(k,parity_sets[j]): parity_pauli[j].v[k]=1 if np.in1d(k,remainder_sets[j]): remainder_pauli[j].v[k]=1 Xj=Pauli(np.zeros(n),np.zeros(n)) Xj.w[j]=1 Yj=Pauli(np.zeros(n),np.zeros(n)) Yj.v[j]=1 Yj.w[j]=1 # defines the two mapped Pauli components of a_i and a_i^\dag, according to a_i -> (a[i][0]+i*a[i][1])/2, a_i^\dag -> (a_[i][0]-i*a[i][1])/2 a.append((update_pauli[j]*Xj*parity_pauli[j],update_pauli[j]*Yj*remainder_pauli[j])) """ #################################################################### ############ BUILDING THE MAPPED HAMILTONIAN ################ #################################################################### """ """ ####################### One-body ############################# """ for i in range(n): for j in range(n): if h1[i,j]!=0: for alpha in range(2): for beta in range(2): pauli_prod=sgn_prod(a[i][alpha],a[j][beta]) pauli_term=[ h1[i,j]*1/4*pauli_prod[1]*np.power(-1j,alpha)*np.power(1j,beta), pauli_prod[0] ] pauli_list=pauli_term_append(pauli_term,pauli_list,threshold) """ ####################### Two-body ############################# """ for i in range(n): for j in range(n): for k in range(n): for m in range(n): if h2[i,j,k,m]!=0: for alpha in range(2): for beta in range(2): for gamma in range(2): for delta in range(2): """ # Note: chemists' notation for the labeling, h2(i,j,k,m) adag_i adag_k a_m a_j """ pauli_prod_1=sgn_prod(a[i][alpha],a[k][beta]) pauli_prod_2=sgn_prod(pauli_prod_1[0],a[m][gamma]) pauli_prod_3=sgn_prod(pauli_prod_2[0],a[j][delta]) phase1=pauli_prod_1[1]*pauli_prod_2[1]*pauli_prod_3[1] phase2=np.power(-1j,alpha+beta)*np.power(1j,gamma+delta) pauli_term=[h2[i,j,k,m]*1/16*phase1*phase2,pauli_prod_3[0]] pauli_list=pauli_term_append(pauli_term,pauli_list,threshold) """ #################################################################### ################# WRITE TO FILE ################### #################################################################### """ if out_file!= None: out_stream=open(out_file,'w') for pauli_term in pauli_list: out_stream.write(pauli_term[1].to_label()+'\n') out_stream.write('%.15f' % pauli_term[0].real+'\n') out_stream.close() return pauli_list
def _bravyi_kitaev_mode(self, n): """ Bravyi-Kitaev mode Args: n (int): number of modes """ def parity_set(j, n): """Computes the parity set of the j-th orbital in n modes Args: j (int) : the orbital index n (int) : the total number of modes Returns: numpy.ndarray: Array of mode indexes """ indexes = np.array([]) if n % 2 != 0: return indexes if j < n / 2: indexes = np.append(indexes, parity_set(j, n / 2)) else: indexes = np.append( indexes, np.append(parity_set(j - n / 2, n / 2) + n / 2, n / 2 - 1)) return indexes def update_set(j, n): """Computes the update set of the j-th orbital in n modes Args: j (int) : the orbital index n (int) : the total number of modes Returns: numpy.ndarray: Array of mode indexes """ indexes = np.array([]) if n % 2 != 0: return indexes if j < n / 2: indexes = np.append(indexes, np.append(n - 1, update_set(j, n / 2))) else: indexes = np.append(indexes, update_set(j - n / 2, n / 2) + n / 2) return indexes def flip_set(j, n): """Computes the flip set of the j-th orbital in n modes Args: j (int) : the orbital index n (int) : the total number of modes Returns: numpy.ndarray: Array of mode indexes """ indexes = np.array([]) if n % 2 != 0: return indexes if j < n / 2: indexes = np.append(indexes, flip_set(j, n / 2)) elif j >= n / 2 and j < n - 1: indexes = np.append(indexes, flip_set(j - n / 2, n / 2) + n / 2) else: indexes = np.append( np.append(indexes, flip_set(j - n / 2, n / 2) + n / 2), n / 2 - 1) return indexes a = [] # FIND BINARY SUPERSET SIZE bin_sup = 1 while n > np.power(2, bin_sup): bin_sup += 1 # DEFINE INDEX SETS FOR EVERY FERMIONIC MODE update_sets = [] update_pauli = [] parity_sets = [] parity_pauli = [] flip_sets = [] remainder_sets = [] remainder_pauli = [] for j in range(n): update_sets.append(update_set(j, np.power(2, bin_sup))) update_sets[j] = update_sets[j][update_sets[j] < n] parity_sets.append(parity_set(j, np.power(2, bin_sup))) parity_sets[j] = parity_sets[j][parity_sets[j] < n] flip_sets.append(flip_set(j, np.power(2, bin_sup))) flip_sets[j] = flip_sets[j][flip_sets[j] < n] remainder_sets.append(np.setdiff1d(parity_sets[j], flip_sets[j])) update_pauli.append(Pauli(np.zeros(n), np.zeros(n))) parity_pauli.append(Pauli(np.zeros(n), np.zeros(n))) remainder_pauli.append(Pauli(np.zeros(n), np.zeros(n))) for k in range(n): if np.in1d(k, update_sets[j]): update_pauli[j].w[k] = 1 if np.in1d(k, parity_sets[j]): parity_pauli[j].v[k] = 1 if np.in1d(k, remainder_sets[j]): remainder_pauli[j].v[k] = 1 x_j = Pauli(np.zeros(n), np.zeros(n)) x_j.w[j] = 1 y_j = Pauli(np.zeros(n), np.zeros(n)) y_j.v[j] = 1 y_j.w[j] = 1 a.append((update_pauli[j] * x_j * parity_pauli[j], update_pauli[j] * y_j * remainder_pauli[j])) return a
class TestPauli(QiskitTestCase): """Tests for Pauli class""" def setUp(self): v = np.zeros(3) w = np.zeros(3) v[0] = 1 w[1] = 1 v[2] = 1 w[2] = 1 self.p3 = Pauli(v, w) def test_random_pauli5(self): length = 2 q = random_pauli(length) self.log.info(q) self.assertEqual(q.numberofqubits, length) self.assertEqual(len(q.v), length) self.assertEqual(len(q.w), length) self.assertEqual(len(q.to_label()), length) self.assertEqual(len(q.to_matrix()), 2 ** length) def test_pauli_invert(self): self.log.info("===== p3 =====") self.log.info(self.p3) self.assertEqual(str(self.p3), 'v = 1.0\t0.0\t1.0\t\nw = 0.0\t1.0\t1.0\t') self.log.info("\tIn label form:") self.log.info(self.p3.to_label()) self.assertEqual(self.p3.to_label(), 'ZXY') self.log.info("\tIn matrix form:") self.log.info(self.p3.to_matrix()) m = np.array([ [0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. - 1.j, 0. + 0.j], [0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 1.j], [0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. - 1.j, 0. + 0.j, 0. + 0.j, 0. + 0.j], [0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 1.j, 0. + 0.j, 0. + 0.j], [0. + 0.j, 0. + 0.j, 0. + 1.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j], [0. + 0.j, 0. - 0.j, 0. + 0.j, 0. - 1.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j], [0. + 1.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j], [0. + 0.j, 0. - 1.j, 0. + 0.j, 0. - 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j]]) self.assertTrue((self.p3.to_matrix() == m).all()) self.log.info("===== r =====") r = inverse_pauli(self.p3) self.assertEqual(str(r), 'v = 1.0\t0.0\t1.0\t\nw = 0.0\t1.0\t1.0\t') self.log.info("In label form:") self.log.info(r.to_label()) self.assertEqual(r.to_label(), 'ZXY') self.log.info("\tIn matrix form:") self.assertTrue((r.to_matrix() == m).all()) def test_pauli_group(self): self.log.info("Group in tensor order:") expected = ['III', 'XII', 'YII', 'ZII', 'IXI', 'XXI', 'YXI', 'ZXI', 'IYI', 'XYI', 'YYI', 'ZYI', 'IZI', 'XZI', 'YZI', 'ZZI', 'IIX', 'XIX', 'YIX', 'ZIX', 'IXX', 'XXX', 'YXX', 'ZXX', 'IYX', 'XYX', 'YYX', 'ZYX', 'IZX', 'XZX', 'YZX', 'ZZX', 'IIY', 'XIY', 'YIY', 'ZIY', 'IXY', 'XXY', 'YXY', 'ZXY', 'IYY', 'XYY', 'YYY', 'ZYY', 'IZY', 'XZY', 'YZY', 'ZZY', 'IIZ', 'XIZ', 'YIZ', 'ZIZ', 'IXZ', 'XXZ', 'YXZ', 'ZXZ', 'IYZ', 'XYZ', 'YYZ', 'ZYZ', 'IZZ', 'XZZ', 'YZZ', 'ZZZ'] grp = pauli_group(3, case=1) for j in grp: self.log.info('==== j (tensor order) ====') self.log.info(j.to_label()) self.assertEqual(expected.pop(0), j.to_label()) self.log.info("Group in weight order:") expected = ['III', 'XII', 'YII', 'ZII', 'IXI', 'IYI', 'IZI', 'IIX', 'IIY', 'IIZ', 'XXI', 'YXI', 'ZXI', 'XYI', 'YYI', 'ZYI', 'XZI', 'YZI', 'ZZI', 'XIX', 'YIX', 'ZIX', 'IXX', 'IYX', 'IZX', 'XIY', 'YIY', 'ZIY', 'IXY', 'IYY', 'IZY', 'XIZ', 'YIZ', 'ZIZ', 'IXZ', 'IYZ', 'IZZ', 'XXX', 'YXX', 'ZXX', 'XYX', 'YYX', 'ZYX', 'XZX', 'YZX', 'ZZX', 'XXY', 'YXY', 'ZXY', 'XYY', 'YYY', 'ZYY', 'XZY', 'YZY', 'ZZY', 'XXZ', 'YXZ', 'ZXZ', 'XYZ', 'YYZ', 'ZYZ', 'XZZ', 'YZZ', 'ZZZ'] grp = pauli_group(3) for j in grp: self.log.info('==== j (weight order) ====') self.log.info(j.to_label()) self.assertEqual(expected.pop(0), j.to_label()) def test_pauli_sgn_prod(self): p1 = Pauli(np.array([0]), np.array([1])) p2 = Pauli(np.array([1]), np.array([1])) self.log.info("sign product:") p3, sgn = sgn_prod(p1, p2) self.log.info("p1: %s", p1.to_label()) self.log.info("p2: %s", p2.to_label()) self.log.info("p3: %s", p3.to_label()) self.log.info("sgn_prod(p1, p2): %s", str(sgn)) self.assertEqual(p1.to_label(), 'X') self.assertEqual(p2.to_label(), 'Y') self.assertEqual(p3.to_label(), 'Z') self.assertEqual(sgn, 1j) self.log.info("sign product reverse:") p3, sgn = sgn_prod(p2, p1) self.log.info("p2: %s", p2.to_label()) self.log.info("p1: %s", p1.to_label()) self.log.info("p3: %s", p3.to_label()) self.log.info("sgn_prod(p2, p1): %s", str(sgn)) self.assertEqual(p1.to_label(), 'X') self.assertEqual(p2.to_label(), 'Y') self.assertEqual(p3.to_label(), 'Z') self.assertEqual(sgn, -1j) def test_equality_equal(self): """Test equality operator: equal Paulis""" p1 = self.p3 p2 = deepcopy(p1) self.log.info(p1 == p2) self.assertTrue(p1 == p2) self.log.info(p2.to_label()) self.log.info(p1.to_label()) self.assertEqual(p1.to_label(), 'ZXY') self.assertEqual(p2.to_label(), 'ZXY') def test_equality_different(self): """Test equality operator: different Paulis""" p1 = self.p3 p2 = deepcopy(p1) p2.v[0] = (p1.v[0] + 1) % 2 self.log.info(p1 == p2) self.assertFalse(p1 == p2) self.log.info(p2.to_label()) self.log.info(p1.to_label()) self.assertEqual(p1.to_label(), 'ZXY') self.assertEqual(p2.to_label(), 'IXY') def test_inequality_equal(self): """Test inequality operator: equal Paulis""" p1 = self.p3 p2 = deepcopy(p1) self.log.info(p1 != p2) self.assertFalse(p1 != p2) self.log.info(p2.to_label()) self.log.info(p1.to_label()) self.assertEqual(p1.to_label(), 'ZXY') self.assertEqual(p2.to_label(), 'ZXY') def test_inequality_different(self): """Test inequality operator: different Paulis""" p1 = self.p3 p2 = deepcopy(p1) p2.v[0] = (p1.v[0] + 1) % 2 self.log.info(p1 != p2) self.assertTrue(p1 != p2) self.log.info(p2.to_label()) self.log.info(p1.to_label()) self.assertEqual(p1.to_label(), 'ZXY') self.assertEqual(p2.to_label(), 'IXY')
def two_qubit_reduction(ham_in, m, out_file=None, threshold=0.000000000001): """ Eliminates the central and last qubit in a list of Pauli that has diagonal operators (Z,I) at those positions.abs It can be used to taper two qubits in parity and binary-tree mapped fermionic Hamiltonians when the spin orbitals are ordered in two spin sectors, according to the number of particles in the system. Args: ham_in (list): a list of Paulis representing the mapped fermionic Hamiltonian m (int): number of fermionic particles out_file (string or None): name of the optional file to write the Pauli list on threshold (float): threshold for Pauli simplification Returns: list: A tapered Hamiltonian in the form of list of Paulis with coefficients """ ham_out = [] if m % 4 == 0: par_1 = 1 par_2 = 1 elif m % 4 == 1: par_1 = -1 par_2 = -1 # could be also +1, +1/-1 are spin-parity sectors elif m % 4 == 2: par_1 = 1 par_2 = -1 else: par_1 = -1 par_2 = -1 # could be also +1, +1/-1 are spin-parity sectors if isinstance(ham_in, str): # conversion from Hamiltonian text file to pauli_list ham_in = Hamiltonian_from_file(ham_in) # number of qubits n = len(ham_in[0][1].v) for pauli_term in ham_in: # loop over Pauli terms coeff_out = pauli_term[0] # Z operator encountered at qubit n/2-1 if pauli_term[1].v[n // 2 - 1] == 1 and pauli_term[1].w[n // 2 - 1] == 0: coeff_out = par_2 * coeff_out # Z operator encountered at qubit n-1 if pauli_term[1].v[n - 1] == 1 and pauli_term[1].w[n - 1] == 0: coeff_out = par_1 * coeff_out v_temp = [] w_temp = [] for j in range(n): if j != n // 2 - 1 and j != n - 1: v_temp.append(pauli_term[1].v[j]) w_temp.append(pauli_term[1].w[j]) pauli_term_out = [coeff_out, Pauli(v_temp, w_temp)] ham_out = pauli_term_append(pauli_term_out, ham_out, threshold) #################################################################### # ################ WRITE TO FILE ################## #################################################################### if out_file is not None: out_stream = open(out_file, 'w') for pauli_term in ham_out: out_stream.write(pauli_term[1].to_label() + '\n') out_stream.write('%.15f' % pauli_term[0].real + '\n') out_stream.close() return ham_out
def test_hamiltonian(self): # pylint: disable=unexpected-keyword-arg # printing an example from a H2 file hfile = self._get_resource_path("H2Equilibrium.txt") hamiltonian = make_Hamiltonian(Hamiltonian_from_file(hfile)) self.log.info(hamiltonian) # [[-0.24522469381221926 0 0 0.18093133934472627 ] # [0 -1.0636560168497590 0.18093133934472627 0] # [0 0.18093133934472627 -1.0636560168497592 0] # [0.18093133934472627 0 0 -1.8369675149908681]] expected_result = [ [(-0.245224693812+0j), 0j, 0j, (0.180931339345+0j)], [0j, (-1.06365601685+0j), (0.180931339345+0j), 0j], [0j, (0.180931339345+0j), (-1.06365601685+0j), 0j], [(0.180931339345+0j), 0j, 0j, (-1.83696751499+0j)] ] for i in range(4): with self.subTest(i=i): for result, expected in zip(hamiltonian[i], expected_result[i]): self.assertAlmostEqual(result, expected) # printing an example from a graph input n = 3 v0 = np.zeros(n) v0[2] = 1 v1 = np.zeros(n) v1[0] = 1 v1[1] = 1 v2 = np.zeros(n) v2[0] = 1 v2[2] = 1 v3 = np.zeros(n) v3[1] = 1 v3[2] = 1 pauli_list = [(1, Pauli(v0, np.zeros(n))), (1, Pauli(v1, np.zeros(n))), (1, Pauli(v2, np.zeros(n))), (1, Pauli(v3, np.zeros(n)))] a = make_Hamiltonian(pauli_list) self.log.info(a) w, v = la.eigh(a, eigvals=(0, 0)) self.log.info(w) self.log.info(v) data = {'000': 10} self.log.info(Energy_Estimate(data, pauli_list)) data = {'001': 10} self.log.info(Energy_Estimate(data, pauli_list)) data = {'010': 10} self.log.info(Energy_Estimate(data, pauli_list)) data = {'011': 10} self.log.info(Energy_Estimate(data, pauli_list)) data = {'100': 10} self.log.info(Energy_Estimate(data, pauli_list)) data = {'101': 10} self.log.info(Energy_Estimate(data, pauli_list)) data = {'110': 10} self.log.info(Energy_Estimate(data, pauli_list)) data = {'111': 10} self.log.info(Energy_Estimate(data, pauli_list))
def test_pauli(self): v = np.zeros(3) w = np.zeros(3) v[0] = 1 w[1] = 1 v[2] = 1 w[2] = 1 p = Pauli(v, w) self.log.info(p) self.log.info("In label form:") self.log.info(p.to_label()) self.log.info("In matrix form:") self.log.info(p.to_matrix()) q = random_pauli(2) self.log.info(q) r = inverse_pauli(p) self.log.info("In label form:") self.log.info(r.to_label()) self.log.info("Group in tensor order:") grp = pauli_group(3, case=1) for j in grp: self.log.info(j.to_label()) self.log.info("Group in weight order:") grp = pauli_group(3) for j in grp: self.log.info(j.to_label()) self.log.info("sign product:") p1 = Pauli(np.array([0]), np.array([1])) p2 = Pauli(np.array([1]), np.array([1])) p3, sgn = sgn_prod(p1, p2) self.log.info(p1.to_label()) self.log.info(p2.to_label()) self.log.info(p3.to_label()) self.log.info(sgn) self.log.info("sign product reverse:") p3, sgn = sgn_prod(p2, p1) self.log.info(p2.to_label()) self.log.info(p1.to_label()) self.log.info(p3.to_label()) self.log.info(sgn)