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 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 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 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 global_gradient_opdm(self, params: np.ndarray, alpha_opdm: np.ndarray): opdm = np.zeros((self.num_qubits, self.num_qubits), dtype=np.complex128) opdm[::2, ::2] = alpha_opdm opdm[1::2, 1::2] = alpha_opdm tpdm = 2 * wedge(opdm, opdm, (1, 1), (1, 1)) # now go through and generate all the necessary Z, Y, Y_kl matrices kappa_matrix = rhf_params_to_matrix(params, len(self.occ) + len(self.virt), self.occ, self.virt) kappa_matrix_full = np.kron(kappa_matrix, np.eye(2)) w_full, v_full = np.linalg.eigh( -1j * kappa_matrix_full) # so that kappa = i U lambda U^ eigs_scaled_full = get_matrix_of_eigs(w_full) grad = np.zeros(self.nocc * self.nvirt, dtype=np.complex128) kdelta = np.eye(self.num_qubits) # NOW GENERATE ALL TERMS ASSOCIATED WITH THE GRADIENT!!!!!! for p in range(self.nocc * self.nvirt): grad_params = np.zeros_like(params) grad_params[p] = 1 Y = rhf_params_to_matrix(grad_params, len(self.occ) + len(self.virt), self.occ, self.virt) Y_full = np.kron(Y, np.eye(2)) # Now rotate Y int othe basis that diagonalizes Z Y_kl_full = v_full.conj().T @ Y_full @ v_full # now rotate Y_{kl} * (exp(i(l_{k} - l_{l})) - 1) / (i(l_{k} - l_{l})) # into the original basis pre_matrix_full = v_full @ (eigs_scaled_full * Y_kl_full) @ v_full.conj().T grad_expectation = -1.0 * np.einsum( 'ab,pq,aq,pb', self.hamiltonian.one_body_tensor, pre_matrix_full, kdelta, opdm, optimize='optimal').real grad_expectation += 1.0 * np.einsum( 'ab,pq,bp,aq', self.hamiltonian.one_body_tensor, pre_matrix_full, kdelta, opdm, optimize='optimal').real grad_expectation += 1.0 * np.einsum( 'ijkl,pq,iq,jpkl', self.hamiltonian.two_body_tensor, pre_matrix_full, kdelta, tpdm, optimize='optimal').real grad_expectation += -1.0 * np.einsum( 'ijkl,pq,jq,ipkl', self.hamiltonian.two_body_tensor, pre_matrix_full, kdelta, tpdm, optimize='optimal').real grad_expectation += -1.0 * np.einsum( 'ijkl,pq,kp,ijlq', self.hamiltonian.two_body_tensor, pre_matrix_full, kdelta, tpdm, optimize='optimal').real grad_expectation += 1.0 * np.einsum( 'ijkl,pq,lp,ijkq', self.hamiltonian.two_body_tensor, pre_matrix_full, kdelta, tpdm, optimize='optimal').real grad[p] = grad_expectation return grad
def rhf_global_gradient(self, params: np.ndarray, alpha_opdm: np.ndarray): """ Compute rhf global gradient Args: params: rhf-parameters for rotation matrix. alpha_opdm: 1-RDM corresponding to results of basis rotation parameterized by `params'. Returns: gradient vector the same size as the input `params' """ opdm = np.zeros((2 * self.num_orbitals, 2 * self.num_orbitals), dtype=np.complex128) opdm[::2, ::2] = alpha_opdm opdm[1::2, 1::2] = alpha_opdm tpdm = 2 * wedge(opdm, opdm, (1, 1), (1, 1)) # now go through and generate all the necessary Z, Y, Y_kl matrices kappa_matrix = rhf_params_to_matrix(params, len(self.occ) + len(self.virt), self.occ, self.virt) kappa_matrix_full = np.kron(kappa_matrix, np.eye(2)) w_full, v_full = np.linalg.eigh( -1j * kappa_matrix_full) # so that kappa = i U lambda U^ eigs_scaled_full = get_matrix_of_eigs(w_full) grad = np.zeros(self.nocc * self.nvirt, dtype=np.complex128) # kdelta = np.eye(2 * self.num_orbitals) # NOW GENERATE ALL TERMS ASSOCIATED WITH THE GRADIENT!!!!!! for p in range(self.nocc * self.nvirt): grad_params = np.zeros_like(params) grad_params[p] = 1 Y = rhf_params_to_matrix(grad_params, len(self.occ) + len(self.virt), self.occ, self.virt) Y_full = np.kron(Y, np.eye(2)) # Now rotate Y int othe basis that diagonalizes Z Y_kl_full = v_full.conj().T.dot(Y_full).dot(v_full) # now rotate Y_{kl} * (exp(i(l_{k} - l_{l})) - 1) / (i(l_{k} - l_{l})) # into the original basis pre_matrix_full = v_full.dot(eigs_scaled_full * Y_kl_full).dot( v_full.conj().T) grad_expectation = -1.0 * np.einsum( 'ab,pa,pb', self.hamiltonian.one_body_tensor, pre_matrix_full, opdm, optimize='optimal').real grad_expectation += 1.0 * np.einsum( 'ab,bq,aq', self.hamiltonian.one_body_tensor, pre_matrix_full, opdm, optimize='optimal').real grad_expectation += 1.0 * np.einsum( 'ijkl,pi,jpkl', self.hamiltonian.two_body_tensor, pre_matrix_full, tpdm, optimize='optimal').real grad_expectation += -1.0 * np.einsum( 'ijkl,pj,ipkl', self.hamiltonian.two_body_tensor, pre_matrix_full, tpdm, optimize='optimal').real grad_expectation += -1.0 * np.einsum( 'ijkl,kq,ijlq', self.hamiltonian.two_body_tensor, pre_matrix_full, tpdm, optimize='optimal').real grad_expectation += 1.0 * np.einsum( 'ijkl,lq,ijkq', self.hamiltonian.two_body_tensor, pre_matrix_full, tpdm, optimize='optimal').real grad[p] = grad_expectation return grad