def test_hubbard_trotter_error_matches_low_depth_trotter_error(self): hamiltonian = normal_ordered(fermi_hubbard(3, 3, 1., 2.3)) error_operator = ( fermionic_swap_trotter_error_operator_diagonal_two_body( hamiltonian)) error_operator.compress() # Unpack result into terms, indices they act on, and whether # they're hopping operators. result = simulation_ordered_grouped_low_depth_terms_with_info( hamiltonian) terms, indices, is_hopping = result old_error_operator = low_depth_second_order_trotter_error_operator( terms, indices, is_hopping, jellium_only=True) old_error_operator -= error_operator self.assertEqual(old_error_operator, FermionOperator.zero())
def test_1D_jellium_trotter_error_matches_low_depth_trotter_error(self): hamiltonian = normal_ordered(jellium_model( hypercube_grid_with_given_wigner_seitz_radius_and_filling( 1, 5, wigner_seitz_radius=10., spinless=True), spinless=True, plane_wave=False)) error_operator = ( fermionic_swap_trotter_error_operator_diagonal_two_body( hamiltonian)) error_operator.compress() # Unpack result into terms, indices they act on, and whether # they're hopping operators. result = simulation_ordered_grouped_low_depth_terms_with_info( hamiltonian) terms, indices, is_hopping = result old_error_operator = low_depth_second_order_trotter_error_operator( terms, indices, is_hopping, jellium_only=True) old_error_operator -= error_operator self.assertEqual(old_error_operator, FermionOperator.zero())
def fermionic_swap_trotter_error_operator_diagonal_two_body(hamiltonian): """Compute the fermionic swap network Trotter error of a diagonal two-body Hamiltonian. Args: hamiltonian (FermionOperator): The diagonal Coulomb Hamiltonian to compute the Trotter error for. Returns: error_operator: The second-order Trotter error operator. Notes: Follows Eq 9 of Poulin et al., arXiv:1406.4920, applied to the Trotter step detailed in Kivlichan et al., arxiv:1711.04789. """ single_terms = numpy.array( simulation_ordered_grouped_low_depth_terms_with_info(hamiltonian)[0]) # Cache the halved terms for use in the second commutator. halved_single_terms = single_terms / 2.0 term_mode_mask = bit_mask_of_modes_acted_on_by_fermionic_terms( single_terms, count_qubits(hamiltonian)) error_operator = FermionOperator.zero() for beta, term_beta in enumerate(single_terms): modes_acted_on_by_term_beta = set() for beta_action in term_beta.terms: modes_acted_on_by_term_beta.update( set(operator[0] for operator in beta_action)) beta_mode_mask = numpy.logical_or.reduce( [term_mode_mask[mode] for mode in modes_acted_on_by_term_beta]) # alpha_prime indices that could have a nonzero commutator, i.e. # there's overlap between the modes the corresponding terms act on. valid_alpha_primes = numpy.where(beta_mode_mask)[0] # Only alpha_prime < beta enters the error operator; filter for this. valid_alpha_primes = valid_alpha_primes[valid_alpha_primes < beta] for alpha_prime in valid_alpha_primes: term_alpha_prime = single_terms[alpha_prime] inner_commutator_term = ( commutator_ordered_diagonal_coulomb_with_two_body_operator( term_beta, term_alpha_prime)) modes_acted_on_by_inner_commutator = set() for inner_commutator_action in inner_commutator_term.terms: modes_acted_on_by_inner_commutator.update( set(operator[0] for operator in inner_commutator_action)) # If the inner commutator has no action, the commutator is zero. if not modes_acted_on_by_inner_commutator: continue inner_commutator_mask = numpy.logical_or.reduce([ term_mode_mask[mode] for mode in modes_acted_on_by_inner_commutator ]) # alpha indices that could have a nonzero commutator. valid_alphas = numpy.where(inner_commutator_mask)[0] # Filter so alpha <= beta in the double commutator. valid_alphas = valid_alphas[valid_alphas <= beta] for alpha in valid_alphas: # If alpha = beta, only use half the term. if alpha != beta: outer_term_alpha = single_terms[alpha] else: outer_term_alpha = halved_single_terms[alpha] # Add the partial double commutator to the error operator. commutator_ordered_diagonal_coulomb_with_two_body_operator( outer_term_alpha, inner_commutator_term, prior_terms=error_operator) # Divide by 12 to match the error operator definition. error_operator /= 12.0 return error_operator