def test_bogoliubov_transform_quadratic_hamiltonian_inverse_is_dagger(
        n_qubits, real, particle_conserving, atol):
    quad_ham = random_quadratic_hamiltonian(
        n_qubits,
        real=real,
        conserves_particle_number=particle_conserving,
        seed=46533)
    _, transformation_matrix, _ = quad_ham.diagonalizing_bogoliubov_transform()

    qubits = cirq.LineQubit.range(n_qubits)

    if transformation_matrix.shape == (n_qubits, n_qubits):
        daggered_transformation_matrix = transformation_matrix.T.conj()
    else:
        left_block = transformation_matrix[:, :n_qubits]
        right_block = transformation_matrix[:, n_qubits:]
        daggered_transformation_matrix = numpy.block(
            [left_block.T.conj(), right_block.T])

    circuit1 = cirq.Circuit(
        cirq.inverse(bogoliubov_transform(qubits, transformation_matrix)))

    circuit2 = cirq.Circuit(
        bogoliubov_transform(qubits, daggered_transformation_matrix))

    cirq.testing.assert_allclose_up_to_global_phase(circuit1.unitary(),
                                                    circuit2.unitary(),
                                                    atol=atol)
def test_bogoliubov_transform_quadratic_hamiltonian(n_qubits,
                                                    conserves_particle_number,
                                                    atol=5e-5):
    qubits = LineQubit.range(n_qubits)

    # Initialize a random quadratic Hamiltonian
    quad_ham = random_quadratic_hamiltonian(n_qubits,
                                            conserves_particle_number,
                                            real=False)
    quad_ham_sparse = get_sparse_operator(quad_ham)

    # Compute the orbital energies and circuit
    orbital_energies, transformation_matrix, constant = (
        quad_ham.diagonalizing_bogoliubov_transform())
    circuit = cirq.Circuit(bogoliubov_transform(qubits, transformation_matrix))

    # Pick some random eigenstates to prepare, which correspond to random
    # subsets of [0 ... n_qubits - 1]
    n_eigenstates = min(2**n_qubits, 5)
    subsets = [
        numpy.random.choice(range(n_qubits),
                            numpy.random.randint(1, n_qubits + 1), False)
        for _ in range(n_eigenstates)
    ]
    # Also test empty subset
    subsets += [()]

    for occupied_orbitals in subsets:
        # Compute the energy of this eigenstate
        energy = (sum(orbital_energies[i] for i in occupied_orbitals) +
                  constant)

        # Construct initial state
        initial_state = sum(
            2**(n_qubits - 1 - int(i)) for i in occupied_orbitals)

        # Get the state using a circuit simulation
        state1 = circuit.final_wavefunction(initial_state)

        # Also test the option to start with a computational basis state
        special_circuit = cirq.Circuit(
            bogoliubov_transform(qubits,
                                 transformation_matrix,
                                 initial_state=initial_state))
        state2 = special_circuit.final_wavefunction(
            initial_state, qubits_that_should_be_present=qubits)

        # Check that the result is an eigenstate with the correct eigenvalue
        numpy.testing.assert_allclose(quad_ham_sparse.dot(state1),
                                      energy * state1,
                                      atol=atol)
        numpy.testing.assert_allclose(quad_ham_sparse.dot(state2),
                                      energy * state2,
                                      atol=atol)
Beispiel #3
0
def test_spin_symmetric_bogoliubov_transform(n_spatial_orbitals,
                                             conserves_particle_number,
                                             atol=5e-5):
    n_qubits = 2 * n_spatial_orbitals
    qubits = LineQubit.range(n_qubits)

    # Initialize a random quadratic Hamiltonian
    quad_ham = random_quadratic_hamiltonian(n_spatial_orbitals,
                                            conserves_particle_number,
                                            real=True,
                                            expand_spin=True,
                                            seed=28166)

    # Reorder the Hamiltonian and get sparse matrix
    quad_ham = openfermion.get_quadratic_hamiltonian(
        openfermion.reorder(openfermion.get_fermion_operator(quad_ham),
                            openfermion.up_then_down))
    quad_ham_sparse = get_sparse_operator(quad_ham)

    # Compute the orbital energies and transformation_matrix
    up_orbital_energies, _, _ = (quad_ham.diagonalizing_bogoliubov_transform(
        spin_sector=0))
    down_orbital_energies, _, _ = (quad_ham.diagonalizing_bogoliubov_transform(
        spin_sector=1))
    _, transformation_matrix, _ = (
        quad_ham.diagonalizing_bogoliubov_transform())

    # Pick some orbitals to occupy
    up_orbitals = list(range(2))
    down_orbitals = [0, 2, 3]
    energy = sum(up_orbital_energies[up_orbitals]) + sum(
        down_orbital_energies[down_orbitals]) + quad_ham.constant

    # Construct initial state
    initial_state = (sum(2**(n_qubits - 1 - int(i)) for i in up_orbitals) +
                     sum(2**(n_qubits - 1 - int(i + n_spatial_orbitals))
                         for i in down_orbitals))

    # Apply the circuit
    circuit = cirq.Circuit(
        bogoliubov_transform(qubits,
                             transformation_matrix,
                             initial_state=initial_state))
    state = circuit.final_state_vector(initial_state=initial_state)

    # Check that the result is an eigenstate with the correct eigenvalue
    numpy.testing.assert_allclose(quad_ham_sparse.dot(state),
                                  energy * state,
                                  atol=atol)
def test_prepare_gaussian_state_with_spin_symmetry(n_spatial_orbitals,
                                                   conserves_particle_number,
                                                   occupied_orbitals,
                                                   initial_state,
                                                   atol=1e-5):

    n_qubits = 2 * n_spatial_orbitals
    qubits = LineQubit.range(n_qubits)

    # Initialize a random quadratic Hamiltonian
    quad_ham = random_quadratic_hamiltonian(n_spatial_orbitals,
                                            conserves_particle_number,
                                            real=True,
                                            expand_spin=True,
                                            seed=639)

    # Reorder the Hamiltonian and get sparse matrix
    quad_ham = openfermion.get_quadratic_hamiltonian(
        openfermion.reorder(openfermion.get_fermion_operator(quad_ham),
                            openfermion.up_then_down))
    quad_ham_sparse = get_sparse_operator(quad_ham)

    # Compute the energy of the desired state
    energy = 0.0
    for spin_sector in range(2):
        orbital_energies, _, _ = (quad_ham.diagonalizing_bogoliubov_transform(
            spin_sector=spin_sector))
        energy += sum(orbital_energies[i]
                      for i in occupied_orbitals[spin_sector])
    energy += quad_ham.constant

    # Get the state using a circuit simulation
    circuit = cirq.Circuit(
        prepare_gaussian_state(qubits,
                               quad_ham,
                               occupied_orbitals,
                               initial_state=initial_state))

    if isinstance(initial_state, list):
        initial_state = sum(1 << (n_qubits - 1 - i) for i in initial_state)
    state = circuit.final_state_vector(initial_state=initial_state)

    # Check that the result is an eigenstate with the correct eigenvalue
    numpy.testing.assert_allclose(quad_ham_sparse.dot(state),
                                  energy * state,
                                  atol=atol)
def test_prepare_gaussian_state(n_qubits,
                                conserves_particle_number,
                                occupied_orbitals,
                                initial_state,
                                atol=1e-5):

    qubits = LineQubit.range(n_qubits)

    # Initialize a random quadratic Hamiltonian
    quad_ham = random_quadratic_hamiltonian(n_qubits,
                                            conserves_particle_number,
                                            real=False)
    quad_ham_sparse = get_sparse_operator(quad_ham)

    # Compute the energy of the desired state
    if occupied_orbitals is None:
        energy = quad_ham.ground_energy()
    else:
        orbital_energies, _, constant = (
            quad_ham.diagonalizing_bogoliubov_transform())
        energy = sum(orbital_energies[i] for i in occupied_orbitals) + constant

    # Get the state using a circuit simulation
    circuit = cirq.Circuit(
        prepare_gaussian_state(qubits,
                               quad_ham,
                               occupied_orbitals,
                               initial_state=initial_state))
    if isinstance(initial_state, list):
        initial_state = sum(1 << (n_qubits - 1 - i) for i in initial_state)
    state = circuit.final_state_vector(initial_state=initial_state)

    # Check that the result is an eigenstate with the correct eigenvalue
    numpy.testing.assert_allclose(quad_ham_sparse.dot(state),
                                  energy * state,
                                  atol=atol)