Generate the TikZ code for one line of the circuit up to a certain
        gate.

        It modifies the circuit to include only the gates which have not been
        drawn. It automatically switches to other lines if the gates on those
        lines have to be drawn earlier.

        :param int line: Line to generate the TikZ code for.
        :param Program circuit: The circuit to draw.
        :param int end: Gate index to stop at (for recursion).
        :return:TikZ code representing the current qubit line and, if it was
         necessary to draw other lines, those lines as well.
        :rtype: string

def to_tikz(self, line, circuit, end=None):
        """
        Generate the TikZ code for one line of the circuit up to a certain
        gate.

        It modifies the circuit to include only the gates which have not been
        drawn. It automatically switches to other lines if the gates on those
        lines have to be drawn earlier.

        :param int line: Line to generate the TikZ code for.
        :param Program circuit: The circuit to draw.
        :param int end: Gate index to stop at (for recursion).
        :return:TikZ code representing the current qubit line and, if it was
         necessary to draw other lines, those lines as well.
        :rtype: string
        """
        if end is None:
            end = len(circuit[line])
        tikz_code = []
        cmds = circuit[line]
        for i in range(0, end):
            gate = cmds[i].gate
            lines = cmds[i].lines
            ctrl_lines = cmds[i].ctrl_lines
            all_lines = list(lines)
            all_lines.remove(line)
            for l in all_lines:
                gate_idx = 0
                while not (circuit[l][gate_idx] == cmds[i]):
                    gate_idx += 1
                tikz_code.append(self.to_tikz(l, circuit, gate_idx))

                # We remove the first element of the current line, since we have processed it.
                circuit[l] = circuit[l][1:]
            all_lines = cmds[i].target_lines + cmds[i].ctrl_lines
            pos = max([self.pos[l] for l in range(min(all_lines),
                                                  max(all_lines) + 1)])
            for l in range(min(all_lines), max(all_lines) + 1):
                self.pos[l] = pos + self._gate_pre_offset(gate)

            connections = ""
            for l in all_lines:
                connections += self._line(self.op_count[l] - 1, self.op_count[l], line=l)
            add_str = ""
            if gate == X:
                # draw NOT-gate with controls
                add_str = self._x_gate(cmds[i].target_lines, ctrl_lines)
                # and make the target qubit quantum if one of the controls is
                if not self.is_quantum[lines[0]]:
                    if sum([self.is_quantum[i] for i in ctrl_lines]) > 0:
                        self.is_quantum[lines[0]] = True
            elif gate == Z and len(ctrl_lines) > 0:
                add_str = self._cz_gate(lines + ctrl_lines)
            elif gate == SWAP:
                add_str = self._swap_gate(lines, ctrl_lines)
            elif gate == MEASURE:
                # draw measurement gate
                for l in lines:
                    op = self._op(l)
                    width = self._gate_width(MEASURE)
                    height = self._gate_height(MEASURE)
                    shift0 = .07 * height
                    shift1 = .36 * height
                    shift2 = .1 * width
                    add_str += ("\n\\node[measure,edgestyle] ({op}) at ({pos},-{line}) {{}};\n"
                                "\\draw[edgestyle] ([yshift=-{shift1}cm,xshift={shift2}cm]{op}.west)"
                                " to [out=60,in=180] ([yshift={shift0}cm]{op}."
                                "center) to [out=0, in=120] ([yshift=-{shift1}"
                                "cm,xshift=-{shift2}cm]{op}.east);\n"
                                "\\draw[edgestyle] ([yshift=-{shift1}cm]{op}."
                                "center) to ([yshift=-{shift2}cm,xshift=-{shift1}cm]{op}.north east);").format(
                        op=op, pos=self.pos[l], line=l, shift0=shift0, shift1=shift1, shift2=shift2)
                    self.op_count[l] += 1
                    self.pos[l] += (self._gate_width(gate) + self._gate_offset(gate))
                    self.is_quantum[l] = False
            elif gate == ALLOCATE:
                # Draw 'begin line'.
                add_str = "\n\\node[none] ({}) at ({},-{}) {{$\\Ket{{0}}{}$}};"
                id_str = ""
                if self.settings['gates']['AllocateQubitGate']['draw_id']:
                    id_str = "^{{\\textcolor{{red}}{{{}}}}}".format(cmds[i].id)
                add_str = add_str.format(self._op(line), self.pos[line], line,
                                         id_str)
                self.op_count[line] += 1
                self.pos[line] += (self._gate_offset(gate) + self._gate_width(gate))
                self.is_quantum[line] = self.settings['lines']['init_quantum']
            else:
                # Regular gate must draw the lines it does not act upon.
                # If it spans multiple qubits.
                add_str = self._regular_gate(gate, lines, ctrl_lines, cmds[i].target_lines)
                for l in lines:
                    self.is_quantum[l] = True
            tikz_code.append(add_str)
            if not gate == ALLOCATE:
                tikz_code.append(connections)
        circuit[line] = circuit[line][end:]
        return "".join(tikz_code)