pyqpanda.Visualization.circuit_composer 源代码

import numpy
import pyqpanda as pq
from typing import List
from pyqpanda.Visualization.matplotlib_draw import MatplotlibDrawer
from pyqpanda import circuit_layer

corners_str = ['┌', '┐', '└', '┘']
left_str, right_str = '┤', '├'
horizontal_str, vertical_str = '─', '│'
space = ' '


[文档] class CircuitComposer(pq.QCircuit): """CircuitComposer for representing quantum circuit using ascii art. Args ---------- n_qubits: int Number of qubits of quantum circuit. circuit_layers : List[List[str]] List of each layer of quantum circuit, each layer of a list of string, representing each line of ascii art. Examples -------- >>> n_qubits = 6 >>> qvm = pq.CPUQVM() >>> qvm.init_qvm() >>> q = qvm.qAlloc_many(n_qubits) >>> circ1 = CircuitComposer(n_qubits) >>> circuit = pq.QCircuit() >>> circuit << pq.H(q[0]) << pq.CNOT(q[0], q[1]) << pq.CNOT(q[1], q[2]) >>> circ1.append(circuit) >>> circ1 << pq.BARRIER(q) >>> circ1.append(pq.QFT(q[4:]), "QFT") >>> print(circ1) ┌─┐ ! q_0: |0>─ ┤H├ ───■── ────── ────! ──────── └─┘ ┌──┴─┐ ! q_1: |0>─ ─── ┤CNOT├ ───■── ────! ──────── └────┘ ┌──┴─┐ ! q_2: |0>─ ─── ────── ┤CNOT├ ────! ──────── └────┘ ! q_3: |0>─ ─── ────── ────── ────! ──────── ! ┌──────┐ q_4: |0>─ ─── ────── ────── ────! ┤4 ├ ! │ QFT │ q_5: |0>─ ─── ────── ────── ────! ┤5 ├ ! └──────┘ >>> print(circ1.circuit) ┌─┐ ! q_0: |0>─┤H├ ───■── ────── ────! ─── ────────────── ─── ─ └─┘ ┌──┴─┐ ! q_1: |0>──── ┤CNOT├ ───■── ────! ─── ────────────── ─── ─ └────┘ ┌──┴─┐ ! q_2: |0>──── ────── ┤CNOT├ ────! ─── ────────────── ─── ─ └────┘ ! q_3: |0>──── ────── ────── ────! ─── ────────────── ─── ─ ! ┌─┐ q_4: |0>──── ────── ────── ────! ─── ───────■────── ┤H├ X ! ┌─┐ ┌──────┴─────┐ └─┘ │ q_5: |0>──── ────── ────── ────! ┤H├ ┤CR(1.570796)├ ─── X ! └─┘ └────────────┘ """ def __init__(self, n_qubits: int) -> None: super().__init__()
[文档] self.n_qubits = n_qubits
# Saving all circuit layers, each layer is a list of string
[文档] self.circuit_layers = [self.__get_prefix_circuit()]
[文档] self.circuit_latex_layers = self.__get_latex_prefix_circuit()
[文档] self.circuit_pic_layers = []
def __lshift__(self, circ: pq.QCircuit): return self.insert(circ)
[文档] def append(self, circ: pq.QCircuit, name: str = '') -> None: """Append a quantum circuit. Args ---------- circ : pq.QCircuit Quantum circuit to be appended. name : str, optional Name of the appended quantum circuit, by default None Notes ----- If `name` is empty string, then append the circuit with its string representation not boxed. The name must be in full English and cannot contain numbers or symbols Even when a circuit is appended with a name, the composed circuit string can be get by using `circuit` property. Examples -------- >>> circ = CircuitComposer(2) >>> circuit = pq.QCircuit() >>> circuit << pq.H(qubits[0]) << pq.CNOT(qubits[0], qubits[1]) >>> circ.append(circuit) >>> print(circ) ┌─┐ q_0: |0>─ ┤H├ ───■── └─┘ ┌──┴─┐ q_1: |0>─ ─── ┤CNOT├ └────┘ >>> circ.append(circuit, "GHZ") >>> print(circ) ┌─┐ ┌──────┐ q_0: |0>─ ┤H├ ───■── ┤0 ├ └─┘ ┌──┴─┐ │ GHZ │ q_1: |0>─ ─── ┤CNOT├ ┤1 ├ └────┘ └──────┘ >>> print(circ.circuit) ┌─┐ ┌─┐ q_0: |0>─┤H├ ───■── ┤H├ ───■── └─┘ ┌──┴─┐ └─┘ ┌──┴─┐ q_1: |0>──── ┤CNOT├ ─── ┤CNOT├ └────┘ └────┘ """ if name: self.__insert_circuit(circ, name) else: self.insert(circ)
[文档] def insert(self, circ: pq.QCircuit): if self == circ: raise NotImplementedError("Circuit cannot insert on itself.") self = super().insert(circ) # append ASII self.circuit_layers.append(self.__get_circuit_strings(circ)) # append latex circuit_latex = self.__get_circuit_latex(circ) for i in range(len(circuit_latex)): self.circuit_latex_layers[i + 1] = (self.circuit_latex_layers[i + 1][:-12] + circuit_latex[i]) # remove "&\nghost{}\\" # append pic self.circuit_pic_layers.append([circ, None]) return self
def __insert_circuit(self, circ: pq.QCircuit, name, gateType=None): self = super().insert(circ) # append ASII self.circuit_layers.append(self.__get_circuit_box_string(circ, name)) # append latex circuit_latex = self.__get_circuit_box_latex(circ, name) for i in range(len(circuit_latex)): self.circuit_latex_layers[i + 1] = (self.circuit_latex_layers[i + 1][:-12] + circuit_latex[i]) # remove "&\nghost{}\\" # append pic circuit_pic = self.__get_circuit_box_pic(circ, name) self.circuit_pic_layers.append([circuit_pic, name]) def __str__(self) -> str: result = '' circuit_text =[] for row in range(len(self.circuit_layers[0])): line ='' for col in range(len(self.circuit_layers)): line+=self.circuit_layers[col][row] circuit_text.append(line) # # num = int(len(circuit_text)/100+1) # for i in range(num): for line in circuit_text: result += line + '\n' return result
[文档] def draw_circuit(self, output=None, filename=None) -> str: """ draw a quantum circuit. Parameters ---------- output : str,Output type: text、latex、pic filename : str, optional When the output type is pic, this parameter can be used to specify the path to save the picture Returns ------- str, if 'text' return ASII of circuit, if 'latex' return latex of circuit, if 'pic' return picture save path of circuit, Notes ----- If `output` is empty string, use text if filename is empty string,use 'QCircuit_pic.png' """ if output is None: output = "text" if output == "text": return self.__str__() # output latex elif output == 'latex': result = '' for i in range(len(self.circuit_latex_layers)): result += self.circuit_latex_layers[i] result += '\n' return result elif output == 'pic': if filename is None: filename = 'QCircuit_pic.png' node_infos = [] for i in range(len(self.circuit_pic_layers)): if self.circuit_pic_layers[i][1] is not None: infos = circuit_layer(self.circuit_pic_layers[i][0])[0] infos[0][0].m_name = self.circuit_pic_layers[i][1] node_infos.extend(infos) else: infos = circuit_layer(self.circuit_pic_layers[i][0])[0] node_infos.extend(infos) layer_info = circuit_layer(self) # print(info.m_node_type) qcd = MatplotlibDrawer(qregs=layer_info[1], cregs=layer_info[2], ops=node_infos, scale=0.7, fold=30) qcd.draw(filename,False) return filename
@property
[文档] def circuit(self): """Return original quantum circuit representation.""" circ_text = pq.draw_qprog_text(self, output_file='') return circ_text
def __get_circuit_string_lists(self, circ: pq.QCircuit = None) -> List[str]: """Get quantum circuit string list. Parameters ---------- circ : pq.QCircuit, optional Quantum circuit, by default None. Returns ------- List[str] string representation of `circ`. """ qvm = pq.CPUQVM() qvm.init_qvm() qubits = qvm.qAlloc_many(self.n_qubits) circuit = pq.QCircuit() for q in qubits: circuit << pq.I(q) if circ: circuit << circ circ_text = pq.draw_qprog_text(circuit, output_file='') circ_text = circ_text.strip('\n') circ_text = circ_text.split('\n') # destroy qvm qvm.finalize() return circ_text def __get_circuit_latex_lists(self, circ: pq.QCircuit = None) -> List[str]: """Get quantum circuit latex list. Parameters ---------- circ : pq.QCircuit, optional Quantum circuit, by default None. Returns ------- List[str] latex string representation of `circ`. """ qvm = pq.CPUQVM() qvm.init_qvm() qubits = qvm.qAlloc_many(self.n_qubits) circuit = pq.QCircuit() for q in qubits: circuit << pq.I(q) if circ: circuit << circ circ_text = pq.draw_qprog_latex(circuit, output_file='') circ_text = circ_text.strip('\n') circ_text = circ_text.split('\n') # Remove the head and tail circ_text = circ_text[8:-2] # Remove I gate new_lines = [] for line in circ_text: line = line[line.find("I") + 3:] new_lines.append(line) # destroy qvm qvm.finalize() return new_lines def __get_prefix_circuit(self): circ_text = self.__get_circuit_string_lists() # Note: Only 1000 qubits are considered, i.e., qubit width is 3 by # default. pos_1 = circ_text[0].find('┌') if pos_1 == -1: raise ValueError("Unable to generate circuit prefix.") new_lines = [circ[0:pos_1] for circ in circ_text] return new_lines def __get_latex_prefix_circuit(self): circ_text = [] # latex header circ_text.append("\\documentclass[border=2px]{standalone}\n" "\n" "\\usepackage[braket, qm]{qcircuit}\n" "\\usepackage{graphicx}\n" "\n" "\\begin{document}\n" "\\scalebox{1.0}{\n" "\\Qcircuit @C = 1.0em @R = 0.5em @!R{ \\\\") # latex mid for i in range(self.n_qubits): circ_text.append(r"\nghost{q_{%d}\ket{0}}&\lstick{q_{%d}\ket{0}}&\nghost{}\\" % (i, i)) # latex end circ_text.append("\\\\ }} \n" "\\end{document}") return circ_text def __get_circuit_strings(self, circ: pq.QCircuit) -> List[str]: circ_text = self.__get_circuit_string_lists(circ) pos = circ_text[0].find('┐') pos2 = 8 # circ_text[1].find('>') if pos == -1: raise ValueError("Unable to generate circuit text representation.") new_lines = [circuit[pos + 1:] for circuit in circ_text[:2*self.n_qubits+1]] new_lines.extend([circuit[ pos2 + 1:] for circuit in circ_text[2*self.n_qubits+1:]]) # remove '>' for row in range(len(new_lines)): new_lines[row] = new_lines[row].rstrip('>') # join join_row = len(self.circuit_layers[0]) while join_row < len(new_lines): join_row += 1 for i in range(len(self.circuit_layers[0])): new_lines[i] += new_lines[join_row] join_row += 1 new_lines = new_lines[:len(self.circuit_layers[0])] return new_lines def __get_circuit_latex(self, circ: pq.QCircuit) -> List[str]: circ_text = self.__get_circuit_latex_lists(circ) return circ_text def __get_circuit_box_string(self, circ: pq.QCircuit, name: str) -> List[str]: """Get box string representation of quantum circuit. Parameters ---------- circ : pq.QCircuit Quantum circuit. name : str Name of quantum circuit. Returns ------- List[str] Box string representaion of `circ`. """ qubits = pq.get_all_used_qubits_to_int(circ) qubits.sort() if not qubits: return ['' for _ in range(2 * self.n_qubits + 1)] # two 1's represent two spaces qubit_witdh = len(str(qubits[-1])) width = 1 + qubit_witdh + 1 + len(name) + 1 + 1 all_qubits = list(range(self.n_qubits)) qubit_index = [all_qubits.index(element) for element in qubits] min_index = qubit_index[0] max_index = qubit_index[-1] lines = [] # Empty qubits for i in range(min_index): lines.append(space * width) lines.append(horizontal_str * width) first_line = corners_str[0] + horizontal_str * (width - 2) + corners_str[1] lines.append(first_line) # middle lines middle_lines = 2 * (max_index - min_index) + 1 for i in range(middle_lines): if i % 2 == 0: q = all_qubits[min_index + i // 2] str_qubit = str(q) if q in qubits else space * qubit_witdh if i != (max_index - min_index): line = '{}{}{}{}'.format(left_str, str_qubit, space * (width - 2 - len(str_qubit)), right_str) else: # name line line = '{}{}{}{}{}{}'.format(left_str, str_qubit, space, name, space, right_str ) elif i == max_index - min_index: # circuit name line = '{}{}{}{}{}'.format(vertical_str, space * (qubit_witdh + 1), name, space, vertical_str) else: line = vertical_str + space * (width - 2) + vertical_str lines.append(line) last_line = corners_str[2] + horizontal_str * (width - 2) + corners_str[3] lines.append(last_line) # Empty qubits for i in range(max_index, self.n_qubits - 1): lines.append(horizontal_str * width) lines.append(space * width) return lines def __get_circuit_box_latex(self, circ: pq.QCircuit, name: str) -> List[str]: """Get box string of latex type for the quantum circuit. Parameters ---------- circ : pq.QCircuit Quantum circuit. name : str Name of quantum circuit. Returns ------- List[str] Box string of `circ`. """ qubits = pq.get_all_used_qubits_to_int(circ) qubits.sort() if not qubits: return [r'&\nghost{}\\' for _ in range(self.n_qubits)] # two 1's represent two spaces qubit_witdh = len(str(qubits[-1])) width = 1 + qubit_witdh + 1 + len(name) + 1 + 1 all_qubits = list(range(self.n_qubits)) qubit_index = [all_qubits.index(element) for element in qubits] min_index = qubit_index[0] max_index = qubit_index[-1] lines = [] # Empty qubits for i in range(min_index): lines.append(r"&\qw &\qw &\nghost{}\\") # middle lines middle_lines = (max_index - min_index) lines.append(r"&\multigate {%d}{\mathcal{%s}}_<<<{%d} &\qw &\nghost{}\\" % (middle_lines, name, min_index)) for i in range(middle_lines): lines.append(r"&\ghost{\mathcal{%s}}_<<<{%d} &\qw &\nghost{}\\" % (name, min_index + i + 1)) # Empty qubits for i in range(max_index, self.n_qubits - 1): lines.append(r"&\qw &\qw &\nghost{}\\") return lines def __get_circuit_box_pic(self, circ: pq.QCircuit, name: str) -> List[str]: """Packaging a circuit as a QOracle , removing detailed information about the circuit to improve efficiency Parameters ---------- circ : pq.QCircuit Quantum circuit. name : str Name of quantum circuit. Returns ------- pq.QCircuit,A circuit containing a QOracle """ q = pq.get_all_used_qubits(circ) if not q: return pq.QCircuit() new_circ = pq.QCircuit() new_circ << pq.QOracle(q, numpy.eye((2 ** len(q)))) return new_circ