def setUp(self): super().setUp() # np.random.seed(50) self.seed = 50 algorithm_globals.random_seed = self.seed try: self.driver = PySCFDriver(atom='H .0 .0 .0; H .0 .0 0.735', unit=UnitsType.ANGSTROM, basis='sto3g') except QiskitNatureError: self.skipTest('PYSCF driver does not appear to be installed') return molecule = self.driver.run() self.num_particles = molecule.num_alpha + molecule.num_beta self.num_spin_orbitals = molecule.num_orbitals * 2 fer_op = FermionicOperator(h1=molecule.one_body_integrals, h2=molecule.two_body_integrals) map_type = 'PARITY' qubit_op = fer_op.mapping(map_type) self.qubit_op = TwoQubitReduction( num_particles=self.num_particles).convert(qubit_op) self.num_qubits = self.qubit_op.num_qubits self.init_state = HartreeFock(self.num_spin_orbitals, self.num_particles) self.var_form_base = None
def test_with_two_qubit_reduction(self): """Test the VQE using TwoQubitReduction.""" qubit_op = PauliSumOp.from_list([ ("IIII", -0.8105479805373266), ("IIIZ", 0.17218393261915552), ("IIZZ", -0.22575349222402472), ("IZZI", 0.1721839326191556), ("ZZII", -0.22575349222402466), ("IIZI", 0.1209126326177663), ("IZZZ", 0.16892753870087912), ("IXZX", -0.045232799946057854), ("ZXIX", 0.045232799946057854), ("IXIX", 0.045232799946057854), ("ZXZX", -0.045232799946057854), ("ZZIZ", 0.16614543256382414), ("IZIZ", 0.16614543256382414), ("ZZZZ", 0.17464343068300453), ("ZIZI", 0.1209126326177663), ]) tapered_qubit_op = TwoQubitReduction(num_particles=2).convert(qubit_op) for simulator in [self.qasm_simulator, self.statevector_simulator]: with self.subTest(f"Test for {simulator}."): vqe = VQE( self.ry_wavefunction, SPSA(maxiter=300, last_avg=5), quantum_instance=simulator, ) result = vqe.compute_minimum_eigenvalue(tapered_qubit_op) energy = -1.868 if simulator == self.qasm_simulator else self.h2_energy self.assertAlmostEqual(result.eigenvalue.real, energy, places=2)
def _map_fermionic_operator_to_qubit( fer_op: FermionicOperator, qubit_mapping: str, num_particles: List[int], two_qubit_reduction: bool) -> PauliSumOp: """ 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 = TwoQubitReduction( num_particles=num_particles).convert(qubit_op) return qubit_op
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 = TwoQubitReduction( num_particles=num_particles).convert(qubit_op) commutativities = [] if not z2_symmetries.is_empty(): for symmetry in z2_symmetries.symmetries: symmetry_op = PauliSumOp.from_list([(symmetry.to_label(), 1.0) ]) commuting = qubit_op.primitive.table.commutes_with_all( symmetry_op.primitive.table) anticommuting = qubit_op.primtive.table.anticommutes_with_all( symmetry_op.primitive.table) if commuting != anticommuting: # only one of them is True if commuting: commutativities.append(True) elif anticommuting: commutativities.append(False) else: raise QiskitNatureError( "Symmetry {} is nor commute neither anti-commute " "to exciting operator.".format(symmetry.to_label())) return qubit_op, commutativities
def test_convert(self): """ convert test """ qubit_op = PauliSumOp.from_list([ ("IIII", -0.8105479805373266), ("IIIZ", 0.17218393261915552), ("IIZZ", -0.22575349222402472), ("IZZI", 0.1721839326191556), ("ZZII", -0.22575349222402466), ("IIZI", 0.1209126326177663), ("IZZZ", 0.16892753870087912), ("IXZX", -0.045232799946057854), ("ZXIX", 0.045232799946057854), ("IXIX", 0.045232799946057854), ("ZXZX", -0.045232799946057854), ("ZZIZ", 0.16614543256382414), ("IZIZ", 0.16614543256382414), ("ZZZZ", 0.17464343068300453), ("ZIZI", 0.1209126326177663), ]) tapered_qubit_op = TwoQubitReduction(num_particles=2).convert(qubit_op) self.assertIsInstance(tapered_qubit_op, TaperedPauliSumOp) primitive = SparsePauliOp.from_list([ ("II", -1.052373245772859), ("ZI", -0.39793742484318007), ("IZ", 0.39793742484318007), ("ZZ", -0.01128010425623538), ("XX", 0.18093119978423142), ]) symmetries = [Pauli("IIZI"), Pauli("ZIII")] sq_paulis = [Pauli("IIXI"), Pauli("XIII")] sq_list = [1, 3] tapering_values = [-1, 1] z2_symmetries = Z2Symmetries(symmetries, sq_paulis, sq_list, tapering_values) expected_op = TaperedPauliSumOp(primitive, z2_symmetries) self.assertEqual(tapered_qubit_op, expected_op)
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: PauliSumOp: 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 = TwoQubitReduction( num_particles=num_particles).convert(qubit_op) if not z2_symmetries.is_empty(): symm_commuting = True for symmetry in z2_symmetries.symmetries: symmetry_op = PauliSumOp.from_list([(symmetry.to_label(), 1.0) ]) symm_commuting = qubit_op.primitive.table.commutes_with_all( symmetry_op.primitive.table) 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
def test_readme_sample(self): """ readme sample test """ # pylint: disable=import-outside-toplevel,redefined-builtin def print(*args): """ overloads print to log values """ if args: self.log.debug(args[0], *args[1:]) # --- Exact copy of sample code ---------------------------------------- from qiskit_nature import FermionicOperator from qiskit_nature.drivers import PySCFDriver, UnitsType from qiskit.opflow import TwoQubitReduction # 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 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 = TwoQubitReduction( num_particles=num_particles).convert(qubit_op) num_qubits = qubit_op.num_qubits # setup a classical optimizer for VQE from qiskit.algorithms.optimizers import L_BFGS_B optimizer = L_BFGS_B() # setup the initial state for the variational form from qiskit_nature.circuit.library import HartreeFock init_state = HartreeFock(num_spin_orbitals, num_particles) # setup the variational form for VQE from qiskit.circuit.library import TwoLocal var_form = TwoLocal(num_qubits, ['ry', 'rz'], 'cz') # add the initial state var_form.compose(init_state, front=True) # set the backend for the quantum computation from qiskit import Aer backend = Aer.get_backend('statevector_simulator') # setup and run VQE from qiskit.algorithms import VQE algorithm = VQE(var_form, optimizer=optimizer, quantum_instance=backend) result = algorithm.compute_minimum_eigenvalue(qubit_op) print(result.eigenvalue.real) # ---------------------------------------------------------------------- self.assertAlmostEqual(result.eigenvalue.real, -1.8572750301938803, places=6)