ó
    …~ic4  ã                   ó²  • S r SSKrSSKrSSKJr  SSKJrJr  / SQr	 " S S\R                  5      r\" S5      \" S	5      \R                  S
 5       5       5       r\R                  \R                  4S j5       r\R                  S 5       r\R                  S 5       rS rS rS rS\R                  4S jr\" S5      \R                  " SS9S 5       5       rg)zÇ
Algorithms for chordal graphs.

A graph is chordal if every cycle of length at least 4 has a chord
(an edge joining two nodes not adjacent in the cycle).
https://en.wikipedia.org/wiki/Chordal_graph
é    N)Úconnected_components)Úarbitrary_elementÚnot_implemented_for)Ú
is_chordalÚfind_induced_nodesÚchordal_graph_cliquesÚchordal_graph_treewidthÚNetworkXTreewidthBoundExceededÚcomplete_to_chordal_graphc                   ó   • \ rS rSrSrSrg)r
   é   zRException raised when a treewidth bound has been provided and it has
been exceeded© N)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Ú__static_attributes__r   ó    ÚX/home/mande/repo/quber/.venv/lib/python3.13/site-packages/networkx/algorithms/chordal.pyr
   r
      s   † ôr   r
   ÚdirectedÚ
multigraphc                 ód   • [        U R                  5      S::  a  g[        [        U 5      5      S:H  $ )ul  Checks whether G is a chordal graph.

A graph is chordal if every cycle of length at least 4 has a chord
(an edge joining two nodes not adjacent in the cycle).

Parameters
----------
G : graph
  A NetworkX graph.

Returns
-------
chordal : bool
  True if G is a chordal graph and False otherwise.

Raises
------
NetworkXNotImplemented
    The algorithm does not support DiGraph, MultiGraph and MultiDiGraph.

Examples
--------
>>> e = [
...     (1, 2),
...     (1, 3),
...     (2, 3),
...     (2, 4),
...     (3, 4),
...     (3, 5),
...     (3, 6),
...     (4, 5),
...     (4, 6),
...     (5, 6),
... ]
>>> G = nx.Graph(e)
>>> nx.is_chordal(G)
True

Notes
-----
The routine tries to go through every node following maximum cardinality
search. It returns False when it finds that the separator for any node
is not a clique.  Based on the algorithms in [1]_.

Self loops are ignored.

References
----------
.. [1] R. E. Tarjan and M. Yannakakis, Simple linear-time algorithms
   to test chordality of graphs, test acyclicity of hypergraphs, and
   selectively reduce acyclic hypergraphs, SIAM J. Comput., 13 (1984),
   pp. 566â€“579.
é   Tr   )ÚlenÚnodesÚ_find_chordality_breaker)ÚGs    r   r   r      s.   € ôr ˆ1�7‰7ƒ|�qÓØÜÔ'¨Ó*Ó+¨qÑ0Ð0r   c                 ó  • [        U 5      (       d  [        R                  " S5      e[        R                  " U 5      nUR	                  X5        [        5       n[        XAU5      nU(       aL  Uu  pxn	UR                  U5        U H  n
X¡:w  d  M
  UR	                  X5        M     [        XAU5      nU(       a  ML  U(       aM  UR                  U5        X    H4  n[        U[        X   5      -  5      S:X  d  M"  UR                  U5          U$    U$ )a!  Returns the set of induced nodes in the path from s to t.

Parameters
----------
G : graph
  A chordal NetworkX graph
s : node
    Source node to look for induced nodes
t : node
    Destination node to look for induced nodes
treewidth_bound: float
    Maximum treewidth acceptable for the graph H. The search
    for induced nodes will end as soon as the treewidth_bound is exceeded.

Returns
-------
induced_nodes : Set of nodes
    The set of induced nodes in the path from s to t in G

Raises
------
NetworkXError
    The algorithm does not support DiGraph, MultiGraph and MultiDiGraph.
    If the input graph is an instance of one of these classes, a
    :exc:`NetworkXError` is raised.
    The algorithm can only be applied to chordal graphs. If the input
    graph is found to be non-chordal, a :exc:`NetworkXError` is raised.

Examples
--------
>>> G = nx.Graph()
>>> G = nx.generators.classic.path_graph(10)
>>> induced_nodes = nx.find_induced_nodes(G, 1, 9, 2)
>>> sorted(induced_nodes)
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Notes
-----
G must be a chordal graph and (s,t) an edge that is not in G.

If a treewidth_bound is provided, the search for induced nodes will end
as soon as the treewidth_bound is exceeded.

The algorithm is inspired by Algorithm 4 in [1]_.
A formal definition of induced node can also be found on that reference.

Self Loops are ignored

References
----------
.. [1] Learning Bounded Treewidth Bayesian Networks.
   Gal Elidan, Stephen Gould; JMLR, 9(Dec):2699--2731, 2008.
   http://jmlr.csail.mit.edu/papers/volume9/elidan08a/elidan08a.pdf
úInput graph is not chordal.é   )
r   ÚnxÚNetworkXErrorÚGraphÚadd_edgeÚsetr   ÚupdateÚaddr   )r   ÚsÚtÚtreewidth_boundÚHÚinduced_nodesÚtripletÚuÚvÚwÚns              r   r   r   \   sì   € ôp �a�=‰=Ü×ÒÐ<Ó=Ð=ä
�Š�‹€AØ‡J�JˆqÔÜ“E€MÜ& q¨_Ó=€GÞ
Ø‰	ˆˆqØ×Ñ˜WÔ%ÛˆAØ�vØ—
‘
˜1Ö ñ ô +¨1°ÓAˆ÷ ˆ'ö à×Ñ˜!ÔØ”ˆAÜ�=¤3 q¡t£9Ñ,Ó-°Õ2Ø×!Ñ! !Ô$ØØÐñ	 ð Ðr   c              #   ó  ^ #   • U 4S j[        T 5       5        GHe  nUR                  5       S:X  aM  [        R                  " U5      S:”  a  [        R                  " S5      e[        UR                  5       5      v •  Me  [        UR                  5       5      n[        U5      nUR                  U5        U1nU1nU(       a±  [        XU5      nUR                  U5        UR                  U5        [        UR                  U5      5      U-  nUR                  U5      n[        U5      (       a&  UR                  U5        Xe:¼  d  [        U5      v •  UnO[        R                  " S5      eU(       a  M±  [        U5      v •  GMh     g7f)a½  Returns all maximal cliques of a chordal graph.

The algorithm breaks the graph in connected components and performs a
maximum cardinality search in each component to get the cliques.

Parameters
----------
G : graph
  A NetworkX graph

Yields
------
frozenset of nodes
    Maximal cliques, each of which is a frozenset of
    nodes in `G`. The order of cliques is arbitrary.

Raises
------
NetworkXError
    The algorithm does not support DiGraph, MultiGraph and MultiDiGraph.
    The algorithm can only be applied to chordal graphs. If the input
    graph is found to be non-chordal, a :exc:`NetworkXError` is raised.

Examples
--------
>>> e = [
...     (1, 2),
...     (1, 3),
...     (2, 3),
...     (2, 4),
...     (3, 4),
...     (3, 5),
...     (3, 6),
...     (4, 5),
...     (4, 6),
...     (5, 6),
...     (7, 8),
... ]
>>> G = nx.Graph(e)
>>> G.add_node(9)
>>> cliques = [c for c in chordal_graph_cliques(G)]
>>> cliques[0]
frozenset({1, 2, 3})
c              3   ób   >#   • U  H$  nTR                  U5      R                  5       v •  M&     g 7f©N)ÚsubgraphÚcopy)Ú.0Úcr   s     €r   Ú	<genexpr>Ú(chordal_graph_cliques.<locals>.<genexpr>Ú   s'   øé € ÐDÒ,C qˆa�j‰j˜‹m× Ñ ×"Ð"Ò,Cùs   ƒ,/é   r   r    N)r   Únumber_of_nodesr"   Únumber_of_selfloopsr#   Ú	frozensetr   r&   r   ÚremoveÚ_max_cardinality_noder(   Ú	neighborsr6   Ú_is_complete_graph)r   ÚCÚ
unnumberedr0   ÚnumberedÚclique_wanna_beÚnew_clique_wanna_beÚsgs   `       r   r   r   ¬   s?  øé € ô\ EÔ,@ÀÔ,C×DˆØ×ÑÓ !Ó#Ü×%Ò% aÓ(¨1Ó,Ü×&Ò&Ð'DÓEÐEÜ˜AŸG™G›IÓ&Ô&ä˜QŸW™W›Y›ˆJÜ! !Ó$ˆAØ×Ñ˜aÔ Ø�sˆHØ ˜cˆOÞÜ)¨!¸ÓB�Ø×!Ñ! !Ô$Ø—‘˜Q”Ü&)¨!¯+©+°a«.Ó&9¸HÑ&DÐ#Ø—Z‘Z Ó0�Ü% b×)Ñ)Ø'×+Ñ+¨AÔ.Ø.ÓAÜ'¨Ó8Ò8Ø&9‘Oä×*Ò*Ð+HÓIÐI÷ �*ô ˜OÓ,Õ,ò1 Eùs   ƒE,FÅ1Fc                 óÀ   • [        U 5      (       d  [        R                  " S5      eSn[        R                  " U 5       H  n[	        U[        U5      5      nM     US-
  $ )a(  Returns the treewidth of the chordal graph G.

Parameters
----------
G : graph
  A NetworkX graph

Returns
-------
treewidth : int
    The size of the largest clique in the graph minus one.

Raises
------
NetworkXError
    The algorithm does not support DiGraph, MultiGraph and MultiDiGraph.
    The algorithm can only be applied to chordal graphs. If the input
    graph is found to be non-chordal, a :exc:`NetworkXError` is raised.

Examples
--------
>>> e = [
...     (1, 2),
...     (1, 3),
...     (2, 3),
...     (2, 4),
...     (3, 4),
...     (3, 5),
...     (3, 6),
...     (4, 5),
...     (4, 6),
...     (5, 6),
...     (7, 8),
... ]
>>> G = nx.Graph(e)
>>> G.add_node(9)
>>> nx.chordal_graph_treewidth(G)
3

References
----------
.. [1] https://en.wikipedia.org/wiki/Tree_decomposition#Treewidth
r    éÿÿÿÿr<   )r   r"   r#   r   Úmaxr   )r   Ú
max_cliqueÚcliques      r   r	   r	   õ   sT   € ôZ �a�=‰=Ü×ÒÐ<Ó=Ð=à€JÜ×*Ò*¨1Ö-ˆÜ˜¤S¨£[Ó1Š
ñ .à˜‰>Ðr   c                 óÌ   • [         R                  " U 5      S:”  a  [         R                  " S5      eU R                  5       nUS:  a  gU R	                  5       nXS-
  -  S-  nX#:H  $ )z&Returns True if G is a complete graph.r   z'Self loop found in _is_complete_graph()r!   Tr<   )r"   r>   r#   r=   Únumber_of_edges)r   r2   ÚeÚ	max_edgess       r   rC   rC   +  se   € ä	×Ò˜aÓ  1Ó$Ü×ÒÐHÓIÐIØ	×ÑÓ€AØˆ1ƒuØØ	×ÑÓ€AØ˜!‘e‘ Ñ!€IØ‰>Ðr   c                 ó¶   • [        U 5      nU  HH  nU[        [        X   R                  5       5      U/-   5      -
  nU(       d  M7  X#R                  5       4s  $    g)z5Given a non-complete graph G, returns a missing edge.N)r&   ÚlistÚkeysÚpop)r   r   r/   Úmissings       r   Ú_find_missing_edgerX   7  sL   € ä�‹F€EÛˆØœ#œd 1¡4§9¡9£;Ó/°1°#Ñ5Ó6Ñ6ˆßˆ7Ø—{‘{“}Ð%Ò%ò r   c                 ó†   • SnU H3  n[        X    Vs/ s H  oUU;   d  M
  UPM     sn5      nXc:”  d  M/  UnUnM5     W$ s  snf )zXReturns a the node in choices that has more connections in G
to nodes in wanna_connect.
rK   )r   )r   ÚchoicesÚwanna_connectÚ
max_numberÚxÚyÚnumberÚmax_cardinality_nodes           r   rA   rA   @  sQ   € ð €JÛˆÜ ¢Ó<¢˜A¨mÑ);—a¡Ñ<Ó=ˆØÕØˆJØ#$Ò ñ	 ð
  Ðùò	 =s   “	>
 >
c                 ó  • [        U 5      S:X  a  [        R                  " S5      e[        U 5      nUc  [	        U 5      nUR                  U5        U1nSnU(       a­  [        XU5      nUR                  U5        UR                  U5        [        X   5      U-  nU R                  U5      n[        U5      (       a4  [        U[        U5      5      nXR:”  a  [        R                  " SU 35      eO[        U5      u  pšX–U
4$ U(       a  M­  g)a/  Given a graph G, starts a max cardinality search
(starting from s if s is given and from an arbitrary node otherwise)
trying to find a non-chordal cycle.

If it does find one, it returns (u,v,w) where u,v,w are the three
nodes that together with s are involved in the cycle.

It ignores any self loops.
r   zGraph has no nodes.rK   ztreewidth_bound exceeded: r   )r   r"   ÚNetworkXPointlessConceptr&   r   r@   rA   r(   r6   rC   rL   r
   rX   )r   r)   r+   rE   rF   Úcurrent_treewidthr0   rG   rI   r/   r1   s              r   r   r   M  s  € ô ˆ1ƒv�ƒ{Ü×)Ò)Ð*?Ó@Ð@Ü�Q“€JØ�yÜ˜aÓ ˆØ×Ñ�aÔØˆs€HØÐÞ
Ü! !°Ó:ˆØ×Ñ˜!ÔØ�‰�QŒÜ˜a™d›) hÑ.ˆØ�Z‰Z˜Ó(ˆÜ˜b×!Ñ!ä #Ð$5´s¸?Ó7KÓ LÐØ Ó2Ü×7Ò7Ø0Ð1BÐ0CÐDóð ð 3ô (¨Ó+‰FˆQØ˜!�9Ð÷# ˆ*ð$ r   T)Úreturns_graphc           	      ón  ^• U R                  5       nU Vs0 s H  o"S_M     nn[        R                  " U5      (       a  X4$ [        5       nUR	                  5        Vs0 s H  o"S_M     snm[        UR	                  5       5      n[        [        UR	                  5       5      SS5       Hæ  n[        UU4S jS9nUR                  U5        XcU'   / nU H¢  n	U R                  X—5      (       a  UR                  U	5        M,  TU	   n
U Vs/ s H  nTU   U
:  d  M  UPM     nn[        R                  " UR                  X·U	/-   5      X—5      (       d  M  UR                  U	5        UR                  Xy45        M¤     U H  nTU==   S-  ss'   M     Mè     UR                  U5        X4$ s  snf s  snf s  snf )a‡  Return a copy of G completed to a chordal graph

Adds edges to a copy of G to create a chordal graph. A graph G=(V,E) is
called chordal if for each cycle with length bigger than 3, there exist
two non-adjacent nodes connected by an edge (called a chord).

Parameters
----------
G : NetworkX graph
    Undirected graph

Returns
-------
H : NetworkX graph
    The chordal enhancement of G
alpha : Dictionary
        The elimination ordering of nodes of G

Notes
-----
There are different approaches to calculate the chordal
enhancement of a graph. The algorithm used here is called
MCS-M and gives at least minimal (local) triangulation of graph. Note
that this triangulation is not necessarily a global minimum.

https://en.wikipedia.org/wiki/Chordal_graph

References
----------
.. [1] Berry, Anne & Blair, Jean & Heggernes, Pinar & Peyton, Barry. (2004)
       Maximum Cardinality Search for Computing Minimal Triangulations of
       Graphs.  Algorithmica. 39. 287-298. 10.1007/s00453-004-1084-3.

Examples
--------
>>> from networkx.algorithms.chordal import complete_to_chordal_graph
>>> G = nx.wheel_graph(10)
>>> H, alpha = complete_to_chordal_graph(G)
r   rK   c                 ó   >• TU    $ r5   r   )ÚnodeÚweights    €r   Ú<lambda>Ú+complete_to_chordal_graph.<locals>.<lambda>§  s	   ø€ °6¸$²<r   )Úkeyr<   )r7   r"   r   r&   r   rT   Úranger   rL   r@   Úhas_edgeÚappendÚhas_pathr6   r(   Úadd_edges_from)r   r,   rg   ÚalphaÚchordsÚunnumbered_nodesÚiÚzÚupdate_nodesr^   Úy_weightÚlower_nodesrh   s               @r   r   r   t  sŽ  ø€ ðT 	
�‰‹€AÙ!"Ó#¢˜�1ŠW¡€EÐ#Ü	‡}‚}�Q×ÑØˆxˆÜ‹U€FØ"#§'¡'¤)Ó,¢)˜$�AŠg¡)Ñ,€FÜ˜AŸG™G›I“ÐÜ”3�q—w‘w“y“> 1 bÖ)ˆäÐ Ô&?Ñ@ˆØ×Ñ Ô"Øˆa‰ØˆÛ!ˆAØ�z‰z˜!×ÑØ×#Ñ# AÖ&ð " !™9�á%5óÚ%5˜T¸À¹ÈÑ9P—DÑ%5ð ð ô —;’;˜qŸz™z¨+¸A¸Ñ*>Ó?À×FÓFØ ×'Ñ'¨Ô*Ø—J‘J ˜vÖ&ñ "ó !ˆDØ�4‹L˜AÑ�Ló !ñ' *ð* ×Ñ�VÔØˆ8€Oùò9 $ùò -ùòs   –F(ÁF-Ä	F2ÄF2)r   ÚsysÚnetworkxr"   Únetworkx.algorithms.componentsr   Únetworkx.utilsr   r   Ú__all__ÚNetworkXExceptionr
   Ú_dispatchabler   Úmaxsizer   r   r	   rC   rX   rA   r   r   r   r   r   Ú<module>r�      s  ðñó ã Ý ?ß Aò€ô R×%9Ñ%9ô ñ
 �ZÓ Ù�\Ó"Ø×Ññ81ó ó #ó !ð81ðv ×ÑØ03·±ó Ló ðLð^ ×ÑñE-ó ðE-ðP ×Ññ2ó ð2òj	ò&ò
 ð #'¸¿¹ô $ñN �ZÓ Ø×Ò Ñ%ñEó &ó !ñEr   