Ejemplo n.º 1
0
    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()
Ejemplo n.º 2
0
    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]
Ejemplo n.º 3
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
Ejemplo n.º 4
0
    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
Ejemplo n.º 5
0
    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()
Ejemplo n.º 6
0
    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
Ejemplo n.º 7
0
    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()
Ejemplo n.º 8
0
    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
Ejemplo n.º 9
0
    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()