Source code for qubiter.SEO_Lista

from qubiter.EchoingSEO_reader import *
# from PlaceholderManager import *
from io import StringIO
from qubiter.SEO_simulator import *
import os
import tempfile


[docs]class SEO_Lista: """ Whereas with Qubiter, the main way of storing circuits is **in files**, with programs like PyQuil (by Rigetti) and Cirq (by Google), circuits ( aka programs) are stored **entirely in memory**, essentially as Python lists of gates. Lists of this type can be sliced, combined, etc. When using such lists, it is easy to randomly access any gate of the circuit at will. This is convenient, for instance, when doing circuit optimizations (i.e., replacing the circuit by an equivalent but hopefully shorter one, what IBM qiskit calls "transpiling"). In this class, we support Qubiter's version of PyQuil's and Cirq's gate lists. In Qubiter, we use simply a Python list of the lines, stored as strings, with the ending ```\\n``` removed, of the circuit's English file. Attributes ---------- line_list : list[str] num_qbits : int """
[docs] def __init__(self, num_qbits, line_list=None): """ Constructor Returns ------- """ self.num_qbits = num_qbits self.line_list = line_list if not line_list: self.line_list = []
[docs] def append(self, fun_name, param_list, emb=None): """ This method adds at the end of self a new single line for a single gate. fun_name is the name of any function in SEO_writer whose name starts with the string 'write_' and param_list is a list containing values for the arguments of fun_name. This method creates an object of SEO_writer called `wr` and calls eval('wr.' + fun_name + '(*param_list)'). Instead of creating temporary English and Picture files as was done in a previous version of this function, wr now writes into in-streams which are StringIO that live purely in memory. This is much more efficient because it involves no files at any time. Parameters ---------- fun_name : str param_list : list emb : CktEmbedder Returns ------- """ assert fun_name[:6] == 'write_' file_prefix = 'tempo970361432226978' if emb: emb1 = emb else: emb1 = CktEmbedder(self.num_qbits, self.num_qbits) eng_out = StringIO() pic_out = StringIO() wr = SEO_writer(file_prefix, emb1, english_out=eng_out, picture_out=pic_out) eval('wr.' + fun_name + '(*param_list)') line = eng_out.getvalue().strip('\n') eng_out.close() pic_out.close() self.line_list.append(line)
[docs] def add_xy_meas_coda(self, bit_pos_to_xy_str): """ This method adds a "coda" (tail ending) to self using data in bit_pos_to_xy_str to determine what coda will be. Parameters ---------- bit_pos_to_xy_str : dict[int, str] Returns ------- None """ for bit_pos, xy_str in bit_pos_to_xy_str.items(): if xy_str == 'X': # exp(-i*sigy*pi/4)*sigz*exp(i*sigy*pi/4) = sigx self.append('write_Ry', [bit_pos, np.pi/4]) elif xy_str == 'Y': # exp(i*sigx*pi/4)*sigz*exp(-i*sigx*pi/4) = sigy self.append('write_Rx', [bit_pos, -np.pi/4]) else: assert False, "Unsupported qbit measurement. '" + \ xy_str + "' Should be either 'X' or 'Y'"
[docs] @staticmethod def eng_file_to_line_list(file_prefix, num_qbits): """ This static method reads an English file with file prefix `file_prefix` and it returns a list of its line strings. Note that the ```\\n``` at the end of each line in the English file is removed before adding it to the line list. Parameters ---------- file_prefix : str num_qbits : int Returns ------- list[str] """ path = file_prefix + '_' + str(num_qbits) + '_eng.txt' with open(utg.preface(path), 'r') as f: line_list = [line.rstrip('\n') for line in f] return line_list
[docs] @staticmethod def line_list_to_eng_and_pic_files(line_list, file_prefix, num_qbits): """ This method does the reverse of eng_file_to_line_list(). It writes both an English file and a Picture file with file prefix=file_prefix. Note that an ```\\n``` is added at the end of each line in the line list before writing the line to the English file. Parameters ---------- line_list : list[str] file_prefix : str num_qbits : int Returns ------- None """ end_str = '_' + str(num_qbits) + '_eng.txt' with open(utg.preface(file_prefix + end_str), 'w') as f: for line in line_list: f.write(line + '\n') # this writes a Picture file from the English file just created EchoingSEO_reader.pic_file_from_eng_file(file_prefix, num_qbits)
[docs] def write_eng_and_pic_files(self, file_prefix): """ This method does the same as line_list_to_eng_and_pic_files(), except it is called by an object of this class instead of being a static method. Parameters ---------- file_prefix : str Returns ------- None """ SEO_Lista.line_list_to_eng_and_pic_files( self.line_list, file_prefix, self.num_qbits)
[docs] def simulate(self, **kwargs1): """ This method creates a temporary English file from self, and uses that to create an object of SEO_simulator called sim. This has the effect of evolving the state vector to its final state. The method ends by deleting the temporary English file, and returning sim. The output sim can be used to access the final state vector, etc. Parameters ---------- kwargs1 : list key-word arguments of SEO_simulator Returns ------- SEO_simulator """ file_prefix = '610935122304' end_str = '_' + str(self.num_qbits) + '_eng.txt' fname = file_prefix + end_str with open(utg.preface(fname), 'w') as f: for line in self.line_list: f.write(line + '\n') sim = SEO_simulator(file_prefix, self.num_qbits, **kwargs1) os.remove(utg.preface(fname)) return sim
# this doesn't work, maybe because temp file opened twice # file_prefix = '610935122304' # end_str = '_' + str(self.num_qbits) + '_eng.txt' # fname = file_prefix + end_str # fi = tempfile.NamedTemporaryFile(mode='w+b', # prefix=file_prefix, # suffix=end_str, # dir=utg.preface('x')[:-2], # delete=True) # for line in self.line_list: # fi.write(line + '\n') # # sim opens file by name # sim = SEO_simulator(file_prefix, self.num_qbits, **kwargs1) # # sim closes file # return sim
[docs] def print(self): """ Prints self.line_list, one item per line. Returns ------- None """ print('\n'.join(self.line_list))
[docs] def get_var_nums_and_fun_names(self): """ This method returns 2 lists: * a list of all the distinct variable numbers * a list of all the distinct function names encountered in the circuit. Returns ------- list[int], list[str] """ var_nums = [] fun_names = [] for line in self.line_list: split_line = line.split() for token in split_line: if PlaceholderManager.is_legal_var_name(token): token_var_nums = \ PlaceholderManager.get_leg_var_var_nums(token) fun_name = PlaceholderManager.get_leg_var_fun_name(token) for var_num in token_var_nums: if var_num not in var_nums: var_nums.append(var_num) if fun_name and fun_name not in fun_names: fun_names.append(fun_name) return var_nums, fun_names
[docs] def __add__(self, other): """ Define + of two SEO_Lista objects. Parameters ---------- other : SEO_Lista Returns ------- SEO_Lista """ assert self.num_qbits == other.num_qbits return SEO_Lista(self.num_qbits, self.line_list + other.line_list)
[docs] def __iadd__(self, other): """ Define += for inplace addition of an SEO_Lista object to self. Parameters ---------- other : SEO_Lista Returns ------- SEO_Lista """ assert self.num_qbits == other.num_qbits self.line_list += other.line_list return self
[docs] def __getitem__(self, item): """ Define self[item]. Parameters ---------- item : slice Returns ------- SEO_Lista """ return SEO_Lista(self.num_qbits, self.line_list[item])
[docs] def herm(self): """ This method returns an EngLineList which is the Hermitian conjugate of self. Returns ------- SEO_Lista """ rev_li = list(reversed(self.line_list)) lista = SEO_Lista(self.num_qbits, rev_li) def minus(in_str): if in_str[0] == '-': new_str = in_str[1:] else: new_str = '-' + in_str return new_str for line_pos, line in enumerate(lista.line_list): split_line = line.split('\t') line_name = split_line[0] if line_name == 'DIAG': by_pos = split_line.index('BY') for k, token in enumerate(line[by_pos+1:]): line[by_pos+1+k] = minus(token) elif line_name == "HAD2": pass elif line_name == "IF_M(": pass elif line_name == "}IF_M": pass elif line_name == "LOOP": pass elif line_name == "MEAS": pass elif line_name == "MP_Y": by_pos = split_line.index('BY') for k, token in enumerate(line[by_pos+1:]): line[by_pos+1+k] = minus(token) elif line_name == "NEXT": pass elif line_name == 'NOTA': pass elif line_name == "PHAS": split_line[1] = minus(split_line[1]) elif line_name == "P0PH": split_line[1] = minus(split_line[1]) elif line_name == "P1PH": split_line[1] = minus(split_line[1]) elif line_name == "PRINT": pass elif line_name == "ROTX": split_line[1] = minus(split_line[1]) elif line_name == "ROTY": split_line[1] = minus(split_line[1]) elif line_name == "ROTZ": split_line[1] = minus(split_line[1]) elif line_name == "ROTN": for k in range(1, 4): split_line[k] = minus(split_line[k]) elif line_name == "SIGX": pass elif line_name == "SIGY": pass elif line_name == "SIGZ": pass elif line_name == "SWAP": pass elif line_name == "SWAY": for k in range(4, 6): split_line[k] = minus(split_line[k]) elif line_name == "U_2_": for k in range(1, 5): split_line[k] = minus(split_line[k]) else: assert False, \ "reading an unsupported line kind: " + line_name lista.line_list[line_pos] = '\t'.join(split_line) return lista
if __name__ == "__main__": def main(): num_qbits = 4 file_prefix = 'eng_file_line_list_test' emb = CktEmbedder(num_qbits, num_qbits) wr = SEO_writer(file_prefix, emb) wr.write_Rx(2, rads=np.pi/7) wr.write_Rx(1, rads='#2*.5') wr.write_Rx(1, rads='my_fun1#2') wr.write_Rn(3, rads_list=['#1', '-#1*3', '#3']) wr.write_Rx(1, rads='-my_fun2#2#1') wr.write_cnot(2, 3) wr.close_files() lili = SEO_Lista.eng_file_to_line_list(file_prefix, num_qbits) lista = SEO_Lista(num_qbits, lili) print("\nlista print") lista.print() nums, names = lista.get_var_nums_and_fun_names() print("lista's all_var_nums=\n", nums) print("lista's all_fun_names=\n", names) lista.write_eng_and_pic_files(file_prefix + '_ditto') print("\nlista[1:] print") lista[1:].print() lista_twice = lista + lista print("\nlista_twice print") lista_twice.print() nums, names = lista_twice.get_var_nums_and_fun_names() print("lista_twice's all_var_nums=\n", nums) print("lista_twice's all_fun_names=\n", names) lista_0 = SEO_Lista(num_qbits) lista_0 += lista print("\nlista_0 print") lista_0.print() lista_herm = lista.herm() print('\nlista_herm print') lista_herm.print() lista = SEO_Lista(4) lista.append('write_cnot', [0, 1]) lista.append('write_Rn', [2, [np.pi / 2, -np.pi / 2, np.pi / 3]]) print('\n print 2 line lista') lista.print() sim = lista.simulate() sim.describe_st_vec_dict() lista.add_xy_meas_coda({0: 'X', 1: 'Y'}) lista.print() main()