def test_reduce(self): self.assertEqual( self.reduced_qubit_op, openfermion.QubitOperator("X0 Z1", self.a) + openfermion.QubitOperator("Y2", self.b) + openfermion.QubitOperator("Z0 X1 X2", self.c) + openfermion.QubitOperator("Y3", self.d))
def test_reduce_inactive_qubits(self): self.assertEqual( self.inactive_qubits_reduced_qubit_op, openfermion.QubitOperator("X0 Y1 Z2 X4", self.a) + openfermion.QubitOperator("Y1 Y3 X4", self.b) + openfermion.QubitOperator("Z0 Y1 X2 X3 X4", self.c) + openfermion.QubitOperator("Y1 X4 Y5", self.d))
def test_reduce_stationary_qubits(self): self.assertEqual( self.stationary_qubits_inactivated_qubit_op, openfermion.QubitOperator("X0 Z2", self.a) + openfermion.QubitOperator("Y3", self.b) + openfermion.QubitOperator("Z0 X2 X3", self.c) + openfermion.QubitOperator("Y7", self.d))
def test_eigvalsh(self): a, b, c, d, e = 1, 2, 3, 4, 5 qubit_op = (openfermion.QubitOperator("X0 Y1 Z2", a) + openfermion.QubitOperator("Y1 X2", b) + openfermion.QubitOperator("Y1 X4", c) + openfermion.QubitOperator("Z0 Y1 X2", d) + openfermion.QubitOperator("Z0 Y1 Z4", e)) inactive_qubits_reduced_qubit_op, _ = \ reduce_inactive_qubits(qubit_op) stationary_qubits_inactivated_qubit_op, _ = \ inactivate_stationary_qubits(qubit_op) reduced_qubit_op, n_stationary, n_inactive = reduce(qubit_op) # # n_stationary==1, n_inactive==1 in this case # self.assertEqual(n_stationary, 1) # self.assertEqual(n_inactive, 1) # e.g. # [-11, -11, -11, -11, # -3, -3, -3, -3, # 3, 3, 3, 3, # 11, 11, 11, 11] eig = np.linalg.eigvalsh( openfermion.get_sparse_operator(qubit_op).toarray()) # e.g. # [-11, -11, # -3, -3, # 3, 3, # 11, 11] eig_inactive_qubits_reduced = np.linalg.eigvalsh( openfermion.get_sparse_operator( inactive_qubits_reduced_qubit_op).toarray()) # Note that `inactivate_stationary_qubits` won't reduce the dimension of # the multi-qubit space of the qubit operator. eig_stationary_qubits_inactivated = np.linalg.eigvalsh( openfermion.get_sparse_operator( stationary_qubits_inactivated_qubit_op).toarray()) # e.g. # [-11, # -3, # 3, # 11] eig_reduced = np.linalg.eigvalsh( openfermion.get_sparse_operator(reduced_qubit_op).toarray()) self.assertTrue( np.allclose(eig, np.repeat(eig_inactive_qubits_reduced, 2**n_inactive))) self.assertTrue( np.allclose(eig, np.repeat(eig_reduced, 2**(n_stationary + n_inactive))))
def test_group(self): grouped = group(self.qubit_op, by_qubit_indices=(3, 5)) self.assertEqual( grouped, { ((3, "I"), (5, "X")): openfermion.QubitOperator("X0 Y1 Z2 X5 ", self.a) + openfermion.QubitOperator(" Y1 X5 Y7", self.d), ((3, "Y"), (5, "X")): openfermion.QubitOperator(" Y1 Y3 X5 ", self.b), ((3, "X"), (5, "X")): openfermion.QubitOperator("Z0 Y1 X2 X3 X5 ", self.c) })
def setUp(self) -> None: self.a, self.b, self.c, self.d = np.random.rand(4) self.qubit_op = ( openfermion.QubitOperator("X0 Y1 Z2 X5 ", self.a) + openfermion.QubitOperator(" Y1 Y3 X5 ", self.b) + openfermion.QubitOperator("Z0 Y1 X2 X3 X5 ", self.c) + openfermion.QubitOperator(" Y1 X5 Y7", self.d)) self.inactive_qubits_reduced_qubit_op, _ = \ reduce_inactive_qubits(self.qubit_op) self.stationary_qubits_inactivated_qubit_op, _ = \ inactivate_stationary_qubits(self.qubit_op) self.reduced_qubit_op, _, _ = reduce(self.qubit_op)
def inactivate_stationary_qubits( qubit_operator: openfermion.QubitOperator ) -> typing.Tuple[openfermion.QubitOperator, int]: """ Set the stationary qubits in a qubit operator to be "inactive". Here, "stationary" means the qubit is ONLY acted by ONE kind of operators in {"X", "Y", "Z", "I"}, which differs from the meaning of "generally stationary" in `block_reduce`. "Inactive" means the qubit is not acted by any effective Pauli operators (i.e. only acted on by the identity operator). The definition here is same as in `reduce_inactive_qubits`. See also: `block_reduce` `reduce_inactive_qubits` :param qubit_operator: The qubit operator to be processed. :return: The processed qubit operator, and the number of inactivated stationary qubits. Example: >>> op = (openfermion.QubitOperator("X0 Y1", 0.1) + ... openfermion.QubitOperator("Z0 Y1 X3", 0.2)) >>> inactivate_stationary_qubits(op) (0.1 [X0] + 0.2 [Z0 X3], 1) """ common_ops = typing.cast(set, None) # type: typing.Set[typing.Tuple[int, str]] for term in qubit_operator.terms.keys(): if common_ops is not None: common_ops.intersection_update(set(term)) else: common_ops = set(term) num_stationary_qubits = len(common_ops) reduced_qubit_op = openfermion.QubitOperator() for term, coefficient in qubit_operator.terms.items(): reduced_term = tuple(pauli_on_qubit for pauli_on_qubit in term if pauli_on_qubit not in common_ops) _op = openfermion.QubitOperator() _op.terms[reduced_term] = coefficient reduced_qubit_op += _op return reduced_qubit_op, num_stationary_qubits
def test_nonzero_op_constant(self): # matrix_a form: # [[ 0.96, 0. ] # [ 0. , -0.49 ]] # qubit_op.constant == 0.235 qubit_op = (openfermion.QubitOperator("", 0.235) + openfermion.QubitOperator("Z0", 0.725)) self.assertEqual(reduce_inactive_qubits(qubit_op), (qubit_op, 0)) self.assertEqual(inactivate_stationary_qubits(qubit_op), (qubit_op, 0)) self.assertEqual(reduce(qubit_op), (qubit_op, 0, 0))
def break_operators_into_subsets(qubit_operator): """Break a qubit operator into subsets, where the terms in each subset all mutually commute.""" qop_zero = openfermion.QubitOperator('', 0) subsets = [] for term in qubit_operator: #print('term ',term) new_subset = True for subset in subsets: #print('subset ',subset) is_commutable_with_all_term_in_subset = True for term_in_subset in subset: #print('term_in_subset ',term_in_subset) if openfermion.utils.commutator(term, term_in_subset) != qop_zero: is_commutable_with_all_term_in_subset = False #print(term,'and',term_in_subset,'dont commute.') break if is_commutable_with_all_term_in_subset: subset += term new_subset = False break if new_subset: subsets.append(term) return subsets
def system_to_QubitOperator(sys): ''' Export a spin lattice hamiltonian built in kwant to openfermion. Parameters ---------- sys: kwant.system.FiniteSystem or kwant.system.InfiniteSystem Returns ---------- ham: openfermion.QubitOperator The hamiltonian of sys as an openfermion object. ''' if not isinstance(sys, kwant.system.System): raise TypeError(f'Expecting an instance of System, got {type(sys)}.') ham = openfermion.QubitOperator() #on site terms for lat_ix in sys.id_by_site.values(): val = sys.hamiltonian(lat_ix, lat_ix) ham += _single_term_to_QubitOperator(val, lat_ix, lat_ix) #interaction terms for edge in range(sys.graph.num_edges): lat_ix1 = sys.graph.head(edge) lat_ix2 = sys.graph.tail(edge) val = sys.hamiltonian(lat_ix1, lat_ix2) / 2 ham += _single_term_to_QubitOperator(val, lat_ix1, lat_ix2) return ham
def group(qubit_operator: openfermion.QubitOperator, by_qubit_indices: typing.Iterable[int]): grouped = {} for term, coefficient in qubit_operator.terms.items(): paulis_at_indices = { qubit_index: pauli for qubit_index, pauli in term if qubit_index in by_qubit_indices } for i in by_qubit_indices: if i not in paulis_at_indices: paulis_at_indices[i] = "I" paulis_at_indices = sorted( ((qubit_index, pauli) for qubit_index, pauli in paulis_at_indices.items()), key=lambda item: item[0]) paulis_at_indices = tuple(paulis_at_indices) op = openfermion.QubitOperator() op.terms[term] = coefficient if paulis_at_indices not in grouped: grouped[paulis_at_indices] = op else: grouped[paulis_at_indices] += op return grouped
def break_operators_into_subsets_dummy(qubit_operator): """Break a qubit operator into subsets, where the terms in each subset all mutually commute.""" qop_zero = openfermion.QubitOperator('', 0) subsets = [] for term in qubit_operator: subsets.append(term) return subsets
def test_exponent_statevectors(self): qubit_operators = [] # only symetric qubit operators will works, because qiskit and openfermion use different qubit orderings qubit_operators.append(openfermion.QubitOperator('Z0 Y1 Z2')) qubit_operators.append(openfermion.QubitOperator('X0 Y1 X2')) qubit_operators.append(openfermion.QubitOperator('Y0 X1 X2 Y3')) for qubit_operator in qubit_operators: qubit_operator_tuple = list(qubit_operator.terms.keys())[0] n_qubits = len(qubit_operator_tuple) for angle in range(10): angle = 2 * numpy.pi / 10 # <<< create a statevector using QiskitSimulation.get_exponent_qasm >>> qasm = QasmUtils.qasm_header(n_qubits) qasm += QasmUtils.exponent_qasm(qubit_operator_tuple, angle) qiskit_statevector = QiskitSimBackend.statevector_from_qasm( qasm) qiskit_statevector = qiskit_statevector * numpy.exp( 1j * angle) # correct for a global phase qiskit_statevector = qiskit_statevector.round( 2) # round for the purpose of testing # <<< create a statevector using MatrixCalculation.get_qubit_operator_exponent_matrix >>> exp_matrix = MatrixUtils.get_excitation_matrix( 1j * qubit_operator, n_qubits, angle).todense() # prepare initial statevector corresponding to state |0> array_statevector = numpy.zeros(2**n_qubits) array_statevector[0] = 1 # update statevector array_statevector = numpy.array( exp_matrix.dot(array_statevector))[0].round( 2) # round for the purpose of testing # <<<< compare both state vectors >>>> self.assertEqual(len(array_statevector), len(qiskit_statevector)) # check the components of the two vectors are equal for i in range(len(qiskit_statevector)): self.assertEqual(qiskit_statevector[i], array_statevector[i])
def test_block_reduce(self): const = 1 qubit_op = (openfermion.QubitOperator("", const) + openfermion.QubitOperator("X0 Y1 Z2 X5 X8", self.a) + openfermion.QubitOperator(" Y1 Y3 X5 X8", self.b) + openfermion.QubitOperator("Z0 Y1 X2 X3 X5 Y7 X8", self.c) + openfermion.QubitOperator(" Y1 X5 Y7 ", self.d)) self.assertEqual( block_reduce(qubit_op), { ((1, "I"), (4, "I"), (5, "I"), (6, "I"), (7, "I"), (8, "I")): openfermion.QubitOperator("", const), ((1, "Y"), (4, "I"), (5, "X"), (6, "I"), (7, "I"), (8, "X")): openfermion.QubitOperator("X0 Z1 ", self.a) + openfermion.QubitOperator(" Y2", self.b), ((1, "Y"), (4, "I"), (5, "X"), (6, "I"), (7, "Y"), (8, "X")): openfermion.QubitOperator("Z0 X1 X2", self.c), ((1, "Y"), (4, "I"), (5, "X"), (6, "I"), (7, "Y"), (8, "I")): openfermion.QubitOperator("", self.d) })
def test_pauli_gates_circuit_statevector(self): qubit_operator = openfermion.QubitOperator('X0 Y1') qasm_circuit = QasmUtils.qasm_header(2) qasm_circuit += QasmUtils.pauli_word_qasm(qubit_operator) statevector = QiskitSimBackend.statevector_from_qasm(qasm_circuit) expected_statevector = numpy.array([0, 0, 0, 1j]) self.assertEqual(len(expected_statevector), len(statevector)) for i in range(len(statevector)): self.assertEqual(statevector[i], expected_statevector[i])
def _single_term_to_QubitOperator(val, ix1, ix2): ''' Export single term of the hamiltonian to openfermion. Single term means either an onsite/single spin term at lattice site ix1 = ix2 - such as Zeeman hamiltonian - or an interaction between two spins at sites ix1 and ix2. Parameters ---------- val: 2x2 array for ix1 = ix2 or 4x4 array for ix1 =/= ix2 ix1, ix2: int lattice position indices. Returns ---------- op: openfermion.QubitOperator ''' try: dims = val.shape except: raise ValueError(f'Expected a matrix, got {type(val)}.') pauli_coefs = to_pauli_basis(val) op = openfermion.QubitOperator() #On site terms if ix1 == ix2: assert dims == (2, 2), f'Onsite terms must be 2x2 matrices, got {dims}' for name, coef in zip(pauli_names, pauli_coefs): if name == '1': op += openfermion.QubitOperator('', coef) else: op += openfermion.QubitOperator(name + str(ix1), coef) return op #Interaction terms assert dims == (4, 4), f'Onsite terms must be 4x4 matrices, got {dims}' for name, coef in zip(pauli_names4, pauli_coefs): if name == ('1', '1'): op += openfermion.QubitOperator('', coef) elif name[0] == '1': op += openfermion.QubitOperator(name[1] + str(ix2), coef) elif name[1] == '1': op += openfermion.QubitOperator(name[0] + str(ix1), coef) else: op += openfermion.QubitOperator( name[0] + str(ix1) + ' ' + name[1] + str(ix2), coef) return op
def test_hamiltonian_variational_study_init_qubit_operator(): ansatz = SwapNetworkTrotterAnsatz(test_hamiltonian) study = HamiltonianVariationalStudy('study', ansatz, openfermion.QubitOperator((0, 'X'))) assert study.hamiltonian == openfermion.QubitOperator((0, 'X'))
def test_single_interaction_term(): assert sl._single_term_to_QubitOperator( 5 * np.kron(sl.sigma_x, sl.sigma_z), 0, 1) == openfermion.QubitOperator('X0 Z1', 5)
def cleanup(qop, thresh=1e-12): retval = openfermion.QubitOperator() terms = retval.terms for k, v in qop.terms.items(): if abs(v) > thresh: terms[k] = v return retval
def reduce_inactive_qubits( qubit_operator: openfermion.QubitOperator, inactive_qubits: typing.Optional[typing.Iterable[int]] = None ) -> typing.Tuple[openfermion.QubitOperator, int]: """ Reduce the inactive qubits in a qubit operator. :param qubit_operator: The qubit operator to be simplified (i.e. reduced). :param inactive_qubits: The qubits to be reduced from the qubit operator. If given out explicitly, the qubits in `inactive_qubits` will all be removed from the qubit operator (no matter whether it is really "inactive"). If left to be default, the inactive qubits to be removed will be automatically determined. Here, "inactive" means that there are not any effective Pauli operators ("X", "Y", "Z") acting on the qubits in `qubit_operator`. :return: The reduced qubit operator, and the number of reduced qubits. Example: >>> op = (openfermion.QubitOperator("X0 Y1", 0.1) + ... openfermion.QubitOperator("Z0 Y1 X3", 0.2)) >>> reduce_inactive_qubits(op) (0.1 [X0 Y1] + 0.2 [Z0 Y1 X2], 1) >>> reduce_inactive_qubits(op, (0, 2)) (0.1 [Y0] + 0.2 [Y0 X1], 2) >>> reduce_inactive_qubits(op, (0,)) (0.1 [Y0] + 0.2 [Y0 X2], 1) """ if inactive_qubits is None: active_qubits = set() for term in qubit_operator.terms.keys(): for qubit_index, pauli in term: active_qubits.add(qubit_index) active_qubits = sorted(active_qubits) else: active_qubits = sorted( q for q in range(0, openfermion.count_qubits(qubit_operator)) if q not in inactive_qubits) reduced_qubit_op = openfermion.QubitOperator() for term, coefficient in qubit_operator.terms.items(): reduced_term = tuple((active_qubits.index(qubit_index), pauli) for qubit_index, pauli in term if qubit_index in active_qubits) _op = openfermion.QubitOperator() _op.terms[reduced_term] = coefficient reduced_qubit_op += _op if inactive_qubits is None: # if in the default case: assert len(active_qubits) == openfermion.count_qubits(reduced_qubit_op) else: # For cases like: # # reduce_inactive_qubits( # openfermion.QubitOperator("Z0 Y1 X3", 0.2), # (3,) # ) # # active_qubits == (0, 1, 2), but the reduced operator is # # openfermion.QubitOperator("Z0 Y1", 0.2) # # counting whose qubits will give out 2 instead of 3. pass num_reduced_qubits = \ openfermion.count_qubits(qubit_operator) - len(active_qubits) return reduced_qubit_op, num_reduced_qubits
# print(k1,k2,v) if k1 == k2: b_ij[nvar][nvar] = v key_i.append(k1) nvar += 1 for (k1, k2), v in Q.items(): if k1 != k2: for i in range(nvar): for j in range(nvar): if k1 == key_i[i] and k2 == key_i[j]: if i < j: b_ij[i][j] = v else: b_ij[j][i] = v hamil = of.QubitOperator() J_ij = np.zeros((nvar, nvar)) h_i = np.zeros(nvar) for i in range(nvar): for j in range(nvar): if i >= j: continue J_ij[i][j] = b_ij[i][j] if J_ij[i][j] == 0: continue hamil += of.QubitOperator(((i, 'Z'), (j, 'Z')), J_ij[i][j]) for i in range(nvar): bias = 0 for k in range(nvar):
def Hamiltonian(u,v,t): ''' Function that returns the hamiltonian with the given parameters by using openfermion.QubitOperators. Parameters ---------- u : float One the parameters in the Hamiltonian, see report for description. v : float One the parameters in the Hamiltonian, see report for description. t : float One the parameters in the Hamiltonian, see report for description. Returns ------- hamiltonian : Sum of openfermion.QubitOperators The hamiltonian as defined in the report with the parameters as provided. ''' hamiltonian = -2 * t * of.QubitOperator('X0') hamiltonian += -2 * t * of.QubitOperator('X1') hamiltonian += -2 * t * of.QubitOperator('X2') hamiltonian += -2 * t * of.QubitOperator('X3') hamiltonian += v/16 * of.QubitOperator('Z0 Z3') hamiltonian += v/16 * of.QubitOperator('Z1 Z2') hamiltonian += v/16 * of.QubitOperator('Z0 Z1 Z2') hamiltonian += v/16 * of.QubitOperator('Z0 Z2 Z3') hamiltonian += v/16 * of.QubitOperator('Z0 Z1 Z3') hamiltonian += v/16 * of.QubitOperator('Z1 Z2 Z3') hamiltonian += (v + 4*u)/16 * of.QubitOperator('Z0 Z1') hamiltonian += (v + 4*u)/16 * of.QubitOperator('Z2 Z3') hamiltonian += (v + 4*u)/16 * of.QubitOperator('Z0 Z2') hamiltonian += (v + 4*u)/16 * of.QubitOperator('Z1 Z3') hamiltonian += (v + 4*u)/16 * of.QubitOperator('Z0') hamiltonian += (v + 4*u)/16 * of.QubitOperator('Z1') hamiltonian += (v + 4*u)/16 * of.QubitOperator('Z2') hamiltonian += (v + 4*u)/16 * of.QubitOperator('Z3') hamiltonian += (v + 4*u)/16 * of.QubitOperator('Z0 Z1 Z2 Z3') return hamiltonian
def test_hamiltonian_objective_init_qubit_operator(): obj = HamiltonianObjective(openfermion.QubitOperator((0, 'X'))) assert obj.hamiltonian == openfermion.QubitOperator((0, 'X'))
def test_single_onsite_term(): assert sl._single_term_to_QubitOperator( sl.sigma_x, 0, 0) == openfermion.QubitOperator('X0')