§
    º³Ùg–(  ã                  óh   — d Z ddlmZ ddlmZ ddlmZ ddlmZm	Z	 ddl
mZmZ  G d„ d¦  «        Zd	S )
a¡  
Channel event manager for pulse schedules.

This module provides a `ChannelEvents` class that manages a series of instructions for a
pulse channel. Channel-wise filtering of the pulse program makes
the arrangement of channels easier in the core drawer function.
The `ChannelEvents` class is expected to be called by other programs (not by end-users).

The `ChannelEvents` class instance is created with the class method ``load_program``:

.. code-block:: python

    event = ChannelEvents.load_program(sched, DriveChannel(0))

The `ChannelEvents` is created for a specific pulse channel and loosely assorts pulse
instructions within the channel with different visualization purposes.

Phase and frequency related instructions are loosely grouped as frame changes.
The instantaneous value of those operands are combined and provided as ``PhaseFreqTuple``.
Instructions that have finite duration are grouped as waveforms.

The grouped instructions are returned as an iterator by the corresponding method call:

.. code-block:: python

    for t0, frame, instruction in event.get_waveforms():
        ...

    for t0, frame_change, instructions in event.get_frame_changes():
        ...

The class method ``get_waveforms`` returns the iterator of waveform type instructions with
the ``PhaseFreqTuple`` (frame) at the time when instruction is issued.
This is because a pulse envelope of ``Waveform`` may be modulated with a
phase factor $exp(-i \omega t - \phi)$ with frequency $\omega$ and phase $\phi$ and
appear on the canvas. Thus, it is better to tell users in which phase and frequency
the pulse envelope is modulated from a viewpoint of program debugging.

On the other hand, the class method ``get_frame_changes`` returns a ``PhaseFreqTuple`` that
represents a total amount of change at that time because it is convenient to know
the operand value itself when we debug a program.

Because frame change type instructions are usually zero duration, multiple instructions
can be issued at the same time and those operand values should be appropriately
combined. In Qiskit Pulse we have set and shift type instructions for the frame control,
the set type instruction will be converted into the relevant shift amount for visualization.
Note that these instructions are not interchangeable and the order should be kept.
For example:

.. code-block:: python

    sched1 = Schedule()
    sched1 = sched1.insert(0, ShiftPhase(-1.57, DriveChannel(0))
    sched1 = sched1.insert(0, SetPhase(3.14, DriveChannel(0))

    sched2 = Schedule()
    sched2 = sched2.insert(0, SetPhase(3.14, DriveChannel(0))
    sched2 = sched2.insert(0, ShiftPhase(-1.57, DriveChannel(0))

In this example, ``sched1`` and ``sched2`` will have different frames.
On the drawer canvas, the total frame change amount of +3.14 should be shown for ``sched1``,
while ``sched2`` is +1.57. Since the `SetPhase` and the `ShiftPhase` instruction behave
differently, we cannot simply sum up the operand values in visualization output.

It should be also noted that zero duration instructions issued at the same time will be
overlapped on the canvas. Thus it is convenient to plot a total frame change amount rather
than plotting each operand value bound to the instruction.
é    )Úannotations)Údefaultdict)ÚIterator)ÚpulseÚcircuit)ÚPhaseFreqTupleÚPulseInstructionc                  ó  — e Zd ZdZej        j        ej        j        ej        j        fZ	ej        j
        ej        j        ej        j        ej        j        fZdd„Zedd„¦   «         Zdd„Zdd„Zdd„Zed d„¦   «         ZdS )!ÚChannelEventszChannel event manager.Ú	waveformsúdict[int, pulse.Instruction]Úframesú"dict[int, list[pulse.Instruction]]Úchannelúpulse.channels.Channelc                óZ   — || _         || _        || _        d| _        d| _        d| _        dS )a  Create new event manager.

        Args:
            waveforms: List of waveforms shown in this channel.
            frames: List of frame change type instructions shown in this channel.
            channel: Channel object associated with this manager.
        ç        N)Ú
_waveformsÚ_framesr   Ú_init_phaseÚ_init_frequencyÚ_dt)Úselfr   r   r   s       úZ/granary/edev/quantum/lib/python3.11/site-packages/qiskit/visualization/pulse_v2/events.pyÚ__init__zChannelEvents.__init__h   s8   € ð $ˆŒØˆŒØˆŒð ˆÔØ"ˆÔð ˆŒˆˆó    Úprogramúpulse.Schedulec                óB  — i }t          t          ¦  «        }|                     |g¬¦  «        j        D ]\\  }}t	          || j        ¦  «        r|j        dk    rŒ&|||<   Œ,t	          || j        ¦  «        r||                              |¦  «         Œ]t          |||¦  «        S )a  Load a pulse program represented by ``Schedule``.

        Args:
            program: Target ``Schedule`` to visualize.
            channel: The channel managed by this instance.

        Returns:
            ChannelEvents: The channel event manager for the specified channel.
        )Úchannelsr   )
r   ÚlistÚfilterÚinstructionsÚ
isinstanceÚ_waveform_groupÚdurationÚ_frame_groupÚappendr   )Úclsr   r   r   r   Út0Úinsts          r   Úload_programzChannelEvents.load_program€   s®   € ð ˆ	Ý�TÑ"Ô"ˆð  Ÿš°°	˜Ñ:Ô:ÔGð 	(ð 	(‰HˆB�Ý˜$ Ô 3Ñ4Ô4ð (Ø”= AÒ%Ð%àØ $�	˜"‘�Ý˜D #Ô"2Ñ3Ô3ð (Ø�r”
×!Ò! $Ñ'Ô'Ð'øå˜Y¨°Ñ8Ô8Ð8r   ÚdtÚfloatÚinit_frequencyÚ
init_phasec                ó<   — |pd| _         |pd| _        |pd| _        dS )zºSetup system status.

        Args:
            dt: Time resolution in sec.
            init_frequency: Modulation frequency in Hz.
            init_phase: Initial phase in rad.
        g      ð?r   N)r   r   r   )r   r-   r/   r0   s       r   Ú
set_configzChannelEvents.set_configš   s/   € ð �9˜ˆŒØ-Ð4°ˆÔØ%Ð,¨ˆÔÐÐr   ÚreturnúIterator[PulseInstruction]c              #  óÌ  K  — t          | j                             ¦   «         d„ d¬¦  «        }t          | j                             ¦   «         d„ ¬¦  «        }| j        }| j        }|D �]|\  }}d}t          |¦  «        dk    rn|d         d         |k    r\|                     ¦   «         \  }}	t           	                    |	||¬	¦  «        \  }}t          |¦  «        dk    r|d         d         |k    °\t          |t          j        ¦  «        r1t          |                     d
„ |j        D ¦   «         ¦  «        ¦  «        }t          |t          j        ¦  «        r1t          |                     d„ |j        D ¦   «         ¦  «        ¦  «        }t!          ||¦  «        }
t          |t"          j        ¦  «        r|j                             ¦   «         }t)          || j        |
||¦  «        V — �Œ~dS )z-Return waveform type instructions with frame.c                ó   — | d         S ©Nr   © ©Úxs    r   ú<lambda>z-ChannelEvents.get_waveforms.<locals>.<lambda>¨   ó
   € È!ÈAÌ$€ r   T)ÚkeyÚreversec                ó   — | d         S r7   r8   r9   s    r   r;   z-ChannelEvents.get_waveforms.<locals>.<lambda>©   s
   € ÈÈ1Ì€ r   ©r=   Fr   éÿÿÿÿ©Úframe_changesÚphaseÚ	frequencyc                ó   — i | ]}|d “ŒS ©r   r8   ©Ú.0Úparams     r   ú
<dictcomp>z/ChannelEvents.get_waveforms.<locals>.<dictcomp>¹   ó   € Ð)QÐ)QÐ)Q°u¨%°Ð)QÐ)QÐ)Qr   c                ó   — i | ]}|d “ŒS rG   r8   rH   s     r   rK   z/ChannelEvents.get_waveforms.<locals>.<dictcomp>»   ó   € Ð1]Ð1]Ð1]¸u°%¸Ð1]Ð1]Ð1]r   N)Úsortedr   Úitemsr   r   r   ÚlenÚpopr   Ú_calculate_current_framer$   r   ÚParameterExpressionr.   ÚbindÚ
parametersr   r   ÚPlayÚis_parameterizedr	   r   )r   Úsorted_frame_changesÚsorted_waveformsrD   rE   r*   r+   Ú	is_opaqueÚ_rC   Úframes              r   Úget_waveformszChannelEvents.get_waveforms¦   s÷  è è € å% d¤l×&8Ò&8Ñ&:Ô&:ÀÀÐX\Ð]Ñ]Ô]ÐÝ! $¤/×"7Ò"7Ñ"9Ô"9¸~¸~ÐNÑNÔNÐð Ô ˆØÔ(ˆ	Ø(ð 	Iñ 	I‰HˆB�ØˆIåÐ*Ñ+Ô+¨aÒ/Ð/Ð4HÈÔ4LÈQÔ4OÐSUÒ4UÐ4UØ#7×#;Ò#;Ñ#=Ô#=Ñ ��=Ý#0×#IÒ#IØ"/°uÈ	ð $Jñ $ô $Ñ ��yõ Ð*Ñ+Ô+¨aÒ/Ð/Ð4HÈÔ4LÈQÔ4OÐSUÒ4UÐ4Uõ ˜%¥Ô!<Ñ=Ô=ð TÝ˜eŸjšjÐ)QÐ)QÀÔ@PÐ)QÑ)QÔ)QÑRÔRÑSÔS�Ý˜)¥WÔ%@ÑAÔAð `Ý! )§.¢.Ð1]Ð1]È	ÔH\Ð1]Ñ1]Ô1]Ñ"^Ô"^Ñ_Ô_�	å" 5¨)Ñ4Ô4ˆEõ ˜$¥¤
Ñ+Ô+ð :Ø œJ×7Ò7Ñ9Ô9�	å" 2 t¤x°¸¸iÑHÔHÐHÐHÐHÑHð+	Ið 	Ir   c              #  óh  K  — t          | j                             ¦   «         d„ ¬¦  «        }| j        }| j        }|D ]õ\  }}d}|}|}t
                               |||¬¦  «        \  }}t          ||z
  ||z
  ¦  «        }	t          |t          j
        ¦  «        r3t          |                     d„ |j        D ¦   «         ¦  «        ¦  «        }d}t          |t          j
        ¦  «        r3t          |                     d„ |j        D ¦   «         ¦  «        ¦  «        }d}t          || j        |	||¦  «        V — ŒödS )	zEReturn frame change type instructions with total frame change amount.c                ó   — | d         S r7   r8   r9   s    r   r;   z1ChannelEvents.get_frame_changes.<locals>.<lambda>É   r<   r   r@   FrB   c                ó   — i | ]}|d “ŒS rG   r8   rH   s     r   rK   z3ChannelEvents.get_frame_changes.<locals>.<dictcomp>Û   rL   r   Tc                ó   — i | ]}|d “ŒS rG   r8   rH   s     r   rK   z3ChannelEvents.get_frame_changes.<locals>.<dictcomp>Þ   rN   r   N)rO   r   rP   r   r   r   rS   r   r$   r   rT   r.   rU   rV   r	   r   )
r   rY   rD   rE   r*   rC   r[   Ú	pre_phaseÚpre_frequencyr]   s
             r   Úget_frame_changeszChannelEvents.get_frame_changesÅ   s[  è è € õ  & d¤l×&8Ò&8Ñ&:Ô&:ÀÀÐOÑOÔOÐàÔ ˆØÔ(ˆ	Ø!5ð 	Rð 	RÑˆB�ØˆIàˆIØ%ˆMÝ,×EÒEØ+°5ÀIð  Fñ  ô  ÑˆE�9õ
 # 5¨9Ñ#4°iÀ-Ñ6OÑPÔPˆEõ ˜%¥Ô!<Ñ=Ô=ð !Ý˜eŸjšjÐ)QÐ)QÀÔ@PÐ)QÑ)QÔ)QÑRÔRÑSÔS�Ø �	Ý˜)¥WÔ%@ÑAÔAð !Ý! )§.¢.Ð1]Ð1]È	ÔH\Ð1]Ñ1]Ô1]Ñ"^Ô"^Ñ_Ô_�	Ø �	å" 2 t¤x°¸ÀyÑQÔQÐQÐQÐQÐQð)	Rð 	Rr   rC   ú$list[pulse.instructions.Instruction]rD   rE   útuple[float, float]c                óV  — |D ]£}t          |t          j        j        ¦  «        r|j        }Œ)t          |t          j        j        ¦  «        r||j        z  }ŒSt          |t          j        j        ¦  «        r|j        }Œzt          |t          j        j        ¦  «        r
||j        z  }Œ¤||fS )a   Calculate the current frame from the previous frame.

        If parameter is unbound phase or frequency accumulation with this instruction is skipped.

        Args:
            frame_changes: List of frame change instructions at a specific time.
            phase: Phase of previous frame.
            frequency: Frequency of previous frame.

        Returns:
            Phase and frequency of new frame.
        )	r$   r   r#   ÚSetFrequencyrE   ÚShiftFrequencyÚSetPhaserD   Ú
ShiftPhase)r)   rC   rD   rE   Úframe_changes        r   rS   z&ChannelEvents._calculate_current_frameã   s¯   € ð" *ð 	,ð 	,ˆLÝ˜,­Ô(:Ô(GÑHÔHð ,Ø(Ô2�	�	Ý˜L­%Ô*<Ô*KÑLÔLð ,Ø˜\Ô3Ñ3�	�	Ý˜L­%Ô*<Ô*EÑFÔFð ,Ø$Ô*��Ý˜L­%Ô*<Ô*GÑHÔHð ,Ø˜Ô+Ñ+�øà�iÐÐr   N)r   r   r   r   r   r   )r   r   r   r   )r-   r.   r/   r.   r0   r.   )r3   r4   )rC   rf   rD   r.   rE   r.   r3   rg   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r#   rW   ÚDelayÚAcquirer%   ri   rj   rk   rl   r'   r   Úclassmethodr,   r2   r^   re   rS   r8   r   r   r   r   Y   s  € € € € € Ø Ð ð 	ÔÔØÔÔ ØÔÔ"ð€Oð 	ÔÔ'ØÔÔ)ØÔÔ#ØÔÔ%ð	€Lðð ð ð ð0 ð9ð 9ð 9ñ „[ð9ð2
-ð 
-ð 
-ð 
-ðIð Ið Ið Ið>Rð Rð Rð Rð< ð ð  ð  ñ „[ð ð  ð  r   r   N)rq   Ú
__future__r   Úcollectionsr   Úcollections.abcr   Úqiskitr   r   Ú#qiskit.visualization.pulse_v2.typesr   r	   r   r8   r   r   ú<module>rz      s¶   ððCð CðH #Ð "Ð "Ð "Ð "Ð "Ø #Ð #Ð #Ð #Ð #Ð #Ø $Ð $Ð $Ð $Ð $Ð $à !Ð !Ð !Ð !Ð !Ð !Ð !Ð !Ø PÐ PÐ PÐ PÐ PÐ PÐ PÐ Pðe ð e ð e ð e ð e ñ e ô e ð e ð e ð e r   