from qubiter.CGateSEO_writer import *
from qubiter.SEO_reader import *
[docs]class CGateExpander(SEO_reader):
"""
Qubiter English and Picture files allow single lines that represent U(2)
matrices of numerous types with 0, 1 or multiple controls of either the
n or nbar kind. If we say a gate is controlled, it may have 1 or more
controls (it might be singly or multiply controlled). This class is a
child of SEO_reader. The class reads any previously created Qubiter
English file and it writes new English & Picture files wherein every
line of the original English file is expanded into a sequence of (1)
single qubit rotations and (2) simple CNOTs. Such a class is useful
because many quantum computers (for example, IBM Quantum Experience) can
only do (1) and (2).
If the input English file has file_prefix as file prefix, then the
output English & Picture files have as file prefix file_prefix + '_X1',
assuming that '_X' + str(k) for some integer k is not already the ending
of file_prefix. If it is, then the ending is changed to '_X' + str(
k+1).
Global phase factors are ignored, so expansions equal the original line
up to a phase factor.
You can get a count of the number of CNOTs in the expanded file by
creating an object of the class SEO_reader.
Attributes
----------
wr : CGateSEO_writer
This object of CGateSEO_writer, created in the class constructor,
is called inside every use_ function to do some writing in the output
files.
"""
[docs] def __init__(self, file_prefix, num_qbits, **kwargs):
"""
Constructor
Parameters
----------
file_prefix : str
num_qbits : int
Returns
-------
"""
# temporary embedder
emb = CktEmbedder(num_qbits, num_qbits)
out_file_prefix = SEO_reader.xed_file_prefix(file_prefix)
self.wr = CGateSEO_writer(out_file_prefix, emb,
one_line=False, expand_1c_u2=True)
SEO_reader.__init__(self, file_prefix, num_qbits, **kwargs)
self.wr.close_files()
[docs] def two_embs_for_c_qbit_swap(self, bit1, bit2, controls):
"""
This internal function returns two CktEmbedder objects called emb0,
emb1 that are used to write an expansion for a controlled swap of
bits bit1, bit2.
Parameters
----------
bit1 : int
bit2 : int
controls : Controls
Returns
-------
(CktEmbedder, CktEmbedder)
"""
num_trols = len(controls.kinds)
num_qbits_bef = num_trols + 2
num_qbits_aft = self.num_qbits
bit_map0 = [0]*num_qbits_bef
for k in range(num_trols):
bit_map0[k] = controls.bit_pos[num_trols-k-1]
bit_map0[-2] = bit2
bit_map0[-1] = bit1
bit_map1 = bit_map0.copy()
bit_map1[-2] = bit1
bit_map1[-1] = bit2
emb0 = CktEmbedder(num_qbits_bef, num_qbits_aft, bit_map0)
emb1 = CktEmbedder(num_qbits_bef, num_qbits_aft, bit_map1)
return emb0, emb1
[docs] def emb_for_c_u2(self, tar_bit_pos, controls):
"""
This internal function returns a CktEmbedder object called emb that
is used to write an expansion for a controlled U(2) matrix with
target at tar_bit_pos.
Parameters
----------
tar_bit_pos : int
controls : Controls
Returns
-------
CktEmbedder
"""
num_trols = len(controls.kinds)
num_qbits_bef = num_trols + 1
num_qbits_aft = self.num_qbits
bit_map = [0]*num_qbits_bef
for k in range(num_trols):
bit_map[k] = controls.bit_pos[num_trols-k-1]
bit_map[-1] = tar_bit_pos
emb = CktEmbedder(num_qbits_bef, num_qbits_aft, bit_map)
return emb
[docs] def write_gate_name(self, name, num_trols):
"""
This function is used solely in the verbose mode. It announces with
a NOTA comment line the beginning of a gate expansion.
Parameters
----------
name : str
num_trols : int
Returns
-------
None
"""
skip0 = num_trols == 0 and not name == "SWAP"
skip1 = num_trols == 1 and name == "SIGX"
if skip0 or skip1:
pass
else:
if self.verbose:
self.wr.write_NOTA('--------expansion of ' + name)
[docs] def use_DIAG(self, trols, rad_angles):
"""
Returns error message if input circuit contains diagonal unitaries
DIAG.
Parameters
----------
trols : Controls
rad_angles : list[float]
Returns
-------
"""
assert False, "This circuit contains diagonal unitaries DIAG." \
"You should expand them first using class DiagUnitaryExpander"
[docs] def use_HAD2(self, tar_bit_pos, controls):
"""
This function expands a HAD2 line; i.e., it reads the line from the
input English file and writes an expansion of it in the output
English & Picture files.
Parameters
----------
tar_bit_pos : int
controls : Controls
Returns
-------
None
"""
self.write_gate_name("HAD2", len(controls.kinds))
self.wr.emb = self.emb_for_c_u2(tar_bit_pos, controls)
self.wr.write(controls.kinds,
OneQubitGate.had2)
[docs] def use_IF_M_beg(self, controls):
"""
This function echoes IF_M_beg line.
Parameters
----------
controls : Controls
Returns
-------
None
"""
self.wr.write_IF_M_beg(controls)
[docs] def use_IF_M_end(self):
"""
This function echoes IF_M_end line
Parameters
----------
Returns
-------
None
"""
self.wr.write_IF_M_end()
[docs] def use_LOOP(self, loop_num, nreps):
"""
This function echoes a LOOP line; i.e., it transcribes the line from
the input English file to the output English & Picture files.
Parameters
----------
loop_num : int
nreps : int
Returns
-------
None
"""
self.wr.write_LOOP(loop_num, nreps)
[docs] def use_MEAS(self, tar_bit_pos, kind):
"""
This function echoes a MEAS line; i.e., it transcribes the line from
the input English file to the output English & Picture files.
Parameters
----------
kind : int
tar_bit_pos : int
Returns
-------
None
"""
self.wr.emb = CktEmbedder(self.num_qbits, self.num_qbits)
# print("----", tar_bit_pos, self.wr.emb.bit_map)
self.wr.write_MEAS(tar_bit_pos, kind)
[docs] def use_MP_Y(self, tar_bit_pos, trols, rad_angles):
"""
Returns error message if input circuit contains multiplexors MP_Y.
Parameters
----------
tar_bit_pos : int
trols : Controls
rad_angles : list[float]
Returns
-------
"""
assert False, "This circuit contains multiplexors." \
"You should expand them first using class MultiplexorExpander"
[docs] def use_NEXT(self, loop_num):
"""
This function echoes a NEXT line; i.e., it transcribes the line from
the input English file to the output English & Picture files.
Parameters
----------
loop_num : int
Returns
-------
None
"""
self.wr.write_NEXT(loop_num)
[docs] def use_NOTA(self, bla_str):
"""
This function echoes a NOTA line; i.e., it transcribes the line from
the input English file to the output English & Picture files.
Parameters
----------
bla_str : str
Returns
-------
None
"""
self.wr.write_NOTA(bla_str)
[docs] def use_PHAS(self, angle_rads, tar_bit_pos, controls):
"""
This function expands a PHAS line; i.e., it reads the line from the
input English file and writes an expansion of it in the output
English & Picture files.
Parameters
----------
angle_rads : float
tar_bit_pos : int
controls : Controls
Returns
-------
None
"""
self.write_gate_name("PHAS", len(controls.kinds))
self.wr.emb = self.emb_for_c_u2(tar_bit_pos, controls)
self.wr.write(controls.kinds,
OneQubitGate.phase_fac, [angle_rads])
[docs] def use_P_PH(self, projection_bit, angle_rads, tar_bit_pos, controls):
"""
This function expands a P0PH or P1PH line; i.e., it reads the line
from the input English file and writes an expansion of it in the
output English & Picture files.
Parameters
----------
projection_bit : int
angle_rads : float
tar_bit_pos : int
controls : Controls
Returns
-------
None
"""
name = ''
if projection_bit == 0:
u2_fun = OneQubitGate.P_0_phase_fac
name = 'P0PH'
elif projection_bit == 1:
u2_fun = OneQubitGate.P_1_phase_fac
name = 'P1PH'
else:
assert False
self.write_gate_name(name, len(controls.kinds))
self.wr.emb = self.emb_for_c_u2(tar_bit_pos, controls)
self.wr.write(controls.kinds, u2_fun, [angle_rads])
[docs] def use_PRINT(self, style, line_num):
"""
This function echoes a PRINT line; i.e., it transcribes the line
from the input English file to the output English & Picture files.
Parameters
----------
style : str
line_num : int
Returns
-------
None
"""
self.wr.write_PRINT(style)
[docs] def use_ROTA(self, axis, angle_rads, tar_bit_pos, controls):
"""
This function expands a ROTX, ROTY or ROTZ line; i.e., it reads the
line from the input English file and writes an expansion of it in
the output English & Picture files.
Parameters
----------
axis : int
angle_rads : float
tar_bit_pos : int
controls : Controls
Returns
-------
None
"""
name = ''
if axis == 1:
name = 'ROTX'
elif axis == 2:
name = 'ROTY'
elif axis == 3:
name = 'ROTZ'
else:
assert False
self.write_gate_name(name, len(controls.kinds))
self.wr.emb = self.emb_for_c_u2(tar_bit_pos, controls)
self.wr.write(controls.kinds,
OneQubitGate.rot_ax, [angle_rads, axis])
[docs] def use_ROTN(self, angle_x_rads, angle_y_rads, angle_z_rads,
tar_bit_pos, controls):
"""
This function expands a ROTN line; i.e., it reads the line from the
input English file and writes an expansion of it in the output
English & Picture files.
Parameters
----------
angle_x_rads : float
angle_y_rads : float
angle_z_rads : float
tar_bit_pos : int
controls : Controls
Returns
-------
None
"""
self.write_gate_name("ROTN", len(controls.kinds))
self.wr.emb = self.emb_for_c_u2(tar_bit_pos, controls)
rad_ang_list = [angle_x_rads, angle_y_rads, angle_z_rads]
self.wr.write(controls.kinds,
OneQubitGate.rot,
rad_ang_list)
[docs] def use_SIG(self, axis, tar_bit_pos, controls):
"""
This function expands a SIGX, SIGY or SIGZ line; i.e., it reads the
line from the input English file and writes an expansion of it in
the output English & Picture files.
Parameters
----------
axis : int
tar_bit_pos : int
controls : Controls
Returns
-------
None
"""
name = ''
if axis == 1:
u2_fun = OneQubitGate.sigx
name = 'SIGX'
elif axis == 2:
u2_fun = OneQubitGate.sigy
name = 'SIGY'
elif axis == 3:
u2_fun = OneQubitGate.sigz
name = 'SIGZ'
else:
assert False
self.write_gate_name(name, len(controls.kinds))
self.wr.emb = self.emb_for_c_u2(tar_bit_pos, controls)
self.wr.write(controls.kinds, u2_fun)
[docs] def use_SWA_(self, bit1, bit2, controls, rads_list=None):
"""
This internal function expands a SWAP or SWAY line; i.e., it reads
the line from the input English file and writes an expansion of it
in the output English & Picture files.
Parameters
----------
bit1 : int
bit2 : int
controls : Controls
rads_list : list[float]
list of 4 floats
Returns
-------
None
"""
use_sway = False
if rads_list is not None:
assert len(rads_list) == 2
use_sway = True
self.write_gate_name("SWAP" if not use_sway else 'SWAY',
len(controls.kinds))
emb0, emb1 = self.two_embs_for_c_qbit_swap(bit1, bit2, controls)
num_trols = len(controls.kinds)
self.wr.emb = emb0 # intialize emb
# insert opening Hadamards for controls equal to n_bar = |0><0|
self.wr.write_hads(controls.kinds)
self.wr.write([True] * (num_trols + 1), OneQubitGate.sigx)
self.wr.emb = emb1 # change emb
if not use_sway:
self.wr.write([True] * (num_trols + 1),
OneQubitGate.sigx)
else:
rads0, rads1 = rads_list
self.wr.write([True] * (num_trols + 1),
OneQubitGate.u2, [rads0, rads1, 0.0, 0.0])
self.wr.emb = emb0 # restore emb
self.wr.write([True] * (num_trols + 1), OneQubitGate.sigx)
# insert closing Hadamards for controls equal to n_bar = |0><0|
self.wr.write_hads(controls.kinds, herm_conj=True)
[docs] def use_SWAP(self, bit1, bit2, controls):
"""
This function expands a SWAP; i.e., it reads the line from the input
English file and writes an expansion of it in the output English &
Picture files.
Parameters
----------
bit1 : int
bit2 : int
controls : Controls
Returns
-------
None
"""
self.use_SWA_(bit1, bit2, controls)
[docs] def use_SWAY(self, bit1, bit2, controls, rads_list):
"""
This function expands a SWAY line; i.e., it reads the line from the
input English file and writes an expansion of it in the output
English & Picture files.
Parameters
----------
bit1 : int
bit2 : int
controls : Controls
rads_list : list[float]
Returns
-------
None
"""
self.use_SWA_(bit1, bit2, controls, rads_list)
[docs] def use_U_2_(self, rads0, rads1, rads2, rads3,
tar_bit_pos, controls):
"""
This function expands a U_2_ line; i.e., it reads the line from the
input English file and writes an expansion of it in the output
English & Picture files.
Parameters
----------
rads0 : float
rads1 : float
rads2 : float
rads3 : float
tar_bit_pos : int
controls : Controls
Returns
-------
None
"""
self.write_gate_name("U_2_", len(controls.kinds))
self.wr.emb = self.emb_for_c_u2(tar_bit_pos, controls)
rad_ang_list = [rads0, rads1, rads2, rads3]
self.wr.write(controls.kinds,
OneQubitGate.u2,
rad_ang_list)
[docs] def do_log(self):
"""
This class does a "flat" reading of the input file; i.e.,
the reading does not respect loop structure. Hence, we won't let it
write a log file, for if we did, it would be incorrect. A correct
log file can always be obtained by creating a SEO_reader object.
Returns
-------
None
"""
pass
if __name__ == "__main__":
def main():
xer = CGateExpander('fou_test', 6, verbose=True)
xer = CGateExpander('fou_test_X1', 6, verbose=True)
xer = CGateExpander('ph_est_test', 8, verbose=True)
xer = CGateExpander('sim_test2', 4, verbose=True)
# write log file for sim_test2
SEO_reader('sim_test2', 4, write_log=True)
xer = CGateExpander('sim_test3', 4, verbose=True)
main()