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
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:]
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
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