예제 #1
0
    def test_bk_jw_majoranas(self):
        # Check if the Majorana operators have the same spectrum
        # irrespectively of the transform.
        n_qubits = 7

        a = FermionOperator(((1, 0),))
        a_dag = FermionOperator(((1, 1),))

        c = a + a_dag
        d = 1j * (a_dag - a)

        c_spins = [jordan_wigner(c), bravyi_kitaev_tree(c)]
        d_spins = [jordan_wigner(d), bravyi_kitaev_tree(d)]

        c_sparse = [get_sparse_operator(c_spins[0]),
                    get_sparse_operator(c_spins[1])]
        d_sparse = [get_sparse_operator(d_spins[0]),
                    get_sparse_operator(d_spins[1])]

        c_spectrum = [eigenspectrum(c_spins[0]),
                      eigenspectrum(c_spins[1])]
        d_spectrum = [eigenspectrum(d_spins[0]),
                      eigenspectrum(d_spins[1])]

        self.assertAlmostEqual(0., numpy.amax(numpy.absolute(d_spectrum[0] -
                                                             d_spectrum[1])))
예제 #2
0
    def test_bravyi_kitaev_tree_transform(self):
        # Check that the QubitOperators are two-term.
        lowering = bravyi_kitaev_tree(FermionOperator(((3, 0),)))
        raising = bravyi_kitaev_tree(FermionOperator(((3, 1),)))
        self.assertEqual(len(raising.terms), 2)
        self.assertEqual(len(lowering.terms), 2)

        #  Test the locality invariant for N=2^d qubits
        # (c_j majorana is always log2N+1 local on qubits)
        n_qubits = 16
        invariant = numpy.log2(n_qubits) + 1
        for index in range(n_qubits):
            operator = bravyi_kitaev_tree(FermionOperator(((index, 0),)), n_qubits)
            qubit_terms = operator.terms.items()  # Get the majorana terms.

            for item in qubit_terms:
                coeff = item[1]

                #  Identify the c majorana terms by real
                #  coefficients and check their length.
                if not isinstance(coeff, complex):
                    self.assertEqual(len(item[0]), invariant)

        #  Hardcoded coefficient test on 16 qubits
        lowering = bravyi_kitaev_tree(FermionOperator(((9, 0),)), n_qubits)
        raising = bravyi_kitaev_tree(FermionOperator(((9, 1),)), n_qubits)

        correct_operators_c = ((7, 'Z'), (8, 'Z'), (9, 'X'),
                               (11, 'X'), (15, 'X'))
        correct_operators_d = ((7, 'Z'), (9, 'Y'), (11, 'X'), (15, 'X'))

        self.assertEqual(lowering.terms[correct_operators_c], 0.5)
        self.assertEqual(lowering.terms[correct_operators_d], 0.5j)
        self.assertEqual(raising.terms[correct_operators_d], -0.5j)
        self.assertEqual(raising.terms[correct_operators_c], 0.5)
예제 #3
0
    def test_bk_jw_number_operator(self):
        # Check if number operator has the same spectrum in both
        # BK and JW representations
        n = number_operator(1, 0)
        jw_n = jordan_wigner(n)
        bk_n = bravyi_kitaev_tree(n)

        # Diagonalize and make sure the spectra are the same.
        jw_spectrum = eigenspectrum(jw_n)
        bk_spectrum = eigenspectrum(bk_n)

        self.assertAlmostEqual(0., numpy.amax(
            numpy.absolute(jw_spectrum - bk_spectrum)))
예제 #4
0
    def test_bk_jw_hopping_operator(self):
        # Check if the spectrum fits for a single hoppping operator
        ho = FermionOperator(((1, 1), (4, 0))) + FermionOperator(
            ((4, 1), (1, 0)))
        jw_ho = jordan_wigner(ho)
        bk_ho = bravyi_kitaev_tree(ho)

        # Diagonalize and make sure the spectra are the same.
        jw_spectrum = eigenspectrum(jw_ho)
        bk_spectrum = eigenspectrum(bk_ho)

        self.assertAlmostEqual(0., numpy.amax(
                               numpy.absolute(jw_spectrum - bk_spectrum)))
예제 #5
0
    def test_bk_jw_number_operator_scaled(self):
        # Check if number operator has the same spectrum in both
        # JW and BK representations
        n_qubits = 1
        n = number_operator(n_qubits, 0, coefficient=2)  # eigenspectrum (0,2)
        jw_n = jordan_wigner(n)
        bk_n = bravyi_kitaev_tree(n)

        # Diagonalize and make sure the spectra are the same.
        jw_spectrum = eigenspectrum(jw_n)
        bk_spectrum = eigenspectrum(bk_n)

        self.assertAlmostEqual(0., numpy.amax(
                               numpy.absolute(jw_spectrum - bk_spectrum)))
예제 #6
0
    def test_bk_jw_integration(self):
        # This is a legacy test, which was a minimal failing example when
        # optimization for hermitian operators was used.

        # Minimal failing example:
        fo = FermionOperator(((3, 1),))

        jw = jordan_wigner(fo)
        bk = bravyi_kitaev_tree(fo)

        jw_spectrum = eigenspectrum(jw)
        bk_spectrum = eigenspectrum(bk)

        self.assertAlmostEqual(0., numpy.amax(numpy.absolute(jw_spectrum -
                                                             bk_spectrum)))
예제 #7
0
def load_and_transform(filename, orbitals, transform):
    # Load data
    print('--- loading molecule ---')
    molecule = MolecularData(filename=filename)

    print('filename: {}'.format(molecule.filename))
    #print('n_atoms: {}'.format(molecule.n_atoms))
    #print('n_electrons: {}'.format(molecule.n_electrons))
    #print('n_orbitals: {}'.format(molecule.n_orbitals))
    #print('Canonical Orbitals: {}'.format(molecule.canonical_orbitals))
    #print('n_qubits: {}'.format(molecule.n_qubits))

    # get the Hamiltonian for a specific choice of active space
    # set the Hamiltonian parameters
    occupied_orbitals, active_orbitals = orbitals

    molecular_hamiltonian = molecule.get_molecular_hamiltonian(
        occupied_indices=range(occupied_orbitals),
        active_indices=range(active_orbitals))

    # map the operator to fermions and then qubits
    fermion_hamiltonian = get_fermion_operator(molecular_hamiltonian)

    # get interaction operator
    interaction_hamiltonian = get_interaction_operator(fermion_hamiltonian)

    if transform is 'JW':
        qubit_h = jordan_wigner(fermion_hamiltonian)
        qubit_h.compress()
    elif transform is 'BK':
        qubit_h = bravyi_kitaev(fermion_hamiltonian)
        qubit_h.compress()
    elif transform is 'BKSF':
        qubit_h = bravyi_kitaev_fast(interaction_hamiltonian)
        qubit_h.compress()
    elif transform is 'BKT':
        qubit_h = bravyi_kitaev_tree(fermion_hamiltonian)
        qubit_h.compress()
    elif transform is 'PC':
        qubit_h = binary_code_transform(fermion_hamiltonian,
                                        parity_code(2 * active_orbitals))
        qubit_h.compress()
    else:
        print('ERROR: Unrecognized qubit transformation: {}'.format(transform))
        sys.exit(2)

    return qubit_h
예제 #8
0
    def test_bk_jw_number_operators(self):
        # Check if a number operator has the same spectrum in both
        # JW and BK representations
        n_qubits = 2
        n1 = number_operator(n_qubits, 0)
        n2 = number_operator(n_qubits, 1)
        n = n1 + n2

        jw_n = jordan_wigner(n)
        bk_n = bravyi_kitaev_tree(n)

        # Diagonalize and make sure the spectra are the same.
        jw_spectrum = eigenspectrum(jw_n)
        bk_spectrum = eigenspectrum(bk_n)

        self.assertAlmostEqual(0., numpy.amax(
            numpy.absolute(jw_spectrum - bk_spectrum)))
예제 #9
0
    def test_bk_jw_integration_original(self):
        # This is a legacy test, which was an example proposed by Ryan,
        # failing when optimization for hermitian operators was used.
        fermion_operator = FermionOperator(((3, 1), (2, 1), (1, 0), (0, 0)),
                                           -4.3)
        fermion_operator += FermionOperator(((3, 1), (1, 0)), 8.17)
        fermion_operator += 3.2 * FermionOperator()

        # Map to qubits and compare matrix versions.
        jw_qubit_operator = jordan_wigner(fermion_operator)
        bk_qubit_operator = bravyi_kitaev_tree(fermion_operator)

        # Diagonalize and make sure the spectra are the same.
        jw_spectrum = eigenspectrum(jw_qubit_operator)
        bk_spectrum = eigenspectrum(bk_qubit_operator)
        self.assertAlmostEqual(0., numpy.amax(numpy.absolute(jw_spectrum -
                                              bk_spectrum)), places=5)
예제 #10
0
def symmetry_conserving_bravyi_kitaev_HOTFIX(fermion_hamiltonian, active_orbitals,
                                      active_fermions):
    """ Returns the qubit Hamiltonian for the fermionic Hamiltonian
        supplied, with two qubits removed using conservation of electron
        spin and number, as described in arXiv:1701.08213.

        Args:
            fermion_hamiltonian: A fermionic hamiltonian obtained
                                 using OpenFermion. An instance
                                 of the FermionOperator class.

            active_orbitals: Int type object. The number of active orbitals
                             being considered for the system.

            active_fermions: Int type object. The number of active fermions
                              being considered for the system (note, this
                              is less than the number of electrons in a
                              molecule if some orbitals have been assumed
                              filled).
        Returns:
                qubit_hamiltonian: The qubit Hamiltonian corresponding to
                                   the supplied fermionic Hamiltonian, with
                                   two qubits removed using spin symmetries.
        WARNING:
                Reorders orbitals from the default even-odd ordering to all
                spin-up orbitals, then all spin-down orbitals.
        Raises:
                ValueError if fermion_hamiltonian isn't of the type
                FermionOperator, or active_orbitals isn't an integer,
                or active_fermions isn't an integer.

        Notes: This function reorders the spin orbitals as all spin-up, then
               all spin-down. It uses the OpenFermion bravyi_kitaev_tree
               mapping, rather than the bravyi-kitaev mapping.
               Caution advised when using with a Fermi-Hubbard Hamiltonian;
               this technique correctly reduces the Hamiltonian only for the
               lowest energy even and odd fermion number states, not states
               with an arbitrary number of fermions.
    """
    # Catch errors if inputs are of wrong type.
    if type(fermion_hamiltonian) is not FermionOperator:
        raise ValueError('Supplied operator should be an instance '
                         'of FermionOperator class')
    if type(active_orbitals) is not int:
        raise ValueError('Number of active orbitals should be an integer.')
    if type(active_fermions) is not int:
        raise ValueError('Number of active fermions should be an integer.')

    # Arrange spins up then down, then BK map to qubit Hamiltonian.
    ''' MODIFIED -- to make sure, that single operators of a Hamiltonian also give valid results '''
    fermion_hamiltonian_reorder = reorder(fermion_hamiltonian, up_then_down,
                                          num_modes=active_orbitals)  # added num_modes info
    qubit_hamiltonian = bravyi_kitaev_tree(fermion_hamiltonian_reorder, n_qubits=active_orbitals)  # added n_qubits info
    ''' END MODIFIED '''
    qubit_hamiltonian.compress()

    # Allocates the parity factors for the orbitals as in arXiv:1704.05018.
    remainder = active_fermions % 4
    if remainder == 0:
        parity_final_orb = 1
        parity_middle_orb = 1
    elif remainder == 1:
        parity_final_orb = -1
        parity_middle_orb = -1
    elif remainder == 2:
        parity_final_orb = 1
        parity_middle_orb = -1
    else:
        parity_final_orb = -1
        parity_middle_orb = 1

    # Removes the final qubit, then the middle qubit.
    qubit_hamiltonian = edit_hamiltonian_for_spin(qubit_hamiltonian,
                                                  active_orbitals,
                                                  parity_final_orb)
    qubit_hamiltonian = edit_hamiltonian_for_spin(qubit_hamiltonian,
                                                  active_orbitals/2,
                                                  parity_middle_orb)
    qubit_hamiltonian = prune_unused_indices(qubit_hamiltonian)

    return qubit_hamiltonian
예제 #11
0
 def test_bk_n_qubits_too_small(self):
     with self.assertRaises(ValueError):
         bravyi_kitaev_tree(FermionOperator('2^ 3^ 5 0'), n_qubits=4)
예제 #12
0
 def test_bk_identity(self):
     self.assertTrue(bravyi_kitaev_tree(FermionOperator(())) ==
                     QubitOperator(()))