
    phP                     f    S r SSKrSSKJr  S rS rS rS rS r	S	 r
S
 rS rSS jrSS jrS rg)z<
Functions for determining network connectivity properties.
    N)connected_componentsc                 H    UR                  5       nSXSS24'   SUSS2U 4'   U$ )z-Remove connections to or from external nodes.r   N)copy)external_indicescms     L/home/james-whalen/.local/lib/python3.13/site-packages/pyphi/connectivity.pyapply_boundary_conditions_to_cmr	      s/    	BBBq
I    c                 ^   ^ ^ [        UU 4S j[        TR                  S   5       5       5      $ )z:Return indices of inputs to the node with the given index.c              3   F   >#    U  H  nTU   T   (       d  M  Uv   M     g 7fN .0ir   indexs     r   	<genexpr>%get_inputs_from_cm.<locals>.<genexpr>   s     ?.q"Q%,.   !	!r   tuplerangeshaper   r   s   ``r   get_inputs_from_cmr      !    ?E"((1+.???r
   c                 ^   ^ ^ [        UU 4S j[        TR                  S   5       5       5      $ )z;Return indices of the outputs of node with the given index.c              3   F   >#    U  H  nTT   U   (       d  M  Uv   M     g 7fr   r   r   s     r   r   &get_outputs_from_cm.<locals>.<genexpr>   s     ?.q"U)A,.r   r   r   r   s   ``r   get_outputs_from_cmr       r   r
   c                     U R                  S5      nU R                  S5      n[        R                  " US:  US:  5      n[        [        R                  " U5      S   5      $ )z:Return indices of nodes that have both inputs and outputs.r      )sumnplogical_andr   where)r   inputsoutputsnodes_with_inputs_and_outputss       r   causally_significant_nodesr*      sO    VVAYFffQiG$&NN6A:w{$K!78;<<r
   c                     [         R                  " X 45      nU(       a  U(       d  U$ SU[         R                  " X5      '   U$ )as  Construct a connectivity matrix.

Args:
    n (int): The dimensions of the matrix
    _from (tuple[int]): Nodes with outgoing connections to ``to``
    to (tuple[int]): Nodes with incoming connections from ``_from``

Returns:
    np.ndarray: An |n x n| connectivity matrix with the |i,jth| entry is
    ``1`` if |i| is in ``_from`` and |j| is in ``to``, and 0 otherwise.
r"   )r$   zerosix_)n_fromtor   s       r   relevant_connectionsr1   (   s8     
1&	B 	BrvveIr
   c                   ^  [         R                  " T R                  S5      S:H  5      (       a  g[         R                  " T R                  S5      S:H  5      (       a  g[	        [        T R                  S   5      5      nU 4S jnU 4S jn[         R                  " T R                  S5      5      /nU" U5      nU" U5      n [         R                  " Xd5      (       a  gUnU" U5      nU" U5      n[         R                  " XQ5      (       a  gML  )u  Return whether ``cm`` can be arranged as a block connectivity matrix.

If so, the corresponding mechanism/purview is trivially reducible.
Technically, only square matrices are "block diagonal", but the notion of
connectivity carries over.

We test for block connectivity by trying to grow a block of nodes such
that:

- 'source' nodes only input to nodes in the block
- 'sink' nodes only receive inputs from source nodes in the block

For example, the following connectivity matrix represents connections from
``nodes1 = A, B, C`` to ``nodes2 = D, E, F, G`` (without loss of
generality, note that ``nodes1`` and ``nodes2`` may share elements)::

     D  E  F  G
  A [1, 1, 0, 0]
  B [1, 1, 0, 0]
  C [0, 0, 1, 1]

Since nodes |AB| only connect to nodes |DE|, and node |C| only connects to
nodes |FG|, the subgraph is reducible, because the cut ::

  A,B    C
  ─── ✕ ───
  D,E   F,G

does not change the structure of the graph.
r"   r   Tc                 b   > [         R                  " TU SS24   R                  S5      5      S   $ )z5Return all nodes that `nodes` connect to (output to).Nr   r$   r&   r#   nodesr   s    r   
outputs_ofblock_cm.<locals>.outputs_off   s*    xx5!8((+,Q//r
   c                 b   > [         R                  " TSS2U 4   R                  S5      5      S   $ )z5Return all nodes which connect to (input to) `nodes`.Nr"   r   r4   r5   s    r   	inputs_toblock_cm.<locals>.inputs_toj   s*    xx1e8((+,Q//r
   F)	r$   anyr#   alllistr   r   argmaxarray_equal)r   r(   r7   r:   sourcessinkssink_inputss   `      r   block_cmrD   ?   s    > 
vvbffQi1n	vvbffQi1n5!%&G00
 yy#$GwEE"K
>>+//
  7#& >>%)) r
   c                 8   U(       a  U(       d  gU [         R                  " X5         n U R                  S5      R                  5       (       a$  U R                  S5      R                  5       (       d  g[	        U5      S:  a  [	        U5      S:  a  [        U 5      $ g)zReturn whether connections from ``nodes1`` to ``nodes2`` are reducible.

Args:
    cm (np.ndarray): The network's connectivity matrix.
    nodes1 (tuple[int]): Source nodes
    nodes2 (tuple[int]): Sink nodes
Tr   r"   F)r$   r-   r#   r=   lenrD   r   nodes1nodes2s      r   block_reduciblerJ      sk     	BFF6"	#B 66!9==??"&&)--//
6{Q3v;?|r
   c                 Z    Ub  U [         R                  " X5         n [        XS9u  p4US:  $ )z.Test connectivity for the connectivity matrix.)
connection   )r$   r-   r   )r   r6   rL   num_components_s        r   
_connectedrP      s3    u$%,RGNAr
   c                     [        XS5      $ )zReturn whether the connectivity matrix is strongly connected.

Remember that a singleton graph is strongly connected.

Args:
    cm (np.ndarray): A square connectivity matrix.

Keyword Args:
    nodes (tuple[int]): A subset of nodes to consider.
strongrP   r   r6   s     r   	is_strongrU      s     b**r
   c                     [        XS5      $ )zReturn whether the connectivity matrix is weakly connected.

Args:
    cm (np.ndarray): A square connectivity matrix.

Keyword Args:
    nodes (tuple[int]): A subset of nodes to consider.
weakrS   rT   s     r   is_weakrX      s     b((r
   c                     U(       a  U(       d  gU [         R                  " X5         n U R                  S5      R                  5       =(       a    U R                  S5      R                  5       $ )a  Test connectivity of one set of nodes to another.

Args:
    cm (``np.ndarrray``): The connectivity matrix
    nodes1 (tuple[int]): The nodes whose outputs to ``nodes2`` will be
        tested.
    nodes2 (tuple[int]): The nodes whose inputs from ``nodes1`` will
        be tested.

Returns:
    bool: ``True`` if all elements in ``nodes1`` output to some element in
    ``nodes2`` and all elements in ``nodes2`` have an input from some
    element in ``nodes1``, or if either set of nodes is empty; ``False``
    otherwise.
Tr   r"   )r$   r-   r#   r=   rG   s      r   is_fullrZ      sH      	BFF6"	#B 66!9==?.rvvay}}.r
   r   )__doc__numpyr$   scipy.sparse.csgraphr   r	   r   r    r*   r1   rD   rJ   rP   rU   rX   rZ   r   r
   r   <module>r^      sM   
  5@
@
=.CP,+	)/r
   