コード例 #1
0
    def test_relations(self):
        n_spatial_orbitals = 2

        s_plus = s_plus_operator(n_spatial_orbitals)
        s_minus = s_minus_operator(n_spatial_orbitals)
        sx = sx_operator(n_spatial_orbitals)
        sy = sy_operator(n_spatial_orbitals)
        sz = sz_operator(n_spatial_orbitals)
        s_squared = s_squared_operator(n_spatial_orbitals)

        identity = FermionOperator(())

        self.assertEqual(normal_ordered(sx),
                         normal_ordered(.5 * (s_plus + s_minus)))
        self.assertEqual(normal_ordered(sy),
                         normal_ordered((.5 / 1.j) * (s_plus - s_minus)))
        self.assertEqual(normal_ordered(s_squared),
                         normal_ordered(sx**2 + sy**2 + sz**2))
        self.assertEqual(
            normal_ordered(s_squared),
            normal_ordered(s_plus * s_minus + sz * (sz - identity)))
        self.assertEqual(normal_ordered(commutator(s_plus, s_minus)),
                         normal_ordered(2 * sz))
        self.assertEqual(normal_ordered(commutator(sx, sy)),
                         normal_ordered(1.j * sz))
コード例 #2
0
 def test_commutator(self):
     operator_a = FermionOperator('')
     self.assertTrue(FermionOperator().isclose(
         commutator(operator_a, self.fermion_operator)))
     operator_b = QubitOperator('X1 Y2')
     self.assertTrue(
         commutator(self.qubit_operator,
                    operator_b).isclose(self.qubit_operator * operator_b -
                                        operator_b * self.qubit_operator))
    def test_commutator(self):
        operator_a = (
            FermionOperator('0^ 0', 0.3) + FermionOperator('1^ 1', 0.1j) +
            FermionOperator('1^ 0^ 1 0', -0.2) + FermionOperator('1^ 3') +
            FermionOperator('3^ 0') + FermionOperator('3^ 2', 0.017) -
            FermionOperator('2^ 3', 1.99) + FermionOperator('3^ 1^ 3 1', .09) +
            FermionOperator('2^ 0^ 2 0', .126j) +
            FermionOperator('4^ 2^ 4 2') + FermionOperator('3^ 0^ 3 0'))

        operator_b = (
            FermionOperator('3^ 1', 0.7) + FermionOperator('1^ 3', -9.) +
            FermionOperator('1^ 0^ 3 0', 0.1) -
            FermionOperator('3^ 0^ 1 0', 0.11) + FermionOperator('3^ 2^ 3 2') +
            FermionOperator('3^ 1^ 3 1', -1.37) +
            FermionOperator('4^ 2^ 4 2') + FermionOperator('4^ 1^ 4 1') +
            FermionOperator('1^ 0^ 4 0', 16.7) +
            FermionOperator('1^ 0^ 4 3', 1.67) +
            FermionOperator('4^ 3^ 5 2', 1.789j) +
            FermionOperator('6^ 5^ 4 1', -11.789j))

        reference = normal_ordered(commutator(operator_a, operator_b))
        result = commutator_ordered_diagonal_coulomb_with_two_body_operator(
            operator_a, operator_b)

        diff = result - reference
        self.assertTrue(diff.isclose(FermionOperator.zero()))
    def test_integration_jellium_hamiltonian_with_negation(self):
        hamiltonian = normal_ordered(
            jellium_model(Grid(2, 3, 1.), plane_wave=False))

        part_a = FermionOperator.zero()
        part_b = FermionOperator.zero()

        add_to_a_or_b = 0  # add to a if 0; add to b if 1
        for term, coeff in hamiltonian.terms.items():
            # Partition terms in the Hamiltonian into part_a or part_b
            if add_to_a_or_b:
                part_a += FermionOperator(term, coeff)
            else:
                part_b += FermionOperator(term, coeff)
            add_to_a_or_b ^= 1

        reference = normal_ordered(commutator(part_a, part_b))
        result = commutator_ordered_diagonal_coulomb_with_two_body_operator(
            part_a, part_b)

        self.assertTrue(result.isclose(reference))

        negative = commutator_ordered_diagonal_coulomb_with_two_body_operator(
            part_b, part_a)
        result += negative

        self.assertTrue(result.isclose(FermionOperator.zero()))
コード例 #5
0
def generate_QCC_gradient_groupings(hamiltonian,
                                    n_qubits,
                                    hf_occ,
                                    cutoff=0.001):

    QMF_angles = np.concatenate([np.array([0] * n_qubits), np.pi * hf_occ])

    hamiltonian_flip_indices = get_hamiltonian_flipindices(
        hamiltonian, n_qubits)

    gradient_groupings = []

    for flip_indices in hamiltonian_flip_indices:

        representative_entangler = generate_qubitop(
            generate_representative(flip_indices, n_qubits))

        pauli_commutator = commutator(hamiltonian, representative_entangler)

        gradient = abs(
            1j / 2 * eval_meanfield_expectation(pauli_commutator, QMF_angles))

        if gradient > cutoff:

            gradient_groupings.append((flip_indices, round(gradient, 4)))

    gradient_groupings = Sort(gradient_groupings)

    return gradient_groupings
コード例 #6
0
def double_commutator(op1,
                      op2,
                      op3,
                      indices2=None,
                      indices3=None,
                      is_hopping_operator2=None,
                      is_hopping_operator3=None):
    """Return the double commutator [op1, [op2, op3]].

    Assumes the operators are from the dual basis Hamiltonian.

    Args:
        op1, op2, op3 (FermionOperators): operators for the commutator.
        indices2, indices3 (set): The indices op2 and op3 act on.
        is_hopping_operator2 (bool): Whether op2 is a hopping operator.
        is_hopping_operator3 (bool): Whether op3 is a hopping operator.

    Returns:
        The double commutator of the given operators.
    """
    if is_hopping_operator2 and is_hopping_operator3:
        indices2 = set(indices2)
        indices3 = set(indices3)
        # Determine which indices both op2 and op3 act on.
        try:
            intersection, = indices2.intersection(indices3)
        except ValueError:
            return FermionOperator.zero()

        # Remove the intersection from the set of indices, since it will get
        # cancelled out in the final result.
        indices2.remove(intersection)
        indices3.remove(intersection)

        # Find the indices of the final output hopping operator.
        index2, = indices2
        index3, = indices3
        coeff2 = op2.terms[list(op2.terms)[0]]
        coeff3 = op3.terms[list(op3.terms)[0]]
        commutator23 = (FermionOperator(
            ((index2, 1), (index3, 0)), coeff2 * coeff3) + FermionOperator(
                ((index3, 1), (index2, 0)), -coeff2 * coeff3))
    else:
        commutator23 = normal_ordered(commutator(op2, op3))

    return normal_ordered(commutator(op1, commutator23))
    def test_integration_random_diagonal_coulomb_hamiltonian(self):
        hamiltonian1 = normal_ordered(
            get_fermion_operator(
                random_diagonal_coulomb_hamiltonian(n_qubits=7)))
        hamiltonian2 = normal_ordered(
            get_fermion_operator(
                random_diagonal_coulomb_hamiltonian(n_qubits=7)))

        reference = normal_ordered(commutator(hamiltonian1, hamiltonian2))
        result = commutator_ordered_diagonal_coulomb_with_two_body_operator(
            hamiltonian1, hamiltonian2)

        self.assertTrue(result.isclose(reference))
コード例 #8
0
    def test_uccsd_singlet_symmetries(self):
        """Test that the singlet generator has the correct symmetries."""
        test_orbitals = 8
        test_electrons = 4

        packed_amplitude_size = uccsd_singlet_paramsize(
            test_orbitals, test_electrons)
        packed_amplitudes = randn(int(packed_amplitude_size))
        generator = uccsd_singlet_generator(packed_amplitudes, test_orbitals,
                                            test_electrons)

        # Construct symmetry operators
        sz = sz_operator(test_orbitals)
        s_squared = s_squared_operator(test_orbitals)

        # Check the symmetries
        comm_sz = normal_ordered(commutator(generator, sz))
        comm_s_squared = normal_ordered(commutator(generator, s_squared))
        zero = FermionOperator()

        self.assertEqual(comm_sz, zero)
        self.assertEqual(comm_s_squared, zero)
コード例 #9
0
ファイル: _bch_expansion.py プロジェクト: donnice/OpenFermion
def bin_str_to_commutator(bin_str, x, y):
    """
    Generate nested commutator in Dynkin's style with binary string representation
    e.g. '010...' -> [X,[Y,[X, ...]]]
    """
    from openfermion.utils import commutator

    char_to_xy = lambda char: x if char == '0' else y
    next_term = char_to_xy(bin_str[0])
    later_terms = bin_str[1:]
    if len(bin_str) == 1:
        return next_term
    else:
        return commutator(next_term, bin_str_to_commutator(later_terms, x, y))
コード例 #10
0
        def add_singles(occ_idx, vir_idx):
            for i in occ_idx:
                for a in vir_idx:
                    single = FermionOperator(((a, 1), (i, 0)))
                    # 1. build Fermion anti-Hermitian operator
                    single -= hermitian_conjugated(single)
                    # 2. JW transformation to qubit operator
                    jw_single = jordan_wigner(single)
                    h_single_commutator = commutator(self.h_qubit_OF, jw_single)
                    # 3. qforte.build_from_openfermion(OF_qubitop)
                    qf_jw_single = qforte.build_from_openfermion(jw_single)
                    qf_commutator = qforte.build_from_openfermion(h_single_commutator)

                    self.fermion_ops.append((i,a))
                    self.jw_ops.append(qf_jw_single)
                    self.jw_commutators.append(qf_commutator)
    def test_warning_on_bad_input_first_arg(self):
        with warnings.catch_warnings(record=True) as w:
            operator_a = FermionOperator('4^ 3^ 2 1')
            operator_b = FermionOperator('3^ 2^ 3 2')

            reference = normal_ordered(commutator(operator_a, operator_b))
            result = (
                commutator_ordered_diagonal_coulomb_with_two_body_operator(
                    operator_a, operator_b))

            self.assertTrue(len(w) == 1)
            self.assertIn('Defaulted to standard commutator evaluation',
                          str(w[-1].message))

            # Result should still be correct in this case.
            diff = result - reference
            self.assertTrue(diff.isclose(FermionOperator.zero()))
コード例 #12
0
        def add_doubles(occ_idx_pairs, vir_idx_pairs):
            for ji in occ_idx_pairs:
                for ba in vir_idx_pairs:
                    j, i = ji
                    b, a = ba

                    double = FermionOperator(F'{a}^ {b}^ {i} {j}')
                    double -= hermitian_conjugated(double)
                    jw_double = jordan_wigner(double)
                    h_double_commutator = commutator(self.h_qubit_OF, jw_double)

                    qf_jw_double = qforte.build_from_openfermion(jw_double)
                    qf_commutator = qforte.build_from_openfermion(
                    h_double_commutator)

                    self.fermion_ops.append((j,i,b,a))
                    self.jw_ops.append(qf_jw_double)
                    self.jw_commutators.append(qf_commutator)
コード例 #13
0
def benchmark_commutator_diagonal_coulomb_operators_2D_spinless_jellium(
        side_length):
    """Test speed of computing commutators using specialized functions.

    Args:
        side_length: The side length of the 2D jellium grid. There are
            side_length ** 2 qubits, and O(side_length ** 4) terms in the
            Hamiltonian.

    Returns:
        runtime_commutator: The time it takes to compute a commutator, after
            partitioning the terms and normal ordering, using the regular
            commutator function.
        runtime_diagonal_commutator: The time it takes to compute the same
            commutator using methods restricted to diagonal Coulomb operators.
    """
    hamiltonian = normal_ordered(
        jellium_model(Grid(2, side_length, 1.), plane_wave=False))

    part_a = FermionOperator.zero()
    part_b = FermionOperator.zero()
    add_to_a_or_b = 0  # add to a if 0; add to b if 1
    for term, coeff in hamiltonian.terms.items():
        # Partition terms in the Hamiltonian into part_a or part_b
        if add_to_a_or_b:
            part_a += FermionOperator(term, coeff)
        else:
            part_b += FermionOperator(term, coeff)
        add_to_a_or_b ^= 1

    start = time.time()
    _ = normal_ordered(commutator(part_a, part_b))
    end = time.time()
    runtime_commutator = end - start

    start = time.time()
    _ = commutator_ordered_diagonal_coulomb_with_two_body_operator(
        part_a, part_b)
    end = time.time()
    runtime_diagonal_commutator = end - start

    return runtime_commutator, runtime_diagonal_commutator
コード例 #14
0
def single_operator_gradient(p, q, jw_hamiltonian, state, n_qubits):
    """Function
    Compute gradient d<H>/dXpq

    Author(s): Masaki Taii, Takashi Tsuchimochi
    """
    dummy = FermionOperator(f"{n_qubits-1}^ {n_qubits-1}", 1.)
    fermi = FermionOperator(f"{p}^ {q}", 1.) + FermionOperator(
        f"{q}^ {p}", -1.)

    jw_dummy = jordan_wigner(dummy)
    jw_fermi = jordan_wigner(fermi)
    jw_gradient = commutator(jw_fermi, jw_hamiltonian) + jw_dummy

    observable_dummy \
            = create_observable_from_openfermion_text(str(jw_dummy))
    observable_gradient \
            = create_observable_from_openfermion_text(str(jw_gradient))

    gradient = (observable_gradient.get_expectation_value(state) \
                - observable_dummy.get_expectation_value(state))
    return gradient
コード例 #15
0
 def test_commutator_operator_a_bad_type(self):
     with self.assertRaises(TypeError):
         commutator(1, self.fermion_operator)
コード例 #16
0
def QCC(qubit_H,
        entanglers,
        angle_folds,
        amplitude_folds,
        sampler,
        num_cycles=5,
        num_samples=1000,
        strength=1e3,
        verbose=False):

    n, N_ent = count_qubits(qubit_H), len(entanglers)
    if N_ent == 0:
        QMF_energy, bloch_angles = QMF(qubit_H,
                                       angle_folds,
                                       sampler,
                                       num_cycles=num_cycles,
                                       num_samples=num_samples,
                                       strength=strength,
                                       verbose=verbose)
        return QMF_energy, bloch_angles

    expr = qubit_op_to_expr(qubit_H, angle_folds=angle_folds)

    #get coefficients
    if amplitude_folds == 0:
        alpha = [se.sin(se.Symbol('tau' + str(i))) for i in range(N_ent)]
        beta = [(1 - se.cos(se.Symbol('tau' + str(i)))) for i in range(N_ent)]
    elif amplitude_folds == 1:
        alpha = [
            se.Symbol('F' + str(i)) * se.sin(se.Symbol('tau' + str(i)))
            for i in range(N_ent)
        ]
        beta = [(1 - se.cos(se.Symbol('tau' + str(i)))) for i in range(N_ent)]
    else:
        alpha = [
            se.Symbol('F' + str(i)) * se.sin(se.Symbol('tau' + str(i)))
            for i in range(N_ent)
        ]
        beta = [
            (1 - se.Symbol('G' + str(i)) * se.cos(se.Symbol('tau' + str(i))))
            for i in range(N_ent)
        ]

    #calculate QCC transformation
    expr = 0
    entanglers_str = list(entanglers.keys())
    term_combs = list(itertools.product('abn', repeat=N_ent))
    for term_comb in term_combs:
        coeff, term = 1, qubit_H
        for i in range(len(term_comb)):
            char, P = term_comb[i], entanglers[entanglers_str[i]]

            if char == 'a':
                coeff *= alpha[i]
                term = -1j / 2 * commutator(term, P)
            elif char == 'b':
                coeff *= beta[i]
                term = 1 / 2 * P * commutator(term, P)

        term = qubit_op_to_expr(term, angle_folds=angle_folds)
        expr += coeff * term

    #minimize QCC expression
    QCC_energy, cont_dict, disc_dict = minimize_expr(expr,
                                                     angle_folds,
                                                     amplitude_folds,
                                                     sampler,
                                                     max_cycles=num_cycles,
                                                     num_samples=num_samples,
                                                     strength=strength,
                                                     verbose=verbose)

    #unfold continuous variables
    for key in cont_dict:
        num = str(key)[3:]
        if str(key)[:3] == 'phi':
            if angle_folds == 3:
                try:
                    W = disc_dict[se.Symbol('W' + str(num))]
                    if W == -1:
                        cont_dict[key] = np.pi - cont_dict[key]
                except KeyError:
                    pass
            if angle_folds >= 2:
                try:
                    Q = disc_dict[se.Symbol('Q' + str(num))]
                    if Q == -1:
                        cont_dict[key] = 2 * np.pi - cont_dict[key]
                except KeyError:
                    pass

        elif str(key)[:3] == 'the':
            if angle_folds >= 1:
                try:
                    Z = disc_dict[se.Symbol('Z' + str(num))]
                    if Z == -1:
                        cont_dict[key] = np.pi - cont_dict[key]
                except KeyError:
                    pass

        else:
            if amplitude_folds == 2:
                try:
                    G = disc_dict[se.Symbol('G' + str(num))]
                    if G == 1:
                        cont_dict[key] = np.pi - cont_dict[key]
                except KeyError:
                    pass
            if amplitude_folds >= 1:
                try:
                    F = disc_dict[se.Symbol('F' + str(num))]
                    if F == -1:
                        cont_dict[key] = 2 * np.pi - cont_dict[key]
                except KeyError:
                    pass

    return QCC_energy, cont_dict
コード例 #17
0
def bch_expand_baseline(x, y, order):
    """Compute log[e^x e^y] using the Baker-Campbell-Hausdorff formula
    Args:
        x: An operator for which multiplication and addition are supported.
            For instance, a QubitOperator, FermionOperator or numpy array.
        y: The same type as x.
        order(int): The order to truncate the BCH expansions. Currently
            function goes up to only third order.

    Returns:
        z: The truncated BCH operator.

    Raises:
        ValueError: operator x is not same type as operator y.
        ValueError: invalid order parameter.
        ValueError: order exceeds maximum order supported.
    """
    from openfermion.utils import commutator

    # First order.
    z = x + y

    # Second order.
    if order > 1:
        z += commutator(x, y) / 2.

    # Third order.
    if order > 2:
        z += commutator(x, commutator(x, y)) / 12.
        z += commutator(y, commutator(y, x)) / 12.

    # Fourth order.
    if order > 3:
        z -= commutator(y, commutator(x, commutator(x, y))) / 24.

    # Fifth order.
    if order > 4:
        z -= commutator(
            y, commutator(y, commutator(y, commutator(y, x)))) / 720.
        z -= commutator(
            x, commutator(x, commutator(x, commutator(x, y)))) / 720.
        z += commutator(
            x, commutator(y, commutator(y, commutator(y, x)))) / 360.
        z += commutator(
            y, commutator(x, commutator(x, commutator(x, y)))) / 360.
        z += commutator(
            y, commutator(x, commutator(y, commutator(x, y)))) / 120.
        z += commutator(
            x, commutator(y, commutator(x, commutator(y, x)))) / 120.

    return z
コード例 #18
0
 def test_commutes_identity(self):
     com = commutator(FermionOperator.identity(),
                      FermionOperator('2^ 3', 2.3))
     self.assertTrue(com.isclose(FermionOperator.zero()))
コード例 #19
0
 def test_commutes_no_intersection(self):
     com = commutator(FermionOperator('2^ 3'), FermionOperator('4^ 5^ 3'))
     com = normal_ordered(com)
     self.assertTrue(com.isclose(FermionOperator.zero()))
コード例 #20
0
 def test_commutes_number_operators(self):
     com = commutator(FermionOperator('4^ 3^ 4 3'), FermionOperator('2^ 2'))
     com = normal_ordered(com)
     self.assertTrue(com.isclose(FermionOperator.zero()))
コード例 #21
0
 def test_commutator_hopping_operators(self):
     com = commutator(3 * FermionOperator('1^ 2'), FermionOperator('2^ 3'))
     com = normal_ordered(com)
     self.assertTrue(com.isclose(FermionOperator('1^ 3', 3)))
コード例 #22
0
 def test_commutator_not_same_type(self):
     with self.assertRaises(TypeError):
         commutator(self.fermion_operator, self.qubit_operator)
コード例 #23
0
 def test_commutator_hopping_with_single_number(self):
     com = commutator(FermionOperator('1^ 2', 1j), FermionOperator('1^ 1'))
     com = normal_ordered(com)
     self.assertTrue(com.isclose(-FermionOperator('1^ 2') * 1j))
コード例 #24
0
 def test_commutator_hopping_with_double_number_two_intersections(self):
     com = commutator(FermionOperator('2^ 3'), FermionOperator('3^ 2^ 3 2'))
     com = normal_ordered(com)
     self.assertTrue(com.isclose(FermionOperator.zero()))
コード例 #25
0
ファイル: _sparse_tools.py プロジェクト: skynet/OpenFermion
def jw_get_ground_states_by_particle_number(sparse_operator,
                                            particle_number,
                                            sparse=True,
                                            num_eigs=3):
    """For a Jordan-Wigner encoded Hermitian operator, compute the lowest
    eigenvalue and eigenstates at a particular particle number. The operator
    must conserve particle number.

    Args:
        sparse_operator(sparse): A Jordan-Wigner encoded sparse operator.
        particle_number(int): The particle number at which to compute
            ground states.
        sparse(boolean, optional): Whether to use sparse eigensolver.
            Default is True.
        num_eigs(int, optional): The number of eigenvalues to request from the
            sparse eigensolver. Needs to be at least as large as the degeneracy
            of the ground energy in order to obtain all ground states.
            Only used if `sparse=True`. Default is 3.

    Returns:
        ground_energy(float): The lowest eigenvalue of sparse_operator within
            the eigenspace of the number operator corresponding to
            particle_number.

        ground_states(list[ndarray]): A list of the corresponding eigenstates.

    Warning:
        The running time of this method is exponential in the number of qubits.
    """
    # Check if operator is Hermitian
    if not is_hermitian(sparse_operator):
        raise ValueError('sparse_operator must be Hermitian.')

    n_qubits = int(numpy.log2(sparse_operator.shape[0]))

    # Check if operator conserves particle number
    sparse_num_op = jordan_wigner_sparse(number_operator(n_qubits))
    com = commutator(sparse_num_op, sparse_operator)
    if com.nnz:
        maxval = max(map(abs, com.data))
        if maxval > EQ_TOLERANCE:
            raise ValueError('sparse_operator must conserve particle number.')

    # Get the operator restricted to the subspace of the desired
    # particle number
    restricted_operator = jw_number_restrict_operator(sparse_operator,
                                                      particle_number,
                                                      n_qubits)

    if sparse and num_eigs >= restricted_operator.shape[0] - 1:
        # Restricted operator too small for sparse eigensolver
        sparse = False

    # Compute eigenvalues and eigenvectors
    if sparse:
        eigvals, eigvecs = scipy.sparse.linalg.eigsh(restricted_operator,
                                                     k=num_eigs,
                                                     which='SA')
        if abs(max(eigvals) - min(eigvals)) < EQ_TOLERANCE:
            warnings.warn(
                'The lowest {} eigenvalues are degenerate. '
                'There may be more ground states; increase '
                'num_eigs or set sparse=False to get '
                'them.'.format(num_eigs), RuntimeWarning)
    else:
        dense_restricted_operator = restricted_operator.toarray()
        eigvals, eigvecs = numpy.linalg.eigh(dense_restricted_operator)

    # Get the ground energy
    if sparse:
        ground_energy = sorted(eigvals)[0]
    else:
        # No need to sort in the case of dense eigenvalue computation
        ground_energy = eigvals[0]

    # Get the indices of eigenvectors corresponding to the ground energy
    ground_state_indices = numpy.where(
        abs(eigvals - ground_energy) < EQ_TOLERANCE)

    ground_states = list()

    for i in ground_state_indices[0]:
        restricted_ground_state = eigvecs[:, i]
        # Expand this ground state to the whole vector space
        number_indices = jw_number_indices(particle_number, n_qubits)
        expanded_ground_state = scipy.sparse.csc_matrix(
            (restricted_ground_state.flatten(),
             (number_indices, [0] * len(number_indices))),
            shape=(2**n_qubits, 1))
        # Add the expanded ground state to the list
        ground_states.append(expanded_ground_state)

    return ground_energy, ground_states
コード例 #26
0
 def test_commutator_operator_b_bad_type(self):
     with self.assertRaises(TypeError):
         commutator(self.qubit_operator, "hello")