QNLP  v1.0
CircuitPrinter.circuit_printer.CircuitPrinter Class Reference
Collaboration diagram for CircuitPrinter.circuit_printer.CircuitPrinter:
Collaboration graph

Public Member Functions

def __init__ (self, num_qubits)
 
def ncu_cct_depth (self, num_ctrl)
 
def ctrl_line_column (self, gate_name, ctrl, tgt, column_length)
 
def single_qubit_line_column (self, gate_name, index, column_length)
 
def slice_line_column (self, slice_name, column_length)
 
def load_data_csv (self, csv_file)
 
def row_merge ()
 
def latex_cct (self, data_file, file_name="cct", max_depth=16)
 

Data Fields

 num_qubits
 
 ccts
 

Detailed Description

The CircuitPrinter class creates a quantum circuit .tex file for viewing the circuit output.
Assumes the availability of the quantikz LaTeX package when compiling. Preferably use lualatex
to ensure sufficient memory access.

Definition at line 1 of file circuit_printer.py.

Constructor & Destructor Documentation

◆ __init__()

def CircuitPrinter.circuit_printer.CircuitPrinter.__init__ (   self,
  num_qubits 
)

Definition at line 7 of file circuit_printer.py.

7  def __init__(self, num_qubits):
8  self.num_qubits = num_qubits
9  self.ccts = []
10 

Member Function Documentation

◆ ctrl_line_column()

def CircuitPrinter.circuit_printer.CircuitPrinter.ctrl_line_column (   self,
  gate_name,
  ctrl,
  tgt,
  column_length 
)
Creates a columnar slice of the circuit with the given gate name, control and target lines.
The number of qubits specifies the length of the column.

Definition at line 20 of file circuit_printer.py.

20  def ctrl_line_column(self, gate_name, ctrl, tgt, column_length):
21  """
22  Creates a columnar slice of the circuit with the given gate name, control and target lines.
23  The number of qubits specifies the length of the column.
24  """
25 
26  column = [r"\qw & "]*column_length
27  column[tgt] = r"\gate{{{}}} & ".format(gate_name)
28  column[ctrl] = r"\ctrl{{{}}} & ".format(tgt - ctrl)
29  return column
30 

Referenced by CircuitPrinter.circuit_printer.CircuitPrinter.load_data_csv().

Here is the caller graph for this function:

◆ latex_cct()

def CircuitPrinter.circuit_printer.CircuitPrinter.latex_cct (   self,
  data_file,
  file_name = "cct",
  max_depth = 16 
)
LaTeX file outputter for quantum circuit generation.

Definition at line 124 of file circuit_printer.py.

124  def latex_cct(self, data_file, file_name="cct", max_depth=16):
125  """
126  LaTeX file outputter for quantum circuit generation.
127  """
128  cct_array = self.load_data_csv(data_file)
129  num_cct = len(cct_array)
130  depth = len(cct_array[0])
131 
132  for cct_idx in range(num_cct):
133  with open(file_name + "_" + str(cct_idx) + ".tex", "w") as f:
134  f.write("\\documentclass{article} \n \\usepackage{amsmath} \\usepackage{adjustbox} \\usepackage{tikz} \\usetikzlibrary{quantikz} \\usepackage[margin=0.5cm]{geometry} \n \\begin{document} \centering\n")
135  # Split the circuit on a given depth boundary
136 
137  # Due to issues with latex variables ending with numeric indices, appending letters to the temporary savebox commands allows us to generate multiple of these.
138  # As depth is an issue with circuits, we currently expect the output not to exceed n-choose-k of 52-C-4 = 270725 combinations
139  # This will suffice until later.
140  import string, itertools
141  s_list = [i for i in string.ascii_letters]
142  box_str = r"\Box"
143  label_iterator = itertools.combinations(s_list,4)
144  box_labels = []
145 
146  for i in range(0, depth, max_depth):
147  local_label = box_str + "".join( next(label_iterator))
148  box_labels.append(local_label)
149  f.write(r"\newsavebox{{{}}}".format(local_label))
150  f.write(r"\savebox{{{}}}{{".format(local_label))
151 
152  f.write("\\begin{quantikz}[row sep={0.5cm,between origins}, column sep={0.75cm,between origins}, slice label style={inner sep=1pt,anchor=south west,rotate=40}]")
153  #Transposes the data so that q rows of length n exist, rather than n cols of length q
154  if(i + max_depth < depth):
155  cct_list_qubit= list(map(list, zip(*cct_array[cct_idx][i:i+max_depth])))
156  else:
157  cct_list_qubit= list(map(list, zip(*cct_array[cct_idx][i:])))
158 
159  for q in range(len(cct_list_qubit)):
160  out_str = "\\qw & ".join(cct_list_qubit[q]) + " \\qw "
161  if(q != len(cct_list_qubit)-1):
162  out_str += " \\\\ "
163  f.write(out_str)
164  f.write(" \\end{quantikz}\n}\n")
165  f.write("\n")
166 
167  for idx,l in enumerate(box_labels):
168  f.write(r"\usebox{{{}}} \\".format(l))
169  f.write("\n \\vspace{2em}")
170 
171  f.write(r"\end{document}")
172 

References CircuitPrinter.circuit_printer.CircuitPrinter.load_data_csv().

Here is the call graph for this function:

◆ load_data_csv()

def CircuitPrinter.circuit_printer.CircuitPrinter.load_data_csv (   self,
  csv_file 
)
Loads the data from a CSV file. Assumes the following layout:
gate_name, control_qubit_number, target_qubit_number, gate_matrix_values

Definition at line 52 of file circuit_printer.py.

52  def load_data_csv(self, csv_file):
53  """
54  Loads the data from a CSV file. Assumes the following layout:
55  gate_name, control_qubit_number, target_qubit_number, gate_matrix_values
56  """
57  import csv
58  cct = []
59  with open(csv_file, 'r') as csvfile:
60 
61  filereader = csv.reader(csvfile, delimiter=',')
62  data = list(filereader)
63  cct_local = []
64  mergeable_row = 0
65  for idx,row in enumerate(data[1:]):
66  #Check for break in circuit runs, empty data, and single run datasets (ie currently empty output)
67  prev_was_ctrl = False
68  if (row != "\n") and (row != []) and (row != data[-1]):
69  if row[0][0:4] == "#!#{":
70  slice_label = row[0].rsplit("}")[0].rsplit("{")[-1]
71  slice_col = self.slice_line_column(slice_label, self.num_qubits)
72  cct_local.append(slice_col)
73 
74  elif int(row[1]) <= 2**32:
75  prev_was_ctrl = True
76  cct_local.append(self.ctrl_line_column(row[0], int(row[1]), int(row[2]), self.num_qubits) )
77 
78  else:
79  #Single qubit value; max value here indicates that the output value for the ctrl line was 2^64, hence non-existent
80  curr_col = self.single_qubit_line_column(row[0], int(row[2]), self.num_qubits)
81  #Attempt to merge non interfering gates to the same column to reduce visual circuit size
82  '''if (len(cct_local) > 0) and (prev_was_ctrl == False):
83  prev_col = cct_local[-1]
84 
85  icurr = [idx for (idx,val) in enumerate(curr_col) if val != "\\qw & "]
86  iprev = [idx for (idx,val) in enumerate(prev_col) if val != "\\qw & "]
87 
88  if icurr[0] != iprev[0] and len(icurr) == 1 and len(iprev) == 1:
89  curr_row[iprev[0]] = prev_row[iprev[0]]
90  del cct_local[-1]
91  '''
92  cct_local.append(curr_col)
93  prev_was_ctrl == False
94  else:
95  cct.append(cct_local)
96  cct_local = []
97  self.ccts = cct
98  return cct
99 

References CircuitPrinter.circuit_printer.CircuitPrinter.ccts, CircuitPrinter.circuit_printer.CircuitPrinter.ctrl_line_column(), CircuitPrinter.circuit_printer.CircuitPrinter.num_qubits, CircuitPrinter.circuit_printer.CircuitPrinter.single_qubit_line_column(), and CircuitPrinter.circuit_printer.CircuitPrinter.slice_line_column().

Referenced by CircuitPrinter.circuit_printer.CircuitPrinter.latex_cct().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ncu_cct_depth()

def CircuitPrinter.circuit_printer.CircuitPrinter.ncu_cct_depth (   self,
  num_ctrl 
)
Calculate the required depth for the circuit using the implemented nCU decomposition

Definition at line 11 of file circuit_printer.py.

11  def ncu_cct_depth(self, num_ctrl):
12  """
13  Calculate the required depth for the circuit using the implemented nCU decomposition
14  """
15  if num_ctrl > 2:
16  return 2 + 3*self.ncu_cct_depth(num_ctrl-1)
17  else:
18  return 5
19 

References CircuitPrinter.circuit_printer.CircuitPrinter.ncu_cct_depth().

Referenced by CircuitPrinter.circuit_printer.CircuitPrinter.ncu_cct_depth().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ row_merge()

def CircuitPrinter.circuit_printer.CircuitPrinter.row_merge ( )
WIP: Merges rows between independent qubit operations to reduce printed circuit size
e.g. [I, I, I, X], [I, Z, I, I] -> [I, Z, X, I]

Definition at line 100 of file circuit_printer.py.

100  def row_merge():
101  """
102  WIP: Merges rows between independent qubit operations to reduce printed circuit size
103  e.g. [I, I, I, X], [I, Z, I, I] -> [I, Z, X, I]
104  """
105  data = self.ccts[0]
106  for i in range(1,len(data)):
107  prev_mod_vals = [(idx,val) for (idx,val) in enumerate(data[i-1]) if val != "\\qw & "]
108  curr_mod_vals = [(idx,val) for (idx,val) in enumerate(data[i]) if val != "\\qw & "]
109  for j in prev_mod_vals:
110  prev_has_ctrl = []
111  if "\\ctrl" in j[1]:
112  # Terrible, but it will do for now
113  range_len_prev = int(j[1].rsplit("}")[0].rsplit("{")[1])
114  prev_has_ctrl = [(j[0], j[0] + range_len_prev)]
115  for k in curr_mod_vals:
116  curr_has_ctrl = []
117  if "\\ctrl" in k[1]:
118  # Still terrible, but it will do for now
119  range_len_curr = int(k[1].rsplit("}")[0].rsplit("{")[1])
120  curr_has_ctrl = [(k[0], k[0] + range_len_curr)]
121  # Continue this later... seems incredibly inefficient
122 
123 

References CircuitPrinter.circuit_printer.CircuitPrinter.ccts.

◆ single_qubit_line_column()

def CircuitPrinter.circuit_printer.CircuitPrinter.single_qubit_line_column (   self,
  gate_name,
  index,
  column_length 
)
Creates a columnar slice of the circuit with the given gate name, on index
The number of qubits specifies the length of the column.

Definition at line 31 of file circuit_printer.py.

31  def single_qubit_line_column(self, gate_name, index, column_length):
32  """
33  Creates a columnar slice of the circuit with the given gate name, on index
34  The number of qubits specifies the length of the column.
35  """
36 
37  column = ["\qw & "]*column_length
38  column[index] = r"\gate{{{}}} & ".format(gate_name)
39  return column
40 

Referenced by CircuitPrinter.circuit_printer.CircuitPrinter.load_data_csv().

Here is the caller graph for this function:

◆ slice_line_column()

def CircuitPrinter.circuit_printer.CircuitPrinter.slice_line_column (   self,
  slice_name,
  column_length 
)
Creates a columnar slice of the circuit with a dashed line denoting the marked section

Definition at line 41 of file circuit_printer.py.

41  def slice_line_column(self, slice_name, column_length):
42  """
43  Creates a columnar slice of the circuit with a dashed line denoting the marked section
44  """
45 
46  column = ["\qw & "]*column_length
47  if "\\" in slice_name:
48  slice_name = "${}$".format(slice_name)
49  column[0] = r"\qw\slice{{{}}} & ".format(slice_name)
50  return column
51 

Referenced by CircuitPrinter.circuit_printer.CircuitPrinter.load_data_csv().

Here is the caller graph for this function:

Field Documentation

◆ ccts

CircuitPrinter.circuit_printer.CircuitPrinter.ccts

◆ num_qubits

CircuitPrinter.circuit_printer.CircuitPrinter.num_qubits

The documentation for this class was generated from the following file: