Source code for mindquantum.io.qasm.openqasm

# Copyright 2021 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================
"""OpenQASM support module."""
# pylint: disable=import-outside-toplevel
import ast
import operator as op
import re

import numpy as np

from mindquantum.utils import fdopen
from mindquantum.utils.type_value_check import _check_input_type


def join_qubit(gate):
    """Convert qubit list to openqasm style."""
    return ','.join(f'q[{i}]' for i in gate.ctrl_qubits + gate.obj_qubits)


def x_related(gate):
    """Convert mindquantum gate to qasm."""
    ctrl = gate.ctrl_qubits
    jointed = join_qubit(gate)
    if len(ctrl) == 1:
        return f"cx {jointed};"
    if not ctrl:
        return f"x {jointed};"
    if len(ctrl) == 2:
        return f"ccx {join_qubit};"
    raise ValueError(f"Cannot convert {gate} to qasm.")


def y_related(gate):
    """Convert mindquantum gate to qasm."""
    ctrl = gate.ctrl_qubits
    jointed = join_qubit(gate)
    if len(ctrl) == 1:
        return f"cy {jointed};"
    if not ctrl:
        return f"y {jointed};"
    raise ValueError(f"Cannot convert {gate} to qasm.")


def z_related(gate):
    """Convert mindquantum gate to qasm."""
    ctrl = gate.ctrl_qubits
    jointed = join_qubit(gate)
    if len(ctrl) == 1:
        return f"cz {jointed};"
    if not ctrl:
        return f"z {jointed};"
    raise ValueError(f"Cannot convert {gate} to qasm.")


def cnot_related(gate):
    """Convert mindquantum gate to qasm."""
    from mindquantum.core import gates as G  # noqa: N812

    return x_related(G.X.on(gate.obj_qubits[0], gate.obj_qubits[1:] + gate.ctrl_qubits))


def global_phase_related(gate):
    """Convert mindquantum gate to qasm."""
    if len(gate.ctrl_qubits) == 1:
        return f"p({-gate.coeff.const}) {gate.ctrl_qubits[0]};"
    raise ValueError(f"Cannot convert {gate} to qasm.")


def h_related(gate):
    """Convert mindquantum gate to qasm."""
    ctrl = gate.ctrl_qubits
    jointed = join_qubit(gate)
    if len(ctrl) == 1:
        return f"ch {jointed};"
    if not ctrl:
        return f"h {jointed};"
    raise ValueError(f"Cannot convert {gate} to qasm.")


def i_related(gate):
    """Convert mindquantum gate to qasm."""
    return f"id q[{gate.obj_qubits[0]}];"


def phase_related(gate):
    """Convert mindquantum gate to qasm."""
    ctrl = gate.ctrl_qubits
    jointed = join_qubit(gate)
    coeff = gate.coeff.const
    if len(ctrl) == 1:
        return f"cp({coeff}) {jointed};"
    if not ctrl:
        return f"p({coeff}) {jointed};"
    raise ValueError(f"Cannot convert {gate} to qasm.")


def rx_related(gate):
    """Convert mindquantum gate to qasm."""
    ctrl = gate.ctrl_qubits
    jointed = join_qubit(gate)
    coeff = gate.coeff.const
    if len(ctrl) == 1:
        return f"crx({coeff}) {jointed};"
    if not ctrl:
        return f"rx({coeff}) {jointed};"
    raise ValueError(f"Cannot convert {gate} to qasm.")


def ry_related(gate):
    """Convert mindquantum gate to qasm."""
    ctrl = gate.ctrl_qubits
    jointed = join_qubit(gate)
    coeff = gate.coeff.const
    if len(ctrl) == 1:
        return f"cry({coeff}) {jointed};"
    if not ctrl:
        return f"ry({coeff}) {jointed};"
    raise ValueError(f"Cannot convert {gate} to qasm.")


def rz_related(gate):
    """Convert mindquantum gate to qasm."""
    ctrl = gate.ctrl_qubits
    jointed = join_qubit(gate)
    coeff = gate.coeff.const
    if len(ctrl) == 1:
        return f"crz({coeff}) {jointed};"
    if not ctrl:
        return f"rz({coeff}) {jointed};"
    raise ValueError(f"Cannot convert {gate} to qasm.")


def rxx_related(gate):
    """Convert mindquantum gate to qasm."""
    ctrl = gate.ctrl_qubits
    jointed = join_qubit(gate)
    coeff = gate.coeff.const
    if not ctrl:
        return f"rxx({coeff}) {jointed};"
    raise ValueError(f"Cannot convert {gate} to qasm.")


def rzz_related(gate):
    """Convert mindquantum gate to qasm."""
    ctrl = gate.ctrl_qubits
    jointed = join_qubit(gate)
    coeff = gate.coeff.const
    if not ctrl:
        return f"rzz({coeff}) {jointed};"
    raise ValueError(f"Cannot convert {gate} to qasm.")


def s_related(gate):
    """Convert mindquantum gate to qasm."""
    ctrl = gate.ctrl_qubits
    jointed = join_qubit(gate)
    if not ctrl:
        if not gate.hermitianed:
            return f"s {jointed};"
        return f"sdg {jointed};"
    raise ValueError(f"Cannot convert {gate} to qasm.")


def t_related(gate):
    """Convert mindquantum gate to qasm."""
    ctrl = gate.ctrl_qubits
    jointed = join_qubit(gate)
    if not ctrl:
        if not gate.hermitianed:
            return f"t {jointed};"
        return f"tdg {jointed};"
    raise ValueError(f"Cannot convert {gate} to qasm.")


def sx_related(gate):
    """Convert mindquantum gate to qasm."""
    ctrl = gate.ctrl_qubits
    jointed = join_qubit(gate)
    if not ctrl:
        if not gate.hermitianed:
            return f"sx {jointed};"
        return f"sxdg {jointed};"
    raise ValueError(f"Cannot convert {gate} to qasm.")


def swap_related(gate):
    """Convert mindquantum gate to qasm."""
    ctrl = gate.ctrl_qubits
    jointed = join_qubit(gate)
    if len(ctrl) == 1:
        return f"cswap {jointed};"
    if not ctrl:
        return f"swap {jointed};"
    raise ValueError(f"Cannot convert {gate} to qasm.")


def u3_related(gate):
    """Convert mindquantum gate to qasm."""
    p_0, p_1, p_2 = gate.prs
    p_0 = p_0.const
    p_1 = p_1.const
    p_2 = p_2.const
    ctrl = gate.ctrl_qubits
    jointed = join_qubit(gate)
    if len(ctrl) == 1:
        return f"cu({p_0},{p_1},{p_2}) {jointed};"
    if not ctrl:
        return f"u({p_0},{p_1},{p_2}) {jointed};"
    raise ValueError(f"Cannot convert {gate} to qasm.")


def extra_qid(cmd, qregs, cregs):
    """Get qubit id."""
    regs = re.findall(r'[a-zA-Z_][a-zA-Z0-9_]*\[\d+\]', cmd)
    if regs:
        out = []
        for i in regs:
            reg_name = re.findall(r'[a-zA-Z_][a-zA-Z0-9_]*', i)[0]
            reg_id = int(re.findall(r'\d+', i)[0])
            if reg_name in qregs:
                out.append(qregs[reg_name][reg_id])
            elif reg_name in cregs:
                out.append(cregs[reg_name][reg_id])
            else:
                raise ValueError(f"Registor {reg_name} not allocated.")
        return (out,)
    possible_name = [i for i in re.findall(r'[a-zA-Z_][a-zA-Z0-9_]*', cmd) if i in qregs or i in cregs]
    out = np.array([qregs[i] if i in qregs else cregs[i] for i in possible_name]).T
    return tuple([int(j) for j in i] for i in out)


def extra_params(cmd, dtype=float):
    """Get gate parameters."""
    matches = re.findall(r'\((.*)\)', cmd)
    out = []
    for i in matches:
        for j in i.split(','):
            pr = j.strip()
            if dtype == str:
                out.append(pr)
            else:
                if '*' in pr:
                    pr = pr.replace('pi', str(np.pi)).replace('π', str(np.pi))
                    pr = [float(i.strip()) for i in pr.split('*')]
                    out.append(pr[0] * pr[1])
                elif '/' in pr:
                    pr = pr.replace('pi', str(np.pi)).replace('π', str(np.pi))
                    pr = [float(i.strip()) for i in pr.split('/')]
                    out.append(pr[0] / pr[1])
                else:
                    out.append(float(pr))
    return out


def extra_gate_name(cmd: str):
    """Get gate name."""
    cmd = cmd.strip()
    space_idx = cmd.find(' ')
    if space_idx == -1:
        raise ValueError(f"Wrong command: {cmd}")
    sub_cmd = cmd[:space_idx]
    if '(' in sub_cmd:
        return sub_cmd[: sub_cmd.find('(')].strip()
    return sub_cmd.strip()


def parse_gate_cmd(cmd, qregs, cregs):
    """Parse a gate command."""
    try:
        cmd = cmd.strip()
        gate_name = extra_gate_name(cmd)
        qid = extra_qid(cmd, qregs, cregs)
        if gate_name == 'pauli':
            params = extra_params(cmd, dtype=str)
        else:
            params = extra_params(cmd)
        return gate_name, params, qid
    except:  # pylint: disable=raise-missing-from # noqa: E722
        raise ValueError(f"Cannot parse command: {cmd}")


def gene_reg(cmds):
    """Parse quantum and classical registor."""
    qregs = {}
    cregs = {}
    total_q, total_c = 0, 0
    for i in cmds:
        if i.startswith('creg'):
            creg_name = re.findall(r'\s(.*)?\[', i)[0]
            n_c_this = int(re.findall(r'\[(.*)?\]', i)[0])
            cregs[creg_name] = list(range(total_c, total_c + n_c_this))
            total_c += n_c_this
            continue
        if i.startswith('qreg'):
            qreg_name = re.findall(r'\s(.*)?\[', i)[0]
            n_q_this = int(re.findall(r'\[(.*)?\]', i)[0])
            qregs[qreg_name] = list(range(total_q, total_q + n_q_this))
            total_q += n_q_this
            continue
    return qregs, total_q, cregs, total_c


def extra_func_body(cmd):
    """Get definition of custom gate."""
    matches = re.findall(r'\{(.*)\}', cmd)
    return [i.strip() for i in matches[0].strip().split(';')]


def extra_func_head(cmd):
    """Get gate name and parameters for custom gate."""
    cmd = cmd.replace('gate ', '')
    cmd = cmd[: cmd.find('{')].strip()
    if '(' in cmd:
        name = cmd[: cmd.find('(')].strip()
        params = extra_params(cmd, dtype=str)
        qid = re.findall(r'\)(.*)', cmd)[0].strip().split(',')
        qid = [i.strip() for i in qid]
        return name, params, qid
    name = cmd[: cmd.find(' ')].strip()
    qid = cmd[cmd.find(' ') :].strip().split(',')
    qid = [i.strip() for i in qid]
    return name, [], qid


def eval_expr(expr):
    """Safe eval of string expression."""
    return eval_(ast.parse(expr, mode='eval').body)


def eval_(node):
    """Safe eval of string expression."""
    operators = {
        ast.Add: op.add,
        ast.Sub: op.sub,
        ast.Mult: op.mul,
        ast.Div: op.truediv,
        ast.Pow: op.pow,
        ast.USub: op.neg,
    }

    if isinstance(node, ast.Num):
        return node.n
    if isinstance(node, ast.BinOp):
        return operators[type(node.op)](eval_(node.left), eval_(node.right))
    if isinstance(node, ast.UnaryOp):
        return operators[type(node.op)](eval_(node.operand))
    raise TypeError(node)


def eval_pr(pr, prs, gate_params):
    """Calculate the parameters."""
    pr = pr.replace('pi', str(np.pi)).replace('π', str(np.pi))
    for idx, p in enumerate(gate_params):
        pr = pr.replace(p, str(prs[idx]))
    return eval_expr(pr)


def generate_custom_gate(gate_def, custom_gate, gate_map_openqasm_mq):
    """Generate a custom gate defined in openqasm."""
    from mindquantum.core.circuit import Circuit

    gate_name, gate_params, gate_qids = extra_func_head(gate_def)
    body = extra_func_body(gate_def)

    def gate(prs, qids):
        circ = Circuit()
        for cmd in body:
            if not cmd:
                continue
            sub_gate_name = extra_gate_name(cmd)
            sub_gate_params = extra_params(cmd, str)
            if sub_gate_params:
                sub_gate_qid = cmd[cmd.find(')') + 1 :]
            else:
                sub_gate_qid = cmd[cmd.find(' ') :]
            sub_gate_qid = [i.strip() for i in sub_gate_qid.split(',')]
            real_qid = [qids[gate_qids.index(i)] for i in sub_gate_qid]
            real_prs = [eval_pr(i, prs, gate_params) for i in sub_gate_params]
            if sub_gate_name not in gate_map_openqasm_mq:
                if sub_gate_name not in custom_gate:
                    raise ValueError(f"{sub_gate_name} not defined.")
                circ += custom_gate[sub_gate_name](real_prs, real_qid)
            else:
                circ += gate_map_openqasm_mq[sub_gate_name](real_prs, real_qid)
        return circ

    custom_gate[gate_name] = gate


def mq_to_qasm_v2(circ, gate_map_mq_openqasm, version: str = '2.0'):
    """Convert mindquantum circuit to openqasm."""
    from mindquantum.algorithm.compiler import BasicDecompose, compile_circuit
    from mindquantum.core import gates as G  # noqa: N812
    from mindquantum.core.circuit import Circuit

    if version != '2.0':
        raise ValueError("Only support qasm version 2.0")
    if circ.is_noise_circuit:
        raise ValueError("Cannot convert noise circuit to qasm.")
    cmds = ['OPENQASM 2.0;', 'include "qelib1.inc";', f'qreg q[{circ.n_qubits}];']
    mea_qubits = sorted({m.obj_qubits[0] for m in circ.all_measures.keys()})
    reg_map = {j: i for i, j in enumerate(mea_qubits)}
    if mea_qubits:
        cmds.append(f"creg c[{len(mea_qubits)}];")
    for gate in circ:
        gate: G.BasicGate
        if isinstance(gate, G.BarrierGate):
            obj = gate.obj_qubits
            if not gate.obj_qubits:
                obj = list(range(circ.n_qubits))
            cmds.append(f"barrier {join_qubit(G.BARRIER.on(obj))};")
            continue
        if isinstance(gate, G.Measure):
            cmds.append(f"measure q[{gate.obj_qubits[0]}] -> c[{reg_map[gate.obj_qubits[0]]}];")
            continue
        if gate.__class__ in gate_map_mq_openqasm:
            cmds.append(gate_map_mq_openqasm[gate.__class__](gate))
            continue
        compiled_circ = compile_circuit(BasicDecompose(), Circuit([gate]))
        for sub_gate in compiled_circ:
            if sub_gate.__class__ in gate_map_mq_openqasm:
                cmds.append(gate_map_mq_openqasm[sub_gate.__class__](sub_gate))
            else:
                raise ValueError(f"Cannot convert {sub_gate} to openqasm after decompose gate {gate}")
    return '\n'.join(cmds)


def prepare_qasm(qasm: str):
    """Remove new line between bracket."""
    qasm = re.sub(r'//.*?\n', '\n', qasm.lower())
    new_qasm = ''
    start_body = False
    for i in qasm:
        if i == '{':
            start_body = True
            new_qasm = new_qasm.strip()
        if i == '\n' and start_body:
            continue
        if i == '}':
            start_body = False
        new_qasm += i
    return [i.strip() for i in new_qasm.strip().split('\n')]


# pylint: disable=too-many-locals,too-many-branches
def qasm_to_mq_v2(qasm: str, gate_map_openqasm_mq):
    """Convert openqasm to mindquantum circuit."""
    from mindquantum.core.circuit import Circuit

    cmds = prepare_qasm(qasm)
    circ = Circuit()
    custom_gate = {}
    measures = {}
    qregs, _, cregs, _ = gene_reg(cmds)
    for i in cmds:
        if i.startswith('openqasm'):
            if not i.endswith('2.0;'):
                raise ValueError(f"OpenQASM version not supported: {i}")
            continue
        if i.startswith("include"):
            if not i.endswith('"qelib1.inc";'):
                raise ValueError(f"Include other head file not supported: {i}")
            continue
        if i.startswith('qreg') or i.startswith('creg') or not i:
            continue
        if i.startswith('gate '):
            generate_custom_gate(i, custom_gate, gate_map_openqasm_mq)
        else:
            cmd = i.strip()
            gate_name, params, qids = parse_gate_cmd(cmd, qregs, cregs)
            if gate_name == 'barrier':
                circ += gate_map_openqasm_mq['barrier'](params, [q[0] for q in qids])
                continue
            for qid in qids:
                if gate_name in custom_gate:
                    circ += custom_gate[gate_name](params, qid)
                elif gate_name in gate_map_openqasm_mq:
                    mq_gate = gate_map_openqasm_mq[gate_name](params, qid)
                    if gate_name == 'measure':
                        mq_gate.key = f"q{qid[0]}_{measures.get(qid[0], 0)}"
                        measures[qid[0]] = measures.get(qid[0], 0) + 1
                    circ += mq_gate
                else:
                    raise ValueError(f"{cmd} not implement.")
    return circ


[docs]class OpenQASM: """ Convert a circuit to openqasm format. Examples: >>> import numpy as np >>> from mindquantum.core import Circuit >>> from mindquantum.io import OpenQASM >>> circuit = Circuit().rx(0.3, 0).z(0, 1).zz(np.pi, [0, 1]) >>> openqasm = OpenQASM() >>> circuit_str = openqasm.to_string(circuit) >>> print(circuit_str) OPENQASM 2.0; include "qelib1.inc"; qreg q[2]; rx(0.3) q[0]; cz q[1],q[0]; rzz(6.283185307179586) q[0],q[1]; """ def __init__(self): """Construct a openqasm parse.""" from mindquantum.core import gates as G # noqa: N812 from mindquantum.core.circuit import Circuit self.gate_map_openqasm_mq = { 'barrier': lambda prs, qids: Circuit([G.BarrierGate().on(qids)]), 'ccx': lambda prs, qids: G.X.on(qids[-1], qids[:-1]), 'ch': lambda prs, qids: G.H.on(qids[-1], qids[:-1]), 'cp': lambda prs, qids: G.PhaseShift(prs[0]).on(qids[-1], qids[:-1]), 'crx': lambda prs, qids: G.RX(prs[0]).on(qids[-1], qids[:-1]), 'cry': lambda prs, qids: G.RY(prs[0]).on(qids[-1], qids[:-1]), 'crz': lambda prs, qids: G.RZ(prs[0]).on(qids[-1], qids[:-1]), 'cswap': lambda prs, qids: G.SWAP.on(qids[1:], qids[0]), 'cx': lambda prs, qids: G.X.on(qids[1], qids[0]), 'csx': lambda prs, qids: Circuit( [ G.RX(np.pi / 2).on(qids[1], qids[0]), G.PhaseShift(np.pi / 2).on(qids[0]), ] ), 'cu': lambda prs, qids: Circuit( [ G.U3(prs[0], prs[1], prs[2]).on(qids[1], qids[0]), G.PhaseShift(prs[3]).on(qids[0]), ] ), 'cu1': lambda prs, qids: G.U3(0, 0, prs[0]).on(qids[1], qids[0]), 'cu3': lambda prs, qids: G.U3(prs[0], prs[1], prs[2]).on(qids[1], qids[0]), 'cy': lambda prs, qids: G.Y.on(qids[1], qids[0]), 'cz': lambda prs, qids: G.Z.on(qids[1], qids[0]), 'h': lambda prs, qids: G.H.on(qids[0]), 'id': lambda prs, qids: G.I.on(qids[0]), 'measure': lambda prs, qids: G.Measure().on(qids[0]), 'p': lambda prs, qids: G.PhaseShift(prs[0]).on(qids[0]), 'rccx': lambda prs, qids: Circuit( [ G.H.on(qids[2]), G.T.on(qids[2]), G.X.on(qids[2], qids[1]), G.T.on(qids[2]).hermitian(), G.X.on(qids[2], qids[0]), G.T.on(qids[2]), G.X.on(qids[2], qids[1]), G.T.on(qids[2]).hermitian(), G.H.on(qids[2]), ] ), 'rx': lambda prs, qids: G.RX(prs[0]).on(qids), 'ry': lambda prs, qids: G.RY(prs[0]).on(qids), 'rz': lambda prs, qids: G.RZ(prs[0]).on(qids), 'rxx': lambda prs, qids: G.Rxx(prs[0]).on(qids), 'ryy': lambda prs, qids: G.Ryy(prs[0]).on(qids), 'rzz': lambda prs, qids: G.Rzz(prs[0]).on(qids), 's': lambda prs, qids: G.S.on(qids), 'sdg': lambda prs, qids: G.S.on(qids).hermitian(), 'swap': lambda prs, qids: G.SWAP.on(qids), 'sx': lambda prs, qids: G.SX.on(qids), 'sxdg': lambda prs, qids: G.SX.on(qids).hermitian(), 't': lambda prs, qids: G.T.on(qids), 'tdg': lambda prs, qids: G.T.on(qids).hermitian(), 'u': lambda prs, qids: G.U3(*prs).on(qids), 'u1': lambda prs, qids: G.U3(0, 0, prs[0]).on(qids), 'u2': lambda prs, qids: G.U3(np.pi / 2, prs[0], prs[1]).on(qids), 'u3': lambda prs, qids: G.U3(*prs).on(qids), 'x': lambda prs, qids: G.X.on(qids), 'y': lambda prs, qids: G.Y.on(qids), 'z': lambda prs, qids: G.Z.on(qids), } self.gate_map_mq_openqasm = { G.XGate: x_related, G.YGate: y_related, G.ZGate: z_related, G.CNOTGate: cnot_related, G.GlobalPhase: global_phase_related, G.HGate: h_related, G.IGate: i_related, G.PhaseShift: phase_related, G.RX: rx_related, G.RY: ry_related, G.RZ: rz_related, G.Rxx: rxx_related, G.Rzz: rzz_related, G.SGate: s_related, G.TGate: t_related, G.SXGate: sx_related, G.SWAPGate: swap_related, G.U3: u3_related, }
[docs] def to_string(self, circuit, version="2.0"): # pylint: disable=R0912,R0914,R0915 """ Convert circuit to openqasm. Args: circuit (Circuit): The quantum circuit you want to translated to openqasm. version (str): The openqasm version you want to use. Default: ``'2.0'``. Returns: str, The openqasm format of input circuit. Raises: TypeError: if `circuit` is not a Circuit. TypeError: if `version` is not a str. NotImplementedError: if openqasm version not implement. ValueError: if gate not implement in this version. """ return mq_to_qasm_v2(circuit, self.gate_map_mq_openqasm, version)
[docs] def to_file(self, file_name, circuit, version="2.0"): """ Convert a quantum circuit to openqasm format and save in file. Args: file_name (str): The file name you want to save the openqasm file. circuit (Circuit): The Circuit you want to convert. version (str): The version of openqasm. Default: ``'2.0'``. Raises: TypeError: if `file_name` is not a str. TypeError: if `circuit` is not a Circuit. TypeError: if `version` is not a str. """ from mindquantum.core import ( # pylint: disable=import-outside-toplevel,cyclic-import Circuit, ) if not isinstance(file_name, str): raise TypeError(f'file_name requires a str, but get {type(file_name)}') if not isinstance(circuit, Circuit): raise TypeError(f"circuit requires a Circuit, but get {type(circuit)}") if not isinstance(version, str): raise TypeError(f'version requires a str, but get {type(version)}') with fdopen(file_name, 'w') as fd: fd.writelines(self.to_string(circuit, version)) print(f"write circuit to {file_name} finished!")
[docs] def from_file(self, file_name): """ Read a openqasm file. Args: file_name (str): The path of file that stored quantum circuit in openqasm format. Returns: Circuit, the quantum circuit translated from openqasm file. """ with fdopen(file_name, 'r') as fd: cmds = fd.readlines() return qasm_to_mq_v2('\n'.join(cmds), self.gate_map_openqasm_mq)
[docs] def from_string(self, string): """ Read a OpenQASM string. Args: string (str): The OpenQASM string of Circuit. Returns: :class:`~.core.circuit.Circuit`, the quantum circuit translated from OpenQASM string. Examples: >>> from mindquantum.io import OpenQASM >>> from mindquantum.core.circuit import Circuit >>> circ = Circuit().x(0, 1).h(1) >>> string = OpenQASM().to_string(circ) >>> OpenQASM().from_string(string) ┏━━━┓ q0: ──┨╺╋╸┠───────── ┗━┳━┛ ┃ ┏━━━┓ q1: ────■───┨ H ┠─── ┗━━━┛ """ _check_input_type('string', str, string) return qasm_to_mq_v2(string, self.gate_map_openqasm_mq)