
    phf@                        S r SSKJrJrJr  SSKJr  SSKJr  SSKJ	r	J
r
JrJr  SSKJr  S r\" 0 S	S
9S 5       rS r\" 0 S	S
9S 5       rS!S jrS rS rS r\" 0 S	S
9S 5       rS rS rS rS rS r " S S\5      r\" 5       rS"S jr\RA                  S5      S"S j5       r!\RA                  S5      S"S j5       r"\RA                  S5      S"S  j5       r#g	)#z&
Functions for generating partitions.
    )chainpermutationsproduct   )config)cache)Bipartition
KPartitionPartTripartition)Registryc              #      #    [        U 5      n U (       d  g[        U 5      S:X  a  U /v   gU S   n[        U SS 5       H7  n[        U5       H  u  p4USU U/U-   /-   X#S-   S -   v   M     U//U-   v   M9     g7f)zGenerate all set partitions of a collection.

Example:
    >>> list(partitions(range(3)))  # doctest: +NORMALIZE_WHITESPACE
    [[[0, 1, 2]],
     [[0], [1, 2]],
     [[0, 1], [2]],
     [[1], [0, 2]],
     [[0], [1], [2]]]
Nr   r   )listlen
partitions	enumerate)
collectionfirstsmallernsubsets        I/home/james-whalen/.local/lib/python3.13/site-packages/pyphi/partition.pyr   r      s      j!J 
:!lqMEjn-"7+IA"1+%6!1 22WqST]BB ,wi'!! .s   A8A:N)r   maxmemc                     / nU S::  a  U$ [        SU S-
  -  5       H^  n/ / /n[        U 5       H  nX$-	  S-  nX5   R                  U5        M     UR                  [        US   5      [        US   5      45        M`     U$ )aB  Return indices for undirected bipartitions of a sequence.

Args:
    N (int): The length of the sequence.

Returns:
    list: A list of tuples containing the indices for each of the two
    parts.

Example:
    >>> N = 3
    >>> bipartition_indices(N)
    [((), (0, 1, 2)), ((0,), (1, 2)), ((1,), (0, 2)), ((0, 1), (2,))]
r      r   )rangeappendtuple)Nresultipartr   bits         r   bipartition_indicesr$   .   s      FAv1q1u:BxqA6Q,CIQ  	uT!W~uT!W~67  M    c           	         ^  [        [        T 5      5       VVs/ s H/  u  p[        U 4S jU 5       5      [        U 4S jU 5       5      4PM1     snn$ s  snnf )a-  Return a list of bipartitions for a sequence.

Args:
    a (Iterable): The sequence to partition.

Returns:
    list[tuple[tuple]]: A list of tuples containing each of the two
    partitions.

Example:
    >>> bipartition((1,2,3))
    [((), (1, 2, 3)), ((1,), (2, 3)), ((2,), (1, 3)), ((1, 2), (3,))]
c              3   .   >#    U  H
  nTU   v   M     g 7fN .0r!   seqs     r   	<genexpr>bipartition.<locals>.<genexpr>Z        -9a3q69   c              3   .   >#    U  H
  nTU   v   M     g 7fr(   r)   r+   jr,   s     r   r-   r.   [   r/   r0   )r$   r   r   )r,   	part0_idx	part1_idxs   `  r   bipartitionr6   L   sX      )<CH(EG(E$	 -9---9--/(EG G Gs   6Ac                 b    [        U 5      nXSSS2    Vs/ s H
  o"SSS2   PM     sn-   $ s  snf )a  Return indices for directed bipartitions of a sequence.

Args:
    N (int): The length of the sequence.

Returns:
    list: A list of tuples containing the indices for each of the two
    parts.

Example:
    >>> N = 3
    >>> directed_bipartition_indices(N)  # doctest: +NORMALIZE_WHITESPACE
    [((), (0, 1, 2)),
     ((0,), (1, 2)),
     ((1,), (0, 2)),
     ((0, 1), (2,)),
     ((2,), (0, 1)),
     ((0, 2), (1,)),
     ((1, 2), (0,)),
     ((0, 1, 2), ())]
N)r$   )r   indicesidxs      r   directed_bipartition_indicesr;   _   s7    . "!$G4R4=9=C$B$i=9999s   ,c           	         ^  [        [        T 5      5       VVs/ s H/  u  p#[        U 4S jU 5       5      [        U 4S jU 5       5      4PM1     nnnU(       a  USS $ U$ s  snnf )a  Return a list of directed bipartitions for a sequence.

Args:
    seq (Iterable): The sequence to partition.

Returns:
    list[tuple[tuple]]: A list of tuples containing each of the two
    parts.

Example:
    >>> directed_bipartition((1, 2, 3))  # doctest: +NORMALIZE_WHITESPACE
    [((), (1, 2, 3)),
     ((1,), (2, 3)),
     ((2,), (1, 3)),
     ((1, 2), (3,)),
     ((3,), (1, 2)),
     ((1, 3), (2,)),
     ((2, 3), (1,)),
     ((1, 2, 3), ())]
c              3   .   >#    U  H
  nTU   v   M     g 7fr(   r)   r*   s     r   r-   'directed_bipartition.<locals>.<genexpr>   s     )y!s1vyr0   c              3   .   >#    U  H
  nTU   v   M     g 7fr(   r)   r2   s     r   r-   r>      s     0KAQr0   r   r8   )r;   r   r   )r,   
nontrivialr4   r5   bipartitionss   `    r   directed_bipartitionrB   {   sl    . %AS$J$J I 
)y)	)50K0K+KL$J    Ab!!s   6A c              #      #    [        U 5      n [        U 5       H   u  pU4[        U SU XS-   S -   5      4v   M"     g7f)z4Generate bipartitions where one part is of length 1.Nr   )r   r   r   )r,   r!   elts      r   bipartition_of_onerE      sC     
s)CC.vuS!WsE8}4566 !s   <>c              #   2   #    U  H  nUSSS2   v   M     g7f)z#Reverse the elements of a sequence.Nr8   r)   )r,   rD   s     r   reverse_elementsrG      s     $B$i s   c                 T    [        [        U 5      5      n[        U[        U5      5      $ )a  Generate directed bipartitions where one part is of length 1.

Args:
    seq (Iterable): The sequence to partition.

Returns:
    list[tuple[tuple]]: A list of tuples containing each of the two
    partitions.

Example:
    >>> partitions = directed_bipartition_of_one((1, 2, 3))
    >>> list(partitions)  # doctest: +NORMALIZE_WHITESPACE
    [((1,), (2, 3)),
     ((2,), (1, 3)),
     ((3,), (1, 2)),
     ((2, 3), (1,)),
     ((1, 3), (2,)),
     ((1, 2), (3,))]
)r   rE   r   rG   )r,   rA   s     r   directed_bipartition_of_onerI      s'    ( *3/0L/=>>r%   c                     / nU S::  a  U$ / SQn[        X S9 HP  n/ / / /n[        U5       H  u  pVXF   R                  U5        M     UR                  [        S U 5       5      5        MR     U$ )a:  Return indices for directed tripartitions of a sequence.

Args:
    N (int): The length of the sequence.

Returns:
    list[tuple]: A list of tuples containing the indices for each
    partition.

Example:
    >>> N = 1
    >>> directed_tripartition_indices(N)
    [((0,), (), ()), ((), (0,), ()), ((), (), (0,))]
r   )r   r   r   )repeatc              3   8   #    U  H  n[        U5      v   M     g 7fr(   )r   )r+   ps     r   r-   0directed_tripartition_indices.<locals>.<genexpr>   s     3dE!HHds   )r   r   r   r   )r   r    basekeyr"   r!   locations          r   directed_tripartition_indicesrR      st      FAvDt&B|$S>KAN!!!$ * 	e3d334 ' Mr%   c              #      ^ #    [        [        T 5      5       HF  u  pn[        U 4S jU 5       5      [        U 4S jU 5       5      [        U 4S jU 5       5      4v   MH     g7f)a  Generator over all directed tripartitions of a sequence.

Args:
    seq (Iterable): a sequence.

Yields:
    tuple[tuple]: A tripartition of ``seq``.

Example:
    >>> seq = (2, 5)
    >>> list(directed_tripartition(seq))  # doctest: +NORMALIZE_WHITESPACE
    [((2, 5), (), ()),
     ((2,), (5,), ()),
     ((2,), (), (5,)),
     ((5,), (2,), ()),
     ((), (2, 5), ()),
     ((), (2,), (5,)),
     ((5,), (), (2,)),
     ((), (5,), (2,)),
     ((), (), (2, 5))]
c              3   .   >#    U  H
  nTU   v   M     g 7fr(   r)   r*   s     r   r-   (directed_tripartition.<locals>.<genexpr>        'QSVQr0   c              3   .   >#    U  H
  nTU   v   M     g 7fr(   r)   r2   s     r   r-   rU      rV   r0   c              3   .   >#    U  H
  nTU   v   M     g 7fr(   r)   )r+   kr,   s     r   r-   rU      rV   r0   N)rR   r   r   )r,   abcs   `   r   directed_tripartitionr]      sS     , 1S:a'Q'''Q'''Q'') 	) ;s   A A#c                     [        U5       Vs/ s H  n/ PM     nn[        U 5       H  nXQUS-         R                  X6   5        M      U$ s  snf )Nr   )r   r   )r   rZ   rY   r   r!   psr3   s          r   _visitr`     sL    Ah	h"hB	1X
QU8JM* I 
 s   Ac           	   #     #    U S:X  a  [        X4XV5      v   O%[        U S-
  US-
  X-   S-  X4XV5       H  nUv   M	     XS-   :X  a@  U S-
  X@'   [        X4XV5      v   XA   S:  a"  XA   S-
  XA'   [        X4XV5      v   XA   S:  a  M!  g g XS-   :  a  X-   S-  S:X  a  U S-
  XAS-
  '   OU S-
  X@'   XA   U-   S-  S:X  a  [        XS-
  SX4XV5       H  nUv   M	     O[        XS-
  SX4XV5       H  nUv   M	     XA   S:  a[  XA   S-
  XA'   XA   U-   S-  S:X  a  [        XS-
  SX4XV5       H  nUv   M	     O[        XS-
  SX4XV5       H  nUv   M	     XA   S:  a  MZ  g g g 7f)Nr   r   r   r`   _f_bmunusigmar   rZ   rY   r   vs           r   rc   rc   	  s     
QwQ1))BFBFRZ1$4aAJAG K	!V|QQ1))eaiEAIAEq-- eai 
1fJ!q QA1fIFAEEEMQ!#FAqQ; < FAqQ; <eaiEAIAE"a'BQ1?AG @ BQ1?AG @ eai 
s   A?ECEEc           	   #     #    XS-   :X  aB  XA   U S-
  :  a$  [        X4XV5      v   XA   S-   XA'   XA   U S-
  :  a  M$  [        X4XV5      v   SX@'   OXS-   :  a  XA   U-   S-  S:X  a  [        XS-
  SX4XV5       H  nUv   M	     O[        XS-
  SX4XV5       H  nUv   M	     XA   U S-
  :  a]  XA   S-   XA'   XA   U-   S-  S:X  a  [        XS-
  SX4XV5       H  nUv   M	     O[        XS-
  SX4XV5       H  nUv   M	     XA   U S-
  :  a  M]  X-   S-  S:X  a  SXAS-
  '   OSX@'   U S:X  a  [        X4XV5      v   g [        U S-
  US-
  X-   S-  X4XV5       H  nUv   M	     g 7f)Nr   r   r   rb   re   s           r   rd   rd   ,  s     
!V|eb1fnq--EAIAE eb1fn Q1))	1fEEMQ!#FAqQ; < FAqQ; <eb1fnEAIAE"a'BQ1?AG @ BQ1?AG @ eb1fn J!q A1fIAE	QwQ1))BFBFRZ1$4aAJAG Ks   6ECEAEc           	          [        U 5      n [        U 5      nUS:X  d  US:  a  / $ US:X  a  U //$ S/US-   -  n[        SUS-   5       H  nUS-
  X2U-
  U-   '   M     [        XSX#X5      $ )zGenerate all ``k``-partitions of a collection.

Example:
    >>> list(k_partitions(range(3), 2))
    [[[0, 1], [2]], [[0], [1, 2]], [[0, 2], [1]]]
r   r   )r   r   r   rc   )r   rY   r   rZ   r3   s        r   k_partitionsrl   O  s     j!JJA 	AvQ	Av~	
q1uA1a!e_1ua%!) aAqQ++r%   c                       \ rS rSrSrSrSrg)PartitionRegistryih  a!  Storage for partition schemes registered with PyPhi.

Users can define custom partitions:

Examples:
    >>> @partition_types.register('NONE')  # doctest: +SKIP
    ... def no_partitions(mechanism, purview):
    ...    return []

And use them by setting ``config.PARTITION_TYPE = 'NONE'``
r   r)   N)__name__
__module____qualname____firstlineno____doc__desc__static_attributes__r)   r%   r   rn   rn   h  s    
 Dr%   rn   c                 B    [         [        R                     nU" XU5      $ )z^Return a generator over all mechanism-purview partitions, based on the
current configuration.
)partition_typesr   PARTITION_TYPE)	mechanismpurviewnode_labelsfuncs       r   mip_partitionsr}   z  s!     6001D	K00r%   BIc           	   #     #    [        U 5      n[        U5      n[        X45       H^  u  pVUS   (       d  US   (       d  M  US   (       d  US   (       d  M1  [        [	        US   US   5      [	        US   US   5      US9v   M`     g7f)u=  Return an generator of all |small_phi| bipartitions of a mechanism over
a purview.

Excludes all bipartitions where one half is entirely empty, *e.g*::

     A     ∅
    ─── ✕ ───
     B     ∅

is not valid, but ::

     A     ∅
    ─── ✕ ───
     ∅     B

is.

Args:
    mechanism (tuple[int]): The mechanism to partition
    purview (tuple[int]): The purview to partition

Yields:
    Bipartition: Where each bipartition is::

        bipart[0].mechanism   bipart[1].mechanism
        ─────────────────── ✕ ───────────────────
        bipart[0].purview     bipart[1].purview

Example:
    >>> mechanism = (0,)
    >>> purview = (2, 3)
    >>> for partition in mip_bipartitions(mechanism, purview):
    ...     print(partition, '\n')  # doctest: +NORMALIZE_WHITESPACE
     ∅     0
    ─── ✕ ───
     2     3
    <BLANKLINE>
     ∅     0
    ─── ✕ ───
     3     2
    <BLANKLINE>
     ∅     0
    ─── ✕ ───
    2,3    ∅
r   r   r{   N)r6   rB   r   r	   r   )ry   rz   r{   
numeratorsdenominatorsr   ds          r   mip_bipartitionsr     s|     ^ Y'J'0L
1aDAaDDqtqttd1Q41.QqT1Q40@*57 7 2s   9BB2BTRIc           
   #     ^#    [        U 5      n[        U5      n[        5       nS n[        U[	        X45      5       H  u  px[        [        US   US   5      [        US   US   5      [        SUS   5      US9R                  5       n	S mU4S jn
U
" U	5      (       a  Md  X;  d  Mk  UR                  U	5        U	v   M     g	7f)
u  Return an iterator over all wedge partitions.

These are partitions which strictly split the mechanism and allow a subset
of the purview to be split into a third partition, e.g.::

     A     B     ∅
    ─── ✕ ─── ✕ ───
     B     C     D

See |PARTITION_TYPE| in |config| for more information.

Args:
    mechanism (tuple[int]): A mechanism.
    purview (tuple[int]): A purview.

Yields:
    Tripartition: all unique tripartitions of this mechanism and purview.
c                     U u  pUS   =(       d    US   =(       aK    US   =(       d    US   =(       a3    US   =(       a    US   =(       d    US   (       + =(       d
    US   (       + $ )z2Return whether the factoring should be considered.r   r   r)   )	factoring	numeratordenominators      r   validwedge_partitions.<locals>.valid  si     "+	q\+[^ !q\+[^!l+y|  Q Q	
r%   r   r   r)   r   r   c                 @    U R                   =(       d    U R                  $ )z!Check that the part is not empty.ry   rz   )r"   s    r   nonempty"wedge_partitions.<locals>.nonempty  s    >>1T\\1r%   c                 
  > U S   U S   4U S   U S   4U S   U S   4/nU H_  u  p#T" U5      (       d  M  T" U5      (       d  M#  UR                   UR                   -   S:X  d  UR                  UR                  -   S:X  d  M_    g   g)u   Check if the tripartition can be transformed into a causally
equivalent partition by combing two of its parts; e.g., A/∅ × B/∅ ×
∅/CD is equivalent to AB/∅ × ∅/CD so we don't include it.
r   r   r   r)   TFr   )tripartpairsxyr   s       r   compressible&wedge_partitions.<locals>.compressible  s     WQZ(WQZ(WQZ(E
 QKKHQKKq{{2b8QYY."4	 
 r%   N)	r6   r]   setfilterr   r   r   	normalizeadd)ry   rz   r{   r   r   yieldedr   r   r   r   r   r   s              @r   wedge_partitionsr     s     ( Y'J(1LeG

 ugj?@1qt1qtQqTN#	

 )+ 		2	" G$$)?KK MA As   BC C'CALLc              #   ~  #    [        U 5       GH  nUR                  / 5        [        U5      n[        [        U5      U5      n[	        SUS-   5       H  nXF-
  n[        X5       H  nU V	s/ s H  n	[        U	5      PM     nn	UR                  S/U-  5        [        [        U5      5       Hu  n
[        UU
5       VVs/ s H#  u  p[        [        U5      [        U5      5      PM%     nnnUS   R                  U :X  a  US   R                  (       a  Mh  [        USU06v   Mw     M     M     GM!     gs  sn	f s  snnf 7f)a  Return all possible partitions of a mechanism and purview.

Partitions can consist of any number of parts.

Args:
    mechanism (tuple[int]): A mechanism.
    purview (tuple[int]): A purview.

Yields:
    KPartition: A partition of this mechanism and purview into ``k`` parts.
r   r)   r   r{   N)r   r   r   minr   rl   r   extendr   r   zipr   ry   rz   r
   )ry   rz   r{   mechanism_partitionn_mechanism_partsmax_purview_partitionn_purview_partsn_emptypurview_partition_listpurview_permutationmrM   partss                 r   all_partitionsr     sK      *)4""2& 34 #CL2C D$Q(=(ABO'9G%1'%K!2C%E2C &+5\2C " %E "(("8 ,/$%67,9'
 %((;(;%=%=DA U1XuQx0%=   Qx))Y658;K;K $eEEE,9 &L  C	  5%Es   A)D=+D2
 =D==*D7'AD=)Fr(   )$rs   	itertoolsr   r   r    r   r   modelsr	   r
   r   r   registryr   r   r$   r6   r;   rB   rE   rG   rI   rR   r]   r`   rc   rd   rl   rn   rw   r}   registerr   r   r   r)   r%   r   <module>r      s,  
 3 2   ? ? "8 R :G& R: :6B7?0 R <)B F F,2  $%1 $47  47n % D !DN % (F !(Fr%   