示例#1
0
    def perfect_experimental_avg(self, params):

        """
        calculates the exact experimental result of the operator the Experiment object was initialized with

        :param params: (list) the list of parameters for the state preparation ansatz.

        """

        if(self.prepare_each_time_==False):
            #1 initialize a quantum computer
            qc = qforte.Computer(self.n_qubits_)

            #2 build/update generator with params
            # self.generator_.set_parameters(params)

            #3 apply generator (once if prepare_each_time = False, N_sample times if)
            qc.apply_circuit(self.generator_)

            #4 measure operator
            n_terms = len(self.operator_.terms())
            term_sum = 0.0

            for k in range(n_terms):
                term_sum += self.operator_.terms()[k][0] * qc.perfect_measure_circuit(self.operator_.terms()[k][1]);

            return numpy.real(term_sum)

        elif(self.prepare_each_time_==True):
            raise Exception('No support yet for measurement with multiple state preparations')
示例#2
0
    def build_classical_CI_mats(self):
        """Builds a classical configuration interaction out of single determinants.
        """
        num_tot_basis = len(self._pre_sa_ref_lst)
        h_CI = np.zeros((num_tot_basis,num_tot_basis), dtype=complex)

        omega_lst = []
        Homega_lst = []

        for i, ref in enumerate(self._pre_sa_ref_lst):
            # NOTE: do NOT use Uprep here (is determinant specific).
            Un = qforte.Circuit()
            for j in range(self._nqb):
                if ref[j] == 1:
                    Un.add(qforte.gate('X', j, j))

            QC = qforte.Computer(self._nqb)
            QC.apply_circuit(Un)
            omega_lst.append(np.asarray(QC.get_coeff_vec(), dtype=complex))

            Homega = np.zeros((2**self._nqb), dtype=complex)

            QC.apply_operator(self._qb_ham)
            Homega_lst.append(np.asarray(QC.get_coeff_vec(), dtype=complex))

            for j in range(len(omega_lst)):
                h_CI[i][j] = np.vdot(omega_lst[i], Homega_lst[j])
                h_CI[j][i] = np.conj(h_CI[i][j])

        return h_CI
示例#3
0
    def build_sparse_S_b(self, b):
        b_sparse = []
        idx_sparse = []
        for I, bI in enumerate(b):
            if(np.abs(bI) > self._b_thresh):
                idx_sparse.append(I)
                b_sparse.append(bI)
        Idim = len(idx_sparse)
        self._n_pauli_trm_measures += int(Idim*(Idim+1)*0.5)

        S = np.zeros((len(b_sparse),len(b_sparse)), dtype=complex)

        Ipsi_qc = qf.Computer(self._nqb)
        Ipsi_qc.set_coeff_vec(copy.deepcopy(self._qc.get_coeff_vec()))
        CI = np.zeros(shape=(Idim, int(2**self._nqb)), dtype=complex)

        for i in range(Idim):
            S[i][i] = 1.0 # With Pauli strings, this is always the inner product
            Ii = idx_sparse[i]
            Ipsi_qc.apply_operator(self._sig.terms()[Ii][1])
            CI[i,:] = copy.deepcopy(Ipsi_qc.get_coeff_vec())
            for j in range(i):
                S[i][j] = S[j][i] = np.vdot(CI[i,:], CI[j,:])
            Ipsi_qc.set_coeff_vec(copy.deepcopy(self._qc.get_coeff_vec()))

        return idx_sparse, np.real(S), np.real(b_sparse)
示例#4
0
    def evolve(self):
        """Perform QITE for a time step :math:`\\Delta \\beta`.
        """
        self._Uqite.add(self._Uprep)
        self._qc = qf.Computer(self._nqb)
        self._qc.apply_circuit(self._Uqite)

        if(self._do_lanczos):
            self._lanczos_vecs = []
            self._Hlanczos_vecs = []

            self._lanczos_vecs.append(copy.deepcopy(self._qc.get_coeff_vec()))

            qcSig_temp = qf.Computer(self._nqb)
            qcSig_temp.set_coeff_vec(copy.deepcopy(self._qc.get_coeff_vec()))
            qcSig_temp.apply_operator(self._qb_ham)
            self._Hlanczos_vecs.append(copy.deepcopy(qcSig_temp.get_coeff_vec()))


        print(f"{'beta':>7}{'E(beta)':>18}{'N(params)':>14}{'N(CNOT)':>18}{'N(measure)':>20}")
        print('-------------------------------------------------------------------------------')
        print(f' {0.0:7.3f}    {self._Ekb[0]:+15.9f}    {self._n_classical_params:8}        {self._n_cnot:10}        {self._n_pauli_trm_measures:12}')

        if (self._print_summary_file):
            f = open("summary.dat", "w+", buffering=1)
            f.write(f"#{'beta':>7}{'E(beta)':>18}{'N(params)':>14}{'N(CNOT)':>18}{'N(measure)':>20}\n")
            f.write('#-------------------------------------------------------------------------------\n')
            f.write(f'  {0.0:7.3f}    {self._Ekb[0]:+15.9f}    {self._n_classical_params:8}        {self._n_cnot:10}        {self._n_pauli_trm_measures:12}\n')

        for kb in range(1, self._nbeta):
            self.do_qite_step()
            if(self._do_lanczos):
                if(kb % self._lanczos_gap == 0):
                    self._lanczos_vecs.append(copy.deepcopy(self._qc.get_coeff_vec()))

                    qcSig_temp = qf.Computer(self._nqb)
                    qcSig_temp.set_coeff_vec(copy.deepcopy(self._qc.get_coeff_vec()))
                    qcSig_temp.apply_operator(self._qb_ham)
                    self._Hlanczos_vecs.append(copy.deepcopy(qcSig_temp.get_coeff_vec()))

            print(f' {kb*self._db:7.3f}    {self._Ekb[kb]:+15.9f}    {self._n_classical_params:8}        {self._n_cnot:10}        {self._n_pauli_trm_measures:12}')
            if (self._print_summary_file):
                f.write(f'  {kb*self._db:7.3f}    {self._Ekb[kb]:+15.9f}    {self._n_classical_params:8}        {self._n_cnot:10}        {self._n_pauli_trm_measures:12}\n')
        self._Egs = self._Ekb[-1]

        if (self._print_summary_file):
            f.close()
示例#5
0
    def fill_excited_dets(self):
        for _, sq_op in self._pool_obj:
            # 1. Identify the excitation operator
            # occ => i,j,k,...
            # vir => a,b,c,...
            # sq_op is 1.0(a^ b^ i j) - 1.0(j^ i^ b a)

            temp_idx = sq_op.terms()[0][2][-1]
            # TODO: This code assumes that the first N orbitals are occupied, and the others are virtual.
            # Use some other mechanism to identify the occupied orbitals, so we can use use PQE on excited
            # determinants.
            if temp_idx < int(
                    sum(self._ref) / 2):  # if temp_idx is an occupied idx
                sq_creators = sq_op.terms()[0][1]
                sq_annihilators = sq_op.terms()[0][2]
            else:
                sq_creators = sq_op.terms()[0][2]
                sq_annihilators = sq_op.terms()[0][1]

            # 2. Get the bit representation of the sq_ex_op acting on the reference.
            # We determine the projective condition for this amplitude by zero'ing this residual.

            # `destroyed` exists solely for error catching.
            destroyed = False

            excited_det = qforte.QubitBasis(self._nqb)
            for k, occ in enumerate(self._ref):
                excited_det.set_bit(k, occ)

            # loop over annihilators
            for p in reversed(sq_annihilators):
                if (excited_det.get_bit(p) == 0):
                    destroyed = True
                    break

                excited_det.set_bit(p, 0)

            # then over creators
            for p in reversed(sq_creators):
                if (excited_det.get_bit(p) == 1):
                    destroyed = True
                    break

                excited_det.set_bit(p, 1)

            if destroyed:
                raise ValueError(
                    "no ops should destroy reference, something went wrong!!")

            I = excited_det.add()

            qc_temp = qforte.Computer(self._nqb)
            qc_temp.apply_circuit(self._Uprep)
            qc_temp.apply_operator(sq_op.jw_transform())
            phase_factor = qc_temp.get_coeff_vec()[I]

            self._excited_dets.append((I, phase_factor))
示例#6
0
    def run(self,
            beta=1.0,
            db=0.2,
            expansion_type='SD',
            sparseSb=True,
            b_thresh=1.0e-6,
            x_thresh=1.0e-10,
            do_lanczos=False,
            lanczos_gap=2):

        self._beta = beta
        self._db = db
        self._nbeta = int(beta/db)+1
        self._expansion_type = expansion_type
        self._sparseSb = sparseSb
        self._total_phase = 1.0 + 0.0j
        self._Uqite = qf.Circuit()
        self._b_thresh = b_thresh
        self._x_thresh = x_thresh

        self._n_classical_params = 0
        self._n_cnot = self._Uprep.get_num_cnots()
        self._n_pauli_trm_measures = 0

        self._do_lanczos = do_lanczos
        self._lanczos_gap = lanczos_gap

        qc_ref = qf.Computer(self._nqb)
        qc_ref.apply_circuit(self._Uprep)
        self._Ekb = [np.real(qc_ref.direct_op_exp_val(self._qb_ham))]

        # Print options banner (should done for all algorithms).
        self.print_options_banner()

        # Build expansion pool.
        self.build_expansion_pool()

        # Do the imaginary time evolution.
        self.evolve()

        if (self._do_lanczos):
            self.do_qlanczos()

        # Print summary banner (should done for all algorithms).
        self.print_summary_banner()

        # verify that required attributes were defined
        # (should done for all algorithms).
        self.verify_run()
示例#7
0
    def build_orb_energies(self):
        """Calculates single qubit energies. Used in quasi-Newton updates.
        """
        self._orb_e = []

        print('\nBuilding single particle energies list:')
        print('---------------------------------------', flush=True)
        qc = qf.Computer(self._nqb)
        qc.apply_circuit(build_Uprep(self._ref, 'occupation_list'))
        E0 = qc.direct_op_exp_val(self._qb_ham)

        for i in range(self._nqb):
            qc = qf.Computer(self._nqb)
            qc.apply_circuit(build_Uprep(self._ref, 'occupation_list'))
            qc.apply_gate(qf.gate('X', i, i))
            Ei = qc.direct_op_exp_val(self._qb_ham)

            if(i<sum(self._ref)):
                ei = E0 - Ei
            else:
                ei = Ei - E0

            print(f'  {i:3}     {ei:+16.12f}', flush=True)
            self._orb_e.append(ei)
示例#8
0
    def get_residual_vector(self, trial_amps):
        """Returns the residual vector with elements pertaining to all operators
        in the ansatz circuit.

        Parameters
        ----------
        trial_amps : list of floats
            The list of (real) floating point numbers which will characterize
            the state preparation circuit used in calculation of the residuals.
        """
        if (self._pool_type == 'sa_SD'):
            raise ValueError(
                'Must use single term particle-hole nbody operators for residual calculation'
            )

        U = self.ansatz_circuit(trial_amps)

        qc_res = qforte.Computer(self._nqb)
        qc_res.apply_circuit(self._Uprep)
        qc_res.apply_circuit(U)
        qc_res.apply_operator(self._qb_ham)
        qc_res.apply_circuit(U.adjoint())

        coeffs = qc_res.get_coeff_vec()
        residuals = []

        for I, phase_factor in self._excited_dets:

            # Get the residual element, after accounting for numerical noise.
            res_m = coeffs[I] * phase_factor
            if (np.imag(res_m) != 0.0):
                raise ValueError(
                    "residual has imaginary component, something went wrong!!")

            if (self._noise_factor > 1e-12):
                res_m = np.random.normal(np.real(res_m), self._noise_factor)

            residuals.append(res_m)

        self._res_vec_evals += 1
        self._res_m_evals += len(self._tamps)

        return residuals
示例#9
0
    def build_S(self):
        """Construct the matrix S (eq. 5a) of Motta.
        """
        Idim = self._NI

        S = np.zeros((Idim, Idim), dtype=complex)

        Ipsi_qc = qf.Computer(self._nqb)
        Ipsi_qc.set_coeff_vec(copy.deepcopy(self._qc.get_coeff_vec()))
        # CI[I][J] = (σ_I Ψ)_J
        self._n_pauli_trm_measures += int(self._NI*(self._NI+1)*0.5)
        CI = np.zeros(shape=(Idim, int(2**self._nqb)), dtype=complex)

        for i in range(Idim):
            S[i][i] = 1.0 # With Pauli strings, this is always the inner product
            Ipsi_qc.apply_operator(self._sig.terms()[i][1])
            CI[i,:] = copy.deepcopy(Ipsi_qc.get_coeff_vec())
            for j in range(i):
                S[i][j] = S[j][i] = np.vdot(CI[i,:], CI[j,:])
            Ipsi_qc.set_coeff_vec(copy.deepcopy(self._qc.get_coeff_vec()))

        return np.real(S)
示例#10
0
    def build_b(self):
        """Construct the vector b (eq. 5b) of Motta, with h[m] the full Hamiltonian.
        """

        b  = np.zeros(self._NI, dtype=complex)

        denom = np.sqrt(1 - 2*self._db*self._Ekb[-1])
        prefactor = -1.0j / denom

        self._n_pauli_trm_measures += self._Nl * self._NI

        Hpsi_qc = qf.Computer(self._nqb)
        Hpsi_qc.set_coeff_vec(copy.deepcopy(self._qc.get_coeff_vec()))
        Hpsi_qc.apply_operator(self._qb_ham)
        C_Hpsi_qc = copy.deepcopy(Hpsi_qc.get_coeff_vec())

        for I, (op_coefficient, operator) in enumerate(self._sig.terms()):
            Hpsi_qc.apply_operator(operator)
            exp_val = np.vdot(self._qc.get_coeff_vec(), Hpsi_qc.get_coeff_vec())
            b[I] = prefactor * op_coefficient * exp_val
            Hpsi_qc.set_coeff_vec(copy.deepcopy(C_Hpsi_qc))

        return np.real(b)
示例#11
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
示例#12
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
示例#13
0
    def run(self,
            guess_energy: float,
            t = 1.0,
            nruns = 20,
            success_prob = 0.5,
            num_precise_bits = 4):
        """
        guess_energy : A guess for the eigenvalue of the eigenspace with which |0>^(n)
            has greatest overlap. You should be confident the ground state is within
        t : A scaling parameter that controls the precision of the computation. You should
            confident that the eigenvalue of interest is within +/- t of the guess energy.
        """

        # float: evolution times
        self._t = t
        # int: number of times to sample the eigenvalue distribution
        self._nruns = nruns
        self._success_prob = success_prob
        self._num_precise_bits = num_precise_bits
        self._Uqpe = qforte.Circuit()
        # int: The number of qubits needed to represent the state.
        self._n_state_qubits = self._nqb
        eps = 1 - success_prob
        # int: The number of ancilla qubits used to hold eigenvalue information
        self._n_ancilla = num_precise_bits + int(np.log2(2 + (1.0/eps)))
        # int: The total number of qubits needed in the circuit
        self._n_tot_qubits = self._n_state_qubits + self._n_ancilla
        self._abegin = self._n_state_qubits
        self._aend = self._n_tot_qubits - 1

        self._n_classical_params = 0
        self._n_pauli_trm_measures = nruns

        self._guess_energy = guess_energy
        self._guess_periods = round(self._t * guess_energy / (-2 * np.pi))

        # Print options banner (should done for all algorithms).
        self.print_options_banner()

        ######### QPE ########

        # Apply Hadamard gates to all ancilla qubits
        self._Uqpe.add(self.get_Uhad())

        # Prepare the trial state on the non-ancilla qubits
        self._Uqpe.add(self._Uprep)

        # add controll e^-iHt circuit
        self._Uqpe.add(self.get_dynamics_circ())

        # add reverse QFT
        self._Uqpe.add(self.get_qft_circuit('reverse'))

        computer = qforte.Computer(self._n_tot_qubits)
        computer.apply_circuit(self._Uqpe)

        self._n_cnot = self._Uqpe.get_num_cnots()

        if(self._fast):
            z_readouts = computer.measure_z_readouts_fast(self._abegin, self._aend, self._nruns)
        else:
            Zcirc = self.get_z_circuit()
            z_readouts = computer.measure_readouts(Zcirc, self._nruns)

        self._phases = []
        for readout in z_readouts:
            val = sum(z / (2**i) for i, z in enumerate(readout, start=1))
            self._phases.append(val)

        # find final binary string of phase readouts:
        final_readout = []
        final_readout_aves = []
        for i in range(self._n_ancilla):
            iave = sum(readout[i] for readout in z_readouts) / nruns
            final_readout_aves.append(iave)
            final_readout.append(1 if iave > 0.5 else 0)

        self._final_phase = sum(z / (2**i) for i, z in enumerate(final_readout, start=1))

        E_u = -2 * np.pi * (self._final_phase + self._guess_periods - 1) / t
        E_l = -2 * np.pi * (self._final_phase + self._guess_periods - 0) / t
        E_qpe = E_l if abs(E_l - guess_energy) < abs(E_u - guess_energy) else E_u

        res = stats.mode(np.asarray(self._phases))
        self._mode_phase = res.mode[0]
        E_u = -2 * np.pi * (self._mode_phase + self._guess_periods - 1) / t
        E_l = -2 * np.pi * (self._mode_phase + self._guess_periods - 0) / t
        self._mode_energy = E_l if abs(E_l - guess_energy) < abs(E_u - guess_energy) else E_u

        print('\n           ==> QPE readout averages <==')
        print('------------------------------------------------')
        for i, ave in enumerate(final_readout_aves):
            print('  bit ', i,  ': ', ave)
        print('\n  Final bit readout: ', final_readout)

        ######### QPE ########

        # set Egs
        self._Egs = E_qpe

        # set Umaxdepth
        self._Umaxdepth = self._Uqpe

        # Print summary banner (should done for all algorithms).
        self.print_summary_banner()

        # verify that required attributes were defined
        # (should done for all algorithms).
        self.verify_run()
示例#14
0
    def update_ansatz(self):
        self._n_pauli_measures_k = 0
        # TODO: Check if this deepcopy is needed. The one argument of energy_feval should be const.
        x0 = copy.deepcopy(self._tamps)
        init_gues_energy = self.energy_feval(x0)

        # do U^dag e^iH U |Phi_o> = |Phi_res>
        U = self.ansatz_circuit()

        qc_res = qf.Computer(self._nqb)
        qc_res.apply_circuit(self._Uprep)
        qc_res.apply_circuit(U)
        qc_res.apply_circuit(self._eiH)
        qc_res.apply_circuit(U.adjoint())

        res_coeffs = qc_res.get_coeff_vec()

        # build different res_sq list using M_omega
        if (self._M_omega != 'inf'):
            res_sq_tmp = [
                np.real(np.conj(res_coeffs[I]) * res_coeffs[I])
                for I in range(len(res_coeffs))
            ]

            # Nmu_lst => [ det1, det2, det3, ... det_M_omega]
            det_lst = np.random.choice(len(res_coeffs),
                                       self._M_omega,
                                       p=res_sq_tmp)

            print(f'|Co|dt^2 :       {np.amax(res_sq_tmp):12.14f}')
            print(
                f'mu_o :           {np.where(res_sq_tmp == np.amax(res_sq_tmp))[0][0]}'
            )

            No_idx = np.where(res_sq_tmp == np.amax(res_sq_tmp))[0][0]
            print(f'\nNo_idx   {No_idx:4}')

            No = np.count_nonzero(det_lst == No_idx)
            print(f'\nNo       {No:10}')

            res_sq = []
            Nmu_lst = []
            for mu in range(len(res_coeffs)):
                Nmu = np.count_nonzero(det_lst == mu)
                if (Nmu > 0):
                    print(
                        f'mu:    {mu:8}      Nmu      {Nmu:10}  r_mu: { Nmu / (self._M_omega):12.14f} '
                    )
                    Nmu_lst.append((Nmu, mu))
                res_sq.append((Nmu / (self._M_omega), mu))

            ## 1. sort
            Nmu_lst.sort()
            res_sq.sort()

            ## 2. set norm
            self._curr_res_sq_norm = sum(
                rmu_sq[0] for rmu_sq in res_sq[:-1]) / (self._dt * self._dt)

            ## 3. print stuff
            print('  \n--> Begin selection opt with residual magnitudes:')
            print('  Initial guess energy:          ',
                  round(init_gues_energy, 10))
            print(
                f'  Norm of approximate res vec:  {np.sqrt(self._curr_res_sq_norm):14.12f}'
            )

            ## 4. check conv status (need up update function with if(M_omega != 'inf'))
            if (len(Nmu_lst) == 1):
                print('  SPQE converged with M_omega thresh!')
                self._converged = True
                self._final_energy = self._energies[-1]
                self._final_result = self._results[-1]
            else:
                self._converged = False

            ## 5. add new toperator
            if not self._converged:
                if self._verbose:
                    print('\n')
                    print('     op index (Imu)     Number of times measured')
                    print('  -----------------------------------------------')

                for Nmu_tup in Nmu_lst[:-1]:
                    if (self._verbose):
                        print(
                            f"  {Nmu_tup[1]:10}                  {np.real(Nmu_tup[0]):14}"
                        )
                    if (Nmu_tup[1] not in self._tops):
                        self._tops.insert(0, Nmu_tup[1])
                        self._tamps.insert(0, 0.0)
                        self.add_from_basis_idx(Nmu_tup[1])

                self._n_classical_params_lst.append(len(self._tops))

        else:  # when M_omega == 'inf', proceed with standard SPQE
            res_sq = [(np.real(np.conj(res_coeffs[I]) * res_coeffs[I]), I)
                      for I in range(len(res_coeffs))]
            res_sq.sort()
            self._curr_res_sq_norm = sum(
                rmu_sq[0] for rmu_sq in res_sq[:-1]) / (self._dt * self._dt)

            print(
                '  \n--> Begin selection opt with residual magnitudes |r_mu|:')
            print('  Initial guess energy: ', round(init_gues_energy, 10))
            print(
                f'  Norm of res vec:      {np.sqrt(self._curr_res_sq_norm):14.12f}'
            )

            self.conv_status()

            if not self._converged:
                if self._verbose:
                    print('\n')
                    print('     op index (Imu)           Residual Factor')
                    print('  -----------------------------------------------')
                res_sq_sum = 0.0

                if (self._use_cumulative_thresh):
                    # Make a running list of operators. When the sum of res_sq exceeds the target, every operator
                    # from here out is getting added to the ansatz..
                    temp_ops = []
                    for rmu_sq, op_idx in res_sq[:-1]:
                        res_sq_sum += rmu_sq / (self._dt * self._dt)
                        if res_sq_sum > (self._spqe_thresh *
                                         self._spqe_thresh):
                            if (self._verbose):
                                Ktemp = self.get_op_from_basis_idx(op_idx)
                                print(
                                    f"  {op_idx:10}                  {np.real(rmu_sq)/(self._dt * self._dt):14.12f}   {Ktemp.str()}"
                                )
                            if op_idx not in self._tops:
                                temp_ops.append(op_idx)
                                self.add_from_basis_idx(op_idx)

                    for temp_op in temp_ops[::-1]:
                        self._tops.insert(0, temp_op)
                        self._tamps.insert(0, 0.0)

                else:
                    # Add the single operator with greatest rmu_sq not yet in the ansatz
                    res_sq.reverse()
                    for rmu_sq, op_idx in res_sq[1:]:
                        print(
                            f"  {op_idx:10}                  {np.real(rmu_sq)/(self._dt * self._dt):14.12f}"
                        )
                        if op_idx not in self._tops:
                            print('Adding this operator to ansatz')
                            self._tops.insert(0, op_idx)
                            self._tamps.insert(0, 0.0)
                            self.add_from_basis_idx(op_idx)
                            break

                self._n_classical_params_lst.append(len(self._tops))
示例#15
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