Source code for qubiter.adv_applications.StairsDeriv_rigetti

from qubiter.adv_applications.StairsDeriv import *
from qubiter.adv_applications.MeanHamil import *
from qubiter.device_specific.Qubiter_to_RigettiPyQuil import *
from qubiter.device_specific.RigettiTools import *
import qubiter.utilities_gen as utg
from qubiter.CGateExpander import *

import itertools as it
import copy as cp

from openfermion.ops import QubitOperator

from pyquil.quil import Program
from pyquil.api import QVMConnection
from pyquil.gates import *
from pyquil import get_qc
from pyquil.api import WavefunctionSimulator
# from pyquil.reference_simulator import ReferenceWavefunctionSimulator


[docs]class StairsDeriv_rigetti(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 Rigetti Pyquil simulators or their physical qc device. Attributes ---------- qc : QuantumComputer returned by PyQuil method get_qc() translation_line_list : list[str] a list of lines of PyQuil code generated by the translator. The lines all start with "pg +=". translator : Qubiter_to_RigettiPyQuil """
[docs] def __init__(self, qc, deriv_gate_str, gate_str_to_rads_list, file_prefix, parent_num_qbits, hamil, **kwargs): """ Constructor Parameters ---------- qc : QuantumComputer 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) self.qc = qc self.translator = None self.translation_line_list = []
[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) wr.close_files() # wr.print_pic_file() # wr.print_eng_file() 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) vman = PlaceholderManager( var_num_to_rads=var_num_to_rads, fun_name_to_fun=fun_name_to_fun) # CGateExpander and the translator Qubiter_to_RigettiPyQuil # are both children of SEO_reader. SEO_reader and any of its # subclasses will accept a vman ( object of # PlaceholderManager) in one of its keyword args. If a # SEO_reader is given a vman as input, it will use it to # replace placeholder variable strings by floats. # PyQuil does not support multi-controlled u2 gates so # expand them to lowest common denominator, CNOTs and single # qubit gates, using CGateExpander. Give CGateExpander a # vman input so as to float all variables before expansion expan = CGateExpander(self.file_prefix, num_qbits_w_anc, vars_manager=vman) # this gives name of new file with expansion out_file_prefix = SEO_reader.xed_file_prefix(self.file_prefix) # expan.wr.print_pic_file() # expan.wr.print_eng_file() # this creates a file with all PyQuil gates that are # independent of hamil. self.translator = Qubiter_to_RigettiPyQuil( out_file_prefix, self.num_qbits, aqasm_name='RigPyQuil', prelude_str='', ending_str='') with open(utg.preface(self.translator.aqasm_path), 'r') as fi: self.translation_line_list = fi.readlines() pg = Program() for line in self.translation_line_list: line = line.strip('\n') if line: exec(line) len_pg_in = len(pg) 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. # Remember bug in Pyquil. Slicing a program turns it into # a list pg = Program(pg[:len_pg_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'} RigettiTools.add_xy_meas_coda_to_program( pg, bit_pos_to_xy_str) # get effective state vec if self.num_samples: # send and receive from cloud, get obs_vec bitstrings = self.qc.run_and_measure(pg, trials=self.num_samples) obs_vec = RigettiTools.obs_vec_from_bitstrings( bitstrings, self.num_qbits, bs_is_array=False) # go from obs_vec to effective state vec counts_dict = StateVec.get_counts_from_obs_vec( self.num_qbits, obs_vec) emp_pd = StateVec.get_empirical_pd_from_counts( self.num_qbits, counts_dict) effective_st_vec = StateVec.\ get_emp_state_vec_from_emp_pd( self.num_qbits, emp_pd) else: # num_samples = 0 sim = WavefunctionSimulator() st_vec_arr = sim.wavefunction(pg).amplitudes st_vec_arr = st_vec_arr.reshape([2]*self.num_qbits) perm = list(reversed(range(self.num_qbits))) st_vec_arr = np.transpose(st_vec_arr, perm) effective_st_vec = StateVec(self.num_qbits, st_vec_arr) # 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(): print(5) main()