Ejemplo n.º 1
0
    def __init__(self, operator, t=1, k=20, mode='local'):
        super().__init__([t])

        if not is_hermitian(operator):
            raise ValueError("Hamiltonian must be Hermitian.")

        if (not isinstance(k, int)) or k <= 0:
            raise ValueError("Argument k must be a postive integer.")

        if mode == 'local':
            boson_operator = prune_unused_indices(operator)
        elif mode == 'global':
            boson_operator = operator

        if isinstance(boson_operator, QuadOperator):
            boson_operator = get_boson_operator(boson_operator, hbar=sf.hbar)

        self.layer = trotter_layer(boson_operator, t, k)
        self.num_layers = k

        num_modes = max([op[0] for term in operator.terms for op in term]) + 1

        if mode == 'local':
            self.ns = num_modes
        elif mode == 'global':
            # pylint: disable=protected-access
            self.ns = pu.Program_current_context.num_subsystems
Ejemplo n.º 2
0
    def __init__(self, operator, t=1, mode='local'):
        super().__init__([t])

        if not is_hermitian(operator):
            raise ValueError("Hamiltonian must be Hermitian.")

        if mode == 'local':
            quad_operator = prune_unused_indices(operator)
        elif mode == 'global':
            quad_operator = operator

        if isinstance(quad_operator, BosonOperator):
            quad_operator = get_quad_operator(quad_operator, hbar=sf.hbar)

        A, d = quadratic_coefficients(quad_operator)

        if mode == 'local':
            self.ns = A.shape[0] // 2
        elif mode == 'global':
            # pylint: disable=protected-access
            self.ns = pu.Program_current_context.num_subsystems
            if A.shape[0] < 2 * self.ns:
                # expand the quadratic coefficient matrix to take
                # into account the extra modes
                A_n = A.shape[0] // 2
                tmp = np.zeros([2 * self.ns, 2 * self.ns])

                tmp[:A_n, :A_n] = A[:A_n, :A_n]
                tmp[:A_n, self.ns:self.ns + A_n] = A[:A_n, A_n:]
                tmp[self.ns:self.ns + A_n, :A_n] = A[A_n:, :A_n]
                tmp[self.ns:self.ns + A_n, self.ns:self.ns + A_n] = A[A_n:,
                                                                      A_n:]

                A = tmp

        self.S = expm(sympmat(self.ns) @ A * t)

        self.disp = False
        if not np.all(d == 0.):
            self.disp = True
            if np.all(A == 0.):
                self.d = d * t
            else:
                if np.linalg.cond(A) >= 1 / sys.float_info.epsilon:
                    # the matrix is singular, add a small epsilon
                    eps = 1e-9
                    epsI = eps * np.identity(2 * self.ns)
                    s = inv(A + epsI) @ d
                    tmp = (np.identity(2*self.ns) \
                        - expm(sympmat(self.ns) @ (A+epsI) * t).T) @ s / eps
                else:
                    s = inv(A) @ d
                    tmp = s - self.S.T @ s

                self.d = np.zeros([2 * self.ns])
                self.d[self.ns:] = tmp[:self.ns]
                self.d[:self.ns] = tmp[self.ns:]
Ejemplo n.º 3
0
    def __init__(self, operator, t=1, k=20, mode='local', hbar=None):
        super().__init__([t, operator])

        try:
            # pylint: disable=protected-access
            self.hbar = _Engine._current_context.hbar
        except AttributeError:
            if hbar is None:
                raise ValueError(
                    "Either specify the hbar keyword argument, "
                    "or use this operator inside an engine context.")
            else:
                self.hbar = hbar

        if not is_hermitian(operator):
            raise ValueError("Hamiltonian must be Hermitian.")

        if (not isinstance(k, int)) or k <= 0:
            raise ValueError("Argument k must be a postive integer.")

        if mode == 'local':
            boson_operator = prune_unused_indices(operator)
        elif mode == 'global':
            boson_operator = operator

        if isinstance(boson_operator, QuadOperator):
            boson_operator = get_boson_operator(boson_operator, hbar=self.hbar)

        self.layer = trotter_layer(boson_operator, t, k)
        self.num_layers = k

        num_modes = max([op[0] for term in operator.terms for op in term]) + 1

        if mode == 'local':
            self.ns = num_modes
        elif mode == 'global':
            # pylint: disable=protected-access
            self.ns = _Engine._current_context.num_subsystems
Ejemplo n.º 4
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