
    ph.                         S r SSKrSSKJr  SSKr\R                  " \5      rS r	S r
S rS r\rS rS	 rS
 rS rS r\rS rS rS rS r\r\r\r\r\r\r\r\r\r \r!\r"\r#g)z
Conversion functions.

See the documentation on PyPhi :ref:`tpm-conventions` for information on the
different representations that these functions convert between.
    N)log2c                 \    [        [        U 5      SS R                  U5      SSS2   S5      $ )zReverse the bits of the ``n``-bit decimal number ``i``.

Examples:
    >>> reverse_bits(12, 7)
    24
    >>> reverse_bits(0, 1)
    0
    >>> reverse_bits(1, 2)
    2
   N)intbinzfillins     G/home/james-whalen/.local/lib/python3.13/site-packages/pyphi/convert.pyreverse_bitsr      s/     s1vabz"4R4(!,,    c                 8    U (       a  [        S U  5       5      $ S$ )z*Convert nodes to a tuple of their indices.c              3   8   #    U  H  oR                   v   M     g 7fN)index.0r   s     r   	<genexpr> nodes2indices.<locals>.<genexpr>%        (%Q%    tuplenodess    r   nodes2indicesr   #       ,15(%((9r9r   c                 8    U (       a  [        S U  5       5      $ S$ )z)Convert nodes to a tuple of their states.c              3   8   #    U  H  oR                   v   M     g 7fr   stater   s     r   r   nodes2state.<locals>.<genexpr>*   r   r   r   r   r   s    r   nodes2stater&   (   r    r   c                     [        X5      $ )zJConvert between big-endian and little-endian for indices in
``range(n)``.
)r   r
   s     r   be2ler(   -   s     r   c                 F    [        SR                  S U  5       5      S5      $ )a  Convert a PyPhi state-tuple to a decimal index according to the
big-endian convention.

Args:
    state (tuple[int]): A state-tuple where the |ith| element of the tuple
        gives the state of the |ith| node.

Returns:
    int: A decimal integer corresponding to a network state under the
    big-endian convention.

Examples:
    >>> state2be_index((1, 0, 0, 0, 0))
    16
    >>> state2be_index((1, 1, 1, 0, 0, 0, 0, 0))
    224
 c              3   J   #    U  H  n[        [        U5      5      v   M     g 7fr   strr   r   s     r   r   !state2be_index.<locals>.<genexpr>I   s     2Eqs3q6{{E   !#r   r   joinr#   s    r   state2be_indexr2   7   s     $ rww2E22A66r   c           	      R    [        SR                  S U SSS2    5       5      S5      $ )a  Convert a PyPhi state-tuple to a decimal index according to the
little-endian convention.

Args:
    state (tuple[int]): A state-tuple where the |ith| element of the tuple
        gives the state of the |ith| node.

Returns:
    int: A decimal integer corresponding to a network state under the
    little-endian convention.

Examples:
    >>> state2le_index((1, 0, 0, 0, 0))
    1
    >>> state2le_index((1, 1, 1, 0, 0, 0, 0, 0))
    7
r*   c              3   J   #    U  H  n[        [        U5      5      v   M     g 7fr   r,   r   s     r   r   !state2le_index.<locals>.<genexpr>^   s     8Kqs3q6{{Kr/   Nr   r   r0   r#   s    r   state2le_indexr6   L   s(    $ rww8E$B$K88!<<r   c                 @   ^  [        U 4S j[        U5       5       5      $ )a7  Convert a decimal integer to a PyPhi state tuple with the little-endian
convention.

The output is the reverse of |be_index2state()|.

Args:
    i (int): A decimal integer corresponding to a network state under the
        little-endian convention.

Returns:
    tuple[int]: A state-tuple where the |ith| element of the tuple gives
    the state of the |ith| node.

Examples:
    >>> number_of_nodes = 5
    >>> le_index2state(1, number_of_nodes)
    (1, 0, 0, 0, 0)
    >>> number_of_nodes = 8
    >>> le_index2state(7, number_of_nodes)
    (1, 1, 1, 0, 0, 0, 0, 0)
c              3   4   >#    U  H  nTU-	  S -  v   M     g7f)   Nr   )r   r   r   s     r   r   !le_index2state.<locals>.<genexpr>w   s     >'=!!q&A'=s   )r   ranger   number_of_nodess   ` r   le_index2stater>   a   s    , >u_'=>>>r   c                 $    [        X5      SSS2   $ )ao  Convert a decimal integer to a PyPhi state tuple using the big-endian
convention that the most-significant bits correspond to low-index nodes.

The output is the reverse of |le_index2state()|.

Args:
    i (int): A decimal integer corresponding to a network state under the
        big-endian convention.

Returns:
    tuple[int]: A state-tuple where the |ith| element of the tuple gives
    the state of the |ith| node.

Examples:
    >>> number_of_nodes = 5
    >>> be_index2state(1, number_of_nodes)
    (0, 0, 0, 0, 1)
    >>> number_of_nodes = 8
    >>> be_index2state(7, number_of_nodes)
    (0, 0, 0, 0, 0, 1, 1, 1)
Nr   )r>   r<   s     r   be_index2stater@   z   s    , !-dd33r   c                     [         R                  " U R                  5      nU R                  S   n[        [	        U5      5      n[        U5       H  nU [        XC5      SS24   XSS24'   M     U$ )a  Convert a state-by-state TPM from big-endian to little-endian or vice
versa.

Args:
    tpm (np.ndarray): A state-by-state TPM.

Returns:
    np.ndarray: The state-by-state TPM in the other indexing format.

Example:
    >>> tpm = np.arange(16).reshape([4, 4])
    >>> be2le_state_by_state(tpm)
    array([[ 0.,  1.,  2.,  3.],
           [ 8.,  9., 10., 11.],
           [ 4.,  5.,  6.,  7.],
           [12., 13., 14., 15.]])
r   N)npemptyshaper   r   r;   r(   )tpmleNr   r   s        r   be2le_state_by_staterH      s[    $ 
#))	B		!ADGA1XuQ{A~&a4 Ir   c                     [         R                  " U 5      n U R                  S   nU R                  S/U-  U/-   SS9R	                  [
        5      $ )zReshape a state-by-node TPM to the multidimensional form.

See documentation for the |Network| object for more information on TPM
formats.
r   r   ForderrB   arrayrD   reshapeastypefloatrE   rG   s     r   to_multidimensionalrS      sJ     ((3-C		"A
 ;;sQw!}C;077>>r   c                     [         R                  " U 5      n U R                  S   nU R                  SU-  U/SS9R	                  [
        5      $ )zReshape a state-by-node TPM to the 2-dimensional form.

See :ref:`tpm-conventions` and documentation for the |Network| object for
more information on TPM representations.
r   r   rJ   rK   rM   rR   s     r   to_2dimensionalrU      sD     ((3-C		"A;;1ay;,33E::r   c                    [         R                  " U 5      n U R                  S   n[        [	        U5      5      n[         R
                  " S/U-  U/-   5      n[        U5       Vs0 s H  oD[        XB5      _M     nn[         R                  " [        U5       VVs/ s H$  n[        U5       Vs/ s H
  oEU   U   PM     snPM&     snn5      n[        U5       Vs/ s H	  o`Xv   -  PM     nnUR                  5        H<  u  pI[        U5       Vs/ s H  n[         R                  " X   U   5      PM      snX9'   M>     U$ s  snf s  snf s  snnf s  snf s  snf )aP  Convert a state-by-state TPM to a state-by-node TPM.

.. danger::
    Many nondeterministic state-by-state TPMs can be represented by a
    single a state-by-state TPM. However, the mapping can be made to be
    one-to-one if we assume the state-by-state TPM is conditionally
    independent, as this function does. **If the given TPM is not
    conditionally independent, the conditional dependencies will be
    silently lost.**

.. note::
    The indices of the rows and columns of the state-by-state TPM are
    assumed to follow the little-endian convention. The indices of the rows
    of the resulting state-by-node TPM also follow the little-endian
    convention. See the documentation on PyPhi the :ref:`tpm-conventions`
    more information.

Args:
    tpm (list[list] or np.ndarray): A square state-by-state TPM with row
        and column indices following the little-endian convention.

Returns:
    np.ndarray: A state-by-node TPM, with row indices following the
    little-endian convention.

Example:
    >>> tpm = np.array([[0.5, 0.5, 0.0, 0.0],
    ...                 [0.0, 1.0, 0.0, 0.0],
    ...                 [0.0, 0.2, 0.0, 0.8],
    ...                 [0.0, 0.3, 0.7, 0.0]])
    >>> state_by_state2state_by_node(tpm)
    array([[[0.5, 0. ],
            [1. , 0.8]],
    <BLANKLINE>
           [[1. , 0. ],
            [0.3, 0.7]]])
r   r   )
rB   rN   rD   r   r   zerosr;   r>   itemssum)
rE   SrG   sbn_tpmr   statesr   node_onon_probabilitiesr$   s
             r   state_by_state2state_by_noder_      s   N ((3-C		"ADGAhha1#'G/4Qx8x!%%xF8 hh%(K(QuQx8x!1x8(KLG27(;(Qgj((;LLN CH(K(Q"&&!1!4Q!78(K	 #
 N 9 9K;
 Ls*   %D>E
-E>E
E%EE
c           	         [         R                  " U 5      n [        U 5      n U R                  S   nSU-  n[         R                  " X"45      n[         R
                  " [         R                  " U S:  U S:  5      5      (       d2  [        U5       H!  n[        XA5      n[        X   5      nSX4U4'   M#     U$ [        U5       H  n[        XA5      nX   n[        U5       Hp  n[         R                  " [        Xa5       Vs/ s H  oPM     sn5      n	[         R                  " XyS:H     5      [         R                  " SXyS:H     -
  5      -  X4U4'   Mr     M     U$ s  snf )a  Convert a state-by-node TPM to a state-by-state TPM.

.. important::
    A nondeterministic state-by-node TPM can have more than one
    representation as a state-by-state TPM. However, the mapping can be
    made to be one-to-one if we assume the TPMs to be conditionally
    independent. Therefore, **this function returns the corresponding
    conditionally independent state-by-state TPM.**

.. note::
    The indices of the rows of the state-by-node TPM are assumed to follow
    the little-endian convention, while the indices of the columns follow
    the big-endian convention. The indices of the rows and columns of the
    resulting state-by-state TPM both follow the big-endian convention. See
    the documentation on PyPhi :ref:`tpm-conventions` for more info.

Args:
    tpm (list[list] or np.ndarray): A state-by-node TPM with row indices
        following the little-endian convention and column indices following
        the big-endian convention.

Returns:
    np.ndarray: A state-by-state TPM, with both row and column indices
    following the big-endian convention.

>>> tpm = np.array([[1, 1, 0],
...                 [0, 0, 1],
...                 [0, 1, 1],
...                 [1, 0, 0],
...                 [0, 0, 1],
...                 [1, 0, 0],
...                 [1, 1, 1],
...                 [1, 0, 1]])
>>> state_by_node2state_by_state(tpm)
array([[0., 0., 0., 1., 0., 0., 0., 0.],
       [0., 0., 0., 0., 1., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 1., 0.],
       [0., 1., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 1., 0., 0., 0.],
       [0., 1., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 1.],
       [0., 0., 0., 0., 0., 1., 0., 0.]])
r   r   r9   r   )rB   rN   rS   rD   rW   anylogical_andr;   r>   r6   prod)
rE   rG   rZ   sbs_tpmprevious_state_indexprevious_statecurrent_state_indexmarginal_tpmr   current_states
             r   state_by_node2state_by_staterj     sQ   Z ((3-C
c
"C		"A	1AhhvG66"..q#'233$)!H  ,,@DN"01D"EABG*==> %-& N %*!H  ,,@DN.L',Qx# " ./B FG F1Q FG!I GGL!);<=GGAa-? @@AB .AAB (0 %- N	 Hs   =E)$__doc__loggingmathr   numpyrB   	getLogger__name__logr   r   r&   r(   le2ber2   r6   r>   r@   rH   le2be_state_by_staterS   rU   r_   rj   b2ll2bl2sb2ss2ls2bb2l_sbsl2b_sbsto_mdto_2dsbn2sbssbs2sbnr   r   r   <module>r      s   
    !-:
:
 	7*=*?2424 , ?";9~K` 


&
&r   