# Source code for qutip.qip.qasm

    import re
    import os
    from itertools import chain
    from copy import deepcopy
    import warnings

    from math import pi
    import numpy as np

    from qutip.qip.circuit import QubitCircuit
    from qutip.qip.operations import (
        controlled_gate, qasmu_gate, rz, snot, gate_sequence_product,
    )

    __all__ = ["read_qasm", "save_qasm", "print_qasm", "circuit_to_qasm_str"]

    class QasmGate:
        '''
        Class which stores the gate definitions as specified in the QASM file.
        '''

        def __init__(self, name, gate_args, gate_regs):
            self.name = name
            self.gate_args = gate_args
            self.gate_regs = gate_regs
            self.gates_inside = []

    def _get_qiskit_gates():
        '''
        Create and return a dictionary containing custom gates needed
        for "qiskit" mode. These include a subset of gates usually defined
        in the file "qelib1.inc".

        Returns a dictionary mapping gate names to QuTiP gates.
        '''

        def u2(args):
            return qasmu_gate([np.pi/2, args[0], args[1]])

        def id():
            return qasmu_gate([0, 0, 0])

        def sdg():
            return rz(-1 * np.pi/2)

        def tdg():
            return rz(-1 * np.pi/4)

        def cu3(args):
            return controlled_gate(qasmu_gate(args))

        def ch():
            return controlled_gate(snot())

        return {"ch": ch, "tdg": tdg, "id": id, "u2": u2, "sdg": sdg, "cu3": cu3}

    def _tokenize_line(command):
        '''
        Tokenize (break into several parts a string of) a single line of QASM code.

        Parameters
        ----------
        command : str
            One line of QASM code to be broken into "tokens".

        Returns
        -------
        tokens : list of str
            The tokens (parts) corresponding to the qasm line taken as input.
        '''

        # for gates without arguments
        if "(" not in command:
            tokens = list(chain(*[a.split() for a in command.split(",")]))
            tokens = [token.strip() for token in tokens]
        # for classically controlled gates
        elif re.match(r"\s*if\s*\(", command):
            groups = re.match(r"\s*if\s*\((.*)\)\s*(.*)\s+\((.*)\)(.*)", command)
            # for classically controlled gates with arguments
            if groups:
                tokens = ["if", "(", groups.group(1), ")"]
                tokens_gate = _tokenize_line("{} ({}) {}".format(groups.group(2),
                                                                 groups.group(3),
                                                                 groups.group(4)))
                tokens += tokens_gate
            # for classically controlled gates without arguments
            else:
                groups = re.match(r"\s*if\s*\((.*)\)(.*)", command)
                tokens = ["if", "(", groups.group(1), ")"]
                tokens_gate = _tokenize_line(groups.group(2))
                tokens += tokens_gate
            tokens = [token.strip() for token in tokens]
        # for gates with arguments
        else:
            groups = re.match(r"(^.*?)\((.*)\)(.*)", command)
            if not groups:
                raise SyntaxError("QASM: Incorrect bracket formatting")
            tokens = groups.group(1).split()
            tokens.append("(")
            tokens += groups.group(2).split(",")
            tokens.append(")")
            tokens += groups.group(3).split(",")
            tokens = [token.strip() for token in tokens]

        return tokens

    def _tokenize(token_cmds):
        '''
        Tokenize QASM code for processing, i.e. break it into several parts.

        Parameters
        ----------
        token_cmds : list of str
            Lines of QASM code.

        Returns
        -------
        tokens : list of (list of str)
            List of tokens corresponding to each QASM line taken as input.
        '''

        processed_commands = []

        for line in token_cmds:

            # carry out some pre-processing for convenience
            for c in "[]()":
                line = line.replace(c, " " + c + " ")
            for c in "{}":
                line = line.replace(c, " ; " + c + " ; ")
            line_commands = line.split(";")
            line_commands = list(filter(lambda x: x != "", line_commands))

            for command in line_commands:
                tokens = _tokenize_line(command)
                processed_commands.append(tokens)

        return list(filter(lambda x: x != [], processed_commands))

    def _gate_processor(command):
        '''
        Process tokens for a gate call statement separating them into args and regs.
        Processes tokens from a "gate call" (e.g. rx(pi) q[0]) and returns the
        tokens for the arguments and registers separately.
        '''

        gate_args = []
        gate_regs = []
        tokens = command[1:]
        reg_start = 0

        # extract arguments
        if "(" in tokens and ")" in tokens:
            bopen = tokens.index("(")
            bclose = tokens.index(")")
            gate_args = tokens[bopen+1:bclose]
            reg_start = bclose+1

        # extract registers
        gate_regs = tokens[reg_start:]

        return gate_args, gate_regs

    class QasmProcessor:
        '''
        Class which holds variables used in processing QASM code.
        '''

        def __init__(self, commands, mode="qiskit", version="2.0"):
            self.qubit_regs = {}
            self.cbit_regs = {}
            self.num_qubits = 0
            self.num_cbits = 0
            self.qasm_gates = {}
            self.mode = mode
            self.version = version
            self.predefined_gates = set(["CX", "U"])

            if self.mode == "qiskit":
                self.qiskitgates = set(["u3", "u2", "u1", "cx",  "id", "x", "y",
                                        "z", "h", "s", "sdg", "t", "tdg", "rx",
                                        "ry", "rz", "cz", "cy", "ch", "ccx", "crz",
                                        "cu1", "cu3"])
                self.predefined_gates = self.predefined_gates.union(self.qiskitgates)

            self.gate_names = deepcopy(self.predefined_gates)
            for gate in self.predefined_gates:
                self.qasm_gates[gate] = QasmGate("U",
                                                 ["alpha", "beta", "gamma"],
                                                 ["q"])
            self.commands = commands

        def _process_includes(self):
            '''
            QASM allows for code to be specified in additional files with the
            ".inc" extension, especially to specify gate definitions in terms of
            the built-in gates. Process into tokens all the
            additional files and insert it into previously processed list.
            '''

            prev_index = 0
            expanded_commands = []

            for curr_index, command in enumerate(self.commands):

                if command[0] != "include":
                    continue

                filename = command[1].strip('"')

                if self.mode == "qiskit" and filename == "qelib1.inc":
                    continue

                if os.path.exists(filename):
                    with open(filename, "r") as f:
                        qasm_lines = [line.strip() for line
                                      in f.read().splitlines()]
                        qasm_lines = list(filter(
                                          lambda x: x[:2] != "//" and x != "",
                                          qasm_lines))

                        expanded_commands = (expanded_commands
                                             + command[prev_index:curr_index]
                                             + _tokenize(qasm_lines))
                        prev_index = curr_index + 1
                else:
                    raise ValueError(command[1] + ": such a file does not exist")

            expanded_commands += self.commands[prev_index:]
            self.commands = expanded_commands

        def _initialize_pass(self):
            '''
            Passes through the tokenized commands, create QasmGate objects for
            each user-defined gate, process register declarations.
            '''

            gate_defn_mode = False
            open_bracket_mode = False

            unprocessed = []

            for num, command in enumerate(self.commands):
                if gate_defn_mode:
                    if command[0] == "{":
                        gate_defn_mode = False
                        open_bracket_mode = True
                        gate_elems = []
                        continue
                    else:
                        raise SyntaxError("QASM: incorrect bracket formatting")
                elif open_bracket_mode:
                    if command[0] == "{":
                        raise SyntaxError("QASM: incorrect bracket formatting")
                    elif command[0] == "}":
                        if not curr_gate.gates_inside:
                            raise NotImplementedError("QASM: opaque gate {} are  \
                                                       not allowed, please define \
                                                       or omit \
                                                       them".format(curr_gate.name))
                        open_bracket_mode = False
                        self.gate_names.add(curr_gate.name)
                        self.qasm_gates[curr_gate.name] = curr_gate
                        continue
                    elif command[0] in self.gate_names:
                        name = command[0]
                        gate_args, gate_regs = _gate_processor(command)
                        gate_added = self.qasm_gates[name]
                        curr_gate.gates_inside.append([name,
                                                       gate_args,
                                                       gate_regs])
                elif command[0] == "gate":
                    gate_name = command[1]
                    gate_args, gate_regs = _gate_processor(command[1:])
                    curr_gate = QasmGate(gate_name, gate_args, gate_regs)
                    gate_defn_mode = True

                elif command[0] == "qreg":
                    groups = re.match(r"(.*)\[(.*)\]", "".join(command[1:]))
                    if groups:
                        qubit_name = groups.group(1)
                        num_regs = int(groups.group(2))
                        self.qubit_regs[qubit_name] = list(range(
                                                    self.num_qubits,
                                                    self.num_qubits + num_regs))
                        self.num_qubits += num_regs
                    else:
                        raise SyntaxError("QASM: incorrect bracket formatting")

                elif command[0] == "creg":
                    groups = re.match(r"(.*)\[(.*)\]", "".join(command[1:]))
                    if groups:
                        cbit_name = groups.group(1)
                        num_regs = int(groups.group(2))
                        self.cbit_regs[cbit_name] = list(range(self.num_cbits,
                                                         self.num_cbits + num_regs))
                        self.num_cbits += num_regs
                    else:
                        raise SyntaxError("QASM: incorrect bracket formatting")
                elif command[0] == "reset":
                    raise NotImplementedError(("QASM: reset functionality "
                                               "is not supported."))
                elif command[0] in ["barrier", "include"]:
                    continue
                else:
                    unprocessed.append(num)
                    continue

            if open_bracket_mode:
                raise SyntaxError("QASM: incorrect bracket formatting")

            self.commands = [self.commands[i] for i in unprocessed]

        def _custom_gate(self, qc_temp, gate_call):
            '''
            Recursively process a custom-defined gate with specified arguments
            to produce a dummy circuit with all the gates in the custom-defined
            gate.

            Parameters
            ----------

            qc_temp: :class:`.QubitCircuit`
                temporary circuit to process custom gate
            gate_call: list of str
                tokens corresponding to gate signature/call
            '''

            gate_name, args, regs = gate_call
            gate = self.qasm_gates[gate_name]
            args_map = {}
            regs_map = {}

            # maps variables to supplied arguments, registers
            for i, arg in enumerate(gate.gate_args):
                args_map[arg] = eval(str(args[i]))
            for i, reg in enumerate(gate.gate_regs):
                regs_map[reg] = regs[i]
            # process all the constituent gates with supplied arguments, registers
            for call in gate.gates_inside:

                # create function call for the constituent gate
                name, com_args, com_regs = call

                for arg, real_arg in args_map.items():
                    com_args = [command.replace(arg.strip(), str(real_arg))
                                for command in com_args]
                for reg, real_reg in regs_map.items():
                    com_regs = [command.replace(reg.strip(), str(real_reg))
                                for command in com_regs]
                com_args = [eval(arg) for arg in com_args]

                if name in self.predefined_gates:
                    qc_temp.user_gates = _get_qiskit_gates()
                    com_regs = [int(reg) for reg in com_regs]
                    self._add_predefined_gates(qc_temp, name, com_regs, com_args)
                else:
                    self._custom_gate(qc_temp, [name, com_args, com_regs])

        def _regs_processor(self, regs, reg_type):
            '''
            Process register tokens: map them to the :class:`.QubitCircuit` indices
            of the respective registers.

            Parameters
            ----------
            regs : list of str
                Token list corresponding to qubit/cbit register invocations.
            reg_type : str
                reg_type can be "measure" or "gate" to specify type of required
                processing.

            Returns
            -------

            regs list : list of (list of regs)
                    list of register sets to which circuit operations
                    are applied.

            '''

            # turns messy tokens into appropriate form
            # ['q', 'p', '[', '0', ']'] -> ['q', 'p[0]']
            regs = [reg.replace(" ", "") for reg in regs]
            if "[" in regs:
                prev_token = ""
                new_regs = []
                open_bracket_mode = False
                for token in regs:
                    if token == "[":
                        open_bracket_mode = True
                    elif open_bracket_mode:
                        if token == "]":
                            open_bracket_mode = False
                            reg_name = new_regs.pop()
                            new_regs.append(reg_name + "[" + reg_num + "]")
                        elif token.isdigit():
                            reg_num = token
                        else:
                            raise SyntaxError("QASM: incorrect bracket formatting")
                    else:
                        new_regs.append(token)
                if open_bracket_mode:
                    raise SyntaxError("QASM: incorrect bracket formatting")
                regs = new_regs

            if reg_type == "measure":

                # processes register tokens of the form q[i] -> c[i]
                groups = re.match(r"(.*)\[(.*)\]->(.*)\[(.*)\]", "".join(regs))
                if groups:
                    qubit_name = groups.group(1)
                    qubit_ind = int(groups.group(2))
                    qubit_lst = self.qubit_regs[qubit_name]
                    if qubit_ind < len(qubit_lst):
                        qubit = qubit_lst[0] + qubit_ind
                    else:
                        raise ValueError("QASM: qubit index out of bounds")
                    cbit_name = groups.group(3)
                    cbit_ind = int(groups.group(4))
                    cbit_lst = self.cbit_regs[cbit_name]
                    if cbit_ind < len(cbit_lst):
                        cbit = cbit_lst[0] + cbit_ind
                    else:
                        raise ValueError("QASM: cbit index out of bounds")
                    return [(qubit, cbit)]
                # processes register tokens of the form q -> c
                else:
                    qubit_name = regs[0]
                    cbit_name = regs[2]
                    qubits = self.qubit_regs[qubit_name]
                    cbits = self.cbit_regs[cbit_name]
                    if len(qubits) == len(cbits):
                        return zip(qubits, cbits)
                    else:
                        raise ValueError("QASM: qubit and cbit \
                                         register sizes are different")
            else:
                # processes gate tokens to create sets of registers to
                # which the gates are applied.
                new_regs = []
                expand = 0
                for reg in regs:
                    if "[" in reg:
                        groups = re.match(r"(.*)\[(.*)\]", "".join(reg))
                        qubit_name = groups.group(1)
                        qubit_ind = int(groups.group(2))
                        qubit_lst = self.qubit_regs[qubit_name]
                        if qubit_ind < len(qubit_lst):
                            qubit = qubit_lst[0] + qubit_ind
                    else:
                        qubit_name = reg
                        qubit = self.qubit_regs[qubit_name]
                        expand = len(qubit)
                    new_regs.append(qubit)
                if expand:
                    return zip(*list(map(
                            lambda x: x if isinstance(x, list) else [x] * expand,
                            new_regs)))
                else:
                    return [new_regs]

        def _add_qiskit_gates(self, qc, name, regs, args=None,
                              classical_controls=None, control_value=None):
            """
            Add any gates that are pre-defined in qiskit-style exported
            qasm file with included "qelib1.inc".

            Parameters
            ----------
            qc : :class:`.QubitCircuit`
                the circuit to which the gate is added.
            name : str
                name of gate to be added.
            regs : list of int
                list of qubit register indices to add gates to.
            args : float, optional
                value of args supplied to the gate.
            classical_controls : list of int, optional
                indices of classical bits to control gate on.
            control_value : int, optional
                value of classical bits to control on, the classical controls are
                interpreted as an integer with lowest bit being the first one.
                If not specified, then the value is interpreted to be
                2 ** len(classical_controls) - 1
                (i.e. all classical controls are 1).
            """

            gate_name_map_1q = {"x": "X", "y": "Y", "z": "Z", "h": "SNOT",
                                "t": "T", "s": "S", "sdg": "sdg", "tdg": "tdg",
                                "rx": "RX", "ry": "RY", "rz": "RZ"}
            if len(args) == 0:
                args = None
            elif len(args) == 1:
                args = args[0]

            if name == "u3":
                qc.add_gate("QASMU", targets=regs[0], arg_value=args,
                            classical_controls=classical_controls,
                            control_value=control_value)
            elif name == "u2":
                qc.add_gate("u2", targets=regs[0], arg_value=args,
                            classical_controls=classical_controls,
                            control_value=control_value)
            elif name == "u1":
                qc.add_gate("RZ", targets=regs[0], arg_value=args,
                            classical_controls=classical_controls,
                            control_value=control_value)
            elif name == "cz":
                qc.add_gate("CZ", targets=regs[1], controls=regs[0],
                            classical_controls=classical_controls,
                            control_value=control_value)
            elif name == "cy":
                qc.add_gate("CY", targets=regs[1], controls=regs[0],
                            classical_controls=classical_controls,
                            control_value=control_value)
            elif name == "ch":
                qc.add_gate("ch", targets=regs,
                            classical_controls=classical_controls,
                            control_value=control_value)
            elif name == "ccx":
                qc.add_gate("TOFFOLI", targets=regs[2], controls=regs[:2],
                            classical_controls=classical_controls,
                            control_value=control_value)
            elif name == "crz":
                qc.add_gate("CRZ", targets=regs[1], controls=regs[0],
                            arg_value=args,
                            classical_controls=classical_controls,
                            control_value=control_value)
            elif name == "cu1":
                qc.add_gate("CPHASE", targets=regs[1], controls=regs[0],
                            arg_value=args,
                            classical_controls=classical_controls,
                            control_value=control_value)
            elif name == "cu3":
                qc.add_gate("cu3", targets=[regs[0], regs[1]],
                            arg_value=args,
                            classical_controls=classical_controls,
                            control_value=control_value)
            if name == "cx":
                qc.add_gate("CNOT",  targets=int(regs[1]), controls=int(regs[0]),
                            classical_controls=classical_controls,
                            control_value=control_value)
            elif name in gate_name_map_1q:
                if args == []:
                    args = None
                qc.add_gate(gate_name_map_1q[name], targets=regs[0], arg_value=args,
                            classical_controls=classical_controls,
                            control_value=control_value)

        def _add_predefined_gates(self, qc, name, com_regs, com_args,
                                  classical_controls=None, control_value=None):
            """
            Add any gates that are pre-defined and/or inbuilt
            in our circuit.

            Parameters
            ----------
            qc : :class:`.QubitCircuit`
                the circuit to which the gate is added.
            name : str
                name of gate to be added.
            regs : list of int
                list of qubit register indices to add gates to.
            args : float, optional
                value of args supplied to the gate.
            classical_controls : list of int, optional
                indices of classical bits to control gate on.
            control_value : int, optional
                value of classical bits to control on, the classical controls are
                interpreted as an integer with lowest bit being the first one.
                If not specified, then the value is interpreted to be
                2 ** len(classical_controls) - 1
                (i.e. all classical controls are 1).
            """

            if name == "CX":
                qc.add_gate("CNOT",
                            targets=int(com_regs[1]),
                            controls=int(com_regs[0]),
                            classical_controls=classical_controls,
                            control_value=control_value)
            elif name == "U":
                qc.add_gate("QASMU",
                            targets=int(com_regs[0]),
                            arg_value=[float(arg) for arg in com_args],
                            classical_controls=classical_controls,
                            control_value=control_value)
            elif name in self.qiskitgates and self.mode == "qiskit":
                self._add_qiskit_gates(qc, name, com_regs, com_args,
                                       classical_controls, control_value)

        def _gate_add(self, qc, command, custom_gates,
                      classical_controls=None, control_value=None):
            '''
            Add gates to :class:`.QubitCircuit` from processed tokens,
            define custom gates if necessary.

            Parameters
            ----------
            qc: :class:`.QubitCircuit`
                circuit object to which gate is added
            command: list of str
                list of tokens corresponding to gate application
            custom_gates: {gate name : gate function or unitary}
                dictionary of user gates defined for qutip
            classical_controls : int or list of int, optional
                indices of classical bits to control gate on.
            control_value : int, optional
                value of classical bits to control on, the classical controls are
                interpreted as an integer with lowest bit being the first one.
                If not specified, then the value is interpreted to be
                2 ** len(classical_controls) - 1
                (i.e. all classical controls are 1).
            '''

            args, regs = _gate_processor(command)
            reg_set = self._regs_processor(regs, "gate")

            if args:
                gate_name = "{}({})".format(command[0], ",".join(args))
            else:
                gate_name = "{}".format(command[0])

            # creates custom-gate (if required) using gate defn and provided args
            if (command[0] not in self.predefined_gates
                    and command[0] not in custom_gates):
                n = len(reg_set[0])
                qc_temp = QubitCircuit(n)
                self._custom_gate(qc_temp,
                                  [command[0], args, [str(i) for i in range(n)]])
                unitary_mat = gate_sequence_product(qc_temp.propagators())
                custom_gates[gate_name] = unitary_mat

            qc.user_gates = custom_gates

            # adds gate to the QubitCircuit
            for regs in reg_set:
                regs = [int(i) for i in regs]
                if command[0] in self.predefined_gates:
                    args = [eval(arg) for arg in args]
                    self._add_predefined_gates(
                                        qc,
                                        command[0],
                                        regs,
                                        args,
                                        classical_controls=classical_controls,
                                        control_value=control_value)
                else:
                    if not isinstance(regs, list):
                        regs = [regs]
                    qc.add_gate(gate_name,
                                targets=regs,
                                classical_controls=classical_controls,
                                control_value=control_value)

        def _final_pass(self, qc):
            '''
            Take a blank circuit, add all the gates and measurements specified
            by QASM.
            '''

            custom_gates = {}
            if self.mode == "qiskit":
                custom_gates = _get_qiskit_gates()

            for command in self.commands:
                if command[0] in self.gate_names:
                    # adds gates to the QubitCircuit
                    self._gate_add(qc, command, custom_gates)
                elif command[0] == "measure":
                    # adds measurement to the QubitCircuit
                    reg_set = self._regs_processor(command[1:], "measure")
                    for regs in reg_set:
                        qc.add_measurement("M", targets=[regs[0]],
                                           classical_store=regs[1])
                elif command[0] == "if":
                    warnings.warn(("Information about individual registers"
                                  " is not preserved in QubitCircuit"))
                    # adds classically controlled gates to the QubitCircuit
                    cbit_reg, control_value = command[2].split("==")
                    cbit_inds = self.cbit_regs[cbit_reg]
                    control_value = int(control_value)
                    self._gate_add(qc, command[4:], custom_gates,
                                   cbit_inds, control_value)
                else:
                    err = "QASM: {} is not a valid QASM command.".format(command[0])
                    raise SyntaxError(err)

    def read_qasm(qasm_input, mode="qiskit", version="2.0", strmode=False):
        '''
        Read OpenQASM intermediate representation
        (https://github.com/Qiskit/openqasm) and return
        a :class:`.QubitCircuit` and state inputs as specified in the
        QASM file.

        Parameters
        ----------
        qasm_input : str
            File location or String Input for QASM file to be imported. In case of
            string input, the parameter strmode must be True.
        mode : str
            QASM mode to be read in. When mode is "qiskit",
            the "qelib1.inc" include is automatically included,
            without checking externally. Otherwise, each include is
            processed.
        version : str
            QASM version of the QASM file. Only version 2.0 is currently supported.
        strmode : bool
            if specified as True, indicates that qasm_input is in string format
            rather than from file.

        Returns
        -------
        qc : :class:`.QubitCircuit`
            Returns a :class:`.QubitCircuit` object specified in the QASM file.
        '''

        if strmode:
            qasm_lines = qasm_input.splitlines()
        else:
            f = open(qasm_input, "r")
            qasm_lines = f.read().splitlines()
            f.close()

        # split input into lines and ignore comments
        qasm_lines = [line.strip() for line in qasm_lines]
        qasm_lines = list(filter(lambda x: x[:2] != "//" and x != "", qasm_lines))

        if version != "2.0":
            raise NotImplementedError("QASM: Only OpenQASM 2.0 \
                                      is currently supported.")

        if qasm_lines.pop(0) != "OPENQASM 2.0;":
            raise SyntaxError("QASM: File does not contain QASM 2.0 header")

        qasm_obj = QasmProcessor(qasm_lines, mode=mode, version=version)
        qasm_obj.commands = _tokenize(qasm_obj.commands)

        qasm_obj._process_includes()

        qasm_obj._initialize_pass()
        qc = QubitCircuit(qasm_obj.num_qubits, num_cbits=qasm_obj.num_cbits)

        qasm_obj._final_pass(qc)

        return qc

    _GATE_NAME_TO_QASM_NAME = {
        "QASMU": "U",
        "RX": "rx",
        "RY": "ry",
        "RZ": "rz",
        "SNOT": "h",
        "X": "x",
        "Y": "y",
        "Z": "z",
        "S": "s",
        "T": "t",
        "CRZ": "crz",
        "CNOT": "cx",
        "TOFFOLI": "ccx"
    }

    class QasmOutput():
        """
        Class for QASM export.

        Parameters
        ----------
        version: str, optional
            OpenQASM version, currently must be "2.0" necessarily.
        """

        def __init__(self, version="2.0"):
            self.version = version
            self.lines = []
            self.gate_name_map = deepcopy(_GATE_NAME_TO_QASM_NAME)

        def output(self, line="", n=0):
            '''
            Pipe QASM output string to QasmOutput's lines variable.

            Parameters
            ----------
            line: str, optional
                string to be appended to QASM output.
            n: int, optional
                number of blank lines to be appended to QASM output.
            '''

            if line:
                self.lines.append(line)
            self.lines = self.lines + [""] * n

        def _flush(self):
            '''
            Resets QasmOutput variables.
            '''

            self.lines = []
            self.gate_name_map = deepcopy(_GATE_NAME_TO_QASM_NAME)

        def _qasm_str(self, q_name, q_controls, q_targets, q_args):
            '''
            Returns QASM string for gate definition or gate application given
            name, registers, arguments.
            '''

            if not q_controls:
                q_controls = []
            q_regs = q_controls + q_targets

            if isinstance(q_targets[0], int):
                q_regs = ",".join(['q[{}]'.format(reg) for reg in q_regs])
            else:
                q_regs = ",".join(q_regs)

            if q_args:
                if isinstance(q_args, list):
                    q_args = ",".join([str(arg) for arg in q_args])
                return "{}({}) {};".format(q_name, q_args, q_regs)
            else:
                return "{} {};".format(q_name, q_regs)

        def _qasm_defn_from_resolved(self, curr_gate, gates_lst):
            '''
            Resolve QASM definition of QuTiP gate in terms of component gates.

            Parameters
            ----------
            curr_gate: :class:`.Gate`
                QuTiP gate which needs to be resolved into component gates.
            gates_lst: list of :class:`.Gate`
                list of gate that constitute QASM definition of self.
            '''

            forbidden_gates = ["GLOBALPHASE", "PHASEGATE"]
            reg_map = ['a', 'b', 'c']

            q_controls = None
            if curr_gate.controls:
                q_controls = [reg_map[i] for i in curr_gate.controls]
            q_targets = [reg_map[i] for i in curr_gate.targets]
            arg_name = None
            if curr_gate.arg_value:
                arg_name = "theta"

            self.output("gate {} {{".format(self._qasm_str(curr_gate.name.lower(),
                                                           q_controls,
                                                           q_targets,
                                                           arg_name)[:-1]))

            for gate in gates_lst:
                if gate.name in self.gate_name_map:
                    gate.targets = [reg_map[i] for i in gate.targets]
                    if gate.controls:
                        gate.controls = [reg_map[i] for i in gate.controls]
                    self.output(self._qasm_str(
                                    self.gate_name_map[gate.name],
                                    gate.controls,
                                    gate.targets,
                                    gate.arg_value))
                elif gate.name in forbidden_gates:
                    continue
                else:
                    raise ValueError(("The given resolved gate {} cannot be defined"
                                      " in QASM format").format(curr_gate.name))
            self.output("}")

        def _qasm_defn_resolve(self, gate):
            '''
            Resolve QASM definition of QuTiP gate if possible.

            Parameters
            ----------
            gate: :class:`.Gate`
                QuTiP gate which needs to be resolved into component gates.

            '''

            qc = QubitCircuit(3)
            gates_lst = []
            if gate.name == "CSIGN":
                qc._gate_CSIGN(gate, gates_lst)
            else:
                err_msg = "No definition specified for {} gate".format(gate.name)
                raise NotImplementedError(err_msg)

            self._qasm_defn_from_resolved(gate, gates_lst)
            self.gate_name_map[gate.name] = gate.name.lower()

        def _qasm_defns(self, gate):
            '''
            Define QASM gates for QuTiP gates that do not have QASM counterparts.

            Parameters
            ----------
            gate: :class:`.Gate`
                QuTiP gate which needs to be defined in QASM format.
            '''

            if gate.name == "CRY":
                gate_def = "gate cry(theta) a,b { cu3(theta,0,0) a,b; }"
            elif gate.name == "CRX":
                gate_def = "gate crx(theta) a,b { cu3(theta,-pi/2,pi/2) a,b; }"
            elif gate.name == "SQRTNOT":
                gate_def = "gate sqrtnot a {h a; u1(-pi/2) a; h a; }"
            elif gate.name == "CS":
                gate_def = "gate cs a,b { cu1(pi/2) a,b; }"
            elif gate.name == "CT":
                gate_def = "gate ct a,b { cu1(pi/4) a,b; }"
            elif gate.name == "SWAP":
                gate_def = "gate swap a,b { cx a,b; cx b,a; cx a,b; }"
            else:
                self._qasm_defn_resolve(gate)
                return

            self.output("// QuTiP definition for gate {}".format(gate.name))
            self.output(gate_def)
            self.gate_name_map[gate.name] = gate.name.lower()

        def qasm_name(self, gate_name):
            '''
            Return QASM gate name for corresponding QuTiP gate.

            Parameters
            ----------
            gate_name: str
                QuTiP gate name.
            '''

            if gate_name in self.gate_name_map:
                return self.gate_name_map[gate_name]
            else:
                return None

        def is_defined(self, gate_name):
            '''
            Check if QASM gate definition exists for QuTiP gate.

            Parameters
            ----------
            gate_name: str
                QuTiP gate name.
            '''

            return gate_name in self.gate_name_map

        def _qasm_output(self, qc):
            '''
            QASM output handler.

            Parameters
            ----------
            qc: :class:`.QubitCircuit`
                circuit object to produce QASM output for.
            '''

            self._flush()

            self.output("// QASM 2.0 file generated by QuTiP", 1)

            if self.version == "2.0":
                self.output("OPENQASM 2.0;")
            else:
                raise NotImplementedError("QASM: Only OpenQASM 2.0 \
                                          is currently supported.")

            self.output('include "qelib1.inc";', 1)

            qc._to_qasm(self)

            return self.lines

    def print_qasm(qc):
        '''
        Print QASM output of circuit object.

        Parameters
        ----------
        qc: :class:`.QubitCircuit`
            circuit object to produce QASM output for.
        '''

        qasm_out = QasmOutput("2.0")
        lines = qasm_out._qasm_output(qc)
        for line in lines:
            print(line)

    def circuit_to_qasm_str(qc):
        '''
        Return QASM output of circuit object as string

        Parameters
        ----------
        qc: :class:`.QubitCircuit`
            circuit object to produce QASM output for.

        Returns
        -------
        output: str
            string corresponding to QASM output.
        '''

        qasm_out = QasmOutput("2.0")
        lines = qasm_out._qasm_output(qc)
        output = ""
        for line in lines:
            output += line + "\n"
        return output

    def save_qasm(qc, file_loc):
        '''
        Save QASM output of circuit object to file.

        Parameters
        ----------
        qc: :class:`.QubitCircuit`
            circuit object to produce QASM output for.
        '''

        qasm_out = QasmOutput("2.0")
        lines = qasm_out._qasm_output(qc)
        with open(file_loc, "w") as f:
            for line in lines:
                f.write("{}\n".format(line))