def build_hamiltonian_operators(self, qubit_mapping, two_qubit_reduction,
                                    epsilon, num_particles):
        self.M_h_elements = []
        self.Q_h_elements = []
        self.times_MQ_h = []

        for (I, J) in self.elements:
            t0 = time.time()
            EI, EJ = self.E_mu[I], self.E_mu[J]
            MIJ_oper, MIJ_idx = triple_commutator_adj_twobody_nor(
                self.n, EI, EJ, self.h)
            QIJ_oper, QIJ_idx = triple_commutator_adj_twobody_adj(
                self.n, EI, EJ, self.h)
            t1 = time.time()
            self.logfile.write(
                "M,Q elements (H) %d %d --- time for FermionicOperator %f\n" %
                (I, J, t1 - t0))
            MIJ_oper = MIJ_oper.mapping(map_type=qubit_mapping.value,
                                        threshold=epsilon,
                                        idx=MIJ_idx)
            QIJ_oper = QIJ_oper.mapping(map_type=qubit_mapping.value,
                                        threshold=epsilon,
                                        idx=QIJ_idx)
            if qubit_mapping == 'parity' and two_qubit_reduction:
                MIJ_oper = Z2Symmetries.two_qubit_reduction(
                    MIJ_oper, num_particles)
                QIJ_oper = Z2Symmetries.two_qubit_reduction(
                    QIJ_oper, num_particles)
            self.M_h_elements.append(MIJ_oper)
            self.Q_h_elements.append(QIJ_oper)
            t2 = time.time()
            self.times_MQ_h.append((I, J, t1 - t0, t2 - t1))
            self.logfile.write(
                "M,Q elements (H) %d %d --- time for Mapping %f\n" %
                (I, J, t2 - t1))
    def _build_commutator_routine(params: List, operator: WeightedPauliOperator,
                                  z2_symmetries: Z2Symmetries, sign: int
                                  ) -> Tuple[int, int, WeightedPauliOperator, WeightedPauliOperator,
                                             WeightedPauliOperator, WeightedPauliOperator]:
        """Numerically computes the commutator / double commutator between operators.

        Args:
            params: list containing the indices of matrix element and the corresponding
                excitation operators
            operator: the hamiltonian
            z2_symmetries: z2_symmetries in case of tapering
            sign: commute or anticommute

        Returns:
            The indices of the matrix element and the corresponding qubit
            operator for each of the EOM matrices
        """
        m_u, n_u, left_op, right_op_1, right_op_2 = params
        if left_op is None:
            q_mat_op = None
            w_mat_op = None
            m_mat_op = None
            v_mat_op = None
        else:
            if right_op_1 is None and right_op_2 is None:
                q_mat_op = None
                w_mat_op = None
                m_mat_op = None
                v_mat_op = None
            else:
                if right_op_1 is not None:
                    q_mat_op = commutator(left_op, operator, right_op_1, sign=sign)
                    w_mat_op = commutator(left_op, right_op_1, sign=sign)
                    q_mat_op = None if q_mat_op.is_empty() else q_mat_op
                    w_mat_op = None if w_mat_op.is_empty() else w_mat_op
                else:
                    q_mat_op = None
                    w_mat_op = None

                if right_op_2 is not None:
                    m_mat_op = commutator(left_op, operator, right_op_2, sign=sign)
                    v_mat_op = commutator(left_op, right_op_2, sign=sign)
                    m_mat_op = None if m_mat_op.is_empty() else m_mat_op
                    v_mat_op = None if v_mat_op.is_empty() else v_mat_op
                else:
                    m_mat_op = None
                    v_mat_op = None

                if not z2_symmetries.is_empty():
                    if q_mat_op is not None and not q_mat_op.is_empty():
                        q_mat_op = z2_symmetries.taper(q_mat_op)
                    if w_mat_op is not None and not w_mat_op.is_empty():
                        w_mat_op = z2_symmetries.taper(w_mat_op)
                    if m_mat_op is not None and not m_mat_op.is_empty():
                        m_mat_op = z2_symmetries.taper(m_mat_op)
                    if v_mat_op is not None and not v_mat_op.is_empty():
                        v_mat_op = z2_symmetries.taper(v_mat_op)

        return m_u, n_u, q_mat_op, w_mat_op, m_mat_op, v_mat_op
 def build_operators(self, task, qubit_mapping, two_qubit_reduction,
                     num_particles, epsilon):
     self.matrix_elements_adj_nor[task] = []
     self.matrix_elements_adj_adj[task] = []
     self.time_statistics[task] = []
     # -----
     for (I, J) in self.elements:
         # ----- computation
         t0 = time.time()
         EI, EJ = self.E_mu[I], self.E_mu[J]
         if (task == 'overlap'):
             adj_nor_oper, adj_nor_idx = commutator_adj_nor(self.n, EI, EJ)
             adj_adj_oper, adj_adj_idx = commutator_adj_adj(self.n, EI, EJ)
         if (task == 'hamiltonian'):
             adj_nor_oper, adj_nor_idx = triple_commutator_adj_twobody_nor(
                 self.n, EI, EJ, self.h)
             adj_adj_oper, adj_adj_idx = triple_commutator_adj_twobody_adj(
                 self.n, EI, EJ, self.h)
         if (task == 'diagnosis_number'):
             adj_nor_oper, adj_nor_idx = triple_commutator_adj_onebody_nor(
                 self.n, EI, EJ, self.ne)
             adj_adj_oper, adj_adj_idx = triple_commutator_adj_onebody_adj(
                 self.n, EI, EJ, self.ne)
         if (task == 'diagnosis_spin-z'):
             adj_nor_oper, adj_nor_idx = triple_commutator_adj_onebody_nor(
                 self.n, EI, EJ, self.sz)
             adj_adj_oper, adj_adj_idx = triple_commutator_adj_onebody_adj(
                 self.n, EI, EJ, self.sz)
         if (task == 'diagnosis_spin-squared'):
             adj_nor_oper, adj_nor_idx = triple_commutator_adj_twobody_nor(
                 self.n, EI, EJ, self.ss)
             adj_adj_oper, adj_adj_idx = triple_commutator_adj_twobody_adj(
                 self.n, EI, EJ, self.ss)
         t1 = time.time()
         self.logfile.write(
             "task: " + task +
             " elements %d %d --- time for FermionicOperator %f\n" %
             (I, J, t1 - t0))
         # ----- mapping
         adj_nor_oper = adj_nor_oper.mapping(map_type=qubit_mapping.value,
                                             threshold=epsilon,
                                             idx=adj_nor_idx)
         adj_adj_oper = adj_adj_oper.mapping(map_type=qubit_mapping.value,
                                             threshold=epsilon,
                                             idx=adj_adj_idx)
         if qubit_mapping.value == 'parity' and two_qubit_reduction:
             adj_nor_oper = Z2Symmetries.two_qubit_reduction(
                 adj_nor_oper, num_particles)
             adj_adj_oper = Z2Symmetries.two_qubit_reduction(
                 adj_adj_oper, num_particles)
         self.matrix_elements_adj_nor[task].append(adj_nor_oper)
         self.matrix_elements_adj_adj[task].append(adj_adj_oper)
         t2 = time.time()
         # ----- timings
         self.logfile.write("task: " + task +
                            " elements %d %d --- time for Mapping %f\n" %
                            (I, J, t2 - t1))
         self.time_statistics[task].append((I, J, t1 - t0, t2 - t1))
Beispiel #4
0
    def _process_z2symmetry_reduction(self, qubit_op, aux_ops):

        z2_symmetries = Z2Symmetries.find_Z2_symmetries(qubit_op)
        if z2_symmetries.is_empty():
            logger.debug('No Z2 symmetries found')
            z2_qubit_op = qubit_op
            z2_aux_ops = aux_ops
            z2_symmetries = Z2Symmetries([], [], [], None)
        else:
            logger.debug('%s Z2 symmetries found: %s', len(z2_symmetries.symmetries),
                         ','.join([symm.to_label() for symm in z2_symmetries.symmetries]))

            # Check auxiliary operators commute with main operator's symmetry
            logger.debug('Checking operators commute with symmetry:')
            symmetry_ops = []
            for symmetry in z2_symmetries.symmetries:
                symmetry_ops.append(WeightedPauliOperator(paulis=[[1.0, symmetry]]))
            commutes = Hamiltonian._check_commutes(symmetry_ops, qubit_op)
            if not commutes:
                raise QiskitChemistryError('Z2 symmetry failure main operator must commute '
                                           'with symmetries found from it')
            for i, aux_op in enumerate(aux_ops):
                commutes = Hamiltonian._check_commutes(symmetry_ops, aux_op)
                if not commutes:
                    aux_ops[i] = None  # Discard since no meaningful measurement can be done

            if self._z2symmetry_reduction == 'auto':
                hf_state = HartreeFock(num_orbitals=self._molecule_info[self.INFO_NUM_ORBITALS],
                                       qubit_mapping=self._qubit_mapping,
                                       two_qubit_reduction=self._two_qubit_reduction,
                                       num_particles=self._molecule_info[self.INFO_NUM_PARTICLES])
                z2_symmetries = Hamiltonian._pick_sector(z2_symmetries, hf_state.bitstr)
            else:
                if len(self._z2symmetry_reduction) != len(z2_symmetries.symmetries):
                    raise QiskitChemistryError('z2symmetry_reduction tapering values list has '
                                               'invalid length {} should be {}'.
                                               format(len(self._z2symmetry_reduction),
                                                      len(z2_symmetries.symmetries)))
                valid = np.all(np.isin(self._z2symmetry_reduction, [-1, 1]))
                if not valid:
                    raise QiskitChemistryError('z2symmetry_reduction tapering values list must '
                                               'contain -1\'s and/or 1\'s only was {}'.
                                               format(self._z2symmetry_reduction,))
                z2_symmetries.tapering_values = self._z2symmetry_reduction

            logger.debug('Apply symmetry with tapering values %s', z2_symmetries.tapering_values)
            chop_to = 0.00000001  # Use same threshold as qubit mapping to chop tapered operator
            z2_qubit_op = z2_symmetries.taper(qubit_op).chop(chop_to)
            z2_aux_ops = []
            for aux_op in aux_ops:
                z2_aux_ops.append(z2_symmetries.taper(aux_op).chop(chop_to) if aux_op is not None
                                  else None)

        return z2_qubit_op, z2_aux_ops, z2_symmetries
 def build_overlap_operators(self, qubit_mapping, two_qubit_reduction,
                             epsilon, num_particles):
     self.V_elements = []
     self.W_elements = []
     self.times_VW = []
     for (I, J) in self.elements:
         t0 = time.time()
         EI, EJ = self.E_mu[I], self.E_mu[J]
         VIJ_oper, VIJ_idx = commutator_adj_nor(self.n, EI, EJ)
         WIJ_oper, WIJ_idx = [None] * 4, [None] * 4
         t1 = time.time()
         self.logfile.write(
             "V,W elements %d %d --- time for FermionicOperator %f\n" %
             (I, J, t1 - t0))
         VIJ_oper = VIJ_oper.mapping(map_type=qubit_mapping.value,
                                     threshold=epsilon,
                                     idx=VIJ_idx)
         if qubit_mapping.value == 'parity' and two_qubit_reduction:
             VIJ_oper = Z2Symmetries.two_qubit_reduction(
                 VIJ_oper, num_particles)
         self.V_elements.append(VIJ_oper)
         t2 = time.time()
         self.times_VW.append((I, J, t1 - t0, t2 - t1))
         self.logfile.write("V,W elements %d %d --- time for Mapping %f\n" %
                            (I, J, t2 - t1))
def get_qubit_op(target_molecule):
    geometry, multiplicity, charge = generate_molecule_dict()
    driver = PySCFDriver(atom=geometry_convert(target_molecule),
                         unit=UnitsType.ANGSTROM,
                         charge=charge[target_molecule],
                         spin=0,
                         basis='sto3g')
    molecule = driver.run()
    repulsion_energy = molecule.nuclear_repulsion_energy
    num_particles = molecule.num_alpha + molecule.num_beta
    num_spin_orbitals = molecule.num_orbitals * 2
    one_RDM = make_one_rdm(target_molecule)
    w = calculate_noons(one_RDM)
    freeze_list, remove_list = generate_freeze_remove_list(w)
    remove_list = [x % molecule.num_orbitals for x in remove_list]
    freeze_list = [x % molecule.num_orbitals for x in freeze_list]
    remove_list = [x - len(freeze_list) for x in remove_list]
    remove_list += [
        x + molecule.num_orbitals - len(freeze_list) for x in remove_list
    ]
    freeze_list += [x + molecule.num_orbitals for x in freeze_list]
    ferOp = FermionicOperator(h1=molecule.one_body_integrals,
                              h2=molecule.two_body_integrals)
    ferOp, energy_shift = ferOp.fermion_mode_freezing(freeze_list)
    num_spin_orbitals -= len(freeze_list)
    num_particles -= len(freeze_list)
    ferOp = ferOp.fermion_mode_elimination(remove_list)
    num_spin_orbitals -= len(remove_list)
    qubitOp = ferOp.mapping(map_type='bravyi_kitaev', threshold=0.00000001)
    qubitOp = Z2Symmetries.two_qubit_reduction(qubitOp, num_particles)
    shift = energy_shift + repulsion_energy
    return qubitOp, num_particles, num_spin_orbitals, shift
Beispiel #7
0
    def test_h2_one_qubit(self):
        """Test H2 with tapering."""
        two_qubit_reduction = False
        qubit_mapping = 'jordan_wigner'
        core = Hamiltonian(transformation=TransformationType.FULL,
                           qubit_mapping=QubitMappingType.JORDAN_WIGNER,
                           two_qubit_reduction=two_qubit_reduction,
                           freeze_core=False,
                           orbital_reduction=[])
        qubit_op, _ = core.run(self.molecule)

        num_orbitals = core.molecule_info['num_orbitals']
        num_particles = core.molecule_info['num_particles']

        z2_symmetries = Z2Symmetries.find_Z2_symmetries(qubit_op)
        tapered_op = z2_symmetries.taper(qubit_op)[5]
        eom_ee = QEomEE(tapered_op,
                        num_orbitals=num_orbitals,
                        num_particles=num_particles,
                        qubit_mapping=qubit_mapping,
                        two_qubit_reduction=two_qubit_reduction,
                        z2_symmetries=tapered_op.z2_symmetries,
                        untapered_op=qubit_op)
        result = eom_ee.run()
        np.testing.assert_array_almost_equal(self.reference,
                                             result['energies'])
Beispiel #8
0
def lih(dist=1.5):
    mol = PySCFDriver(atom=
                      'H 0.0 0.0 0.0;'\
                      'Li 0.0 0.0 {}'.format(dist), unit=UnitsType.ANGSTROM, charge=0,
                      spin=0, basis='sto-3g')
    mol = mol.run()
    freeze_list = [0]
    remove_list = [-3, -2]
    repulsion_energy = mol.nuclear_repulsion_energy
    num_particles = mol.num_alpha + mol.num_beta
    num_spin_orbitals = mol.num_orbitals * 2
    remove_list = [x % mol.num_orbitals for x in remove_list]
    freeze_list = [x % mol.num_orbitals for x in freeze_list]
    remove_list = [x - len(freeze_list) for x in remove_list]
    remove_list += [
        x + mol.num_orbitals - len(freeze_list) for x in remove_list
    ]
    freeze_list += [x + mol.num_orbitals for x in freeze_list]
    ferOp = FermionicOperator(h1=mol.one_body_integrals,
                              h2=mol.two_body_integrals)
    ferOp, energy_shift = ferOp.fermion_mode_freezing(freeze_list)
    num_spin_orbitals -= len(freeze_list)
    num_particles -= len(freeze_list)
    ferOp = ferOp.fermion_mode_elimination(remove_list)
    num_spin_orbitals -= len(remove_list)

    qubitOp = ferOp.mapping(map_type='parity', threshold=0.00000001)
    qubitOp = Z2Symmetries.two_qubit_reduction(qubitOp, num_particles)

    shift = energy_shift + repulsion_energy
    cHam = op_converter.to_matrix_operator(qubitOp)
    cHam = cHam.dense_matrix + shift * numpy.identity(16)

    return cHam
    def test_h2_one_qubit_qasm(self):
        """Test H2 with tapering and qasm backend"""
        two_qubit_reduction = True
        qubit_mapping = 'parity'
        core = Hamiltonian(transformation=TransformationType.FULL,
                           qubit_mapping=QubitMappingType.PARITY,
                           two_qubit_reduction=two_qubit_reduction,
                           freeze_core=False,
                           orbital_reduction=[])
        qubit_op, _ = core.run(self.molecule)

        num_orbitals = core.molecule_info['num_orbitals']
        num_particles = core.molecule_info['num_particles']

        # tapering
        z2_symmetries = Z2Symmetries.find_Z2_symmetries(qubit_op)
        # know the sector
        tapered_op = z2_symmetries.taper(qubit_op)[1]

        var_form = RY(tapered_op.num_qubits, depth=1)
        optimizer = SPSA(max_trials=50)

        eom_vqe = QEomVQE(tapered_op, var_form, optimizer, num_orbitals=num_orbitals,
                          num_particles=num_particles, qubit_mapping=qubit_mapping,
                          two_qubit_reduction=two_qubit_reduction,
                          z2_symmetries=tapered_op.z2_symmetries, untapered_op=qubit_op)

        backend = BasicAer.get_backend('qasm_simulator')
        quantum_instance = QuantumInstance(backend, shots=65536)
        result = eom_vqe.run(quantum_instance)
        np.testing.assert_array_almost_equal(self.reference, result['energies'], decimal=2)
 def _map_fermionic_operator_to_qubit(fer_op, qubit_mapping, num_particles,
                                      two_qubit_reduction):
     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
Beispiel #11
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
Beispiel #12
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
Beispiel #13
0
def get_H2_data(dist):
    """ 
    Use the qiskit chemistry package to get the qubit Hamiltonian for LiH

    Parameters
    ----------
    dist : float
        The nuclear separations

    Returns
    -------
    qubitOp : qiskit.aqua.operators.WeightedPauliOperator
        Qiskit representation of the qubit Hamiltonian
    shift : float
        The ground state of the qubit Hamiltonian needs to be corrected by this amount of
        energy to give the real physical energy. This includes the replusive energy between
        the nuclei and the energy shift of the frozen orbitals.
    """
    driver = PySCFDriver(atom="H .0 .0 .0; H .0 .0 " + str(dist), 
                         unit=UnitsType.ANGSTROM, 
                         charge=0, 
                         spin=0, 
                         basis='sto3g',
                        )
    molecule = driver.run()
    repulsion_energy = molecule.nuclear_repulsion_energy
    num_particles = molecule.num_alpha + molecule.num_beta
    num_spin_orbitals = molecule.num_orbitals * 2
    ferOp = FermionicOperator(h1=molecule.one_body_integrals, h2=molecule.two_body_integrals)
    qubitOp = ferOp.mapping(map_type='parity', threshold=1E-8)
    qubitOp = Z2Symmetries.two_qubit_reduction(qubitOp,num_particles)
    shift = repulsion_energy

    return qubitOp, shift
Beispiel #14
0
def get_qubit_op(dist):
    #atom="Li .0 .0 .0; H .0 .0 " + str(dist)
    #atom="Be .0 .0 .0; H .0 .0 -" + str(dist) + "; H .0 .0 " + str(dist)
    driver = PySCFDriver("Li .0 .0 .0; H .0 .0 " + str(dist),
                         unit=UnitsType.ANGSTROM,
                         charge=0,
                         spin=0,
                         basis='sto3g')
    molecule = driver.run()
    freeze_list = [0]
    remove_list = [-3, -2]
    repulsion_energy = molecule.nuclear_repulsion_energy
    num_particles = molecule.num_alpha + molecule.num_beta
    num_spin_orbitals = molecule.num_orbitals * 2
    remove_list = [x % molecule.num_orbitals for x in remove_list]
    freeze_list = [x % molecule.num_orbitals for x in freeze_list]
    remove_list = [x - len(freeze_list) for x in remove_list]
    remove_list += [
        x + molecule.num_orbitals - len(freeze_list) for x in remove_list
    ]
    freeze_list += [x + molecule.num_orbitals for x in freeze_list]
    ferOp = FermionicOperator(h1=molecule.one_body_integrals,
                              h2=molecule.two_body_integrals)
    ferOp, energy_shift = ferOp.fermion_mode_freezing(freeze_list)
    num_spin_orbitals -= len(freeze_list)
    num_particles -= len(freeze_list)
    ferOp = ferOp.fermion_mode_elimination(remove_list)
    num_spin_orbitals -= len(remove_list)
    qubitOp = ferOp.mapping(map_type='parity', threshold=0.00000001)
    qubitOp = Z2Symmetries.two_qubit_reduction(qubitOp, num_particles)
    shift = energy_shift + repulsion_energy
    return qubitOp, num_particles, num_spin_orbitals, shift
Beispiel #15
0
    def test_qpe(self, distance):
        """ qpe test """
        self.log.debug('Testing End-to-End with QPE on '
                       'H2 with inter-atomic distance %s.', distance)
        try:
            driver = PySCFDriver(atom='H .0 .0 .0; H .0 .0 {}'.format(distance),
                                 unit=UnitsType.ANGSTROM,
                                 charge=0,
                                 spin=0,
                                 basis='sto3g')
        except QiskitChemistryError:
            self.skipTest('PYSCF driver does not appear to be installed')

        molecule = driver.run()
        qubit_mapping = 'parity'
        fer_op = FermionicOperator(
            h1=molecule.one_body_integrals, h2=molecule.two_body_integrals)
        qubit_op = fer_op.mapping(map_type=qubit_mapping, threshold=1e-10)
        qubit_op = Z2Symmetries.two_qubit_reduction(qubit_op, 2)

        exact_eigensolver = ExactEigensolver(qubit_op, k=1)
        results = exact_eigensolver.run()
        reference_energy = results['energy']
        self.log.debug('The exact ground state energy is: %s', results['energy'])

        num_particles = molecule.num_alpha + molecule.num_beta
        two_qubit_reduction = True
        num_orbitals = qubit_op.num_qubits + \
            (2 if two_qubit_reduction else 0)

        num_time_slices = 1
        n_ancillae = 6

        state_in = HartreeFock(qubit_op.num_qubits, num_orbitals,
                               num_particles, qubit_mapping, two_qubit_reduction)
        iqft = Standard(n_ancillae)

        qpe = QPE(qubit_op, state_in, iqft, num_time_slices, n_ancillae,
                  expansion_mode='suzuki',
                  expansion_order=2, shallow_circuit_concat=True)
        backend = qiskit.BasicAer.get_backend('qasm_simulator')
        quantum_instance = QuantumInstance(backend, shots=100)
        result = qpe.run(quantum_instance)

        self.log.debug('eigvals:                  %s', result['eigvals'])
        self.log.debug('top result str label:     %s', result['top_measurement_label'])
        self.log.debug('top result in decimal:    %s', result['top_measurement_decimal'])
        self.log.debug('stretch:                  %s', result['stretch'])
        self.log.debug('translation:              %s', result['translation'])
        self.log.debug('final energy from QPE:    %s', result['energy'])
        self.log.debug('reference energy:         %s', reference_energy)
        self.log.debug('ref energy (transformed): %s',
                       (reference_energy + result['translation']) * result['stretch'])
        self.log.debug('ref binary str label:     %s',
                       decimal_to_binary(
                           (reference_energy + result['translation']) * result['stretch'],
                           max_num_digits=n_ancillae + 3, fractional_part_only=True))

        np.testing.assert_approx_equal(result['energy'], reference_energy, significant=2)
Beispiel #16
0
    def __init__(self, operator, num_orbitals, num_particles,
                 qubit_mapping=None, two_qubit_reduction=False,
                 active_occupied=None, active_unoccupied=None,
                 is_eom_matrix_symmetric=True, se_list=None, de_list=None,
                 z2_symmetries=None, untapered_op=None):
        """Constructor.

        Args:
            operator (WeightedPauliOperator): qubit operator
            num_orbitals (int):  total number of spin orbitals
            num_particles (Union(list, int)): number of particles, if it is a list,
                                        the first number
                                        is alpha and the second number if beta.
            qubit_mapping (str): qubit mapping type
            two_qubit_reduction (bool): two qubit reduction is applied or not
            active_occupied (list): list of occupied orbitals to include, indices are
                                    0 to n where n is num particles // 2
            active_unoccupied (list): list of unoccupied orbitals to include, indices are
                                    0 to m where m is (num_orbitals - num particles) // 2
            is_eom_matrix_symmetric (bool): is EoM matrix symmetric
            se_list (list[list]): single excitation list, overwrite the setting in active space
            de_list (list[list]): double excitation list, overwrite the setting in active space
            z2_symmetries (Z2Symmetries): represent the Z2 symmetries
            untapered_op (WeightedPauliOperator): if the operator is tapered, we need
                                                    untapered operator
                                                    to build element of EoM matrix
        """
        self._operator = operator
        self._num_orbitals = num_orbitals
        self._num_particles = num_particles
        self._qubit_mapping = qubit_mapping
        self._two_qubit_reduction = two_qubit_reduction
        self._active_occupied = active_occupied
        self._active_unoccupied = active_unoccupied

        se_list_default, de_list_default = UCCSD.compute_excitation_lists(
            self._num_particles, self._num_orbitals, self._active_occupied, self._active_unoccupied)

        if se_list is None:
            self._se_list = se_list_default
        else:
            self._se_list = se_list
            logger.info("Use user-specified single excitation list: %s", self._se_list)

        if de_list is None:
            self._de_list = de_list_default
        else:
            self._de_list = de_list
            logger.info("Use user-specified double excitation list: %s", self._de_list)

        self._z2_symmetries = z2_symmetries if z2_symmetries is not None \
            else Z2Symmetries([], [], [])
        self._untapered_op = untapered_op if untapered_op is not None else operator

        self._is_eom_matrix_symmetric = is_eom_matrix_symmetric
    def test_readme_sample(self):
        """ readme sample test """
        # pylint: disable=import-outside-toplevel

        # --- Exact copy of sample code ----------------------------------------

        from qiskit.chemistry import FermionicOperator
        from qiskit.chemistry.drivers import PySCFDriver, UnitsType
        from qiskit.aqua.operators import Z2Symmetries

        # Use PySCF, a classical computational chemistry software
        # package, to compute the one-body and two-body integrals in
        # molecular-orbital basis, necessary to form the Fermionic operator
        driver = PySCFDriver(atom='H .0 .0 .0; H .0 .0 0.735',
                             unit=UnitsType.ANGSTROM,
                             basis='sto3g')
        molecule = driver.run()
        num_particles = molecule.num_alpha + molecule.num_beta
        num_spin_orbitals = molecule.num_orbitals * 2

        # Build the qubit operator, which is the input to the VQE algorithm in Aqua
        ferm_op = FermionicOperator(h1=molecule.one_body_integrals,
                                    h2=molecule.two_body_integrals)
        map_type = 'PARITY'
        qubit_op = ferm_op.mapping(map_type)
        qubit_op = Z2Symmetries.two_qubit_reduction(qubit_op, num_particles)
        num_qubits = qubit_op.num_qubits

        # setup a classical optimizer for VQE
        from qiskit.aqua.components.optimizers import L_BFGS_B
        optimizer = L_BFGS_B()

        # setup the initial state for the variational form
        from qiskit.chemistry.components.initial_states import HartreeFock
        init_state = HartreeFock(num_qubits, num_spin_orbitals, num_particles)

        # setup the variational form for VQE
        from qiskit.aqua.components.variational_forms import RYRZ
        var_form = RYRZ(num_qubits, initial_state=init_state)

        # setup and run VQE
        from qiskit.aqua.algorithms import VQE
        algorithm = VQE(qubit_op, var_form, optimizer)

        # set the backend for the quantum computation
        from qiskit import Aer
        backend = Aer.get_backend('statevector_simulator')

        result = algorithm.run(backend)
        print(result['energy'])

        # ----------------------------------------------------------------------

        self.assertAlmostEqual(result['energy'], -1.8572750301938803, places=6)
    def setUp(self):
        super().setUp()
        try:
            self.molecule = "H 0.000000 0.000000 0.735000;H 0.000000 0.000000 0.000000"
            self.driver = PySCFDriver(atom=self.molecule,
                                      unit=UnitsType.ANGSTROM,
                                      charge=0,
                                      spin=0,
                                      basis='631g')
            self.qmolecule = self.driver.run()
            self.core = Hamiltonian(transformation=TransformationType.FULL,
                                    qubit_mapping=QubitMappingType.PARITY,
                                    two_qubit_reduction=True,
                                    freeze_core=True,
                                    orbital_reduction=[])
            self.qubit_op, _ = self.core.run(self.qmolecule)

            z2_symmetries = Z2Symmetries.find_Z2_symmetries(self.qubit_op)
            tapered_ops = z2_symmetries.taper(self.qubit_op)
            smallest_eig_value = 99999999999999
            smallest_idx = -1
            for idx, _ in enumerate(tapered_ops):
                ee = ExactEigensolver(tapered_ops[idx], k=1)
                curr_value = ee.run()['energy']
                if curr_value < smallest_eig_value:
                    smallest_eig_value = curr_value
                    smallest_idx = idx
            self.the_tapered_op = tapered_ops[smallest_idx]

            self.reference_energy_pUCCD = -1.1434447924298028
            self.reference_energy_UCCD0 = -1.1476045878481704
            self.reference_energy_UCCD0full = -1.1515491334334347
            # reference energy of UCCSD/VQE with tapering everywhere
            self.reference_energy_UCCSD = -1.1516142309717594
            # reference energy of UCCSD/VQE when no tapering on excitations is used
            self.reference_energy_UCCSD_no_tap_exc = -1.1516142309717594
            # excitations for succ
            self.reference_singlet_double_excitations = [[0, 1, 4, 5],
                                                         [0, 1, 4, 6],
                                                         [0, 1, 4, 7],
                                                         [0, 2, 4, 6],
                                                         [0, 2, 4, 7],
                                                         [0, 3, 4, 7]]
            # groups for succ_full
            self.reference_singlet_groups = [[[0, 1, 4, 5]],
                                             [[0, 1, 4, 6], [0, 2, 4, 5]],
                                             [[0, 1, 4, 7], [0, 3, 4, 5]],
                                             [[0, 2, 4, 6]],
                                             [[0, 2, 4, 7], [0, 3, 4, 6]],
                                             [[0, 3, 4, 7]]]
        except QiskitChemistryError:
            self.skipTest('PYSCF driver does not appear to be installed')
Beispiel #19
0
def get_LiH_qubit_op(dist):
    """ 
    Use the qiskit chemistry package to get the qubit Hamiltonian for LiH

    Parameters
    ----------
    dist : float
        The nuclear separations

    Returns
    -------
    qubitOp : qiskit.aqua.operators.WeightedPauliOperator
        Qiskit representation of the qubit Hamiltonian
    shift : float
        The ground state of the qubit Hamiltonian needs to be corrected by this amount of
        energy to give the real physical energy. This includes the replusive energy between
        the nuclei and the energy shift of the frozen orbitals.
    """
    driver = PySCFDriver(
        atom="Li .0 .0 .0; H .0 .0 " + str(dist),
        unit=UnitsType.ANGSTROM,
        charge=0,
        spin=0,
        basis='sto3g',
    )
    molecule = driver.run()
    freeze_list = [0]
    remove_list = [-3, -2]
    repulsion_energy = molecule.nuclear_repulsion_energy
    num_particles = molecule.num_alpha + molecule.num_beta
    num_spin_orbitals = molecule.num_orbitals * 2
    remove_list = [x % molecule.num_orbitals for x in remove_list]
    freeze_list = [x % molecule.num_orbitals for x in freeze_list]
    remove_list = [x - len(freeze_list) for x in remove_list]
    remove_list += [
        x + molecule.num_orbitals - len(freeze_list) for x in remove_list
    ]
    freeze_list += [x + molecule.num_orbitals for x in freeze_list]
    ferOp = FermionicOperator(h1=molecule.one_body_integrals,
                              h2=molecule.two_body_integrals)
    ferOp, energy_shift = ferOp.fermion_mode_freezing(freeze_list)
    num_spin_orbitals -= len(freeze_list)
    num_particles -= len(freeze_list)
    ferOp = ferOp.fermion_mode_elimination(remove_list)
    num_spin_orbitals -= len(remove_list)
    qubitOp = ferOp.mapping(map_type='parity', threshold=1E-8)
    #qubitOp = qubitOp.two_qubit_reduced_operator(num_particles)
    qubitOp = Z2Symmetries.two_qubit_reduction(qubitOp, num_particles)
    shift = repulsion_energy + energy_shift

    return qubitOp, shift
    def test_h2_one_qubit_statevector(self):
        """Test H2 with tapering and statevector backend."""
        two_qubit_reduction = True
        qubit_mapping = 'parity'
        warnings.filterwarnings('ignore', category=DeprecationWarning)
        core = Hamiltonian(transformation=TransformationType.FULL,
                           qubit_mapping=QubitMappingType.PARITY,
                           two_qubit_reduction=two_qubit_reduction,
                           freeze_core=False,
                           orbital_reduction=[])
        warnings.filterwarnings('always', category=DeprecationWarning)
        qubit_op, _ = core.run(self.molecule)

        num_orbitals = core.molecule_info['num_orbitals']
        num_particles = core.molecule_info['num_particles']

        # tapering
        z2_symmetries = Z2Symmetries.find_Z2_symmetries(qubit_op)
        # know the sector
        tapered_op = z2_symmetries.taper(qubit_op)[1]

        initial_state = HartreeFock(num_orbitals=num_orbitals,
                                    num_particles=num_particles,
                                    qubit_mapping=qubit_mapping,
                                    two_qubit_reduction=two_qubit_reduction,
                                    sq_list=tapered_op.z2_symmetries.sq_list)
        var_form = UCCSD(num_orbitals=num_orbitals,
                         num_particles=num_particles,
                         initial_state=initial_state,
                         qubit_mapping=qubit_mapping,
                         two_qubit_reduction=two_qubit_reduction,
                         z2_symmetries=tapered_op.z2_symmetries)
        optimizer = SPSA(maxiter=50)

        eom_vqe = QEomVQE(tapered_op,
                          var_form,
                          optimizer,
                          num_orbitals=num_orbitals,
                          num_particles=num_particles,
                          qubit_mapping=qubit_mapping,
                          two_qubit_reduction=two_qubit_reduction,
                          z2_symmetries=tapered_op.z2_symmetries,
                          untapered_op=qubit_op)

        backend = BasicAer.get_backend('statevector_simulator')
        quantum_instance = QuantumInstance(backend)
        result = eom_vqe.run(quantum_instance)
        np.testing.assert_array_almost_equal(self.reference,
                                             result['energies'],
                                             decimal=5)
Beispiel #21
0
def get_qubit_op(dist):
    driver = PySCFDriver(atom="H .0 .0 .0; H .0 .0 " + str(dist),
                         unit=UnitsType.ANGSTROM,
                         charge=0,
                         spin=0,
                         basis='sto3g')
    molecule = driver.run()
    nuc_energy = molecule.nuclear_repulsion_energy
    num_particles = molecule.num_alpha + molecule.num_beta
    num_spin_orbitals = molecule.num_orbitals * 2
    ferOp = FermionicOperator(h1=molecule.one_body_integrals,
                              h2=molecule.two_body_integrals)
    qubitOp = ferOp.mapping(map_type='parity', threshold=0.00000001)
    qubitOp = Z2Symmetries.two_qubit_reduction(qubitOp, num_particles)
    return qubitOp, num_particles, num_spin_orbitals, nuc_energy
def load_qubitop_for_molecule(molecule_data):
    atom_list = [a[0] + ' ' + " ".join([str(elem) for elem in a[1]]) for a in molecule_data['geometry']]
    atom = "; ".join(atom_list) 
    #atom = 'Li .0 .0 .0; H .0 .0 3.9'
    basis = molecule_data['basis']
    transform = molecule_data['transform']
    electrons = molecule_data['electrons']
    active = molecule_data['active_orbitals']
    driver = PySCFDriver(atom=atom, unit=UnitsType.ANGSTROM, basis=basis, charge=0, spin=0)
    molecule = driver.run()
    num_particles = molecule.num_alpha + molecule.num_beta
    num_spin_orbitals = molecule.num_orbitals * 2
    #print("# of electrons: {}".format(num_particles))
    #print("# of spin orbitals: {}".format(num_spin_orbitals))
    freeze_list = [x for x in range(int(active/2), int(num_particles/2))]
    remove_list = [-x for x in range(active,molecule.num_orbitals-int(num_particles/2)+int(active/2))]
    #print(freeze_list)
    #print(remove_list)

    if transform == 'BK':
        map_type = 'bravyi_kitaev'
    elif transform == 'JW':
        map_type = 'jordan_wigner'
    else:
        map_type = 'parity'
    remove_list = [x % molecule.num_orbitals for x in remove_list]
    freeze_list = [x % molecule.num_orbitals for x in freeze_list]
    remove_list = [x - len(freeze_list) for x in remove_list]
    remove_list += [x + molecule.num_orbitals - len(freeze_list)  for x in remove_list]
    freeze_list += [x + molecule.num_orbitals for x in freeze_list]
    fermiOp = FermionicOperator(h1=molecule.one_body_integrals, h2=molecule.two_body_integrals)
    energy_shift = 0
    if len(freeze_list) > 0:
        fermiOp, energy_shift = fermiOp.fermion_mode_freezing(freeze_list)
    num_spin_orbitals -= len(freeze_list)
    num_particles -= len(freeze_list)
    if len(remove_list) > 0:
        fermiOp = fermiOp.fermion_mode_elimination(remove_list)
    num_spin_orbitals -= len(remove_list)
    qubitOp = fermiOp.mapping(map_type=map_type, threshold=0.00000001)
    if len(freeze_list) > 0 or len(remove_list) >0:
        qubitOp = Z2Symmetries.two_qubit_reduction(qubitOp, num_particles)

    #print(qubitOp.print_operators())
    num_spin_orbitals= qubitOp.num_qubits
    return molecule, qubitOp, map_type, num_particles, num_spin_orbitals
Beispiel #23
0
def h2(dist=0.75):
    mol = PySCFDriver(atom=
                      'H 0.0 0.0 0.0;'\
                      'H 0.0 0.0 {}'.format(dist), unit=UnitsType.ANGSTROM, charge=0,
                      spin=0, basis='sto-3g')
    mol = mol.run()
    h1 = mol.one_body_integrals
    h2 = mol.two_body_integrals

    nuclear_repulsion_energy = mol.nuclear_repulsion_energy
    num_particles = mol.num_alpha + mol.num_beta + 0
    ferOp = FermionicOperator(h1=h1, h2=h2)
    qubitOp = ferOp.mapping(map_type='parity', threshold=0.00000001)
    qubitOp = Z2Symmetries.two_qubit_reduction(qubitOp, num_particles)

    cHam = op_converter.to_matrix_operator(qubitOp)
    cHam = cHam.dense_matrix + nuclear_repulsion_energy * numpy.identity(4)

    return cHam
Beispiel #24
0
    def _pick_sector(z2_symmetries: Z2Symmetries, hf_str: np.ndarray) -> Z2Symmetries:
        """
        Based on Hartree-Fock bit string and found symmetries to determine the sector.
        The input z2 symmetries will be mutated with the determined tapering values.

        Args:
            z2_symmetries: the z2 symmetries object.
            hf_str: Hartree-Fock bit string (the last index is for qubit 0).

        Returns:
            the original z2 symmetries filled with the correct tapering values.
        """
        # Finding all the symmetries using the find_Z2_symmetries:
        taper_coef = []
        for sym in z2_symmetries.symmetries:
            # pylint: disable=no-member
            coef = -1 if np.logical_xor.reduce(np.logical_and(sym.z[::-1], hf_str)) else 1
            taper_coef.append(coef)
        z2_symmetries.tapering_values = taper_coef
        return z2_symmetries
Beispiel #25
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
Beispiel #26
0
    def setUp(self):
        super().setUp()
        try:
            driver = PySCFDriver(atom='Li .0 .0 .0; H .0 .0 1.6',
                                 unit=UnitsType.ANGSTROM,
                                 charge=0,
                                 spin=0,
                                 basis='sto3g')
        except QiskitChemistryError:
            self.skipTest('PYSCF driver does not appear to be installed')
        self.qmolecule = driver.run()
        self.core = Hamiltonian(transformation=TransformationType.FULL,
                                qubit_mapping=QubitMappingType.PARITY,
                                two_qubit_reduction=True,
                                freeze_core=True,
                                orbital_reduction=[])
        self.qubit_op, _ = self.core.run(self.qmolecule)
        self.z2_symmetries = Z2Symmetries.find_Z2_symmetries(self.qubit_op)

        self.reference_energy = -7.882096489442
Beispiel #27
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
Beispiel #28
0
    def __init__(self,
                 num_qubits: int,
                 depth: int,
                 num_orbitals: int,
                 num_particles: Union[List[int], int],
                 active_occupied: Optional[List[int]] = None,
                 active_unoccupied: Optional[List[int]] = None,
                 initial_state: Optional[InitialState] = None,
                 qubit_mapping: str = 'parity',
                 two_qubit_reduction: bool = True,
                 num_time_slices: int = 1,
                 shallow_circuit_concat: bool = True,
                 z2_symmetries: Optional[Z2Symmetries] = None,
                 method_singles: str = 'both',
                 method_doubles: str = 'ucc',
                 excitation_type: str = 'sd',
                 same_spin_doubles: bool = True,
                 skip_commute_test: bool = False) -> None:
        """Constructor.

        Args:
            num_qubits: number of qubits, has a min. value of 1.
            depth: number of replica of basic module, has a min. value of 1.
            num_orbitals: number of spin orbitals, has a min. value of 1.
            num_particles: number of particles, if it is a list,
                            the first number is alpha and the second number if beta.
            active_occupied: list of occupied orbitals to consider as active space.
            active_unoccupied: list of unoccupied orbitals to consider as active space.
            initial_state: An initial state object.
            qubit_mapping: qubit mapping type.
            two_qubit_reduction: two qubit reduction is applied or not.
            num_time_slices: parameters for dynamics, has a min. value of 1.
            shallow_circuit_concat: indicate whether to use shallow (cheap) mode for
                                           circuit concatenation.
            z2_symmetries: represent the Z2 symmetries, including symmetries,
                            sq_paulis, sq_list, tapering_values, and cliffords.
            method_singles: specify the single excitation considered. 'alpha', 'beta',
                                'both' only alpha or beta spin-orbital single excitations or
                                both (all of them).
            method_doubles: specify the single excitation considered. 'ucc' (conventional
                                ucc), succ (singlet ucc), succ_full (singlet ucc full),
                                pucc (pair ucc).
            excitation_type: specify the excitation type 'sd', 's', 'd' respectively
                                for single and double, only single, only double excitations.
            same_spin_doubles: enable double excitations of the same spin.
            skip_commute_test: 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.


         Raises:
             ValueError: Computed qubits do not match actual value
        """
        validate_min('num_qubits', num_qubits, 1)
        validate_min('depth', depth, 1)
        validate_min('num_orbitals', num_orbitals, 1)
        if isinstance(num_particles, list) and len(num_particles) != 2:
            raise ValueError(
                'Num particles value {}. Number of values allowed is 2'.format(
                    num_particles))
        validate_in_set('qubit_mapping', qubit_mapping,
                        {'jordan_wigner', 'parity', 'bravyi_kitaev'})
        validate_min('num_time_slices', num_time_slices, 1)
        validate_in_set('method_singles', method_singles,
                        {'both', 'alpha', 'beta'})
        validate_in_set('method_doubles', method_doubles,
                        {'ucc', 'pucc', 'succ', 'succ_full'})
        validate_in_set('excitation_type', excitation_type, {'sd', 's', 'd'})
        super().__init__()

        self._z2_symmetries = Z2Symmetries([], [], [], []) \
            if z2_symmetries is None else z2_symmetries

        self._num_qubits = num_orbitals if not two_qubit_reduction else num_orbitals - 2
        self._num_qubits = self._num_qubits if self._z2_symmetries.is_empty() \
            else self._num_qubits - len(self._z2_symmetries.sq_list)
        if self._num_qubits != num_qubits:
            raise ValueError(
                'Computed num qubits {} does not match actual {}'.format(
                    self._num_qubits, num_qubits))
        self._depth = depth
        self._num_orbitals = num_orbitals
        if isinstance(num_particles, list):
            self._num_alpha = num_particles[0]
            self._num_beta = num_particles[1]
        else:
            logger.info(
                "We assume that the number of alphas and betas are the same.")
            self._num_alpha = num_particles // 2
            self._num_beta = num_particles // 2

        self._num_particles = [self._num_alpha, self._num_beta]

        if sum(self._num_particles) > self._num_orbitals:
            raise ValueError(
                '# of particles must be less than or equal to # of orbitals.')

        self._initial_state = initial_state
        self._qubit_mapping = qubit_mapping
        self._two_qubit_reduction = two_qubit_reduction
        self._num_time_slices = num_time_slices
        self._shallow_circuit_concat = shallow_circuit_concat

        # advanced parameters
        self._method_singles = method_singles
        self._method_doubles = method_doubles
        self._excitation_type = excitation_type
        self.same_spin_doubles = same_spin_doubles
        self._skip_commute_test = skip_commute_test

        self._single_excitations, self._double_excitations = \
            UCCSD.compute_excitation_lists([self._num_alpha, self._num_beta], self._num_orbitals,
                                           active_occupied, active_unoccupied,
                                           same_spin_doubles=self.same_spin_doubles,
                                           method_singles=self._method_singles,
                                           method_doubles=self._method_doubles,
                                           excitation_type=self._excitation_type,)

        self._hopping_ops, self._num_parameters = self._build_hopping_operators(
        )
        self._excitation_pool = None
        self._bounds = [(-np.pi, np.pi) for _ in range(self._num_parameters)]

        self._logging_construct_circuit = True
        self._support_parameterized_circuit = True

        self.uccd_singlet = False
        if self._method_doubles == 'succ_full':
            self.uccd_singlet = True
            self._single_excitations, self._double_excitations = \
                UCCSD.compute_excitation_lists([self._num_alpha, self._num_beta],
                                               self._num_orbitals,
                                               active_occupied, active_unoccupied,
                                               same_spin_doubles=self.same_spin_doubles,
                                               method_singles=self._method_singles,
                                               method_doubles=self._method_doubles,
                                               excitation_type=self._excitation_type,
                                               )
        if self.uccd_singlet:
            self._hopping_ops, _ = self._build_hopping_operators()
        else:
            self._hopping_ops, self._num_parameters = self._build_hopping_operators(
            )
            self._bounds = [(-np.pi, np.pi)
                            for _ in range(self._num_parameters)]

        if self.uccd_singlet:
            self._double_excitations_grouped = \
                UCCSD.compute_excitation_lists_singlet(self._double_excitations, num_orbitals)
            self.num_groups = len(self._double_excitations_grouped)

            logging.debug('Grouped double excitations for singlet ucc')
            logging.debug(self._double_excitations_grouped)

            self._num_parameters = self.num_groups
            self._bounds = [(-np.pi, np.pi) for _ in range(self.num_groups)]

            # this will order the hopping operators
            self.labeled_double_excitations = []
            for i in range(len(self._double_excitations)):
                self.labeled_double_excitations.append(
                    (self._double_excitations[i], i))

            order_hopping_op = UCCSD.order_labels_for_hopping_ops(
                self._double_excitations, self._double_excitations_grouped)
            logging.debug('New order for hopping ops')
            logging.debug(order_hopping_op)

            self._hopping_ops_doubles_temp = []
            self._hopping_ops_doubles = self._hopping_ops[
                len(self._single_excitations):]
            for i in order_hopping_op:
                self._hopping_ops_doubles_temp.append(
                    self._hopping_ops_doubles[i])

            self._hopping_ops[len(self._single_excitations
                                  ):] = self._hopping_ops_doubles_temp

        self._logging_construct_circuit = True
Beispiel #29
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
Beispiel #30
0
    def _process_z2symmetry_reduction(
            self, qubit_op: WeightedPauliOperator,
            aux_ops: List[WeightedPauliOperator]) -> Tuple:
        """
        Implement z2 symmetries in the qubit operator

        Args:
            qubit_op : qubit operator
            aux_ops: auxiliary operators

        Returns:
            (z2_qubit_op, z2_aux_ops, z2_symmetries)

        Raises:
            QiskitChemistryError: Invalid input
        """
        z2_symmetries = Z2Symmetries.find_Z2_symmetries(qubit_op)
        if z2_symmetries.is_empty():
            logger.debug('No Z2 symmetries found')
            z2_qubit_op = qubit_op
            z2_aux_ops = aux_ops
            z2_symmetries = Z2Symmetries([], [], [], None)
        else:
            logger.debug(
                '%s Z2 symmetries found: %s', len(z2_symmetries.symmetries),
                ','.join(
                    [symm.to_label() for symm in z2_symmetries.symmetries]))

            # Check auxiliary operators commute with main operator's symmetry
            logger.debug('Checking operators commute with symmetry:')
            symmetry_ops = []
            for symmetry in z2_symmetries.symmetries:
                symmetry_ops.append(
                    WeightedPauliOperator(paulis=[[1.0, symmetry]]))
            commutes = FermionicTransformation._check_commutes(
                symmetry_ops, qubit_op)
            if not commutes:
                raise QiskitChemistryError(
                    'Z2 symmetry failure main operator must commute '
                    'with symmetries found from it')
            for i, aux_op in enumerate(aux_ops):
                commutes = FermionicTransformation._check_commutes(
                    symmetry_ops, aux_op)
                if not commutes:
                    aux_ops[
                        i] = None  # Discard since no meaningful measurement can be done

            if self._z2symmetry_reduction == 'auto':
                from ..circuit.library.initial_states.hartree_fock import hartree_fock_bitstring
                hf_bitstr = hartree_fock_bitstring(
                    num_orbitals=self._molecule_info['num_orbitals'],
                    qubit_mapping=self._qubit_mapping,
                    two_qubit_reduction=self._two_qubit_reduction,
                    num_particles=self._molecule_info['num_particles'])
                z2_symmetries = FermionicTransformation._pick_sector(
                    z2_symmetries, hf_bitstr)
            else:
                if len(self._z2symmetry_reduction) != len(
                        z2_symmetries.symmetries):
                    raise QiskitChemistryError(
                        'z2symmetry_reduction tapering values list has '
                        'invalid length {} should be {}'.format(
                            len(self._z2symmetry_reduction),
                            len(z2_symmetries.symmetries)))
                valid = np.all(np.isin(self._z2symmetry_reduction, [-1, 1]))
                if not valid:
                    raise QiskitChemistryError(
                        'z2symmetry_reduction tapering values list must '
                        'contain -1\'s and/or 1\'s only was {}'.format(
                            self._z2symmetry_reduction, ))
                z2_symmetries.tapering_values = self._z2symmetry_reduction

            logger.debug('Apply symmetry with tapering values %s',
                         z2_symmetries.tapering_values)
            chop_to = 0.00000001  # Use same threshold as qubit mapping to chop tapered operator
            z2_qubit_op = z2_symmetries.taper(qubit_op).chop(chop_to)
            z2_aux_ops = []
            for aux_op in aux_ops:
                if aux_op is None:
                    z2_aux_ops += [None]
                else:
                    z2_aux_ops += [z2_symmetries.taper(aux_op).chop(chop_to)]

        return z2_qubit_op, z2_aux_ops, z2_symmetries