Source code for qubiter.adv_applications.StairsDeriv_native

from qubiter.adv_applications.StairsDeriv import *
from qubiter.SEO_Lista import *
import itertools as it


[docs]class StairsDeriv_native(StairsDeriv): """ This class is a child of StairsDeriv. Its main purpose is to override the method get_mean_val() of its abstract parent class StairsDeriv. In this class, the simulation necessary to evaluate the output of get_mean_val() is done by native, Qubiter simulators. Attributes ---------- """
[docs] def __init__(self, deriv_gate_str, gate_str_to_rads_list, file_prefix, parent_num_qbits, hamil, **kwargs): """ Constructor Parameters ---------- deriv_gate_str : str gate_str_to_rads_list : dict[str, list[float|str]] file_prefix : str parent_num_qbits : int hamil : QubitOperator kwargs : dict key-word arguments of MeanHamil Returns ------- """ StairsDeriv.__init__(self, deriv_gate_str, gate_str_to_rads_list, file_prefix, parent_num_qbits, hamil, **kwargs)
[docs] def get_mean_val(self, var_num_to_rads): """ This method returns a list partials_list consisting of 4 floats which are the partial derivatives wrt the 4 possible derivative directions ( deriv_direc), of the multi-controlled gate U specified by self.deriv_gate_str. Parameters ---------- var_num_to_rads : dict[int, float] Returns ------- list[float] """ partials_list = [0., 0., 0., 0.] # number of bits with (i.e., including) ancilla num_qbits_w_anc = self.num_qbits for has_neg_polarity, deriv_direc in it.product( *[[False, True], range(4)]): if self.deriv_gate_str == 'prior': if has_neg_polarity: has_neg_polarity = None else: continue # this skips iteration in loop for dpart_name in StairsDeriv.dpart_dict[deriv_direc]: emb = CktEmbedder(num_qbits_w_anc, num_qbits_w_anc) wr = StairsDerivCkt_writer(self.deriv_gate_str, has_neg_polarity, deriv_direc, dpart_name, self.gate_str_to_rads_list, self.file_prefix, emb) t_list = self.gate_str_to_rads_list[self.deriv_gate_str] coef_of_dpart = StairsDerivCkt_writer.\ get_coef_of_dpart(t_list, deriv_direc, dpart_name, var_num_to_rads) fun_name_to_fun = StairsDerivCkt_writer.\ get_fun_name_to_fun(t_list, deriv_direc, dpart_name) lili = SEO_Lista.eng_file_to_line_list(wr.file_prefix, num_qbits_w_anc) lista = SEO_Lista(num_qbits_w_anc, line_list=lili) len_lista_in = len(lista.line_list) for term, coef in self.hamil.terms.items(): # we have checked before that coef is real coef = complex(coef).real # print('nnnnnbbbbb', term) new_term = tuple(list(term) + [(num_qbits_w_anc-1, 'X')]) # print('jjjjjjj', new_term) # throw out previous coda lista = lista[:len_lista_in] # add measurement coda for this term of hamil # and for X at ancilla bit_pos_to_xy_str =\ {bit: action for bit, action in new_term if action != 'Z'} lista.add_xy_meas_coda(bit_pos_to_xy_str) # run simulation. get fin state vec vman = PlaceholderManager( var_num_to_rads=var_num_to_rads, fun_name_to_fun=fun_name_to_fun) # simulator will change init_st_vec so use # fresh copy of it each time init_st_vec = cp.deepcopy(self.init_st_vec) sim = lista.simulate(init_st_vec=init_st_vec, vars_manager=vman) fin_st_vec = sim.cur_st_vec_dict['pure'] # get effective state vec if self.num_samples: # if num_samples !=0, then # sample qubiter-generated empirical prob dist pd = fin_st_vec.get_pd() obs_vec = StateVec.get_observations_vec( num_qbits_w_anc, pd, self.num_samples) counts_dict = StateVec.get_counts_from_obs_vec( num_qbits_w_anc, obs_vec) emp_pd = StateVec.get_empirical_pd_from_counts( num_qbits_w_anc, counts_dict) # print('mmmmmmmm,,,', np.linalg.norm(pd-emp_pd)) emp_st_vec = StateVec.\ get_emp_state_vec_from_emp_pd(num_qbits_w_anc, emp_pd) effective_st_vec = emp_st_vec else: # num_samples = 0 effective_st_vec = fin_st_vec # add contribution to mean real_arr = self.get_real_vec(new_term) mean_val_change = coef*effective_st_vec.\ get_mean_value_of_real_diag_mat(real_arr) mean_val_change *= coef_of_dpart if has_neg_polarity: mean_val_change *= -1 partials_list[deriv_direc] += mean_val_change return partials_list
if __name__ == "__main__": def main(): num_qbits = 4 parent_num_qbits = num_qbits - 1 # one bit for ancilla # u2_bit_to_higher_bits = None u2_bit_to_higher_bits = {0: [2], 1: [2], 2: []} gate_str_to_rads_list = StairsCkt_writer.\ get_gate_str_to_rads_list(parent_num_qbits, '#int', rads_const=np.pi/2, u2_bit_to_higher_bits=u2_bit_to_higher_bits) pp.pprint(gate_str_to_rads_list) deriv_gate_str = list(gate_str_to_rads_list.keys())[2] file_prefix = 'stairs_deriv_native_test' hamil = QubitOperator('X1 Y0 X1 Y1', .4) +\ QubitOperator('Y2 X1', .7) der = StairsDeriv_native(deriv_gate_str, gate_str_to_rads_list, file_prefix, parent_num_qbits, hamil) var_num_to_rads = StairsCkt_writer.get_var_num_to_rads( gate_str_to_rads_list, 'const', rads_const=np.pi/2) partials_list = der.get_mean_val(var_num_to_rads) print('partials_list=', partials_list) main()