Exemplo n.º 1
0
def is_hermitian(operator):
    """Test if operator is Hermitian."""
    # Handle FermionOperator, BosonOperator, and InteractionOperator
    if isinstance(operator,
                  (FermionOperator, BosonOperator, InteractionOperator)):
        return (normal_ordered(operator) == normal_ordered(
            hermitian_conjugated(operator)))

    # Handle QubitOperator and QuadOperator
    if isinstance(operator, (QubitOperator, QuadOperator)):
        return operator == hermitian_conjugated(operator)

    # Handle sparse matrix
    elif isinstance(operator, spmatrix):
        difference = operator - hermitian_conjugated(operator)
        discrepancy = 0.
        if difference.nnz:
            discrepancy = max(abs(difference.data))
        return discrepancy < EQ_TOLERANCE

    # Handle numpy array
    elif isinstance(operator, numpy.ndarray):
        difference = operator - hermitian_conjugated(operator)
        discrepancy = numpy.amax(abs(difference))
        return discrepancy < EQ_TOLERANCE

    # Unsupported type
    else:
        raise TypeError('Checking whether a {} is hermitian is not '
                        'supported.'.format(type(operator).__name__))
Exemplo n.º 2
0
    def test_quad_triple(self):
        op_132 = QuadOperator(((1, 'p'), (3, 'q'), (2, 'q')))
        op_123 = QuadOperator(((1, 'p'), (2, 'q'), (3, 'q')))
        op_321 = QuadOperator(((3, 'q'), (2, 'q'), (1, 'p')))

        self.assertTrue(op_132 == normal_ordered(op_123))
        self.assertTrue(op_132 == normal_ordered(op_132))
        self.assertTrue(op_132 == normal_ordered(op_321))
Exemplo n.º 3
0
    def test_fermion_triple(self):
        op_132 = FermionOperator(((1, 1), (3, 0), (2, 0)))
        op_123 = FermionOperator(((1, 1), (2, 0), (3, 0)))
        op_321 = FermionOperator(((3, 0), (2, 0), (1, 1)))

        self.assertTrue(op_132 == normal_ordered(-op_123))
        self.assertTrue(op_132 == normal_ordered(op_132))
        self.assertTrue(op_132 == normal_ordered(op_321))
Exemplo n.º 4
0
 def test_random_quadratic(self):
     n_qubits = 5
     quad_ham = random_quadratic_hamiltonian(n_qubits, True)
     ferm_op = get_fermion_operator(quad_ham)
     self.assertTrue(
         normal_ordered(ferm_op) == normal_ordered(
             get_fermion_operator(get_diagonal_coulomb_hamiltonian(
                 ferm_op))))
Exemplo n.º 5
0
 def test_convert_forward_back(self):
     n_qubits = 6
     random_operator = get_fermion_operator(
         random_interaction_operator(n_qubits))
     chemist_operator = chemist_ordered(random_operator)
     normalized_chemist = normal_ordered(chemist_operator)
     difference = normalized_chemist - normal_ordered(random_operator)
     self.assertAlmostEqual(0., difference.induced_norm())
Exemplo n.º 6
0
def test_get_fermion_operator_majorana_operator():
    a = MajoranaOperator((0, 3), 2.0) + MajoranaOperator((1, 2, 3))
    op = get_fermion_operator(a)
    expected_op = (-2j * (FermionOperator(((0, 0), (1, 0))) - FermionOperator(
        ((0, 0), (1, 1))) + FermionOperator(
            ((0, 1), (1, 0))) - FermionOperator(
                ((0, 1), (1, 1)))) - 2 * FermionOperator(
                    ((0, 0), (1, 1), (1, 0))) + 2 * FermionOperator(
                        ((0, 1), (1, 1), (1, 0))) + FermionOperator(
                            (0, 0)) - FermionOperator((0, 1)))
    assert normal_ordered(op) == normal_ordered(expected_op)
Exemplo n.º 7
0
 def test_q_squared(self):
     b = self.hbar * (BosonOperator('0^ 0^') + BosonOperator('0 0') +
                      BosonOperator('') + 2 * BosonOperator('0^ 0')) / 2
     q = normal_ordered(get_quad_operator(b, hbar=self.hbar),
                        hbar=self.hbar)
     expected = QuadOperator('q0 q0')
     self.assertTrue(q == expected)
Exemplo n.º 8
0
 def test_interaction_operator(self):
     for n_orbitals, real, _ in itertools.product((1, 2, 5), (True, False),
                                                  range(5)):
         operator = random_interaction_operator(n_orbitals, real=real)
         normal_ordered_operator = normal_ordered(operator)
         expected_qubit_operator = jordan_wigner(operator)
         actual_qubit_operator = jordan_wigner(normal_ordered_operator)
         assert expected_qubit_operator == actual_qubit_operator
         two_body_tensor = normal_ordered_operator.two_body_tensor
         n_orbitals = len(two_body_tensor)
         ones = numpy.ones((n_orbitals, ) * 2)
         triu = numpy.triu(ones, 1)
         shape = (n_orbitals**2, 1)
         mask = (triu.reshape(shape) * ones.reshape(shape[::-1]) +
                 ones.reshape(shape) * triu.reshape(shape[::-1])).reshape(
                     (n_orbitals, ) * 4)
         assert numpy.allclose(mask * two_body_tensor,
                               numpy.zeros((n_orbitals, ) * 4))
         for term in normal_ordered_operator:
             order = len(term) // 2
             left_term, right_term = term[:order], term[order:]
             assert all(i[1] == 1 for i in left_term)
             assert all(i[1] == 0 for i in right_term)
             assert left_term == tuple(sorted(left_term, reverse=True))
             assert right_term == tuple(sorted(right_term, reverse=True))
Exemplo n.º 9
0
 def test_p_squared(self):
     b = self.hbar * (-BosonOperator('1^ 1^') - BosonOperator('1 1') +
                      BosonOperator('') + 2 * BosonOperator('1^ 1')) / 2
     q = normal_ordered(get_quad_operator(b, hbar=self.hbar),
                        hbar=self.hbar)
     expected = QuadOperator('p1 p1')
     self.assertTrue(q == expected)
Exemplo n.º 10
0
    def test_hubbard(self):
        x_dim = 4
        y_dim = 5
        tunneling = 2.
        coulomb = 3.
        chemical_potential = 7.
        magnetic_field = 11.
        periodic = False

        hubbard_model = fermi_hubbard(x_dim, y_dim, tunneling, coulomb,
                                      chemical_potential, magnetic_field,
                                      periodic)

        self.assertTrue(
            normal_ordered(hubbard_model) == normal_ordered(
                get_fermion_operator(
                    get_diagonal_coulomb_hamiltonian(hubbard_model))))
Exemplo n.º 11
0
    def test_get_molecular_operator(self):
        coefficient = 3.
        operators = ((2, 1), (3, 0), (0, 0), (3, 1))
        op = FermionOperator(operators, coefficient)

        molecular_operator = get_interaction_operator(op)
        fermion_operator = get_fermion_operator(molecular_operator)
        fermion_operator = normal_ordered(fermion_operator)
        self.assertTrue(normal_ordered(op) == fermion_operator)

        op = FermionOperator('1^ 1')
        op *= 0.5 * EQ_TOLERANCE
        molecular_operator = get_interaction_operator(op)
        self.assertEqual(molecular_operator.constant, 0)
        self.assertTrue(
            numpy.allclose(molecular_operator.one_body_tensor,
                           numpy.zeros((2, 2))))
Exemplo n.º 12
0
def double_commutator(op1,
                      op2,
                      op3,
                      indices2=None,
                      indices3=None,
                      is_hopping_operator2=None,
                      is_hopping_operator3=None):
    """Return the double commutator [op1, [op2, op3]].

    Args:
        op1, op2, op3 (FermionOperators or BosonOperators): operators for
            the commutator. All three operators must be of the same type.
        indices2, indices3 (set): The indices op2 and op3 act on.
        is_hopping_operator2 (bool): Whether op2 is a hopping operator.
        is_hopping_operator3 (bool): Whether op3 is a hopping operator.

    Returns:
        The double commutator of the given operators.
    """
    if is_hopping_operator2 and is_hopping_operator3:
        indices2 = set(indices2)
        indices3 = set(indices3)
        # Determine which indices both op2 and op3 act on.
        try:
            intersection, = indices2.intersection(indices3)
        except ValueError:
            return FermionOperator.zero()

        # Remove the intersection from the set of indices, since it will get
        # cancelled out in the final result.
        indices2.remove(intersection)
        indices3.remove(intersection)

        # Find the indices of the final output hopping operator.
        index2, = indices2
        index3, = indices3
        coeff2 = op2.terms[list(op2.terms)[0]]
        coeff3 = op3.terms[list(op3.terms)[0]]
        commutator23 = (FermionOperator(
            ((index2, 1), (index3, 0)), coeff2 * coeff3) + FermionOperator(
                ((index3, 1), (index2, 0)), -coeff2 * coeff3))
    else:
        commutator23 = normal_ordered(commutator(op2, op3))

    return normal_ordered(commutator(op1, commutator23))
Exemplo n.º 13
0
    def test_get_quadratic_hamiltonian_hermitian(self):
        """Test properly formed quadratic Hamiltonians."""
        # Non-particle-number-conserving without chemical potential
        quadratic_op = get_quadratic_hamiltonian(self.hermitian_op)
        fermion_operator = get_fermion_operator(quadratic_op)
        fermion_operator = normal_ordered(fermion_operator)
        self.assertTrue(normal_ordered(self.hermitian_op) == fermion_operator)

        # Non-particle-number-conserving chemical potential
        quadratic_op = get_quadratic_hamiltonian(self.hermitian_op,
                                                 chemical_potential=3.)
        fermion_operator = get_fermion_operator(quadratic_op)
        fermion_operator = normal_ordered(fermion_operator)
        self.assertTrue(normal_ordered(self.hermitian_op) == fermion_operator)

        # Particle-number-conserving
        quadratic_op = get_quadratic_hamiltonian(self.hermitian_op_pc)
        fermion_operator = get_fermion_operator(quadratic_op)
        fermion_operator = normal_ordered(fermion_operator)
        self.assertTrue(
            normal_ordered(self.hermitian_op_pc) == fermion_operator)

        fop = FermionOperator('1^ 1')
        fop *= 0.5E-8
        quad_op = get_quadratic_hamiltonian(fop)
        self.assertEqual(quad_op.constant, 0)
Exemplo n.º 14
0
 def test_boson_two_term(self):
     op_b = BosonOperator(((2, 0), (4, 0), (2, 1)), 88.)
     normal_ordered_b = normal_ordered(op_b)
     expected = (BosonOperator(((4, 0), ), 88.) + BosonOperator(
         ((2, 1), (4, 0), (2, 0)), 88.))
     self.assertTrue(normal_ordered_b == expected)
Exemplo n.º 15
0
 def test_quad_two_term(self):
     op_b = QuadOperator('p0 q0 p3', 88.)
     normal_ordered_b = normal_ordered(op_b, hbar=2)
     expected = QuadOperator('p3', -88. * 2j) + QuadOperator(
         'q0 p0 p3', 88.0)
     self.assertTrue(normal_ordered_b == expected)
Exemplo n.º 16
0
 def test_quad_offsite(self):
     op = QuadOperator(((3, 'p'), (2, 'q')))
     self.assertTrue(op == normal_ordered(op))
Exemplo n.º 17
0
 def test_boson_multi(self):
     op = BosonOperator(((2, 0), (1, 1), (2, 1)))
     expected = (BosonOperator(((2, 1), (1, 1), (2, 0))) + BosonOperator(
         ((1, 1), )))
     self.assertTrue(expected == normal_ordered(op))
Exemplo n.º 18
0
 def test_boson_offsite(self):
     op = BosonOperator(((3, 1), (2, 0)))
     self.assertTrue(op == normal_ordered(op))
Exemplo n.º 19
0
 def test_boson_offsite_reversed(self):
     op = BosonOperator(((3, 0), (2, 1)))
     expected = BosonOperator(((2, 1), (3, 0)))
     self.assertTrue(expected == normal_ordered(op))
Exemplo n.º 20
0
 def test_fermion_double_create_separated(self):
     op = FermionOperator(((3, 1), (2, 0), (3, 1)))
     expected = FermionOperator((), 0.0)
     self.assertTrue(expected == normal_ordered(op))
Exemplo n.º 21
0
 def test_boson_number_reversed(self):
     n_term_rev2 = BosonOperator(((2, 0), (2, 1)))
     number_op2 = number_operator(3, 2, parity=1)
     expected = BosonOperator(()) + number_op2
     self.assertTrue(normal_ordered(n_term_rev2) == expected)
def commutator_ordered_diagonal_coulomb_with_two_body_operator(
        operator_a, operator_b, prior_terms=None):
    """Compute the commutator of two-body operators provided that both are
    normal-ordered and that the first only has diagonal Coulomb interactions.

    Args:
        operator_a: The first FermionOperator argument of the commutator.
            All terms must be normal-ordered, and furthermore either hopping
            operators (i^ j) or diagonal Coulomb operators (i^ i or i^ j^ i j).
        operator_b: The second FermionOperator argument of the commutator.
            operator_b can be any arbitrary two-body operator.
        prior_terms (optional): The initial FermionOperator to add to.

    Returns:
        The commutator, or the commutator added to prior_terms if provided.

    Notes:
        The function could be readily extended to the case of arbitrary
        two-body operator_a given that operator_b has the desired form;
        however, the extra check slows it down without desirable added utility.
    """
    if prior_terms is None:
        prior_terms = FermionOperator.zero()

    for term_a in operator_a.terms:
        coeff_a = operator_a.terms[term_a]
        for term_b in operator_b.terms:
            coeff_b = operator_b.terms[term_b]

            coefficient = coeff_a * coeff_b

            # If term_a == term_b the terms commute, nothing to add.
            if term_a == term_b or not term_a or not term_b:
                continue

            # Case 1: both operators are two-body, operator_a is i^ j^ i j.
            if (len(term_a) == len(term_b) == 4
                    and term_a[0][0] == term_a[2][0]
                    and term_a[1][0] == term_a[3][0]):
                _commutator_two_body_diagonal_with_two_body(
                    term_a, term_b, coefficient, prior_terms)

            # Case 2: commutator of a 1-body and a 2-body operator
            elif (len(term_b) == 4
                  and len(term_a) == 2) or (len(term_a) == 4
                                            and len(term_b) == 2):
                _commutator_one_body_with_two_body(term_a, term_b, coefficient,
                                                   prior_terms)

            # Case 3: both terms are one-body operators (both length 2)
            elif len(term_a) == 2 and len(term_b) == 2:
                _commutator_one_body_with_one_body(term_a, term_b, coefficient,
                                                   prior_terms)

            # Final case (case 4): violation of the input promise. Still
            # compute the commutator, but warn the user.
            else:
                warnings.warn('Defaulted to standard commutator evaluation '
                              'due to an out-of-spec operator.')
                additional = FermionOperator.zero()
                additional.terms[term_a + term_b] = coefficient
                additional.terms[term_b + term_a] = -coefficient
                additional = term_reordering.normal_ordered(additional)

                prior_terms += additional

    return prior_terms
Exemplo n.º 23
0
 def test_boson_single_term(self):
     op = BosonOperator('4 3 2 1') + BosonOperator('3 2')
     self.assertTrue(op == normal_ordered(op))
Exemplo n.º 24
0
 def test_quad_offsite_reversed(self):
     op = QuadOperator(((3, 'q'), (2, 'p')))
     expected = QuadOperator(((2, 'p'), (3, 'q')))
     self.assertTrue(expected == normal_ordered(op))
Exemplo n.º 25
0
 def test_exceptions(self):
     with self.assertRaises(TypeError):
         _ = normal_ordered(1)
Exemplo n.º 26
0
 def test_fermion_number_reversed(self):
     n_term_rev2 = FermionOperator(((2, 0), (2, 1)))
     number_op2 = number_operator(3, 2)
     expected = FermionOperator(()) - number_op2
     self.assertTrue(normal_ordered(n_term_rev2) == expected)
Exemplo n.º 27
0
 def test_boson_number(self):
     number_op2 = BosonOperator(((2, 1), (2, 0)))
     self.assertTrue(number_op2 == normal_ordered(number_op2))
Exemplo n.º 28
0
 def test_fermion_multi(self):
     op = FermionOperator(((2, 0), (1, 1), (2, 1)))
     expected = (-FermionOperator(
         ((2, 1), (1, 1), (2, 0))) - FermionOperator(((1, 1), )))
     self.assertTrue(expected == normal_ordered(op))