
    \h:6                         S r SSKJr  SSKJr  SSKJr  SSKJr  SSK	J
r
  SSKJr  SSKJr  SS	KJr  / S
QrS rSS jrSS jrS rSS jrS rSS jrSS jrS rg)z1Primitive circuit operations on quantum circuits.    )reduce)default_sort_key)Tuple)Mul)Symbolsympify)numbered_symbols)Gate)	kmp_tablefind_subcircuitreplace_subcircuitconvert_to_symbolic_indicesconvert_to_real_indicesrandom_reducerandom_insertc                 *   SnSn/ nUR                  S5        UR                  S5        U[        U 5      :  a[  XS-
     X   :X  a  US-   nUR                  U5        US-   nO!US:  a  X2   nOUR                  S5        US-   nU[        U 5      :  a  M[  U$ )zBuild the 'partial match' table of the Knuth-Morris-Pratt algorithm.

Note: This is applicable to strings or
quantum circuits represented as tuples.
   r      )appendlen)wordposcndtables       Z/var/www/auris/envauris/lib/python3.13/site-packages/sympy/physics/quantum/circuitutils.pyr   r      s     C C E	LL	LLO
D	/a=DI%'CLL'C1W*CLLO'C D	/ L    c                    [        U [        5      (       a  U R                  n [        U[        5      (       a  UR                  n[        U5      S:X  d  [        U5      [        U 5      :  a  gUS:  a  [        U 5      nUnSn[	        U5      nXE-   U:  aE  X   XU-      :X  a  US-   nOXE-   Xe   -
  nXe   S:  a  Xe   OSnU[        U5      :X  a  U$ XE-   U:  a  ME  g)aH  Finds the subcircuit in circuit, if it exists.

Explanation
===========

If the subcircuit exists, the index of the start of
the subcircuit in circuit is returned; otherwise,
-1 is returned.  The algorithm that is implemented
is the Knuth-Morris-Pratt algorithm.

Parameters
==========

circuit : tuple, Gate or Mul
    A tuple of Gates or Mul representing a quantum circuit
subcircuit : tuple, Gate or Mul
    A tuple of Gates or Mul to find in circuit
start : int
    The location to start looking for subcircuit.
    If start is the same or past end, -1 is returned.
end : int
    The last place to look for a subcircuit.  If end
    is less than 1 (one), then the length of circuit
    is taken to be end.

Examples
========

Find the first instance of a subcircuit:

>>> from sympy.physics.quantum.circuitutils import find_subcircuit
>>> from sympy.physics.quantum.gate import X, Y, Z, H
>>> circuit = X(0)*Z(0)*Y(0)*H(0)
>>> subcircuit = Z(0)*Y(0)
>>> find_subcircuit(circuit, subcircuit)
1

Find the first instance starting at a specific position:

>>> find_subcircuit(circuit, subcircuit, start=1)
1

>>> find_subcircuit(circuit, subcircuit, start=2)
-1

>>> circuit = circuit*subcircuit
>>> find_subcircuit(circuit, subcircuit, start=2)
4

Find the subcircuit within some interval:

>>> find_subcircuit(circuit, subcircuit, start=2, end=2)
-1
r   r   r   )
isinstancer   argsr   r   )circuit
subcircuitstartendr   indexr   s          r   r   r   8   s    p '3,,*c""__

:!s:W=
Qw'l CEj!E;#
e 44AIE+,C$)L2$5EL1EC
O#J ;#
 r   Nc                 R   US:  a  Sn[        U [        5      (       a  U R                  n [        U[        5      (       a  UR                  n[        U[        5      (       a  UR                  nOUc  Sn[        XUS9nUS:  a%  U SU nX[	        U5      -   [	        U 5       nXR-   U-   n U $ )a  Replaces a subcircuit with another subcircuit in circuit,
if it exists.

Explanation
===========

If multiple instances of subcircuit exists, the first instance is
replaced.  The position to being searching from (if different from
0) may be optionally given.  If subcircuit cannot be found, circuit
is returned.

Parameters
==========

circuit : tuple, Gate or Mul
    A quantum circuit.
subcircuit : tuple, Gate or Mul
    The circuit to be replaced.
replace : tuple, Gate or Mul
    The replacement circuit.
pos : int
    The location to start search and replace
    subcircuit, if it exists.  This may be used
    if it is known beforehand that multiple
    instances exist, and it is desirable to
    replace a specific instance.  If a negative number
    is given, pos will be defaulted to 0.

Examples
========

Find and remove the subcircuit:

>>> from sympy.physics.quantum.circuitutils import replace_subcircuit
>>> from sympy.physics.quantum.gate import X, Y, Z, H
>>> circuit = X(0)*Z(0)*Y(0)*H(0)*X(0)*H(0)*Y(0)
>>> subcircuit = Z(0)*Y(0)
>>> replace_subcircuit(circuit, subcircuit)
(X(0), H(0), X(0), H(0), Y(0))

Remove the subcircuit given a starting search point:

>>> replace_subcircuit(circuit, subcircuit, pos=1)
(X(0), H(0), X(0), H(0), Y(0))

>>> replace_subcircuit(circuit, subcircuit, pos=2)
(X(0), Z(0), Y(0), H(0), X(0), H(0), Y(0))

Replace the subcircuit:

>>> replacement = H(0)*Z(0)
>>> replace_subcircuit(circuit, subcircuit, replace=replacement)
(X(0), H(0), Z(0), H(0), X(0), H(0), Y(0))
r    )r$   r   )r    r   r!   r   r   )r"   r#   replacer   locleftrights          r   r   r      s    p Qw'3,,*c""__
'3,,	 'S
9C Rxq~c*o-c'l;.5(Nr   c                 :    0 nU  H  n[        X   5      X'   M     U$ Nr   )mappingnew_mapkeys      r   _sympify_qubit_mapr2      s$    Gw|, Nr   c                    [        U [        5      (       a  U R                  n [        SSS9n[	        U5      n0 nS nUb'  [        U[
        5      (       d  SU-  n[        U5      eUnUb5  [        U[        5       R                  5      (       d  SU-  n[        U5      eUnUb*  [        U[        5      (       d  SSU-  -   n[        U5      eUn[        U5      nU" U5      n	S	n
U  H  n[        U[        5      (       a5  [        UR                  UUUS
9nUu  ppTUR                  U5        U" U5      n	Oe[        U[        [        45      (       a+  [        UUUUS
9nUu  ppTUR                  U5        U" U5      n	OX;   a  X   nO[	        U5      nXU'   XYU'   Un[        U[        5      (       a  UR                  " U6 nX4-   n
M     XXT4$ )a  Returns the circuit with symbolic indices and the
dictionary mapping symbolic indices to real indices.

The mapping is 1 to 1 and onto (bijective).

Parameters
==========

seq : tuple, Gate/Integer/tuple or Mul
    A tuple of Gate, Integer, or tuple objects, or a Mul
start : Symbol
    An optional starting symbolic index
gen : object
    An optional numbered symbol generator
qubit_map : dict
    An existing mapping of symbolic indices to real indices

All symbolic indices have the format 'i#', where # is
some number >= 0.
ir   )prefixr$   c                 L    S n[        [        XR                  5       5      5      $ )Nc                     U S   U S   4$ )Nr   r   r(   )items    r   <lambda>Iconvert_to_symbolic_indices.<locals>.create_inverse_map.<locals>.<lambda>  s    $q'47!3r   )dictmapitems)symb_to_real_map	rev_itemss     r   create_inverse_map7convert_to_symbolic_indices.<locals>.create_inverse_map  s     3	C	#9#9#;<==r   z+Expected Symbol for starting index, got %r.zExpected a generator, got %r.z$Expected dict for existing map, got z%r.r(   )	qubit_mapr$   gen)r    r   r!   r
   nextr   	TypeError	__class__r;   r2   r   r   updatetupler   )seqr$   rC   rB   	index_gencur_ndxndx_mapr@   msginv_mapsym_seqr8   resultsym_itemr0   s                  r   r   r      s   , #shh !26I9oG G> %((?%GCC. 
#/1;;<<1C7CC. 	)T**99$%CC.  )G )GGdD!!0;B7>5>@F 5;1HwNN7#(1Guen--0;B7>5>@F 5;1HwNN7#(1G_}H 3iG#G#DMHdD!!~~x0HK'A D W//r   c                    [        U [        5      (       a  U R                  n [        U[        5      (       d  SU-  n[	        U5      e[        U5      nSnU  H  n[        U[        5      (       a  [        UR                  U5      nO+[        U[        [        45      (       a  [        XA5      nOX   n[        U[        5      (       a  UR                  " U6 nX54-   nM     U$ )a_  Returns the circuit with real indices.

Parameters
==========

seq : tuple, Gate/Integer/tuple or Mul
    A tuple of Gate, Integer, or tuple objects or a Mul
qubit_map : dict
    A dictionary mapping symbolic indices to real indices.

Examples
========

Change the symbolic indices to real integers:

>>> from sympy import symbols
>>> from sympy.physics.quantum.circuitutils import convert_to_real_indices
>>> from sympy.physics.quantum.gate import X, Y, H
>>> i0, i1 = symbols('i:2')
>>> index_map = {i0 : 0, i1 : 1}
>>> convert_to_real_indices(X(i0)*Y(i1)*H(i0)*X(i1), index_map)
(X(0), Y(1), H(0), X(1))
z$Expected dict for qubit_map, got %r.r(   )r    r   r!   r;   rE   r2   r   r   rH   r   rF   )rI   rB   rM   real_seqr8   	real_items         r   r   r   M  s    2 #shhi&&4y@n"9-IHdD!!/		9EIuen--/@I "IdD!!	2Il*   Or   c                 &   SSK Jn  U(       d  U $ [        U [        5      (       a  U R                  n [        U5      nU" U5      nU(       a;  U" [        U5      5      nUR                  U5      n[        X5      S:w  a  OU(       a  M;  U $ [        X5      $ )aw  Shorten the length of a quantum circuit.

Explanation
===========

random_reduce looks for circuit identities in circuit, randomly chooses
one to remove, and returns a shorter yet equivalent circuit.  If no
identities are found, the same circuit is returned.

Parameters
==========

circuit : Gate tuple of Mul
    A tuple of Gates representing a quantum circuit
gate_ids : list, GateIdentity
    List of gate identities to find in circuit
seed : int or list
    seed used for _randrange; to override the random selection, provide a
    list of integers: the elements of gate_ids will be tested in the order
    given by the list

r   
_randranger   )
sympy.core.randomrW   r    r   r!   flatten_idsr   popr   r   )r"   gate_idsseedrW   ids	randranger4   ids           r   r   r     s    . -'3,,
h
C 4 I c#hWWQZ7'2-	 #  g**r   c                     SSK Jn  U(       d  U $ [        U [        5      (       a  U R                  n U" U5      nU" [        U 5      S-   5      nX" [        U5      5         n[        U 5      n X`XU& [        U 5      $ )ax  Insert a circuit into another quantum circuit.

Explanation
===========

random_insert randomly chooses a location in the circuit to insert
a randomly selected circuit from amongst the given choices.

Parameters
==========

circuit : Gate tuple or Mul
    A tuple or Mul of Gates representing a quantum circuit
choices : list
    Set of circuit choices
seed : int or list
    seed used for _randrange; to override the random selections, give
    a list two integers, [i, j] where i is the circuit location where
    choice[j] will be inserted.

Notes
=====

Indices for insertion should be [0, n] if n is the length of the
circuit.
r   rV   r   )rX   rW   r    r   r!   r   listrH   )r"   choicesr\   rW   r^   r*   choices          r   r   r     sr    6 -'3,, 4 I
CL1$
%CYs7|,-F7mGC>r   c                 J    S n[        X/ 5      n U R                  [        S9  U $ )Nc                 8    U [        UR                  [        S9-   $ )Nr1   )sortedequivalent_idsr   )accan_ids     r   r9   flatten_ids.<locals>.<lambda>  s    #u/C/C,<)> #>r   rf   )r   sortr   )r]   collapses     r   rY   rY     s)    >H

#CHH!H"Jr   )r   r   )Nr   )NNNr.   )__doc__	functoolsr   sympy.core.sortingr   sympy.core.containersr   sympy.core.mulr   sympy.core.symbolr   sympy.core.sympifyr	   sympy.utilitiesr
   sympy.physics.quantum.gater   __all__r   r   r   r2   r   r   r   r   rY   r(   r   r   <module>rx      s^    7  / '  $ & , +@UpRj^0B2j/+d*^r   