def test_label_display_mode(self, label, pre_processing): """test label_display_mode""" fer_op = FermionicOp(pre_processing(label), display_format="dense") fer_op.display_format = "sparse" self.assertListEqual(fer_op.to_list(), str2list(label)) fer_op.display_format = "dense" self.assertNotEqual(fer_op.to_list(), str2list(label))
def test_init_multiple_digits(self): """Test __init__ for sparse label with multiple digits""" actual = FermionicOp([("-_2 +_10", 1 + 2j), ("-_12", 56 + 0j)], register_length=13, display_format="dense") desired = [ ("II-IIIIIII+II", 1 + 2j), ("IIIIIIIIIIII-", 56), ] self.assertListEqual(actual.to_list(), desired)
def test_second_q_ops(self): """Test second_q_ops.""" op = self.prop.second_q_ops()["AngularMomentum"] with open( self.get_resource_path("angular_momentum_op.json", "second_q/properties/resources"), "r", encoding="utf8", ) as file: expected = json.load(file) expected_op = FermionicOp(expected).simplify() self.assertSetEqual(frozenset(op.to_list("dense")), frozenset(expected_op.to_list("dense")))
def test_init_multiterm(self): """Test __init__ with multi terms""" with self.subTest("Test 1"): labels = [("N", 2), ("-", 3.14)] self.assertListEqual( FermionicOp(labels, display_format="dense").to_list(), labels) with self.subTest("Test 2"): labels = [("+-", 1), ("-+", -1)] op = FermionicOp([("+_0 -_1", 1.0), ("-_0 +_1", -1.0)], register_length=2, display_format="dense") self.assertListEqual(op.to_list(), labels)
def _get_adjacency_matrix(fer_op: FermionicOp) -> np.ndarray: """Return an adjacency matrix specifying the edges in the BKSF graph for the operator `fer_op`. The graph is undirected, so we choose to return the edges in the upper triangle. (There are no self edges.) The lower triangle entries are all `False`. Args: fer_op: The Fermionic operator. Returns: numpy.ndarray(dtype=bool): edge_matrix the adjacency matrix. """ n_modes = fer_op.register_length edge_matrix = np.zeros((n_modes, n_modes), dtype=bool) for term in fer_op.to_list(): if _operator_coefficient(term) != 0: _add_edges_for_term(edge_matrix, _operator_string(term)) return edge_matrix
def test_init(self, label, pre_processing): """Test __init__""" fer_op = FermionicOp(pre_processing(label), display_format="dense") self.assertListEqual(fer_op.to_list(), [(label, 1)]) self.assertFermionEqual(eval(repr(fer_op)), fer_op) # pylint: disable=eval-used
def assertFermionEqual(self, first: FermionicOp, second: FermionicOp): """Fail if two FermionicOps are different. Note that this equality check is approximated since the true equality check is costly. """ self.assertSetEqual(frozenset(first.to_list()), frozenset(second.to_list(first.display_format)))
def _convert_operator(ferm_op: FermionicOp, edge_list: np.ndarray) -> SparsePauliOp: """Convert a fermionic operator together with qubit-connectivity graph to a Pauli operator. This is the heart of the implementation of BKSF mapping. The connectivity graph must be computed before this method is called. The returned Pauli operator must be sorted and simplified. Args: ferm_op: The fermionic operator to convert. edge_list: The qubit-connectivity graph expressed as an edge list. Returns: An un-simplified Pauli operator representing `ferm_op`. Raises: ValueError: if the type of interaction of any term is unknown. """ sparse_pauli = None for term in ferm_op.to_list(): if _operator_coefficient(term) == 0: continue term_type, facs = _analyze_term(_operator_string(term)) if facs[0][1] == "-": # keep only one of h.c. pair continue ## Following only filters h.c. of some number-excitation op if facs[0][0] == facs[1][ 0]: # first op is number op, which is it's own h.c. if len(facs) > 2 and facs[2][ 1] == "-": # So, look at next op to skip h.c. continue if term_type == TermType.NUMBER: # a^\dagger_p a_p p = facs[0][0] # pylint: disable=invalid-name h1_pq = _operator_coefficient(term) sparse_pauli = _add_sparse_pauli( sparse_pauli, _number_operator(edge_list, p, h1_pq)) continue if term_type == TermType.EXCITATION: (p, q) = [facs[i][0] for i in range(2)] # p < q always # pylint: disable=invalid-name h1_pq = _operator_coefficient(term) sparse_pauli = _add_sparse_pauli( sparse_pauli, _excitation_operator(edge_list, p, q, h1_pq)) else: facs_reordered, phase = _to_physicist_index_order(facs) h2_pqrs = phase * _operator_coefficient(term) (p, q, r, s) = [facs_reordered[i][0] for i in range(4)] # pylint: disable=invalid-name if term_type == TermType.DOUBLE_EXCITATION: sparse_pauli = _add_sparse_pauli( sparse_pauli, _double_excitation(edge_list, p, q, r, s, h2_pqrs)) elif term_type == TermType.COULOMB_EXCHANGE: sparse_pauli = _add_sparse_pauli( sparse_pauli, _coulomb_exchange(edge_list, p, q, s, h2_pqrs)) elif term_type == TermType.NUMBER_EXCITATION: # Note that h2_pqrs is not divided by 2 here, as in the aqua code sparse_pauli = _add_sparse_pauli( sparse_pauli, _number_excitation(edge_list, p, q, r, s, h2_pqrs)) else: raise ValueError("Unknown interaction: ", term_type) if sparse_pauli is None: sparse_pauli = _pauli_id(edge_list.shape[1], complex(0.0)) return sparse_pauli