qpe_toolbox.circuit.plot_circuits ================================= .. py:module:: qpe_toolbox.circuit.plot_circuits Functions --------- .. autoapisummary:: qpe_toolbox.circuit.plot_circuits.assign_sublayers_per_round qpe_toolbox.circuit.plot_circuits.assign_sublayers qpe_toolbox.circuit.plot_circuits.draw_2_qubit_layer qpe_toolbox.circuit.plot_circuits.draw_1_qubit_layer qpe_toolbox.circuit.plot_circuits.draw_init_product_state qpe_toolbox.circuit.plot_circuits.draw_layered_circuit qpe_toolbox.circuit.plot_circuits.build_reverse_light_cone_circuit qpe_toolbox.circuit.plot_circuits.draw_layered_expval Module Contents --------------- .. py:function:: assign_sublayers_per_round(circ, gate_round) Assign non-overlapping two-qubit gates of a given circuit round to sublayers for plotting. This function groups all two-qubit gates acting in a given entangling layer (``gate_round``) into sublayers, such that no two gates within the same sublayer act on overlapping qubit intervals when the circuit is plotted in a 1D layout. For example, in QAOA: :math:`U_x U_{zz} \langle\Psi\rangle \rightarrow U_{zz}` may include arbitrarily long-range two-qubit gates spanning on overlapping register lines The sublayers are constructed greedily by sorting gates by their qubit intervals and placing each gate in the earliest compatible sublayer. :param circ: Quantum circuit. :type circ: :quimb-api:`Circuit` :param gate_round: Circuit round for which the sublayers are constructed. :type gate_round: int :returns: * **dict_gates_to_sublayers** (*dict*) -- Mapping from the two-qubit gates in a depth/round/layer (represented as an ordered qubit pair ``(i, j)`` with ``i < j``) to the index of the sublayer it is assigned to. The overall structure is ``dict[tuple[int, int], int]`` corresponding to ``dict_mappings[tuple[qubit1, qubit2], sublayer_ind]``. * **list_sublayers** (*list*) -- List of sublayers for the given depth/round/layer. Each element of the list corresponds to one circuit layer, and contains a list of sublayers, where each sublayer is represented as ``(sublayer_index, gates)``; ``gates`` is a list of two-qubit edges ``(i, j)``. The overall structure is ``list[tuple[int, list[tuple[int, int]]]]``, corresponding to ``list_sublayers[tuple[sublayer_end, list[tuple[qubit1,qubit2]]]]``. ``sublayer_end`` refers to the largest qubit index occupied in the sublayer. .. rubric:: Notes - Only two-qubit gates (``len(gate.qubits) == 2``) are considered. - Gates are treated as closed intervals ``[i, j]`` on the qubit line. - The algorithm is greedy and does not guarantee a minimum number of sublayers, but is sufficient for circuit plotting. - This function assumes that the full circuit is being plotted. .. py:function:: assign_sublayers(circ) Assign non-overlapping two-qubit gates to sublayers across all circuit depths. :param circ: Quantum circuit. :type circ: :quimb-api:`Circuit` :returns: * **list_dict_gates_to_sublayers** (*list*) -- List of mappings from the two-qubit gates in a depth/round/layer (represented as an ordered qubit pair ``(i, j)`` with ``i < j``) to the index of the sublayer it is assigned to. The overall structure is ``list[dict[tuple[int, int], int]]`` corresponding to ``list_layers[dict_mappings[tuple[qubit1, qubit2], sublayer_ind]]``. * **list_sublayers** (*list*) -- Nested list of sublayers organized by circuit depth. When we refer to depth, we also refer to round or layer indistinctly. Each element of the list corresponds to one circuit layer, and contains a list of sublayers, where each sublayer is represented as ``(sublayer_index, gates)``; ``gates`` is a list of two-qubit edges ``(i, j)``. The overall structure is ``list[list[tuple[int, list[tuple[int, int]]]]]``, corresponding to ``list_layers[list_sublayers[tuple[sublayer_edge, list[tuple[qubit1,qubit2]]]]]``. .. py:function:: draw_2_qubit_layer(ax, n_qubits, X, sublayers, dict_sublayer, gate_label, fontsize, col_face, active_qubits, *, reverse=False) Draw a two-qubit gate layer with sublayer structure on a Matplotlib Axes. This function visualizes a layer of two-qubit gates, which are arranged horizontally according to their assigned sublayer to avoid overlaps. :param ax: Axes object on which the layer is drawn. :type ax: :matplotlib-api:`axes.Axes` :param n_qubits: Total number of qubits in the circuit. Used to position the layer label. :type n_qubits: int :param X: Horizontal offset for the start of this layer in ``ax``. :type X: float :param sublayers: List of sublayers. Each entry is expected to be a tuple of the form ``(last_end, list_of_gate_pairs)``, where ``list_of_gate_pairs`` contains tuples ``(i, j)`` of qubit indices acted on by each gate. :type sublayers: list :param dict_sublayer: Mapping from gate qubit pairs ``(i, j)`` to integer sublayer indices. These indices determine the horizontal placement of the gates. :type dict_sublayer: dict :param gate_label: Label for the entire layer (e.g. ``r"$U_{zz}$"``, ``r"CNOT"``), drawn above the qubit register. :type gate_label: str :param fontsize: Font size used for the layer label. :type fontsize: int or float :param col_face: Face color of the square gate markers (Matplotlib-compatible). :type col_face: color :param active_qubits: Indices of qubits on which the gate is applied. Useful when drawing expectation values with unitary cancellation. :type active_qubits: iterable of int :param reverse: If ``True``, reverse the horizontal ordering of the sublayers. This is useful when plotting circuits from right to left, like in an expectation value (see :func:`draw_expval` function). Default is ``False``. :type reverse: bool, optional .. rubric:: Notes - The horizontal position of each gate is ``X + sublayer_index``. .. py:function:: draw_1_qubit_layer(ax, n_qubits, X, gate_label, fontsize, col_face, active_qubits) Draw a single-qubit gate layer on selected qubits. :param ax: Axes object on which the layer is drawn. :type ax: :matplotlib-api:`axes.Axes` :param n_qubits: Total number of qubits in the circuit. :type n_qubits: int :param X: Horizontal position of the gate layer. :type X: float :param gate_label: Label for the gate layer (e.g. ``"$R_y$"``, ``"$U_x$"``), drawn above the qubit register. :type gate_label: str :param fontsize: Font size used for the layer label. :type fontsize: int or float :param col_face: Face color of the square gate markers (Matplotlib-compatible). :type col_face: color :param active_qubits: Indices of qubits on which the gate is applied. Useful when drawing expectation values with unitary cancellation. :type active_qubits: iterable of int .. rubric:: Notes - Only qubits listed in ``active_qubits`` are drawn. .. py:function:: draw_init_product_state(ax, n_qubits, X, state_label, fontsize, col_face, *, is_right_side=False) Draw an initial product state on a circuit diagram. This function visualizes the initial state of each qubit as a labeled circle, optionally placing qubit indices to the left or right. :param ax: Axes object on which the initial state is drawn. :type ax: :matplotlib-api:`axes.Axes` :param n_qubits: Total number of qubits. :type n_qubits: int :param X: Horizontal offset for the initial state drawing. :type X: float :param state_label: Label for the qubit state (e.g. ``"$0$"``, ``"$+$"``). :type state_label: str :param fontsize: Font size used for the labels. :type fontsize: int or float :param col_face: Face color of the state circles. :type col_face: color :param is_right_side: Side on which to draw the qubit index labels. Default is left. :type is_right_side: bool, optional .. py:function:: draw_layered_circuit(circ, *, max_depth=np.inf, list_names=None) Draw a layered quantum circuit using Matplotlib. This function visualizes a quantum circuit, ASSUMING it is composed of alternating single-qubit and two-qubit layers. The circuit is drawn left-to-right, and gates placed according to their layer (round) structure. :param circ: Quantum circuit. :type circ: :quimb-api:`Circuit` :param max_depth: Maximum number of circuit layers to draw. Default is inf, the full circuit is drawn. :type max_depth: int or inf, optional :param list_names: Labels used for annotating different parts of the circuit. Expected structure: - ``list_names[0]`` : str Label for the initial product state. - ``list_names[1]`` : list of str Labels for single-qubit layers, one per circuit layer. e.g. for QAOA: ``[f"$\mathrm{{R_x^{{({i})}} }}$" for i in range(1, p + 1)]`` where ``p`` is the depth of the Ansatz and ``i`` indicates the layer. - ``list_names[2]`` : list of str Labels for two-qubit layers, one per circuit layer. :type list_names: list, optional :returns: **fig** -- Figure showing the layered circuit diagram. :rtype: :matplotlib-api:`figure.Figure` .. py:function:: build_reverse_light_cone_circuit(selected_edge, circ) Extract the reverse light-cone circuit around a selected two-qubit interaction edge. The input circuit must be made of one- and two-qubit gates only (as e.g. QAOA) .. math:: U_1 U_{\mathrm{ent}} U_1 U_{\mathrm{ent}} \cdots |\text{initial product state}\rangle This function extracts the light cone of a selected two-qubit interaction term (Pauli string with weight 2) from a full circuit and reconstructs it as an explicit :quimb-api:`Circuit` instance. The resulting circuit contains only the gates that causally influence the selected edge, ordered by their round. The reconstruction is performed by parsing tensor tags from the reverse light-cone TN representation and re-applying the corresponding single- and two-qubit gates to a new circuit. :param selected_edge: The edge (pair of qubit indices) for which the light cone is constructed. :type selected_edge: tuple[int, int] :param circ: Quantum circuit. :type circ: :quimb-api:`Circuit` :returns: **circ_revlc** -- A new circuit containing only the gates in the reverse light cone of ``selected_edge``, acting on the same number of qubits as ``circ``. :rtype: :quimb-api:`Circuit` .. rubric:: Notes - Gate information is recovered from tensor tags. - Gate parameters are set to zero when reconstructing the circuit, as the function is intended for structural and visualization purposes rather than numerical simulation. .. py:function:: draw_layered_expval(selected_edge, circ, *, list_names=None, commutation=True) Draw the tensor-network representation of an expectation value. .. math:: \langle \Psi | U^\dagger O_{\text{edge}} U | \Psi \rangle This function visualizes the light-cone structure of a quantum circuit, ASSUMING that it consists on layers of single- and two-spin rotations, around a two-site observable. The circuit is split symmetrically around the observable and drawn from the inside out, showing how the light cone grows layer by layer. :param selected_edge: Pair of qubit indices on which the observable acts. :type selected_edge: iterable of int with length 2 :param circ: Quantum circuit. :type circ: :quimb-api:`Circuit` :param list_names: Labels used for annotating the diagram. Expected structure: - ``list_names[0]`` : str Label for the product state. - ``list_names[1]`` : list of str Labels for single-qubit layers (indexed by layer). - ``list_names[2]`` : list of str Labels for two-qubit layers (indexed by layer). :type list_names: list, optional :param commutation: If the entangling gates commute with themselves when overlapping on one qubit (e.g. the RZZ gate), then further simplification is carried out at the level of the active qubits of each layer. :type commutation: bool, optional :returns: **fig** -- Figure showing the tensor-network expectation value diagram. :rtype: :matplotlib-api:`figure.Figure`