def run(self, s=3, dt=0.5, target_root=0, diagonalize_each_step=True ): self._s = s self._nstates = s+1 self._dt = dt self._target_root = target_root self._diagonalize_each_step = diagonalize_each_step self._n_classical_params = 0 self._n_cnot = 0 self._n_pauli_trm_measures = 0 # Print options banner (should done for all algorithms). self.print_options_banner() ######### SRQK ######### # Build S and H matricies if(self._fast): self._S, self._Hbar = self.build_qk_mats() else: raise ValueError("A realistice implementation of non-Trotterized SRQK is unavalable.") # Set the condition number of QSD overlap self._Scond = np.linalg.cond(self._S) # Get eigenvalues and eigenvectors self._eigenvalues, self._eigenvectors \ = canonical_geig_solve(self._S, self._Hbar, print_mats=self._verbose, sort_ret_vals=True) print('\n ==> QK eigenvalues <==') print('----------------------------------------') for i, val in enumerate(self._eigenvalues): print(' root {} {:.8f} {:.8f}j'.format(i, np.real(val), np.imag(val))) # Set ground state energy. self._Egs = np.real(self._eigenvalues[0]) # Set target state energy. if(self._target_root==0): self._Ets = self._Egs else: self._Ets = np.real(self._eigenvalues[self._target_root]) ######### SRQK ######### # Print summary banner (should done for all algorithms). self.print_summary_banner() # verify that required attributes were defined # (should be called for all algorithms!) self.verify_run()
def do_qlanczos(self): """""" n_lanczos_vecs = len(self._lanczos_vecs) h_mat = np.zeros((n_lanczos_vecs, n_lanczos_vecs), dtype=complex) s_mat = np.zeros((n_lanczos_vecs, n_lanczos_vecs), dtype=complex) print('\n\n-----------------------------------------------------') print(' Quantum Imaginary Time Lanczos ') print('-----------------------------------------------------\n\n') print(f"{'Beta':>7}{'k(S)':>7}{'E(Npar)':>19}") print( '-------------------------------------------------------------------------------' ) if (self._print_summary_file): f2 = open("lanczos_summary.dat", "w+", buffering=1) f2.write(f"#{'Beta':>7}{'k(S)':>7}{'E(Npar)':>19}\n") f2.write( '#-------------------------------------------------------------------------------\n' ) for m in range(n_lanczos_vecs): for n in range(m + 1): h_mat[m][n] = np.vdot(self._lanczos_vecs[m], self._Hlanczos_vecs[n]) h_mat[n][m] = np.conj(h_mat[m][n]) s_mat[m][n] = np.vdot(self._lanczos_vecs[m], self._lanczos_vecs[n]) s_mat[n][m] = np.conj(s_mat[m][n]) k = m + 1 evals, evecs = canonical_geig_solve(s_mat[0:k, 0:k], h_mat[0:k, 0:k], print_mats=False, sort_ret_vals=True) scond = np.linalg.cond(s_mat[0:k, 0:k]) print( f'{m * self._lanczos_gap * self._db:7.3f} {scond:7.2e} {np.real(evals[0]):+15.9f} ' ) if (self._print_summary_file): f2.write( f'{m * self._lanczos_gap * self._db:7.3f} {scond:7.2e} {np.real(evals[0]):+15.9f} \n' ) if (self._print_summary_file): f2.close() self._Egs_lanczos = evals[0]
def build_sa_qk_mats(self): """Returns the QK effective hamiltonain and overlap matrices in a basis of spin adapted references. """ num_tot_basis = len(self._sa_ref_lst) * self._nstates_per_ref h_mat = np.zeros((num_tot_basis,num_tot_basis), dtype=complex) s_mat = np.zeros((num_tot_basis,num_tot_basis), dtype=complex) omega_lst = [] Homega_lst = [] for i, ref in enumerate(self._sa_ref_lst): for m in range(self._nstates_per_ref): Um = qforte.Circuit() phase1 = 1.0 if(m>0): fact = (0.0-1.0j) * m * self._mr_dt expn_op1, phase1 = trotterize(self._qb_ham, factor=fact, trotter_number=self._trotter_number) Um.add(expn_op1) QC = qforte.Computer(self._nqb) state_prep_lst = [] for term in ref: coeff = term[0] det = term[1] idx = ref_to_basis_idx(det) state = qforte.QubitBasis(idx) state_prep_lst.append( (state, coeff) ) QC.set_state(state_prep_lst) QC.apply_circuit(Um) QC.apply_constant(phase1) omega_lst.append(np.asarray(QC.get_coeff_vec(), dtype=complex)) QC.apply_operator(self._qb_ham) Homega_lst.append(np.asarray(QC.get_coeff_vec(), dtype=complex)) if(self._diagonalize_each_step): print('\n\n') print(f"{'k(S)':>7}{'E(Npar)':>19}{'N(params)':>14}{'N(CNOT)':>18}{'N(measure)':>20}") print('-------------------------------------------------------------------------------') # TODO (opt): add this to previous loop for p in range(num_tot_basis): for q in range(p, num_tot_basis): h_mat[p][q] = np.vdot(omega_lst[p], Homega_lst[q]) h_mat[q][p] = np.conj(h_mat[p][q]) s_mat[p][q] = np.vdot(omega_lst[p], omega_lst[q]) s_mat[q][p] = np.conj(s_mat[p][q]) if (self._diagonalize_each_step): # TODO (cleanup): have this print to a separate file evals, evecs = canonical_geig_solve(s_mat[0:p+1, 0:p+1], h_mat[0:p+1, 0:p+1], print_mats=False, sort_ret_vals=True) scond = np.linalg.cond(s_mat[0:p+1, 0:p+1]) cs_str = '{:.2e}'.format(scond) k = p+1 self._n_classical_params = k if(k==1): self._n_cnot = self._srqk._n_cnot else: self._n_cnot = 2 * Um.get_num_cnots() self._n_pauli_trm_measures = k * self._Nl + self._srqk._n_pauli_trm_measures self._n_pauli_trm_measures += k * (k-1) * self._Nl self._n_pauli_trm_measures += k * (k-1) print(f' {scond:7.2e} {np.real(evals[self._target_root]):+15.9f} {self._n_classical_params:8} {self._n_cnot:10} {self._n_pauli_trm_measures:12}') return s_mat, h_mat
def build_qk_mats(self): num_tot_basis = len(self._single_det_refs) * self._nstates_per_ref h_mat = np.zeros((num_tot_basis,num_tot_basis), dtype=complex) s_mat = np.zeros((num_tot_basis,num_tot_basis), dtype=complex) # TODO (opt): make numpy arrays. omega_lst = [] Homega_lst = [] for i, ref in enumerate(self._single_det_refs): for m in range(self._nstates_per_ref): # NOTE: do NOT use Uprep here (is determinant specific). Um = qforte.Circuit() for j in range(self._nqb): if ref[j] == 1: Um.add(qforte.gate('X', j, j)) phase1 = 1.0 if(m>0): fact = (0.0-1.0j) * m * self._mr_dt expn_op1, phase1 = trotterize(self._qb_ham, factor=fact, trotter_number=self._trotter_number) Um.add(expn_op1) QC = qforte.Computer(self._nqb) QC.apply_circuit(Um) QC.apply_constant(phase1) omega_lst.append(np.asarray(QC.get_coeff_vec(), dtype=complex)) QC.apply_operator(self._qb_ham) Homega_lst.append(np.asarray(QC.get_coeff_vec(), dtype=complex)) if(self._diagonalize_each_step): print('\n\n') print(f"{'k(S)':>7}{'E(Npar)':>19}{'N(params)':>14}{'N(CNOT)':>18}{'N(measure)':>20}") print('-------------------------------------------------------------------------------') for p in range(num_tot_basis): for q in range(p, num_tot_basis): h_mat[p][q] = np.vdot(omega_lst[p], Homega_lst[q]) h_mat[q][p] = np.conj(h_mat[p][q]) s_mat[p][q] = np.vdot(omega_lst[p], omega_lst[q]) s_mat[q][p] = np.conj(s_mat[p][q]) if (self._diagonalize_each_step): # TODO (cleanup): have this print to a separate file evals, evecs = canonical_geig_solve(s_mat[0:p+1, 0:p+1], h_mat[0:p+1, 0:p+1], print_mats=False, sort_ret_vals=True) scond = np.linalg.cond(s_mat[0:p+1, 0:p+1]) cs_str = '{:.2e}'.format(scond) k = p+1 self._n_classical_params = k if(k==1): self._n_cnot = self._srqk._n_cnot else: self._n_cnot = 2 * Um.get_num_cnots() self._n_pauli_trm_measures = k * self._Nl + self._srqk._n_pauli_trm_measures self._n_pauli_trm_measures += k * (k-1) * self._Nl self._n_pauli_trm_measures += k * (k-1) print(f' {scond:7.2e} {np.real(evals[self._target_root]):+15.9f} {self._n_classical_params:8} {self._n_cnot:10} {self._n_pauli_trm_measures:12}') return s_mat, h_mat
def run(self, d=2, s=3, mr_dt=0.5, target_root=0, reference_generator='SRQK', use_phase_based_selection=False, use_spin_adapted_refs=True, s_o=4, dt_o=0.25, trotter_order_o=1, trotter_number_o=1, diagonalize_each_step=True ): self._d = d self._s = s self._nstates_per_ref = s+1 self._nstates = d*(s+1) self._mr_dt = mr_dt self._target_root = target_root self._reference_generator = reference_generator self._use_phase_based_selection = use_phase_based_selection self._use_spin_adapted_refs = use_spin_adapted_refs self._s_o = s_o self._ninitial_states = s_o + 1 self._dt_o = dt_o self._trotter_order_o = trotter_order_o self._trotter_number_o = trotter_number_o self._diagonalize_each_step=diagonalize_each_step if(self._state_prep_type != 'occupation_list'): raise ValueError("MRSQK implementation can only handle occupation_list reference.") # Print options banner (should done for all algorithms). self.print_options_banner() ######### MRSQK ######### # 1. Build the reference wavefunctions. if(reference_generator=='SRQK'): print('\n ==> Beginning SRQK for reference selection.') self._srqk = SRQK(self._sys, self._ref, trotter_order=self._trotter_order_o, trotter_number=self._trotter_number_o) self._srqk.run(s=self._s_o, dt=self._dt_o) self._n_classical_params = self._srqk._n_classical_params self._n_cnot = self._srqk._n_cnot self._n_pauli_trm_measures = self._srqk._n_pauli_trm_measures self.build_refs_from_srqk() print('\n ==> SRQK reference selection complete.') elif(reference_generator=='ACI'): raise NotImplementedError('ACI reference generation not yet available in qforte.') print('\n ==> Beginning ACI for reference selction.') print('\n ==> ACI reference selction complete.') else: raise ValueError("Incorrect value passed for reference_generator, can be 'SRQK' or 'ACI'.") # 2. Build the S and H matrices. # Build S and H matricies if(self._fast): if(self._use_spin_adapted_refs): self._S, self._Hbar = self.build_sa_qk_mats() else: self._S, self._Hbar = self.build_qk_mats() else: self._S, self._Hbar = self.build_qk_mats_realistic() # Set the condition number of QSD overlap self._Scond = np.linalg.cond(self._S) # 3. Solve the generalized eigenproblem # Get eigenvalues and eigenvectors self._eigenvalues, self._eigenvectors \ = canonical_geig_solve(self._S, self._Hbar, print_mats=self._verbose, sort_ret_vals=True) # 4. Report and set results. print('\n ==> MRSQK eigenvalues <==') print('----------------------------------------') for i, val in enumerate(self._eigenvalues): print(' root {} {:.8f} {:.8f}j'.format(i, np.real(val), np.imag(val))) # Set ground state energy. self._Egs = np.real(self._eigenvalues[0]) # Set target state energy. if(self._target_root==0): self._Ets = self._Egs else: self._Ets = np.real(self._eigenvalues[self._target_root]) self._n_classical_params = self._nstates # diagonal terms of Hbar if(reference_generator=='SRQK'): self._n_pauli_trm_measures = self._nstates * self._Nl + self._srqk._n_pauli_trm_measures else: raise ValueError('Can only count number of paulit term measurements when using SRQK.') # off-diagonal of Hbar (<X> and <Y> of Hadamard test) self._n_pauli_trm_measures += self._nstates*(self._nstates-1) * self._Nl # off-diagonal of S (<X> and <Y> of Hadamard test) self._n_pauli_trm_measures += self._nstates*(self._nstates-1) ######### MRSQK ######### # Print summary banner (should done for all algorithms). self.print_summary_banner() # verify that required attributes were defined # (should be called for all algorithms!) self.verify_run()
def build_sa_qk_mats(self): # TODO (cleanup): imporve/update docs """Returns matrices P and Q with dimension (nstates_per_ref * len(ref_lst) X nstates_per_ref * len(ref_lst)) based on the evolution of two unitary operators Um = exp(-i * m * dt * H) and Un = exp(-i * n * dt *H). This is done for all spin adapted refrerences |Phi_K> in ref_lst, with (Q) and without (P) measuring with respect to the operator H. Elements P_mn are given by <Phi_I| Um^dag Un | Phi_J>. Elements Q_mn are given by <Phi_I| Um^dag H Un | Phi_J>. This function builds P and Q in an efficient manor and gives the same result as M built from 'matrix_element', but is unphysical for a quantum computer. Arguments --------- ref_lst : list of lists A list containing all of the spin adapted references |Phi_K> to perfrom evolutions on. Is specifically a list of lists of pairs containing coefficient vales and a lists pertaning to single determinants. As an example, ref_lst = [ [ (1.0, [1,1,0,0]) ], [ (0.7071, [0,1,1,0]), (0.7071, [1,0,0,1]) ] ]. nstates_per_ref : int The number of Krylov basis states to generate for each reference. dt_lst : list List of time steps to use for each reference (ususally the same for all references). H : QuantumOperator The operator to time evolove and measure with respect to (usually the Hamiltonain). nqubits : int The number of qubits trot_number : int The number of trotter steps (m) to perform when approximating the matrix exponentials (Um or Un). For the exponential of two non commuting terms e^(A + B), the approximate operator C(m) = (e^(A/m) * e^(B/m))^m is exact in the infinite m limit. Returns ------- s_mat : ndarray A numpy array containing the elements P_mn h_mat : ndarray A numpy array containing the elements Q_mn """ num_tot_basis = len(self._sa_ref_lst) * self._nstates_per_ref h_mat = np.zeros((num_tot_basis,num_tot_basis), dtype=complex) s_mat = np.zeros((num_tot_basis,num_tot_basis), dtype=complex) omega_lst = [] Homega_lst = [] for i, ref in enumerate(self._sa_ref_lst): for m in range(self._nstates_per_ref): # TODO (cleanup): will need to consider gate count for this part. Um = qforte.QuantumCircuit() phase1 = 1.0 if(m>0): fact = (0.0-1.0j) * m * self._mr_dt expn_op1, phase1 = trotterize(self._qb_ham, factor=fact, trotter_number=self._trotter_number) Um.add_circuit(expn_op1) QC = qforte.QuantumComputer(self._nqb) state_prep_lst = [] for term in ref: coeff = term[0] det = term[1] idx = ref_to_basis_idx(det) state = qforte.QuantumBasis(idx) state_prep_lst.append( (state, coeff) ) QC.set_state(state_prep_lst) QC.apply_circuit(Um) QC.apply_constant(phase1) omega_lst.append(np.asarray(QC.get_coeff_vec(), dtype=complex)) QC.apply_operator(self._qb_ham) Homega_lst.append(np.asarray(QC.get_coeff_vec(), dtype=complex)) if(self._diagonalize_each_step): print('\n\n') print(f"{'k(S)':>7}{'E(Npar)':>19}{'N(params)':>14}{'N(CNOT)':>18}{'N(measure)':>20}") print('-------------------------------------------------------------------------------') # TODO (opt): add this to previous loop for p in range(num_tot_basis): for q in range(p, num_tot_basis): h_mat[p][q] = np.vdot(omega_lst[p], Homega_lst[q]) h_mat[q][p] = np.conj(h_mat[p][q]) s_mat[p][q] = np.vdot(omega_lst[p], omega_lst[q]) s_mat[q][p] = np.conj(s_mat[p][q]) if (self._diagonalize_each_step): # TODO (cleanup): have this print to a separate file evals, evecs = canonical_geig_solve(s_mat[0:p+1, 0:p+1], h_mat[0:p+1, 0:p+1], print_mats=False, sort_ret_vals=True) scond = np.linalg.cond(s_mat[0:p+1, 0:p+1]) cs_str = '{:.2e}'.format(scond) k = p+1 self._n_classical_params = k if(k==1): self._n_cnot = self._srqk._n_cnot else: self._n_cnot = 2 * Um.get_num_cnots() self._n_pauli_trm_measures = k * self._Nl + self._srqk._n_pauli_trm_measures self._n_pauli_trm_measures += k * (k-1) * self._Nl self._n_pauli_trm_measures += k * (k-1) print(f' {scond:7.2e} {np.real(evals[self._target_root]):+15.9f} {self._n_classical_params:8} {self._n_cnot:10} {self._n_pauli_trm_measures:12}') return s_mat, h_mat
def run(self, d=2, s=3, mr_dt=0.5, target_root=0, reference_generator='SRQK', use_phase_based_selection=False, use_spin_adapted_refs=True, s_o=4, dt_o=0.25, trotter_order_o=1, trotter_number_o=1, diagonalize_each_step=True ): """ _d : int The number of reference states. _diagonalize_each_step : bool For diagnostic purposes, should the eigenvalue of the target root of the quantum Krylov subspace be printed after each new unitary? We recommend passing an s so the change in the eigenvalue is small. _ninitial_states : bool _nstates : int The number of states _nstates_per_ref : int The number of states for a generated reference. _reference_generator : {"SRQK"} Specifies an algorithm to choose the reference state. _s : int The greatest m to use in unitaries _target_root : int Which root of the quantum Krylov subspace should be taken? _use_phase_based_selection : bool _use_spin_adapted_refs : bool SRQK Reference Specific Keywords _dt_o : float dt for SRQK. _s_o : int s for SRQK. _trotter_number_o : int The number of Trotter steps to be used in the SRQK algorithm. _trotter_order_o : int The operator ordering to be used in the Trotter product. """ self._d = d self._s = s self._nstates_per_ref = s+1 self._nstates = d*(s+1) self._mr_dt = mr_dt self._target_root = target_root self._reference_generator = reference_generator self._use_phase_based_selection = use_phase_based_selection self._use_spin_adapted_refs = use_spin_adapted_refs self._s_o = s_o self._ninitial_states = s_o + 1 self._dt_o = dt_o self._trotter_order_o = trotter_order_o self._trotter_number_o = trotter_number_o self._diagonalize_each_step=diagonalize_each_step # Print options banner (should done for all algorithms). self.print_options_banner() ######### MRSQK ######### # 1. Build the reference wavefunctions. if(reference_generator=='SRQK'): print('\n ==> Beginning SRQK for reference selection.') self._srqk = SRQK(self._sys, self._ref, trotter_order=self._trotter_order_o, trotter_number=self._trotter_number_o) self._srqk.run(s=self._s_o, dt=self._dt_o) self._n_classical_params = self._srqk._n_classical_params self._n_cnot = self._srqk._n_cnot self._n_pauli_trm_measures = self._srqk._n_pauli_trm_measures self.build_refs_from_srqk() print('\n ==> SRQK reference selection complete.') elif(reference_generator=='ACI'): raise NotImplementedError('ACI reference generation not yet available in qforte.') print('\n ==> Beginning ACI for reference selction.') print('\n ==> ACI reference selction complete.') else: raise ValueError("Incorrect value passed for reference_generator, can be 'SRQK' or 'ACI'.") # 2. Build the S and H matrices. # Build S and H matricies if(self._fast): if(self._use_spin_adapted_refs): self._S, self._Hbar = self.build_sa_qk_mats() else: self._S, self._Hbar = self.build_qk_mats() else: self._S, self._Hbar = self.build_qk_mats_realistic() # Set the condition number of QSD overlap self._Scond = np.linalg.cond(self._S) # 3. Solve the generalized eigenproblem # Get eigenvalues and eigenvectors self._eigenvalues, self._eigenvectors \ = canonical_geig_solve(self._S, self._Hbar, print_mats=self._verbose, sort_ret_vals=True) # 4. Report and set results. print('\n ==> MRSQK eigenvalues <==') print('----------------------------------------') for i, val in enumerate(self._eigenvalues): print(' root {} {:.8f} {:.8f}j'.format(i, np.real(val), np.imag(val))) # Set ground state energy. self._Egs = np.real(self._eigenvalues[0]) # Set target state energy. if(self._target_root==0): self._Ets = self._Egs else: self._Ets = np.real(self._eigenvalues[self._target_root]) self._n_classical_params = self._nstates # diagonal terms of Hbar if(reference_generator=='SRQK'): self._n_pauli_trm_measures = self._nstates * self._Nl + self._srqk._n_pauli_trm_measures else: raise ValueError('Can only count number of paulit term measurements when using SRQK.') # off-diagonal of Hbar (<X> and <Y> of Hadamard test) self._n_pauli_trm_measures += self._nstates*(self._nstates-1) * self._Nl # off-diagonal of S (<X> and <Y> of Hadamard test) self._n_pauli_trm_measures += self._nstates*(self._nstates-1) ######### MRSQK ######### # Print summary banner (should done for all algorithms). self.print_summary_banner() # verify that required attributes were defined # (should be called for all algorithms!) self.verify_run()
def build_qk_mats(self): """Returns matrices S and H needed for the QK algorithm using the Trotterized form of the unitary operators U_n = exp(-i n dt H) The mathematical operations of this function are unphysical for a quantum computer, but efficient for a simulator. Returns ------- s_mat : ndarray A numpy array containing the elements S_mn = <Phi | Um^dag Un | Phi>. _nstates by _nstates h_mat : ndarray A numpy array containing the elements H_mn = <Phi | Um^dag H Un | Phi> _nstates by _nstates """ h_mat = np.zeros((self._nstates,self._nstates), dtype=complex) s_mat = np.zeros((self._nstates,self._nstates), dtype=complex) # Store these vectors for the aid of MRSQK self._omega_lst = [] Homega_lst = [] if(self._diagonalize_each_step): print('\n\n') print(f"{'k(S)':>7}{'E(Npar)':>19}{'N(params)':>14}{'N(CNOT)':>18}{'N(measure)':>20}") print('-------------------------------------------------------------------------------') if (self._print_summary_file): f = open("summary.dat", "w+", buffering=1) f.write(f"#{'k(S)':>7}{'E(Npar)':>19}{'N(params)':>14}{'N(CNOT)':>18}{'N(measure)':>20}\n") f.write('#-------------------------------------------------------------------------------\n') Hsp = get_scipy_csc_from_op(self._qb_ham, -1.0j) QC = qforte.Computer(self._nqb) QC.apply_circuit(self._Uprep) # get the time evolution vectors psi_t_vecs = apply_time_evolution_op(QC, Hsp, self._dt, self._nstates) for m in range(self._nstates): # # Compute U_m |φ> QC = qforte.Computer(self._nqb) QC.set_coeff_vec(psi_t_vecs[m]) self._omega_lst.append(np.asarray(QC.get_coeff_vec(), dtype=complex)) # Compute H U_m |φ> QC.apply_operator(self._qb_ham) Homega_lst.append(np.asarray(QC.get_coeff_vec(), dtype=complex)) # Compute S_mn = <φ| U_m^\dagger U_n |φ> and H_mn = <φ| U_m^\dagger H U_n |φ> for n in range(len(self._omega_lst)): h_mat[m][n] = np.vdot(self._omega_lst[m], Homega_lst[n]) h_mat[n][m] = np.conj(h_mat[m][n]) s_mat[m][n] = np.vdot(self._omega_lst[m], self._omega_lst[n]) s_mat[n][m] = np.conj(s_mat[m][n]) if (self._diagonalize_each_step): # TODO (cleanup): have this print to a separate file k = m+1 evals, evecs = canonical_geig_solve(s_mat[0:k, 0:k], h_mat[0:k, 0:k], print_mats=False, sort_ret_vals=True) scond = np.linalg.cond(s_mat[0:k, 0:k]) self._n_classical_params = k self._n_cnot = 0 self._n_pauli_trm_measures = k * self._Nl self._n_pauli_trm_measures += k * (k-1) * self._Nl self._n_pauli_trm_measures += k * (k-1) print(f' {scond:7.2e} {np.real(evals[self._target_root]):+15.9f} {self._n_classical_params:8} {0:10} {self._n_pauli_trm_measures:12}') if (self._print_summary_file): f.write(f' {scond:7.2e} {np.real(evals[self._target_root]):+15.9f} {self._n_classical_params:8} {0:10} {self._n_pauli_trm_measures:12}\n') if (self._diagonalize_each_step and self._print_summary_file): f.close() self._n_classical_params = self._nstates self._n_cnot = 0 # diagonal terms of Hbar self._n_pauli_trm_measures = self._nstates * self._Nl # off-diagonal of Hbar (<X> and <Y> of Hadamard test) self._n_pauli_trm_measures += self._nstates*(self._nstates-1) * self._Nl # off-diagonal of S (<X> and <Y> of Hadamard test) self._n_pauli_trm_measures += self._nstates*(self._nstates-1) return s_mat, h_mat
def run(self, s=3, dt=0.5, target_root=0, diagonalize_each_step=True): """ Construct a reference state for the MRSQK algorithm as some root of the Hamiltonian in the space of H U_n φ where U_m = exp(-i m dt H) and φ a single determinant. _diagonalize_each_step : bool For diagnostic purposes, should the eigenvalue of the target root of the quantum Krylov subspace be printed after each new unitary? We recommend passing an s so the change in the eigenvalue is small. _dt : float The dt used in the unitaries _nstates : int The number of states _s : int The greatest m to use in unitaries _target_root : int Which root of the quantum Krylov subspace should be taken? """ self._s = s self._nstates = s + 1 self._dt = dt self._target_root = target_root self._diagonalize_each_step = diagonalize_each_step self._n_classical_params = 0 self._n_cnot = 0 self._n_pauli_trm_measures = 0 # Print options banner (should done for all algorithms). self.print_options_banner() ######### SRQK ######### # Build S and H matricies if (self._fast): self._S, self._Hbar = self.build_qk_mats() else: self._S, self._Hbar = self.build_qk_mats_realistic() # Set the condition number of QSD overlap self._Scond = np.linalg.cond(self._S) # Get eigenvalues and eigenvectors self._eigenvalues, self._eigenvectors \ = canonical_geig_solve(self._S, self._Hbar, print_mats=self._verbose, sort_ret_vals=True) print('\n ==> QK eigenvalues <==') print('----------------------------------------') for i, val in enumerate(self._eigenvalues): print(' root {} {:.8f} {:.8f}j'.format( i, np.real(val), np.imag(val))) # Set ground state energy. self._Egs = np.real(self._eigenvalues[0]) # Set target state energy. if (self._target_root == 0): self._Ets = self._Egs else: self._Ets = np.real(self._eigenvalues[self._target_root]) ######### SRQK ######### # Print summary banner (should done for all algorithms). self.print_summary_banner() # verify that required attributes were defined # (should be called for all algorithms!) self.verify_run()