Example #1
0
    def test_random(self):

        # Create random DiagonalCoulombHamiltonian.
        n_qubits = 8
        random.seed(n_qubits)
        one_body = numpy.zeros((n_qubits, n_qubits), float)
        two_body = numpy.zeros((n_qubits, n_qubits), float)
        for p in range(8):
            for q in range(p, 8):
                one_body[p, q] = random.random()
                two_body[p, q] = random.random()
        one_body += one_body.T
        two_body += two_body.T
        diagonal_operator = DiagonalCoulombHamiltonian(
            one_body, two_body, random.random())

        # Compute the lambda norm using expensive (reliable) method.
        qubit_operator = jordan_wigner(diagonal_operator)
        del qubit_operator.terms[()]
        reliable_norm = qubit_operator.induced_norm()

        # Compute the lambda norm using the method under test.
        test_norm = lambda_norm(diagonal_operator)

        # Third norm.
        third_norm = 0.
        for term, coefficient in qubit_operator.terms.items():
            third_norm += abs(coefficient)

        # Test.
        self.assertAlmostEqual(third_norm, reliable_norm)
        self.assertAlmostEqual(test_norm, reliable_norm)
Example #2
0
def random_diagonal_coulomb_hamiltonian(n_qubits, real=False):
    """Generate a random instance of DiagonalCoulombHamiltonian.

    Args:
        n_qubits: The number of qubits
        real: Whether to use only real numbers in the one-body term
    """
    one_body = random_hermitian_matrix(n_qubits, real=real)
    two_body = random_hermitian_matrix(n_qubits, real=True)
    constant = numpy.random.randn()
    return DiagonalCoulombHamiltonian(one_body, two_body, constant)
Example #3
0
def get_diagonal_coulomb_hamiltonian(fermion_operator, n_qubits=None):
    """Convert a FermionOperator to a DiagonalCoulombHamiltonian."""
    if not isinstance(fermion_operator, FermionOperator):
        raise TypeError('Input must be a FermionOperator.')

    if n_qubits is None:
        n_qubits = count_qubits(fermion_operator)
    if n_qubits < count_qubits(fermion_operator):
        raise ValueError('Invalid number of qubits specified.')

    fermion_operator = normal_ordered(fermion_operator)
    constant = 0.
    one_body = numpy.zeros((n_qubits, n_qubits), complex)
    two_body = numpy.zeros((n_qubits, n_qubits), float)

    for term, coefficient in fermion_operator.terms.items():
        # Ignore this term if the coefficient is zero
        if abs(coefficient) < EQ_TOLERANCE:
            continue

        if len(term) == 0:
            constant = coefficient
        else:
            actions = [operator[1] for operator in term]
            if actions == [1, 0]:
                p, q = [operator[0] for operator in term]
                one_body[p, q] = coefficient
            elif actions == [1, 1, 0, 0]:
                p, q, r, s = [operator[0] for operator in term]
                if p == r and q == s:
                    if abs(numpy.imag(coefficient)) > EQ_TOLERANCE:
                        raise ValueError(
                            'FermionOperator does not map to '
                            'DiagonalCoulombHamiltonian (not Hermitian).')
                    coefficient = numpy.real(coefficient)
                    two_body[p, q] = -.5 * coefficient
                    two_body[q, p] = -.5 * coefficient
                else:
                    raise ValueError('FermionOperator does not map to '
                                     'DiagonalCoulombHamiltonian '
                                     '(contains terms with indices '
                                     '{}).'.format((p, q, r, s)))
            else:
                raise ValueError('FermionOperator does not map to '
                                 'DiagonalCoulombHamiltonian (contains terms '
                                 'with action {}.'.format(tuple(actions)))

    # Check that the operator is Hermitian
    if not is_hermitian(one_body):
        raise ValueError(
            'FermionOperator does not map to DiagonalCoulombHamiltonian '
            '(not Hermitian).')

    return DiagonalCoulombHamiltonian(one_body, two_body, constant)
Example #4
0
    def test_diagonal_coulomb_hamiltonian(self):
        n_qubits = 5
        one_body = random_hermitian_matrix(n_qubits, real=False)
        two_body = random_hermitian_matrix(n_qubits, real=True)
        constant = numpy.random.randn()
        op = DiagonalCoulombHamiltonian(one_body, two_body, constant)

        op1 = get_sparse_operator(op)
        op2 = get_sparse_operator(jordan_wigner(get_fermion_operator(op)))
        diff = op1 - op2
        discrepancy = 0.
        if diff.nnz:
            discrepancy = max(abs(diff.data))
        self.assertAlmostEqual(discrepancy, 0.)
Example #5
0
def get_diagonal_coulomb_hamiltonian(fermion_operator,
                                     n_qubits=None,
                                     ignore_incompatible_terms=False):
    r"""Convert a FermionOperator to a DiagonalCoulombHamiltonian.

    Args:
        fermion_operator(FermionOperator): The operator to convert.
        n_qubits(int): Optionally specify the total number of qubits in the
            system
        ignore_incompatible_terms(bool): This flag determines the behavior
            of this method when it encounters terms that are not represented
            by the DiagonalCoulombHamiltonian class, namely, terms that are
            not quadratic and not quartic of the form
            a^\dagger_p a_p a^\dagger_q a_q. If set to True, this method will
            simply ignore those terms. If False, then this method will raise
            an error if it encounters such a term. The default setting is False.
    """
    if not isinstance(fermion_operator, FermionOperator):
        raise TypeError('Input must be a FermionOperator.')

    if n_qubits is None:
        n_qubits = count_qubits(fermion_operator)
    if n_qubits < count_qubits(fermion_operator):
        raise ValueError('Invalid number of qubits specified.')

    fermion_operator = normal_ordered(fermion_operator)
    constant = 0.
    one_body = numpy.zeros((n_qubits, n_qubits), complex)
    two_body = numpy.zeros((n_qubits, n_qubits), float)

    for term, coefficient in fermion_operator.terms.items():
        # Ignore this term if the coefficient is zero
        if abs(coefficient) < EQ_TOLERANCE:
            continue

        if len(term) == 0:
            constant = coefficient
        else:
            actions = [operator[1] for operator in term]
            if actions == [1, 0]:
                p, q = [operator[0] for operator in term]
                one_body[p, q] = coefficient
            elif actions == [1, 1, 0, 0]:
                p, q, r, s = [operator[0] for operator in term]
                if p == r and q == s:
                    if abs(numpy.imag(coefficient)) > EQ_TOLERANCE:
                        raise ValueError(
                            'FermionOperator does not map to '
                            'DiagonalCoulombHamiltonian (not Hermitian).')
                    coefficient = numpy.real(coefficient)
                    two_body[p, q] = -.5 * coefficient
                    two_body[q, p] = -.5 * coefficient
                elif not ignore_incompatible_terms:
                    raise ValueError('FermionOperator does not map to '
                                     'DiagonalCoulombHamiltonian '
                                     '(contains terms with indices '
                                     '{}).'.format((p, q, r, s)))
            elif not ignore_incompatible_terms:
                raise ValueError('FermionOperator does not map to '
                                 'DiagonalCoulombHamiltonian (contains terms '
                                 'with action {}.'.format(tuple(actions)))

    # Check that the operator is Hermitian
    if not is_hermitian(one_body):
        raise ValueError(
            'FermionOperator does not map to DiagonalCoulombHamiltonian '
            '(not Hermitian).')

    return DiagonalCoulombHamiltonian(one_body, two_body, constant)