def test_double_commtator_more_info_both_hopping(self): com = double_commutator( FermionOperator('4^ 3^ 4 3'), FermionOperator('1^ 2', 2.1) + FermionOperator('2^ 1', 2.1), FermionOperator('1^ 3', -1.3) + FermionOperator('3^ 1', -1.3), indices2=set([1, 2]), indices3=set([1, 3]), is_hopping_operator2=True, is_hopping_operator3=True) self.assertEqual(com, (FermionOperator('4^ 3^ 4 2', 2.73) + FermionOperator('4^ 2^ 4 3', 2.73)))
def test_double_commutator_more_info_not_hopping(self): com = double_commutator(FermionOperator('3^ 2'), FermionOperator('2^ 3') + FermionOperator('3^ 2'), FermionOperator('4^ 2^ 4 2'), indices2=set([2, 3]), indices3=set([2, 4]), is_hopping_operator2=True, is_hopping_operator3=False) self.assertEqual( com, (FermionOperator('4^ 2^ 4 2') - FermionOperator('4^ 3^ 4 3')))
def test_double_commutator_no_intersection_with_union_of_second_two(self): com = double_commutator(FermionOperator('4^ 3^ 6 5'), FermionOperator('2^ 1 0'), FermionOperator('0^')) self.assertEqual(com, FermionOperator.zero())
def low_depth_second_order_trotter_error_operator(terms, indices=None, is_hopping_operator=None, jellium_only=False, verbose=False): """Determine the difference between the exact generator of unitary evolution and the approximate generator given by the second-order Trotter-Suzuki expansion. Args: terms: a list of FermionOperators in the Hamiltonian in the order in which they will be simulated. indices: a set of indices the terms act on in the same order as terms. is_hopping_operator: a list of whether each term is a hopping operator. jellium_only: Whether the terms are from the jellium Hamiltonian only, rather than the full dual basis Hamiltonian (i.e. whether c_i = c for all number operators i^ i, or whether they depend on i as is possible in the general case). verbose: Whether to print percentage progress. Returns: The difference between the true and effective generators of time evolution for a single Trotter step. Notes: follows Equation 9 of Poulin et al.'s work in "The Trotter Step Size Required for Accurate Quantum Simulation of Quantum Chemistry", applied to the "stagger"-based Trotter step for detailed in Kivlichan et al., "Quantum Simulation of Electronic Structure with Linear Depth and Connectivity", arxiv:1711.04789. """ more_info = bool(indices) n_terms = len(terms) if verbose: import time start = time.time() error_operator = FermionOperator.zero() for beta in range(n_terms): if verbose and beta % (n_terms // 30) == 0: print('%4.3f percent done in' % ((float(beta) / n_terms)**3 * 100), time.time() - start) for alpha in range(beta + 1): for alpha_prime in range(beta): # If we have pre-computed info on indices, use it to determine # trivial double commutation. if more_info: if (not trivially_double_commutes_dual_basis_using_term_info( # pylint: disable=C indices[alpha], indices[beta], indices[alpha_prime], is_hopping_operator[alpha], is_hopping_operator[beta], is_hopping_operator[alpha_prime], jellium_only)): # Determine the result of the double commutator. double_com = double_commutator( terms[alpha], terms[beta], terms[alpha_prime], indices[beta], indices[alpha_prime], is_hopping_operator[beta], is_hopping_operator[alpha_prime]) if alpha == beta: double_com /= 2.0 error_operator += double_com # If we don't have more info, check for trivial double # commutation using the terms directly. elif not trivially_double_commutes_dual_basis( terms[alpha], terms[beta], terms[alpha_prime]): double_com = double_commutator(terms[alpha], terms[beta], terms[alpha_prime]) if alpha == beta: double_com /= 2.0 error_operator += double_com error_operator /= 12.0 return error_operator