Exemplo n.º 1
0
    def _build_hopping_operator(index, num_orbitals, num_particles, qubit_mapping,
                                two_qubit_reduction, z2_symmetries):

        h_1 = np.zeros((num_orbitals, num_orbitals))
        h_2 = np.zeros((num_orbitals, num_orbitals, num_orbitals, num_orbitals))
        if len(index) == 2:
            i, j = index
            h_1[i, j] = 1.0
            h_1[j, i] = -1.0
        elif len(index) == 4:
            i, j, k, m = index
            h_2[i, j, k, m] = 1.0
            h_2[m, k, j, i] = -1.0

        dummpy_fer_op = FermionicOperator(h1=h_1, h2=h_2)
        qubit_op = dummpy_fer_op.mapping(qubit_mapping)
        if two_qubit_reduction:
            qubit_op = Z2Symmetries.two_qubit_reduction(qubit_op, num_particles)

        if not z2_symmetries.is_empty():
            symm_commuting = True
            for symmetry in z2_symmetries.symmetries:
                symmetry_op = WeightedPauliOperator(paulis=[[1.0, symmetry]])
                symm_commuting = qubit_op.commute_with(symmetry_op)
                if not symm_commuting:
                    break
            qubit_op = z2_symmetries.taper(qubit_op) if symm_commuting else None

        if qubit_op is None:
            logger.debug('Excitation (%s) is skipped since it is not commuted '
                         'with symmetries', ','.join([str(x) for x in index]))
        return qubit_op, index
Exemplo n.º 2
0
            def _dipole_op(dipole_integrals: np.ndarray, axis: str) \
                    -> Tuple[WeightedPauliOperator, float, float]:
                """
                Dipole operators

                Args:
                    dipole_integrals: dipole integrals
                    axis: axis for dipole moment calculation

                Returns:
                    (qubit_op_, shift, ph_shift_)
                """
                logger.debug('Creating aux op for dipole %s', axis)
                fer_op_ = FermionicOperator(h1=dipole_integrals)
                fer_op_, shift, did_shift_ = self._try_reduce_fermionic_operator(
                    fer_op_, freeze_list, remove_list)
                if did_shift_:
                    logger.info("Frozen orbital %s dipole shift: %s", axis,
                                shift)
                ph_shift_ = 0.0
                if self._transformation == FermionicTransformationType.PARTICLE_HOLE.value:
                    fer_op_, ph_shift_ = fer_op_.particle_hole_transformation(
                        new_nel)
                    ph_shift_ = -ph_shift_
                    logger.info("Particle hole %s dipole shift: %s", axis,
                                ph_shift_)
                qubit_op_ = self._map_fermionic_operator_to_qubit(
                    fer_op_, self._qubit_mapping, new_nel,
                    self._two_qubit_reduction)
                qubit_op_.name = 'Dipole ' + axis
                logger.debug('  num paulis: %s', len(qubit_op_.paulis))
                return qubit_op_, shift, ph_shift_
Exemplo n.º 3
0
    def _build_single_hopping_operator(index, num_particles, num_orbitals, qubit_mapping,
                                       two_qubit_reduction, z2_symmetries):

        h_1 = np.zeros((num_orbitals, num_orbitals), dtype=complex)
        h_2 = np.zeros((num_orbitals, num_orbitals, num_orbitals, num_orbitals), dtype=complex)
        if len(index) == 2:
            i, j = index
            h_1[i, j] = 4.0
        elif len(index) == 4:
            i, j, k, m = index
            h_2[i, j, k, m] = 16.0
        fer_op = FermionicOperator(h_1, h_2)
        qubit_op = fer_op.mapping(qubit_mapping)
        if qubit_mapping == 'parity' and two_qubit_reduction:
            qubit_op = Z2Symmetries.two_qubit_reduction(qubit_op, num_particles)

        commutativities = []
        if not z2_symmetries.is_empty():
            for symmetry in z2_symmetries.symmetries:
                symmetry_op = WeightedPauliOperator(paulis=[[1.0, symmetry]])
                commuting = qubit_op.commute_with(symmetry_op)
                anticommuting = qubit_op.anticommute_with(symmetry_op)

                if commuting != anticommuting:  # only one of them is True
                    if commuting:
                        commutativities.append(True)
                    elif anticommuting:
                        commutativities.append(False)
                else:
                    raise AquaError("Symmetry {} is nor commute neither anti-commute "
                                    "to exciting operator.".format(symmetry.to_label()))

        return qubit_op, commutativities
Exemplo n.º 4
0
 def _dipole_op(dipole_integrals, axis):
     logger.debug('Creating aux op for dipole {}'.format(axis))
     fer_op_ = FermionicOperator(h1=dipole_integrals)
     fer_op_, shift, did_shift_ = self._try_reduce_fermionic_operator(fer_op_, freeze_list, remove_list)
     if did_shift_:
         logger.info("Frozen orbital {} dipole shift: {}".format(axis, shift))
     ph_shift_ = 0.0
     if self._transformation == TransformationType.PH.value:
         fer_op_, ph_shift_ = fer_op_.particle_hole_transformation(new_nel)
         ph_shift_ = -ph_shift_
         logger.info("Particle hole {} dipole shift: {}".format(axis, ph_shift_))
     qubit_op_ = self._map_fermionic_operator_to_qubit(fer_op_, self._qubit_mapping, new_nel,
                                                       self._two_qubit_reduction)
     logger.debug('  num paulis: {}'.format(len(qubit_op_.paulis)))
     return qubit_op_, shift, ph_shift_
Exemplo n.º 5
0
    def _build_hopping_operator(self, index):
        def check_commutativity(op_1, op_2):
            com = op_1 * op_2 - op_2 * op_1
            com.zeros_coeff_elimination()
            return True if com.is_empty() else False

        two_d_zeros = np.zeros((self._num_orbitals, self._num_orbitals))
        four_d_zeros = np.zeros((self._num_orbitals, self._num_orbitals,
                                 self._num_orbitals, self._num_orbitals))

        dummpy_fer_op = FermionicOperator(h1=two_d_zeros, h2=four_d_zeros)
        h1 = two_d_zeros.copy()
        h2 = four_d_zeros.copy()
        if len(index) == 2:
            i, j = index
            h1[i, j] = 1.0
            h1[j, i] = -1.0
        elif len(index) == 4:
            i, j, k, m = index
            h2[i, j, k, m] = 1.0
            h2[m, k, j, i] = -1.0
        dummpy_fer_op.h1 = h1
        dummpy_fer_op.h2 = h2

        qubit_op = dummpy_fer_op.mapping(self._qubit_mapping)
        qubit_op = qubit_op.two_qubit_reduced_operator(
            self._num_particles) if self._two_qubit_reduction else qubit_op

        if self._qubit_tapering:
            for symmetry in self._symmetries:
                symmetry_op = Operator(paulis=[[1.0, symmetry]])
                symm_commuting = check_commutativity(symmetry_op, qubit_op)
                if not symm_commuting:
                    break

        if self._qubit_tapering:
            if symm_commuting:
                qubit_op = Operator.qubit_tapering(qubit_op, self._cliffords,
                                                   self._sq_list,
                                                   self._tapering_values)
            else:
                qubit_op = None

        if qubit_op is None:
            logger.debug('excitation ({}) is skipped since it is not commuted '
                         'with symmetries'.format(','.join(
                             [str(x) for x in index])))
        return qubit_op
Exemplo n.º 6
0
    def _build_hopping_operator(index, num_orbitals, num_particles,
                                qubit_mapping, two_qubit_reduction,
                                qubit_tapering, symmetries, cliffords, sq_list,
                                tapering_values):
        def check_commutativity(op_1, op_2):
            com = op_1 * op_2 - op_2 * op_1
            com.zeros_coeff_elimination()
            return True if com.is_empty() else False

        h1 = np.zeros((num_orbitals, num_orbitals))
        h2 = np.zeros((num_orbitals, num_orbitals, num_orbitals, num_orbitals))
        if len(index) == 2:
            i, j = index
            h1[i, j] = 1.0
            h1[j, i] = -1.0
        elif len(index) == 4:
            i, j, k, m = index
            h2[i, j, k, m] = 1.0
            h2[m, k, j, i] = -1.0

        dummpy_fer_op = FermionicOperator(h1=h1, h2=h2)
        qubit_op = dummpy_fer_op.mapping(qubit_mapping, num_workers=1)
        qubit_op = qubit_op.two_qubit_reduced_operator(num_particles) \
            if two_qubit_reduction else qubit_op

        if qubit_tapering:
            for symmetry in symmetries:
                symmetry_op = Operator(paulis=[[1.0, symmetry]])
                symm_commuting = check_commutativity(symmetry_op, qubit_op)
                if not symm_commuting:
                    break

        if qubit_tapering:
            if symm_commuting:
                qubit_op = Operator.qubit_tapering(qubit_op, cliffords,
                                                   sq_list, tapering_values)
            else:
                qubit_op = None

        if qubit_op is None:
            logger.debug('Excitation ({}) is skipped since it is not commuted '
                         'with symmetries'.format(','.join(
                             [str(x) for x in index])))
        return index, qubit_op
Exemplo n.º 7
0
 def _dipole_op(dipole_integrals, axis):
     logger.debug('Creating aux op for dipole %s', axis)
     fer_op_ = FermionicOperator(h1=dipole_integrals)
     fer_op_, shift, did_shift_ = self._try_reduce_fermionic_operator(fer_op_,
                                                                      freeze_list,
                                                                      remove_list)
     if did_shift_:
         logger.info("Frozen orbital %s dipole shift: %s", axis, shift)
     ph_shift_ = 0.0
     if self._transformation == TransformationType.PARTICLE_HOLE.value:
         fer_op_, ph_shift_ = fer_op_.particle_hole_transformation(new_nel)
         ph_shift_ = -ph_shift_
         logger.info("Particle hole %s dipole shift: %s", axis, ph_shift_)
     qubit_op_ = self._map_fermionic_operator_to_qubit(fer_op_,
                                                       self._qubit_mapping,
                                                       new_nel,
                                                       self._two_qubit_reduction)
     qubit_op_.name = 'Dipole ' + axis
     logger.debug('  num paulis: %s', len(qubit_op_.paulis))
     return qubit_op_, shift, ph_shift_
Exemplo n.º 8
0
    def _try_reduce_fermionic_operator(fer_op: FermionicOperator,
                                       freeze_list: List,
                                       remove_list: List) -> Tuple:
        """
        Trying to reduce the fermionic operator w.r.t to freeze and remove list if provided

        Args:
            fer_op: fermionic operator
            freeze_list: freeze list of orbitals
            remove_list: remove list of orbitals

        Returns:
            (fermionic_operator, energy_shift, did_shift)
        """
        # pylint: disable=len-as-condition
        did_shift = False
        energy_shift = 0.0
        if len(freeze_list) > 0:
            fer_op, energy_shift = fer_op.fermion_mode_freezing(freeze_list)
            did_shift = True
        if len(remove_list) > 0:
            fer_op = fer_op.fermion_mode_elimination(remove_list)
        return fer_op, energy_shift, did_shift
Exemplo n.º 9
0
    def _map_fermionic_operator_to_qubit(fer_op: FermionicOperator,
                                         qubit_mapping: str,
                                         num_particles: List[int],
                                         two_qubit_reduction: bool) -> WeightedPauliOperator:
        """

        Args:
            fer_op: Fermionic Operator
            qubit_mapping: fermionic to qubit mapping
            num_particles: number of particles
            two_qubit_reduction: two qubit reduction

        Returns:
            qubit operator
        """

        qubit_op = fer_op.mapping(map_type=qubit_mapping, threshold=0.00000001)
        if qubit_mapping == 'parity' and two_qubit_reduction:
            qubit_op = Z2Symmetries.two_qubit_reduction(qubit_op, num_particles)
        return qubit_op
Exemplo n.º 10
0
    def run(self, qmolecule):
        logger.debug('Processing started...')
        # Save these values for later combination with the quantum computation result
        self._hf_energy = qmolecule.hf_energy
        self._nuclear_repulsion_energy = qmolecule.nuclear_repulsion_energy
        self._nuclear_dipole_moment = qmolecule.nuclear_dipole_moment
        self._reverse_dipole_sign = qmolecule.reverse_dipole_sign

        core_list = qmolecule.core_orbitals if self._freeze_core else []
        reduce_list = self._orbital_reduction

        if self._freeze_core:
            logger.info("Freeze_core specified. Core orbitals to be frozen: %s", core_list)
        if reduce_list:
            logger.info("Configured orbital reduction list: %s", reduce_list)
            reduce_list = [x + qmolecule.num_orbitals if x < 0 else x for x in reduce_list]

        freeze_list = []
        remove_list = []

        # Orbitals are specified by their index from 0 to n-1, where n is the number of orbitals the
        # molecule has. The combined list of the core orbitals, when freeze_core is true, with any
        # user supplied orbitals is what will be used. Negative numbers may be used to indicate the
        # upper virtual orbitals, so -1 is the highest, then -2 etc. and these will
        # be converted to the
        # positive 0-based index for computation.
        # In the combined list any orbitals that are occupied are added to a freeze list and an
        # energy is stored from these orbitals to be added later.
        # Unoccupied orbitals are just discarded.
        # Because freeze and eliminate is done in separate steps,
        # with freeze first, we have to re-base
        # the indexes for elimination according to how many orbitals were removed when freezing.
        #
        orbitals_list = list(set(core_list + reduce_list))
        num_alpha = qmolecule.num_alpha
        num_beta = qmolecule.num_beta
        new_num_alpha = num_alpha
        new_num_beta = num_beta
        if orbitals_list:
            orbitals_list = np.array(orbitals_list)
            orbitals_list = \
                orbitals_list[(orbitals_list >= 0) & (orbitals_list < qmolecule.num_orbitals)]

            freeze_list_alpha = [i for i in orbitals_list if i < num_alpha]
            freeze_list_beta = [i for i in orbitals_list if i < num_beta]
            freeze_list = np.append(freeze_list_alpha,
                                    [i + qmolecule.num_orbitals for i in freeze_list_beta])

            remove_list_alpha = [i for i in orbitals_list if i >= num_alpha]
            remove_list_beta = [i for i in orbitals_list if i >= num_beta]
            rla_adjust = -len(freeze_list_alpha)
            rlb_adjust = -len(freeze_list_alpha) - len(freeze_list_beta) + qmolecule.num_orbitals
            remove_list = np.append([i + rla_adjust for i in remove_list_alpha],
                                    [i + rlb_adjust for i in remove_list_beta])

            logger.info("Combined orbital reduction list: %s", orbitals_list)
            logger.info("  converting to spin orbital reduction list: %s",
                        np.append(np.array(orbitals_list),
                                  np.array(orbitals_list) + qmolecule.num_orbitals))
            logger.info("    => freezing spin orbitals: %s", freeze_list)
            logger.info("    => removing spin orbitals: %s (indexes accounting for freeze %s)",
                        np.append(remove_list_alpha,
                                  np.array(remove_list_beta) + qmolecule.num_orbitals), remove_list)

            new_num_alpha -= len(freeze_list_alpha)
            new_num_beta -= len(freeze_list_beta)

        new_nel = [new_num_alpha, new_num_beta]

        fer_op = FermionicOperator(h1=qmolecule.one_body_integrals, h2=qmolecule.two_body_integrals)
        fer_op, self._energy_shift, did_shift = \
            Hamiltonian._try_reduce_fermionic_operator(fer_op, freeze_list, remove_list)
        if did_shift:
            logger.info("Frozen orbital energy shift: %s", self._energy_shift)
        if self._transformation == TransformationType.PARTICLE_HOLE.value:
            fer_op, ph_shift = fer_op.particle_hole_transformation(new_nel)
            self._ph_energy_shift = -ph_shift
            logger.info("Particle hole energy shift: %s", self._ph_energy_shift)
        logger.debug('Converting to qubit using %s mapping', self._qubit_mapping)
        qubit_op = Hamiltonian._map_fermionic_operator_to_qubit(fer_op,
                                                                self._qubit_mapping, new_nel,
                                                                self._two_qubit_reduction)
        qubit_op.name = 'Electronic Hamiltonian'

        logger.debug('  num paulis: %s, num qubits: %s', len(qubit_op.paulis), qubit_op.num_qubits)

        aux_ops = []

        def _add_aux_op(aux_op, name):
            aux_qop = Hamiltonian._map_fermionic_operator_to_qubit(aux_op,
                                                                   self._qubit_mapping,
                                                                   new_nel,
                                                                   self._two_qubit_reduction)
            aux_qop.name = name
            aux_ops.append(aux_qop)
            logger.debug('  num paulis: %s', aux_qop.paulis)

        logger.debug('Creating aux op for Number of Particles')
        _add_aux_op(fer_op.total_particle_number(), 'Number of Particles')
        logger.debug('Creating aux op for S^2')
        _add_aux_op(fer_op.total_angular_momentum(), 'S^2')
        logger.debug('Creating aux op for Magnetization')
        _add_aux_op(fer_op.total_magnetization(), 'Magnetization')

        if qmolecule.has_dipole_integrals():
            def _dipole_op(dipole_integrals, axis):
                logger.debug('Creating aux op for dipole %s', axis)
                fer_op_ = FermionicOperator(h1=dipole_integrals)
                fer_op_, shift, did_shift_ = self._try_reduce_fermionic_operator(fer_op_,
                                                                                 freeze_list,
                                                                                 remove_list)
                if did_shift_:
                    logger.info("Frozen orbital %s dipole shift: %s", axis, shift)
                ph_shift_ = 0.0
                if self._transformation == TransformationType.PARTICLE_HOLE.value:
                    fer_op_, ph_shift_ = fer_op_.particle_hole_transformation(new_nel)
                    ph_shift_ = -ph_shift_
                    logger.info("Particle hole %s dipole shift: %s", axis, ph_shift_)
                qubit_op_ = self._map_fermionic_operator_to_qubit(fer_op_,
                                                                  self._qubit_mapping,
                                                                  new_nel,
                                                                  self._two_qubit_reduction)
                qubit_op_.name = 'Dipole ' + axis
                logger.debug('  num paulis: %s', len(qubit_op_.paulis))
                return qubit_op_, shift, ph_shift_

            op_dipole_x, self._x_dipole_shift, self._ph_x_dipole_shift = \
                _dipole_op(qmolecule.x_dipole_integrals, 'x')
            op_dipole_y, self._y_dipole_shift, self._ph_y_dipole_shift = \
                _dipole_op(qmolecule.y_dipole_integrals, 'y')
            op_dipole_z, self._z_dipole_shift, self._ph_z_dipole_shift = \
                _dipole_op(qmolecule.z_dipole_integrals, 'z')

            aux_ops.append(op_dipole_x)
            aux_ops.append(op_dipole_y)
            aux_ops.append(op_dipole_z)

        logger.info('Molecule num electrons: %s, remaining for processing: %s',
                    [num_alpha, num_beta], new_nel)
        nspinorbs = qmolecule.num_orbitals * 2
        new_nspinorbs = nspinorbs - len(freeze_list) - len(remove_list)
        logger.info('Molecule num spin orbitals: %s, remaining for processing: %s',
                    nspinorbs, new_nspinorbs)

        self._add_molecule_info(self.INFO_NUM_PARTICLES, [new_num_alpha, new_num_beta])
        self._add_molecule_info(self.INFO_NUM_ORBITALS, new_nspinorbs)
        self._add_molecule_info(self.INFO_TWO_QUBIT_REDUCTION,
                                self._two_qubit_reduction
                                if self._qubit_mapping == 'parity' else False)

        z2symmetries = Z2Symmetries([], [], [], None)
        if self._z2symmetry_reduction is not None:
            logger.debug('Processing z2 symmetries')
            qubit_op, aux_ops, z2symmetries = self._process_z2symmetry_reduction(qubit_op, aux_ops)
        self._add_molecule_info(self.INFO_Z2SYMMETRIES, z2symmetries)

        logger.debug('Processing complete ready to run algorithm')
        return qubit_op, aux_ops
Exemplo n.º 11
0
    def _build_hopping_operator(index,
                                num_orbitals,
                                num_particles,
                                qubit_mapping,
                                two_qubit_reduction,
                                z2_symmetries,
                                skip_commute_test=False):
        """
        Builds a hopping operator given the list of indices (index) that is a single or a double
        excitation.

        Args:
            index (list): a single or double excitation (e.g. double excitation [0,1,2,3] for a 4
                          spin-orbital system)
            num_orbitals (int): number of spin-orbitals
            num_particles (int): number of electrons
            qubit_mapping (str): qubit mapping type
            two_qubit_reduction (bool): reduce the number of qubits by 2 if
                                        parity qubit mapping is used
            z2_symmetries (Z2Symmetries): class that contains the symmetries
                                          of hamiltonian for tapering
            skip_commute_test (bool): when tapering excitation operators we test and exclude any
                                that do not commute with symmetries. This test can be skipped to
                                include all tapered excitation operators whether they commute
                                or not.
        Returns:
            WeightedPauliOperator: qubit_op
            list: index
        """
        h_1 = np.zeros((num_orbitals, num_orbitals))
        h_2 = np.zeros(
            (num_orbitals, num_orbitals, num_orbitals, num_orbitals))
        if len(index) == 2:
            i, j = index
            h_1[i, j] = 1.0
            h_1[j, i] = -1.0
        elif len(index) == 4:
            i, j, k, m = index
            h_2[i, j, k, m] = 1.0
            h_2[m, k, j, i] = -1.0

        dummpy_fer_op = FermionicOperator(h1=h_1, h2=h_2)
        qubit_op = dummpy_fer_op.mapping(qubit_mapping)
        if two_qubit_reduction:
            qubit_op = Z2Symmetries.two_qubit_reduction(
                qubit_op, num_particles)

        if not z2_symmetries.is_empty():
            symm_commuting = True
            for symmetry in z2_symmetries.symmetries:
                symmetry_op = WeightedPauliOperator(paulis=[[1.0, symmetry]])
                symm_commuting = qubit_op.commute_with(symmetry_op)
                if not symm_commuting:
                    break
            if not skip_commute_test:
                qubit_op = z2_symmetries.taper(
                    qubit_op) if symm_commuting else None
            else:
                qubit_op = z2_symmetries.taper(qubit_op)

        if qubit_op is None:
            logger.debug(
                'Excitation (%s) is skipped since it is not commuted '
                'with symmetries', ','.join([str(x) for x in index]))
        return qubit_op, index
Exemplo n.º 12
0
    def _do_transform(
        self,
        qmolecule: QMolecule,
        aux_operators: Optional[List[FermionicOperator]] = None
    ) -> Tuple[WeightedPauliOperator, List[WeightedPauliOperator]]:
        """
        Args:
            qmolecule: qmolecule
            aux_operators: Additional ``FermionicOperator``s to map to a qubit operator.

        Returns:
            (qubit operator, auxiliary operators)

        """
        logger.debug('Processing started...')
        # Save these values for later combination with the quantum computation result
        self._hf_energy = qmolecule.hf_energy
        self._nuclear_repulsion_energy = qmolecule.nuclear_repulsion_energy
        self._nuclear_dipole_moment = qmolecule.nuclear_dipole_moment
        self._reverse_dipole_sign = qmolecule.reverse_dipole_sign

        core_list = qmolecule.core_orbitals if self._freeze_core else []
        reduce_list = self._orbital_reduction

        if self._freeze_core:
            logger.info(
                "Freeze_core specified. Core orbitals to be frozen: %s",
                core_list)
        if reduce_list:
            logger.info("Configured orbital reduction list: %s", reduce_list)
            reduce_list = [
                x + qmolecule.num_orbitals if x < 0 else x for x in reduce_list
            ]

        freeze_list = []
        remove_list = []

        # Orbitals are specified by their index from 0 to n-1, where n is the number of orbitals the
        # molecule has. The combined list of the core orbitals, when freeze_core is true, with any
        # user supplied orbitals is what will be used. Negative numbers may be used to indicate the
        # upper virtual orbitals, so -1 is the highest, then -2 etc. and these will
        # be converted to the
        # positive 0-based index for computation.
        # In the combined list any orbitals that are occupied are added to a freeze list and an
        # energy is stored from these orbitals to be added later.
        # Unoccupied orbitals are just discarded.
        # Because freeze and eliminate is done in separate steps,
        # with freeze first, we have to re-base
        # the indexes for elimination according to how many orbitals were removed when freezing.
        #
        orb_list = list(set(core_list + reduce_list))
        num_alpha = qmolecule.num_alpha
        num_beta = qmolecule.num_beta
        new_num_alpha = num_alpha
        new_num_beta = num_beta
        if orb_list:
            orbitals_list = np.array(orb_list)
            orbitals_list = orbitals_list[
                (cast(np.ndarray, orbitals_list) >= 0)
                & (orbitals_list < qmolecule.num_orbitals)]

            freeze_list_alpha = [i for i in orbitals_list if i < num_alpha]
            freeze_list_beta = [i for i in orbitals_list if i < num_beta]
            freeze_list = np.append(
                freeze_list_alpha,
                [i + qmolecule.num_orbitals for i in freeze_list_beta])

            remove_list_alpha = [i for i in orbitals_list if i >= num_alpha]
            remove_list_beta = [i for i in orbitals_list if i >= num_beta]
            rla_adjust = -len(freeze_list_alpha)
            rlb_adjust = -len(freeze_list_alpha) - len(
                freeze_list_beta) + qmolecule.num_orbitals
            remove_list = np.append(
                [i + rla_adjust for i in remove_list_alpha],
                [i + rlb_adjust for i in remove_list_beta])

            logger.info("Combined orbital reduction list: %s", orbitals_list)
            logger.info(
                "  converting to spin orbital reduction list: %s",
                np.append(np.array(orbitals_list),
                          np.array(orbitals_list) + qmolecule.num_orbitals))
            logger.info("    => freezing spin orbitals: %s", freeze_list)
            logger.info(
                "    => removing spin orbitals: %s (indexes accounting for freeze %s)",
                np.append(remove_list_alpha,
                          np.array(remove_list_beta) + qmolecule.num_orbitals),
                remove_list)

            new_num_alpha -= len(freeze_list_alpha)
            new_num_beta -= len(freeze_list_beta)

        new_nel = [new_num_alpha, new_num_beta]

        # construct the fermionic operator
        fer_op = FermionicOperator(h1=qmolecule.one_body_integrals,
                                   h2=qmolecule.two_body_integrals)

        # try to reduce it according to the freeze and remove list
        fer_op, self._energy_shift, did_shift = \
            FermionicTransformation._try_reduce_fermionic_operator(fer_op, freeze_list, remove_list)
        # apply same transformation for the aux operators
        if aux_operators is not None:
            aux_operators = [
                FermionicTransformation._try_reduce_fermionic_operator(
                    op, freeze_list, remove_list)[0] for op in aux_operators
            ]

        if did_shift:
            logger.info("Frozen orbital energy shift: %s", self._energy_shift)
        # apply particle hole transformation, if specified
        if self._transformation == FermionicTransformationType.PARTICLE_HOLE.value:
            fer_op, ph_shift = fer_op.particle_hole_transformation(new_nel)
            self._ph_energy_shift = -ph_shift
            logger.info("Particle hole energy shift: %s",
                        self._ph_energy_shift)

            # apply the same transformation for the aux operators
            if aux_operators is not None:
                aux_operators = [
                    op.particle_hole_transformation(new_nel)[0]
                    for op in aux_operators
                ]

        logger.debug('Converting to qubit using %s mapping',
                     self._qubit_mapping)
        qubit_op = FermionicTransformation._map_fermionic_operator_to_qubit(
            fer_op, self._qubit_mapping, new_nel, self._two_qubit_reduction)
        qubit_op.name = 'Fermionic Operator'

        logger.debug('  num paulis: %s, num qubits: %s', len(qubit_op.paulis),
                     qubit_op.num_qubits)

        aux_ops = []  # list of the aux operators

        def _add_aux_op(aux_op: FermionicOperator, name: str) -> None:
            """
            Add auxiliary operators

            Args:
                aux_op: auxiliary operators
                name: name

            """
            aux_qop = FermionicTransformation._map_fermionic_operator_to_qubit(
                aux_op, self._qubit_mapping, new_nel,
                self._two_qubit_reduction)
            aux_qop.name = name

            aux_ops.append(aux_qop)
            logger.debug('  num paulis: %s', aux_qop.paulis)

        # the first three operators are hardcoded to number of particles, angular momentum
        # and magnetization in this order
        logger.debug('Creating aux op for Number of Particles')
        _add_aux_op(fer_op.total_particle_number(), 'Number of Particles')
        logger.debug('Creating aux op for S^2')
        _add_aux_op(fer_op.total_angular_momentum(), 'S^2')
        logger.debug('Creating aux op for Magnetization')
        _add_aux_op(fer_op.total_magnetization(), 'Magnetization')

        # the next three are dipole moments, if supported by the qmolecule
        if qmolecule.has_dipole_integrals():
            self._has_dipole_moments = True

            def _dipole_op(dipole_integrals: np.ndarray, axis: str) \
                    -> Tuple[WeightedPauliOperator, float, float]:
                """
                Dipole operators

                Args:
                    dipole_integrals: dipole integrals
                    axis: axis for dipole moment calculation

                Returns:
                    (qubit_op_, shift, ph_shift_)
                """
                logger.debug('Creating aux op for dipole %s', axis)
                fer_op_ = FermionicOperator(h1=dipole_integrals)
                fer_op_, shift, did_shift_ = self._try_reduce_fermionic_operator(
                    fer_op_, freeze_list, remove_list)
                if did_shift_:
                    logger.info("Frozen orbital %s dipole shift: %s", axis,
                                shift)
                ph_shift_ = 0.0
                if self._transformation == FermionicTransformationType.PARTICLE_HOLE.value:
                    fer_op_, ph_shift_ = fer_op_.particle_hole_transformation(
                        new_nel)
                    ph_shift_ = -ph_shift_
                    logger.info("Particle hole %s dipole shift: %s", axis,
                                ph_shift_)
                qubit_op_ = self._map_fermionic_operator_to_qubit(
                    fer_op_, self._qubit_mapping, new_nel,
                    self._two_qubit_reduction)
                qubit_op_.name = 'Dipole ' + axis
                logger.debug('  num paulis: %s', len(qubit_op_.paulis))
                return qubit_op_, shift, ph_shift_

            op_dipole_x, self._x_dipole_shift, self._ph_x_dipole_shift = \
                _dipole_op(qmolecule.x_dipole_integrals, 'x')
            op_dipole_y, self._y_dipole_shift, self._ph_y_dipole_shift = \
                _dipole_op(qmolecule.y_dipole_integrals, 'y')
            op_dipole_z, self._z_dipole_shift, self._ph_z_dipole_shift = \
                _dipole_op(qmolecule.z_dipole_integrals, 'z')

            aux_ops += [op_dipole_x, op_dipole_y, op_dipole_z]

        # add user specified auxiliary operators
        if aux_operators is not None:
            for aux_op in aux_operators:
                if hasattr(aux_op, 'name'):
                    name = aux_op.name
                else:
                    name = ''
                _add_aux_op(aux_op, name)

        logger.info('Molecule num electrons: %s, remaining for processing: %s',
                    [num_alpha, num_beta], new_nel)
        nspinorbs = qmolecule.num_orbitals * 2
        new_nspinorbs = nspinorbs - len(freeze_list) - len(remove_list)
        logger.info(
            'Molecule num spin orbitals: %s, remaining for processing: %s',
            nspinorbs, new_nspinorbs)

        self._molecule_info['num_particles'] = (new_num_alpha, new_num_beta)
        self._molecule_info['num_orbitals'] = new_nspinorbs
        reduction = self._two_qubit_reduction if self._qubit_mapping == 'parity' else False
        self._molecule_info['two_qubit_reduction'] = reduction
        self._untapered_qubit_op = qubit_op

        z2symmetries = Z2Symmetries([], [], [], None)
        if self._z2symmetry_reduction is not None:
            logger.debug('Processing z2 symmetries')
            qubit_op, aux_ops, z2symmetries = self._process_z2symmetry_reduction(
                qubit_op, aux_ops)
        self._molecule_info['z2_symmetries'] = z2symmetries

        logger.debug('Processing complete ready to run algorithm')
        return qubit_op, aux_ops
Exemplo n.º 13
0
    def run(self, qmolecule):
        logger.debug('Processing started...')
        # Save these values for later combination with the quantum computation result
        self._hf_energy = qmolecule.hf_energy
        self._nuclear_repulsion_energy = qmolecule.nuclear_repulsion_energy
        self._nuclear_dipole_moment = qmolecule.nuclear_dipole_moment
        self._reverse_dipole_sign = qmolecule.reverse_dipole_sign

        core_list = qmolecule.core_orbitals if self._freeze_core else []
        reduce_list = self._orbital_reduction

        if self._freeze_core:
            logger.info("Freeze_core specified. Core orbitals to be frozen: {}".format(core_list))
        if len(reduce_list) > 0:
            logger.info("Configured orbital reduction list: {}".format(reduce_list))
            reduce_list = [x + qmolecule.num_orbitals if x < 0 else x for x in reduce_list]

        freeze_list = []
        remove_list = []

        # Orbitals are specified by their index from 0 to n-1, where n is the number of orbitals the
        # molecule has. The combined list of the core orbitals, when freeze_core is true, with any
        # user supplied orbitals is what will be used. Negative numbers may be used to indicate the
        # upper virtual orbitals, so -1 is the highest, then -2 etc. and these will be converted to the
        # positive 0-based index for computation.
        # In the combined list any orbitals that are occupied are added to a freeze list and an
        # energy is stored from these orbitals to be added later. Unoccupied orbitals are just discarded.
        # Because freeze and eliminate is done in separate steps, with freeze first, we have to re-base
        # the indexes for elimination according to how many orbitals were removed when freezing.
        #
        orbitals_list = list(set(core_list + reduce_list))
        nel = qmolecule.num_alpha + qmolecule.num_beta
        new_nel = nel
        if len(orbitals_list) > 0:
            orbitals_list = np.array(orbitals_list)
            orbitals_list = orbitals_list[(orbitals_list >= 0) & (orbitals_list < qmolecule.num_orbitals)]

            freeze_list = [i for i in orbitals_list if i < int(nel/2)]
            freeze_list = np.append(np.array(freeze_list), np.array(freeze_list) + qmolecule.num_orbitals)

            remove_list = [i for i in orbitals_list if i >= int(nel/2)]
            remove_list_orig_idx = np.append(np.array(remove_list), np.array(remove_list) + qmolecule.num_orbitals)
            remove_list = np.append(np.array(remove_list) - int(len(freeze_list)/2), np.array(remove_list) + qmolecule.num_orbitals - len(freeze_list))
            logger.info("Combined orbital reduction list: {}".format(orbitals_list))
            logger.info("  converting to spin orbital reduction list: {}".format(np.append(np.array(orbitals_list), np.array(orbitals_list) + qmolecule.num_orbitals)))
            logger.info("    => freezing spin orbitals: {}".format(freeze_list))
            logger.info("    => removing spin orbitals: {} (indexes accounting for freeze {})".format(remove_list_orig_idx, remove_list))

            new_nel -= len(freeze_list)

        fer_op = FermionicOperator(h1=qmolecule.one_body_integrals, h2=qmolecule.two_body_integrals)
        fer_op, self._energy_shift, did_shift = Hamiltonian._try_reduce_fermionic_operator(fer_op, freeze_list, remove_list)
        if did_shift:
            logger.info("Frozen orbital energy shift: {}".format(self._energy_shift))
        if self._transformation == TransformationType.PH.value:
            fer_op, ph_shift = fer_op.particle_hole_transformation(new_nel)
            self._ph_energy_shift = -ph_shift
            logger.info("Particle hole energy shift: {}".format(self._ph_energy_shift))
        logger.debug('Converting to qubit using {} mapping'.format(self._qubit_mapping))
        qubit_op = Hamiltonian._map_fermionic_operator_to_qubit(fer_op, self._qubit_mapping, new_nel,
                                                                self._two_qubit_reduction)
        logger.debug('  num paulis: {}, num qubits: {}'.format(len(qubit_op.paulis), qubit_op.num_qubits))
        algo_input = EnergyInput(qubit_op)

        def _add_aux_op(aux_op):
            algo_input.add_aux_op(Hamiltonian._map_fermionic_operator_to_qubit(aux_op, self._qubit_mapping, new_nel,
                                                                               self._two_qubit_reduction))
            logger.debug('  num paulis: {}'.format(len(algo_input.aux_ops[-1].paulis)))

        logger.debug('Creating aux op for Number of Particles')
        _add_aux_op(fer_op.total_particle_number())
        logger.debug('Creating aux op for S^2')
        _add_aux_op(fer_op.total_angular_momentum())
        logger.debug('Creating aux op for Magnetization')
        _add_aux_op(fer_op.total_magnetization())

        if qmolecule.has_dipole_integrals():
            def _dipole_op(dipole_integrals, axis):
                logger.debug('Creating aux op for dipole {}'.format(axis))
                fer_op_ = FermionicOperator(h1=dipole_integrals)
                fer_op_, shift, did_shift_ = self._try_reduce_fermionic_operator(fer_op_, freeze_list, remove_list)
                if did_shift_:
                    logger.info("Frozen orbital {} dipole shift: {}".format(axis, shift))
                ph_shift_ = 0.0
                if self._transformation == TransformationType.PH.value:
                    fer_op_, ph_shift_ = fer_op_.particle_hole_transformation(new_nel)
                    ph_shift_ = -ph_shift_
                    logger.info("Particle hole {} dipole shift: {}".format(axis, ph_shift_))
                qubit_op_ = self._map_fermionic_operator_to_qubit(fer_op_, self._qubit_mapping, new_nel,
                                                                  self._two_qubit_reduction)
                logger.debug('  num paulis: {}'.format(len(qubit_op_.paulis)))
                return qubit_op_, shift, ph_shift_

            op_dipole_x, self._x_dipole_shift, self._ph_x_dipole_shift = _dipole_op(qmolecule.x_dipole_integrals, 'x')
            op_dipole_y, self._y_dipole_shift, self._ph_y_dipole_shift = _dipole_op(qmolecule.y_dipole_integrals, 'y')
            op_dipole_z, self._z_dipole_shift, self._ph_z_dipole_shift = _dipole_op(qmolecule.z_dipole_integrals, 'z')

            algo_input.add_aux_op(op_dipole_x)
            algo_input.add_aux_op(op_dipole_y)
            algo_input.add_aux_op(op_dipole_z)

        logger.info('Molecule num electrons: {}, remaining for processing: {}'.format(nel, new_nel))
        nspinorbs = qmolecule.num_orbitals * 2
        new_nspinorbs = nspinorbs - len(freeze_list) - len(remove_list)
        logger.info('Molecule num spin orbitals: {}, remaining for processing: {}'.format(nspinorbs, new_nspinorbs))

        self._add_molecule_info(self.INFO_NUM_PARTICLES, new_nel)
        self._add_molecule_info(self.INFO_NUM_ORBITALS, new_nspinorbs)
        self._add_molecule_info(self.INFO_TWO_QUBIT_REDUCTION,
                                self._two_qubit_reduction if self._qubit_mapping == 'parity' else False)

        logger.debug('Processing complete ready to run algorithm')
        return algo_input.qubit_op, algo_input.aux_ops