예제 #1
0
def _slater_basis_change(
        qubits: Sequence[cirq.QubitId], transformation_matrix: numpy.ndarray,
        initially_occupied_orbitals: Optional[Sequence[int]]) -> cirq.OP_TREE:
    n_qubits = len(qubits)

    if initially_occupied_orbitals is None:
        decomposition, diagonal = givens_decomposition_square(
            transformation_matrix)
        circuit_description = list(reversed(decomposition))
        # The initial state is not a computational basis state so the
        # phases left on the diagonal in the decomposition matter
        yield (cirq.Rz(rads=numpy.angle(diagonal[j])).on(qubits[j])
               for j in range(n_qubits))
    else:
        initially_occupied_orbitals = cast(Sequence[int],
                                           initially_occupied_orbitals)
        transformation_matrix = transformation_matrix[list(
            initially_occupied_orbitals)]
        n_occupied = len(initially_occupied_orbitals)
        # Flip bits so that the first n_occupied are 1 and the rest 0
        initially_occupied_orbitals_set = set(initially_occupied_orbitals)
        yield (cirq.X(qubits[j]) for j in range(n_qubits)
               if (j < n_occupied) != (j in initially_occupied_orbitals_set))
        circuit_description = slater_determinant_preparation_circuit(
            transformation_matrix)

    yield _ops_from_givens_rotations_circuit_description(
        qubits, circuit_description)
예제 #2
0
    def diagonalizing_circuit(self):
        r"""Get a circuit for a unitary that diagonalizes this Hamiltonian

        This circuit performs the transformation to a basis in which the
        Hamiltonian takes the diagonal form

        .. math::

            \sum_{j} \varepsilon_j b^\dagger_j b_j + \text{constant}.

        Returns
        -------
            circuit_description (list[tuple]):
                A list of operations describing the circuit. Each operation
                is a tuple of objects describing elementary operations that
                can be performed in parallel. Each elementary operation
                is either the string 'pht' indicating a particle-hole
                transformation on the last fermionic mode, or a tuple of
                the form :math:`(i, j, \theta, \varphi)`,
                indicating a Givens rotation
                of modes :math:`i` and :math:`j` by angles :math:`\theta`
                and :math:`\varphi`.
        """
        transformation_matrix = self.diagonalizing_bogoliubov_transform()

        if self.conserves_particle_number:
            # The Hamiltonian conserves particle number, so we don't need
            # to use the most general procedure.
            decomposition, _ = givens_decomposition_square(
                    transformation_matrix)
            circuit_description = list(reversed(decomposition))
        else:
            # The Hamiltonian does not conserve particle number, so we
            # need to use the most general procedure.
            # Rearrange the transformation matrix because the circuit
            # generation routine expects it to describe annihilation
            # operators rather than creation operators.
            left_block = transformation_matrix[:, :self.n_qubits]
            right_block = transformation_matrix[:, self.n_qubits:]

            # Can't use numpy.block because that requires numpy>=1.13.0
            new_transformation_matrix = numpy.empty(
                    (self.n_qubits, 2 * self.n_qubits), dtype=complex)
            new_transformation_matrix[:, :self.n_qubits] = numpy.conjugate(
                    right_block)
            new_transformation_matrix[:, self.n_qubits:] = numpy.conjugate(
                    left_block)

            # Get the circuit description
            decomposition, left_decomposition, _, _ = (
                fermionic_gaussian_decomposition(new_transformation_matrix))

            # need to use left_diagonal too
            circuit_description = list(reversed(
                decomposition + left_decomposition))

        return circuit_description
예제 #3
0
    def diagonalizing_circuit(self):
        """Get a circuit for a unitary that diagonalizes this Hamiltonian

        This circuit performs the transformation to a basis in which the
        Hamiltonian takes the diagonal form

        .. math::

            \sum_{j} \\varepsilon_j b^\dagger_j b_j + \\text{constant}.

        Returns
        -------
            circuit_description (list[tuple]):
                A list of operations describing the circuit. Each operation
                is a tuple of objects describing elementary operations that
                can be performed in parallel. Each elementary operation
                is either the string 'pht' indicating a particle-hole
                transformation on the last fermionic mode, or a tuple of
                the form :math:`(i, j, \\theta, \\varphi)`,
                indicating a Givens rotation
                of modes :math:`i` and :math:`j` by angles :math:`\\theta`
                and :math:`\\varphi`.
        """
        diagonalizing_unitary = self.diagonalizing_bogoliubov_transform()

        if self.conserves_particle_number:
            # The Hamiltonian conserves particle number, so we don't need
            # to use the most general procedure.
            decomposition, diagonal = givens_decomposition_square(
                diagonalizing_unitary)
            circuit_description = list(reversed(decomposition))
        else:
            # The Hamiltonian does not conserve particle number, so we
            # need to use the most general procedure.
            # Get the unitary rows which represent the Gaussian unitary
            gaussian_unitary_matrix = diagonalizing_unitary[self.n_qubits:]

            # Get the circuit description
            decomposition, left_decomposition, diagonal, left_diagonal = (
                fermionic_gaussian_decomposition(gaussian_unitary_matrix))
            # need to use left_diagonal too
            circuit_description = list(
                reversed(decomposition + left_decomposition))

        return circuit_description
 def _rotate_mo(mo_coeff, mo_occ, dx):
     decompositio = []
     dr = pyscf.scf.hf.unpack_uniq_var(dx, mo_occ)
     u = scipy.linalg.expm(dr)
     decomposition = givens_decomposition_square(u)
     return np.dot(mo_coeff, u)