def get_interaction_rdm(qubit_operator, n_qubits=None): """Build an InteractionRDM from measured qubit operators. Returns: An InteractionRDM object. """ # Avoid circular import. from openfermion.transforms import jordan_wigner if n_qubits is None: n_qubits = count_qubits(qubit_operator) one_rdm = numpy.zeros((n_qubits, ) * 2, dtype=complex) two_rdm = numpy.zeros((n_qubits, ) * 4, dtype=complex) # One-RDM. for i, j in itertools.product(range(n_qubits), repeat=2): transformed_operator = jordan_wigner(FermionOperator(((i, 1), (j, 0)))) for term, coefficient in iteritems(transformed_operator.terms): if term in qubit_operator.terms: one_rdm[i, j] += coefficient * qubit_operator.terms[term] # Two-RDM. for i, j, k, l in itertools.product(range(n_qubits), repeat=4): transformed_operator = jordan_wigner( FermionOperator(((i, 1), (j, 1), (k, 0), (l, 0)))) for term, coefficient in iteritems(transformed_operator.terms): if term in qubit_operator.terms: two_rdm[i, j, k, l] += coefficient * qubit_operator.terms[term] return InteractionRDM(one_rdm, two_rdm)
def energy_from_opdm(opdm, constant, one_body_tensor, two_body_tensor): """ Evaluate the energy of an opdm assuming the 2-RDM is opdm ^ opdm :param opdm: single spin-component of the full spin-orbital opdm. :param constant: constant shift to the Hamiltonian. Commonly this is the nuclear repulsion energy. :param one_body_tensor: spatial one-body integrals :param two_body_tensor: spatial two-body integrals :return: """ spin_opdm = np.kron(opdm, np.eye(2)) spin_tpdm = 2 * wedge(spin_opdm, spin_opdm, (1, 1), (1, 1)) molecular_hamiltonian = generate_hamiltonian(constant=constant, one_body_integrals=one_body_tensor, two_body_integrals=two_body_tensor) rdms = InteractionRDM(spin_opdm, spin_tpdm) return rdms.expectation(molecular_hamiltonian).real
def get_molecular_rdm_spin(self, use_fci=False): """Method to return 1-RDM and 2-RDMs from CISD or FCI, adapted for spin-orbitals. Args: use_fci: Boolean indicating whether to use RDM from FCI calculation. Returns: rdm: An instance of the MolecularRDM class. Raises: MisissingCalculationError: If the CI calculation has not been performed. """ # Make sure requested RDM has been computed and load. if use_fci: if self.fci_energy is None: raise MissingCalculationError( 'Missing FCI RDM in {}'.format(self.filename) + 'Run FCI calculation before loading FCI RDMs.') else: one_rdm = self.fci_one_rdm two_rdm = self.fci_two_rdm else: if self.cisd_energy is None: raise MissingCalculationError( 'Missing CISD RDM in {}'.format(self.filename) + 'Run CISD calculation before loading CISD RDMs.') else: one_rdm = self.cisd_one_rdm two_rdm = self.cisd_two_rdm one_rdm = numpy.kron(one_rdm/2,numpy.eye(2)) #two_rdm n_qubits = one_rdm.shape[0] new_two_rdm = numpy.zeros((n_qubits, n_qubits,n_qubits, n_qubits)) for p in range(n_qubits // 2): for q in range(n_qubits // 2): for r in range(n_qubits // 2): for s in range(n_qubits // 2): new_two_rdm[2 * p, 2 * q + 1, 2 * r + 1, 2 * s] = (two_rdm[p, q, r, s] / 2.) new_two_rdm[2 * p + 1, 2 * q, 2 * r, 2 * s + 1] = (two_rdm[p, q, r, s] / 2.) new_two_rdm[2 * p, 2 * q + 1, 2 * r, 2 * s + 1] = -(two_rdm[p, q, r, s] / 2.) new_two_rdm[2 * p + 1, 2 * q, 2 * r + 1, 2 * s] = -(two_rdm[p, q, r, s] / 2.) # Truncate. one_rdm[numpy.absolute(one_rdm) < EQ_TOLERANCE] = 0. new_two_rdm[numpy.absolute(new_two_rdm) < EQ_TOLERANCE] = 0. # Cast to InteractionRDM class. rdm = InteractionRDM(one_rdm, new_two_rdm) return rdm
def rdms_from_opdm_aa(self, opdm_aa): """ Generate InteractionRDM for the problem from opdm_aa :param opdm_aa: :return: """ opdm = np.zeros((self.num_qubits, self.num_qubits), dtype=complex) opdm[::2, ::2] = opdm_aa opdm[1::2, 1::2] = opdm_aa tpdm = wedge(opdm, opdm, (1, 1), (1, 1)) rdms = InteractionRDM(opdm, 2 * tpdm) return rdms
def test_qiskitpauli_to_qubitop_type_enforced(): """Enforce the appropriate type""" create_one = FermionOperator("1^") empty_one_body = np.zeros((2, 2)) empty_two_body = np.zeros((2, 2, 2, 2)) interact_one = InteractionOperator(1, empty_one_body, empty_two_body) interact_rdm = InteractionRDM(empty_one_body, empty_two_body) with pytest.raises(TypeError): qiskitpauli_to_qubitop(create_one) with pytest.raises(TypeError): qiskitpauli_to_qubitop(interact_one) with pytest.raises(TypeError): qiskitpauli_to_qubitop(interact_rdm)
def rdms_from_opdm_aa(self, opdm_aa) -> InteractionRDM: """Generate the RDM from just the alpha-alpha block. Due to symmetry, the beta-beta block is the same, and the other blocks are zero. Args: opdm_aa: The alpha-alpha block of the RDM """ opdm = np.zeros((self.num_qubits, self.num_qubits), dtype=complex) opdm[::2, ::2] = opdm_aa opdm[1::2, 1::2] = opdm_aa tpdm = wedge(opdm, opdm, (1, 1), (1, 1)) rdms = InteractionRDM(opdm, 2 * tpdm) return rdms
def test_translation_type_enforcement(): """ Make sure type check works """ create_one = FermionOperator("1^") empty_one_body = np.zeros((2, 2)) empty_two_body = np.zeros((2, 2, 2, 2)) interact_one = InteractionOperator(1, empty_one_body, empty_two_body) interact_rdm = InteractionRDM(empty_one_body, empty_two_body) with pytest.raises(TypeError): qubitop_to_qiskitpauli(create_one) with pytest.raises(TypeError): qubitop_to_qiskitpauli(interact_one) with pytest.raises(TypeError): qubitop_to_qiskitpauli(interact_rdm)
def rdms_from_rhf_opdm(self, opdm_aa: np.ndarray) -> InteractionRDM: """ Generate spin-orbital InteractionRDM object from the alpha-spin opdm. Args: opdm_aa: single spin sector of the 1-particle denstiy matrix Returns: InteractionRDM object for full spin-orbital 1-RDM and 2-RDM """ opdm = np.zeros((2 * self.num_orbitals, 2 * self.num_orbitals), dtype=np.complex128) opdm[::2, ::2] = opdm_aa opdm[1::2, 1::2] = opdm_aa tpdm = wedge(opdm, opdm, (1, 1), (1, 1)) rdms = InteractionRDM(opdm, 2 * tpdm) return rdms
def get_expectation_values_from_rdms( interactionrdm: InteractionRDM, qubitoperator: QubitOperator, sort_terms: bool = False, ) -> ExpectationValues: """Computes expectation values of Pauli strings in a QubitOperator given a fermionic InteractionRDM from OpenFermion. Args: interactionrdm: interaction RDM to use for the expectation values computation, as an OF InteractionRDM object qubitoperator: qubit operator to compute the expectation values for in the form of an OpenFermion QubitOperator object sort_terms: whether or not the input qubit operator needs to be sorted before calculating expectations Returns: expectation values of Pauli strings in the qubit operator as an ExpectationValues object """ if sort_terms: terms_iterator = sorted(qubitoperator.terms.items(), key=lambda x: abs(x[1]), reverse=True) else: terms_iterator = qubitoperator.terms.items() reordered_qubitoperator = QubitOperator() for term, coefficient in terms_iterator: reordered_qubitoperator += QubitOperator(term, coefficient) expectations_packed = interactionrdm.get_qubit_expectations( reordered_qubitoperator) if () in expectations_packed.terms: del expectations_packed.terms[( )] # Expectation of the constant term is excluded from expectation values expectations = np.array(list(expectations_packed.terms.values())) if np.any(np.abs(np.imag(expectations)) > 1e-3): raise RuntimeWarning( f"Expectation values extracted from rdms inside get_expectation_values_from_rdms are complex!" ) expectations = np.real(expectations) np.clip(expectations, -1, 1, out=expectations) return ExpectationValues(expectations)
def test_pyquil_to_qubitop_type_enforced(): """Enforce the appropriate type""" create_one = FermionOperator("1^") empty_one_body = np.zeros((2, 2)) empty_two_body = np.zeros((2, 2, 2, 2)) interact_one = InteractionOperator(1, empty_one_body, empty_two_body) interact_rdm = InteractionRDM(empty_one_body, empty_two_body) with pytest.raises(TypeError): pyquilpauli_to_qubitop(create_one) with pytest.raises(TypeError): pyquilpauli_to_qubitop(interact_one) with pytest.raises(TypeError): pyquilpauli_to_qubitop(interact_rdm) # don't accept anything other than pyquil PauliSum or PauliTerm with pytest.raises(TypeError): pyquilpauli_to_qubitop(create_one) with pytest.raises(TypeError): pyquilpauli_to_qubitop(interact_one) with pytest.raises(TypeError): pyquilpauli_to_qubitop(interact_rdm)
def get_molecular_rdm(self, use_fci=False): """Method to return 1-RDM and 2-RDMs from CISD or FCI. Args: use_fci: Boolean indicating whether to use RDM from FCI calculation. Returns: rdm: An instance of the MolecularRDM class. Raises: MisissingCalculationError: If the CI calculation has not been performed. """ # Make sure requested RDM has been computed and load. if use_fci: if self.fci_energy is None: raise MissingCalculationError( 'Missing FCI RDM in {}'.format(self.filename) + 'Run FCI calculation before loading FCI RDMs.') else: one_rdm = self.fci_one_rdm two_rdm = self.fci_two_rdm else: if self.cisd_energy is None: raise MissingCalculationError( 'Missing CISD RDM in {}'.format(self.filename) + 'Run CISD calculation before loading CISD RDMs.') else: one_rdm = self.cisd_one_rdm two_rdm = self.cisd_two_rdm # Truncate. one_rdm[numpy.absolute(one_rdm) < EQ_TOLERANCE] = 0. two_rdm[numpy.absolute(two_rdm) < EQ_TOLERANCE] = 0. # Cast to InteractionRDM class. rdm = InteractionRDM(one_rdm, two_rdm) return rdm
def test_translation_type_enforcement(): """ Make sure type check works """ create_one = FermionOperator("1^") empty_one_body = np.zeros((2, 2)) empty_two_body = np.zeros((2, 2, 2, 2)) interact_one = InteractionOperator(1, empty_one_body, empty_two_body) interact_rdm = InteractionRDM(empty_one_body, empty_two_body) with pytest.raises(TypeError): qubitop_to_pyquilpauli(create_one) with pytest.raises(TypeError): qubitop_to_pyquilpauli(interact_one) with pytest.raises(TypeError): qubitop_to_pyquilpauli(interact_rdm) # don't accept anything other than pyquil PauliSum or PauliTerm with pytest.raises(TypeError): qubitop_to_pyquilpauli(create_one) with pytest.raises(TypeError): qubitop_to_pyquilpauli(interact_one) with pytest.raises(TypeError): qubitop_to_pyquilpauli(interact_rdm)