Exemple #1
0
 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)))
Exemple #2
0
 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')))
Exemple #3
0
 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())
Exemple #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