K i:6dZddlmZddlmZddlmZddlmZddl m Z ddl m Z ddl mZdd lmZgd Zd Zdd ZddZdZddZdZddZddZdZy )z1Primitive circuit operations on quantum circuits.)reduce)default_sort_key)Tuple)Mul)Symbolsympify)numbered_symbols)Gate) kmp_tablefind_subcircuitreplace_subcircuitconvert_to_symbolic_indicesconvert_to_real_indices random_reduce random_insertc&d}d}g}|jd|jd|t|krZ||dz ||k(r|dz}|j||dz}n!|dkDr||}n|jd|dz}|t|krZ|S)zBuild the 'partial match' table of the Knuth-Morris-Pratt algorithm. Note: This is applicable to strings or quantum circuits represented as tuples. r)appendlen)wordposcndtables h/mnt/ssd/data/python-lab/Trading/venv/lib/python3.12/site-packages/sympy/physics/quantum/circuitutils.pyr r s C C E LL LLO D / a=DI %'C LL 'C 1W*C LLO'C D / Lct|tr |j}t|tr |j}t|dk(st|t|kDry|dkr t|}|}d}t |}||z|krG|||||zk(r|dz}n||z||z }||dkDr||nd}|t|k(r|S||z|krGy)aFinds 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 rrr) isinstancerargsrr )circuit subcircuitstartendrindexrs rr r 8sp'3,,*c"__  :!s:W= Qw'l C E j !E ;#  e e 4 4AIE+e ,C$)%L2$5E%L1E C O #J ;#  rNc:|dkrd}t|tr |j}t|tr |j}t|tr |j}n|d}t|||}|dkDr'|d|}||t |zt |}||z|z}|S)aReplaces 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 rr!r r)r"r#replacerlocleftrights rrrsp Qw'3,,*c"__ '3,,  ':S 9C Rxq~c*o-c'l;.5( Nrc:i}|D]}t||||<|SNr)mappingnew_mapkeys r_sympify_qubit_mapr2s-G-ws|, - Nrc^t|tr |j}tdd}t |}i}d}|"t|t sd|z}t ||}|0t|tjsd|z}t ||}|%t|tsdd|zz}t ||}t|}||} d } |D]} t| tr:t| j||| } | \} }}}|j|||} ngt| ttfr0t| ||| } | \} }}}|j|||} n!| | vr| | } nt |}| ||<|| | <|} t| tr| j| } | | fz} | |||fS) aLReturns 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$cNd}tt||jS)Nc|d|dfS)Nrrr()items rzIconvert_to_symbolic_indices..create_inverse_map.. s$q'47!3r)dictmapitems)symb_to_real_map rev_itemss rcreate_inverse_mapz7convert_to_symbolic_indices..create_inverse_map s#3 C #3#9#9#;<==rz+Expected Symbol for starting index, got %r.zExpected a generator, got %r.z$Expected dict for existing map, got z%r.r() qubit_mapr$gen)r rr!r nextr TypeError __class__r:r2r rupdatetupler)seqr$rAr@ index_gencur_ndxndx_mapr?msginv_mapsym_seqr8resultsym_itemr0s rrrs,#shh!26I9oGG> %(?%GCC.  #/1;;<1C7CC.  )T*99$%CC.  )G )GG ( dD !0;B7>5>@F5; 1Hgw NN7 #(1G uen -0;B7>5>@F5; 1Hgw NN7 #(1G W_t}H3iG#GG #GDMH dD !%t~~x0HXK'A (D GWi //rct|tr |j}t|tsd|z}t |t |}d}|D]v}t|t rt|j|}n(t|ttfr t||}n||}t|t r|j|}||fz}x|S)aReturns 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 rr!r:rCr2r rrFrrD)rGr@rKreal_seqr8 real_items rrrMs2#shh i &4y@n"9-IH+ dD !/ 9EI uen -/i@I"$I dD !& 2Iyl*+ Orcddlm}|s|St|tr |j}t |}||}|r5|t |}|j|}t||dk7rn|r5|St||S)aShorten 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.randomrUr rr! flatten_idsrpopr r)r"gate_idsseedrUids randranger4ids rrrs.- '3,, h C4 I  c#h  WWQZ 7B '2 -   gr **rcddlm}|s|St|tr |j}||}|t |dz}||t |}t |}||||t|S)aInsert 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. rrTr)rVrUr rr!rlistrF)r"choicesrZrUr\r*choices rrrss6- '3,,4 I CL1$ %C Ys7|, -F7mGGC >rcRd}t||g}|jt|S)Nc>|t|jtzS)Nr1)sortedequivalent_idsr)accan_ids rr9zflatten_ids..s#u/C/C,<)>#>rrd)rsortr)r[collapses rrWrWs+>H 3 #CHH!H" Jr)rr)Nr)NNNr.)__doc__ functoolsrsympy.core.sortingrsympy.core.containersrsympy.core.mulrsympy.core.symbolrsympy.core.sympifyr sympy.utilitiesr sympy.physics.quantum.gater __all__r r rr2rrrrrWr(rrrus^7/'$&,+ @UpRj^0B2j/+d*^r