
    z	i-0                     4    S r SSKrSSKJrJr   " S S5      rg)zQ
Matrix designed for fast multiplication by permutation and block-diagonal ones.
    N   )Layer1QLayer2Qc                      \ rS rSrSrS\4S jrS\R                  4S jr	\
S\S\R                  4S	 j5       rS
\S\R                  S\4S jrSS
\S\R                  S\4S jjrS
\S\R                  4S jrS
\S\R                  4S jrS
\S\R                  S\R                  S\R&                  4S jrS
\S\R                  S\R                  S\R&                  4S jrS\R                  S\R                  4S jrSrg)PMatrix   zk
Wrapper around a matrix that enables fast multiplication by permutation
matrices and block-diagonal ones.

num_qubitsc                    SU-  n[         R                  " S5      U l        X l        [         R                  " S[         R
                  S9U l        [         R                  " S[         R
                  S9U l        U R                  R                  5       U l	        U R                  R                  5       U l
        [         R                  " U[         R                  S9U l        U R                  R                  5       U l        U R                  R                  5       U l        U R                  R                  5       U l        [         R                  " US4[         R
                  S9U l        [         R                  " US4[         R
                  S9U l        U R'                  U5      U l        [         R                  " U R(                  R*                  [         R
                  S9U l        g)z~
Initializes the internal structures of this object but does not set
the matrix yet.

Args:
    num_qubits: number of qubits.
   r   )r   r   dtype   r   r   N)npempty_mat_dimzeros
complex128
_temp_g2x2
_temp_g4x4copy	_temp_2x2	_temp_4x4arangeint64_identity_perm
_left_perm_right_perm
_temp_perm_temp_slice_dim_x_2_temp_slice_dim_x_4_init_index_matrix_idx_matshape_temp_block_diag)selfr	   dims      l/home/james-whalen/.local/lib/python3.13/site-packages/qiskit/synthesis/unitary/aqc/fast_gradient/pmatrix.py__init__PMatrix.__init__   s8    mHHQK		((6?((6?--/--/ ii288<--224..335--224#%88S!HBMM#J #%88S!HBMM#J //4 ")<)<BMM R    matc                     U R                   R                  S:X  a  UR                  5       U l         g[        R                  " U R                   U5        g)a  
Copies specified matrix to internal storage. Once the matrix
is set, the object is ready for use.

**Note**, the matrix will be copied, mind the size issues.

Args:
    mat: matrix we want to multiply on the left and on the right by
         layer matrices.
r   N)r   sizer   r   copyto)r'   r-   s     r)   
set_matrixPMatrix.set_matrix3   s3     99>>Q
DIIIdii%r,   r(   returnc                    [         R                  " X -  [         R                  S9R                  X 5      n[         R                  " U S-  S4S[         R                  S9n[         R                  " SS[         R                  S9n[        SU S5       H>  nXUS-   2XDS-   24   USS2SS24'   UR                  R                  5       X$S-  SS24'   M@     U$ )z
Fast multiplication can be implemented by picking up a subset of
entries in a sparse matrix.

Args:
    dim: problem dimensionality.

Returns:
    2d-array of indices for the fast multiplication.
r   r      r   )
fill_valuer   r   N)r   r   r   reshapefullrangeTravel)r(   all_idxidxbis        r)   r#   PMatrix._init_index_matrixC   s     ))CIRXX6>>sHggsax'ARXXFGGFq9q#q!A!a%iU23AadGSSYY[CQ	N " 
r,   layertemp_matdaggerc           	         UR                  5       u  pEnU R                  nUR                  n[        R                  " U[        R                  " U R
                  XPR                  S9SUS9  U(       a(  [        R                  " X@R                  S9R                  OUn	[        SUS5       H8  n
[        R                  " USS2XS-   24   XR                  S9USS2XS-   24'   M:     X`R
                  SS& g)a  
Multiplies ``NxN`` matrix, wrapped by this object, by a 1-qubit layer
matrix of the right, where ``N`` is the actual size of matrices involved,
``N = 2^{num. of qubits}``.

Args:
    layer: 1-qubit layer, i.e. the layer with just one non-trivial
           1-qubit gate and other gates are just identity operators.
    temp_mat: a temporary NxN matrix used as a workspace.
    dagger: if true, the right-hand side matrix will be taken as
            conjugate transposed.
outr   axisrF   r   r   N)get_attrr   r/   r   taker   r    conjr   r:   r9   dotr!   r'   rA   rB   rC   gmatperminv_permr-   r(   
gmat_rightr?   s              r)   mul_right_q1PMatrix.mul_right_q1W         %~~/Hiiii 	RWWT--tIPQW_` >DRWWT799
q#q!A "AAI&
8P8P!C11u9 " 'r,   c           	         UR                  5       u  pEnU R                  nUR                  n[        R                  " U[        R                  " U R
                  XPR                  S9SUS9  U(       a(  [        R                  " X@R                  S9R                  OUn	[        SUS5       H8  n
[        R                  " USS2XS-   24   XR                  S9USS2XS-   24'   M:     X`R
                  SS& g)a  
Multiplies ``NxN`` matrix, wrapped by this object, by a 2-qubit layer
matrix on the right, where ``N`` is the actual size of matrices involved,
``N = 2^{num. of qubits}``.

Args:
    layer: 2-qubit layer, i.e. the layer with just one non-trivial
           2-qubit gate and other gates are just identity operators.
    temp_mat: a temporary NxN matrix used as a workspace.
    dagger: if true, the right-hand side matrix will be taken as
            conjugate transposed.
rE   r   rG   r   r   N)rI   r   r/   r   rJ   r   r    rK   r   r:   r9   rL   r"   rM   s              r)   mul_right_q2PMatrix.mul_right_q2w   rT   r,   c           
      2   U R                   nUR                  5       u  pEnUR                  n[        R                  " U[        R                  " U R
                  XPR                  S9SUS9  US:  a@  [        SUS5       H.  n[        R                  " XBXS-   2SS24   X8US-   2SS24   S9  M0     OUS-  n	[        R                  " UR                  SX45      [        R                  " UR                  U	SU45      SS5      5        [        R                  " XCR                  SS5      UR                  SS5      S9  [        R                  " UR                  U	SU45      [        R                  " UR                  SX45      SS5      5        X`R
                  SS& g)	ay  
Multiplies ``NxN`` matrix, wrapped by this object, by a 1-qubit layer
matrix of the left, where ``dim`` is the actual size of matrices involved,
``dim = 2^{num. of qubits}``.

Args:
    layer: 1-qubit layer, i.e. the layer with just one non-trivial
           1-qubit gate and other gates are just identity operators.
    temp_mat: a temporary NxN matrix used as a workspace.
rE   r   rG      r   Nr   r   rI   r/   r   rJ   r   r    r9   rL   r0   r7   swapaxes
r'   rA   rB   r-   rN   rO   rP   r(   r?   halfs
             r)   mul_left_q1PMatrix.mul_left_q1   V    ii$~~/Hii 	RWWT__dHqV^_ 91c1%taa%il3QY\9JK & !8DIIQN+R[[9I9I4QRTW.9Y[\^_-` FF4Q+1A1A!R1HIIIT1cN+R[[9I9I1d.9Y[\^_-`
 &r,   c           
      2   U R                   nUR                  5       u  pEnUR                  n[        R                  " U[        R                  " U R
                  XPR                  S9SUS9  US:  a@  [        SUS5       H.  n[        R                  " XBXS-   2SS24   X8US-   2SS24   S9  M0     OUS-  n	[        R                  " UR                  SX45      [        R                  " UR                  U	SU45      SS5      5        [        R                  " XCR                  SS5      UR                  SS5      S9  [        R                  " UR                  U	SU45      [        R                  " UR                  SX45      SS5      5        X`R
                  SS& g)	ay  
Multiplies ``NxN`` matrix, wrapped by this object, by a 2-qubit layer
matrix on the left, where ``dim`` is the actual size of matrices involved,
``dim = 2^{num. of qubits}``.

Args:
    layer: 2-qubit layer, i.e. the layer with just one non-trivial
           2-qubit gate and other gates are just identity operators.
    temp_mat: a temporary NxN matrix used as a workspace.
rE   r   rG   rY   r   Nr   rZ   r[   r]   s
             r)   mul_left_q2PMatrix.mul_left_q2   ra   r,   tmp1tmp2c           	         U R                   nUR                  5       u  pVn[        R                  " [        R                  " XFSUS9USUS9  U R                  U R
                  p[        R                  " XR                  5        Sn
[        SUR                  S   S5       HQ  nX;US-   2XS-   24   U	SS2SS24'   U
[        R                  " UR                  5       U	R                  5       5      -  n
MS     [        R                  " U
5      $ )aC  
Computes and returns: ``Trace(mat @ C) = Trace(mat @ P^T @ gmat @ P) =
Trace((P @ mat @ P^T) @ gmat) = Trace(C @ (P @ mat @ P^T)) =
vec(gmat^T)^T @ vec(P @ mat @ P^T)``, where mat is ``NxN`` matrix wrapped
by this object, ``C`` is matrix representation of the layer ``L``, and gmat
is 2x2 matrix of underlying 1-qubit gate.

**Note**: matrix of this class must be finalized beforehand.

Args:
    layer: 1-qubit layer.
    tmp1: temporary, external matrix used as a workspace.
    tmp2: temporary, external matrix used as a workspace.

Returns:
    trace of the matrix product.
r   rG   r   g        r   N)r   rI   r   rJ   r   r   r0   r:   r9   r%   rL   r;   r   )r'   rA   re   rf   r-   rN   rO   _gmat_ttmp3_sumr?   s               r)   
product_q1PMatrix.product_q1   s    $ ii(A 	t4dM 
		&&&!q#))A,*A!a%iU23DAJBFF6<<>4::<88D + }}T""r,   c           	         U R                   nUR                  5       u  pVn[        R                  " [        R                  " XFSUS9USUS9  U R                  n[        R                  " UR                  5       U R                  R                  5       SUR                  5       S9  XR                  SUR                  5      -  n[        R                  " [        R                  " U5      5      $ )aC  
Computes and returns: ``Trace(mat @ C) = Trace(mat @ P^T @ gmat @ P) =
Trace((P @ mat @ P^T) @ gmat) = Trace(C @ (P @ mat @ P^T)) =
vec(gmat^T)^T @ vec(P @ mat @ P^T)``, where mat is ``NxN`` matrix wrapped
by this object, ``C`` is matrix representation of the layer ``L``, and gmat
is 4x4 matrix of underlying 2-qubit gate.

**Note**: matrix of this class must be finalized beforehand.

Args:
    layer: 2-qubit layer.
    tmp1: temporary, external matrix used as a workspace.
    tmp2: temporary, external matrix used as a workspace.

Returns:
    trace of the matrix product.
r   rG   r   rZ   )r   rI   r   rJ   r&   r;   r$   r7   r/   r   sum)	r'   rA   re   rf   r-   rN   rO   rh   bldias	            r)   
product_q2PMatrix.product_q2  s    $ ii(A 	t4dM%%


dmm113!Ob$)),,}}RVVE]++r,   c                    U R                   n[        R                  " X R                  SUS9  [        R                  " XR                  SUS9  U R
                  U R                  SS& U R
                  U R                  SS& U R                   $ )z
Applies the left (row) and right (column) permutations to the matrix.
at the end of computation process.

Args:
    temp_mat: temporary, external matrix.

Returns:
    finalized matrix with all transformations applied.
r   rG   r   N)r   r   rJ   r   r   r   )r'   rB   r-   s      r)   finalizePMatrix.finalize$  so     ii 	__1(;
**< "00"11yyr,   )r   r   r$   r   r   r   r   r   r&   r   r   r    r!   r"   N)T)__name__
__module____qualname____firstlineno____doc__intr*   r   ndarrayr1   staticmethodr#   r   boolrR   r   rV   r_   rc   r   rl   rq   rt   __static_attributes__ r,   r)   r   r      s6   
S3 S0&bjj &   

  &'' 'RZZ ' '@'' 'RZZ ' '@#& #&BJJ #&J#& #&BJJ #&J #  #rzz  #  #PRP]P]  #D, ,rzz , ,PRP]P] ,B 

 r,   r   )rz   numpyr   rA   r   r   r   r   r,   r)   <module>r      s     #c cr,   