Exemplo n.º 1
0
 def test_no_intersection_between_first_and_other_terms_is_trivial(self):
     self.assertTrue(
         trivially_double_commutes_dual_basis_using_term_info(
             indices_alpha=set([3, 2]),
             indices_beta=set([1, 4]),
             indices_alpha_prime=set([4, 5]),
             is_hopping_operator_alpha=False,
             is_hopping_operator_beta=True,
             is_hopping_operator_alpha_prime=False,
             jellium_only=True))
Exemplo n.º 2
0
 def test_alpha_is_hopping_operator_others_number_trivial_commutation(self):
     self.assertTrue(
         trivially_double_commutes_dual_basis_using_term_info(
             indices_alpha=set([1, 2]),
             indices_beta=set([3, 4]),
             indices_alpha_prime=set([2, 3]),
             is_hopping_operator_alpha=True,
             is_hopping_operator_beta=False,
             is_hopping_operator_alpha_prime=False,
             jellium_only=True))
Exemplo n.º 3
0
 def test_single_intersection_in_first_commutator_nontrivial(self):
     self.assertFalse(
         trivially_double_commutes_dual_basis_using_term_info(
             indices_alpha=set([3, 2]),
             indices_beta=set([3, 4]),
             indices_alpha_prime=set([4, 5]),
             is_hopping_operator_alpha=False,
             is_hopping_operator_beta=True,
             is_hopping_operator_alpha_prime=False,
             jellium_only=True))
Exemplo n.º 4
0
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